From e116e7c234820c3f2cfdc784c7568e06e90dab26 Mon Sep 17 00:00:00 2001 From: Eli Grey <~@eligrey.com> Date: Fri, 18 Oct 2024 03:43:12 +0000 Subject: [PATCH] Support CSP nonce propagation for injected CSS --- package.json | 2 +- src/config.ts | 9 +++++++++ src/consent-manager.tsx | 6 +++++- src/css.ts | 4 ++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 16de241a..a31ddff0 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/transcend-io/consent-manager-ui.git" }, "homepage": "https://github.com/transcend-io/consent-manager-ui", - "version": "4.18.2", + "version": "4.19.0", "license": "MIT", "main": "build/ui", "files": [ diff --git a/src/config.ts b/src/config.ts index 51dd2024..b8a585df 100644 --- a/src/config.ts +++ b/src/config.ts @@ -20,6 +20,7 @@ const { secondaryPolicy, languages, dismissedViewState = 'Hidden', + nonce } = settings; /** @@ -200,3 +201,11 @@ function validateConfig(config: ConsentManagerConfig): boolean { return true; } + +export const CSP_NONCE = nonce; +if (CSP_NONCE) { + const currentScriptDataset = document.currentScript?.dataset; + if (currentScriptDataset) { + delete currentScriptDataset.nonce; + } +} diff --git a/src/consent-manager.tsx b/src/consent-manager.tsx index a2b6a5a7..036a2e0d 100644 --- a/src/consent-manager.tsx +++ b/src/consent-manager.tsx @@ -6,7 +6,7 @@ import type { import { App } from './components/App'; import { logger } from './logger'; import { createHTMLElement } from './utils/create-html-element'; -import { getMergedConfig } from './config'; +import { CSP_NONCE, getMergedConfig } from './config'; // The `transcend` API: methods which we'll create inside Preact and pass back out here via callback let consentManagerAPI: ConsentManagerAPI | null = null; @@ -54,6 +54,10 @@ export const injectConsentManagerApp = async ( // Append UI container to doc to activate style.sheet (document.documentElement || document).append(consentManager); + if (CSP_NONCE) { + style.nonce = CSP_NONCE; + } + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion style .sheet! // 1st rule so subsequent properties are reset diff --git a/src/css.ts b/src/css.ts index eba1eff1..072fcbfd 100644 --- a/src/css.ts +++ b/src/css.ts @@ -1,3 +1,4 @@ +import { CSP_NONCE } from './config'; import { getAppContainer } from './consent-manager'; import { logger } from './logger'; import { createHTMLElement } from './utils/create-html-element'; @@ -13,6 +14,9 @@ export const injectCss = (stylesheetUrl: string): Promise => const root = getAppContainer(); if (root && stylesheetUrl) { const link = createHTMLElement('link'); + if (CSP_NONCE) { + link.nonce = CSP_NONCE; + } link.type = 'text/css'; link.rel = 'stylesheet'; link.id = stylesheetUrl;