UNPKG

astro

Version:

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

97 lines (96 loc) 3.58 kB
import { partitionByKind } from "../../../core/csp/runtime.js"; function renderCspContent(result) { const { scriptDirective, styleDirective, directives } = result; const script = partitionByKind(scriptDirective); const style = partitionByKind(styleDirective); const finalScriptHashes = /* @__PURE__ */ new Set(); for (const scriptHash of script.default.hashes) { finalScriptHashes.add(`'${scriptHash}'`); } for (const scriptHash of result._metadata.extraScriptHashes) { finalScriptHashes.add(`'${scriptHash}'`); } const finalStyleHashes = /* @__PURE__ */ new Set(); for (const styleHash of style.default.hashes) { finalStyleHashes.add(`'${styleHash}'`); } for (const styleHash of result._metadata.extraStyleHashes) { finalStyleHashes.add(`'${styleHash}'`); } let directivesContent; if (directives.length > 0) { directivesContent = directives.join(";") + ";"; } const scriptResources = script.default.resources.length > 0 ? script.default.resources.join(" ") : "'self'"; const styleResources = style.default.resources.length > 0 ? style.default.resources.join(" ") : "'self'"; const scriptElementDefaultResource = script.default.resources.length > 0 ? "" : "'self'"; const styleElementDefaultResource = style.default.resources.length > 0 ? "" : "'self'"; const scriptElemActive = isEnabled(script.element); const styleElemActive = isEnabled(style.element); const strictDynamicSuffix = scriptDirective.strictDynamic ? ` 'strict-dynamic'` : ""; const scriptBaselineTokens = [ ...scriptElemActive ? [] : [...finalScriptHashes], ...scriptDirective.strictDynamic ? [`'strict-dynamic'`] : [] ]; const scriptSrc = `script-src ${scriptResources} ${scriptBaselineTokens.join(" ")};`; const styleSrc = `style-src ${styleResources} ${(styleElemActive ? [] : [...finalStyleHashes]).join(" ")};`; const scriptSrcElem = scriptElemActive ? renderSpecificDirective( "script-src-elem", script.element.resources, scriptElementDefaultResource, finalScriptHashes, script.element.hashes, strictDynamicSuffix ) : void 0; const scriptSrcAttr = isEnabled(script.attribute) ? renderSpecificDirective( "script-src-attr", script.attribute.resources, "'none'", void 0, script.attribute.hashes ) : void 0; const styleSrcElem = styleElemActive ? renderSpecificDirective( "style-src-elem", style.element.resources, styleElementDefaultResource, finalStyleHashes, style.element.hashes ) : void 0; const styleSrcAttr = isEnabled(style.attribute) ? renderSpecificDirective( "style-src-attr", style.attribute.resources, "'none'", void 0, style.attribute.hashes ) : void 0; return [ directivesContent, scriptSrc, scriptSrcElem, scriptSrcAttr, styleSrc, styleSrcElem, styleSrcAttr ].filter(Boolean).join(" "); } function isEnabled(sources) { return sources.resources.length > 0 || sources.hashes.length > 0; } function renderSpecificDirective(name, resources, defaultResource, sharedHashes, ownHashes, suffix = "") { const hashes = new Set(sharedHashes); for (const hash of ownHashes) { hashes.add(`'${hash}'`); } let finalResources; if (resources.length > 0) { finalResources = resources.map((r) => `${r}`).join(" "); } else if (defaultResource === "'none'" && hashes.size > 0) { finalResources = ""; } else { finalResources = defaultResource; } return `${name} ${[finalResources, ...hashes].filter(Boolean).join(" ")}${suffix};`; } export { renderCspContent };