Skip to content

feat: let Sapwood invite a phone instead of reading its code - #146

Merged
TheCryptoDonkey merged 2 commits into
mainfrom
feat/enrol-invite
Sep 25, 2026
Merged

TheCryptoDonkey merged 2 commits into
mainfrom
feat/enrol-invite

Conversation

@TheCryptoDonkey

Copy link
Copy Markdown
Member

Reverses the optical step of phone-unlock enrolment. The old flow needed Sapwood to read the phone's QR, which a desktop with no camera cannot do.

  1. Add a phone shows a QR: heartwood-unlock:invite?v=1&k=<one-off pubkey>&r=<rendezvous>&x=<expiry>&relay=…. The secret half stays in page memory and is zeroed on confirm, cancel, expiry or teardown. The invite lives for 10 minutes.
  2. Cambium scans it and replies with one kind-24137 event:
    • from a throwaway key;
    • tags h and NIP-40 expiration only;
    • content: its usual enrolment code, NIP-44 v2 encrypted to the invite key.
  3. Sapwood shows the first valid reply's five request words for the owner to compare with the phone. A second reply with a different enrolment key aborts. Continue runs the existing enrolPhone path unchanged: board button, words on the board's card, hand-off, check code.

Someone who saw the QR could send their own key. The words check on the phone and on the board, plus the two-replies abort, catch that. It is the same trust as the existing words check. A relay observer cannot encrypt to the invite key, because it only travels optically.

The paste/scan-the-phone path stays behind a disclosure for older Cambium builds. The shared vector test/fixtures/enrol-invite-v1.json is byte-identical to Cambium's copy. Firmware is unchanged.

Not yet bench-tested end to end; do not merge before a round trip on hardware.

Sapwood now shows a QR ("Scan this with Cambium") that the phone reads
and answers over the relay with the same enrolment code as today,
reversing the old scan/paste step for a desktop with no camera. The
paste/scan path stays as a secondary disclosure for older Cambium
builds. First valid reply wins; a second, different reply aborts the
attempt rather than guessing which phone the owner meant.

Adds enrol-invite.ts (invite creation, URI parsing, reply verification,
and a small state reducer for the collector) with a shared JSON test
vector at test/fixtures/enrol-invite-v1.json for parity with Cambium.
@TheCryptoDonkey
TheCryptoDonkey merged commit 7ee377c into main Sep 25, 2026
4 checks passed
@TheCryptoDonkey
TheCryptoDonkey deleted the feat/enrol-invite branch September 25, 2026 23:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant