mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 17:47:40 +00:00
* feat(runtime): session-only browser keys and an opt-in for pairing from plain-http pages (host) - pairing.registerDeviceKey accepts ephemeral: true (advertised as pairing.device-key-ephemeral.v1). Such keyed rows are dropped when the host restarts and after 12 hours with no live socket; a sweep removes them and cuts any socket still bound to them, so later key auth gets device_revoked. - The WebSocket upgrade Origin is recorded per socket. A first pairing (a never-used pairing code) from an http:// page on another machine is refused with a sealed insecure_origin error unless the operator sets ORCA_ALLOW_INSECURE_WEB_PAIRING=1. Already-paired browsers, https and loopback pages, and native clients are unchanged. - Registry file reading moved to device-registry-file-read.ts to keep the registry under the size cap. * fix(runtime): gate first pairings only for the marked web client, never phones React Native sends an http Origin on every LAN WebSocket, so the Origin alone refused first-time QR pairing from released phones. The web bundle now marks its upgrade with ?orca-client=web; only a marked socket from an http page on another machine is gated. Released hosts ignore the query string. --------- Co-authored-by: m4air <m4air@Mac.localdomain>
48 lines
2.1 KiB
TypeScript
48 lines
2.1 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
hasWebClientUpgradeMarker,
|
|
isInsecureRemoteWebOrigin,
|
|
withWebClientUpgradeMarker
|
|
} from './web-origin-security'
|
|
|
|
describe('isInsecureRemoteWebOrigin', () => {
|
|
it('flags plain http pages served to other machines', () => {
|
|
expect(isInsecureRemoteWebOrigin('http://192.168.1.20:6768')).toBe(true)
|
|
expect(isInsecureRemoteWebOrigin('http://desk.local')).toBe(true)
|
|
expect(isInsecureRemoteWebOrigin('http://[fe80::1]:6768')).toBe(true)
|
|
})
|
|
|
|
it('treats https and loopback pages as secure', () => {
|
|
expect(isInsecureRemoteWebOrigin('https://desk.example.com')).toBe(false)
|
|
expect(isInsecureRemoteWebOrigin('http://localhost:6768')).toBe(false)
|
|
expect(isInsecureRemoteWebOrigin('http://app.localhost')).toBe(false)
|
|
expect(isInsecureRemoteWebOrigin('http://127.0.0.1:6768')).toBe(false)
|
|
expect(isInsecureRemoteWebOrigin('http://127.8.0.1')).toBe(false)
|
|
expect(isInsecureRemoteWebOrigin('http://[::1]:6768')).toBe(false)
|
|
})
|
|
|
|
it('leaves non-browser and unparseable origins to token auth', () => {
|
|
expect(isInsecureRemoteWebOrigin(undefined)).toBe(false)
|
|
expect(isInsecureRemoteWebOrigin('null')).toBe(false)
|
|
expect(isInsecureRemoteWebOrigin('file://')).toBe(false)
|
|
expect(isInsecureRemoteWebOrigin('not a url')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('web client upgrade marker', () => {
|
|
it('round-trips through the endpoint the web bundle dials', () => {
|
|
const marked = withWebClientUpgradeMarker('ws://192.168.1.20:6768')
|
|
expect(marked).toBe('ws://192.168.1.20:6768/?orca-client=web')
|
|
expect(hasWebClientUpgradeMarker(new URL(marked).pathname + new URL(marked).search)).toBe(true)
|
|
expect(withWebClientUpgradeMarker('wss://desk.example.com/orca?x=1')).toBe(
|
|
'wss://desk.example.com/orca?x=1&orca-client=web'
|
|
)
|
|
})
|
|
|
|
it('is absent for phones, CLIs and other paths', () => {
|
|
expect(hasWebClientUpgradeMarker('/')).toBe(false)
|
|
expect(hasWebClientUpgradeMarker(undefined)).toBe(false)
|
|
expect(hasWebClientUpgradeMarker('/?orca-client=phone')).toBe(false)
|
|
})
|
|
})
|