bunch of fixes

This commit is contained in:
TheXamlGuy
2024-05-02 20:58:12 +01:00
parent 7dfbb91762
commit 8d62f36931
17 changed files with 180 additions and 134 deletions
+28
View File
@@ -0,0 +1,28 @@
using System.Security.Cryptography;
namespace Toolkit.Foundation;
public class AesDecryptor :
IDecryptor
{
private const int IvSize = 16;
public byte[] Decrypt(byte[] cipher, byte[] key)
{
Span<byte> iv = cipher.AsSpan(0, IvSize);
ReadOnlySpan<byte> encryptedContent = cipher.AsSpan(IvSize);
using Aes aes = Aes.Create();
aes.Key = key;
aes.IV = iv.ToArray();
using MemoryStream memoryStream = new(encryptedContent.ToArray());
using ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using CryptoStream cryptoStream = new(memoryStream, decryptor, CryptoStreamMode.Read);
using MemoryStream resultStream = new();
cryptoStream.CopyTo(resultStream);
return resultStream.ToArray();
}
}
+34
View File
@@ -0,0 +1,34 @@
using System.Security.Cryptography;
namespace Toolkit.Foundation;
public class AesEncryptor :
IEncryptor
{
private const int IvSize = 16;
public byte[] Encrypt(byte[] data,
byte[] key)
{
if (key.Length != 32)
{
throw new ArgumentException("Key must be 256 bits (32 bytes).");
}
using Aes aes = Aes.Create();
aes.Key = key;
aes.GenerateIV();
using MemoryStream memoryStream = new();
memoryStream.Write(aes.IV.AsSpan(0, IvSize));
using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
using (CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
}
return memoryStream.ToArray();
}
}
+4 -2
View File
@@ -120,7 +120,6 @@ public class ConfigurationSource<TConfiguration>(IConfigurationFile<TConfigurati
lock (lockingObject)
{
IFileInfo fileInfo = configurationFile.FileInfo;
if (File.Exists(fileInfo.PhysicalPath))
{
static Stream OpenRead(IFileInfo fileInfo)
@@ -153,11 +152,14 @@ public class ConfigurationSource<TConfiguration>(IConfigurationFile<TConfigurati
if (currentNode is not null)
{
value = JsonSerializer.Deserialize<TConfiguration>(currentNode[segments[lastIndex]],
if (currentNode[segments[lastIndex]] is JsonNode sectionNode)
{
value = JsonSerializer.Deserialize<TConfiguration>(sectionNode,
serializerOptions ?? defaultSerializerOptions());
return true;
}
}
}
value = default;
return false;
+6 -3
View File
@@ -1,21 +1,24 @@
namespace Toolkit.Foundation;
public class ConfigurationWriter<TConfiguration>(IConfigurationSource<TConfiguration> source) :
public class ConfigurationWriter<TConfiguration>(IConfigurationSource<TConfiguration> source,
IConfigurationFactory<TConfiguration> factory) :
IConfigurationWriter<TConfiguration>
where TConfiguration :
class
{
public void Write(Action<TConfiguration> updateDelegate)
{
if (source.TryGet(out TConfiguration? value))
if (!source.TryGet(out TConfiguration? value))
{
value = (TConfiguration)factory.Create();
}
if (value is not null)
{
updateDelegate?.Invoke(value);
Write(value);
}
}
}
public void Write(object value) => source.Set(value);
+9
View File
@@ -0,0 +1,9 @@
namespace Toolkit.Foundation;
public class Container<T> :
IContainer<T>
{
public T? Value { get; private set; }
public void Set(T value) => Value = value;
}
+8
View File
@@ -0,0 +1,8 @@
namespace Toolkit.Foundation;
public interface IContainer<T>
{
T? Value { get; }
void Set(T value);
}
+6
View File
@@ -0,0 +1,6 @@
namespace Toolkit.Foundation;
public interface IDecryptor
{
byte[] Decrypt(byte[] cipher,
byte[] key);
}
+5
View File
@@ -0,0 +1,5 @@
namespace Toolkit.Foundation;
public interface IEncryptor
{
byte[] Encrypt(byte[] data, byte[] key);
}
+7 -3
View File
@@ -100,7 +100,7 @@ public static class IHostBuilderExtension
return new ConfigurationFile<TConfiguration>(fileInfo);
});
services.TryAddKeyedSingleton<IConfigurationSource<TConfiguration>>(section, (provider, KeyAccelerator) =>
services.TryAddKeyedTransient<IConfigurationSource<TConfiguration>>(section, (provider, key) =>
{
JsonSerializerOptions? defaultSerializer = null;
if (serializerDelegate is not null)
@@ -119,10 +119,11 @@ public static class IHostBuilderExtension
provider.GetRequiredKeyedService<IConfigurationFactory<TConfiguration>>(key)));
services.TryAddKeyedTransient<IConfigurationWriter<TConfiguration>>(section, (provider, key) =>
new ConfigurationWriter<TConfiguration>(provider.GetRequiredKeyedService<IConfigurationSource<TConfiguration>>(key)));
new ConfigurationWriter<TConfiguration>(provider.GetRequiredKeyedService<IConfigurationSource<TConfiguration>>(key),
provider.GetRequiredKeyedService<IConfigurationFactory<TConfiguration>>(key)));
services.TryAddKeyedTransient<IConfigurationFactory<TConfiguration>>(section, (provider, key) =>
new ConfigurationFactory<TConfiguration>(() => defaultConfiguration ?? new TConfiguration()));
new ConfigurationFactory<TConfiguration>(() => defaultConfiguration ?? provider.GetRequiredKeyedService<TConfiguration>(key)));
services.AddTransient<IInitializer, ConfigurationInitializer<TConfiguration>>(provider =>
new ConfigurationInitializer<TConfiguration>(provider.GetRequiredKeyedService<IConfigurationReader<TConfiguration>>(section),
@@ -136,6 +137,9 @@ public static class IHostBuilderExtension
services.TryAddKeyedTransient<IWritableConfiguration<TConfiguration>>(section, (provider, key) =>
new WritableConfiguration<TConfiguration>(provider.GetRequiredKeyedService<IConfigurationWriter<TConfiguration>>(key)));
services.TryAddTransient<IWritableConfiguration<TConfiguration>>(provider =>
new WritableConfiguration<TConfiguration>(provider.GetRequiredKeyedService<IConfigurationWriter<TConfiguration>>(section)));
services.TryAddKeyedTransient<IConfigurationDescriptor<TConfiguration>>(section, (provider, key) =>
new ConfigurationDescriptor<TConfiguration>(section, provider.GetRequiredKeyedService<IConfigurationReader<TConfiguration>>(key)));
+5
View File
@@ -4,3 +4,8 @@ public interface IInitializer
{
Task Initialize();
}
public interface IInitializer<T>
{
Task<T> Initialize();
}
+5
View File
@@ -0,0 +1,5 @@
namespace Toolkit.Foundation;
public interface IKeyDeriver
{
byte[] DeriveKey(string password, byte[] salt, int keySize = 32, int iterations = 10000);
}
+5
View File
@@ -0,0 +1,5 @@
namespace Toolkit.Foundation;
public interface IKeyGenerator
{
byte[] Generate(int size);
}
+5
View File
@@ -0,0 +1,5 @@
namespace Toolkit.Foundation;
public interface IPasswordHasher
{
string HashPassword(string password, int iterations = 10000);
}
@@ -35,126 +35,6 @@ public static class IServiceCollectionExtensions
return services;
}
public static IServiceCollection AddConfiguration<TConfiguration,
TValue>(this IServiceCollection services,
Func<TConfiguration, Action<TValue>> changed)
where TConfiguration : class
where TValue : class, new()
{
services.AddSingleton(new ConfigurationValue<TConfiguration, TValue>(changed));
services.AddHandler<ConfigurationChangedHandler<TConfiguration, TValue>>();
return services;
}
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
string section)
where TConfiguration : class, new() =>
services.AddConfiguration<TConfiguration>(section, "Settings.json", null);
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services)
where TConfiguration : class, new() =>
services.AddConfiguration<TConfiguration>(typeof(TConfiguration).Name, "Settings.json", null);
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
Action<TConfiguration> configurationDelegate)
where TConfiguration : class, new()
{
TConfiguration configuration = new();
configurationDelegate.Invoke(configuration);
return services.AddConfiguration(typeof(TConfiguration).Name, "Settings.json", configuration);
}
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
Action<TConfiguration> configurationDelegate,
string section)
where TConfiguration : class, new()
{
TConfiguration configuration = new();
configurationDelegate.Invoke(configuration);
return services.AddConfiguration(section, "Settings.json", configuration);
}
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
TConfiguration configuration)
where TConfiguration : class, new() =>
services.AddConfiguration(configuration.GetType().Name, "Settings.json", configuration);
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
object configuration)
where TConfiguration : class, new() =>
services.AddConfiguration(configuration.GetType().Name,
"Settings.json", (TConfiguration?)configuration);
public static IServiceCollection AddConfiguration<TConfiguration>(this IServiceCollection services,
string section,
string path = "Settings.json",
TConfiguration? defaultConfiguration = null,
Action<JsonSerializerOptions>? serializerDelegate = null)
where TConfiguration : class, new()
{
services.TryAddSingleton<IConfigurationFile<TConfiguration>>(provider =>
{
IFileInfo? fileInfo = null;
if (provider.GetService<IHostEnvironment>() is IHostEnvironment hostEnvironment)
{
IFileProvider fileProvider = hostEnvironment.ContentRootFileProvider;
fileInfo = fileProvider.GetFileInfo(path);
}
fileInfo ??= new PhysicalFileInfo(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path)));
return new ConfigurationFile<TConfiguration>(fileInfo);
});
services.TryAddKeyedSingleton<IConfigurationSource<TConfiguration>>(section, (provider, KeyAccelerator) =>
{
JsonSerializerOptions? defaultSerializer = null;
if (serializerDelegate is not null)
{
defaultSerializer = new JsonSerializerOptions();
serializerDelegate.Invoke(defaultSerializer);
}
return new ConfigurationSource<TConfiguration>(provider.GetRequiredService<IConfigurationFile<TConfiguration>>(),
section, defaultSerializer);
});
//services.AddHostedService<ConfigurationMonitor<TConfiguration>>();
services.TryAddKeyedTransient<IConfigurationReader<TConfiguration>>(section, (provider, key) =>
new ConfigurationReader<TConfiguration>(provider.GetRequiredKeyedService<IConfigurationSource<TConfiguration>>(key),
provider.GetRequiredKeyedService<IConfigurationFactory<TConfiguration>>(key)));
services.TryAddKeyedTransient<IConfigurationWriter<TConfiguration>>(section, (provider, key) =>
new ConfigurationWriter<TConfiguration>(provider.GetRequiredKeyedService<IConfigurationSource<TConfiguration>>(key)));
services.TryAddKeyedTransient<IConfigurationFactory<TConfiguration>>(section, (provider, key) =>
new ConfigurationFactory<TConfiguration>(() => defaultConfiguration ?? new TConfiguration()));
services.AddTransient<IInitializer, ConfigurationInitializer<TConfiguration>>(provider =>
new ConfigurationInitializer<TConfiguration>(provider.GetRequiredKeyedService<IConfigurationReader<TConfiguration>>(section),
provider.GetRequiredKeyedService<IConfigurationWriter<TConfiguration>>(section),
provider.GetRequiredKeyedService<IConfigurationFactory<TConfiguration>>(section),
provider.GetRequiredService<IPublisher>()));
services.AddTransient<IConfigurationInitializer<TConfiguration>, ConfigurationInitializer<TConfiguration>>(provider =>
provider.GetRequiredService<IServiceFactory>().Create<ConfigurationInitializer<TConfiguration>>(section));
services.AddTransient<IWritableConfiguration<TConfiguration>, WritableConfiguration<TConfiguration>>();
services.TryAddKeyedTransient<IConfigurationDescriptor<TConfiguration>>(section, (provider, key) =>
new ConfigurationDescriptor<TConfiguration>(section, provider.GetRequiredKeyedService<IConfigurationReader<TConfiguration>>(key)));
services.AddTransient(provider =>
provider.GetRequiredKeyedService<IConfigurationDescriptor<TConfiguration>>(section));
services.AddTransient(provider =>
provider.GetRequiredKeyedService<IConfigurationDescriptor<TConfiguration>>(section).Value);
return services;
}
public static IServiceCollection AddHandler<THandler>(this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Transient)
where THandler : IHandler
+13
View File
@@ -0,0 +1,13 @@
using System.Security.Cryptography;
namespace Toolkit.Foundation;
public class KeyDeriver :
IKeyDeriver
{
public byte[] DeriveKey(string password, byte[] salt, int keySize = 32, int iterations = 100000)
{
using Rfc2898DeriveBytes pbkdf2 = new(password, salt, iterations, HashAlgorithmName.SHA256);
return pbkdf2.GetBytes(keySize);
}
}
+15
View File
@@ -0,0 +1,15 @@
using System.Security.Cryptography;
namespace Toolkit.Foundation;
public class KeyGenerator :
IKeyGenerator
{
public byte[] Generate(int size)
{
byte[] key = new byte[size];
RandomNumberGenerator.Fill(key);
return key;
}
}
+19
View File
@@ -0,0 +1,19 @@
using System.Security.Cryptography;
namespace Toolkit.Foundation;
public class PasswordHasher :
IPasswordHasher
{
private const int SaltSize = 16;
public string HashPassword(string password, int iterations = 10000)
{
using Rfc2898DeriveBytes pbkdf2 = new(password, SaltSize, iterations, HashAlgorithmName.SHA256);
byte[] salt = pbkdf2.Salt;
byte[] hash = pbkdf2.GetBytes(32);
return $"{Convert.ToBase64String(salt)}:{Convert.ToBase64String(hash)}";
}
}