mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 01:47:24 +00:00
* feat(remote-runtime): use E2EE v2 for desktop and CLI connections to remote runtimes Desktop connections to remote runtimes (orca serve, orcad, managed SSH, browser bridge) and the orca CLI now use E2EE v2 framing for hosts that support it, and fall back to the legacy framing for hosts that do not. - One-shot requests try v2 first. A host that refuses the v2 hello (hosts from before v2) or refuses capabilities on v2 token auth gets one transparent legacy redial; nothing but the handshake is sent before authentication, so the redial is safe. - After a v2 sign-in succeeds, the host's pinned key is remembered in the profile (shared by the app and the CLI). Every connection to that host, including long-lived sockets, then uses v2 and never falls back. - Long-lived sockets keep legacy framing until a host has proven v2, so they never see an older host refuse a v2 hello. - Hosts accept clientCapabilities on direct v2 token auth, so desktop and CLI clients keep their capability negotiation on v2. Relay token auth stays exact. * feat(remote-runtime): recover a latched host that was downgraded, without a legacy downgrade path A host this profile had signed in to over v2 was refused for good if it was later downgraded below capability-carrying v2 token auth. Hosts now advertise pairing.e2ee-v2-token-capabilities.v1. When a latched host refuses v2, a one-shot request asks the host over legacy framing (keyed to its pinned key, so only the real host can answer) for status.get: - no capability: the host itself says it was downgraded; the latch is dropped and the request goes ahead over legacy; - capability present, or no answer: the request fails with an error that says to update the host or check the network path. Only the read-only status check ever ran over legacy. A refusal faked on the path cannot produce the host's answer, so it cannot force legacy framing for a latched host.
38 lines
1.4 KiB
TypeScript
38 lines
1.4 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import { createRemoteRuntimeClientHandshake } from '../remote-runtime-client-framing'
|
|
import {
|
|
parseRemoteRuntimeRpcFrame,
|
|
remoteRuntimeAuthReplyError,
|
|
remoteRuntimeReadyError,
|
|
REMOTE_RUNTIME_JSON_STRUCTURE_LIMITS
|
|
} from './remote-runtime-request-frames'
|
|
|
|
const HOST_PUBLIC_KEY_B64 = Buffer.alloc(32, 9).toString('base64')
|
|
|
|
describe('remote runtime JSON frame admission', () => {
|
|
it('preserves valid handshake and RPC frames', () => {
|
|
const handshake = createRemoteRuntimeClientHandshake(HOST_PUBLIC_KEY_B64)
|
|
expect(remoteRuntimeReadyError(handshake.acceptReadyText('{"type":"e2ee_ready"}'))).toBeNull()
|
|
expect(
|
|
remoteRuntimeAuthReplyError(handshake.classifyAuthReply('{"type":"e2ee_authenticated"}'))
|
|
).toBeNull()
|
|
expect(parseRemoteRuntimeRpcFrame('{"_keepalive":true}')).toEqual({ type: 'keepalive' })
|
|
})
|
|
|
|
it('rejects excessive nesting before JSON.parse', () => {
|
|
const handshake = createRemoteRuntimeClientHandshake(HOST_PUBLIC_KEY_B64)
|
|
const parseSpy = vi.spyOn(JSON, 'parse')
|
|
try {
|
|
const depth = REMOTE_RUNTIME_JSON_STRUCTURE_LIMITS.nestingDepth + 1
|
|
const amplified = `${'['.repeat(depth)}0${']'.repeat(depth)}`
|
|
|
|
expect(remoteRuntimeReadyError(handshake.acceptReadyText(amplified))).toMatchObject({
|
|
code: 'invalid_runtime_response'
|
|
})
|
|
expect(parseSpy).not.toHaveBeenCalled()
|
|
} finally {
|
|
parseSpy.mockRestore()
|
|
}
|
|
})
|
|
})
|