diff --git a/src/Dan.Plugin.Tilda/Config/KeyVault.cs b/src/Dan.Plugin.Tilda/Config/KeyVault.cs
new file mode 100644
index 0000000..d40e301
--- /dev/null
+++ b/src/Dan.Plugin.Tilda/Config/KeyVault.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading.Tasks;
+using Azure.Identity;
+using Azure.Security.KeyVault.Secrets;
+
+namespace Dan.Plugin.Tilda.Config;
+
+public class KeyVault
+{
+ private SecretClient SecretClient { get; }
+
+ ///
+ /// Key Vault for Core
+ ///
+ /// Name of the Key Vault
+ public KeyVault(string vaultName)
+ {
+ SecretClient = new SecretClient(new Uri($"https://{vaultName}.vault.azure.net/"), new DefaultAzureCredential());
+ }
+
+ ///
+ /// Get a secret from the key vault
+ ///
+ /// Secret name
+ /// The secret value
+ public async Task Get(string key)
+ {
+ var secret = await SecretClient.GetSecretAsync(key);
+ return secret.Value.Value;
+ }
+
+ ///
+ /// Get a certificate from the key vault
+ ///
+ /// Certificate name
+ /// The certificate
+ public async Task GetCertificate(string key)
+ {
+ var base64Certificate = await Get(key);
+ var certBytes = Convert.FromBase64String(base64Certificate);
+
+ var cert = new X509Certificate2(certBytes, string.Empty, X509KeyStorageFlags.MachineKeySet);
+
+ return await Task.FromResult(cert);
+ }
+}
diff --git a/src/Dan.Plugin.Tilda/Config/Settings.cs b/src/Dan.Plugin.Tilda/Config/Settings.cs
index f865126..c278ac9 100644
--- a/src/Dan.Plugin.Tilda/Config/Settings.cs
+++ b/src/Dan.Plugin.Tilda/Config/Settings.cs
@@ -1,4 +1,5 @@
using System;
+using System.Security.Cryptography.X509Certificates;
namespace Dan.Plugin.Tilda.Config
{
@@ -10,12 +11,32 @@ public string GetClassBaseUri(string className)
}
public string RedisConnectionString { get; set; }
-
+
public bool IsTest { get; set; }
public bool IsLocalDevelopment { get; set; }
public string Breaker_RetryWaitTime { get; set; }
public string Breaker_OpenCircuitTime { get; set; }
+
+ public string KofuviEndpoint { get; set; }
+ public string KvName { get; set; }
+ public string KvKofuviCertificateName { get; set; }
+
+ private static string KeyVaultName => Environment.GetEnvironmentVariable("KvName");
+ private static string KofuviCertificateName => Environment.GetEnvironmentVariable("KvKofuviCertificateName");
+
+ private static X509Certificate2 _altinnCertificate { get; set; }
+ public static X509Certificate2 Certificate
+ {
+ get
+ {
+ return _altinnCertificate ?? new KeyVault(KeyVaultName).GetCertificate(KofuviCertificateName).Result;
+ }
+ set
+ {
+ _altinnCertificate = value;
+ }
+ }
}
}
diff --git a/src/Dan.Plugin.Tilda/Dan.Plugin.Tilda.csproj b/src/Dan.Plugin.Tilda/Dan.Plugin.Tilda.csproj
index 2dbc492..7714e9d 100644
--- a/src/Dan.Plugin.Tilda/Dan.Plugin.Tilda.csproj
+++ b/src/Dan.Plugin.Tilda/Dan.Plugin.Tilda.csproj
@@ -23,6 +23,8 @@
+
+
diff --git a/src/Dan.Plugin.Tilda/Models/KofuviResponse.cs b/src/Dan.Plugin.Tilda/Models/KofuviResponse.cs
new file mode 100644
index 0000000..bd12a6d
--- /dev/null
+++ b/src/Dan.Plugin.Tilda/Models/KofuviResponse.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Dan.Plugin.Tilda.Models;
+
+[Serializable]
+public class KofuviResponse
+{
+ [JsonProperty("_embedded")]
+ public Embedded Embedded { get; set; }
+}
+
+[Serializable]
+public class Embedded
+{
+ [JsonProperty("varsling")]
+ public Notification Notification { get; set; }
+}
+
+[Serializable]
+public class Notification
+{
+ [JsonProperty("varslingsadresser")]
+ public List NotificationAddresses { get; set; }
+}
+
+[Serializable]
+public class NotificationAddress
+{
+ [JsonProperty("kontaktinformasjon")]
+ public ContactInformation ContactInformation { get; set; }
+}
+
+[Serializable]
+public class ContactInformation
+{
+ [JsonProperty("digitalVarslingsinformasjon")]
+ public DigitalNotificationInformation DigitalNotificationInformation { get; set; }
+}
+
+[Serializable]
+public class DigitalNotificationInformation
+{
+ [JsonProperty("epostadresse")]
+ public NotificationEmail NotificationEmail { get; set; }
+}
+
+[Serializable]
+public class NotificationEmail
+{
+ [JsonProperty("fullstendigAdresse")]
+ public string CompleteEmail { get; set; }
+}
diff --git a/src/Dan.Plugin.Tilda/Models/TildaRegistryEntry.cs b/src/Dan.Plugin.Tilda/Models/TildaRegistryEntry.cs
index 24577a2..b53179e 100644
--- a/src/Dan.Plugin.Tilda/Models/TildaRegistryEntry.cs
+++ b/src/Dan.Plugin.Tilda/Models/TildaRegistryEntry.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Text;
using Newtonsoft.Json;
namespace Dan.Plugin.Tilda.Models
@@ -14,6 +13,9 @@ public class TildaRegistryEntry
[JsonProperty("tildaenhetNavn", Required = Required.Default, DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Name;
+ [JsonProperty("epostaddresser", Required = Required.Default, DefaultValueHandling = DefaultValueHandling.Ignore)]
+ public List Emails;
+
[JsonProperty("tildaenhetHovedenhet", Required = Required.Default, DefaultValueHandling = DefaultValueHandling.Ignore)]
public string ControlObjectParent;
@@ -31,7 +33,6 @@ public class TildaRegistryEntry
[JsonProperty("driftsstatus", Required = Required.Default, DefaultValueHandling = DefaultValueHandling.Ignore)]
public OperationStatus OperationalStatus;
-
}
public class AccountsInformation
diff --git a/src/Dan.Plugin.Tilda/Program.cs b/src/Dan.Plugin.Tilda/Program.cs
index 014e11f..7c386ce 100644
--- a/src/Dan.Plugin.Tilda/Program.cs
+++ b/src/Dan.Plugin.Tilda/Program.cs
@@ -12,6 +12,7 @@
using Polly.Extensions.Http;
using Polly.Registry;
using System;
+using System.Net.Http;
using Settings = Dan.Plugin.Tilda.Config.Settings;
var host = new HostBuilder()
@@ -20,7 +21,7 @@
{
configuration
.AddJsonFile("worker-logging.json", optional:true);
- })
+ })
.ConfigureServices((context, services) =>
{
// This makes IOption available in the DI container.
@@ -47,8 +48,18 @@
services.AddHttpClient("ERHttpClient", client =>
{
client.Timeout = new TimeSpan(0, 0, 5);
- });
+ });
+ services.AddHttpClient("KofuviClient", _ =>
+ {
+
+ })
+ .ConfigurePrimaryHttpMessageHandler(() =>
+ {
+ var handler = new HttpClientHandler();
+ handler.ClientCertificates.Add(Settings.Certificate);
+ return handler;
+ });;
})
.Build();
diff --git a/src/Dan.Plugin.Tilda/Tilda.cs b/src/Dan.Plugin.Tilda/Tilda.cs
index aca9fb4..0a65308 100644
--- a/src/Dan.Plugin.Tilda/Tilda.cs
+++ b/src/Dan.Plugin.Tilda/Tilda.cs
@@ -30,6 +30,7 @@ public class Tilda
private ILogger _logger;
private HttpClient _client;
private HttpClient _erClient;
+ private HttpClient _kofuviClient;
private Settings _settings;
private readonly IEntityRegistryService _entityRegistryService;
private readonly IEvidenceSourceMetadata _metadata;
@@ -41,6 +42,7 @@ public Tilda(IHttpClientFactory httpClientFactory, IOptions settings,
_policyRegistry = policyRegistry;
_client = httpClientFactory.CreateClient("SafeHttpClient");
_erClient = httpClientFactory.CreateClient("ERHttpClient");
+ _kofuviClient = httpClientFactory.CreateClient("KofuviClient");
_settings = settings.Value;
_entityRegistryService = entityRegistry;
_entityRegistryService.AllowTestCcrLookup = _settings.IsLocalDevelopment || _settings.IsLocalDevelopment;
@@ -440,6 +442,7 @@ private async Task> GetEvidenceValuesStorulykkevirksomhet(Ev
return eb.GetEvidenceValues();
}
+ // TODO: use IncludeSubunits-param in Tildaparameters? And then we can reduce duplicate code between the overloads
private async Task> GetOrganizationsFromBR(string organizationNumber, TildaParameters param)
{
var result = new List();
@@ -450,19 +453,32 @@ private async Task> GetOrganizationsFromBR(string organ
accountsInformation = await Helpers.GetAnnualTurnoverFromBR(organizationNumber, _client, _policyRegistry);
}
- result.Add(await ConvertBRtoTilda(brResult.First(), accountsInformation));
+ var kofuviAddresses = await Helpers.GetKofuviAddresses(_settings.KofuviEndpoint, organizationNumber, _kofuviClient, _logger);
+
+ var organization = await ConvertBRtoTilda(brResult.First(), accountsInformation);
+ if (kofuviAddresses.Count > 0)
+ {
+ organization.Emails = kofuviAddresses;
+ }
+ result.Add(organization);
return result;
}
private async Task GetOrganizationFromBR(string organizationNumber)
{
- var brResultTask = Helpers.GetFromBR(organizationNumber, _erClient, false, _policyRegistry);
- var accountsInformationTask = Helpers.GetAnnualTurnoverFromBR(organizationNumber, _client, _policyRegistry);
+ var brResultTask = await Helpers.GetFromBR(organizationNumber, _erClient, false, _policyRegistry);
+ var accountsInformationTask = await Helpers.GetAnnualTurnoverFromBR(organizationNumber, _client, _policyRegistry);
- await Task.WhenAll(brResultTask, accountsInformationTask);
+ var kofuviAddresses = await Helpers.GetKofuviAddresses(_settings.KofuviEndpoint, organizationNumber, _kofuviClient, _logger);
+
+ var organization = await ConvertBRtoTilda(brResultTask.First(), accountsInformationTask);
+ if (kofuviAddresses.Count > 0)
+ {
+ organization.Emails = kofuviAddresses;
+ }
- return await ConvertBRtoTilda(brResultTask.Result.First(), accountsInformationTask.Result);
+ return organization;
}
private async Task> GetEvidenceValuesTilsynskoordinering(EvidenceHarvesterRequest req, TildaParameters param)
diff --git a/src/Dan.Plugin.Tilda/Utils/Helpers.cs b/src/Dan.Plugin.Tilda/Utils/Helpers.cs
index 4a5fa18..3807805 100644
--- a/src/Dan.Plugin.Tilda/Utils/Helpers.cs
+++ b/src/Dan.Plugin.Tilda/Utils/Helpers.cs
@@ -176,7 +176,7 @@ private static async Task> GetAllUnitsFromBR(string
string rawResult;
try
{
- var response = await client.GetAsync($"http://data.brreg.no/enhetsregisteret/api/enheter/?overordnetEnhet={organizationNumber}");
+ var response = await client.GetAsync($"https://data.brreg.no/enhetsregisteret/api/enheter/?overordnetEnhet={organizationNumber}");
if (response.StatusCode == HttpStatusCode.NotFound)
{
throw new EvidenceSourcePermanentClientException(
@@ -208,7 +208,7 @@ public static async Task> GetFromBR(string organizat
{
List result = new List();
- if (organization == "111111111")
+ if (organization is "111111111" or "811105562")
{
result.Add(new BREntityRegisterEntry()
{
@@ -560,5 +560,56 @@ public static async Task GetPdfreport(string url, string sourceOrgNo, Ht
return result;
}
+
+ // Returns empty list on any error
+ public static async Task> GetKofuviAddresses(string baseEndpoint, string organizationNumber, HttpClient client, ILogger logger)
+ {
+ var targetUrl = $"{baseEndpoint}/api/varslingsadresser/{organizationNumber}";
+ string responseString;
+ try
+ {
+ var response = await client.GetAsync(targetUrl);
+ if (!response.IsSuccessStatusCode)
+ {
+ logger.LogError(
+ "Failed to get kofuvi addresses for org={organizationNumber} on url={targetUrl} with unsuccessful response status={statusCode}",
+ organizationNumber, targetUrl, response.StatusCode
+ );
+ return new List();
+ }
+ responseString = await response.Content.ReadAsStringAsync();
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(
+ "Failed to get kofuvi addresses for org={organizationNumber} on url={targetUrl} with exception ex={ex} message={message} status={status}",
+ organizationNumber, targetUrl, ex.GetType().Name, ex.Message, "hardfail"
+ );
+ return new List();
+ }
+
+ try
+ {
+ var kofuviResponse = JsonConvert.DeserializeObject(responseString);
+ var addresses = kofuviResponse.Embedded.Notification.NotificationAddresses;
+ if (addresses is null || addresses.Count == 0)
+ {
+ return new List();
+ }
+
+ return addresses
+ .Select(a => a.ContactInformation?.DigitalNotificationInformation?.NotificationEmail?.CompleteEmail)
+ .Where(a => a is not null)
+ .ToList();
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(
+ "Failed to deserialize kofuvi response for org={organizationNumber} with exception ex={ex} message={message} status={status}",
+ organizationNumber, ex.GetType().Name, ex.Message, "hardfail"
+ );
+ return new List();
+ }
+ }
}
}