Files

41 lines
3.0 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createPreviewServer } from './share-preview.mjs';
async function fixture(t) {
const server=createPreviewServer({password:'test-password'});
await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));
t.after(()=>{server.closeAllConnections();return new Promise(resolve=>server.close(resolve));});
const base=`http://127.0.0.1:${server.address().port}`;
const request=(url,options={})=>fetch(base+url,{...options,redirect:'manual'});
const origin=base.replace('http:','https:');
const login=async()=>{const r=await request('/__preview/login',{method:'POST',headers:{origin,'content-type':'application/x-www-form-urlencoded'},body:'password=test-password'});assert.equal(r.status,303);const cookie=r.headers.get('set-cookie');assert.match(cookie,/HttpOnly; Secure; SameSite=Strict/);return cookie.split(';')[0];};
return {request,origin,login};
}
test('external link opens login page but cross-site API remains blocked',async t=>{
const {request}=await fixture(t);
const r=await request('/',{headers:{'sec-fetch-site':'cross-site','sec-fetch-mode':'navigate','sec-fetch-dest':'document'}});
assert.equal(r.status,200);assert.match(await r.text(),/访问密码/);
assert.equal((await request('/api/monitoring',{headers:{'sec-fetch-site':'cross-site'}})).status,403);
});
test('anonymous, forged cookie and wrong password never grant access',async t=>{
const {request,origin}=await fixture(t);
assert.equal((await request('/api/monitoring')).status,401);
assert.equal((await request('/api/monitoring',{headers:{cookie:'__Host-beryl_preview=forged'}})).status,401);
const r=await request('/__preview/login',{method:'POST',headers:{origin,'content-type':'application/x-www-form-urlencoded'},body:'password=wrong'});
assert.equal(r.status,401);assert.equal(r.headers.get('set-cookie'),null);
});
test('logout revokes session and cannot be triggered cross-site',async t=>{
const {request,origin,login}=await fixture(t),cookie=await login();
assert.equal((await request('/__preview/logout',{method:'POST',headers:{cookie,origin:'https://evil.example'}})).status,403);
const r=await request('/__preview/logout',{method:'POST',headers:{cookie,origin}});
assert.equal(r.status,303);assert.match(r.headers.get('set-cookie'),/Max-Age=0/);
assert.equal((await request('/api/monitoring',{headers:{cookie}})).status,401);
});
test('login attempts are bounded and foreign origin cannot login',async t=>{
const {request,origin}=await fixture(t);
assert.equal((await request('/__preview/login',{method:'POST',headers:{origin:'https://evil.example'}})).status,403);
for(let i=0;i<10;i++)await request('/__preview/login',{method:'POST',headers:{origin,'content-type':'application/x-www-form-urlencoded'},body:'password=wrong'});
assert.equal((await request('/__preview/login',{method:'POST',headers:{origin,'content-type':'application/x-www-form-urlencoded'},body:'password=test-password'})).status,429);
});