diff --git a/src/aoWebWallet/Pages/GenerateWalletPage.razor b/src/aoWebWallet/Pages/GenerateWalletPage.razor new file mode 100644 index 0000000..5627544 --- /dev/null +++ b/src/aoWebWallet/Pages/GenerateWalletPage.razor @@ -0,0 +1,54 @@ +@page "/generate-wallet" +@inherits MvvmComponentBase +@inject ISnackbar Snackbar + +Generate Wallet - @Program.PageTitlePostFix + + + + + @if (BindingContext.SecretKey == null) + { + + Generate Wallet + Enter a password to encrypt your wallet. The password must be at least 6 characters long. + + + + + + + Generate Wallet + + + } + else + { + + } + + +@code { + private List _items = new List + { + new BreadcrumbItem("Home", href: "/"), + new BreadcrumbItem("Generate Wallet", href: null, disabled: true) + }; +} diff --git a/src/aoWebWallet/Pages/GenerateWalletPage.razor.cs b/src/aoWebWallet/Pages/GenerateWalletPage.razor.cs new file mode 100644 index 0000000..5e1e861 --- /dev/null +++ b/src/aoWebWallet/Pages/GenerateWalletPage.razor.cs @@ -0,0 +1,57 @@ +using aoWebWallet.ViewModels; +using Microsoft.AspNetCore.Components; +using MudBlazor; + +namespace aoWebWallet.Pages +{ + public partial class GenerateWalletPage : MvvmComponentBase + { + private string Password { get; set; } = string.Empty; + private string ConfirmPassword { get; set; } = string.Empty; + private bool PasswordVisible { get; set; } = false; + private InputType PasswordInput { get; set; } = InputType.Password; + private string PasswordInputIcon { get; set; } = Icons.Material.Filled.VisibilityOff; + + private void TogglePasswordVisibility() + { + if (PasswordVisible) + { + PasswordVisible = false; + PasswordInputIcon = Icons.Material.Filled.VisibilityOff; + PasswordInput = InputType.Password; + } + else + { + PasswordVisible = true; + PasswordInputIcon = Icons.Material.Filled.Visibility; + PasswordInput = InputType.Text; + } + } + + private void GenerateWallet() + { + if (string.IsNullOrWhiteSpace(Password) || string.IsNullOrWhiteSpace(ConfirmPassword)) + { + Snackbar.Add("Please enter and confirm your password.", Severity.Warning); + return; + } + + if (Password != ConfirmPassword) + { + Snackbar.Add("Passwords do not match.", Severity.Error); + return; + } + + if (Password.Length < 6) + { + Snackbar.Add("Password must be at least 6 characters long.", Severity.Warning); + return; + } + + BindingContext.SecretKey = Password; + + // TODO: Implement wallet generation logic here + Snackbar.Add("Wallet generated successfully!", Severity.Success); + } + } +} diff --git a/src/aoWebWallet/Shared/AddGenerateWalletComponent.razor b/src/aoWebWallet/Shared/AddGenerateWalletComponent.razor index a70adf3..fb8e341 100644 --- a/src/aoWebWallet/Shared/AddGenerateWalletComponent.razor +++ b/src/aoWebWallet/Shared/AddGenerateWalletComponent.razor @@ -1,4 +1,5 @@ @using aoWebWallet.Models +@using aoww.Services @inherits MvvmComponentBase @inject ArweaveService ArweaveService @inject ISnackbar Snackbar @@ -7,16 +8,16 @@ - - - + + + - @Progress -
- - Create aoWW Wallet - -
+ @Progress +
+ + Create aoWW Wallet + +
@@ -52,17 +53,24 @@ var jwk = await ArweaveService.GenerateWallet(); var address = await ArweaveService.GetAddress(jwk); + var wallet = new Wallet { Address = address, Name = Name, - Jwk = jwk, + JwkSecret = jwk, Source = WalletTypes.Generated, IsReadOnly = false, LastBackedUpDate = null, AddedDate = DateTimeOffset.UtcNow }; + if(!string.IsNullOrEmpty(BindingContext.SecretKey)) + { + var jwkEncrypted = EncryptionService.EncryptWallet(BindingContext.SecretKey, jwk); + wallet.JwkEncrypted = jwkEncrypted; + } + await BindingContext.SaveWallet(wallet); Snackbar.Add($"Wallet added ({address})", Severity.Info); diff --git a/src/aoWebWallet/Shared/AddWalletComponent.razor b/src/aoWebWallet/Shared/AddWalletComponent.razor index c2a5627..c31b064 100644 --- a/src/aoWebWallet/Shared/AddWalletComponent.razor +++ b/src/aoWebWallet/Shared/AddWalletComponent.razor @@ -7,7 +7,13 @@ - +
+ + Generate new wallet + +
diff --git a/src/aoWebWallet/ViewModels/MainViewModel.cs b/src/aoWebWallet/ViewModels/MainViewModel.cs index e161ec1..917d06c 100644 --- a/src/aoWebWallet/ViewModels/MainViewModel.cs +++ b/src/aoWebWallet/ViewModels/MainViewModel.cs @@ -44,6 +44,10 @@ public partial class MainViewModel : ObservableRecipient [ObservableProperty] private string? activeWalletAddress; + + [ObservableProperty] + private string? secretKey; + public Wallet? ActiveWallet { get; set; } public DataLoaderViewModel LastTransactionId { get; set; } = new(); public DataLoaderViewModel> WalletList { get; set; } = new(); diff --git a/src/aoww.Services.Tests/EncryptionTests.cs b/src/aoww.Services.Tests/EncryptionTests.cs index 2a88cba..0d7859e 100644 --- a/src/aoww.Services.Tests/EncryptionTests.cs +++ b/src/aoww.Services.Tests/EncryptionTests.cs @@ -1,10 +1,9 @@ using aoww.Services; -using SiaSkynet; using System.IO; using System.Net.Http.Headers; using System.Threading.Tasks; -namespace SiaSkynet.Tests +namespace aoww.Services.Tests { [TestClass] public class EncryptionTests @@ -29,6 +28,18 @@ public void BasicEncryptionTest() Assert.AreEqual(testValue, dString); } + [TestMethod] + public void WalletTest() + { + var key = "test"; + var jwk = "1234"; + + var encrypted = EncryptionService.EncryptWallet(key, jwk); + var decrypt = EncryptionService.DecryptWallet(key, encrypted); + + Assert.AreEqual(jwk, decrypt); + } + } } diff --git a/src/aoww.Services/EncryptionService.cs b/src/aoww.Services/EncryptionService.cs index 3d3bc77..5e052f7 100644 --- a/src/aoww.Services/EncryptionService.cs +++ b/src/aoww.Services/EncryptionService.cs @@ -9,6 +9,37 @@ namespace aoww.Services { public static class EncryptionService { + public static string EncryptWallet(string secretKey, string jwk) + { + var key = EncryptionService.GenerateKeys(secretKey); + + var encrypted = EncryptionService.Encrypt(System.Text.Encoding.UTF8.GetBytes(jwk), key.privateKey); + //var encryptedString = System.Text.Encoding.UTF8.GetString(encrypted); + var encryptedString = BitConverter.ToString(encrypted).Replace("-", ""); + + return encryptedString; + } + + public static string DecryptWallet(string secretKey, string encryptedJwk) + { + var key = EncryptionService.GenerateKeys(secretKey); + + var cipherData = HexStringToByteArray(encryptedJwk); + + var decrypt = EncryptionService.Decrypt(cipherData, key.privateKey); + var dString = System.Text.Encoding.UTF8.GetString(decrypt); + + return dString; + } + + public static byte[] HexStringToByteArray(string hex) + { + int NumberChars = hex.Length; + byte[] bytes = new byte[NumberChars / 2]; + for (int i = 0; i < NumberChars; i += 2) + bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); + return bytes; + } /// /// Generates a predicatable key pair based on the seed