Skip to content

feat: NIP-05 MVP — /.well-known/nostr.json for single-user pods (#445) #446

Description

@melvincarvalho

MVP slice of #445. Ship the smallest useful NIP-05 endpoint first; defer aggregation, relays, per-pod overrides to follow-ups.

Scope

Single-user mode only. Single name, single pubkey. No knobs.

GET /.well-known/nostr.json returns:

{ "names": { "<single-user-name>": "<hex pubkey from the profile VM>" } }

Where:

  • <single-user-name> = the NIP-05 reserved _ name. NIP-05 §3 specifies _ as the "naked domain" identifier — the user IS the domain, no name@ prefix needed. For a single-user pod where the pod IS the server, that's the natural identifier. --single-user-name controls the WebID path (separate concern); NIP-05 in single-user mode is intrinsically single-name and uses _. A future phase can add --nip05-name <name> if alice@example.com style is wanted on a single-user pod.
  • <hex pubkey> = read from /profile/card.jsonld's verificationMethod via the existing extractNostrPubkeysFromProfile helper in src/auth/nostr-keys.js. No new key-reading code, no touching /private/.

If no key is provisioned (no VM in the profile, or the VM has no Nostr-shaped pubkey), return { "names": {} }. NIP-05 verifiers handle the empty case fine.

If the server isn't in single-user mode, return 404 — multi-user aggregation is the next slice.

Public read (no WAC, no auth). Access-Control-Allow-Origin: * so browser-based Nostr clients can verify.

What this MVP doesn't ship (deferred to follow-ups)

  • Multi-user aggregation (path mode) — one shared /.well-known/nostr.json listing every pod's mapping.
  • Subdomain mode per-host filtering — each subdomain serves its own.
  • ?name= query filtering (per NIP-05 §3) — return everything for now.
  • relays field auto-populated from --nostr.
  • nip46 remote signer.
  • Per-pod opt-out / opt-in.
  • Custom names via --nip05-name.

Acceptance

  • GET /.well-known/nostr.json on a --single-user --provision-keys server returns { names: { "_": "<hex>" } }.
  • Same request when no key was provisioned returns { names: {} }.
  • Same request in multi-user mode returns 404.
  • Access-Control-Allow-Origin: * header on the response.
  • Reads the pubkey from the WebID profile's VM via the existing extractor — no new key-reading code, no touching /private/.
  • Tests cover: provisioned single-user, single-user with no key, multi-user (404).

Refs #445.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions