mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* oom(01): A1-shared-readers — reintroduce #10179 subset Files: 18 applied, 0 deleted (from6eb70d8370) Co-authored-by: Orca <help@stably.ai> * oom(02): A2-shared-image-media — reintroduce #10179 subset Files: 7 applied, 0 deleted (from6eb70d8370) Co-authored-by: Orca <help@stably.ai> * oom(03): A3-shared-fs-listing — reintroduce #10179 subset Files: 21 applied, 0 deleted (from6eb70d8370) Co-authored-by: Orca <help@stably.ai> * oom(04): A4-shared-remote-relay — reintroduce #10179 subset Files: 8 applied, 0 deleted (from6eb70d8370) Co-authored-by: Orca <help@stably.ai> * oom(05): A5-shared-misc — reintroduce #10179 subset Files: 28 applied, 0 deleted (from6eb70d8370) Co-authored-by: Orca <help@stably.ai> * oom(06): B-shared-wiring — reintroduce #10179 subset Files: 81 applied, 0 deleted (from6eb70d8370) Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
99 lines
3.3 KiB
TypeScript
99 lines
3.3 KiB
TypeScript
import { createHash } from 'node:crypto'
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
import {
|
|
encodeMobileE2EEV2Transcript,
|
|
validateMobileE2EEV2Handshake
|
|
} from './mobile-e2ee-v2-contract'
|
|
import { createMobileE2EEV2Fixture, MOBILE_E2EE_V2_VECTOR } from './mobile-e2ee-v2-fixtures'
|
|
|
|
describe('mobile E2EE v2 contract', () => {
|
|
it('validates the exact relay handshake and canonical encodings', () => {
|
|
const { hello, ready } = createMobileE2EEV2Fixture()
|
|
expect(validateMobileE2EEV2Handshake(hello, ready)).not.toBeNull()
|
|
})
|
|
|
|
it('rejects unknown fields, noncanonical base64, and an unechoed nonce', () => {
|
|
const { hello, ready } = createMobileE2EEV2Fixture()
|
|
expect(validateMobileE2EEV2Handshake({ ...hello, extra: true }, ready)).toBeNull()
|
|
expect(
|
|
validateMobileE2EEV2Handshake(
|
|
{ ...hello, clientPublicKeyB64: hello.clientPublicKeyB64.replace(/=$/, '') },
|
|
ready
|
|
)
|
|
).toBeNull()
|
|
expect(
|
|
validateMobileE2EEV2Handshake(hello, {
|
|
...ready,
|
|
clientNonceB64: btoa(String.fromCharCode(...new Uint8Array(32).fill(9)))
|
|
})
|
|
).toBeNull()
|
|
})
|
|
|
|
it('rejects wrong-length handshake fields before base64 decoding', () => {
|
|
const { hello, ready } = createMobileE2EEV2Fixture()
|
|
const oversized = 'A'.repeat(45)
|
|
const decode = vi.spyOn(globalThis, 'atob')
|
|
|
|
expect(
|
|
validateMobileE2EEV2Handshake(
|
|
{ ...hello, clientPublicKeyB64: oversized, clientNonceB64: oversized },
|
|
{
|
|
...ready,
|
|
desktopPublicKeyB64: oversized,
|
|
clientNonceB64: oversized,
|
|
desktopNonceB64: oversized
|
|
}
|
|
)
|
|
).toBeNull()
|
|
expect(decode).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('rejects context and capability-selection changes', () => {
|
|
const { hello, ready } = createMobileE2EEV2Fixture()
|
|
expect(
|
|
validateMobileE2EEV2Handshake(hello, {
|
|
...ready,
|
|
context: { ...ready.context, relayHostId: 'ZbCdEf0123_-xyZ9' }
|
|
})
|
|
).toBeNull()
|
|
expect(
|
|
validateMobileE2EEV2Handshake(
|
|
{ ...hello, capabilities: { framing: [2], payloadKinds: ['binary', 'text'] } },
|
|
ready
|
|
)
|
|
).toBeNull()
|
|
})
|
|
|
|
it('requires relayHostId only for relay context', () => {
|
|
const { hello, ready } = createMobileE2EEV2Fixture()
|
|
const relayWithoutId = { ...hello.context }
|
|
delete (relayWithoutId as { relayHostId?: string }).relayHostId
|
|
expect(validateMobileE2EEV2Handshake({ ...hello, context: relayWithoutId }, ready)).toBeNull()
|
|
|
|
const directContext = {
|
|
protocol: 'orca-mobile-e2ee' as const,
|
|
initiator: 'mobile' as const,
|
|
responder: 'desktop' as const,
|
|
transport: 'direct' as const
|
|
}
|
|
expect(
|
|
validateMobileE2EEV2Handshake(
|
|
{ ...hello, context: directContext },
|
|
{ ...ready, context: directContext }
|
|
)
|
|
).not.toBeNull()
|
|
})
|
|
|
|
it('locks the canonical length-prefixed transcript bytes', () => {
|
|
const { hello, ready } = createMobileE2EEV2Fixture()
|
|
const handshake = validateMobileE2EEV2Handshake(hello, ready)
|
|
expect(handshake).not.toBeNull()
|
|
const transcript = encodeMobileE2EEV2Transcript(handshake!)
|
|
|
|
expect(transcript).toHaveLength(MOBILE_E2EE_V2_VECTOR.transcriptLength)
|
|
expect(createHash('sha256').update(transcript).digest('hex')).toBe(
|
|
MOBILE_E2EE_V2_VECTOR.transcriptHashHex
|
|
)
|
|
})
|
|
})
|