Skip to content

feat(e2ee): pair a browser device with the native daemon through the worker barrier - #435

Merged
Lokesh7025 merged 1 commit into
RCfrom
remote/phone-web
Sep 25, 2026
Merged

Lokesh7025 merged 1 commit into
RCfrom
remote/phone-web

Conversation

@Lokesh7025

Copy link
Copy Markdown
Contributor

Summary

This is the first step toward /remote from a phone web browser. The browser binding could register a device endpoint, but it could not take part in native pairing, and its witness barrier existed only in tests. This PR closes both gaps and adds a build that trusts a real witness.

Pairing (Rust, shared with the browser)

  • PairingClaimV1::create_at and Phone::join_published_welcome now build for wasm32.
  • The activation payload moves to pairing::pair_activation_payload, so native and browser sign identical bytes.
  • BrowserEndpoint gains three operations:
    • pairing_claim: a deterministic claim over the registered KeyPackage for a matching invitation. It is refused once a transaction is pending or the image has joined.
    • join_published: kind 8 over the daemon's published Welcome, with the daemon as the expected inviter.
    • prepare_pair_activation: kind 9 over the native activation payload. The daemon's accept_activation verifies it unchanged.

Replica trust configuration

  • ReplicaTrustSet::decode_config and encode_config define a canonical, bounded byte form: version, three replicas, one to four keys each.
  • The Node test artifact can build daemon and device endpoints from a configured trust.

Worker barrier and page surface

  • worker/barrier.js runs fresh read, reconcile, mutate, continue against the fixed same-origin /v1/e2ee/witness.
  • The witness credential enters once through authorizeWitness() and never leaves the worker. The page receives only exact released results, never requests, certificates, or credentials.
  • The loader exposes createDeviceEndpoint / openDeviceEndpoint handles for pairing and every supported device mutation.
  • Production still fails with rollback_anchor_unavailable. worker/trust.js names no trust, and check-abi enforces that.
  • If a registration fails certification, the worker releases the endpoint. The page reopens it and the next call recovers the committed pending request.

Deployment-test artifact

  • build.mjs deployment-test produces the production artifact with every module byte-identical except worker/trust.js. That module loads trust/replica-trust.bin, pinned by size and SHA-256 in integrity.json.
  • Trust is never taken from a link, query string, or page input.
  • check-abi verifies the byte identity, the single export delta (deployment_test_replica_trust), and the absence of test identifiers.
  • pnpm test:deployment pairs a real browser with a real native daemon through that artifact and a same-origin witness. It then exchanges messages both ways and reopens the endpoint. CI runs it for each browser in the matrix.

The AWS side of the witness is in #434.

Known risk (not fixed here)

KeyPackages carry not_before = the device's clock. A daemon whose clock is behind the phone's by more than the pairing window rejects the claim as KeyPackage. The browser pairing test advances the daemon clock by 2 s to model a small skew. A real phone with a fast clock could hit this, so it needs a tolerance decision before phone testing.

Test plan

  • cargo fmt --check; clippy -D warnings in all CI configurations, plus wasm32 --features deployment-test
  • cargo test -p axl-e2ee: 145 passed with browser-test-fixtures, 133 with node-test-fixtures, including browser_device_pairs_with_the_native_daemon_lifecycle and the trust-config round trip
  • Node binding tests (11), including "configured trust certifies only through the named replicas"
  • Browser build / build:test / deployment-test, check:abi, check:types
  • Existing Playwright suite: 14 passed (Chromium, Firefox)
  • pnpm test:deployment: passed on Chromium and Firefox. WebKit could not launch locally because of missing host libraries, so CI covers it.

…worker barrier

The browser binding could register a device endpoint but could not take
part in native pairing, and its witness barrier existed only in tests.
A phone web client needs both, plus a build that trusts a real witness.

Pairing (Rust, shared with the browser):
- PairingClaimV1::create_at and Phone::join_published_welcome build for
  wasm32. The activation payload moves to pairing::pair_activation_payload
  so native and browser sign the same bytes.
- BrowserEndpoint gains pairing_claim (a deterministic claim over the
  registered KeyPackage for a matching invitation, refused once a
  transaction is pending or the image has joined), join_published (kind 8
  over the daemon's published Welcome with the daemon as inviter), and
  prepare_pair_activation (kind 9 over the native activation payload, so
  the daemon's accept_activation verifies it unchanged).
- A browser test pairs with the native daemon lifecycle end to end:
  submit, confirm, Welcome, join, activation, messages both ways, and the
  identity, ordering, and replay refusals.

Replica trust configuration:
- ReplicaTrustSet::decode_config/encode_config define a canonical,
  bounded byte form (version, three replicas, one to four keys each).
- The Node test artifact can build daemon and device endpoints from a
  configured trust, and a test shows receipts from unnamed replicas
  never complete an operation.

Worker barrier and page surface:
- worker/barrier.js runs fresh read, reconcile, mutate, continue against
  the fixed same-origin /v1/e2ee/witness path. The credential enters once
  through authorizeWitness() and never leaves the worker; the page sees
  only exact released results.
- The loader exposes createDeviceEndpoint/openDeviceEndpoint handles with
  pairingClaim, joinPublished, preparePairActivation and the existing
  device mutations. Production creation still fails with
  rollback_anchor_unavailable because production names no trust.
- A registration that fails certification releases the worker's endpoint
  so the page reopens it; the next call recovers the committed request.

Deployment-test artifact:
- `build.mjs deployment-test` is the production artifact with every
  module byte-identical except worker/trust.js, which loads
  trust/replica-trust.bin pinned by size and SHA-256 in integrity.json.
  Trust is never read from a link, query, or page input. check-abi
  verifies the byte identity, the export delta, and that production
  still names no trust.
- `pnpm test:deployment` pairs a real browser with a native daemon
  through that artifact and the same-origin witness path, then exchanges
  messages both ways and reopens the endpoint. CI runs it for every
  browser in the matrix.

Signed-off-by: Lokesh <lokeshselvam7025@gmail.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 44fb831b-8a2e-4702-ac99-be8fc234d940

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@Lokesh7025
Lokesh7025 merged commit cb33af5 into RC Sep 25, 2026
33 of 34 checks passed
@Lokesh7025
Lokesh7025 deleted the remote/phone-web branch September 25, 2026 15:28
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