encyption wip
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Microsoft.Data.Sqlite;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
@@ -55,14 +54,25 @@ public partial class App : Application
|
|||||||
{
|
{
|
||||||
args.AddServices(services =>
|
args.AddServices(services =>
|
||||||
{
|
{
|
||||||
|
services.AddTransient<IEncryptor, AesEncryptor>();
|
||||||
|
services.AddTransient<IDecryptor, AesDecryptor>();
|
||||||
|
|
||||||
|
services.AddTransient<IPasswordHasher, PasswordHasher>();
|
||||||
|
services.AddTransient<IKeyDeriver, KeyDeriver>();
|
||||||
|
|
||||||
services.AddDbContextFactory<VaultDbContext>(args =>
|
services.AddDbContextFactory<VaultDbContext>(args =>
|
||||||
{
|
{
|
||||||
args.UseSqlite();
|
args.UseSqlite();
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddDbContextFactory<VaultDbContext>();
|
services.AddDbContextFactory<VaultDbContext>();
|
||||||
services.AddHandler<VaultStorageHandler>();
|
|
||||||
|
|
||||||
|
services.AddHandler<OpenVaultHandler>();
|
||||||
|
|
||||||
|
services.AddHandler<CreateVaultStorageHandler>();
|
||||||
|
services.AddHandler<OpenVaultStorageHandler>();
|
||||||
|
|
||||||
|
services.AddTemplate<VaultNavigationViewModel, VaultNavigationView>();
|
||||||
services.AddTemplate<AllNavigationViewModel, AllNavigationView>();
|
services.AddTemplate<AllNavigationViewModel, AllNavigationView>();
|
||||||
services.AddTemplate<StarredNavigationViewModel, StarredNavigationView>();
|
services.AddTemplate<StarredNavigationViewModel, StarredNavigationView>();
|
||||||
services.AddTemplate<CategoriesNavigationViewModel, CategoriesNavigationView>();
|
services.AddTemplate<CategoriesNavigationViewModel, CategoriesNavigationView>();
|
||||||
@@ -74,15 +84,13 @@ public partial class App : Application
|
|||||||
})!);
|
})!);
|
||||||
|
|
||||||
services.AddSingleton<IVaultHostCollection, VaultHostCollection>();
|
services.AddSingleton<IVaultHostCollection, VaultHostCollection>();
|
||||||
services.AddHandler<VaultHandler>();
|
services.AddHandler<CreateVaultHandler>();
|
||||||
|
|
||||||
//services.AddInitializer<VaultsInitializer>();
|
services.AddInitializer<VaultCollectionInitializer>();
|
||||||
|
|
||||||
services.AddTemplate<MainViewModel, MainView>("Main");
|
services.AddTemplate<MainViewModel, MainView>("Main");
|
||||||
|
|
||||||
services.AddTemplate<VaultNavigationViewModel, VaultNavigationView>();
|
|
||||||
services.AddHandler<VaultNavigationViewModelHandler>();
|
services.AddHandler<VaultNavigationViewModelHandler>();
|
||||||
|
|
||||||
services.AddTransient<FooterViewModel>();
|
services.AddTransient<FooterViewModel>();
|
||||||
|
|
||||||
services.AddTemplate<ManageNavigationViewModel, ManageNavigationView>();
|
services.AddTemplate<ManageNavigationViewModel, ManageNavigationView>();
|
||||||
|
|||||||
@@ -12,7 +12,15 @@
|
|||||||
Margin="0,0,0,18"
|
Margin="0,0,0,18"
|
||||||
Text="{Binding Name}"
|
Text="{Binding Name}"
|
||||||
Watermark="Enter vault name" />
|
Watermark="Enter vault name" />
|
||||||
<TextBox Margin="0,0,0,18" Watermark="Enter password" />
|
<TextBox
|
||||||
<TextBox Watermark="Confirm password" />
|
Margin="0,0,0,18"
|
||||||
|
Classes="revealPasswordButton"
|
||||||
|
PasswordChar="●"
|
||||||
|
Text="{Binding Password}"
|
||||||
|
Watermark="Enter password" />
|
||||||
|
<TextBox
|
||||||
|
Classes="revealPasswordButton"
|
||||||
|
PasswordChar="●"
|
||||||
|
Watermark="Confirm password" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ContentDialog>
|
</ContentDialog>
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
<UserControl
|
<UserControl
|
||||||
x:Class="Bitvault.Avalonia.LockView"
|
x:Class="Bitvault.Avalonia.LockView"
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:vm="using:Bitvault"
|
||||||
|
x:DataType="vm:LockViewModel">
|
||||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
<TextBox
|
<TextBox
|
||||||
Width="300"
|
Width="300"
|
||||||
Classes="revealPasswordButton"
|
Classes="revealPasswordButton"
|
||||||
PasswordChar="●">
|
PasswordChar="●"
|
||||||
|
Text="{Binding Password}">
|
||||||
<Interaction.Behaviors>
|
<Interaction.Behaviors>
|
||||||
<KeyBindingTriggerBehavior Gesture="Enter">
|
<KeyBindingTriggerBehavior Gesture="Enter">
|
||||||
<NavigateAction Context="Main" Route="Vault" />
|
<InvokeCommandAction Command="{Binding UnlockCommand}" />
|
||||||
</KeyBindingTriggerBehavior>
|
</KeyBindingTriggerBehavior>
|
||||||
</Interaction.Behaviors>
|
</Interaction.Behaviors>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class AesDecryptor :
|
||||||
|
IDecryptor
|
||||||
|
{
|
||||||
|
private const int IvSize = 16;
|
||||||
|
|
||||||
|
public string Decrypt(string cipherText, byte[] key)
|
||||||
|
{
|
||||||
|
byte[] cipherData = Convert.FromBase64String(cipherText);
|
||||||
|
|
||||||
|
byte[] iv = new byte[IvSize];
|
||||||
|
Array.Copy(cipherData, 0, iv, 0, IvSize); // Extract the IV from the start of the cipher data
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var memoryStream = new MemoryStream(cipherData, IvSize, cipherData.Length - IvSize);
|
||||||
|
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
|
||||||
|
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
|
||||||
|
using (var streamReader = new StreamReader(cryptoStream))
|
||||||
|
{
|
||||||
|
return streamReader.ReadToEnd(); // Return the decrypted text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class AesEncryptor : IEncryptor
|
||||||
|
{
|
||||||
|
public string Encrypt(string plainText, byte[] key)
|
||||||
|
{
|
||||||
|
const int IvSize = 16;
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.GenerateIV();
|
||||||
|
|
||||||
|
byte[] iv = aes.IV;
|
||||||
|
|
||||||
|
using var memoryStream = new MemoryStream();
|
||||||
|
memoryStream.Write(iv, 0, IvSize); // Store IV at the start of the stream
|
||||||
|
|
||||||
|
using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
|
||||||
|
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
|
||||||
|
using (var streamWriter = new StreamWriter(cryptoStream))
|
||||||
|
{
|
||||||
|
streamWriter.Write(plainText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert.ToBase64String(memoryStream.ToArray()); // Return the encrypted data in base64
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class CreateVaultHandler(IComponentFactory componentFactory) :
|
||||||
|
IHandler<Create<Vault>, bool>
|
||||||
|
{
|
||||||
|
public async Task<bool> Handle(Create<Vault> args,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (args.Value is Vault vault)
|
||||||
|
{
|
||||||
|
if (vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
||||||
|
{
|
||||||
|
if (componentFactory.Create<IVaultComponent, VaultConfiguration>($"Vault:{name}", new VaultConfiguration { Name = name }) is IComponentHost host)
|
||||||
|
{
|
||||||
|
if (host.Services.GetRequiredService<IMediator>() is IMediator mediator)
|
||||||
|
{
|
||||||
|
if (await mediator.Handle<Create<VaultStorage>, bool>(Create.As(new VaultStorage(name, password)), cancellationToken))
|
||||||
|
{
|
||||||
|
await host.StartAsync(cancellationToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class CreateVaultStorageHandler(IHostEnvironment environment,
|
||||||
|
IKeyDeriver deriver,
|
||||||
|
IEncryptor encryptor,
|
||||||
|
IDecryptor decryptor,
|
||||||
|
IDbContextFactory<VaultDbContext> dbContextFactory) : IHandler<Create<VaultStorage>, bool>
|
||||||
|
{
|
||||||
|
public async Task<bool> Handle(Create<VaultStorage> args, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (args.Value is VaultStorage vault)
|
||||||
|
{
|
||||||
|
if (vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
||||||
|
{
|
||||||
|
byte[] salt = new byte[16];
|
||||||
|
RandomNumberGenerator.Fill(salt);
|
||||||
|
|
||||||
|
byte[] key = new byte[32];
|
||||||
|
RandomNumberGenerator.Fill(key);
|
||||||
|
|
||||||
|
byte[] derivedKey = deriver.DeriveKey(password, salt);
|
||||||
|
string? encryptedKey = encryptor.Encrypt(Convert.ToBase64String(key), derivedKey);
|
||||||
|
|
||||||
|
|
||||||
|
byte[] derivedKey2 = deriver.DeriveKey(password, salt);
|
||||||
|
var dod = decryptor.Decrypt(encryptedKey, derivedKey2);
|
||||||
|
|
||||||
|
// Derive the key for encryption
|
||||||
|
|
||||||
|
//byte[] encryptionKey = deriver.DeriveKey(password, salt);
|
||||||
|
|
||||||
|
//// Derive the key for decryption
|
||||||
|
//byte[] decryptionKey = deriver.DeriveKey(password, salt);
|
||||||
|
|
||||||
|
//// Compare keys to ensure they're the same
|
||||||
|
//bool areKeysEqual = encryptionKey.SequenceEqual(decryptionKey);
|
||||||
|
|
||||||
|
////byte[] derivedKey = deriver.DeriveKey(password, salt);
|
||||||
|
//string? encrypted = encryptor.Encrypt(password, derivedKey);
|
||||||
|
|
||||||
|
//var storedSalt = Convert.ToBase64String(salt);
|
||||||
|
|
||||||
|
|
||||||
|
//byte[] derivedKey2 = deriver.DeriveKey(password, salt);
|
||||||
|
|
||||||
|
//var d = decryptor.Decrypt(encrypted, derivedKey2);
|
||||||
|
|
||||||
|
// Generate a hash
|
||||||
|
//string hash = hasher.HashPassword(password);
|
||||||
|
|
||||||
|
//string[] parts = hash.Split(':');
|
||||||
|
|
||||||
|
//// Store the salt only
|
||||||
|
//string storedSalt = parts[0];
|
||||||
|
|
||||||
|
//// Use the hash as the password
|
||||||
|
//string storedHash = parts[1];
|
||||||
|
|
||||||
|
//context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, name)}.vault;Mode=ReadWriteCreate;Password={storedHash}");
|
||||||
|
//await context.Database.EnsureCreatedAsync();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,8 +17,12 @@ public partial class CreateVaultViewModel(IServiceProvider provider,
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string name;
|
private string name;
|
||||||
|
|
||||||
|
[MaybeNull]
|
||||||
|
[ObservableProperty]
|
||||||
|
private string password;
|
||||||
|
|
||||||
public async Task<bool> Confirm()
|
public async Task<bool> Confirm()
|
||||||
{
|
{
|
||||||
return await Mediator.Handle<Create<Vault>, bool>(Create.As(new Vault(Name, "")));
|
return await Mediator.Handle<Create<Vault>, bool>(Create.As(new Vault(Name, Password)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Bitvault
|
||||||
|
{
|
||||||
|
public interface IDecryptor
|
||||||
|
{
|
||||||
|
string? Decrypt(string cipherText, byte[] key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Bitvault
|
||||||
|
{
|
||||||
|
public interface IEncryptor
|
||||||
|
{
|
||||||
|
|
||||||
|
string? Encrypt(string plainText, byte[] key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public interface IKeyDeriver
|
||||||
|
{
|
||||||
|
byte[] DeriveKey(string password, byte[] salt, int keySize = 32, int iterations = 10000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public interface IPasswordHasher
|
||||||
|
{
|
||||||
|
string HashPassword(string password, int iterations = 10000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Bitvault
|
||||||
|
{
|
||||||
|
public interface IVaultConnectionPersistence
|
||||||
|
{
|
||||||
|
void Dispose();
|
||||||
|
string? Get(string key);
|
||||||
|
void Set(string key, string connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Toolkit.Foundation;
|
|
||||||
|
|
||||||
namespace Bitvault
|
|
||||||
{
|
|
||||||
public interface IVaultFactory
|
|
||||||
{
|
|
||||||
IComponentHost? Create(string name,
|
|
||||||
string password,
|
|
||||||
VaultConfiguration configuration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,26 @@
|
|||||||
using Toolkit.Foundation;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
namespace Bitvault;
|
namespace Bitvault;
|
||||||
|
|
||||||
public class LockViewModel(IServiceProvider provider,
|
public partial class LockViewModel(IServiceProvider provider,
|
||||||
IServiceFactory factory,
|
IServiceFactory factory,
|
||||||
IMediator mediator,
|
IMediator mediator,
|
||||||
IPublisher publisher,
|
IPublisher publisher,
|
||||||
ISubscriber subscriber,
|
ISubscriber subscriber,
|
||||||
IDisposer disposer) :
|
IDisposer disposer) :
|
||||||
ObservableViewModel(provider, factory, mediator, publisher, subscriber, disposer);
|
ObservableViewModel(provider, factory, mediator, publisher, subscriber, disposer)
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? password;
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void Unlock()
|
||||||
|
{
|
||||||
|
if (Password is { Length: > 0 })
|
||||||
|
{
|
||||||
|
Mediator.Handle<Open<Vault>, bool>(Open.As(new Vault(Password)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class OpenVaultHandler(IMediator mediator) :
|
||||||
|
IHandler<Open<Vault>, bool>
|
||||||
|
{
|
||||||
|
public async Task<bool> Handle(Open<Vault> args,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (args.Value is Vault vault)
|
||||||
|
{
|
||||||
|
if (vault.Password is { Length: > 0 } password)
|
||||||
|
{
|
||||||
|
if (await mediator.Handle<Open<VaultStorage>, bool>(Open.As(new VaultStorage("Personal", password)), cancellationToken))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class OpenVaultStorageHandler(IHostEnvironment environment,
|
||||||
|
IDbContextFactory<VaultDbContext> dbContextFactory) : IHandler<Open<VaultStorage>, bool>
|
||||||
|
{
|
||||||
|
public async Task<bool> Handle(Open<VaultStorage> args, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (args.Value is VaultStorage vault)
|
||||||
|
{
|
||||||
|
if (vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
||||||
|
{
|
||||||
|
using VaultDbContext context = dbContextFactory.CreateDbContext();
|
||||||
|
var d = context.Database.GetDbConnection().ConnectionString;
|
||||||
|
context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, name)}.vault;Mode=ReadWriteCreate;Password={password}");
|
||||||
|
|
||||||
|
bool isOpen = false;
|
||||||
|
await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await context.Database.OpenConnectionAsync();
|
||||||
|
isOpen = true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// We are ignoring this exception as it is either a go, or not.
|
||||||
|
}
|
||||||
|
|
||||||
|
}, cancellationToken);
|
||||||
|
|
||||||
|
return isOpen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
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)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
-2
@@ -1,3 +1,29 @@
|
|||||||
namespace Bitvault;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
public record Vault(string Name, string Password);
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public record Vault
|
||||||
|
{
|
||||||
|
public Vault(string name, string password)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vault(string password)
|
||||||
|
{
|
||||||
|
Password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Vault()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[MaybeNull]
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
[MaybeNull]
|
||||||
|
public string? Password { get; }
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class VaultCollectionInitializer(IEnumerable<IConfigurationDescriptor<VaultConfiguration>> configurations,
|
||||||
|
IComponentFactory componentFactory,
|
||||||
|
IVaultHostCollection vaults) : IInitializer
|
||||||
|
{
|
||||||
|
public async Task Initialize()
|
||||||
|
{
|
||||||
|
foreach (IConfigurationDescriptor<VaultConfiguration> configuration in configurations)
|
||||||
|
{
|
||||||
|
if (componentFactory.Create<IVaultComponent, VaultConfiguration>(configuration.Section, configuration.Value) is IComponentHost host)
|
||||||
|
{
|
||||||
|
vaults.Add(host);
|
||||||
|
await host.StartAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class VaultConnectionPersistence :
|
||||||
|
IVaultConnectionPersistence,
|
||||||
|
IDisposable
|
||||||
|
{
|
||||||
|
private string? connection;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
connection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Get(string key)
|
||||||
|
{
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(string key,
|
||||||
|
string connection)
|
||||||
|
{
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Toolkit.Foundation;
|
|
||||||
|
|
||||||
namespace Bitvault;
|
|
||||||
|
|
||||||
|
|
||||||
public class VaultHandler(IComponentFactory factory) :
|
|
||||||
IHandler<Create<Vault>, bool>
|
|
||||||
{
|
|
||||||
public async Task<bool> Handle(Create<Vault> args,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (args.Value is Vault vault)
|
|
||||||
{
|
|
||||||
if (factory.Create<IVaultComponent>($"Vault:{vault.Name}", new VaultConfiguration { Name = vault.Name }) is IComponentHost host)
|
|
||||||
{
|
|
||||||
if (host.Services.GetRequiredService<IMediator>() is IMediator mediator)
|
|
||||||
{
|
|
||||||
if (await mediator.Handle<Create<VaultStorage>, bool>(Create.As(new VaultStorage(vault.Name, vault.Password)), cancellationToken))
|
|
||||||
{
|
|
||||||
await host.StartAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Toolkit.Foundation;
|
|
||||||
|
|
||||||
namespace Bitvault;
|
|
||||||
|
|
||||||
public class VaultInitializer(IServiceProvider provider,
|
|
||||||
IProxyService<IPublisher> publisher) : IInitializer
|
|
||||||
{
|
|
||||||
public async Task Initialize()
|
|
||||||
{
|
|
||||||
if (provider.GetService<IComponentHost>() is IComponentHost vault)
|
|
||||||
{
|
|
||||||
if (vault.Services.GetRequiredService<VaultConfiguration>() is VaultConfiguration configuration)
|
|
||||||
{
|
|
||||||
if (vault.Services.GetRequiredService<IServiceFactory>() is IServiceFactory factory)
|
|
||||||
{
|
|
||||||
if (factory.Create<VaultNavigationViewModel>(configuration.Name) is VaultNavigationViewModel viewModel)
|
|
||||||
{
|
|
||||||
await publisher.Proxy.Publish(new Create<IMainNavigationViewModel>(viewModel),
|
|
||||||
nameof(MainViewModel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,27 @@
|
|||||||
using Toolkit.Foundation;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
namespace Bitvault;
|
namespace Bitvault;
|
||||||
|
|
||||||
public class VaultNavigationViewModelHandler(IPublisher publisher,
|
public class VaultNavigationViewModelHandler(IPublisher publisher,
|
||||||
IServiceFactory factory,
|
IVaultHostCollection vaults) :
|
||||||
IEnumerable<IConfigurationDescriptor<VaultConfiguration>> descriptors) :
|
|
||||||
INotificationHandler<Enumerate<IMainNavigationViewModel>>
|
INotificationHandler<Enumerate<IMainNavigationViewModel>>
|
||||||
{
|
{
|
||||||
public async Task Handle(Enumerate<IMainNavigationViewModel> args,
|
public async Task Handle(Enumerate<IMainNavigationViewModel> args,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
foreach (IConfigurationDescriptor<VaultConfiguration> descriptor in descriptors)
|
foreach (IComponentHost vault in vaults)
|
||||||
{
|
{
|
||||||
if (factory.Create<VaultNavigationViewModel>(descriptor.Value.Name) is VaultNavigationViewModel viewModel)
|
if (vault.Services.GetRequiredService<VaultConfiguration>() is VaultConfiguration configuration)
|
||||||
{
|
{
|
||||||
await publisher.Publish(new Create<IMainNavigationViewModel>(viewModel),
|
if (vault.Services.GetRequiredService<IServiceFactory>() is IServiceFactory factory)
|
||||||
nameof(MainViewModel), cancellationToken);
|
{
|
||||||
|
if (factory.Create<VaultNavigationViewModel>(configuration.Name) is VaultNavigationViewModel viewModel)
|
||||||
|
{
|
||||||
|
await publisher.Publish(new Create<IMainNavigationViewModel>(viewModel),
|
||||||
|
nameof(MainViewModel), cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Toolkit.Foundation;
|
|
||||||
|
|
||||||
namespace Bitvault;
|
|
||||||
|
|
||||||
public class VaultStorageHandler(IHostEnvironment environment,
|
|
||||||
IDbContextFactory<VaultDbContext> dbContextFactory) :
|
|
||||||
IHandler<Create<VaultStorage>, bool>
|
|
||||||
{
|
|
||||||
public async Task<bool> Handle(Create<VaultStorage> args, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (args.Value is VaultStorage storage)
|
|
||||||
{
|
|
||||||
using VaultDbContext context = dbContextFactory.CreateDbContext();
|
|
||||||
await Task.Run(async () =>
|
|
||||||
{
|
|
||||||
context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, storage.Name)}.vault;Mode=ReadWriteCreate;Password={storage.Password}");
|
|
||||||
await context.Database.EnsureCreatedAsync(cancellationToken);
|
|
||||||
}, cancellationToken);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Toolkit.Foundation;
|
|
||||||
|
|
||||||
namespace Bitvault;
|
|
||||||
|
|
||||||
public class VaultsInitializer(IEnumerable<IConfigurationDescriptor<VaultConfiguration>> configurations,
|
|
||||||
IVaultFactory factory) : IInitializer
|
|
||||||
{
|
|
||||||
public async Task Initialize()
|
|
||||||
{
|
|
||||||
foreach (IConfigurationDescriptor<VaultConfiguration> configuration in configurations)
|
|
||||||
{
|
|
||||||
//if (factory.Create(configuration.Section, configuration.Value) is IComponentHost host)
|
|
||||||
//{
|
|
||||||
// await host.StartAsync();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user