forked from ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI
Réécriture SvelteKit statique (Svelte 5 runes + TS, adapter-static)
- Données PeerTube (GADE), Castopod (KUTE) et Mastodon (BOKANTE) bakées au build via +page.server.ts (throttle + retry 429 + déduplication) - Charte OKI complète : tokens, thème sombre par défaut (clair opt-in, anti-FOUC), Archivo/Inter self-hébergées, flag-bar, sprite SVG (zéro emoji en interface, zéro Font Awesome/CDN) - i18n FR/EN par routage [[locale]], bundles JSON, hreflang, %lang% serveur - Pages : accueil, /video/[uuid] (embed, téléchargements, partage, commentaires, JSON-LD VideoObject), /categories/[id], /recherche (index JSON baké, recherche client), /direct (live + annonce multi-fuseaux), /dons, /mentions-legales, /offline + 404 kréyòl - Motion gwoka : KineticText (scrub view()), ScrollProgressBar, FlagChip, reveal syncopé, View Transitions, gate prefers-reduced-motion unique - PWA : manifest + Workbox generateSW (fallback /offline/), registerSW statique - Sécurité : CSP par page en <meta> (SHA-256 des inline via scripts/postbuild-csp.mjs) + headers globaux (_headers Cloudflare et .htaccess o2switch), redirections des anciennes URLs PHP - Doc : docs/DEPLOIEMENT-SVELTEKIT.md
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
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)`);
|
||||
Reference in New Issue
Block a user