import {afterEach,describe,expect,it,vi} from 'vitest'; import {renderWispUpgrade} from '../src/wisp'; import worker from '../src/index'; const config={RENDER_RELAY_URL:'https://relay.example/',RELAY_SHARED_SECRET:'test-private-token-'.repeat(3)}; describe('hosted Wisp bridge',()=>{ afterEach(()=>vi.unstubAllGlobals()); it('forwards only the server secret and selected protocol headers',async()=>{ const upstream={status:101} as Response; const mock=vi.fn(async()=>upstream);vi.stubGlobal('fetch',mock); const request=new Request('https://hub.example/wisp/',{headers:{Upgrade:'websocket',Cookie:'private-session','x-relay-token':'attacker','sec-websocket-protocol':'wisp-v2'}}); expect(await renderWispUpgrade(request,config)).toBe(upstream); const [url,options]=mock.mock.calls[0] as unknown as [URL,RequestInit]; expect(url.href).toBe('https://relay.example/wisp/'); const headers=new Headers(options.headers); expect(headers.get('x-relay-token')).toBe(config.RELAY_SHARED_SECRET); expect(headers.has('Cookie')).toBe(false); expect(headers.get('sec-websocket-protocol')).toBe('wisp-v2'); }); it('rejects backend auth failures without forwarding its body',async()=>{ vi.stubGlobal('fetch',vi.fn(async()=>new Response('private backend error',{status:401}))); await expect(renderWispUpgrade(new Request('https://hub.example/wisp/',{headers:{Upgrade:'websocket'}}),config)).rejects.toMatchObject({code:'WISP_UNAVAILABLE'}); }); it('requires a browser session before opening backend connection',async()=>{ const mock=vi.fn();vi.stubGlobal('fetch',mock); const result=await worker.fetch(new Request('https://hub.example/wisp/',{headers:{Upgrade:'websocket',Origin:'https://hub.example'}}),{...config,PROXY_PASSWORD:'test-session-secret-'.repeat(3)} as Env,{} as ExecutionContext); expect(result.status).toBe(401);expect(mock).not.toHaveBeenCalled(); }); it('rejects cross-origin socket attempts',async()=>{ const result=await worker.fetch(new Request('https://hub.example/wisp/',{headers:{Upgrade:'websocket',Origin:'https://evil.example'}}),config as Env,{} as ExecutionContext); expect(result.status).toBe(403); }); it('rejects non-WebSocket requests and missing relay config',async()=>{ await expect(renderWispUpgrade(new Request('https://hub.example/wisp/'),config)).rejects.toMatchObject({status:426}); await expect(renderWispUpgrade(new Request('https://hub.example/wisp/',{headers:{Upgrade:'websocket'}}),{})).rejects.toMatchObject({status:503}); }); });