diff --git a/packages/config/src/options.js b/packages/config/src/options.js
index e5da7d33d6..fb8d5dd85d 100644
--- a/packages/config/src/options.js
+++ b/packages/config/src/options.js
@@ -3,7 +3,6 @@ import fs from 'fs'
import defaultsDeep from 'lodash/defaultsDeep'
import defaults from 'lodash/defaults'
import pick from 'lodash/pick'
-import isObject from 'lodash/isObject'
import uniq from 'lodash/uniq'
import consola from 'consola'
import { guardDir, isNonEmptyString, isPureObject, isUrl, getMainModule } from '@nuxt/utils'
@@ -179,16 +178,14 @@ export function getNuxtConfig(_options) {
}
// Apply default hash to CSP option
- const { csp } = options.render
-
- const cspDefaults = {
- hashAlgorithm: 'sha256',
- allowedSources: undefined,
- policies: undefined,
- reportOnly: options.debug
- }
- if (csp) {
- options.render.csp = defaults(isObject(csp) ? csp : {}, cspDefaults)
+ if (options.render.csp) {
+ options.render.csp = defaults({}, options.render.csp, {
+ hashAlgorithm: 'sha256',
+ allowedSources: undefined,
+ policies: undefined,
+ addMeta: Boolean(options._generate),
+ reportOnly: options.debug
+ })
}
// cssSourceMap
diff --git a/packages/config/test/options.test.js b/packages/config/test/options.test.js
index dc60fd2062..e744db32ea 100644
--- a/packages/config/test/options.test.js
+++ b/packages/config/test/options.test.js
@@ -81,6 +81,7 @@ describe('config: options', () => {
const { render: { csp } } = getNuxtConfig({ render: { csp: { allowedSources: true, test: true } } })
expect(csp).toEqual({
hashAlgorithm: 'sha256',
+ addMeta: false,
allowedSources: true,
policies: undefined,
reportOnly: false,
diff --git a/packages/vue-renderer/src/renderer.js b/packages/vue-renderer/src/renderer.js
index 6e41ef04ea..898c5a7f2d 100644
--- a/packages/vue-renderer/src/renderer.js
+++ b/packages/vue-renderer/src/renderer.js
@@ -407,21 +407,26 @@ export default class VueRenderer {
APP += ``
// Calculate CSP hashes
+ const { csp } = this.context.options.render
const cspScriptSrcHashes = []
- const csp = this.context.options.render.csp
- const containsUnsafeInlineScriptSrc = csp && csp.policies && csp.policies['script-src'] && csp.policies['script-src'].includes(`'unsafe-inline'`)
+ if (csp) {
+ // Only add the hash if 'unsafe-inline' rule isn't present to avoid conflicts (#5387)
+ const containsUnsafeInlineScriptSrc = csp.policies && csp.policies['script-src'] && csp.policies['script-src'].includes(`'unsafe-inline'`)
+ if (!containsUnsafeInlineScriptSrc) {
+ const hash = crypto.createHash(csp.hashAlgorithm)
+ hash.update(serializedSession)
+ cspScriptSrcHashes.push(`'${csp.hashAlgorithm}-${hash.digest('base64')}'`)
+ }
- // Only add the hash if 'unsafe-inline' rule isn't present to avoid conflicts (#5387)
- if (csp && !containsUnsafeInlineScriptSrc) {
- const { hashAlgorithm } = this.context.options.render.csp
- const hash = crypto.createHash(hashAlgorithm)
- hash.update(serializedSession)
- cspScriptSrcHashes.push(`'${hashAlgorithm}-${hash.digest('base64')}'`)
+ // Call ssr:csp hook
+ await this.context.nuxt.callHook('vue-renderer:ssr:csp', cspScriptSrcHashes)
+
+ // Add csp meta tags
+ if (csp.addMeta) {
+ HEAD += ``
+ }
}
- // Call ssr:csp hook
- await this.context.nuxt.callHook('vue-renderer:ssr:csp', cspScriptSrcHashes)
-
// Prepend scripts
APP += this.renderScripts(context)
APP += m.script.text({ body: true })