fix(app): validate contact addresses when saving
Adding a contact now checks the address against the wallet's network and rejects duplicates; whitespace in a pasted address is removed. Before, any string was stored and the error only surfaced at send time.
This commit is contained in:
1 parent
06d1f59c2b
commit
eca4d4ac0c
5 files changed
+117
-5
No files matched your search
@@ -291,7 +291,8 @@ public sealed class MainWindowViewModelTests : VmTestBase
|
||||
var vm = new MainWindowViewModel();
|
||||
RestoreFlow(vm, Mnemonic, null, "c");
|
||||
|
||||
vm.NewContactName = "Alice"; vm.NewContactAddress = "plm1qexample";
|
||||
var alice = Address(1);
|
||||
vm.NewContactName = "Alice"; vm.NewContactAddress = alice;
|
||||
vm.AddContactCommand.Execute(null);
|
||||
vm.NewContactName = ""; vm.NewContactAddress = "ignored";
|
||||
vm.AddContactCommand.Execute(null); // blank name → ignored
|
||||
@@ -306,6 +307,77 @@ public sealed class MainWindowViewModelTests : VmTestBase
|
||||
Assert.Empty(WalletStore.Load(Assert.Single(AppPaths.WalletFiles(NetKind.Mainnet))).Contacts);
|
||||
});
|
||||
|
||||
private static string Address(int index) =>
|
||||
HdAccount.FromMnemonic(ParseMnemonic(), null, ScriptKind.NativeSegwit, ChainProfiles.Mainnet)
|
||||
.GetReceiveAddress(index).ToString();
|
||||
|
||||
[Theory]
|
||||
[InlineData("plm1qexample")] // garbage
|
||||
[InlineData("not an address")]
|
||||
[InlineData("tplm1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")] // wrong network / bad checksum
|
||||
public Task Contacts_RejectInvalidAddresses(string bad) => UiSession.Run(() =>
|
||||
{
|
||||
var vm = new MainWindowViewModel();
|
||||
RestoreFlow(vm, Mnemonic, null, "c1");
|
||||
|
||||
vm.NewContactName = "Bob"; vm.NewContactAddress = bad;
|
||||
vm.AddContactCommand.Execute(null);
|
||||
|
||||
Assert.Empty(vm.Contacts);
|
||||
Assert.Equal(Loc.Tr("msg.contact.address.invalid"), vm.StatusMessage);
|
||||
Assert.Empty(WalletStore.Load(Assert.Single(AppPaths.WalletFiles(NetKind.Mainnet))).Contacts);
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public Task Contacts_RejectAnAddressFromAnotherNetwork() => UiSession.Run(() =>
|
||||
{
|
||||
var vm = new MainWindowViewModel();
|
||||
RestoreFlow(vm, Mnemonic, null, "c2");
|
||||
var regtest = HdAccount.FromMnemonic(ParseMnemonic(), null, ScriptKind.NativeSegwit, ChainProfiles.Regtest)
|
||||
.GetReceiveAddress(0).ToString();
|
||||
|
||||
vm.NewContactName = "Eve"; vm.NewContactAddress = regtest;
|
||||
vm.AddContactCommand.Execute(null);
|
||||
|
||||
Assert.Empty(vm.Contacts);
|
||||
Assert.Equal(Loc.Tr("msg.contact.address.invalid"), vm.StatusMessage);
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public Task Contacts_RejectDuplicatesAndCleanPastedWhitespace() => UiSession.Run(() =>
|
||||
{
|
||||
var vm = new MainWindowViewModel();
|
||||
RestoreFlow(vm, Mnemonic, null, "c3");
|
||||
var a = Address(2);
|
||||
|
||||
vm.NewContactName = " Carol "; vm.NewContactAddress = $" {a[..10]}\n{a[10..]}\r\n";
|
||||
vm.AddContactCommand.Execute(null);
|
||||
Assert.Equal(new ContactEntry("Carol", a), Assert.Single(vm.Contacts));
|
||||
|
||||
vm.NewContactName = "Carol again"; vm.NewContactAddress = a.ToUpperInvariant();
|
||||
vm.AddContactCommand.Execute(null);
|
||||
Assert.Single(vm.Contacts);
|
||||
Assert.Equal(Loc.Tr("msg.contact.duplicate"), vm.StatusMessage);
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public Task Contacts_AlreadyStoredWithAnInvalidAddress_StillLoadAndDisplay() => UiSession.Run(() =>
|
||||
{
|
||||
var vm = new MainWindowViewModel();
|
||||
RestoreFlow(vm, Mnemonic, null, "c4");
|
||||
var path = Assert.Single(AppPaths.WalletFiles(NetKind.Mainnet));
|
||||
var doc = WalletStore.Load(path);
|
||||
doc.Contacts = [new StoredContact { Name = "Legacy", Address = "whatever" }];
|
||||
WalletStore.Save(doc, path, null);
|
||||
vm.CloseWalletCommand.Execute(null);
|
||||
|
||||
vm.WizardStartOpenCommand.Execute(null);
|
||||
vm.OpenExistingCommand.Execute(null);
|
||||
|
||||
Assert.True(vm.IsWalletOpen);
|
||||
Assert.Equal(new ContactEntry("Legacy", "whatever"), Assert.Single(vm.Contacts));
|
||||
});
|
||||
|
||||
// ---- sync + send against the fake server ----
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in new issue
Block a user