@@ -19,6 +19,7 @@ const {
1919const { createSearchIndex} = require ( '../lit-dev-tools/lib/search/plugin.js' ) ;
2020const { preCompress} = require ( '../lit-dev-tools/lib/pre-compress.js' ) ;
2121const luxon = require ( 'luxon' ) ;
22+ const crypto = require ( 'crypto' ) ;
2223
2324// Use the same slugify as 11ty for markdownItAnchor. It's similar to Jekyll,
2425// and preserves the existing URL fragments
@@ -29,6 +30,8 @@ const OUTPUT_DIR = DEV ? '_dev' : '_site';
2930const PLAYGROUND_SANDBOX =
3031 process . env . PLAYGROUND_SANDBOX || 'http://localhost:6416/' ;
3132
33+ const cspInlineScriptHashes = new Set ( ) ;
34+
3235module . exports = function ( eleventyConfig ) {
3336 // https://github.com/JordanShurmer/eleventy-plugin-toc#readme
3437 eleventyConfig . addPlugin ( pluginTOC , {
@@ -333,7 +336,12 @@ ${content}
333336 if ( DEV ) {
334337 return `<script type="module" src="/js/${ path } "></script>` ;
335338 }
336- const script = fsSync . readFileSync ( `rollupout/${ path } ` , 'utf8' ) ;
339+ // Note we must trim before hashing, because our html-minifier will trim
340+ // inline script trailing newlines, and otherwise our hash will be wrong.
341+ const script = fsSync . readFileSync ( `rollupout/${ path } ` , 'utf8' ) . trim ( ) ;
342+ const hash =
343+ 'sha256-' + crypto . createHash ( 'sha256' ) . update ( script ) . digest ( 'base64' ) ;
344+ cspInlineScriptHashes . add ( hash ) ;
337345 return `<script type="module">${ script } </script>` ;
338346 } ) ;
339347
@@ -351,6 +359,10 @@ ${content}
351359 ) ;
352360 } ) ;
353361
362+ eleventyConfig . on ( 'beforeBuild' , ( ) => {
363+ cspInlineScriptHashes . clear ( ) ;
364+ } ) ;
365+
354366 eleventyConfig . on ( 'afterBuild' , async ( ) => {
355367 // The eleventyNavigation plugin requires that each section heading in our
356368 // docs has its own actual markdown file. But we don't actually use these
@@ -412,6 +424,14 @@ ${content}
412424 // them directly instead of spending its own cycles. Note this adds ~4
413425 // seconds to the build, but it's disabled during dev.
414426 await preCompress ( { glob : `${ OUTPUT_DIR } /**/*` } ) ;
427+
428+ // Note we only need to write CSP inline script hashes for the production
429+ // output, because in dev mode we don't inline scripts.
430+ await fs . writeFile (
431+ path . join ( OUTPUT_DIR , 'csp-inline-script-hashes.txt' ) ,
432+ [ ...cspInlineScriptHashes ] . join ( '\n' ) ,
433+ 'utf8'
434+ ) ;
415435 }
416436 } ) ;
417437
0 commit comments