Skip to content

NIP-5D: nostr applets#2303

Open
dskvr wants to merge 2 commits intonostr-protocol:masterfrom
dskvr:nip/5d
Open

NIP-5D: nostr applets#2303
dskvr wants to merge 2 commits intonostr-protocol:masterfrom
dskvr:nip/5d

Conversation

@dskvr
Copy link
Copy Markdown
Contributor

@dskvr dskvr commented Apr 5, 2026

Summary

NIP-5D defines a postMessage protocol for sandboxed web applications ("napplets") running in iframes (or web-views) to communicate with a hosting application ("shell"). The NIP is deliberately a thin core: it specifies the envelope, sandbox rules, sender identification, and manifest-based capability negotiation. Actual protocol messages — relay access, storage, signing, theming, IFC, and so on — are defined by NUB (Napplet Unified Blueprint) extension specs, each of which owns a capability domain.

NIP-5D depends on NIP-5A for napplet manifests and aggregate hash verification (see PR #2287).

What's in the spec

  • TransportpostMessage with '*' target origin (required for opaque-origin sandboxed iframes). Sender identification via MessageEvent.source (unforgeable Window reference), not event.origin.
  • Sandbox — Napplet iframes MUST use sandbox="allow-scripts" without allow-same-origin. Shells MUST NOT provide window.nostr (NIP-07); signing and encryption are security-critical and mediated by the shell through NUB-defined APIs.
  • Wire format — Generic JSON envelope: { "type": "<domain>.<action>", ...payload }. The type field is a domain.action discriminant where the domain corresponds to a NUB capability name (e.g., a NUB named foo owns all foo.* types). The NIP does not enumerate message types. Unknown types MUST be silently ignored to preserve forward compatibility.
  • Identity — The shell assigns napplet identity at iframe creation time by mapping the iframe's Window reference to the (dTag, aggregateHash) tuple from the NIP-5A manifest. No handshake, no challenge-response, no negotiation. Messages from unmapped MessageEvent.source values MUST be silently dropped.
  • Manifest-level NUB negotiation — NIP-5A napplet manifests declare required capabilities via ["requires", "<nub-name>"] tags. Shells check these at load time and SHOULD reject or warn on mismatch.
  • Runtime capability querywindow.napplet.shell.supports('<capability>') returns a boolean. Capability strings are namespaced: bare/nub: for NUB capabilities (e.g., 'relay', 'nub:identity'), perm: for permissions (e.g., 'perm:popups'). Napplets MUST gracefully degrade when a capability is absent.
  • Security model — Iframe sandbox enforcement, unforgeable MessageEvent.source identity binding, aggregate hash verification against NIP-5A manifests, cleartext-only napplet output (shells MUST NOT sign or broadcast ciphertext supplied by a napplet), and silent-drop of unrecognized types to prevent capability probing.

What's NOT in the spec

Specific protocol messages — relay proxy, signer proxy, storage, IFC, theming, feeds, chat, and so on — are defined externally as NUB (Napplet Unified Blueprint) proposals. The NUB ecosystem is organized into two tracks:

  • NUB-WORD (interfaces) — canonical specs for shell-provided API surfaces (e.g., a relay NUB owning the relay.* domain and window.napplet.relay, a storage NUB owning storage.* and window.napplet.storage). One spec per domain name.
  • NUB-NN (message protocols) — numbered specs (NUB-01, NUB-02, …) for napplet-to-napplet event semantics where competing designs are welcome (feed rendering, chat, collaborative editing, etc.).

This split keeps the NIP focused on the core primitive and lets the capability ecosystem iterate independently.

Implementations

There are already a few implementations, will be published soon.

Dependencies

  • Requires NIP-5A for napplet manifest format and aggregate hash verification (PR #2287)
  • References NIP-07 (MUST NOT be exposed to napplet iframes)

@dskvr dskvr marked this pull request as draft April 5, 2026 20:55
@dskvr dskvr force-pushed the nip/5d branch 2 times, most recently from 79ff1aa to 49d3bb7 Compare April 7, 2026 10:16
Expanded on iframe sandboxing requirements and added details about class-posture delegation for napplets.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant