Learn the relay security pin from the active client, whichever path made it

A strict pairing offer kept its minimum only until the relay upsert rebuilt the connection without it, and a pin learned by a client was persisted only when the controller had constructed that client itself. Probe clients adopted from pairing or startup never reported it, so a saved host that negotiated protected lost the pin on restart.

The offer's parsed connection is now stored as is. The controller reads the active client's negotiated floor when it reports connected and asks the store to pin the daemon identity; client constructors no longer carry a persistence callback.
This commit is contained in:
Mohamed Boudra
2026-10-21 15:33:21 +02:00
parent 5310d97e66
commit e50482d4c2
3 changed files with 143 additions and 60 deletions
+2
View File
@@ -57,6 +57,8 @@ The daemon advertises `server_info.features.relayProtectedSecurity: true` on eve
The app pins `minimumSecurityMode: "protected"` on every relay connection to a daemon public key after the first protected handshake with that key, or when the pairing offer carries `minimumSecurityMode`. A pinned client passes `minimumMode: "protected"` to the handshake and refuses a legacy ready before sending credentials. The pin belongs to the daemon identity, not to a relay address: re-importing the same key through any relay keeps it, a different key is a different connection, and connection failures never clear it.
The handshake result is read in one place, `HostRuntimeController` when the host's active client reports connected. Every client reaches that point, whether the controller created it or adopted it from a pairing or startup probe, so no client constructor carries a persistence callback. A probe that negotiated protected but was never adopted pins nothing; the pin lands when the host first goes online.
Within one client process the floor also rises on its own. `DaemonClient` and the Node host connector remember a protected result and require it on every later attempt, so a reconnect after a relay drop cannot be answered in legacy mode even before the pin is persisted.
The daemon refuses a legacy client with close `1008` and reason `protected endpoint security required`, and logs `relay_e2ee_handshake_rejected`. That close code stops at the relay: both relays replace a daemon-side close with their own (the wrangler relay sends `1012 Server disconnected`), so an old client sees an ordinary disconnect and keeps retrying. The only client-detectable failure is the client's own `4002`, which stops reconnecting and tells the user to update.