Files
annu-kute-ced/scripts/postbuild-csp.mjs
T

45 lines
1.4 KiB
JavaScript
Raw Normal View History

import { createHash } from 'node:crypto';
import { readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const BUILD_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'build');
const scriptRe = /<script(?![^>]*\bsrc=)[^>]*>([\s\S]*?)<\/script>/gi;
function* walk(dir) {
for (const entry of readdirSync(dir)) {
const path = join(dir, entry);
if (statSync(path).isDirectory()) yield* walk(path);
else if (entry.endsWith('.html')) yield path;
}
}
let pages = 0;
for (const file of walk(BUILD_DIR)) {
const html = readFileSync(file, 'utf8');
const hashes = new Set();
for (const match of html.matchAll(scriptRe)) {
const content = match[1];
if (!content.trim()) continue;
hashes.add(`'sha256-${createHash('sha256').update(content).digest('base64')}'`);
}
if (hashes.size === 0) continue;
const csp = `default-src 'self'; script-src 'self' ${[...hashes].join(' ')}`;
const meta = `<meta http-equiv="Content-Security-Policy" content="${csp}" />`;
const anchor = html.match(/<meta charset="[^"]+"\s*\/?>/);
if (!anchor) {
console.warn(`[csp] pas d'ancre charset dans ${file}, page ignorée`);
continue;
}
writeFileSync(file, html.replace(anchor[0], `${anchor[0]}\n\t\t${meta}`));
pages++;
}
console.log(`[csp] meta CSP injectée dans ${pages} page(s)`);