aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-03 23:43:18 -0700
committerAdam Soltys <[email protected]>2026-08-03 23:43:18 -0700
commit9a9e2a7e64e02d080d121e1f3079573d00ab28cf (patch)
tree22fe70f90dd404ec49385f554d790a063d9c61dc /src
parent3bc4bf2cb95c1bcf61a10d8b892ee9ccaeffcf2d (diff)
downloadcoinosv3-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.js20
1 files changed, 16 insertions, 4 deletions
diff --git a/src/app.js b/src/app.js
index f2f9ee3..8f9d78b 100644
--- a/src/app.js
+++ b/src/app.js
@@ -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 = '';