Repository navigation
Lock a box to the devices paired with it (protocol v29) - #468
Merged
Merged
Conversation
A box's WebSocket, the port the phone and Tailscale-only Macs use, has no login of its own, and a default tailnet lets every device reach every other. A box can now serve that port only to devices paired with it: - A connection that isn't paired gets no events (no terminal output, no board) and every call but hello and pairing:redeem is refused with "This box needs pairing." SSH is never gated. - A device pairs by trading a one-time code (8 characters, 10 minutes, once) for a token of its own. Codes come from Settings → Boxes → Access → Pair a phone on a paired Mac (a QR the iPhone's Camera opens as ateamgo://pair), from the desktop over SSH, or from `ateam pair` in the box's terminal. - The box keeps pairings in ~/.ateam/pairings.json (0600), token and code hashes only. Unpairing a device drops its live connections at once. Wrong codes drop a connection after five, and codes are refused for a while after many across connections. - A new box comes up locked. A box that ran before stays open until it is locked from a paired device (Lock it, on the Mac or the phone), so an upgrade never locks a phone out; its card says anyone on the tailnet can control it. - The Mac keeps its token in its encrypted store and sends it with every hello; a locked box it can't open shows a code field instead of retrying. The phone keeps its token in the Keychain, shows the same field on the box's card, offers Lock it on an open box, and opens ateamgo://pair links. `ateam pair --unlock` opens a box again when no paired device is left.
Any app or web page can open an ateamgo:// link, and the phone used to pair with, and save, whatever host a pair link named, at once. Now a link with anything but a plain host, a port and an 8-character code is dropped, and a good one asks first: "Pair with this box?", naming its address. Apple's guidance for custom URL schemes: validate every parameter and limit what a URL can do on its own.
- A box gives out pairing codes only once it is locked (or over SSH). On an open box a code adds nothing, and a device that paired before the owner locked it would have kept its way in. - The phone keeps a locked box's refusal exact even when a wake failed too, so the card still offers its code field. - Lock it on the phone asks first, and says the Mac needs a code too if it reaches the box over Tailscale, from `ateam pair` in the box's terminal, which the phone can open. The phone has no other way to hand out a code. - The Mac's lock dialog says a phone needs Ateam Go 1.4 or later to pair.
Ateam Go on the App Store (1.3.x) has no pairing, so a box that came up locked would shut that phone out with nothing in the app to let it in. A fresh box now starts open, like one that has run before, with the warning on its card and Lock it a click away. LOCK_NEW_BOXES in cli.ts turns the old behaviour back on once an Ateam Go that pairs is live on the App Store. - `ateam pair` on an open box says to lock it first instead of printing a code that neither app has a field for. - The installer reports the box as locked, or open with where to lock it, in place of the line about pairing a phone. - The docs say a box starts open, and that a phone needs Ateam Go 1.4 or later to use a locked one.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A box's WebSocket, the port the phone and Tailscale-only Macs connect to, has no login of its own. A tailnet's default policy lets every device reach every other, so anything on the tailnet that reaches that port gets the box: terminals, agents' output, its GitHub token. Today a connection receives every event, terminal output included, the moment it opens, before it makes a single call.
What
A box can serve that port only to the devices paired with it.
system:helloandpairing:redeemis refused with "This box needs pairing." SSH (theattachrelay over the unix socket) is never gated.ateamgo://pair?..., plus the code to type;ateam pairin the box's terminal.~/.ateam/pairings.jsonon the box (0600), with only hashes of tokens and codes, read afresh on every use so the CLI and the daemon agree.LOCK_NEW_BOXESincli.tsmakes a fresh box come up locked once an Ateam Go that pairs is live there; an upgraded box stays as it was either way.install.shreports the box as locked, or as open with where to lock it.ateam pairprints a code for a locked box, and on an open one says to lock it first.ateam pair --unlockreopens a box when no paired device is left.ateam pair.ateamgo://pairlinks pair and save the box, after asking.Protocol v29:
system:hellotakes{ token }and answerspairing, both optional, so an older engine reads as an open box.pairing:*are new methods (FEATURE_MIN_VERSION.pairing).Checked
ateam pairCLI pairs it again.ateam pair, the real CLI: on a fresh data folder it says the box is open and exits 1, writing nothing; on a locked one it prints a code. The installer's check reads both correctly.Pairing links
Any app or web page can open an
ateamgo://link, and Apple's guidance for custom URL schemes is to validate every parameter and limit what a link can do on its own. So the phone drops a pair link with anything but a plain host, a port and an 8-character code, and asks "Pair with this box?", naming its address, before it does anything (apps/mobile/src/pair-link.ts, with tests).Two things stay open by design:
Not run live: the phone's own screens (the code field, Lock it, the
ateamgo://pairlink and its prompt) in a simulator or on a device, and whether the iPhone's Camera opens anateamgo://QR at all. Apple documents universal links for QR codes, and the typed code is the fallback. These ship in the next TestFlight build.