Skip to content

feat(relay): show both key IDs when a relay key does not match its PC id - #2703

Merged
devswha merged 2 commits into
mainfrom
feat/relay-key-fingerprints
Nov 4, 2026
Merged

devswha merged 2 commits into
mainfrom
feat/relay-key-fingerprints

Conversation

@devswha

@devswha devswha commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Summary

The phone's hosted shell refuses a pairing when a relay key is not the one its PC id names. This happens with a pairing link that carries another key under a PC's id, with a saved pairing whose key does not match its id, or when a link's key and the saved key disagree on connect. Before this PR the refusal was a sentence only. Now the phone also shows two IDs a person can compare:

  • The ID the link names, or the ID this phone paired with: the server_id in question. A PC's server_id is a SHA-256 of its real relay key (deriveServerId).
  • The ID of the key the link carries, or of the key this phone saved: the ID that key would have, computed the same way. It shows "Not a valid key" when the key does not parse.

Each ID is labelled by where it came from. The phone never calls either one "the PC's", because a link can name any id it likes. Only the PC's own screen does that: Settings → Phone & devices now shows the PC's ID under its pairing QR code, and the phone's screen points there.

Each ID is shown in eight groups of four characters. A group that differs from the named ID is marked by weight, an underline and colour, and is named "differs" for screen readers.

Both IDs are computed on the device from data it already holds: the link's fragment, the saved pairing, and the PC's own offer. Nothing new is sent to the relay or the PC. The refusal itself is unchanged: no pairing happens, and no saved key is touched.

Changes:

  • src/lib/relay/shellState.ts: keyIdOf, and keyMismatch, which picks the first key that is not the named id's and records where it came from (link or saved). The forged and identity-changed states gain an optional mismatch.
  • src/lib/relay/device.ts: ServerIdentityChangedError carries the saved key and the offered key.
  • src/lib/relay/shell.tsx: fills mismatch on the three refusal paths.
  • src/components/KeyId.tsx (new), RelayShell.tsx and RelayPanel.tsx: the grouped ID, the two-ID block, and the PC's own ID under its QR code. Translations for ko, ja and zh.

Design idea credit: the idea of comparing fingerprints when keys disagree came from a study of another project. No code was taken from it.

Screenshots

A pairing link whose key is not the key of the id it names, opened in the hosted shell.

Before After
1280 · dark
1280 · light
390 · dark
390 · light

Validation

  • bun run check fast: all green (unit 10900 pass, 0 fail), on a tree byte-identical to this head (c627660d).
  • bun test src/components/RelayShell.test.tsx src/lib/relay/shellState.test.ts: covers both states rendering the two IDs with exactly the differing groups marked; the labels by provenance, including that no id is called the PC's and that a bad saved key is labelled the saved key's, not the link's; the invalid-key case; and keyMismatch picking the right key and source in either order. The provenance test fails against the first version of the screen.
  • bun test src/lib/i18n.test.ts: every new string has ko, ja and zh.
  • Built the hosted shell (bun run build:shell) from main and from this branch, and opened a forged pairing link in Chromium at 1280×800 and 390×844, dark and light.
  • Not run: Integration and browser lanes, and Windows. CI runs them.

A pairing link or a saved pairing whose relay key is not the one its PC's
id names was refused with a sentence only. The phone now shows the PC's ID
(a SHA-256 of its real key, the server_id) and the ID the other key would
have, in groups of four, the groups that differ marked by weight, underline
and colour and named for a screen reader. The PC shows its own ID under its
pairing QR code, so a person can tell which one is the PC's.

Both IDs are derived on the device from what it already holds; nothing new
is sent to the relay or the PC.
Codex review: on a forged link the id shown as "This PC's ID" was the link's
own server_id, which the link chooses; and when a saved key was the bad one,
it was labelled as the link's. The phone now labels the ids as the one the
link names or this phone paired with, and the key's as the link's or the
saved pairing's. Only the PC's own screen calls an id the PC's.
@coderabbitai

coderabbitai Bot commented Nov 4, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 42 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 40dcae1 and 3a19040.

Files selected for processing: 21
  • changelog.d/relay-key-fingerprints.md
  • src/components/KeyId.css
  • src/components/KeyId.tsx
  • src/components/RelayPanel.css
  • src/components/RelayPanel.tsx
  • src/components/RelayShell.css
  • src/components/RelayShell.test.tsx
  • src/components/RelayShell.tsx
  • src/lib/i18n.ja.ts
  • src/lib/i18n.ko.ts
  • src/lib/i18n.zh.ts
  • src/lib/i18n/devices.ja.ts
  • src/lib/i18n/devices.ko.ts
  • src/lib/i18n/devices.zh.ts
  • src/lib/i18n/relay.ja.ts
  • src/lib/i18n/relay.ko.ts
  • src/lib/i18n/relay.zh.ts
  • src/lib/relay/device.ts
  • src/lib/relay/shell.tsx
  • src/lib/relay/shellState.test.ts
  • src/lib/relay/shellState.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@devswha

devswha commented Nov 4, 2026

Copy link
Copy Markdown
Owner Author

Codex (gpt-6.1-terra, xhigh) reviewed this branch in two rounds before the PR opened:

  • Round 1, at the first commit:
    • HIGH, reproduced and fixed: on a forged link, the screen labelled the link's own server_id as "This PC's ID". A link chooses that id freely, so the screen vouched for an unverified id.
    • MEDIUM, reproduced and fixed: when the saved key was the bad one, its id was labelled as the link's key.
    • Fix (3a19040d): each id is now labelled by where it came from: the id the link names or this phone paired with, and the key the link carries or this phone saved. Only the PC's own screen (Phone & devices) calls an id the PC's. A test pins both labellings and fails on the first version of the screen.
  • Round 2, at the fix: no actionable findings.

Nothing new is sent to the relay or the PC. Both ids are derived on the device.

@devswha

devswha commented Nov 4, 2026

Copy link
Copy Markdown
Owner Author

Merge note: owner approved the screen from screenshots on 2026-11-04. CodeRabbit was rate-limited and did not review this head; merged on the omo review (CLEAR receipt at 3a19040), the Codex Terra adversarial review (round 1 HIGH + MEDIUM reproduced and fixed with a failing-first test, round 2 no findings) and green required checks.

@devswha
devswha merged commit f73d57d into main Nov 4, 2026
12 checks passed
@devswha
devswha deleted the feat/relay-key-fingerprints branch November 4, 2026 01:00
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