vault unlocking WIP

This commit is contained in:
TheXamlGuy
2024-05-03 19:33:32 +01:00
parent b17be4b0b8
commit e8b9eb7ae5
17 changed files with 102 additions and 43 deletions
+1 -1
View File
@@ -76,7 +76,7 @@ public partial class App : Application
services.AddTemplate<ArchiveNavigationViewModel, ArchiveNavigationView>();
services.AddTemplate<VaultViewModel, VaultView>("Vault");
services.AddTemplate<LockViewModel, LockView>("Lock");
services.AddTemplate<OpenVaultViewModel, OpenVaultView>("Open");
});
})!);
@@ -32,6 +32,9 @@
<ProjectReference Include="..\Toolkit\Toolkit.UI.Controls.Avalonia\Toolkit.UI.Controls.Avalonia.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="OpenVaultView.axaml.cs">
<DependentUpon>OpenVaultView.axaml</DependentUpon>
</Compile>
<Compile Update="ManageNavigationView.axaml.cs">
<DependentUpon>ManageNavigationView.axaml</DependentUpon>
</Compile>
-8
View File
@@ -1,8 +0,0 @@
using Avalonia.Controls;
namespace Bitvault.Avalonia;
public partial class LockView : UserControl
{
public LockView() => InitializeComponent();
}
+4
View File
@@ -8,6 +8,10 @@
FooterMenuItemsSource="{Binding Footer}"
MenuItemTemplate="{Binding Template}"
MenuItemsSource="{Binding}">
<NavigationView.Resources>
<CornerRadius x:Key="NavigationViewContentGridCornerRadius">0</CornerRadius>
<Thickness x:Key="NavigationViewContentGridBorderThickness">1,0,0,0</Thickness>
</NavigationView.Resources>
<Frame x:Name="Main">
<Interaction.Behaviors>
<EventTriggerBehavior EventName="Loaded">
@@ -1,9 +1,9 @@
<UserControl
x:Class="Bitvault.Avalonia.LockView"
x:Class="Bitvault.Avalonia.OpenVaultView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Bitvault"
x:DataType="vm:LockViewModel">
x:DataType="vm:OpenVaultViewModel">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox
Width="300"
@@ -12,7 +12,7 @@
Text="{Binding Password}">
<Interaction.Behaviors>
<KeyBindingTriggerBehavior Gesture="Enter">
<InvokeCommandAction Command="{Binding UnlockCommand}" />
<InvokeCommandAction Command="{Binding InvokeCommand}" />
</KeyBindingTriggerBehavior>
</Interaction.Behaviors>
</TextBox>
+8
View File
@@ -0,0 +1,8 @@
using Avalonia.Controls;
namespace Bitvault.Avalonia;
public partial class OpenVaultView : UserControl
{
public OpenVaultView() => InitializeComponent();
}
+30 -1
View File
@@ -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}">
<Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding Opened}" Value="False">
<ConditionAction>
<ConditionAction.Condition>
<ConditionalExpression ForwardChaining="And">
<ComparisonCondition LeftOperand="{Binding Selected}" RightOperand="True" />
</ConditionalExpression>
</ConditionAction.Condition>
<NavigateAction Context="Main" Route="Open" />
</ConditionAction>
</DataTriggerBehavior>
<DataTriggerBehavior Binding="{Binding Opened}" Value="True">
<ConditionAction>
<ConditionAction.Condition>
<ConditionalExpression ForwardChaining="And">
<ComparisonCondition LeftOperand="{Binding Selected}" RightOperand="True" />
</ConditionalExpression>
</ConditionAction.Condition>
<NavigateAction Context="Main" Route="Vault" />
</ConditionAction>
</DataTriggerBehavior>
<EventTriggerBehavior EventName="Tapped">
<NavigateAction Context="Main" Route="Lock" />
<ConditionAction>
<ConditionAction.Condition>
<ConditionalExpression ForwardChaining="And">
<ComparisonCondition LeftOperand="{Binding Opened}" RightOperand="False" />
</ConditionalExpression>
</ConditionAction.Condition>
<NavigateAction Context="Main" Route="Open" />
</ConditionAction>
</EventTriggerBehavior>
</Interaction.Behaviors>
</NavigationViewItem>
+1 -1
View File
@@ -1,3 +1,3 @@
namespace Bitvault;
public record Locked;
public record Closed;
+11 -9
View File
@@ -20,18 +20,20 @@ public class CreateVaultHandler(IVaultComponentFactory componentFactory) :
IContainer<VaultKey> vaultKeyContainer = host.Services.GetRequiredService<IContainer<VaultKey>>();
IVaultStorage vaultStorage = host.Services.GetRequiredService<IVaultStorage>();
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<VaultConfiguration> configuration =
host.Services.GetRequiredService<IWritableConfiguration<VaultConfiguration>>();
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<VaultConfiguration> configuration =
host.Services.GetRequiredService<IWritableConfiguration<VaultConfiguration>>();
return true;
configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}");
host.Start();
return true;
}
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
public interface IVaultKeyFactory
{
VaultKey Create(byte[] phrase,
VaultKey? Create(byte[] phrase,
byte[]? encryptedKey = null,
byte[]? salt = null);
}
+1 -1
View File
@@ -2,5 +2,5 @@
public interface IVaultStorage
{
Task<bool> CreateAsync(string name, VaultKey key);
Task<bool> Create(string name, VaultKey key);
}
+5 -3
View File
@@ -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;
}
}
}
}
@@ -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<Open<Vault>, bool>(Open.As(new Vault(Password)));
if (await Mediator.Handle<Open<Vault>, bool>(Open.As(new Vault(Password))))
{
await Publisher.Publish<Opened>();
}
}
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
namespace Bitvault;
public record Unlocked;
public record Opened;
+13 -3
View File
@@ -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);
}
+13 -7
View File
@@ -6,15 +6,21 @@ namespace Bitvault;
public partial class VaultNavigationViewModel :
ObservableCollectionViewModel<IVaultNavigationViewModel>,
IMainNavigationViewModel,
INotificationHandler<Unlocked>,
INotificationHandler<Locked>
INotificationHandler<Opened>,
INotificationHandler<Closed>
{
[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<AllNavigationViewModel>();
Add<StarredNavigationViewModel>();
@@ -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;
+1 -1
View File
@@ -10,7 +10,7 @@ public class VaultStorage(IContainer<VaultStorageConnection> connection,
IServiceProvider provider) :
IVaultStorage
{
public async Task<bool> CreateAsync(string name,
public async Task<bool> Create(string name,
VaultKey key)
{
connection.Set(new VaultStorageConnection($"Data Source={Path.Combine(environment.ContentRootPath, name)}" +