aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-28 20:56:15 -0700
committerAdam Soltys <[email protected]>2026-08-28 20:56:15 -0700
commit339e9badc0f06c098f2236af90501572bde1defa (patch)
tree30a96092638c84e6364bef95ed6ea2ba087c99a0
parentef1ed09ec688ce27b8a2c3c957515f4dc7ab0596 (diff)
downloadcoinosv3-339e9badc0f06c098f2236af90501572bde1defa.tar.gz
coinosv3-339e9badc0f06c098f2236af90501572bde1defa.zip
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
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
-rw-r--r--names/server.js2
-rw-r--r--src/features/names.js15
2 files changed, 16 insertions, 1 deletions
diff --git a/names/server.js b/names/server.js
index e713ff4..406bcf2 100644
--- a/names/server.js
+++ b/names/server.js
@@ -753,7 +753,7 @@ Bun.serve({
if (m && req.method === 'GET') {
const domain = (url.searchParams.get('domain') || DOMAIN).toLowerCase();
const rec = state.names[`${m[1]}@${domain}`];
- if (rec) return json({ name: m[1], domain, taken: true, pubkey: rec.pubkey, uri: rec.uri });
+ if (rec) return json({ name: m[1], domain, taken: true, pubkey: rec.pubkey, manager: rec.manager || null, uri: rec.uri });
const reserved = RESERVED.has(m[1]) || !NAME_RE.test(m[1]) || await takenByCoinosUser(domain, m[1]);
return json({ name: m[1], domain, taken: reserved, reserved });
}
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