Add NIP-05 identifiers: store, publish, GUI modal, CLI helpers

- Store an optional nip05 on each profile; publish it in kind 0 metadata
- set-nip05 CLI (+ validation, lower-casing, clear) and nip05-file helper
  that prints the .well-known/nostr.json document for a domain
- Profiles screen: NIP-05 button, handle shown on cards, Nip05Modal with
  client-side validation and Remove action
- Fix Modal stealing focus from autoFocus inputs one frame after open
This commit is contained in:
Avi 2026-08-23 21:59:11 -05:00
commit 045fa47476
14 changed files with 666 additions and 11 deletions

77
docs/NIP-05.md Normal file
View file

@ -0,0 +1,77 @@
# NIP-05 identifiers in Keynectr
A NIP-05 identifier is a human-readable Nostr address that looks like an email
address — for example `boo@l484.com`. When a profile has one, clients such as
Iris, Yakihonne, Amethyst and snort show the handle instead of a raw `npub1…`
key, and users can find and tag you by typing it.
NIP-05 has two halves. Keynectr does the first half; you do the second half
once on your own domain.
## 1. Publish it from Keynectr (the app side)
- **GUI:** Profiles → *NIP-05* button → enter `name@domain.com` → *Save & publish*.
The identifier is stored with the profile and published to your enabled relays
as part of your kind 0 metadata.
- **CLI:**
```bash
B=~/Projects/Nostr_Keynctr/target/release/keynectr
$B set-nip05 <npub> boo@l484.com # set + publish
$B set-nip05 <npub> clear # remove + publish the removal
```
- The special form `_@domain.com` claims the bare domain itself (the whole
domain shows as your handle).
## 2. Serve `.well-known/nostr.json` (the domain side)
Clients verify a NIP-05 claim by fetching:
```
https://<your-domain>/.well-known/nostr.json?name=<local-part>
```
That file must live on the domain in the identifier — publishing alone is not
enough. Keynectr prints the exact document to serve:
```bash
$B nip05-file <npub> boo@l484.com
```
which outputs something like:
```json
{
"names": {
"boo": "3bf0c6…(64-char hex public key)"
},
"relays": {
"3bf0c6…": ["wss://nos.lol", "wss://relay.primal.net"]
}
}
```
Serve it at `https://<domain>/.well-known/nostr.json` with:
- `Content-Type: application/json` (or `application/json; charset=utf-8`)
- CORS header `Access-Control-Allow-Origin: *` (clients fetch it from browsers)
### nginx example
```nginx
location = /.well-known/nostr.json {
include snippets/cors.conf; # or add_header Access-Control-Allow-Origin *;
default_type application/json;
root /var/www/static;
}
```
Then place the printed document at `/var/www/static/.well-known/nostr.json`.
Regenerate it if you switch profiles or change your relay list.
## Notes
- The identifier is lower-cased when stored; validation matches NIP-05's
limited character set (`a-z`, `0-9`, `-`, `_`; `_` for the bare domain).
- Clients cache profiles aggressively — hard-refresh after changing anything.
- Without the well-known file, most clients will not display the handle even
though the metadata was published successfully.