clone

nostr relays on demand at <name>.bind.ws: claim one with your key, pay in zaps past the free allowance

main
bindws / src / nip05.ts
nip05.ts 1.7K
1// Every relay is a NIP-05 domain for its members: alice@<name>.bind.ws is2// the member whose name is "alice". Names live on the member record; members3// claim one by setting nip05 in their kind 0 profile, and the owner can assign4// or clear names from the console.5import type { Settings } from "./settings.ts";67// nip05Document answers /.well-known/nostr.json?name=<name>. A lookup by8// name answers for anyone: the member put that address in their own profile.9// Without a name the document is the directory, so it is empty unless the10// caller may list the members.11export function nip05Document(settings: Settings, name: string | null, relayURL: string, caller: string[] = []): Record<string, unknown> {12 const names: Record<string, string> = {};13 const relays: Record<string, string[]> = {};14 const rows = name === null ? (settings.mayList(caller) ? [] : settings.members().filter((m) => m.name)) : [settings.memberByName(name)].filter((m) => m !== null);15 for (const m of rows) {16 names[m!.name!] = m!.pubkey;17 relays[m!.pubkey] = [relayURL];18 }19 return { names, relays };20}2122// claimFromProfile applies a member's kind 0 nip05 field when it names this relay.23export function claimFromProfile(settings: Settings, content: string, pubkey: string, host: string, now: number) {24 let nip05 = "";25 try {26 const j = JSON.parse(content) as { nip05?: unknown };27 if (typeof j.nip05 === "string") nip05 = j.nip05.trim().toLowerCase();28 } catch {29 return;30 }31 const at = nip05.lastIndexOf("@");32 if (at < 1) return;33 const [name, domain] = [nip05.slice(0, at), nip05.slice(at + 1)];34 if (domain !== host.toLowerCase().split(":")[0]) return;35 if (!settings.isAllowed(pubkey)) return;36 settings.upsertMember(pubkey, { name, via: "profile" }, now);37}