aboutsummaryrefslogtreecommitdiffstats
path: root/names/server.js
diff options
context:
space:
mode:
Diffstat (limited to 'names/server.js')
-rw-r--r--names/server.js13
1 files changed, 11 insertions, 2 deletions
diff --git a/names/server.js b/names/server.js
index 463ab8e..aff4e54 100644
--- a/names/server.js
+++ b/names/server.js
@@ -57,6 +57,13 @@ const RESERVED = new Set([
'user', 'users', 'coinos', 'nostr', 'ark', 'test', 'dev', 'security', 'abuse',
]);
const NAME_RE = /^[a-z0-9][a-z0-9._-]{0,29}$/;
+// What a NEW name may be: letters and digits, 2–24 — coinos v2's rule
+// (/^[\p{L}\p{N}]{2,24}$/u there), held to ASCII because a name is a DNS
+// label here. NAME_RE stays the wider test for names that already exist
+// (a dozen claimed before the rule: bitcoin-education, barefoot.strider…),
+// v2 migrations carrying their own name, and npub-shaped defaults.
+const NEW_NAME_RE = /^[a-z0-9]{2,24}$/;
+const NEW_NAME_ERR = 'names can only have letters and numbers (2–24)';
let state = (() => {
try { return JSON.parse(readFileSync(STATE, 'utf8')); } catch { return { names: {} }; }
@@ -1228,8 +1235,9 @@ Bun.serve({
const granted = !!g && (keys.includes(g.pubkey) || (!!g.manager && keys.includes(g.manager)));
return json({ name: m[1], domain, taken: true, pubkey: rec.pubkey, manager: rec.manager || null, uri: rec.uri, noffer: rec.noffer?.raw || null, lno: rec.lno || null, granted });
}
- 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 });
+ const invalid = !NEW_NAME_RE.test(m[1]) && !npubPrefixOwner(m[1]);
+ const reserved = RESERVED.has(m[1]) || !NAME_RE.test(m[1]) || invalid || await takenByCoinosUser(domain, m[1]);
+ return json({ name: m[1], domain, taken: reserved, reserved, ...(invalid ? { invalid: true } : {}) });
}
// Which name(s) does a wallet key own? Lets an imported seed find its
@@ -1659,6 +1667,7 @@ Bun.serve({
if (existing && existing.pubkey !== auth.pubkey && existing.manager !== auth.pubkey) {
return json({ error: 'name is taken' }, 409);
}
+ if (!existing && !granted && !npubPrefixOwner(name) && !NEW_NAME_RE.test(name)) return json({ error: NEW_NAME_ERR }, 400);
if (!existing && !granted && await takenByCoinosUser(domain, name, auth.pubkey)) return json({ error: 'name is taken' }, 409);
// an npub-shaped name belongs to that identity alone
if (npubPrefixOwner(name)) {