vike
Version:
The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.
49 lines (48 loc) • 2.17 kB
JavaScript
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}'`);
}