fix: pairing token enforcement, QR pairing, background notifications - #24
Merged
Conversation
Pairing was broken in production three ways: the iOS app sent raw JSON the daemon's wire decoder rejects, the pairing token from the QR payload was never transmitted or validated (trust-on-first-connect), and devices were stored under the BLE central UUID instead of their own deviceID so challenge verification and re-identify could never find the key. - PairRequestMessage now carries deviceID and pairingToken - Daemon validates the token against the active pairing window and stores devices under their own deviceID - 5 new tests covering token enforcement (valid/wrong/missing/no-window plus post-pairing auth) - DaemonCoordinator shared state now guarded by a lock (was racy @unchecked Sendable); pendingAuthentications entries cleaned up after each auth resolves; expired challenges/nonces pruned every 60s - PAM socket timeout now daemon timeout + 2s so an approval arriving at the deadline is not lost to the tie
- touchbridge-test pair now renders the pairing payload as a QR code PNG and opens it (image deleted once pairing ends) - iOS app gains a camera QR scanner as the primary pairing path; manual JSON entry stays as fallback - iOS pairing flow now performs the real BLE ceremony: scan for the Mac from the payload, send a wire-format pair request with the token, and only report paired after the Mac accepts (previously the manual-entry path never sent the phone's key to the Mac at all) - Challenges arriving while the app is backgrounded post a local notification and defer Face ID until the app foregrounds — before, the approval prompt silently never appeared - Pairing rejection now surfaces an error with recovery instructions - App version read from bundle instead of hardcoded 0.1.0-alpha
- Add scripts/patch-pam.sh: standalone PAM activation for Homebrew/pkg users — setup.md pointed at a script that did not exist, so cask users could not enable sudo auth by following the docs; now shipped in the pkg and documented with a curl fallback for older installs - build-release.sh derives the artifact version from the git tag instead of hardcoded 0.1.0 (v1.0.0 release shipped 0.1.0-named artifacts); cask notes the legacy filename until the next release - Sync test count to 127 (111 daemon + 16 protocol, verified) across README badge/body and launch copy — README said 91, CHANGELOG 129 - Bump menubar and companion versions to 1.0.0; SECURITY.md supported versions updated to 1.0.x - limitations.md: correct stale single-device claim (daemon side is multi-device since PR #18), document SSH/iPad/locked-phone behavior - setup.md: document QR-scan pairing flow and token expiry
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.
Summary
Fixes the production pairing flow (which was broken end-to-end), enforces the pairing token as a real security boundary, and removes the biggest first-run UX gaps.
Security: pairing token now enforced
Pairing on real devices was broken three ways:
Now
PairRequestMessagecarriesdeviceID+pairingToken, the daemon validates the token against the active 5-minute pairing window (wrong/missing/expired → rejected), and devices are stored under their own ID. 5 new tests cover enforcement.Daemon hardening
DaemonCoordinatorshared state is now lock-guarded (was@unchecked Sendablewith real races from CB callbacks + Tasks)pendingAuthenticationsentries no longer leak on the timeout pathUX
touchbridge-test pairrenders and opens an actual QR code imageDocs / distribution
scripts/patch-pam.sh— setup.md sent Homebrew users to a script that didn't exist, so cask users couldn't activate sudo auth at all; now shipped in the pkg with a curl fallback for existing installsbuild-release.shversions artifacts from the git tag (v1.0.0 release had shipped 0.1.0-named artifacts)Verification
swift test)-Werror