UNPKG

vike

Version:

The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.

49 lines (48 loc) 2.17 kB
import '../../assertEnvServer.js'; export { resolvePageContextCspNone }; export { inferNonceAttr }; export { addCspResponseHeader }; import { import_ } from '@brillout/import'; import { assert } from '../../../utils/assert.js'; async function resolvePageContextCspNone(pageContext) { if (pageContext.cspNonce) return null; // already set by user e.g. `renderPage({ cspNonce: '123456789' })` const { csp } = pageContext.config; const pageContextAddendum = { cspNonce: null }; if (csp?.nonce) { if (csp.nonce === true) { pageContextAddendum.cspNonce = await generateNonce(); } else { pageContextAddendum.cspNonce = await csp.nonce(pageContext); } } return pageContextAddendum; } // Generate a cryptographically secure nonce for Content Security Policy (CSP). // Returns a base64url-encoded nonce string (URL-safe, no padding). // https://github.com/vikejs/vike/issues/1554#issuecomment-3181128304 async function generateNonce() { let cryptoModule; try { cryptoModule = (await import_('crypto')).default; } catch { return Math.random().toString(36).substring(2, 18); } return cryptoModule.randomBytes(16).toString('base64url'); } function inferNonceAttr(pageContext) { // No need to escape the injected HTML — pageContext.cspNone is controlled by the developer, not by the website visitor (I wouldn't know why the developer would set +csp.none to a value coming from the database) const nonceAttr = pageContext.cspNonce ? ` nonce="${pageContext.cspNonce}"` : ''; return nonceAttr; } function addCspResponseHeader(pageContext, headersResponse) { assert(pageContext.cspNonce === null || typeof pageContext.cspNonce === 'string'); // ensure resolvePageContextCspNone() is called before addCspResponseHeader() if (!pageContext.cspNonce) return; if (headersResponse.get('Content-Security-Policy')) return; // No need to sanitize the injected header — see comment above about not escaping HTML headersResponse.set('Content-Security-Policy', `script-src 'self' 'nonce-${pageContext.cspNonce}'`); }