Bug fixes
This commit is contained in:
@@ -12,7 +12,7 @@ public class ArchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decorato
|
||||
{
|
||||
try
|
||||
{
|
||||
if (decoratorService.Service is Item<(Guid, string)> item)
|
||||
if (decoratorService.Value is Item<(Guid, string)> item)
|
||||
{
|
||||
if (cache.Contains(item))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ public class ConfirmCreateItemHandler(IMediator mediator,
|
||||
{
|
||||
public async Task Handle(ConfirmEventArgs<Item> args)
|
||||
{
|
||||
if (itemHeaderConfiguration.Service is ItemHeaderConfiguration headerConfiguration &&
|
||||
itemConfigurationDecorator.Service is ItemConfiguration itemConfiguration)
|
||||
if (itemHeaderConfiguration.Value is ItemHeaderConfiguration headerConfiguration &&
|
||||
itemConfigurationDecorator.Value is ItemConfiguration itemConfiguration)
|
||||
{
|
||||
if (headerConfiguration.Name is { Length: > 0 } name &&
|
||||
headerConfiguration.Category is { Length: > 0 } category)
|
||||
|
||||
@@ -12,7 +12,7 @@ public class ConfirmDeleteItemHandler(IDecoratorService<Item<(Guid, string)>> de
|
||||
{
|
||||
try
|
||||
{
|
||||
if (decoratorService.Service is Item<(Guid, string)> item)
|
||||
if (decoratorService.Value is Item<(Guid, string)> item)
|
||||
{
|
||||
(Guid id, string name) = item.Value;
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ public class ConfirmUpdateItemHandler(IDecoratorService<Item<(Guid, string)>> it
|
||||
{
|
||||
public async Task Handle(ConfirmEventArgs<Item> args)
|
||||
{
|
||||
if (itemDecorator?.Service is Item<(Guid, string)> item &&
|
||||
itemHeaderConfiguration.Service is ItemHeaderConfiguration headerConfiguration &&
|
||||
itemConfigurationDecorator.Service is ItemConfiguration itemConfiguration)
|
||||
if (itemDecorator?.Value is Item<(Guid, string)> item &&
|
||||
itemHeaderConfiguration.Value is ItemHeaderConfiguration headerConfiguration &&
|
||||
itemConfigurationDecorator.Value is ItemConfiguration itemConfiguration)
|
||||
{
|
||||
if (headerConfiguration?.Name is { Length: > 0 } name &&
|
||||
headerConfiguration.Category is { Length: > 0 } category)
|
||||
|
||||
@@ -20,8 +20,8 @@ public class CreateWalletHandler(IWalletHostFactory componentFactory,
|
||||
{
|
||||
if (componentFactory.Create(name) is IComponentHost host)
|
||||
{
|
||||
IWalletFactory factory = host.Services.GetRequiredService<IWalletFactory>();
|
||||
if (await factory.Create(name, password, imageDescriptor))
|
||||
IWalletFactory walletFactory = host.Services.GetRequiredService<IWalletFactory>();
|
||||
if (await walletFactory.Create(name, password, imageDescriptor))
|
||||
{
|
||||
host.Start();
|
||||
publisher.Publish(Activated.As(new Wallet<IComponentHost>(host)));
|
||||
|
||||
@@ -11,7 +11,7 @@ public class FavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> decora
|
||||
{
|
||||
try
|
||||
{
|
||||
if (decoratorService.Service is Item<(Guid, string)> item)
|
||||
if (decoratorService.Value is Item<(Guid, string)> item)
|
||||
{
|
||||
(Guid id, string name) = item.Value;
|
||||
await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 1)));
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
namespace Wallet
|
||||
{
|
||||
public interface IWalletConnectionFactory
|
||||
{
|
||||
Task<WalletConnection?> Create(string name, string key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Wallet;
|
||||
|
||||
public interface IWalletDatabaseFactory
|
||||
{
|
||||
Task<bool> Create(string name, string key);
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
if (itemDecorator.Service is Item<(Guid, string)> item)
|
||||
if (itemDecorator.Value is Item<(Guid, string)> item)
|
||||
{
|
||||
if (item.Value is (Guid Id, _))
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ public class MainViewModelActivationHandler(IPublisher publisher,
|
||||
{
|
||||
IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator =
|
||||
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)
|
||||
is WalletNavigationViewModel viewModel)
|
||||
|
||||
@@ -5,10 +5,11 @@ namespace Wallet;
|
||||
|
||||
public class OpenWalletHandler(IConfigurationDescriptor<WalletConfiguration> descriptor,
|
||||
ISecurityKeyFactory securityKeyFactory,
|
||||
IWalletStoreFactory WalletStorageFactory) :
|
||||
IHandler<ActivateEventArgs<Wallet<string>>, bool>
|
||||
IWalletConnectionFactory walletConnectionFactory,
|
||||
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)
|
||||
{
|
||||
if (args.Sender is Wallet<string> Wallet &&
|
||||
@@ -21,10 +22,13 @@ public class OpenWalletHandler(IConfigurationDescriptor<WalletConfiguration> des
|
||||
byte[]? salt = Convert.FromBase64String(keyPart[0]);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,23 +43,11 @@ public partial class OpenWalletViewModel :
|
||||
using (await new ActivityLock(this))
|
||||
{
|
||||
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.")]))
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class UnarchiveItemHandler(IDecoratorService<Item<(Guid, string)>> decora
|
||||
{
|
||||
try
|
||||
{
|
||||
if (decoratorService.Service is Item<(Guid, string)> item)
|
||||
if (decoratorService.Value is Item<(Guid, string)> item)
|
||||
{
|
||||
(Guid id, string name) = item.Value;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ public class UnfavouriteItemHandler(IDecoratorService<Item<(Guid, string)>> deco
|
||||
{
|
||||
try
|
||||
{
|
||||
if (decoratorService.Service is Item<(Guid, string)> item)
|
||||
if (decoratorService.Value is Item<(Guid, string)> item)
|
||||
{
|
||||
(Guid id, string name) = item.Value;
|
||||
await mediator.Handle<UpdateEventArgs<(Guid, int)>, bool>(new UpdateEventArgs<(Guid, int)>((id, 0)));
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<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.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>
|
||||
<ProjectReference Include="..\Toolkit\Toolkit.Avalonia\Toolkit.Avalonia.csproj" />
|
||||
|
||||
@@ -25,7 +25,7 @@ public class WalletActivatedHandler(IWalletHostCollection Wallets,
|
||||
IDecoratorService<ProfileImage<IImageDescriptor>> profileImageDecorator =
|
||||
host.Services.GetRequiredService<IDecoratorService<ProfileImage<IImageDescriptor>>>();
|
||||
|
||||
ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Service;
|
||||
ProfileImage<IImageDescriptor>? profileImage = profileImageDecorator.Value;
|
||||
if (serviceFactory.Create<WalletNavigationViewModel>(args => args.Initialize(),
|
||||
descriptor.Name, profileImage?.Value, false)
|
||||
is WalletNavigationViewModel viewModel)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Toolkit.Foundation;
|
||||
|
||||
namespace Wallet;
|
||||
|
||||
@@ -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() => connection;
|
||||
public override string ToString() => Value;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,7 @@ using Toolkit.Foundation;
|
||||
namespace Wallet;
|
||||
|
||||
public class WalletFactory(ISecurityKeyFactory securityKeyFactory,
|
||||
IDecoratorService<SecurityKey> secureKeyStore,
|
||||
IWalletStoreFactory walletStoreFactory,
|
||||
IWalletDatabaseFactory walletDatabaseFactory,
|
||||
IWritableConfiguration<WalletConfiguration> configuration,
|
||||
IHostEnvironment environment,
|
||||
IImageWriter imageWriter) :
|
||||
@@ -18,9 +17,7 @@ public class WalletFactory(ISecurityKeyFactory securityKeyFactory,
|
||||
{
|
||||
if (securityKeyFactory.Create(Encoding.UTF8.GetBytes(password)) is SecurityKey key)
|
||||
{
|
||||
secureKeyStore.Set(key);
|
||||
|
||||
if (await walletStoreFactory.Create(name, key))
|
||||
if (await walletDatabaseFactory.Create(name, Convert.ToBase64String(key.DecryptedKey)))
|
||||
{
|
||||
configuration.Write(args => args.Key = $"{Convert.ToBase64String(key.Salt)}:" +
|
||||
$"{Convert.ToBase64String(key.EncryptedKey)}:{Convert.ToBase64String(key.DecryptedKey)}");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Toolkit.Foundation;
|
||||
|
||||
namespace Wallet;
|
||||
@@ -77,6 +78,15 @@ public partial class WalletNavigationViewModel :
|
||||
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)
|
||||
{
|
||||
IsActivated = true;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user