diff --git a/index.html b/index.html index fe0765c..a1d6075 100644 --- a/index.html +++ b/index.html @@ -11,10 +11,7 @@ Portfolio Florian Sylvain - Développeur web fullstack - - + diff --git a/script.js b/script.js index 51c3266..90d0301 100644 --- a/script.js +++ b/script.js @@ -75,3 +75,12 @@ if (menuBtn && nav) { if (e.key === "Escape") closeMenu(); }); } + +document.addEventListener("DOMContentLoaded", function () { + const links = document.querySelectorAll("link[data-onload]"); + links.forEach((link) => { + const onloadCode = link.getAttribute("data-onload"); + link.onload = new Function(onloadCode); + link.removeAttribute("data-onload"); + }); +}); diff --git a/server.js b/server.js index d6453d9..e8baeb6 100644 --- a/server.js +++ b/server.js @@ -179,6 +179,15 @@ function minifyHTML(src) { .replace(/]*>([\s\S]*?)<\/style>/gi, (m, css) => { return m.replace(css, minifyCSS(css)); }) + .replace( + /]*)\s+onload=["']([^"']+)["']([^>]*)>/gi, + (match, before, onloadCode, after) => { + return ``; + } + ) .replace(/\s+([\w-]+)=["']([^"'\s<>]+)["']/g, (m, attr, val) => { if (/^[a-zA-Z0-9._:/-]+$/.test(val)) return ` ${attr}=${val}`; return m; @@ -412,6 +421,30 @@ function preCompress(buf) { }); } +function injectSRIHashes(html) { + const cssEntry = files.get("/style.css"); + if (cssEntry && cssEntry.sri) { + html = html.replace( + /]*href=["']style\.css["'][^>]*)>/gi, + `` + ); + } + + const jsEntry = files.get("/script.js"); + if (jsEntry && jsEntry.sri) { + html = html.replace( + /]*src=["']script\.js["'][^>]*)>/gi, + `` + ); + } + + return html; +} + +function generateSRIHash(content) { + return crypto.createHash("sha384").update(content, "utf8").digest("base64"); +} + async function loadAndMinify(relPath, minify) { const abs = path.join(ROOT, relPath); const src = await fs.promises.readFile(abs); @@ -422,6 +455,13 @@ async function loadAndMinify(relPath, minify) { } const body = minify ? Buffer.from(minify(originalContent), "utf8") : src; + + let sriHash = null; + if (relPath === "style.css" || relPath === "script.js") { + sriHash = generateSRIHash(body.toString("utf8")); + console.log(`SRI hash for ${relPath}: sha384-${sriHash}`); + } + const compressed = await preCompress(body); const stats = await fs.promises.stat(abs); @@ -465,6 +505,7 @@ async function loadAndMinify(relPath, minify) { brEtag: compressed.br ? etag(compressed.br) : undefined, gz: compressed.gz, gzEtag: compressed.gz ? etag(compressed.gz) : undefined, + sri: sriHash, }; files.set("/" + relPath.replace(/\\/g, "/"), entry);