From c2d158c872a0a7051ab34a749581308248947223 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Thu, 2 Apr 2026 19:54:46 -0500 Subject: [PATCH] feat: allow secure config provider to handle reloading config --- .../Configuration/SecureConfigProvider.cs | 58 +++++++++++++++---- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/src/StevanFreeborn.Extensions.Configuration.Secure/Configuration/SecureConfigProvider.cs b/src/StevanFreeborn.Extensions.Configuration.Secure/Configuration/SecureConfigProvider.cs index 622aadc..3c234c1 100644 --- a/src/StevanFreeborn.Extensions.Configuration.Secure/Configuration/SecureConfigProvider.cs +++ b/src/StevanFreeborn.Extensions.Configuration.Secure/Configuration/SecureConfigProvider.cs @@ -9,19 +9,58 @@ using StevanFreeborn.Extensions.Configuration.Secure.Storage; namespace StevanFreeborn.Extensions.Configuration.Secure.Configuration; -internal class SecureConfigProvider( - ISecureStorageProvider storageProvider, - ICryptoProvider cryptoProvider, - ILogger logger -) : ConfigurationProvider +internal class SecureConfigProvider : ConfigurationProvider, IDisposable { - private readonly ISecureStorageProvider _storageProvider = storageProvider ?? throw new ArgumentNullException(nameof(storageProvider)); - private readonly ICryptoProvider _cryptoProvider = cryptoProvider ?? throw new ArgumentNullException(nameof(cryptoProvider)); - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(cryptoProvider)); + private readonly ISecureStorageProvider _storageProvider; + private readonly ICryptoProvider _cryptoProvider; + private readonly ILogger _logger; + + public SecureConfigProvider( + ISecureStorageProvider storageProvider, + ICryptoProvider cryptoProvider, + ILogger logger + ) + { + _storageProvider = storageProvider ?? throw new ArgumentNullException(nameof(storageProvider)); + _cryptoProvider = cryptoProvider ?? throw new ArgumentNullException(nameof(cryptoProvider)); + _logger = logger ?? throw new ArgumentNullException(nameof(cryptoProvider)); + + _storageProvider.StorageChanged += HandleStorageChangedAsync; + } public override void Load() { var encryptedData = _storageProvider.ReadAllAsync().GetAwaiter().GetResult(); + Data = ProcessAndDecryptData(encryptedData); + } + + public void Dispose() + { + _storageProvider.StorageChanged -= HandleStorageChangedAsync; + } + + private async void HandleStorageChangedAsync(object? sender, EventArgs e) + { + try + { + var encryptedData = await _storageProvider.ReadAllAsync().ConfigureAwait(false); + + var newData = ProcessAndDecryptData(encryptedData); + + Data = newData; + + OnReload(); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + _logger.LogFailedToReloadSecureConfig(ex); + } + } + + private Dictionary ProcessAndDecryptData(IDictionary encryptedData) + { var flattenedData = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var kvp in encryptedData) @@ -29,7 +68,6 @@ internal class SecureConfigProvider( try { var decryptedJson = _cryptoProvider.Decrypt(kvp.Value); - using var document = JsonDocument.Parse(decryptedJson); FlattenJsonElement(flattenedData, document.RootElement, kvp.Key); } @@ -41,7 +79,7 @@ internal class SecureConfigProvider( } } - Data = flattenedData; + return flattenedData; } private static void FlattenJsonElement(IDictionary data, JsonElement element, string currentKey)