mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* 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>
88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { openMobileE2EEV2Frame, sealMobileE2EEV2Frame } from './mobile-e2ee-v2-framing'
|
|
|
|
const key = new Uint8Array(32).fill(7)
|
|
const sessionId = new Uint8Array(32).fill(8)
|
|
const payload = new TextEncoder().encode('e2ee-auth')
|
|
|
|
describe('mobile E2EE v2 framing', () => {
|
|
it('round-trips counter-zero auth with the fixed nonce layout', () => {
|
|
const frame = sealMobileE2EEV2Frame({
|
|
payload,
|
|
key,
|
|
sessionId,
|
|
direction: 'mobile-to-desktop',
|
|
payloadKind: 'text',
|
|
counter: 0n
|
|
})
|
|
|
|
expect(Buffer.from(frame.subarray(0, 24)).toString('hex')).toBe(
|
|
'080808080808080808080808020000000000000000000000'
|
|
)
|
|
expect(
|
|
openMobileE2EEV2Frame({
|
|
frame,
|
|
key,
|
|
sessionId,
|
|
direction: 'mobile-to-desktop',
|
|
payloadKind: 'text',
|
|
expectedCounter: 0n
|
|
})
|
|
).toEqual(payload)
|
|
})
|
|
|
|
it('rejects replay, gap, reflection, kind confusion, and cross-session frames', () => {
|
|
const frame = sealMobileE2EEV2Frame({
|
|
payload,
|
|
key,
|
|
sessionId,
|
|
direction: 'mobile-to-desktop',
|
|
payloadKind: 'binary',
|
|
counter: 4n
|
|
})
|
|
const attempt = (overrides: Partial<Parameters<typeof openMobileE2EEV2Frame>[0]>) =>
|
|
openMobileE2EEV2Frame({
|
|
frame,
|
|
key,
|
|
sessionId,
|
|
direction: 'mobile-to-desktop',
|
|
payloadKind: 'binary',
|
|
expectedCounter: 4n,
|
|
...overrides
|
|
})
|
|
|
|
expect(attempt({ expectedCounter: 3n })).toBeNull()
|
|
expect(attempt({ expectedCounter: 5n })).toBeNull()
|
|
expect(attempt({ direction: 'desktop-to-mobile' })).toBeNull()
|
|
expect(attempt({ payloadKind: 'text' })).toBeNull()
|
|
expect(attempt({ sessionId: new Uint8Array(32).fill(9) })).toBeNull()
|
|
})
|
|
|
|
it('uses one exact-next counter sequence across text and binary kinds', () => {
|
|
const kinds = ['text', 'binary', 'text'] as const
|
|
const frames = kinds.map((payloadKind, counter) =>
|
|
sealMobileE2EEV2Frame({
|
|
payload: new Uint8Array([counter]),
|
|
key,
|
|
sessionId,
|
|
direction: 'desktop-to-mobile',
|
|
payloadKind,
|
|
counter: BigInt(counter)
|
|
})
|
|
)
|
|
|
|
for (let counter = 0; counter < frames.length; counter++) {
|
|
expect(
|
|
openMobileE2EEV2Frame({
|
|
frame: frames[counter]!,
|
|
key,
|
|
sessionId,
|
|
direction: 'desktop-to-mobile',
|
|
payloadKind: kinds[counter]!,
|
|
expectedCounter: BigInt(counter)
|
|
})
|
|
).toEqual(new Uint8Array([counter]))
|
|
}
|
|
})
|
|
})
|