feat(ui): password-gated private key reveal in address detail overlay

Replace the direct private-key display in the address detail overlay with a
two-step reveal flow:

- Unencrypted wallet: clicking Show reveals the WIF key immediately.
- Encrypted wallet: clicking Show opens a modal password-prompt overlay; the
  key is displayed only if the entered password matches the wallet file
  password; a wrong password shows an inline error without closing the prompt.

Hiding the key (Hide button) clears the revealed state. Closing the address
overlay or opening a different one always resets both the reveal state and
the password prompt, so no sensitive material lingers between sessions.
This commit is contained in:
2026-06-21 22:28:28 +02:00
parent 4a97172346
commit affeaccae8
@@ -68,11 +68,81 @@ public partial class MainWindowViewModel
[ObservableProperty] [ObservableProperty]
private AddressInfo? addressInfo; private AddressInfo? addressInfo;
[ObservableProperty]
private bool isAddressPrivKeyRevealed;
// ---- private key password prompt ----
[ObservableProperty]
private bool isPrivKeyPromptOpen;
[ObservableProperty]
private string privKeyPromptPassword = "";
[ObservableProperty]
private string privKeyPromptError = "";
partial void OnAddressInfoChanged(AddressInfo? value)
{
IsAddressPrivKeyRevealed = false;
ClosePrivKeyPromptInternal();
}
private void ClosePrivKeyPromptInternal()
{
IsPrivKeyPromptOpen = false;
PrivKeyPromptPassword = "";
PrivKeyPromptError = "";
}
public void ShowAddressInfo(AddressRow row) => public void ShowAddressInfo(AddressRow row) =>
AddressInfo = new AddressInfo(Loc, row.Indirizzo, row.DerivPath, row.PubKey, row.PrivKey); AddressInfo = new AddressInfo(Loc, row.Indirizzo, row.DerivPath, row.PubKey, row.PrivKey);
[RelayCommand] [RelayCommand]
private void CloseAddressInfo() => AddressInfo = null; private void CloseAddressInfo()
{
ClosePrivKeyPromptInternal();
AddressInfo = null;
}
[RelayCommand]
private void RequestPrivKeyReveal()
{
if (AddressInfo is null || !AddressInfo.HasPrivKey) return;
if (string.IsNullOrEmpty(_password))
{
// No encryption: reveal directly
IsAddressPrivKeyRevealed = true;
}
else
{
// Encrypted: open password prompt
PrivKeyPromptPassword = "";
PrivKeyPromptError = "";
IsPrivKeyPromptOpen = true;
}
}
[RelayCommand]
private void ConfirmPrivKeyPassword()
{
if (PrivKeyPromptPassword != _password)
{
PrivKeyPromptError = Loc.Tr("msg.wrongpassword");
return;
}
IsAddressPrivKeyRevealed = true;
ClosePrivKeyPromptInternal();
}
[RelayCommand]
private void CancelPrivKeyPrompt() => ClosePrivKeyPromptInternal();
[RelayCommand]
private void HideAddressPrivKey()
{
IsAddressPrivKeyRevealed = false;
}
// ---- transaction detail overlay ---- // ---- transaction detail overlay ----