import {test,afterEach} from 'node:test'; import assert from 'node:assert/strict'; import http from 'node:http'; import {Readable,Writable} from 'node:stream'; import {build} from 'esbuild'; import {fileURLToPath} from 'node:url'; const result=await build({entryPoints:[fileURLToPath(new URL('../firDevProxy.ts',import.meta.url))],bundle:true,write:false,format:'esm',platform:'node'}); const {firDevProxy}=await import('data:text/javascript;base64,'+Buffer.from(result.outputFiles[0].text).toString('base64')); const original=http.request;afterEach(()=>http.request=original); function middleware(){let handler;firDevProxy().configureServer({middlewares:{use:fn=>handler=fn}});return handler;} function response(){const chunks=[];const res=new Writable({write(chunk,_enc,done){chunks.push(chunk);done();}});res.setHeader=()=>{};return {res,chunks};} test('development relay preserves both binary payloads and exact device channel paths',async()=>{ for(const side of ['left','right']) { let options;const chunks=[];http.request=(opts,callback)=>{ options=opts;const upstream=new Writable({write(chunk,_enc,done){chunks.push(chunk);done();}}); upstream.setTimeout=()=>{};upstream.on('finish',()=>{const reply=Readable.from(['OK']);reply.statusCode=200;reply.headers={};callback(reply);});return upstream; }; const data=Buffer.alloc(32826,side==='left'?0x12:0x34);const req=Readable.from([data]);req.url='/fir-device/192.168.9.133/'+side;req.method='POST';req.headers={'content-length':'32826'}; const {res}=response();const finished=new Promise(resolve=>res.on('finish',resolve));middleware()(req,res,()=>assert.fail('unexpected fallthrough'));await finished; assert.equal(options.agent,false);assert.equal(options.hostname,'192.168.9.133');assert.equal(options.path,'/dev/info.cgi?action=fir&channel='+side);assert.equal(options.headers['Content-Type'],'audio/wav');assert.deepEqual(Buffer.concat(chunks),data);assert.equal(res.statusCode,200); } }); test('relay refuses public hosts, bad channels, methods and payload sizes',()=>{ http.request=()=>assert.fail('invalid request forwarded'); for(const [url,method,length,status] of [['/fir-device/8.8.8.8/left','POST',32826,400],['/fir-device/192.168.9.133/both','POST',32826,400],['/fir-device/192.168.9.133/left','DELETE',32826,400],['/fir-device/192.168.9.133/right','POST',8,422]]) { const {res}=response();middleware()({url,method,headers:{'content-length':String(length)}},res,()=>{});assert.equal(res.statusCode,status); } }); test('GET relay reads original device binary with exact ear path and no upload headers',async()=>{ let options; http.request=(opts,callback)=>{options=opts; const upstream=new Writable({write(_c,_e,done){done();}});upstream.setTimeout=()=>{};upstream.on('finish',()=>{const reply=Readable.from([Buffer.alloc(32826,1)]);reply.statusCode=200;reply.headers={'content-type':'audio/wav'};callback(reply);});return upstream;}; for(const side of ['left','right']){const req=Readable.from([]);req.url='/fir-device/192.168.9.133/'+side;req.method='GET';req.headers={};const {res,chunks}=response();const finished=new Promise(resolve=>res.on('finish',resolve));middleware()(req,res,()=>assert.fail('fallthrough'));await finished;assert.equal(options.agent,false);assert.equal(options.method,'GET');assert.equal(options.path,'/dev/info.cgi?action=fir&channel='+side);assert.deepEqual(options.headers,{});assert.equal(Buffer.concat(chunks).length,32826);} }); test('complete firmware response survives an invalid trailing HTTP tail', async () => { http.request=(_opts,callback)=>{ const upstream=new Writable({write(_c,_e,done){done();}});upstream.setTimeout=()=>{}; upstream.on('finish',()=>{ const reply=Readable.from([Buffer.alloc(32826,7)]);reply.statusCode=200;reply.headers={'content-type':'audio/wav'};reply.complete=true; callback(reply);upstream.emit('error',new Error('Parse Error: Expected HTTP/')); });return upstream; }; const req=Readable.from([]);req.url='/fir-device/192.168.9.133/left';req.method='GET';req.headers={}; const {res,chunks}=response();const finished=new Promise(resolve=>res.on('finish',resolve)); middleware()(req,res,()=>assert.fail('fallthrough'));await finished; assert.equal(res.statusCode,200);assert.equal(Buffer.concat(chunks).length,32826); });