@clerk/nextjs
Version:
Clerk SDK for NextJS
210 lines • 7.48 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var content_security_policy_exports = {};
__export(content_security_policy_exports, {
createContentSecurityPolicyHeaders: () => createContentSecurityPolicyHeaders,
generateNonce: () => generateNonce
});
module.exports = __toCommonJS(content_security_policy_exports);
var import_internal = require("@clerk/backend/internal");
class ContentSecurityPolicyDirectiveManager {
/**
* Creates a new ContentSecurityPolicyDirectiveSet with default values
* @returns A new ContentSecurityPolicyDirectiveSet with default values
*/
static createDefaultDirectives() {
return Object.entries(this.DEFAULT_DIRECTIVES).reduce((acc, [key, values]) => {
acc[key] = new Set(values);
return acc;
}, {});
}
/**
* Checks if a value is a special keyword that requires quoting
* @param value - The value to check
* @returns True if the value is a special keyword
*/
static isKeyword(value) {
return this.KEYWORDS.has(value.replace(/^'|'$/g, ""));
}
/**
* Formats a value according to CSP rules, adding quotes for special keywords
* @param value - The value to format
* @returns The formatted value
*/
static formatValue(value) {
const unquoted = value.replace(/^'|'$/g, "");
return this.isKeyword(unquoted) ? `'${unquoted}'` : value;
}
/**
* Handles directive values, ensuring proper formatting and special case handling
* @param values - Array of values to process
* @returns Set of formatted values
*/
static handleDirectiveValues(values) {
const result = /* @__PURE__ */ new Set();
if (values.includes("'none'") || values.includes("none")) {
result.add("'none'");
return result;
}
values.forEach((v) => result.add(this.formatValue(v)));
return result;
}
}
/** Set of special keywords that require quoting in CSP directives */
ContentSecurityPolicyDirectiveManager.KEYWORDS = /* @__PURE__ */ new Set([
"none",
"self",
"strict-dynamic",
"unsafe-eval",
"unsafe-hashes",
"unsafe-inline"
]);
/** Default CSP directives and their values */
ContentSecurityPolicyDirectiveManager.DEFAULT_DIRECTIVES = {
"connect-src": [
"self",
"https://clerk-telemetry.com",
"https://*.clerk-telemetry.com",
"https://api.stripe.com",
"https://maps.googleapis.com"
],
"default-src": ["self"],
"form-action": ["self"],
"frame-src": [
"self",
"https://challenges.cloudflare.com",
"https://*.js.stripe.com",
"https://js.stripe.com",
"https://hooks.stripe.com"
],
"img-src": ["self", "https://img.clerk.com"],
"script-src": [
"self",
...process.env.NODE_ENV !== "production" ? ["unsafe-eval"] : [],
"unsafe-inline",
"https:",
"http:",
"https://*.js.stripe.com",
"https://js.stripe.com",
"https://maps.googleapis.com"
],
"style-src": ["self", "unsafe-inline"],
"worker-src": ["self", "blob:"]
};
function handleExistingDirective(mergedCSP, key, values) {
if (values.includes("'none'") || values.includes("none")) {
mergedCSP[key] = /* @__PURE__ */ new Set(["'none'"]);
return;
}
const deduplicatedSet = /* @__PURE__ */ new Set();
mergedCSP[key].forEach((value) => {
deduplicatedSet.add(ContentSecurityPolicyDirectiveManager.formatValue(value));
});
values.forEach((value) => {
deduplicatedSet.add(ContentSecurityPolicyDirectiveManager.formatValue(value));
});
mergedCSP[key] = deduplicatedSet;
}
function handleCustomDirective(customDirectives, key, values) {
if (values.includes("'none'") || values.includes("none")) {
customDirectives.set(key, /* @__PURE__ */ new Set(["'none'"]));
return;
}
const formattedValues = /* @__PURE__ */ new Set();
values.forEach((value) => {
const formattedValue = ContentSecurityPolicyDirectiveManager.formatValue(value);
formattedValues.add(formattedValue);
});
customDirectives.set(key, formattedValues);
}
function formatCSPHeader(mergedCSP) {
return Object.entries(mergedCSP).sort(([a], [b]) => a.localeCompare(b)).map(([key, values]) => {
const valueObjs = Array.from(values).map((v) => ({
raw: v,
formatted: ContentSecurityPolicyDirectiveManager.formatValue(v)
}));
return `${key} ${valueObjs.map((item) => item.formatted).join(" ")}`;
}).join("; ");
}
function generateNonce() {
const randomBytes = new Uint8Array(16);
crypto.getRandomValues(randomBytes);
const binaryString = Array.from(randomBytes, (byte) => String.fromCharCode(byte)).join("");
return btoa(binaryString);
}
function buildContentSecurityPolicyDirectives(strict, host, customDirectives, nonce) {
const directives = Object.entries(ContentSecurityPolicyDirectiveManager.DEFAULT_DIRECTIVES).reduce(
(acc, [key, values]) => {
acc[key] = new Set(values);
return acc;
},
{}
);
directives["connect-src"].add(host);
if (strict) {
directives["script-src"].delete("http:");
directives["script-src"].delete("https:");
directives["script-src"].add("'strict-dynamic'");
if (nonce) {
directives["script-src"].add(`'nonce-${nonce}'`);
}
}
if (customDirectives) {
const customDirectivesMap = /* @__PURE__ */ new Map();
Object.entries(customDirectives).forEach(([key, values]) => {
const valuesArray = Array.isArray(values) ? values : [values];
if (ContentSecurityPolicyDirectiveManager.DEFAULT_DIRECTIVES[key]) {
handleExistingDirective(directives, key, valuesArray);
} else {
handleCustomDirective(customDirectivesMap, key, valuesArray);
}
});
customDirectivesMap.forEach((values, key) => {
directives[key] = values;
});
}
return formatCSPHeader(directives);
}
function createContentSecurityPolicyHeaders(host, options) {
var _a;
const headers = [];
const nonce = options.strict ? generateNonce() : void 0;
let cspHeader = buildContentSecurityPolicyDirectives((_a = options.strict) != null ? _a : false, host, options.directives, nonce);
if (options.reportTo) {
cspHeader += "; report-to csp-endpoint";
headers.push([import_internal.constants.Headers.ReportingEndpoints, `csp-endpoint="${options.reportTo}"`]);
}
if (options.reportOnly) {
headers.push([import_internal.constants.Headers.ContentSecurityPolicyReportOnly, cspHeader]);
} else {
headers.push([import_internal.constants.Headers.ContentSecurityPolicy, cspHeader]);
}
if (nonce) {
headers.push([import_internal.constants.Headers.Nonce, nonce]);
}
return {
headers
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createContentSecurityPolicyHeaders,
generateNonce
});
//# sourceMappingURL=content-security-policy.js.map
;