From 58b2fc935bf0cf5f96eb9be9b09f4cfa0d92e940 Mon Sep 17 00:00:00 2001 From: Cyrus Date: Mon, 17 Jun 2024 19:03:36 +0800 Subject: [PATCH 1/2] fix(csp): inline script or style have whitespace character --- src/runtime/nitro/plugins/30-cspSsgHashes.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/nitro/plugins/30-cspSsgHashes.ts b/src/runtime/nitro/plugins/30-cspSsgHashes.ts index 4fc09c88..98e785e4 100644 --- a/src/runtime/nitro/plugins/30-cspSsgHashes.ts +++ b/src/runtime/nitro/plugins/30-cspSsgHashes.ts @@ -4,8 +4,8 @@ import { generateHash } from '../../../utils/hash' import type { Section } from '../../../types/module' -const INLINE_SCRIPT_RE = /]*?\bsrc="[\w:.\-\\/]+")[^>]*>(.*?)<\/script>/gi -const STYLE_RE = /]*>(.*?)<\/style>/gi +const INLINE_SCRIPT_RE = /]*?\bsrc="[\w:.\-\\/]+")[^>]*>([\s\S]*?)<\/script>/gi +const STYLE_RE = /]*>([\s\S]*?)<\/style>/gi const SCRIPT_RE = /]+\bsrc="[^"]+")(?=[^>]+\bintegrity="([\w\-+/=]+)")[^>]+(?:\/>|><\/script[^>]*?>)/gi const LINK_RE = /]+\brel="(stylesheet|preload|modulepreload)")(?=[^>]+\bintegrity="([\w\-+/=]+)")(?=(?:[^>]+\bas="(\w+)")?)[^>]+>/gi From 4aede1b04e306e1da7047d96ab3c34c7b6c4563d Mon Sep 17 00:00:00 2001 From: Cyrus Date: Mon, 17 Jun 2024 19:03:46 +0800 Subject: [PATCH 2/2] test(csp): inline script or style have whitespace character --- test/fixtures/ssgHashes/nuxt.config.ts | 6 ++++ .../pages/inline-script-with-linebreak.vue | 19 ++++++++++ .../pages/inline-style-with-linebreak.vue | 15 ++++++++ test/ssgHashes.test.ts | 35 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 test/fixtures/ssgHashes/pages/inline-script-with-linebreak.vue create mode 100644 test/fixtures/ssgHashes/pages/inline-style-with-linebreak.vue diff --git a/test/fixtures/ssgHashes/nuxt.config.ts b/test/fixtures/ssgHashes/nuxt.config.ts index 308e1a08..11c9a434 100644 --- a/test/fixtures/ssgHashes/nuxt.config.ts +++ b/test/fixtures/ssgHashes/nuxt.config.ts @@ -9,9 +9,15 @@ export default defineNuxtConfig({ '/inline-script': { prerender: true }, + '/inline-script-with-linebreak': { + prerender: true + }, '/inline-style': { prerender: true }, + '/inline-style-with-linebreak': { + prerender: true + }, '/external-script': { prerender: true }, diff --git a/test/fixtures/ssgHashes/pages/inline-script-with-linebreak.vue b/test/fixtures/ssgHashes/pages/inline-script-with-linebreak.vue new file mode 100644 index 00000000..3d4c8b48 --- /dev/null +++ b/test/fixtures/ssgHashes/pages/inline-script-with-linebreak.vue @@ -0,0 +1,19 @@ + + diff --git a/test/fixtures/ssgHashes/pages/inline-style-with-linebreak.vue b/test/fixtures/ssgHashes/pages/inline-style-with-linebreak.vue new file mode 100644 index 00000000..8393b55b --- /dev/null +++ b/test/fixtures/ssgHashes/pages/inline-style-with-linebreak.vue @@ -0,0 +1,15 @@ + + diff --git a/test/ssgHashes.test.ts b/test/ssgHashes.test.ts index 28fb35b1..b59f4c23 100644 --- a/test/ssgHashes.test.ts +++ b/test/ssgHashes.test.ts @@ -84,6 +84,23 @@ describe('[nuxt-security] SSG support of CSP', async () => { expect(externalStyleHashes).toBe(expectedExternalStyleHashes) }) + it('sets script-src for inline scripts with line break', async () => { + const res = await fetch('/inline-script-with-linebreak') + const body = await res.text() + const { metaTag, csp, elementsWithIntegrity, inlineScriptHashes, externalScriptHashes, inlineStyleHashes, externalStyleHashes } = extractDataFromBody(body) + + expect(res).toBeDefined() + expect(res).toBeTruthy() + expect(body).toBeDefined() + expect(metaTag).toBeDefined() + expect(csp).toBeDefined() + expect(elementsWithIntegrity).toBe(expectedIntegrityAttributes) + expect(inlineScriptHashes).toBe(expectedInlineScriptHashes + 1) // Inlined script in head + expect(externalScriptHashes).toBe(expectedExternalScriptHashes + 1) // + 1 vue modulepreload + expect(inlineStyleHashes).toBe(expectedInlineStyleHashes) + expect(externalStyleHashes).toBe(expectedExternalStyleHashes) + }) + it('sets style-src for inline styles', async () => { const res = await fetch('/inline-style') @@ -102,6 +119,24 @@ describe('[nuxt-security] SSG support of CSP', async () => { expect(externalStyleHashes).toBe(expectedExternalStyleHashes) }) + it('sets style-src for inline styles with line break', async () => { + const res = await fetch('/inline-style-with-linebreak') + + const body = await res.text() + const { metaTag, csp, elementsWithIntegrity, inlineScriptHashes, externalScriptHashes, inlineStyleHashes, externalStyleHashes } = extractDataFromBody(body) + + expect(res).toBeDefined() + expect(res).toBeTruthy() + expect(body).toBeDefined() + expect(metaTag).toBeDefined() + expect(csp).toBeDefined() + expect(elementsWithIntegrity).toBe(expectedIntegrityAttributes) + expect(inlineScriptHashes).toBe(expectedInlineScriptHashes) + expect(externalScriptHashes).toBe(expectedExternalScriptHashes + 1) // + 1 vue modulepreload + expect(inlineStyleHashes).toBe(expectedInlineStyleHashes + 1) // Inlined style + expect(externalStyleHashes).toBe(expectedExternalStyleHashes) + }) + it('sets script-src for external scripts', async () => { const res = await fetch('/external-script')