Upgrade the admin DM from NIP-04 to NIP-17 (gift-wrapped) — analysis #46

Open
opened 2026-06-27 00:44:29 +00:00 by padreug · 0 comments
Owner

The daemon's one DM path — the boot-time "nsecBunker has started, use <connection-string>…" notification to admin npubs (utils/dm-user.ts, called from admin/index.ts notifyAdminsOfNewConnection) — uses NIP-04 (kind:4 legacy encrypted DM). This issue weighs moving it to NIP-17 (kind:14 chat message, sealed via NIP-59 kind:13 + gift-wrapped in a kind:1059 event).

Scope note: this is only about the admin DM. The NIP-46 RPC envelope (kind:24133/24134) also uses nip04/nip44 adaptively, but that's the NIP-46 protocol — dictated by the connecting clients (lnbits, the spire) — and is out of scope; we can't unilaterally switch it without breaking them.

Current vs proposed

  • NIP-04 (today): AES-256-CBC, no authentication; the event is a kind:4 authored by the bunker's admin key with a cleartext ["p", recipient] tag and a real timestamp. So the fact that the bunker DM'd this operator, when, and both pubkeys are public; only the content body is (weakly) encrypted.
  • NIP-17 (proposed): the message (kind:14) is sealed (NIP-59 kind:13, NIP-44 v2 encrypted) and gift-wrapped in a kind:1059 event signed by a throwaway ephemeral key with a randomized timestamp. The outer event hides the sender, the content, the message kind, and the real time; only the recipient p-tag is visible (needed for delivery).

Pros

  1. Metadata privacy. Hides that the bunker's admin identity sent a DM, and when. The admin npub is a sensitive identifier (it is the bunker). NIP-04 leaks all of this.
  2. Modern, authenticated crypto. NIP-44 v2 (ChaCha20 + HMAC) vs NIP-04's unauthenticated AES-CBC (malleable, no integrity).
  3. NIP-04 is deprecated ecosystem-wide; clients are dropping it. We shouldn't be adding/keeping new NIP-04 paths.
  4. Cheap to implement. nostr-tools (already our transport lib, ~2.20.0) ships nip17.wrapEvent(senderSecret, { publicKey, relays }, message) and nip59 — the send side is a few lines via a throwaway RelayPool (same shape as the current port).
  5. Aligns with the stack's privacy-forward, Nostr-native direction.

Cons / risks

  1. Recipient client support is the gating factor. The admin client that reads this DM (the operator's nsecBunker admin UI / whatever subscribes) must support NIP-17 — i.e. subscribe for kind:1059 #p=self, unwrap the seal, render kind:14. If it only listens for kind:4, the NIP-17 message is invisible. Action: confirm what reads these admin DMs and whether it does NIP-17 before switching.
  2. Low marginal value for this specific message. It's a one-shot boot notification, and the payload (connection string = the bunker's npub + relays) isn't a hard secret — the privacy win is real but modest here.
  3. Slightly more moving parts (seal + wrap + ephemeral key + randomized created_at), and the randomized timestamp means the DM can appear up to ~2 days in the past in some clients — fine for a notification, worth knowing.
  4. No clean half-step: NIP-44-encrypted DMs are NIP-17 (via gift-wrap); it's nip04 → nip17, not a smaller hop.

Recommendation

Correct direction, low priority, gated on (1) — verify the admin client supports NIP-17. Given the only DM is the low-sensitivity boot notification, there's no urgency, but since NIP-04 is deprecated we shouldn't grow its use. Good candidate to fold into the CLI-port follow-up (the CLI is the likely reader of admin events). If recipient support is uncertain, keep NIP-04 for now rather than dual-send (messy) — revisit once the admin-client NIP-17 story is confirmed.

Refs: #44 (where the DM was ported off NDK to nostr-tools nip04), NIP-17, NIP-44, NIP-59.

The daemon's one DM path — the boot-time "nsecBunker has started, use `<connection-string>`…" notification to admin npubs (`utils/dm-user.ts`, called from `admin/index.ts notifyAdminsOfNewConnection`) — uses **NIP-04** (kind:4 legacy encrypted DM). This issue weighs moving it to **NIP-17** (kind:14 chat message, sealed via NIP-59 kind:13 + gift-wrapped in a kind:1059 event). **Scope note:** this is *only* about the admin DM. The NIP-46 RPC envelope (kind:24133/24134) also uses nip04/nip44 adaptively, but that's the NIP-46 *protocol* — dictated by the connecting clients (lnbits, the spire) — and is out of scope; we can't unilaterally switch it without breaking them. ## Current vs proposed - **NIP-04 (today):** AES-256-CBC, no authentication; the event is a kind:4 authored by the bunker's admin key with a cleartext `["p", recipient]` tag and a real timestamp. So the *fact* that the bunker DM'd this operator, *when*, and *both pubkeys* are public; only the content body is (weakly) encrypted. - **NIP-17 (proposed):** the message (kind:14) is sealed (NIP-59 kind:13, NIP-44 v2 encrypted) and gift-wrapped in a kind:1059 event signed by a **throwaway ephemeral key** with a **randomized timestamp**. The outer event hides the sender, the content, the message kind, and the real time; only the recipient `p`-tag is visible (needed for delivery). ## Pros 1. **Metadata privacy.** Hides that *the bunker's admin identity* sent a DM, and when. The admin npub is a sensitive identifier (it *is* the bunker). NIP-04 leaks all of this. 2. **Modern, authenticated crypto.** NIP-44 v2 (ChaCha20 + HMAC) vs NIP-04's unauthenticated AES-CBC (malleable, no integrity). 3. **NIP-04 is deprecated** ecosystem-wide; clients are dropping it. We shouldn't be adding/keeping new NIP-04 paths. 4. **Cheap to implement.** nostr-tools (already our transport lib, `~2.20.0`) ships `nip17.wrapEvent(senderSecret, { publicKey, relays }, message)` and `nip59` — the send side is a few lines via a throwaway `RelayPool` (same shape as the current port). 5. Aligns with the stack's privacy-forward, Nostr-native direction. ## Cons / risks 1. **Recipient client support is the gating factor.** The admin client that *reads* this DM (the operator's nsecBunker admin UI / whatever subscribes) must support NIP-17 — i.e. subscribe for kind:1059 `#p=self`, unwrap the seal, render kind:14. If it only listens for kind:4, the NIP-17 message is **invisible**. **Action: confirm what reads these admin DMs and whether it does NIP-17 before switching.** 2. **Low marginal value for *this specific* message.** It's a one-shot boot notification, and the payload (connection string = the bunker's npub + relays) isn't a hard secret — the privacy win is real but modest here. 3. Slightly more moving parts (seal + wrap + ephemeral key + randomized created_at), and the randomized timestamp means the DM can appear up to ~2 days in the past in some clients — fine for a notification, worth knowing. 4. No clean half-step: NIP-44-encrypted DMs *are* NIP-17 (via gift-wrap); it's nip04 → nip17, not a smaller hop. ## Recommendation Correct direction, **low priority**, gated on **(1)** — verify the admin client supports NIP-17. Given the only DM is the low-sensitivity boot notification, there's no urgency, but since NIP-04 is deprecated we shouldn't grow its use. Good candidate to fold into the CLI-port follow-up (the CLI is the likely reader of admin events). If recipient support is uncertain, **keep NIP-04 for now** rather than dual-send (messy) — revisit once the admin-client NIP-17 story is confirmed. Refs: #44 (where the DM was ported off NDK to nostr-tools nip04), NIP-17, NIP-44, NIP-59.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/nsecbunkerd#46
No description provided.