vault unlocking WIP
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Bitvault.Avalonia;
|
||||
|
||||
public partial class LockView : UserControl
|
||||
{
|
||||
public LockView() => InitializeComponent();
|
||||
}
|
||||
@@ -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>
|
||||
@@ -0,0 +1,8 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Bitvault.Avalonia;
|
||||
|
||||
public partial class OpenVaultView : UserControl
|
||||
{
|
||||
public OpenVaultView() => InitializeComponent();
|
||||
}
|
||||
@@ -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,3 +1,3 @@
|
||||
namespace Bitvault;
|
||||
|
||||
public record Locked;
|
||||
public record Closed;
|
||||
@@ -20,10 +20,11 @@ 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));
|
||||
if (keyVaultFactory.Create(Encoding.UTF8.GetBytes(password)) is VaultKey key)
|
||||
{
|
||||
vaultKeyContainer.Set(key);
|
||||
|
||||
if (await vaultStorage.CreateAsync(name, key))
|
||||
if (await vaultStorage.Create(name, key))
|
||||
{
|
||||
IWritableConfiguration<VaultConfiguration> configuration =
|
||||
host.Services.GetRequiredService<IWritableConfiguration<VaultConfiguration>>();
|
||||
@@ -35,6 +36,7 @@ public class CreateVaultHandler(IVaultComponentFactory componentFactory) :
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
public interface IVaultKeyFactory
|
||||
{
|
||||
VaultKey Create(byte[] phrase,
|
||||
VaultKey? Create(byte[] phrase,
|
||||
byte[]? encryptedKey = null,
|
||||
byte[]? salt = null);
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
public interface IVaultStorage
|
||||
{
|
||||
Task<bool> CreateAsync(string name, VaultKey key);
|
||||
Task<bool> Create(string name, VaultKey key);
|
||||
}
|
||||
@@ -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,3 +1,3 @@
|
||||
namespace Bitvault;
|
||||
|
||||
public record Unlocked;
|
||||
public record Opened;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)}" +
|
||||
|
||||
Reference in New Issue
Block a user