vault unlocking WIP

This commit is contained in:
TheXamlGuy
2024-05-03 19:33:32 +01:00
parent 7582f63a68
commit abcff30da6
9 changed files with 92 additions and 43 deletions
+1 -4
View File
@@ -6,8 +6,5 @@ namespace Toolkit.Avalonia;
public class AvaloniaDispatcher : public class AvaloniaDispatcher :
IDispatcher IDispatcher
{ {
public async Task InvokeAsync(Action action) public async Task Invoke(Action action) => await Dispatcher.UIThread.InvokeAsync(action);
{
await Dispatcher.UIThread.InvokeAsync(action);
}
} }
+1 -1
View File
@@ -79,7 +79,7 @@ public class ContentDialogHandler(IDispatcher dispatcher) :
async void DeactivateHandler(object? sender, EventArgs args) async void DeactivateHandler(object? sender, EventArgs args)
{ {
deactivatable.DeactivateHandler -= DeactivateHandler; deactivatable.DeactivateHandler -= DeactivateHandler;
await dispatcher.InvokeAsync(contentDialog.Hide); await dispatcher.Invoke(contentDialog.Hide);
} }
deactivatable.DeactivateHandler += DeactivateHandler; deactivatable.DeactivateHandler += DeactivateHandler;
+34 -12
View File
@@ -7,22 +7,44 @@ public class AesDecryptor :
{ {
private const int IvSize = 16; private const int IvSize = 16;
public byte[] Decrypt(byte[] cipher, byte[] key) public bool TryDecrypt(byte[] cipher,
byte[] key,
out byte[]? decryptedData)
{ {
Span<byte> iv = cipher.AsSpan(0, IvSize); decryptedData = null;
ReadOnlySpan<byte> encryptedContent = cipher.AsSpan(IvSize);
using Aes aes = Aes.Create(); if (cipher is null || key is null || cipher.Length < IvSize)
aes.Key = key; {
aes.IV = iv.ToArray(); return false;
}
using MemoryStream memoryStream = new(encryptedContent.ToArray()); try
using ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); {
using CryptoStream cryptoStream = new(memoryStream, decryptor, CryptoStreamMode.Read); Span<byte> iv = cipher.AsSpan(0, IvSize);
ReadOnlySpan<byte> encryptedContent = cipher.AsSpan(IvSize);
using MemoryStream resultStream = new(); using Aes aes = Aes.Create();
cryptoStream.CopyTo(resultStream); aes.Key = key;
aes.IV = iv.ToArray();
return resultStream.ToArray(); using MemoryStream memoryStream = new(encryptedContent.ToArray());
using ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using CryptoStream cryptoStream = new(memoryStream, decryptor, CryptoStreamMode.Read);
using MemoryStream resultStream = new();
cryptoStream.CopyTo(resultStream);
decryptedData = resultStream.ToArray();
return true;
}
catch (CryptographicException)
{
return false;
}
catch (Exception)
{
return false;
}
} }
} }
+32 -17
View File
@@ -7,28 +7,43 @@ public class AesEncryptor :
{ {
private const int IvSize = 16; private const int IvSize = 16;
public byte[] Encrypt(byte[] data, public bool TryEncrypt(byte[] data,
byte[] key) byte[] key,
out byte[]? encryptedData)
{ {
if (key.Length != 32) encryptedData = null;
if (data is null || key is null || key.Length != 32)
{ {
throw new ArgumentException("Key must be 256 bits (32 bytes)."); return false;
} }
using Aes aes = Aes.Create(); try
aes.Key = key;
aes.GenerateIV();
using MemoryStream memoryStream = new();
memoryStream.Write(aes.IV.AsSpan(0, IvSize));
using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
using (CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Write))
{ {
cryptoStream.Write(data, 0, data.Length); using Aes aes = Aes.Create();
cryptoStream.FlushFinalBlock(); aes.Key = key;
} aes.GenerateIV();
return memoryStream.ToArray(); using MemoryStream memoryStream = new();
memoryStream.Write(aes.IV, 0, IvSize);
using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
using (CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
}
encryptedData = memoryStream.ToArray();
return true;
}
catch (CryptographicException)
{
return false;
}
catch (Exception)
{
return false;
}
} }
} }
+3 -2
View File
@@ -1,6 +1,7 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public interface IDecryptor public interface IDecryptor
{ {
byte[] Decrypt(byte[] cipher, bool TryDecrypt(byte[] cipher,
byte[] key); byte[] key,
out byte[]? decryptedData);
} }
+1 -1
View File
@@ -2,5 +2,5 @@
public interface IDispatcher public interface IDispatcher
{ {
Task InvokeAsync(Action action); Task Invoke(Action action);
} }
+4 -1
View File
@@ -1,5 +1,8 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public interface IEncryptor public interface IEncryptor
{ {
byte[] Encrypt(byte[] data, byte[] key); bool TryEncrypt(byte[] data,
byte[] key,
out byte[]? encryptedData);
} }
@@ -412,6 +412,17 @@ public partial class ObservableCollectionViewModel<TViewModel> :
CollectionChanged?.Invoke(this, args); CollectionChanged?.Invoke(this, args);
} }
public partial class ObservableCollectionViewModel<TValue, TViewModel>(IServiceProvider provider,
IServiceFactory factory,
IMediator mediator,
IPublisher publisher,
ISubscriber subscriber, IDisposer disposer) : ObservableCollectionViewModel<TViewModel>(provider, factory, mediator, publisher, subscriber, disposer)
where TViewModel : notnull
{
[ObservableProperty]
private TValue? value;
}
public class ObservableCollectionViewModel(IServiceProvider provider, public class ObservableCollectionViewModel(IServiceProvider provider,
IServiceFactory factory, IServiceFactory factory,
IMediator mediator, IMediator mediator,
+5 -5
View File
@@ -73,29 +73,29 @@ public class Publisher(ISubscriptionManager subscriptionManager,
public Task PublishUI<TMessage>(object key, public Task PublishUI<TMessage>(object key,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TMessage : new() => where TMessage : new() =>
Publish(new TMessage(), args => dispatcher.InvokeAsync(async () => await args()), Publish(new TMessage(), args => dispatcher.Invoke(async () => await args()),
key, cancellationToken); key, cancellationToken);
public Task PublishUI<TMessage>(TMessage message, public Task PublishUI<TMessage>(TMessage message,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TMessage : notnull => where TMessage : notnull =>
Publish(message, args => dispatcher.InvokeAsync(async () => await args()), Publish(message, args => dispatcher.Invoke(async () => await args()),
null, cancellationToken); null, cancellationToken);
public Task PublishUI<TMessage>(TMessage message, public Task PublishUI<TMessage>(TMessage message,
object key, object key,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TMessage : notnull => where TMessage : notnull =>
Publish(message, args => dispatcher.InvokeAsync(async () => await args()), Publish(message, args => dispatcher.Invoke(async () => await args()),
key, cancellationToken); key, cancellationToken);
public Task PublishUI<TMessage>(CancellationToken cancellationToken = default) public Task PublishUI<TMessage>(CancellationToken cancellationToken = default)
where TMessage : new() => where TMessage : new() =>
Publish(new TMessage(), args => dispatcher.InvokeAsync(async () => await args()), Publish(new TMessage(), args => dispatcher.Invoke(async () => await args()),
null, cancellationToken); null, cancellationToken);
public Task PublishUI(object message, public Task PublishUI(object message,
CancellationToken cancellationToken = default) => Publish(message, args => CancellationToken cancellationToken = default) => Publish(message, args =>
dispatcher.InvokeAsync(async () => await args()), dispatcher.Invoke(async () => await args()),
null, cancellationToken); null, cancellationToken);
} }