diff --git a/library/lib/SafeScript.js b/library/lib/SafeScript.js new file mode 100644 index 0000000..92ca18c --- /dev/null +++ b/library/lib/SafeScript.js @@ -0,0 +1,17 @@ +const crypto = require('crypto') +const React = require('react') + +module.exports = { SafeScript, recordScriptHashes } + +function SafeScript({ dangerouslySetInnerHTML }) { + if (!global.scriptHashes) throw new Error('No script hashes present') + global.scriptHashes.add(crypto.createHash('sha256').update(dangerouslySetInnerHTML.__html).digest('base64')) + return React.createElement('script', { dangerouslySetInnerHTML }) +} + +function recordScriptHashes(newScriptHashses, callback) { + global.scriptHashes = newScriptHashses + const result = callback() + global.scriptHashes = null + return result +} diff --git a/library/lib/eval-in-fork.js b/library/lib/eval-in-fork.js index d5e3218..4bf8858 100644 --- a/library/lib/eval-in-fork.js +++ b/library/lib/eval-in-fork.js @@ -8,8 +8,14 @@ attempt(() => { function handleMessage(source) { attempt(() => { process.off('message', handleMessage) - const { template, renderer } = evalSource(source) - const result = renderer(template) + + const { template, renderer, recordScriptHashes } = evalSource(source) + const scriptHashes = new Set() + const result = recordScriptHashes(scriptHashes, () => + renderer(template) + ) + if (scriptHashes.size) + console.log('[Warning]: generating a static template with inline scripts, if you want to use a CSP header, make it a dynamic template by exporting a function') process.send(result, e => attempt(() => { diff --git a/library/lib/rollbar.js b/library/lib/rollbar.js index 63d1ef5..ba8501d 100644 --- a/library/lib/rollbar.js +++ b/library/lib/rollbar.js @@ -1,5 +1,6 @@ import fs from 'fs' import merge from 'rollbar/src/merge' +import { SafeScript } from './SafeScript' const snippet = fs.readFileSync(__non_webpack_require__.resolve('rollbar/dist/rollbar.snippet.js'), 'utf8') @@ -15,5 +16,5 @@ const defaultOptions = { export default function rollbar(options, nonSerializableRollbarConfig = '/* no non-serializable config */') { const config = JSON.stringify(merge(defaultOptions, options)) const __html = `var _rollbarConfig = ${config};${nonSerializableRollbarConfig};${snippet}` - return