Skip to content

feat(remote-connect): account-password mobile pairing and resilient device list#1647

Merged
bobleer merged 1 commit into
GCWing:mainfrom
bobleer:feat/mobile-web-account-pairing
Jul 20, 2026
Merged

feat(remote-connect): account-password mobile pairing and resilient device list#1647
bobleer merged 1 commit into
GCWing:mainfrom
bobleer:feat/mobile-web-account-pairing

Conversation

@bobleer

@bobleer bobleer commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

When the desktop is logged into a BitFun account, QR pairing now requires the same account's username+password instead of a free-form user ID, and the mobile device list transparently recovers from expired delegated identities instead of showing a terminal 'authorization expired' state.

Design spec: docs/superpowers/specs/2026-07-20-mobile-web-account-pairing-and-device-refresh-design.md

Pairing (account mode)

  • QR advertises auth=account with username prefill when the desktop is logged in; unsigned-in desktops keep the legacy user-ID flow.
  • Mobile submits username+password through the ECDH-encrypted room channel; the password is never persisted or logged, and password-less auto-reconnect is disabled in account mode.
  • Desktop verification is verify-only: challenge fetch + local KEK unwrap + comparison against the current session's master key. /api/auth/login is never called, so the desktop token is not refreshed or polluted, and the credentials must match the account currently signed in on the scanned desktop.
  • On success the trusted mobile identity binds the canonical account user id (not the plaintext username), so reconnects keep matching.
  • Account credentials are never downgraded: if the verifier is gone (desktop signed out after generating the QR), a pairing request carrying a password is rejected with a clear re-login message instead of silently falling back to password-less pairing.
  • Login, logout, and account switches refresh or clear the pairing context and the URL-bound trusted identity; the real verification failure cause stays in desktop logs while the mobile receives a unified rejection message (no account enumeration).

Device list resilience

  • RelayHttpClient: clearDelegatedIdentity(), requestDelegatedIdentity({ force }), and a shared 401 handler that clears the delegated identity, force-refreshes it from the paired desktop, and retries listDevices / sendDeviceRpc once.
  • DevicesPage: the terminal tokenExpired state and its i18n keys are removed; failures fall back to retryable errors or the noDelegatedIdentity state.

Verification

  • cargo test -p bitfun-core --lib remote_connect::tests — 5 passed (new focused tests: missing credentials, no-downgrade guard, canonical id binding)
  • cargo test -p bitfun-services-integrations --features remote-connect --test remote_connect_contracts — 51 passed
  • cargo check -p bitfun-desktop — clean
  • pnpm --dir src/mobile-web run type-check — clean

…evice list

Pairing (account mode):
- QR advertises auth=account with username prefill when the desktop is
  logged in; mobile submits account username+password through the ECDH
  room channel (password is never persisted or logged).
- Desktop verifies credentials verify-only: challenge + local master key
  unwrap compared against the current session, without calling
  /api/auth/login, so the desktop token is never disturbed. The trusted
  mobile identity binds the canonical account user id.
- Account credentials are never downgraded to password-less pairing when
  the verifier is unavailable (e.g. desktop signed out after the QR was
  generated); real failure causes are kept in desktop logs while the
  mobile gets a unified rejection message.
- Login/logout/account switch refresh or clear the pairing context and
  the URL-bound trusted identity.

Device list:
- RelayHttpClient refreshes the delegated identity from the paired
  desktop on HTTP 401 and retries once; the terminal 'authorization
  expired' state is removed from the devices page.

Verification:
- cargo test -p bitfun-core --lib remote_connect::tests (5 passed)
- cargo test -p bitfun-services-integrations --features remote-connect
  --test remote_connect_contracts (51 passed)
- cargo check -p bitfun-desktop
- pnpm --dir src/mobile-web run type-check
@bobleer
bobleer merged commit cff39a1 into GCWing:main Jul 20, 2026
5 checks passed
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