From 57f7e32c2461b71e2e8a832fb8be520d0653f098 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 11 Jun 2026 10:28:39 +0000 Subject: [PATCH] =?UTF-8?q?docs(roadmap):=20=C2=A78a=20done=20(mandatory?= =?UTF-8?q?=20pairing);=20split=20=C2=A78b=20into=20host+web=20/=20peer=20?= =?UTF-8?q?layers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §8a (require native pairing by default, serve --open) shipped + deployed. §8b (delegated approval) refined into §8b-1 (host pending-requests + mgmt endpoints + web Approve/Deny — achievable now) and §8b-2 (peer push to a paired Device A — needs the native/Apple client UI). Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/roadmap.md | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index 46435a4..d4d4a4a 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -139,23 +139,28 @@ it's unbuildable on the Linux dev box; the trait boundaries are already in the r The unified host + web-console pairing (arm a window → display the host PIN → user enters it on the client) is built and live. Two changes harden it from "works" to "secure by default": -- **Mandatory PIN pairing by default.** Today the punktfunk/1 host can run open (trust-on-first-use) - — *not* acceptable on a shared LAN, where any reachable device could connect. The unified host - should `require_pairing` out of the box: a client must complete the SPAKE2 PIN ceremony (one online - guess, no offline attack) before any session. The operator arms a window and reads the PIN from the - web console (already built); an explicit `--open` escape hatch covers trusted single-user setups. - The wire is already in place (`M3Options.require_pairing` + the `serve_session` gate); this flips - the default and threads it through `serve --native` and the mgmt arm endpoint. -- **Delegated pairing approval** — the ergonomic enabler for "mandatory" (pair a new device without - fetching the host PIN out of band): +- ✅ **Mandatory PIN pairing by default — done & live** (`§8a`, `serve --native` now requires + pairing; `serve --open` disables it). An unpaired client is rejected at the session gate; pairing + is via the SPAKE2 PIN ceremony (one online guess, no offline attack) armed from the web console. + Validated live: unpaired → "this host requires pairing", then web-armed PIN → "client trusted". + Deployed to the dev box + Bazzite. +- **Delegated pairing approval** *(next — the ergonomic enabler for "mandatory": pair a device + without fetching the host PIN out of band).* Target flow: 1. Device A is already paired (authenticated) to Host X. 2. The user tries to connect Device B to Host X. - 3. Host X pushes a request to the authenticated Device A: *"Allow Device B to pair with Host X?"* - 4. The user approves/denies on Device A; on approve, Host X admits Device B — binding B's - certificate fingerprint — with no PIN typed. + 3. Host X surfaces a request: *"Allow Device B to pair with Host X?"* + 4. The user approves/denies; on approve, Host X admits Device B — binding B's certificate + fingerprint — with no PIN typed. - Needs: a host→client *pairing-approval-request* (B's fingerprint + a human label) delivered to A's - live connection (a QUIC side-plane message) or polled via the mgmt API; an approve/deny round-trip - carrying an approval token; the host gating B's admission on it. The web console **and** the Apple - client render the approval prompt. PIN pairing stays the bootstrap (the first device, or when no - paired device is online to approve). + Two buildable layers: + - **§8b-1 (host + web — achievable now):** an unpaired B that connects to an approval-enabled host + is held as a **pending request** `{id, name, fingerprint, requested_at}` in `NativePairing` + instead of a flat reject; mgmt gains `GET /native/pending` + `POST /native/pending/{id}/{approve, + deny}`; the web console lists pending requests with Approve/Deny. The **operator approves from + the console** — delegated approval via the management surface. + - **§8b-2 (peer push — needs the client):** the host also pushes the pending request over a paired + **Device A**'s live QUIC connection (a new control-plane message); A's app renders the prompt and + replies approve/deny — the user's exact "Device A gets a notification" flow. The native/Apple UI + is a client-agent task. + + PIN pairing (§8a) stays the bootstrap — the first device, or when no approver is online.