From 971db911d47af391695a9d83a3d31c089bfee782 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 4 Aug 2026 01:06:24 -0700 Subject: Never mistake a failed backup lookup for 'no wallet yet' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signing in with a key whose wallet backup exists on relays could still land in 'create a new wallet' when the lookup failed (relays unreachable, signer decrypt denied) — and confirming would have replaced the real backup on any relay the new one reached. Absence is now only believed when a relay actually answered; decrypt failures surface as errors; and the create path takes one last look and adopts a backup that surfaces rather than clobbering it. Co-Authored-By: Claude Fable 5 --- src/features/nostrlogin.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/features') diff --git a/src/features/nostrlogin.js b/src/features/nostrlogin.js index 97ce8be..731c1b9 100644 --- a/src/features/nostrlogin.js +++ b/src/features/nostrlogin.js @@ -14,7 +14,7 @@ import { t } from '../i18n.js'; import { qrSvg } from '../qr.js'; import { extensionSigner, bunkerSigner, keySigner, parseNostrSecret, - walletForSigner, publishWalletBackup, nostrConnect, resumeBunker } from '../nostr-login.js'; + walletForSigner, publishWalletBackup, fetchWalletBackup, nostrConnect, resumeBunker } from '../nostr-login.js'; // The nostr ostrich, in the brand's monochrome. const OSTRICH = ''; @@ -108,14 +108,18 @@ export function nostrLoginFeature(ctx) { if (!st) return; busy(true); try { - const mnemonic = newMnemonic(); - await publishWalletBackup(st.signer, { mnemonic }); + // One last look before publishing a fresh seed: if a backup surfaces + // now (a relay that was unreachable a moment ago), open that wallet + // instead of replacing it on the relays that can see it. + const existing = await fetchWalletBackup(st.signer).catch(() => null); + const mnemonic = existing ? existing.mnemonic : newMnemonic(); + if (!existing) await publishWalletBackup(st.signer, { mnemonic }); ui.nostrLoginNew = null; live = selfHealing(st.signer); - await ctx.openMnemonic(mnemonic, '', { nostrPubkey: st.signer.pubkey }); + await ctx.openMnemonic(mnemonic, (existing && existing.passphrase) || '', { nostrPubkey: st.signer.pubkey }); save({ ...load(), pubkey: st.signer.pubkey, linked: Date.now(), ...sessionOf(st.signer) }); ctx.hook('namesAdoptIdentity', st.signer, npubOf(st.signer.pubkey))?.catch?.(() => {}); - toast(t('nlCreated')); + toast(existing ? t('nlOpenedRestored') : t('nlCreated')); busy(false); } catch (e) { fail(e); } } -- cgit v1.2.3