Skip to content

Appairage client + écran Devices #135

Description

@64ix

Parent

#130

What to build

Client-side pairing that attaches a machine to the relay space, plus the Settings "Devices" screen to manage it.

The first machine calls POST /v1/space, stores its device token, and generates the space data key K0 (32 random bytes) into the #132 safeStorage slot — this ticket owns K0's creation and storage; #134 consumes it. Adding a device is uniform (a third device later works exactly like the second): the existing device generates a fresh random 16-byte join_token, registers SHA-256(join_token) via POST /v1/pairings, and displays the pairing secret base32(join_token ‖ K0 ‖ checksum) — the 4-byte truncated-SHA-256 checksum covers the whole payload, so a transcription error in either half fails at entry instead of surfacing later as a mysterious decrypt failure. The new machine decodes and checksum-verifies the secret, calls POST /v1/join {join_hash}, and stores the returned device token + space_id plus the decoded K0 machine-locally. At space creation the app offers a recovery code base32(K0 ‖ checksum) to save, labeled honestly (decrypts relay data; does not grant relay access — total-device-loss access recovery is an operator runbook step in the relay README).

Copy-paste (with a copy button) is the primary flow. The emdash://join?secret=… deep link requires OS-level custom-protocol support that does not exist in the app today: electron-builder protocols configuration plus open-url (macOS) / second-instance argv (Windows/Linux) handling in the main process — in scope here.

The Devices screen (pattern of SshConnectionsSettingsCard) lists paired devices, adds a device (mints a secret), and offers a single Remove device action with confirmation (revokes the token and removes membership).

Acceptance criteria

  • A machine can create a space (device token stored) and generates + stores K0 in the Schéma local : path nullable + clock de sync + identité device #132 safeStorage slot; a recovery code (K0-only, checksummed) is offered at creation.
  • An existing device can mint a pairing secret (random join_token registered via POST /v1/pairings); a second machine joins with it and ends up holding a device token, the space_id, and the same K0; a corrupted secret fails the checksum at entry with a clear error.
  • The device token and device identity are stored machine-locally (safeStorage + device namespace).
  • The emdash://join deep link is registered at the OS level (electron-builder protocols + main-process open-url/second-instance handling) and routes into the join flow; pairing respects single-use, TTL, and attempt limits (surfaced as clear errors).
  • A Settings "Devices" screen lists devices, adds (mints a secret), and removes a device with confirmation.
  • Tests cover mint/join (incl. checksum failure), K0/token storage, and the relay's pairing responses in the node vitest project; the Devices screen UI itself is browser-suite coverage (not part of the agent gate — report not-run when the infra is absent).

Blocked by

  • 1 (relay), 2 (schema: device identity + safeStorage slots)

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified, ready for an AFK agent

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions