Repository navigation
feat(desktop): open bots on other computers in the account - #336
plotarmordev wants to merge 31 commits into
Conversation
The main process now speaks the phones' end-to-end encrypted channel (hello/welcome, sealed frames) through the account's relay, signed with this install's device key, and runs the 6-digit access request. Checked against the shared relay vectors and a host played in the test.
An account computer that approved this install opens as a store through the relay, so its bots join the sidebar with no SSH setup or QR pairing. Rows ask for access, show the code, and open the computer once approved. An SSH tunnel to the same computer still wins.
- A request I cancel before the computer shows its code is deleted there too, instead of staying on its screen until it expires. - A computer that refuses this device reads No access and stops retrying, as on the phones; a lapsed lease still retries. - A computer that restarts mid-link fails its calls so the next one reconnects, rather than calling it offline. - A channel closes once its computer's store goes, is opened once for concurrent first calls, and is signed only when opened. - The relay signer refuses when signed out instead of keying an empty user.
- An account computer's channel closes once an SSH tunnel takes it over or it turns out to be this computer, not only when its grant goes; only a revoked one loses its store. - A stream I close while its channel is still opening never subscribes, so the computer doesn't keep sending its events.
The connections plan, the relay reference and the sign-in plan still said the desktop app has no encrypted channel to account computers.
Upstream already bumped to 2.38.1, ahead of the latest tag, so this change ships in that release; my 2.39.0 bump is dropped and the connections doc says 2.38.1.
[High impact] The latest changes appear safe to merge; both numbered findings are addressed, with no new actionable issue found. SummaryType: feature | Areas: desktop, host, relay, web, docs | Priority: P3: low The desktop app can request access to other account computers and open their bots through the encrypted relay.
|
A reload only closed the page's local streams, so its relay subscriptions stayed open at the computer, could feed the reloaded page (whose stream ids started over from s1) and used up the host's subscription limit. - The preload closes every open stream on unload, local and remote, and gives each stream a random id, so nothing from a page before reaches one of the next page. - The main process keys relay streams per window and cancels a crashed page's, which never unloads.
The relay channel refused messages over 1 MiB, so a 5 MiB icon (about 6.7 MiB as base64 in JSON) failed. The host accepts 8 MiB from an approved device (host remote::channel MAX_INBOUND).
The desktop app now reports access_requested and access_request_failed (denied, expired or cancelled) through the host's track, as the phones already do. Approval stays device_paired, from the host.
A request withdrawn while its status poll was on the way could still end as denied or expired and count a second access_request_failed. The poll now drops a status that comes back after the request was withdrawn. The store's tests check the request, denial, expiry and cancellation events, and that a cancel during a poll counts once. Two comments now say what the code does: streams have random ids, and the relay channel takes 8 MiB.
|
I addressed Greptile's review in 4 commits (
Checks:
Not run: the two-computer flow (ask for access, approve, chat, reconnect, revoke). It needs a dev account signed in on two computers with the dev cloud, and my sandbox has no signed-in account. For the same reason, |
# Conflicts: # apps/desktop/src/renderer/client/host-client.ts
- Each call of an access request takes a current session token, so a computer that answers after the first token expires can still finish the exchange. The request stays with the account that made it, and a switch of account ends it. - Cancel before the computer shows its code now withdraws the request the main process is waiting on, instead of leaving it polling until it expires. - A withdrawal that fails is logged; the request then leaves the computer's screen when it expires.
Electron's crypto (BoringSSL) has no ChaCha20-Poly1305, so every relay channel failed with "Unknown cipher" in the running app while the unit tests, which run in Node, passed. The frames now use @noble/ciphers and still match the shared relay vectors byte for byte.
When a computer revokes this app, its bots read "No access" but stayed in the sidebar, and Settings kept offering Open until a manual refresh. The account is now listed again as soon as the computer refuses, so its bots go and it reads Ask for access, as on the phones.
|
Updates since the last review:
|
The relay's per-link budget of 8 MiB per 10 s counted wire bytes, while the host's 8 MiB cap for an approved device counts plaintext. Sealed into base64url frames, a 5 MiB icon is about 8.9 MiB and a message at the cap about 10.7 MiB, so the relay closed the link with 4008 rateLimited before the host ever saw it. The budget is now 12 MiB.
The JSON wrapper around the icon data is 17 bytes, so the message was 8 MiB + 1.
…open-upstream-pr-desktop-app-opens-bots- # Conflicts: # apps/desktop/src/renderer/store/cloud.ts # apps/desktop/src/shared/analytics.ts # host/src/analytics/reported.rs
- Pace outgoing frames to the relay's per-link budget (200 messages, 12 MiB per 10 s), so a large attachment no longer trips 4008 and drops the channel mid-upload. - Read the relay's upgrade status (the `ws` client exposes it; Node's built-in WebSocket doesn't): a fourth 403 in a row ends calls with 401, so a revoked device shows No access instead of retrying forever. - Close a link that heard nothing back between two pings, so the next call opens a fresh socket instead of reusing a deaf one.
|
Thanks for the review. I fixed all three findings in ad35909:
There are new unit tests for each in |
…open-upstream-pr-desktop-app-opens-bots- # Conflicts: # apps/desktop/src/renderer/views/settings/ComputersView.tsx
|
I need this so bad 🫠 |
Upstream added its own relay channel (main/channel/) and cloud access request for Codync Cloud computers. This branch now builds on those: the duplicate account-channel/channel-crypto modules are gone, the relay pacer moves into main/channel/, the access request gains the 6-digit code and Cancel for computers that aren't cloud-hosted, and useCloudAttachments opens every approved account computer.
- A computer that rejoins while frames still wait on the relay's rate window no longer gets those frames, sealed for the old channel, ahead of the new handshake; what already left still counts against the window. - An access code that arrives after its request was withdrawn no longer shows on, or counts for, the next request to that computer: each request carries its own id.
|
Thanks for both findings, fixed in 430de71.
I ran |
…open-upstream-pr-desktop-app-opens-bots- # Conflicts: # host/src/analytics.rs
…open-upstream-pr-desktop-app-opens-bots-
- A computer that turns this device away now refreshes the account's computers right away, so its bots go and Settings offers to ask again: the attachments watch each attached store's connection, which reaches neither the app nor the account's list. - Settings keeps a computer opened through the relay under "Other computers in your account" with Open, instead of hiding it once its store exists; only this computer and SSH ones have their own card.
|
Thanks for both findings; fixed in 3785088:
I also merged the latest |
A call queued behind a full relay window was sealed at once, so its timeout could fire before it left; the queued cancel then followed it and the computer still ran the change. The pacer now takes a function and makes each message only once the window has room for it: a call gets its id and frames when it leaves, and one given up on while it waited is never sent. The handshake's deadline likewise starts when hello leaves, not when it is queued.
|
Thanks, both fixed in 578cd7d. The pacer now takes a function and makes each message only once the relay's window has room for it. A call gets its id and is sealed when it leaves, so if it times out while it waits it is never sent (and no cancel goes out for it). The handshake's 10 s deadline now starts when |
Summary
The desktop app can now open bots on the other computers in its account, the same way the phones already do, with no SSH setup or QR pairing.
devnow has for Codync Cloud computers (apps/desktop/src/main/channel/,main/cloud-access.ts):useCloudAttachmentsopens every approved account computer over the channel, not only cloud ones, except this computer and any an SSH tunnel already reaches (renderer/lib/relay-plan.ts). A computer that refuses this device reads No access, the account is listed again, and its bots leave the sidebar.sasCodeinmain/channel/crypto.ts, checked against the shared relay vectors);cloud:cancelAccesswithdraws it. Codync Cloud computers still ask by themselves;renderer/store/account-computers.tskeeps the Settings request state for the others.main/channel/relay-pacer.ts), and the relay's byte budget is 12 MiB per 10 s so one message at the host's 8 MiB cap (about 10.7 MiB once sealed) fits (cloud/src/relay-wire.ts, with a test incloud/test/relay.test.ts).docs/architecture/desktop-app.md,connections.md,docs/reference/remote-relay.md,docs/guides/accounts-and-ssh.md,docs/plans/require-sign-in.mdand the user manual pageweb/content/docs/remote-access.mdx.Other clients: the iPhone and Android apps already open account computers over this channel, so this brings the desktop app level with them, and they don't change. The terminal UI has no account computers. The host's
tracknow accepts the phones'access_requestedandaccess_request_failed(reason:denied/expired/cancelled) from the desktop app too (host/src/analytics/event.rs,analytics/reported.rs,docs/reference/analytics-events.md). It bumps the version to 2.45.0 (2.44.1 is tagged).Validation
On macOS, with current
devmerged in (host and cloud on31022e9f; desktop again on578cd7da, which changes onlyapps/desktopand docs):cd host && cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test: all passed (847 unit tests, plus the integration suites).cd apps/desktop && npm ci && npm run typecheck && npm test: 495/495, including the new and updated tests:shared/cloud-access.test.ts(the code reaches the window only after the reveal; Cancel withdraws the request before or after the code),renderer/lib/account-computers.test.ts,renderer/lib/relay-plan.test.ts,main/channel/relay-pacer.test.tsandmain/channel/relay-channel.test.ts(a call that times out behind a full relay window is never sent; the handshake deadline starts whenhelloleaves),main/channel/crypto.test.ts(the 6-digit code matches the protocol vectors),shared/preload-streams.test.tsandrenderer/lib/refresh.test.ts.cd cloud && npm ci && npm test && npm run typecheck: 196/196, typecheck clean.Not run: Linux (Lima
codync-linux) and Windows (UTM), because neither VM is installed here.What's New: iPhone
zh-Hant
en-US
What's New: Android
zh-Hant
en-US