Repository navigation
Show and store only the device labels Pocket sends at pairing - #1163
Conversation
The pairing approval modal drew the phone's free-text label right above the two-digit input, so a label such as "iPhone · code 58" could tell the person which digits to type. A presence proof does not narrow who sent it: redeeming a setup QR registers the redeemer's own passkey on the account, so whoever redeems a leaked QR first passes the proof. Pairing now matches one-time connection: PAIRING_DEVICE_LABELS holds the two labels Pocket sends, and knownPairingDeviceLabel maps anything else to "Unknown device". The Burrow applies it on receipt, before the modal, the queue, or the ACL record carries the label, and again wherever a record's label is shown (the held-pane strip and the push device list), so a record written by hand or by an older build displays the same way. Pocket's deviceLabel is typed to the set. boundedPairingLabel has no callers left and is removed; the modal's "(unnamed)" fallback is dead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
c9a9d19
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://6ae59115.mouseterm.pages.dev |
| Branch Preview URL: | https://pairing-known-labels.mouseterm.pages.dev |
dormouse-bot
left a comment
There was a problem hiding this comment.
Build & Test fails because of this change: relay/test/e2e-ceremony.test.mjs ("a phone scans, registers off the token, pairs, and is told everything it pins") still pairs with the fixture's default label 'iPhone Safari' and asserts record.label === 'iPhone Safari', while the Burrow now stores 'Unknown device' (job log). The PR's sweep caught the remote-lib-common and lib harnesses but missed this relay one.
Both lines sit outside the diff, so there's no inline suggestion. The fix is to import PAIRING_DEVICE_LABELS from remote-lib-common, default the phone({ credential, label = ... }) fixture to one of its members, and assert the stored record against that member. The other 'iPhone Safari' strings under relay/test/ are passkey labels and are unaffected. I can push that commit if you'd like.
The Argos checks are red on the story change (UnnamedDevice/LongValues replaced by UnknownDevice, plus the Default label), which is the expected visual diff to approve.
CI failed — relay e2e-ceremony test still asserts a free-text pairing label.
The Burrow now records any other label as 'Unknown device'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The laptop now shows and stores a pairing device label only if it is one of the two names Pocket sends. Any other label becomes "Unknown device", as one-time connection already does with its own set.
Why
The pairing modal draws the phone's label right above the two-digit input. The phone chooses both the digits and the label, so a label like "iPhone · code 58" reads as an instruction, and the person types the sender's digits instead of reading them off their own phone.
The rationale had dismissed this for pairing, because a request needs a presence proof from a passkey on the owner's account. That doesn't narrow who can send one: redeeming a setup QR registers the redeemer's own passkey on the account and signs it in. This holds for
setupFinishin bothrelay/src/app.tsandhosted/server/relay-api.ts. So whoever redeems a leaked QR first passes the proof. That is the case the reverse code exists for, since the owner's phone finds the invitation reserved and shows no code.What changed
PAIRING_DEVICE_LABELS('Dormouse Pocket (Home Screen)','Dormouse Pocket (browser)') andknownPairingDeviceLabelare new inremote-lib-common/src/security/e2e-ceremony.ts, beside one-time's set. Pocket'sdeviceLabel()is typed to the set, so the two cannot drift.PairingQueueItem, and the saved ACL record all get the mapped value.boundedPairingLabelhad no callers left, so it is removed. So is the modal's(unnamed)fallback, which can no longer happen. The test harnesses and stories send a Pocket label.Specs
remote-security-model.md→ Pairing gains "The pairing modal and the ACL record never carry text the phone chose." The one-time rule now points at it.security-remote.md"Trust boundary" Add auto-update for the standalone app #7 is edited in place, so no rule id moves. It now fails if the label reaches anything except throughknownPairingDeviceLabel.remote-api.md,pocket-app.md, anddocs/stories/pairing.mdxare updated to match.Tests
Each new test went red under its mutation:
remote-lib-common/test/e2e-ceremony.test.mjs: the exact frozen set; members pass through; labels with digits, near-misses, one-time names, empty strings, and non-strings map to the fallback. Loosening membership to a prefix match turns it red.burrow-runtime.test.ts:'iPhone · code 58'names its pane strip "Unknown device". Dropping the mapping at the strip turns it red.service.test.ts: thePairingQueueItemand the stored record.push-delivery.test.ts: the device list maps record labels. The preview test was rewritten, because labels no longer tell records apart.views.test.ts(new): both install modes produce exactly the set.App.scan.test.tsx:pairreceives a member.These pass:
remote-lib-common(346 tests);relay(292), whose e2e ceremony test now pairs with a Pocket label; libvitest run src/remote src/host/remote(1270) andtsc -b; standalonetsc --noEmit; spec, markdown, public-docs, and e2e lints;scripts/security-audit*.test.mjs(154). Thepairing-acl-live-before-savecanary seed still applies.🤖 Generated with Claude Code