#!/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}! \${randomEmoji}\`;`; 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');