diff --git a/Bitvault.Avalonia/App.axaml.cs b/Bitvault.Avalonia/App.axaml.cs index 8e2b00d..10c3763 100644 --- a/Bitvault.Avalonia/App.axaml.cs +++ b/Bitvault.Avalonia/App.axaml.cs @@ -76,7 +76,7 @@ public partial class App : Application services.AddTemplate(); services.AddTemplate("Vault"); - services.AddTemplate("Lock"); + services.AddTemplate("Open"); }); })!); diff --git a/Bitvault.Avalonia/Bitvault.Avalonia.csproj b/Bitvault.Avalonia/Bitvault.Avalonia.csproj index 6c3b0b5..3baccb9 100644 --- a/Bitvault.Avalonia/Bitvault.Avalonia.csproj +++ b/Bitvault.Avalonia/Bitvault.Avalonia.csproj @@ -32,6 +32,9 @@ + + OpenVaultView.axaml + ManageNavigationView.axaml diff --git a/Bitvault.Avalonia/LockView.axaml.cs b/Bitvault.Avalonia/LockView.axaml.cs deleted file mode 100644 index b54fa07..0000000 --- a/Bitvault.Avalonia/LockView.axaml.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Avalonia.Controls; - -namespace Bitvault.Avalonia; - -public partial class LockView : UserControl -{ - public LockView() => InitializeComponent(); -} \ No newline at end of file diff --git a/Bitvault.Avalonia/MainView.axaml b/Bitvault.Avalonia/MainView.axaml index beb0c77..f2b5e96 100644 --- a/Bitvault.Avalonia/MainView.axaml +++ b/Bitvault.Avalonia/MainView.axaml @@ -8,6 +8,10 @@ FooterMenuItemsSource="{Binding Footer}" MenuItemTemplate="{Binding Template}" MenuItemsSource="{Binding}"> + + 0 + 1,0,0,0 + diff --git a/Bitvault.Avalonia/LockView.axaml b/Bitvault.Avalonia/OpenVaultView.axaml similarity index 78% rename from Bitvault.Avalonia/LockView.axaml rename to Bitvault.Avalonia/OpenVaultView.axaml index 959c287..eeaecaa 100644 --- a/Bitvault.Avalonia/LockView.axaml +++ b/Bitvault.Avalonia/OpenVaultView.axaml @@ -1,9 +1,9 @@ + x:DataType="vm:OpenVaultViewModel"> - + diff --git a/Bitvault.Avalonia/OpenVaultView.axaml.cs b/Bitvault.Avalonia/OpenVaultView.axaml.cs new file mode 100644 index 0000000..224eecd --- /dev/null +++ b/Bitvault.Avalonia/OpenVaultView.axaml.cs @@ -0,0 +1,8 @@ +using Avalonia.Controls; + +namespace Bitvault.Avalonia; + +public partial class OpenVaultView : UserControl +{ + public OpenVaultView() => InitializeComponent(); +} \ No newline at end of file diff --git a/Bitvault.Avalonia/VaultNavigationView.axaml b/Bitvault.Avalonia/VaultNavigationView.axaml index bbc1c41..f87f27c 100644 --- a/Bitvault.Avalonia/VaultNavigationView.axaml +++ b/Bitvault.Avalonia/VaultNavigationView.axaml @@ -5,10 +5,39 @@ xmlns:vm="using:Bitvault" x:DataType="vm:VaultNavigationViewModel" Content="{Binding Name}" + IsExpanded="{Binding Expanded, Mode=TwoWay}" + IsSelected="{Binding Selected}" MenuItemsSource="{Binding}"> + + + + + + + + + + + + + + + + + + + + - + + + + + + + + diff --git a/Bitvault/Locked.cs b/Bitvault/Closed.cs similarity index 53% rename from Bitvault/Locked.cs rename to Bitvault/Closed.cs index 79802a6..26c2740 100644 --- a/Bitvault/Locked.cs +++ b/Bitvault/Closed.cs @@ -1,3 +1,3 @@ namespace Bitvault; -public record Locked; \ No newline at end of file +public record Closed; \ No newline at end of file diff --git a/Bitvault/CreateVaultHandler.cs b/Bitvault/CreateVaultHandler.cs index e27a4c4..3b60518 100644 --- a/Bitvault/CreateVaultHandler.cs +++ b/Bitvault/CreateVaultHandler.cs @@ -20,18 +20,20 @@ public class CreateVaultHandler(IVaultComponentFactory componentFactory) : IContainer vaultKeyContainer = host.Services.GetRequiredService>(); IVaultStorage vaultStorage = host.Services.GetRequiredService(); - VaultKey key = keyVaultFactory.Create(Encoding.UTF8.GetBytes(password)); - vaultKeyContainer.Set(key); - - if (await vaultStorage.CreateAsync(name, key)) + if (keyVaultFactory.Create(Encoding.UTF8.GetBytes(password)) is VaultKey key) { - IWritableConfiguration configuration = - host.Services.GetRequiredService>(); + vaultKeyContainer.Set(key); - configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}"); - host.Start(); + if (await vaultStorage.Create(name, key)) + { + IWritableConfiguration configuration = + host.Services.GetRequiredService>(); - return true; + configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}"); + host.Start(); + + return true; + } } } } diff --git a/Bitvault/IVaultKeyFactory.cs b/Bitvault/IVaultKeyFactory.cs index 1037ba8..34b6c80 100644 --- a/Bitvault/IVaultKeyFactory.cs +++ b/Bitvault/IVaultKeyFactory.cs @@ -2,7 +2,7 @@ public interface IVaultKeyFactory { - VaultKey Create(byte[] phrase, + VaultKey? Create(byte[] phrase, byte[]? encryptedKey = null, byte[]? salt = null); } diff --git a/Bitvault/IVaultStorage.cs b/Bitvault/IVaultStorage.cs index cd11ca6..4cf54f0 100644 --- a/Bitvault/IVaultStorage.cs +++ b/Bitvault/IVaultStorage.cs @@ -2,5 +2,5 @@ public interface IVaultStorage { - Task CreateAsync(string name, VaultKey key); + Task Create(string name, VaultKey key); } \ No newline at end of file diff --git a/Bitvault/OpenVaultHandler.cs b/Bitvault/OpenVaultHandler.cs index 077fff8..e842c03 100644 --- a/Bitvault/OpenVaultHandler.cs +++ b/Bitvault/OpenVaultHandler.cs @@ -18,10 +18,12 @@ public class OpenVaultHandler(VaultConfiguration configuration, byte[]? salt = Convert.FromBase64String(keyPart[0]); byte[]? encryptedKey = Convert.FromBase64String(keyPart[1]); - VaultKey key = keyVaultFactory.Create(Encoding.UTF8.GetBytes(password), encryptedKey, salt); - if (await vaultStorage.CreateAsync(name, key)) + if ( keyVaultFactory.Create(Encoding.UTF8.GetBytes(password), encryptedKey, salt) is VaultKey key) { - + if (await vaultStorage.Create(name, key)) + { + return true; + } } } } diff --git a/Bitvault/LockViewModel.cs b/Bitvault/OpenVaultViewModel.cs similarity index 65% rename from Bitvault/LockViewModel.cs rename to Bitvault/OpenVaultViewModel.cs index a87e320..1293b7d 100644 --- a/Bitvault/LockViewModel.cs +++ b/Bitvault/OpenVaultViewModel.cs @@ -4,7 +4,7 @@ using Toolkit.Foundation; namespace Bitvault; -public partial class LockViewModel(IServiceProvider provider, +public partial class OpenVaultViewModel(IServiceProvider provider, IServiceFactory factory, IMediator mediator, IPublisher publisher, @@ -16,11 +16,14 @@ public partial class LockViewModel(IServiceProvider provider, private string? password; [RelayCommand] - private void Unlock() + private async Task Invoke() { if (Password is { Length: > 0 }) { - Mediator.Handle, bool>(Open.As(new Vault(Password))); + if (await Mediator.Handle, bool>(Open.As(new Vault(Password)))) + { + await Publisher.Publish(); + } } } } \ No newline at end of file diff --git a/Bitvault/Unlocked.cs b/Bitvault/Opened.cs similarity index 51% rename from Bitvault/Unlocked.cs rename to Bitvault/Opened.cs index 551b9f9..dc99b08 100644 --- a/Bitvault/Unlocked.cs +++ b/Bitvault/Opened.cs @@ -1,3 +1,3 @@ namespace Bitvault; -public record Unlocked; \ No newline at end of file +public record Opened; \ No newline at end of file diff --git a/Bitvault/VaultKeyFactory.cs b/Bitvault/VaultKeyFactory.cs index 3598b6d..dba3791 100644 --- a/Bitvault/VaultKeyFactory.cs +++ b/Bitvault/VaultKeyFactory.cs @@ -8,15 +8,25 @@ public class VaultKeyFactory(IKeyGenerator generator, IDecryptor decryptor) : IVaultKeyFactory { - public VaultKey Create(byte[] phrase, + public VaultKey? Create(byte[] phrase, byte[]? encryptedKey = null, byte[]? salt = null) { salt ??= generator.Generate(16); byte[] derivedKey = deriver.DeriveKey(phrase, salt); - encryptedKey ??= encryptor.Encrypt(generator.Generate(32), derivedKey); - byte[] decryptedKey = decryptor.Decrypt(encryptedKey, derivedKey); + if (encryptedKey is null) + { + if (!encryptor.TryEncrypt(generator.Generate(32), derivedKey, out encryptedKey) || encryptedKey is null) + { + return default; + } + } + + if (!decryptor.TryDecrypt(encryptedKey, derivedKey, out byte[]? decryptedKey) || decryptedKey is null) + { + return default; + } return new VaultKey(salt, encryptedKey, decryptedKey); } diff --git a/Bitvault/VaultNavigationViewModel.cs b/Bitvault/VaultNavigationViewModel.cs index 7c8dbc6..e33aec4 100644 --- a/Bitvault/VaultNavigationViewModel.cs +++ b/Bitvault/VaultNavigationViewModel.cs @@ -6,15 +6,21 @@ namespace Bitvault; public partial class VaultNavigationViewModel : ObservableCollectionViewModel, IMainNavigationViewModel, - INotificationHandler, - INotificationHandler + INotificationHandler, + INotificationHandler { [ObservableProperty] - private bool locked; + private bool expanded = true; [ObservableProperty] private string name; + [ObservableProperty] + private bool opened; + + [ObservableProperty] + private bool selected; + public VaultNavigationViewModel(IServiceProvider provider, IServiceFactory factory, IMediator mediator, @@ -30,9 +36,9 @@ public partial class VaultNavigationViewModel : public IContentTemplate Template { get; set; } - public Task Handle(Unlocked args, CancellationToken cancellationToken = default) + public Task Handle(Opened args, CancellationToken cancellationToken = default) { - Locked = true; + Opened = true; Add(); Add(); @@ -42,9 +48,9 @@ public partial class VaultNavigationViewModel : return Task.CompletedTask; } - public Task Handle(Locked args, CancellationToken cancellationToken = default) + public Task Handle(Closed args, CancellationToken cancellationToken = default) { - Locked = true; + Opened = true; Clear(); return Task.CompletedTask; diff --git a/Bitvault/VaultStorage.cs b/Bitvault/VaultStorage.cs index 0c8e406..582b92e 100644 --- a/Bitvault/VaultStorage.cs +++ b/Bitvault/VaultStorage.cs @@ -10,7 +10,7 @@ public class VaultStorage(IContainer connection, IServiceProvider provider) : IVaultStorage { - public async Task CreateAsync(string name, + public async Task Create(string name, VaultKey key) { connection.Set(new VaultStorageConnection($"Data Source={Path.Combine(environment.ContentRootPath, name)}" +