Expand description
Concord v2 stream-key NIP-42 authentication.
Every v2 plane is kind-1059 traffic addressed to a DERIVED per-stream pubkey
(control, guestbook, per-channel chat, rekey, dissolved) — never the user’s
own identity. Relays that gate kind 1059 behind NIP-42 (ditto-relay’s default
AUTH_KINDS=4,1059) require that EVERY authors entry in a kind-1059 REQ be
an authenticated pubkey on the connection, and reply
CLOSED auth-required: all authors must be authenticated otherwise. The
user’s login can’t satisfy that — the stream address isn’t their pubkey — so
an unauthenticated client reads back ZERO events and a join’s control-plane
verify (or any community fetch) fails closed.
The fix (mirroring Armada’s streamAuth): the client HOLDS the stream secret
keys (derived from the community_root / channel keys it already stores), so
it can NIP-42-authenticate AS each stream by signing an extra kind-22242 AUTH
event per stream against the relay’s challenge. This module is the registry
of stream keys the client currently holds plus the challenge responder; the
connection ends up authenticated as the user AND every stream it will query.
Signing is local (raw derived keys) — it never touches the account signer / bunker.
Functions§
- clear
- Forget every registered stream key (on session swap). The responder task exits
on its own when its
SessionGuardinvalidates. - ensure_
responder - Ensure the persistent stream-AUTH responder is running for this session (idempotent). It watches the client’s notification stream and, on EVERY relay AUTH challenge, authenticates as all registered stream keys on that relay.
- is_
empty - Whether we hold any stream keys (skip the whole dance when not).
- prime
- Prepare gated relays for an imminent fetch: make sure the community’s stream keys are registered and the responder is live, so the fetch’s REQ-triggered challenge is answered. A no-op when no client is connected (offline tests).
- prime_
auth - Prime the connection AUTH on
relaysbefore a live subscription: a subscription (unlike a fetch) isn’t auto-retried after the AUTH gate, so the socket must already be authenticated as EVERY stream the sub’sauthorswill name — one unauthenticated key fails the whole REQ. Two passes: - register
- Register a batch of stream keys (idempotent). Returns how many were NEW.
- register_
community - Register every plane a community currently exposes: control, guestbook, the dissolved plane, and each readable channel’s Chat Plane (a keyless private channel has no readable plane yet, so it’s skipped — its rekey plane keys up first). Called at join and on every follow so a rotated address is covered.