import { mkdtempSync, readFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import nacl from 'tweetnacl' import { beforeAll, describe, expect, it } from 'vitest' import { DeviceRegistry } from '../../../src/main/runtime/rpc/server/pairing/device-registry' import type { DeviceEntry } from '../../../src/main/runtime/rpc/server/pairing/device-entry' import { DEVICE_REGISTRY_FILENAME } from '../../../src/main/runtime/rpc/server/pairing/mobile-pairing-files' import { importReleaseCheckoutModule, materializeReleaseCheckout } from './release-checkout' // Across downgrade, preserve ephemeral key rows and token auth; only hosts advertising the capability may receive session-only registration. // The last release without session-only keys; a newer baseline would itself drop the row. const PRE_EPHEMERAL_REF = 'v1.4.224' const SUITE_TIMEOUT_MS = 180_000 type RegistryLike = { validateToken(token: string): { deviceId: string } | null updateLastSeen(deviceId: string): void } let ReleasedRegistry: new (userDataPath: string) => RegistryLike beforeAll(async () => { const checkout = await materializeReleaseCheckout(PRE_EPHEMERAL_REF) const registryModule = await importReleaseCheckoutModule( checkout, 'src/main/runtime/rpc/server/pairing/device-registry.ts' ) // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the pinned release's DeviceRegistry class; a changed shape fails the assertions below. ReleasedRegistry = registryModule.DeviceRegistry as typeof ReleasedRegistry }, SUITE_TIMEOUT_MS) describe('cross-version: session-only browser rows', () => { it('a released registry keeps the session row and token rows; this host drops it on restart', () => { const userDataPath = mkdtempSync(join(tmpdir(), 'orca-xv-web-session-')) const current = new DeviceRegistry(userDataPath) const legacy = current.addDevice('Browser', 'runtime') current.updateLastSeen(legacy.deviceId) const keyB64 = Buffer.from(nacl.sign.keyPair().publicKey).toString('base64') const session = current.forkDeviceKey(legacy.deviceId, keyB64, 'Tab', { ephemeral: true }) const released = new ReleasedRegistry(userDataPath) expect(released.validateToken(legacy.token)?.deviceId).toBe(legacy.deviceId) released.updateLastSeen(legacy.deviceId) const rows: DeviceEntry[] = JSON.parse( readFileSync(join(userDataPath, DEVICE_REGISTRY_FILENAME), 'utf8') ) expect(rows.find((row) => row.deviceId === session.deviceId)).toMatchObject({ ephemeral: true, devicePublicKeyB64: keyB64 }) expect(rows.find((row) => row.deviceId === session.deviceId)?.token).toBeUndefined() const restarted = new DeviceRegistry(userDataPath) expect(restarted.getDevice(session.deviceId)).toBeNull() expect(restarted.validateToken(legacy.token)?.deviceId).toBe(legacy.deviceId) }) })