From 339e9badc0f06c098f2236af90501572bde1defa Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 28 Aug 2026 20:56:15 -0700 Subject: A name the registrar no longer grants is a costume: the wallet verifies its cached name against the record's owner and manager keys each refresh, shedding stale ones (an evicted squat once lingered in the squatter's UI) — the /name endpoint now names the manager too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi --- src/features/names.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/features') diff --git a/src/features/names.js b/src/features/names.js index 5b2f856..0291b40 100644 --- a/src/features/names.js +++ b/src/features/names.js @@ -183,6 +183,21 @@ export function namesFeature(ctx) { } catch {} } } + // A name the registrar no longer grants us is a costume, not an + // address: verify ownership and drop stale local state (a record can + // be evicted server-side — a squatted legacy name once lingered in + // the squatter's UI this way). Registrar outages keep the benefit of + // the doubt. + if (st.name) { + try { + const r = await withTimeout( + fetch(`${REGISTRAR}/name/${encodeURIComponent(st.name)}?domain=${encodeURIComponent(st.domain || DOMAIN())}`).then((x) => x.json()), + 8000, 'registrar'); + const mine = new Set([wallet.nostrPubkey && wallet.nostrPubkey(), (hook('nostrLoginIdentity') || {}).pubkey].filter(Boolean)); + const ours = r && r.taken && (mine.has(r.pubkey) || mine.has(r.manager)); + if (r && !ours) { save({}); st = load(); render(); } + } catch {} + } 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 -- cgit v1.2.3