119 lines
3.2 KiB
JavaScript
Executable File
119 lines
3.2 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* CSP Hash Extractor and Calculator
|
|
*
|
|
* This script extracts inline scripts and styles from HTML files
|
|
* and calculates SHA-256 hashes for use in Content Security Policy headers.
|
|
*
|
|
* Usage:
|
|
* node extract-and-hash-csp.js <html-file-path>
|
|
*
|
|
* Example:
|
|
* node extract-and-hash-csp.js ./docker/showerloop/public/index.html
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const crypto = require('crypto');
|
|
|
|
// Function to calculate CSP hash
|
|
function calculateHash(content) {
|
|
const hash = crypto.createHash('sha256').update(content, 'utf8').digest('base64');
|
|
return `'sha256-${hash}'`;
|
|
}
|
|
|
|
// Function to extract inline scripts from HTML
|
|
function extractInlineScripts(html) {
|
|
const scriptRegex = /<script(?:\s[^>]*)?>([\s\S]*?)<\/script>/gi;
|
|
const scripts = [];
|
|
let match;
|
|
|
|
while ((match = scriptRegex.exec(html)) !== null) {
|
|
const scriptContent = match[1].trim();
|
|
if (scriptContent && !scriptContent.includes('src=')) {
|
|
scripts.push(scriptContent);
|
|
}
|
|
}
|
|
|
|
return scripts;
|
|
}
|
|
|
|
// Function to extract inline styles from HTML
|
|
function extractInlineStyles(html) {
|
|
const styleRegex = /<style(?:\s[^>]*)?>([\s\S]*?)<\/style>/gi;
|
|
const styles = [];
|
|
let match;
|
|
|
|
while ((match = styleRegex.exec(html)) !== null) {
|
|
const styleContent = match[1].trim();
|
|
if (styleContent) {
|
|
styles.push(styleContent);
|
|
}
|
|
}
|
|
|
|
return styles;
|
|
}
|
|
|
|
// Main function
|
|
function main() {
|
|
if (process.argv.length < 3) {
|
|
console.error('Error: Please provide an HTML file path.');
|
|
process.exit(1);
|
|
}
|
|
|
|
const filePath = process.argv[2];
|
|
|
|
try {
|
|
const html = fs.readFileSync(filePath, 'utf8');
|
|
|
|
const scripts = extractInlineScripts(html);
|
|
const styles = extractInlineStyles(html);
|
|
|
|
console.log(`\nAnalyzing file: ${filePath}`);
|
|
console.log('\n=== Inline Scripts ===');
|
|
|
|
if (scripts.length === 0) {
|
|
console.log('No inline scripts found.');
|
|
} else {
|
|
console.log(`Found ${scripts.length} inline scripts.`);
|
|
const scriptHashes = new Set();
|
|
|
|
scripts.forEach((script, index) => {
|
|
const hash = calculateHash(script);
|
|
scriptHashes.add(hash);
|
|
console.log(`\nScript #${index + 1}:`);
|
|
console.log(`${script.substring(0, 100)}${script.length > 100 ? '...' : ''}`);
|
|
console.log(`Hash: ${hash}`);
|
|
});
|
|
|
|
console.log('\nScript CSP directive:');
|
|
console.log(`script-src 'self' ${Array.from(scriptHashes).join(' ')}`);
|
|
}
|
|
|
|
console.log('\n=== Inline Styles ===');
|
|
|
|
if (styles.length === 0) {
|
|
console.log('No inline styles found.');
|
|
} else {
|
|
console.log(`Found ${styles.length} inline styles.`);
|
|
const styleHashes = new Set();
|
|
|
|
styles.forEach((style, index) => {
|
|
const hash = calculateHash(style);
|
|
styleHashes.add(hash);
|
|
console.log(`\nStyle #${index + 1}:`);
|
|
console.log(`${style.substring(0, 100)}${style.length > 100 ? '...' : ''}`);
|
|
console.log(`Hash: ${hash}`);
|
|
});
|
|
|
|
console.log('\nStyle CSP directive:');
|
|
console.log(`style-src 'self' ${Array.from(styleHashes).join(' ')}`);
|
|
}
|
|
} catch (err) {
|
|
console.error(`Error: ${err.message}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|