Files
orca/src/main/runtime/rpc/methods/pairing.test.ts
T
Jinwoo HongandOrca 77b154d5dd Add Orca Relay desktop and mobile transport (#8536)
* feat(mobile): define relay protocol groundwork

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): implement replay-safe E2EE v2 sessions

Co-authored-by: Orca <help@stably.ai>

* test(auth): lock cloud refresh single-flight

Co-authored-by: Orca <help@stably.ai>

* test(mobile): complete E2EE v2 adversarial coverage

Co-authored-by: Orca <help@stably.ai>

* refactor(runtime): unify mobile socket wiring

Co-authored-by: Orca <help@stably.ai>

* feat(runtime): add relay control and data clients

Co-authored-by: Orca <help@stably.ai>

* feat(runtime): coordinate desktop relay sessions

Co-authored-by: Orca <help@stably.ai>

* fix(auth): fence stale cloud session mutations

Co-authored-by: Orca <help@stably.ai>

* feat(runtime): add relay pairing and durable revoke

Co-authored-by: Orca <help@stably.ai>

* feat(runtime): add relay credential pairing RPCs

Co-authored-by: Orca <help@stably.ai>

* feat(settings): show Orca Relay sign-in status

Co-authored-by: Orca <help@stably.ai>

* test(relay): prove desktop lifecycle and E2EE splice

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): persist relay pairing state

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): race direct and relay pairing

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): recover pairing through relay director

Co-authored-by: Orca <help@stably.ai>

* fix(relay): preserve origin controls during drain

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): recover interrupted relay pairing

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): add stable relay RPC sessions

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): supervise direct and relay endpoints

Co-authored-by: Orca <help@stably.ai>

* Cover mobile relay director fallback matrix

Co-authored-by: Orca <help@stably.ai>

* Fix relay settings component test isolation

Co-authored-by: Orca <help@stably.ai>

* Remove unrelated merge formatting drift

Co-authored-by: Orca <help@stably.ai>

* Update runtime connection count integration assertion

Co-authored-by: Orca <help@stably.ai>

* Run mobile typecheck through pnpm

Co-authored-by: Orca <help@stably.ai>

* feat(relay): gate desktop controls on mobile demand

Co-authored-by: Orca <help@stably.ai>

* test(mobile): cover served relay recovery

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): upgrade direct pairings to relay

Co-authored-by: Orca <help@stably.ai>

* fix(relay): harden mobile reconnect and teardown

Co-authored-by: Orca <help@stably.ai>

* fix(auth): clarify account sign-in state

Co-authored-by: Orca <help@stably.ai>

* fix(auth): polish sign-in completion flow

Co-authored-by: Orca <help@stably.ai>

* fix(auth): clarify sign-out confirmation

Co-authored-by: Orca <help@stably.ai>

* fix(auth): simplify sign-in completion page

Co-authored-by: Orca <help@stably.ai>

* feat(mobile): add per-device pairing connection mode

Co-authored-by: Orca <help@stably.ai>

* fix(mobile): stabilize pairing option layout

Co-authored-by: Orca <help@stably.ai>

* fix(mobile): give pairing choices stable space

Co-authored-by: Orca <help@stably.ai>

* fix(mobile): stabilize pairing QR regeneration

Co-authored-by: Orca <help@stably.ai>

* Animate mobile pairing flow height

Co-authored-by: Orca <help@stably.ai>

* Configure auth in packaged builds

Co-authored-by: Orca <help@stably.ai>

* Make Orca Relay pairing an opt-in beta

Co-authored-by: Orca <help@stably.ai>

* Show Relay beta details on hover

Co-authored-by: Orca <help@stably.ai>

* Refine mobile relay pairing choice

Co-authored-by: Orca <help@stably.ai>

* Polish Orca Relay pairing controls

Co-authored-by: Orca <help@stably.ai>

* Keep mobile contract fallback test additive

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-14 11:47:05 -07:00

76 lines
2.5 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import { OrcaRuntimeService } from '../../orca-runtime'
import { RpcDispatcher } from '../dispatcher'
import { PAIRING_METHODS } from './pairing'
function dispatchPairing(
method: string,
params: unknown,
pairing: NonNullable<Parameters<RpcDispatcher['dispatchStreaming']>[2]>['pairing']
): Promise<Record<string, unknown>> {
return new Promise((resolve) => {
const dispatcher = new RpcDispatcher({
runtime: new OrcaRuntimeService(),
methods: PAIRING_METHODS
})
void dispatcher.dispatchStreaming(
{ id: 'request-1', authToken: '', method, params },
(response) => resolve(JSON.parse(response) as Record<string, unknown>),
{ pairing }
)
})
}
describe('pairing RPC methods', () => {
it('passes only phone-owned credential material to the server-bound provider', async () => {
const provisionRelay = vi.fn().mockResolvedValue({
v: 1,
reqId: 'install-1',
authorizationMode: 'authenticated-direct',
currentVersion: 1,
resumeExpiresAt: Date.now() + 60_000
})
const pairing = { getEndpoints: vi.fn(), provisionRelay }
await expect(
dispatchPairing(
'pairing.provisionRelay',
{ reqId: 'install-1', newResumeTokenHash: 'A'.repeat(43) },
pairing
)
).resolves.toMatchObject({ ok: true })
expect(provisionRelay).toHaveBeenCalledWith({
reqId: 'install-1',
newResumeTokenHash: 'A'.repeat(43)
})
})
it('rejects caller-selected identity and authorization metadata', async () => {
const pairing = { getEndpoints: vi.fn(), provisionRelay: vi.fn() }
for (const injected of [
{ relayDeviceId: 'attacker-device' },
{ authorization: { mode: 'relay-basis', basisConnId: 'attacker-basis' } },
{ directAuthId: 'attacker-direct' },
{ acceptedCredentialVersion: 99 }
]) {
await expect(
dispatchPairing(
'pairing.provisionRelay',
{ reqId: 'install-1', newResumeTokenHash: 'A'.repeat(43), ...injected },
pairing
)
).resolves.toMatchObject({ ok: false, error: { code: 'invalid_argument' } })
}
await expect(
dispatchPairing(
'pairing.getEndpoints',
{ installReqId: 'status-1', basisConnId: 'injected' },
pairing
)
).resolves.toMatchObject({ ok: false, error: { code: 'invalid_argument' } })
expect(pairing.provisionRelay).not.toHaveBeenCalled()
expect(pairing.getEndpoints).not.toHaveBeenCalled()
})
})