diff options
| author | Adam Soltys <[email protected]> | 2026-08-03 23:43:18 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-03 23:43:18 -0700 |
| commit | 9a9e2a7e64e02d080d121e1f3079573d00ab28cf (patch) | |
| tree | 22fe70f90dd404ec49385f554d790a063d9c61dc /src | |
| parent | 3bc4bf2cb95c1bcf61a10d8b892ee9ccaeffcf2d (diff) | |
| download | coinosv3-9a9e2a7e64e02d080d121e1f3079573d00ab28cf.tar.gz coinosv3-9a9e2a7e64e02d080d121e1f3079573d00ab28cf.zip | |
Logout shouldn't ask for a password nobody set
Wallets save themselves to this device as soon as you open one, encrypted
under an empty password unless you choose one. Logging out still sent
you to 'Unlock saved wallets — enter your password', which asks for
something that doesn't exist and makes logout look like it did something
drastic. It didn't: logout only drops the keys from memory, and 'Clear
all' is the one that deletes.
With no password, logout now returns to the wallet list — honest, since
nothing is protecting those wallets and a blank prompt protects nothing.
With a password set it prompts exactly as before.
Fixed underneath: mergeVaultList derived the comparison xpub with
accountXpubFor's mainnet default, so on any other network it never
matched the stored one and every unlock re-added the same wallet as a
fresh entry — visible as the same wallet listed twice, once watch-only.
The seed-mismatch checks in 'load recovery phrase' had the same default
and would have rejected the correct seed on testnet.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.js | 20 |
1 files changed, 16 insertions, 4 deletions
@@ -1079,7 +1079,12 @@ function writeVault() { // duplicated; one with no directory entry is added fresh. function mergeVaultList(list) { for (const v of list) { - const xpub = v.xprv ? accountXpubFor({ xprv: v.xprv }) : accountXpubFor({ mnemonic: v.mnemonic, passphrase: v.passphrase || '' }); + // Derive on the wallet's OWN network: accountXpubFor defaults to mainnet, + // and a testnet wallet derives under a different coin type, so leaving it + // to the default produced an xpub that could never match the stored one — + // every unlock re-added the same wallet as a new entry. + const net = v.network || getNetwork(); + const xpub = v.xprv ? accountXpubFor({ xprv: v.xprv }, net) : accountXpubFor({ mnemonic: v.mnemonic, passphrase: v.passphrase || '' }, net); const existing = accounts.find((a) => a.xpub === xpub); if (existing) { existing.type = 'full'; @@ -1142,12 +1147,12 @@ async function doLoadSeed() { let next = null; try { if (isValidMnemonic(raw)) { - if (accountXpubFor({ mnemonic: raw, passphrase: ls.passphrase || '' }) !== acc.xpub) { ls.error = t('seedMismatch'); render(); return; } + if (accountXpubFor({ mnemonic: raw, passphrase: ls.passphrase || '' }, acc.network || getNetwork()) !== acc.xpub) { ls.error = t('seedMismatch'); render(); return; } next = { mnemonic: raw, passphrase: ls.passphrase || '' }; } else { const pk = parseExtendedKey(raw); // throws if not an extended key if (pk.kind !== 'xprv') { ls.error = t('seedNeedsPrivate'); render(); return; } - if (accountXpubFor({ xprv: pk.key }) !== acc.xpub) { ls.error = t('seedMismatch'); render(); return; } + if (accountXpubFor({ xprv: pk.key }, acc.network || getNetwork()) !== acc.xpub) { ls.error = t('seedMismatch'); render(); return; } next = { xprv: pk.key }; } } catch { ls.error = t('seedInvalid'); render(); return; } @@ -1385,7 +1390,14 @@ function lock() { vaultPassword = null; wallet.load({ mnemonic: '', passphrase: '', netName: getNetwork(), offline: false }); wallet.mnemonic = ''; - ui.screen = hasVault() ? 'vault' : 'unlock'; + // Wallets save themselves to this device without asking, under an empty + // password unless one is set. Demanding a password on the way out is then + // theatre — it protects nothing and asks for something nobody chose. With no + // password, logging out means dropping back to the wallet list; with one, it + // means what it says. + ui.screen = !hasVault() ? 'unlock' + : attemptVaultUnlock('') ? 'accounts' + : 'vault'; ui.unlockTab = 'create'; ui.fromWallet = false; ui.watchXpub = ''; |
