nzambello.dev/generate-csp-hashes.js

56 lines
3.4 KiB
JavaScript
Raw Normal View History

2025-08-12 14:45:07 +02:00
#!/usr/bin/env node
import crypto from 'crypto';
import fs from 'fs';
// Function to calculate SHA256 hash of a string
function calculateHash(content) {
return crypto.createHash('sha256').update(content, 'utf8').digest('base64');
}
// Function to read and hash a script file
function hashScriptFile(filePath, description) {
try {
const content = fs.readFileSync(filePath, 'utf8');
const hash = calculateHash(content);
console.log(`\n📄 ${description}:`);
console.log(` File: ${filePath}`);
console.log(` Hash: sha256-${hash}`);
return hash;
} catch (error) {
console.error(`❌ Error reading ${filePath}:`, error.message);
return null;
}
}
// Function to hash inline script content
function hashInlineScript(content, description) {
const hash = calculateHash(content);
console.log(`\n📄 ${description}:`);
console.log(` Content: ${content.substring(0, 50)}...`);
console.log(` Hash: sha256-${hash}`);
return hash;
}
console.log('🔒 CSP Hash Generator for nzambello.dev');
console.log('=' .repeat(50));
// Hash the inline scripts
const greetingScript = `const messages = ['Hi', 'Hello', 'Hey', 'Welcome', 'Ciao']; const emojis = ['🍻', '🧑‍💻', '👋', '😎']; const randomMessage = messages[Math.floor(Math.random() * messages.length)]; const randomEmoji = emojis[Math.floor(Math.random() * emojis.length)]; document.querySelector('.documentFirstHeading').innerHTML = \`\${randomMessage}! <span role=\"presentation\">\${randomEmoji}</span>\`;`;
const themeScript = `const theme = (() => { if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) { return localStorage.getItem('theme'); } if (window.matchMedia('(prefers-color-scheme: dark)').matches) { return 'dark'; } return 'light'; })(); if (theme === 'light') { document.documentElement.setAttribute('data-theme', 'light'); } else { document.documentElement.setAttribute('data-theme', 'dark'); } window.localStorage.setItem('theme', theme || 'dark'); const handleToggleClick = () => { const element = document.documentElement; const currentTheme = element.getAttribute('data-theme'); const themeToSet = currentTheme === 'light' ? 'dark' : 'light'; document.documentElement.setAttribute('data-theme', themeToSet); localStorage.setItem('theme', themeToSet); }; document.getElementById('themeToggle')?.addEventListener('click', handleToggleClick);`;
const mobileMenuScript = `(() => { if (window.innerWidth < 768) { let menuItems = document.querySelectorAll("ul.menu li a"); let mobileCheckbox = document.getElementById("mobile-checkbox"); if (menuItems) { menuItems.forEach(item => { item.addEventListener("click", function (e) { if (!mobileCheckbox) { console.error("Missing checkbox"); return; } mobileCheckbox.click(); }); }); } } })();`;
hashInlineScript(greetingScript, 'Greeting Component Script');
hashInlineScript(themeScript, 'Theme Toggle Script');
hashInlineScript(mobileMenuScript, 'Mobile Menu Script');
console.log('\n📋 CSP script-src directive:');
console.log('script-src \'self\' \'sha256-Yquyj0OvZPim1KtfvmzH7a5g/cyAwbreCP2vA77GIYc=\' \'sha256-5mYCGuMdgD53DYi31hybbLGMf6iBSua4OTpdGEl3490=\' \'sha256-eVurunkZ7K8ov2flSXph7L5iyAFns7adCjYmAIDBgrE=\' https://umami.nzambello.dev');
console.log('\n💡 To update CSP hashes:');
console.log('1. Modify the script content in this file');
console.log('2. Run: node generate-csp-hashes.js');
console.log('3. Update astro.config.mjs and nginx/nginx.conf with new hashes');