diff options
Diffstat (limited to 'lib/VNLib.Plugins.Extensions.Loading/src')
4 files changed, 85 insertions, 2 deletions
diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/ConfigurationExtensions.cs b/lib/VNLib.Plugins.Extensions.Loading/src/ConfigurationExtensions.cs index adfd997..ccb2341 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/ConfigurationExtensions.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/ConfigurationExtensions.cs @@ -167,6 +167,52 @@ namespace VNLib.Plugins.Extensions.Loading } /// <summary> + /// Gets a required configuration property from the specified configuration scope + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="config"></param> + /// <param name="property">The name of the property to get</param> + /// <param name="getter">A function to get the value from the json type</param> + /// <returns>The property value</returns> + /// <exception cref="ArgumentNullException"></exception> + public static T? GetProperty<T>(this IConfigScope config, string property, Func<JsonElement, T> getter) + { + //Check null + _ = config ?? throw new ArgumentNullException(nameof(config)); + _ = property ?? throw new ArgumentNullException(nameof(property)); + _ = getter ?? throw new ArgumentNullException(nameof(getter)); + + return !config.TryGetValue(property, out JsonElement el) ? default : getter(el); + } + + /// <summary> + /// Gets a required configuration property from the specified configuration scope + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="config"></param> + /// <param name="property">The name of the property to get</param> + /// <param name="getter">A function to get the value from the json type</param> + /// <returns>The property value</returns> + /// <exception cref="ArgumentNullException"></exception> + /// <exception cref="KeyNotFoundException"></exception> + public static T GetRequiredProperty<T>(this IConfigScope config, string property, Func<JsonElement, T> getter) + { + //Check null + _ = config ?? throw new ArgumentNullException(nameof(config)); + _ = property ?? throw new ArgumentNullException(nameof(property)); + _ = getter ?? throw new ArgumentNullException(nameof(getter)); + + //Get the property + if(!config.TryGetValue(property, out JsonElement el)) + { + throw new KeyNotFoundException($"Missing required configuration property '{property}'"); + } + + //Even if the getter returns null, throw + return getter(el) ?? throw new KeyNotFoundException($"Missing required configuration property '{property}'"); + } + + /// <summary> /// Gets the configuration property name for the type /// </summary> /// <param name="type">The type to get the configuration name for</param> diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/Events/EventManagment.cs b/lib/VNLib.Plugins.Extensions.Loading/src/Events/EventManagment.cs index 57e4a9c..40a52fc 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/Events/EventManagment.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/Events/EventManagment.cs @@ -57,7 +57,7 @@ namespace VNLib.Plugins.Extensions.Loading.Events { plugin.ThrowIfUnloaded(); - plugin.Log.Verbose("Interval for {t} scheduled", interval); + plugin.Log.Verbose("Interval for {t} scheduled on type {rr}", interval, asyncCallback.Target); //Run interval on plugins bg scheduler _ = plugin.ObserveWork(() => RunIntervalOnPluginScheduler(plugin, asyncCallback, interval, immediate)); diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs b/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs index f2cbd28..c1e6b3d 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs @@ -42,7 +42,14 @@ namespace VNLib.Plugins.Extensions.Loading public ReadOnlySpan<char> Result => _secretChars; - internal SecretResult(ReadOnlySpan<char> value) => _secretChars = value.ToArray(); + internal SecretResult(ReadOnlySpan<char> value) : this(value.ToArray()) + { } + + private SecretResult(char[] secretChars) + { + _secretChars = secretChars; + } + ///<inheritdoc/> protected override void Free() @@ -56,5 +63,7 @@ namespace VNLib.Plugins.Extensions.Loading MemoryUtil.UnsafeZeroMemory<char>(result); return res; } + + internal static SecretResult ToSecret(char[] result) => new(result); } } diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/VaultSecrets.cs b/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/VaultSecrets.cs index 08af485..c2d830f 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/VaultSecrets.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/VaultSecrets.cs @@ -23,9 +23,11 @@ */ using System; +using System.IO; using System.Linq; using System.Text; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using System.Security.Cryptography.X509Certificates; @@ -62,6 +64,7 @@ namespace VNLib.Plugins.Extensions.Loading public const string VAULT_URL_SCHEME = "vault://"; public const string ENV_URL_SCHEME = "env://"; + public const string FILE_URL_SCHEME = "file://"; /// <summary> @@ -125,11 +128,36 @@ namespace VNLib.Plugins.Extensions.Loading return Task.FromResult<ISecretResult?>(envVal == null ? null : new SecretResult(envVal)); } + + //See if the secret is a file path + if (rawSecret.StartsWith(FILE_URL_SCHEME, StringComparison.OrdinalIgnoreCase)) + { + string filePath = rawSecret[FILE_URL_SCHEME.Length..]; + return GetSecretFromFileAsync(filePath, plugin.UnloadToken); + } //Finally, return the raw value return Task.FromResult<ISecretResult?>(new SecretResult(rawSecret.AsSpan())); } + private static async Task<ISecretResult?> GetSecretFromFileAsync(string filePath, CancellationToken ct) + { + //read the file data + byte[] secretFileData = await File.ReadAllBytesAsync(filePath, ct); + + //recover the character data from the file data + int chars = Encoding.UTF8.GetCharCount(secretFileData); + char[] secretFileChars = new char[chars]; + Encoding.UTF8.GetChars(secretFileData, secretFileChars); + + //Create secret from the file data + SecretResult sr = SecretResult.ToSecret(secretFileChars); + + //Clear file data buffer + MemoryUtil.InitializeBlock(secretFileData.AsSpan()); + return sr; + } + /// <summary> /// Gets a secret at the given vault url (in the form of "vault://[mount-name]/[secret-path]?secret=[secret_name]") /// </summary> |