aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-01 22:38:43 -0700
committerAdam Soltys <[email protected]>2026-08-01 22:38:43 -0700
commit39067a27e0ce24386aa6f08c78e9a916e1c8a202 (patch)
tree78a72b5c1be4e53bfa389f60e56ec15325109851 /src
parent4d427f8b863c0bd03a7add9ed198d738cc6d14d3 (diff)
downloadcoinosv3-39067a27e0ce24386aa6f08c78e9a916e1c8a202.tar.gz
coinosv3-39067a27e0ce24386aa6f08c78e9a916e1c8a202.zip
Never spin on a claim that can only fail
After a reload the extension signer is gone, so claiming the user's real npub name was signed by the wallet key — which the anti-squatting rule rightly refuses, and the retry loop then span forever. An installed extension is now silently re-attached when possible (keeping the address tied to the real identity across reloads), refusals are treated as permanent rather than retried, and anything unresumable falls back to the wallet's own npub so an address always appears. Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/features/names.js27
-rw-r--r--src/features/nostrlogin.js15
2 files changed, 36 insertions, 6 deletions
diff --git a/src/features/names.js b/src/features/names.js
index 77b2554..d430d98 100644
--- a/src/features/names.js
+++ b/src/features/names.js
@@ -99,14 +99,29 @@ export function namesFeature(ctx) {
if (!st.name) {
// The address people see should be the identity they know the user
// by: their real npub when a nostr account is linked, else the
- // wallet's own. Both are claimed the same way; the registrar checks
- // that an npub-shaped name really belongs to its claimant.
+ // wallet's own. Claiming the real one has to be SIGNED by that
+ // identity (the registrar won't let anyone else take an npub-shaped
+ // name), so it needs a live signer — after a reload an extension can
+ // usually be re-attached silently; anything else falls back to the
+ // wallet's own identity rather than retrying a claim that can only
+ // ever fail.
const linked = hook('nostrLoginIdentity');
- const npub = (linked && linked.npub) || (wallet.nostrNpub && wallet.nostrNpub());
+ let signer = linked && linked.signer;
+ if (linked && !signer) { try { signer = await hook('nostrLoginResume'); } catch {} }
+ const useReal = !!(linked && signer);
+ const npub = useReal ? linked.npub : (wallet.nostrNpub && wallet.nostrNpub());
if (npub) {
- await claim(npub.slice(0, 20), linked
- ? { signer: linked.signer, manager: wallet.nostrPubkey() }
- : {});
+ const opts = useReal ? { signer, manager: wallet.nostrPubkey() } : {};
+ try {
+ await claim(npub.slice(0, 20), opts);
+ } catch (e) {
+ // A refusal is permanent — never spin on it. Fall back to the
+ // wallet's own name so the user always ends up with an address.
+ const permanent = /belongs to another|is taken|reserved|invalid/i.test(e.message);
+ const own = wallet.nostrNpub && wallet.nostrNpub();
+ if (permanent && useReal && own) await claim(own.slice(0, 20), {});
+ else if (!permanent) throw e;
+ }
st = load();
}
}
diff --git a/src/features/nostrlogin.js b/src/features/nostrlogin.js
index c5369e9..cea13b4 100644
--- a/src/features/nostrlogin.js
+++ b/src/features/nostrlogin.js
@@ -176,6 +176,21 @@ export function nostrLoginFeature(ctx) {
if (!st.pubkey) return null;
return { pubkey: st.pubkey, npub: npubOf(st.pubkey), signer: live };
},
+ // A page reload loses the signer. An installed extension can usually be
+ // re-attached without prompting, which is what lets the payment address
+ // stay tied to the user's real identity across reloads. Returns null for
+ // signers we cannot silently reattach (pasted keys, bunkers).
+ async nostrLoginResume() {
+ if (live) return live;
+ const st = load();
+ if (!st.pubkey || typeof window === 'undefined' || !window.nostr) return null;
+ try {
+ const s = await extensionSigner();
+ if (s.pubkey !== st.pubkey) return null;
+ live = s;
+ return s;
+ } catch { return null; }
+ },
unlockExtra() { return unlockExtra(); },
settingsCards() { return [settingsCard()]; },
};