fix(mobile): give a direct handshake as long as the desktop allows it (#36864)

The phone gave a direct socket 5 s from open to authenticated, while
the desktop keeps an unauthenticated socket for 10 s. On a slow link
(a handshake is two round trips, so ~2.5 s RTT is enough) the phone
dropped the socket the desktop would have accepted, then redialed into
the same deadline forever: the 'Can't connect' loop a test documented.

Both ends now share PAIRED_E2EE_HANDSHAKE_DEADLINE_MS (10 s). A link
that needs 6 s to authenticate now connects on the first dial; one that
never authenticates still escalates the same way, 5 s later. Relay
dials are unaffected: they keep their own stage budgets and race the
direct dial after 2.5 s.
This commit is contained in:
Neil
2026-10-31 21:22:55 -07:00
committed by GitHub
parent de74d6b47a
commit fbb3381dfe
5 changed files with 35 additions and 15 deletions
+2 -2
View File
@@ -1,5 +1,6 @@
// Keep E2EE framing outside transport-independent plaintext RPC handlers.
import type { WebSocket } from 'ws'
import { PAIRED_E2EE_HANDSHAKE_DEADLINE_MS } from '../../../shared/paired-e2ee-handshake-deadline'
import { deriveSharedKey, encrypt, decrypt, decryptBytes } from '../../../shared/e2ee-crypto'
import {
DesktopMobileE2EEV2Session,
@@ -30,7 +31,6 @@ import type {
} from './rpc-binary-sender'
import type { DevicePrincipal } from '../device-principal'
const HANDSHAKE_TIMEOUT_MS = 10_000
const MAX_CONSECUTIVE_DECRYPT_FAILURES = 5
export type E2EEChannelOptions = {
@@ -104,7 +104,7 @@ export class E2EEChannel {
this.handshakeTimer = setTimeout(() => {
this.onError(4002, 'E2EE handshake timeout')
}, HANDSHAKE_TIMEOUT_MS)
}, PAIRED_E2EE_HANDSHAKE_DEADLINE_MS)
}
onMessage(
@@ -0,0 +1,6 @@
/**
* How long a paired socket may take from open to authenticated, on both ends. The desktop closes a
* socket that has not authenticated by then, so a phone that gives up sooner drops slow links the
* desktop would still have accepted.
*/
export const PAIRED_E2EE_HANDSHAKE_DEADLINE_MS = 10_000