Files
AtreidesAssetsFree/tests/server/csp.test.mjs
T

107 lines
4.5 KiB
JavaScript
Raw Permalink Normal View History

2026-10-29 11:57:29 +01:00
// Generated, do not edit. sha256:47f02343d278744260374448334893708a776affbe44624b7fc8f089e85783c7
import { describe, it, before, after } from 'node:test';
import assert from 'node:assert/strict';
import { createServer } from 'node:http';
import { createRequestListener } from '../../server/app.mjs';
import { originOf, connectSrcOrigins, originAllowedByCsp } from '../../shared/csp.js';
import { CONFIG } from '../../shared/config.js';
describe('originOf', () => {
it('geeft het origin van een gewone URL', () => {
assert.equal(originOf('https://mempool.space/api/blocks/tip/height'), 'https://mempool.space');
assert.equal(originOf('https://pool.example.nl:3006/api'), 'https://pool.example.nl:3006');
});
it('geeft null bij iets dat geen URL is, in plaats van te gooien', () => {
for (const rommel of ['', ' ', 'pool.example.nl', 'niet eens een adres', null, undefined, 42]) {
assert.equal(originOf(rommel), null, `${rommel} hoort null te geven`);
}
});
});
describe('connectSrcOrigins', () => {
it('bevat altijd de publieke mempool.space, ook zonder verbindingen', () => {
assert.deepEqual(connectSrcOrigins(), [originOf(CONFIG.PRICE_SOURCES.MEMPOOL_PUBLIC_BASE)]);
});
it('neemt een eigen explorer-verbinding op, zonder codewijziging', () => {
const origins = connectSrcOrigins(['https://pool.example.nl:3006/', 'https://mempool.space']);
assert.deepEqual(origins, ['https://mempool.space', 'https://pool.example.nl:3006']);
});
it('laat met een verbindingsadres niets anders in de header komen dan een origin', () => {
const origins = connectSrcOrigins([
'javascript:alert(1)', 'data:text/plain,x', 'https://a.example; script-src *',
'https://b.example *', 'file:///etc/passwd', 'niet eens een adres',
]);
assert.deepEqual(origins, ['https://mempool.space']);
});
it('ontdubbelt en bevat geen null', () => {
const origins = connectSrcOrigins(['https://mempool.space/api', 'https://mempool.space']);
assert.equal(new Set(origins).size, origins.length);
assert.equal(origins.some(o => !o), false);
});
});
describe('originAllowedByCsp', () => {
it('staat een origin uit de allowlist toe', () => {
assert.equal(originAllowedByCsp(`${CONFIG.PRICE_SOURCES.MEMPOOL_PUBLIC_BASE}/api/blocks/tip/height`), true);
});
it('WEIGERT een profiel dat niet in de lijst van het document stond', () => {
assert.equal(originAllowedByCsp('https://mijn-eigen-explorer.example/api'), false);
});
it('staat een profiel toe dat bij het laden al een verbinding was', () => {
assert.equal(originAllowedByCsp('https://mijn-eigen-explorer.example/api/blocks/tip/height', null,
['https://mijn-eigen-explorer.example']), true);
});
it('weigert rommel in plaats van hem door te laten', () => {
for (const rommel of ['', 'pool.example.nl', null, undefined]) {
assert.equal(originAllowedByCsp(rommel), false);
}
});
it('staat de eigen origin toe, maar alleen als die is meegegeven', () => {
assert.equal(originAllowedByCsp('https://localhost:8080/api/data', 'https://localhost:8080'), true);
assert.equal(originAllowedByCsp('https://localhost:8080/api/data'), false);
});
});
describe('de CSP-header van een echt verzoek', () => {
let server, basis, csp;
before(async () => {
server = createServer(createRequestListener({ credentials: null }));
await new Promise(klaar => server.listen(0, '127.0.0.1', klaar));
basis = `http://127.0.0.1:${server.address().port}`;
const res = await fetch(`${basis}/index.html`);
assert.equal(res.status, 200, 'het inlaadpunt hoort gewoon geserveerd te worden');
csp = res.headers.get('content-security-policy');
});
after(() => server.close());
it('stuurt een header mee', () => {
assert.ok(csp, 'zonder header is er geen grens en zegt de rest van deze suite niets');
});
it('staat in connect-src precies de origins toe die de helper noemt', () => {
const directive = csp.split(';').map(d => d.trim()).find(d => d.startsWith('connect-src'));
const bronnen = directive.split(/\s+/).slice(1);
assert.deepEqual(bronnen, [`'self'`, ...connectSrcOrigins()]);
});
it('houdt script-src kaal op self, zonder enige uitzondering', () => {
const directive = csp.split(';').map(d => d.trim()).find(d => d.startsWith('script-src'));
assert.equal(directive, `script-src 'self'`);
});
it('sluit object-src en frame-ancestors helemaal af', () => {
assert.match(csp, /object-src 'none'/);
assert.match(csp, /frame-ancestors 'none'/);
});
});