2865368771
The accepts for #9 (PIN-window burn) and #13 (knock-queue flood) rested on a circular premise — each cited the other as the safe fallback — and a re-review showed one LAN attacker could defeat BOTH, denying all onboarding. Close them: - #13 per-source-IP cap on the pending-knock queue (MAX_PENDING_PER_IP) so one host can't fill/evict the 32-slot queue (QUIC validates the source address); and eviction now NEVER drops a live *parked* knock (a held-open connection awaiting operator approval), so a cert-rotating flood can't evict the genuine device being onboarded. This makes the delegated-approval path genuinely flood-resistant — restoring the validity of #9's "use delegated approval on hostile LANs" fallback. - #9 fingerprint-bindable PIN window: `NativePairing::arm_for(ttl, Some(fp))` binds the window to one operator-selected device; `pin_for_attempt` returns `BoundToOther` for any other fingerprint, which the QUIC pair path rejects WITHOUT consuming the window — so an unpaired peer can neither pair nor BURN a window armed for a specific device (it can't forge the bound fingerprint). The mgmt `POST /native/pair/arm` gains an optional `fingerprint` (from a pending knock); unbound arming keeps the legacy any-device behavior (trusted-LAN). (Web-console "pair this pending device with a PIN" UX is a follow-up; the flood-resistant knock path above is the immediate hostile-LAN onboarding path.) + regression tests (armed_pin_is_fingerprint_bindable, pending_per_ip_cap_and_parked_protection); api/openapi.json regenerated. 110 host tests + clippy + fmt green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 KiB
65 KiB