import { describe, expect, it } from 'vitest' import { APP_SUBPROTOCOL, encodeTokenSubprotocol } from 'relay-contracts' import { readConfig } from '../src/config' import { createPassthroughTransport, type WebSocketLike } from '../src/ws-transport' import { encodeDpopSubprotocol } from '../src/dpop' const cfg = readConfig({ protocol: 'https:', host: 'alice.term.example.com', hostname: 'alice.term.example.com', }) class MockWs implements WebSocketLike { static last: MockWs | null = null binaryType = '' protocol = '' readonly url: string readonly protocols: readonly string[] closed: { code?: number; reason?: string } | null = null onopen: ((ev: unknown) => void) | null = null onmessage: ((ev: { data: unknown }) => void) | null = null onclose: ((ev: { code?: number; reason?: string }) => void) | null = null onerror: ((ev: unknown) => void) | null = null constructor(url: string, protocols?: string | readonly string[]) { this.url = url this.protocols = protocols === undefined ? [] : typeof protocols === 'string' ? [protocols] : protocols MockWs.last = this } send(): void {} close(code?: number, reason?: string): void { const ev: { code?: number; reason?: string } = {} if (code !== undefined) ev.code = code if (reason !== undefined) ev.reason = reason this.closed = ev this.onclose?.(ev) } fireOpen(echoedProtocol: string): void { this.protocol = echoedProtocol this.onopen?.({}) } } describe('createPassthroughTransport — B6 DPoP proof attachment', () => { const PROOF = 'aGVhZGVy.cGF5bG9hZA.c2ln' it('token + DPoP both ride Sec-WebSocket-Protocol in the frozen order, NEVER the URL', async () => { const t = createPassthroughTransport(cfg, { wsCtor: MockWs, capabilityToken: 'RAWTOK', dpopProof: PROOF, }) const opened = t.open() MockWs.last!.fireOpen(APP_SUBPROTOCOL) await opened expect(MockWs.last!.protocols).toEqual([ APP_SUBPROTOCOL, encodeTokenSubprotocol('RAWTOK'), encodeDpopSubprotocol(PROOF), ]) expect(MockWs.last!.url).not.toContain('RAWTOK') expect(MockWs.last!.url).not.toContain(PROOF) expect(MockWs.last!.url).not.toContain(encodeDpopSubprotocol(PROOF)) expect(MockWs.last!.url).not.toMatch(/\?/) }) it('echo rule holds with a DPoP bearer: only APP_SUBPROTOCOL back is accepted', async () => { const t = createPassthroughTransport(cfg, { wsCtor: MockWs, dpopProof: PROOF }) const opened = t.open() MockWs.last!.fireOpen(encodeDpopSubprotocol(PROOF)) // relay wrongly echoes the DPoP entry await expect(opened).rejects.toThrow() expect(MockWs.last!.closed).not.toBeNull() }) it('no dpopProof → protocols unchanged from the v0.9 token-only path (backward compatible)', async () => { const t = createPassthroughTransport(cfg, { wsCtor: MockWs, capabilityToken: 'RAWTOK' }) const opened = t.open() MockWs.last!.fireOpen(APP_SUBPROTOCOL) await opened expect(MockWs.last!.protocols).toEqual([APP_SUBPROTOCOL, encodeTokenSubprotocol('RAWTOK')]) }) })