Bug fixes

This commit is contained in:
TheXamlGuy
2024-07-05 21:57:01 +01:00
parent e91c03d4de
commit bc5023c8ac
28 changed files with 208 additions and 106 deletions
+10 -11
View File
@@ -84,7 +84,8 @@ public partial class App : Application
services.AddTransient<IKeyDeriver, KeyDeriver>(); services.AddTransient<IKeyDeriver, KeyDeriver>();
services.AddTransient<ISecurityKeyFactory, SecurityKeyFactory>(); services.AddTransient<ISecurityKeyFactory, SecurityKeyFactory>();
services.AddTransient<IWalletStoreFactory, WalletStoreFactory>(); services.AddTransient<IWalletDatabaseFactory, WalletDatabaseFactory>();
services.AddTransient<IWalletConnectionFactory, WalletConnectionFactory>();
services.AddTransient<IInitialization, WalletProfileImageInitializer>(); services.AddTransient<IInitialization, WalletProfileImageInitializer>();
@@ -94,22 +95,19 @@ public partial class App : Application
provider.GetServices<IConfigurationDescriptor<ItemConfiguration>>().OrderBy(x => x.Name) ?? provider.GetServices<IConfigurationDescriptor<ItemConfiguration>>().OrderBy(x => x.Name) ??
Enumerable.Empty<IConfigurationDescriptor<ItemConfiguration>>(); Enumerable.Empty<IConfigurationDescriptor<ItemConfiguration>>();
return new ItemConfigurationCollection(items.ToDictionary(x => x.Name, x => (Func<ItemConfiguration>)(() => x.Value))); return new ItemConfigurationCollection(items.ToDictionary(x => x.Name,
x => (Func<ItemConfiguration>)(() => x.Value)));
}); });
services.TryAddSingleton<IDecoratorService<ProfileImage<IImageDescriptor>>, DecoratorService<ProfileImage<IImageDescriptor>>>(); services.TryAddSingleton<IDecoratorService<ProfileImage<IImageDescriptor>>,
DecoratorService<ProfileImage<IImageDescriptor>>>();
services.TryAddSingleton<IDecoratorService<SecurityKey>, DecoratorService<SecurityKey>>(); services.TryAddSingleton<IDecoratorService<SecurityKey>, DecoratorService<SecurityKey>>();
services.TryAddSingleton<IDecoratorService<WalletConnection>, DecoratorService<WalletConnection>>(); services.TryAddSingleton<IDecoratorService<WalletConnection>, DecoratorService<WalletConnection>>();
services.AddDbContextFactory<WalletContext>((provider, args) => services.AddTransient<IConnection>(provider => provider.GetRequiredService<IDecoratorService<WalletConnection>>().Value!);
{
if (provider.GetRequiredService<IDecoratorService<WalletConnection>>() services.AddDbContextFactory<WalletContext>();
is IDecoratorService<WalletConnection> connection)
{
args.UseSqlite($"{connection.Service}");
}
});
services.AddHandler<CreateProfileImageHandler>(); services.AddHandler<CreateProfileImageHandler>();
@@ -125,6 +123,7 @@ public partial class App : Application
services.AddHandler<CountCategoriesHandler>(); services.AddHandler<CountCategoriesHandler>();
services.AddHandler<OpenWalletHandler>(); services.AddHandler<OpenWalletHandler>();
services.AddHandler<CloseWalletHandler>();
services.AddTemplate<WalletNavigationViewModel, WalletNavigationView>(); services.AddTemplate<WalletNavigationViewModel, WalletNavigationView>();
+34 -4
View File
@@ -7,6 +7,11 @@
x:DataType="vm:WalletNavigationViewModel" x:DataType="vm:WalletNavigationViewModel"
ListBoxExtension.IsItemInvokedEnabled="True" ListBoxExtension.IsItemInvokedEnabled="True"
ToolTip.Tip="{Binding Name}"> ToolTip.Tip="{Binding Name}">
<ListBoxItem.Resources>
<x:Double x:Key="IconSize">40</x:Double>
<CornerRadius x:Key="IconCornerRadius">40</CornerRadius>
</ListBoxItem.Resources>
<Interaction.Behaviors> <Interaction.Behaviors>
<DataTriggerBehavior Binding="{Binding IsOpened}" Value="False"> <DataTriggerBehavior Binding="{Binding IsOpened}" Value="False">
<ConditionAction> <ConditionAction>
@@ -35,8 +40,33 @@
</ConditionAction> </ConditionAction>
</AttachedEventTriggerBehaviour> </AttachedEventTriggerBehaviour>
</Interaction.Behaviors> </Interaction.Behaviors>
<PersonPicture <Grid>
Height="40" <PersonPicture
DisplayName="{Binding Name}" Width="{StaticResource IconSize}"
ProfilePicture="{Binding ImageDescriptor.Image}" /> Height="{StaticResource IconSize}"
DisplayName="{Binding Name}"
ProfilePicture="{Binding ImageDescriptor.Image}" />
<Button
Width="{StaticResource IconSize}"
Height="{StaticResource IconSize}"
Background="Transparent"
CornerRadius="{StaticResource IconCornerRadius}"
IsVisible="{Binding IsActivated}">
<Button.Flyout>
<MenuFlyout>
<MenuItem
Width="216"
Command="{Binding LockCommand}"
Header="Lock">
<MenuItem.Icon>
<PathIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="F1 M 10 14.799999 C 10.266666 14.799999 10.499999 14.699999 10.7 14.5 C 10.9 14.299999 11 14.066667 11 13.799999 C 11 13.533333 10.9 13.299999 10.7 13.099999 C 10.499999 12.9 10.266666 12.799999 10 12.799999 C 9.733333 12.799999 9.499999 12.9 9.3 13.099999 C 9.099999 13.299999 9 13.533333 9 13.799999 C 9 14.066667 9.099999 14.299999 9.3 14.5 C 9.499999 14.699999 9.733333 14.799999 10 14.799999 Z M 6 7.799999 L 7 7.799999 L 7 6.799999 C 7 5.973333 7.293333 5.266666 7.88 4.68 C 8.466666 4.093334 9.173333 3.799999 10 3.799999 C 10.826666 3.799999 11.533333 4.093334 12.12 4.68 C 12.706666 5.266666 13 5.973333 13 6.799999 L 13 7.799999 L 14 7.799999 C 14.826666 7.799999 15.533332 8.093332 16.119999 8.679999 C 16.706665 9.266666 17 9.973333 17 10.799999 L 17 16.799999 C 17 17.626667 16.706665 18.333332 16.119999 18.92 C 15.533332 19.506666 14.826666 19.799999 14 19.799999 L 6 19.799999 C 5.173333 19.799999 4.466666 19.506666 3.88 18.92 C 3.293333 18.333332 3 17.626667 3 16.799999 L 3 10.799999 C 3 9.973333 3.293333 9.266666 3.88 8.679999 C 4.466666 8.093332 5.173333 7.799999 6 7.799999 Z M 10 4.799999 C 9.44 4.799999 8.966666 4.993332 8.58 5.379999 C 8.193333 5.766666 8 6.240001 8 6.799999 L 8 7.799999 L 12 7.799999 L 12 6.799999 C 12 6.240001 11.806666 5.766666 11.42 5.379999 C 11.033333 4.993332 10.559999 4.799999 10 4.799999 Z M 16 10.799999 C 16 10.24 15.806666 9.766666 15.42 9.379999 C 15.033333 8.993333 14.559999 8.799999 14 8.799999 L 6 8.799999 C 5.44 8.799999 4.966666 8.993333 4.58 9.379999 C 4.193333 9.766666 4 10.24 4 10.799999 L 4 16.799999 C 4 17.360001 4.193333 17.833332 4.58 18.219999 C 4.966666 18.606667 5.44 18.799999 6 18.799999 L 14 18.799999 C 14.559999 18.799999 15.033333 18.606667 15.42 18.219999 C 15.806666 17.833332 16 17.360001 16 16.799999 Z " />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
</ListBoxItem> </ListBoxItem>
+8 -2
View File
@@ -2,8 +2,9 @@
namespace Wallet.Data; namespace Wallet.Data;
public class WalletContext(DbContextOptions<WalletContext> options) : public interface IConnection;
DbContext(options)
public class WalletContext(IConnection connection) : DbContext
{ {
public DbSet<BlobEntry> Blobs { get; set; } public DbSet<BlobEntry> Blobs { get; set; }
@@ -11,6 +12,11 @@ public class WalletContext(DbContextOptions<WalletContext> options) :
public DbSet<TagEntry> Tags { get; set; } public DbSet<TagEntry> Tags { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite($"{connection}");
}
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
modelBuilder.Entity<ItemEntry>() modelBuilder.Entity<ItemEntry>()
+1 -1
View File
@@ -12,7 +12,7 @@ public class ArchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decorato
{ {
try try
{ {
if (decoratorService.Service is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
if (cache.Contains(item)) if (cache.Contains(item))
{ {
+19
View File
@@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
using Toolkit.Foundation;
using Wallet.Data;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database;
namespace Wallet;
public class CloseWalletHandler(IDecoratorService<WalletConnection> walletConnectionDecorator,
IDbContextFactory<WalletContext> dbContextFactory) :
IHandler<CloseEventArgs<Wallet>, bool>
{
public async Task<bool> Handle(CloseEventArgs<Wallet> args,
CancellationToken cancellationToken)
{
walletConnectionDecorator.Set(null);
return true;
}
}
+2 -2
View File
@@ -10,8 +10,8 @@ public class ConfirmCreateItemHandler(IMediator mediator,
{ {
public async Task Handle(ConfirmEventArgs<Item> args) public async Task Handle(ConfirmEventArgs<Item> args)
{ {
if (itemHeaderConfiguration.Service is ItemHeaderConfiguration headerConfiguration && if (itemHeaderConfiguration.Value is ItemHeaderConfiguration headerConfiguration &&
itemConfigurationDecorator.Service is ItemConfiguration itemConfiguration) itemConfigurationDecorator.Value is ItemConfiguration itemConfiguration)
{ {
if (headerConfiguration.Name is { Length: > 0 } name && if (headerConfiguration.Name is { Length: > 0 } name &&
headerConfiguration.Category is { Length: > 0 } category) headerConfiguration.Category is { Length: > 0 } category)
+1 -1
View File
@@ -12,7 +12,7 @@ public class ConfirmDeleteItemHandler(IDecoratorService<Item<(Guid, string)>> de
{ {
try try
{ {
if (decoratorService.Service is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
(Guid id, string name) = item.Value; (Guid id, string name) = item.Value;
+3 -3
View File
@@ -11,9 +11,9 @@ public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> it
{ {
public async Task Handle(ConfirmEventArgs<Item> args) public async Task Handle(ConfirmEventArgs<Item> args)
{ {
if (itemDecorator?.Service is Item<(Guid, string)> item && if (itemDecorator?.Value is Item<(Guid, string)> item &&
itemHeaderConfiguration.Service is ItemHeaderConfiguration headerConfiguration && itemHeaderConfiguration.Value is ItemHeaderConfiguration headerConfiguration &&
itemConfigurationDecorator.Service is ItemConfiguration itemConfiguration) itemConfigurationDecorator.Value is ItemConfiguration itemConfiguration)
{ {
if (headerConfiguration?.Name is { Length: > 0 } name && if (headerConfiguration?.Name is { Length: > 0 } name &&
headerConfiguration.Category is { Length: > 0 } category) headerConfiguration.Category is { Length: > 0 } category)
+2 -2
View File
@@ -20,8 +20,8 @@ public class CreateWalletHandler(IWalletHostFactory componentFactory,
{ {
if (componentFactory.Create(name) is IComponentHost host) if (componentFactory.Create(name) is IComponentHost host)
{ {
IWalletFactory factory = host.Services.GetRequiredService<IWalletFactory>(); IWalletFactory walletFactory = host.Services.GetRequiredService<IWalletFactory>();
if (await factory.Create(name, password, imageDescriptor)) if (await walletFactory.Create(name, password, imageDescriptor))
{ {
host.Start(); host.Start();
publisher.Publish(Activated.As(new Wallet<IComponentHost>(host))); publisher.Publish(Activated.As(new Wallet<IComponentHost>(host)));
+1 -1
View File
@@ -11,7 +11,7 @@ public class FavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> decora
{ {
try try
{ {
if (decoratorService.Service is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
(Guid id, string name) = item.Value; (Guid id, string name) = item.Value;
await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 1))); await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 1)));
+8
View File
@@ -0,0 +1,8 @@
namespace Wallet
{
public interface IWalletConnectionFactory
{
Task<WalletConnection?> Create(string name, string key);
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace Wallet;
public interface IWalletDatabaseFactory
{
Task<bool> Create(string name, string key);
}
-6
View File
@@ -1,6 +0,0 @@
namespace Wallet;
public interface IWalletStoreFactory
{
Task<bool> Create(string name, SecurityKey key);
}
@@ -12,7 +12,7 @@ public class ItemContentViewModelActivationHandler(IDecoratorService<Item<(Guid,
{ {
public async Task Handle(ActivationEventArgs<ItemSectionViewModel> args) public async Task Handle(ActivationEventArgs<ItemSectionViewModel> args)
{ {
if (itemDecorator.Service is Item<(Guid, string)> item) if (itemDecorator.Value is Item<(Guid, string)> item)
{ {
if (item.Value is (Guid Id, _)) if (item.Value is (Guid Id, _))
{ {
+1 -1
View File
@@ -21,7 +21,7 @@ public class MainViewModelActivationHandler(IPublisher publisher,
{ {
IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator = IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator =
Wallet.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>(); Wallet.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>();
ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Service; ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Value;
if (factory.Create<WalletNavigationViewModel>(args => args.Initialize(), configuration.Name, profileImage?.Value ?? null, selected) if (factory.Create<WalletNavigationViewModel>(args => args.Initialize(), configuration.Name, profileImage?.Value ?? null, selected)
is WalletNavigationViewModel viewModel) is WalletNavigationViewModel viewModel)
+9 -5
View File
@@ -5,10 +5,11 @@ namespace Wallet;
public class OpenWalletHandler(IConfigurationDescriptor<WalletConfiguration> descriptor, public class OpenWalletHandler(IConfigurationDescriptor<WalletConfiguration> descriptor,
ISecurityKeyFactory securityKeyFactory, ISecurityKeyFactory securityKeyFactory,
IWalletStoreFactory WalletStorageFactory) : IWalletConnectionFactory walletConnectionFactory,
IHandler<ActivateEventArgs<Wallet<string>>, bool> IDecoratorService<WalletConnection> walletConnectionDecorator) :
IHandler<OpenEventArgs<Wallet<string>>, bool>
{ {
public async Task<bool> Handle(ActivateEventArgs<Wallet<string>> args, public async Task<bool> Handle(OpenEventArgs<Wallet<string>> args,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (args.Sender is Wallet<string> Wallet && if (args.Sender is Wallet<string> Wallet &&
@@ -21,10 +22,13 @@ public class OpenWalletHandler(IConfigurationDescriptor<WalletConfiguration> des
byte[]? salt = Convert.FromBase64String(keyPart[0]); byte[]? salt = Convert.FromBase64String(keyPart[0]);
byte[]? encryptedKey = Convert.FromBase64String(keyPart[1]); byte[]? encryptedKey = Convert.FromBase64String(keyPart[1]);
if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password), encryptedKey, salt) is SecurityKey key) if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password),
encryptedKey, salt) is SecurityKey securityKey)
{ {
if (await WalletStorageFactory.Create(name, key)) if (await walletConnectionFactory.Create(name, Convert.ToBase64String(securityKey.DecryptedKey))
is WalletConnection connection)
{ {
walletConnectionDecorator.Set(connection);
return true; return true;
} }
} }
+1 -13
View File
@@ -43,23 +43,11 @@ public partial class OpenWalletViewModel :
using (await new ActivityLock(this)) using (await new ActivityLock(this))
{ {
if (await Validation.Validate(() => Password, [new ValidationRule(async () => if (await Validation.Validate(() => Password, [new ValidationRule(async () =>
await Mediator.Handle<ActivateEventArgs<Wallet<string>>, bool>(Activate.As(new Wallet<string>(Password))), await Mediator.Handle<OpenEventArgs<Wallet<string>>, bool>(Open.As(new Wallet<string>(Password))),
"The password is incorrect, please try again.")])) "The password is incorrect, please try again.")]))
{ {
Publisher.Publish(Opened.As<Wallet>()); Publisher.Publish(Opened.As<Wallet>());
} }
} }
} }
public override async Task OnActivated()
{
Publisher.Publish(Activated.As<Wallet>());
await base.OnActivated();
}
public override async Task OnDeactivated()
{
Publisher.Publish(Deactivated.As<Wallet>());
await base.OnDeactivated();
}
} }
+1 -1
View File
@@ -12,7 +12,7 @@ public class UnarchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decora
{ {
try try
{ {
if (decoratorService.Service is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
(Guid id, string name) = item.Value; (Guid id, string name) = item.Value;
+1 -1
View File
@@ -11,7 +11,7 @@ public class UnfavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> deco
{ {
try try
{ {
if (decoratorService.Service is Item<(Guid, string)> item) if (decoratorService.Value is Item<(Guid, string)> item)
{ {
(Guid id, string name) = item.Value; (Guid id, string name) = item.Value;
await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 0))); await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 0)));
+10
View File
@@ -8,6 +8,16 @@
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" Version="8.1.5" /> <PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" Version="8.1.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0-preview.5.24306.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0-preview.5.24306.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-preview.5.24306.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="9.0.0-preview.5.24306.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0-preview.5.24306.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlcipher" Version="2.1.8" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Toolkit\Toolkit.Avalonia\Toolkit.Avalonia.csproj" /> <ProjectReference Include="..\Toolkit\Toolkit.Avalonia\Toolkit.Avalonia.csproj" />
+1 -1
View File
@@ -25,7 +25,7 @@ public class WalletActivatedHandler(IWalletHostCollection Wallets,
IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator = IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator =
host.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>(); host.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>();
ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Service; ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Value;
if (serviceFactory.Create<WalletNavigationViewModel>(args => args.Initialize(), if (serviceFactory.Create<WalletNavigationViewModel>(args => args.Initialize(),
descriptor.Name, profileImage?.Value, false) descriptor.Name, profileImage?.Value, false)
is WalletNavigationViewModel viewModel) is WalletNavigationViewModel viewModel)
+2
View File
@@ -1,4 +1,6 @@
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using System.Linq;
using System.Xml.Linq;
using Toolkit.Foundation; using Toolkit.Foundation;
namespace Wallet; namespace Wallet;
+6 -5
View File
@@ -1,8 +1,9 @@
namespace Wallet; using Wallet.Data;
public record WalletConnection(string connection) namespace Wallet;
public record WalletConnection(string Value) :
IConnection
{ {
private readonly string connection = connection; public override string ToString() => Value;
public override string ToString() => connection;
} }
+35
View File
@@ -0,0 +1,35 @@
using Wallet.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
namespace Wallet;
public class WalletConnectionFactory(IHostEnvironment environment) :
IWalletConnectionFactory
{
public async Task<WalletConnection?> Create(string name, string key)
{
string databaseFile = $"{Path.Combine(environment.ContentRootPath, name)}.wallet";
if (File.Exists(databaseFile))
{
try
{
return await Task.Run(async () =>
{
WalletConnection connection = new($"Data Source={databaseFile};Mode=ReadWriteCreate;Pooling=true;Password={key}");
using WalletContext context = new(connection);
await context.Database.OpenConnectionAsync().ConfigureAwait(false);
return connection;
});
}
catch
{
return null;
}
}
return null;
}
}
+33
View File
@@ -0,0 +1,33 @@
using Wallet.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
namespace Wallet;
public class WalletDatabaseFactory(IHostEnvironment environment) :
IWalletDatabaseFactory
{
public async Task<bool> Create(string name, string key)
{
string databaseFile = $"{Path.Combine(environment.ContentRootPath, name)}.wallet";
try
{
WalletConnection connection = new($"Data Source={databaseFile};Mode=ReadWriteCreate;Pooling=true;Password={key}");
await Task.Run(async () =>
{
using WalletContext context = new(connection);
await context.Database.EnsureCreatedAsync();
context.Database.GetDbConnection().Close();
context.Database.SetConnectionString(null);
});
}
catch
{
return false;
}
return true;
}
}
+2 -5
View File
@@ -5,8 +5,7 @@ using Toolkit.Foundation;
namespace Wallet; namespace Wallet;
public class WalletFactory(ISecurityKeyFactory securityKeyFactory, public class WalletFactory(ISecurityKeyFactory securityKeyFactory,
IDecoratorService<SecurityKey> secureKeyStore, IWalletDatabaseFactory walletDatabaseFactory,
IWalletStoreFactory walletStoreFactory,
IWritableConfiguration<WalletConfiguration> configuration, IWritableConfiguration<WalletConfiguration> configuration,
IHostEnvironment environment, IHostEnvironment environment,
IImageWriter imageWriter) : IImageWriter imageWriter) :
@@ -18,9 +17,7 @@ public class WalletFactory(ISecurityKeyFactory securityKeyFactory,
{ {
if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key) if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key)
{ {
secureKeyStore.Set(key); if (await walletDatabaseFactory.Create(name, Convert.ToBase64String(key.DecryptedKey)))
if (await walletStoreFactory.Create(name, key))
{ {
configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:" + configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:" +
$"{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}"); $"{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}");
+10
View File
@@ -1,4 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Toolkit.Foundation; using Toolkit.Foundation;
namespace Wallet; namespace Wallet;
@@ -77,6 +78,15 @@ public partial class WalletNavigationViewModel :
return Task.CompletedTask; return Task.CompletedTask;
} }
[RelayCommand]
private async Task Lock()
{
if (await Mediator.Handle<CloseEventArgs<Wallet>, bool>(Close.As<Wallet>()))
{
IsOpened = false;
}
}
public Task Handle(ActivatedEventArgs<Wallet> args) public Task Handle(ActivatedEventArgs<Wallet> args)
{ {
IsActivated = true; IsActivated = true;
-40
View File
@@ -1,40 +0,0 @@
using Wallet.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Toolkit.Foundation;
namespace Wallet;
public class WalletStoreFactory(IDecoratorService<WalletConnection> connection,
IHostEnvironment environment,
IServiceProvider provider) :
IWalletStoreFactory
{
public async Task<bool> Create(string name,
SecurityKey key)
{
connection.Set(new WalletConnection($"Data Source={Path.Combine(environment.ContentRootPath, name)}" +
$".wallet;Mode=ReadWriteCreate;Pooling=true;Password={Convert.ToBase64String(key.DecryptedKey)}"));
IDbContextFactory<WalletContext> dbContextFactory = provider.GetRequiredService<IDbContextFactory<WalletContext>>();
using WalletContext context = await dbContextFactory.CreateDbContextAsync();
try
{
await Task.Run(async () =>
{
await context.Database.EnsureCreatedAsync().ConfigureAwait(false);
await context.Database.CloseConnectionAsync().ConfigureAwait(false);
context.Database.SetConnectionString(null);
}).ConfigureAwait(false);
}
catch
{
return false;
}
return true;
}
}