Skip to content

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

@melvincarvalho

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions