21 lines
4.9 KiB
JavaScript
21 lines
4.9 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { mkdtempSync, writeFileSync, readFileSync, existsSync, mkdirSync, readdirSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { execFileSync } from 'node:child_process';
|
|
import { createHash } from 'node:crypto';
|
|
import http from 'node:http';
|
|
import { fetchPinned, downloadRelease } from '../src/fetch.mjs';
|
|
import { installPaths } from '../src/settings.mjs';
|
|
const digest=x=>createHash('sha256').update(x).digest('hex'),code=c=>e=>e.code===c;
|
|
function fixture(){const root=mkdtempSync(join(tmpdir(),'p1-'));mkdirSync(join(root,'source'));writeFileSync(join(root,'source/cli-proxy-api'),'fake executable');execFileSync('tar',['-czf',join(root,'release.tar.gz'),'-C',join(root,'source'),'cli-proxy-api']);const archive=readFileSync(join(root,'release.tar.gz')),panel=Buffer.from('fake panel');const pin={version:'8.0.42',archive:{url:'https://github.com/router-for-me/CLIProxyAPI/releases/download/v8.0.42/fake.tar.gz',sha256:digest(archive)},binary:{sha256:digest('fake executable')},panel:{url:'https://github.com/router-for-me/Cli-Proxy-API-Management-Center/releases/download/v1.26.7/management.html',sha256:digest(panel)}};return {root,archive,panel,pin,dataRoot:join(root,'data')};}
|
|
test('verified fetch installs binary and panel together; identical repeat is idempotent',async()=>{const f=fixture();const calls=[];const download=async url=>{calls.push(url);return url===f.pin.archive.url?f.archive:f.panel;};const p=await fetchPinned({...f,download});assert.equal(readFileSync(p.binary,'utf8'),'fake executable');assert.equal(readFileSync(p.panel,'utf8'),'fake panel');await fetchPinned({...f,download});assert.equal(calls.length,4);});
|
|
test('proxy-fetch-hash: either bad asset installs nothing',async()=>{for(const bad of ['archive','panel']){const f=fixture();await assert.rejects(fetchPinned({...f,download:async url=>url===f.pin[bad].url?Buffer.from('corrupt'):url===f.pin.archive.url?f.archive:f.panel}),code('proxy-fetch-hash'));assert.equal(existsSync(installPaths(f.dataRoot,f.pin).dir),false);}});
|
|
test('proxy-fetch-existing: conflicting install remains byte-identical',async()=>{const f=fixture(),p=installPaths(f.dataRoot,f.pin);mkdirSync(p.dir,{recursive:true});writeFileSync(p.binary,'old');await assert.rejects(fetchPinned({...f,download:async u=>u===f.pin.archive.url?f.archive:f.panel}),code('proxy-fetch-existing'));assert.equal(readFileSync(p.binary,'utf8'),'old');assert.deepEqual(readdirSync(p.dir),['cli-proxy-api']);});
|
|
test('proxy-fetch-archive: missing executable in verified archive refuses without install',async()=>{const f=fixture();writeFileSync(join(f.root,'source/other'),'other');execFileSync('tar',['-czf',join(f.root,'bad.tar.gz'),'-C',join(f.root,'source'),'other']);f.archive=readFileSync(join(f.root,'bad.tar.gz'));f.pin.archive.sha256=digest(f.archive);await assert.rejects(fetchPinned({...f,download:async u=>u===f.pin.archive.url?f.archive:f.panel}),code('proxy-fetch-archive'));assert.equal(existsSync(installPaths(f.dataRoot,f.pin).dir),false);});
|
|
test('proxy-fetch-url: production downloader permits pinned GitHub release URLs only',async()=>{for(const url of ['http://127.0.0.1:18318/x','https://example.com/x','https://github.com/router-for-me/CLIProxyAPI/blob/main/x'])await assert.rejects(downloadRelease(url),code('proxy-fetch-url'));});
|
|
test('local fake server covers redirect off allowlist and HTTP failure without external fetch',async()=>{const s=http.createServer((q,r)=>{if(q.url==='/redirect'){r.writeHead(302,{Location:'https://example.com/forbidden'});r.end();}else{r.writeHead(503);r.end('do not log response');}});await new Promise(r=>s.listen(0,'127.0.0.1',r));const local=`http://127.0.0.1:${s.address().port}`;try{await assert.rejects(downloadRelease(`${local}/redirect`,{testOrigin:local}),code('proxy-fetch-redirect'));await assert.rejects(downloadRelease(`${local}/fail`,{testOrigin:local}),code('proxy-fetch-failed'));}finally{s.closeAllConnections();await new Promise(r=>s.close(r));}});
|
|
test('proxy-fetch-existing: extra content in an existing install refuses',async()=>{const f=fixture(),download=async u=>u===f.pin.archive.url?f.archive:f.panel,p=await fetchPinned({...f,download});writeFileSync(join(p.dir,'extra'),'old');await assert.rejects(fetchPinned({...f,download}),code('proxy-fetch-existing'));assert.equal(readFileSync(join(p.dir,'extra'),'utf8'),'old');});
|
|
test('local fake file server success and same-origin redirect return exact bytes',async()=>{const f=fixture();const s=http.createServer((q,r)=>{if(q.url==='/redirect'){r.writeHead(302,{Location:'/asset'});r.end();}else r.end(f.archive);});await new Promise(r=>s.listen(0,'127.0.0.1',r));const local=`http://127.0.0.1:${s.address().port}`;try{assert.deepEqual(await downloadRelease(`${local}/redirect`,{testOrigin:local}),f.archive);}finally{s.closeAllConnections();await new Promise(r=>s.close(r));}});
|