feat: allow specifying json type info explicity or resolving from registered options instance
This commit is contained in:
@@ -1,8 +1,12 @@
|
|||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
|
||||||
namespace StevanFreeborn.Extensions.Configuration.Secure.Configuration;
|
namespace StevanFreeborn.Extensions.Configuration.Secure.Configuration;
|
||||||
|
|
||||||
internal interface ISecureConfig
|
internal interface ISecureConfig
|
||||||
{
|
{
|
||||||
Task<bool> DeleteAsync(string key, CancellationToken ct = default);
|
|
||||||
Task<T?> GetAsync<T>(string key, CancellationToken ct = default);
|
|
||||||
Task SetAsync<T>(string key, T value, CancellationToken ct = default);
|
Task SetAsync<T>(string key, T value, CancellationToken ct = default);
|
||||||
}
|
Task SetAsync<T>(string key, T value, JsonTypeInfo<T> typeInfo, CancellationToken ct = default);
|
||||||
|
Task<T?> GetAsync<T>(string key, CancellationToken ct = default);
|
||||||
|
Task<T?> GetAsync<T>(string key, JsonTypeInfo<T> typeInfo, CancellationToken ct = default);
|
||||||
|
Task<bool> DeleteAsync(string key, CancellationToken ct = default);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
|
||||||
using StevanFreeborn.Extensions.Configuration.Secure.Cryptography;
|
using StevanFreeborn.Extensions.Configuration.Secure.Cryptography;
|
||||||
using StevanFreeborn.Extensions.Configuration.Secure.Storage;
|
using StevanFreeborn.Extensions.Configuration.Secure.Storage;
|
||||||
@@ -7,7 +8,8 @@ namespace StevanFreeborn.Extensions.Configuration.Secure.Configuration;
|
|||||||
|
|
||||||
internal sealed class SecureConfig(
|
internal sealed class SecureConfig(
|
||||||
ISecureStorageProvider storageProvider,
|
ISecureStorageProvider storageProvider,
|
||||||
ICryptoProvider cryptoProvider
|
ICryptoProvider cryptoProvider,
|
||||||
|
JsonSerializerOptions jsonOptions
|
||||||
) : ISecureConfig
|
) : ISecureConfig
|
||||||
{
|
{
|
||||||
private readonly ISecureStorageProvider _storageProvider = storageProvider ??
|
private readonly ISecureStorageProvider _storageProvider = storageProvider ??
|
||||||
@@ -16,11 +18,20 @@ internal sealed class SecureConfig(
|
|||||||
private readonly ICryptoProvider _cryptoProvider = cryptoProvider ??
|
private readonly ICryptoProvider _cryptoProvider = cryptoProvider ??
|
||||||
throw new ArgumentNullException(nameof(cryptoProvider));
|
throw new ArgumentNullException(nameof(cryptoProvider));
|
||||||
|
|
||||||
public async Task SetAsync<T>(string key, T value, CancellationToken ct = default)
|
private readonly JsonSerializerOptions _jsonOptions = jsonOptions ??
|
||||||
|
throw new ArgumentNullException(nameof(jsonOptions));
|
||||||
|
|
||||||
|
public Task SetAsync<T>(string key, T value, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var typeInfo = GetTypeInfo<T>();
|
||||||
|
return SetAsync(key, value, typeInfo, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SetAsync<T>(string key, T value, JsonTypeInfo<T> typeInfo, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(key))
|
if (string.IsNullOrWhiteSpace(key))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(key));
|
throw new ArgumentException("Cannot be null or whitespace.", nameof(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value is null)
|
if (value is null)
|
||||||
@@ -28,17 +39,23 @@ internal sealed class SecureConfig(
|
|||||||
throw new ArgumentNullException(nameof(value));
|
throw new ArgumentNullException(nameof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
var json = JsonSerializer.Serialize(value);
|
var json = JsonSerializer.Serialize(value, typeInfo);
|
||||||
var encryptedValue = _cryptoProvider.Encrypt(json);
|
var encryptedValue = _cryptoProvider.Encrypt(json);
|
||||||
|
|
||||||
await _storageProvider.WriteAsync(key, encryptedValue, ct).ConfigureAwait(false);
|
await _storageProvider.WriteAsync(key, encryptedValue, ct).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<T?> GetAsync<T>(string key, CancellationToken ct = default)
|
public Task<T?> GetAsync<T>(string key, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(key))
|
var typeInfo = GetTypeInfo<T>();
|
||||||
|
return GetAsync(key, typeInfo, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<T?> GetAsync<T>(string key, JsonTypeInfo<T> typeInfo, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(key))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(key));
|
throw new ArgumentException("Cannot be null or whitespace.", nameof(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
var encryptedData = await _storageProvider.ReadAsync(key, ct).ConfigureAwait(false);
|
var encryptedData = await _storageProvider.ReadAsync(key, ct).ConfigureAwait(false);
|
||||||
@@ -49,11 +66,24 @@ internal sealed class SecureConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var data = _cryptoProvider.Decrypt(encryptedData);
|
var data = _cryptoProvider.Decrypt(encryptedData);
|
||||||
return JsonSerializer.Deserialize<T>(data);
|
return JsonSerializer.Deserialize(data, typeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<bool> DeleteAsync(string key, CancellationToken ct = default)
|
public Task<bool> DeleteAsync(string key, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return _storageProvider.DeleteAsync(key, ct);
|
return _storageProvider.DeleteAsync(key, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JsonTypeInfo<T> GetTypeInfo<T>()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (JsonTypeInfo<T>?)_jsonOptions.GetTypeInfo(typeof(T))
|
||||||
|
?? throw new InvalidOperationException($"AOT metadata for type '{typeof(T).Name}' is missing. Did you forget to register it via {nameof(SecureConfigBuilder.AddJsonAotContext)}()?");
|
||||||
|
}
|
||||||
|
catch (NotSupportedException ex)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"AOT metadata for type '{typeof(T).Name}' is missing. Did you forget to register it via {nameof(SecureConfigBuilder.AddJsonAotContext)}()?", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user