UNPKG

nuxt-security

Version:

🛡️ Security Module for Nuxt based on HTTP Headers and Middleware

43 lines (42 loc) 1.73 kB
import { defineNitroPlugin } from "nitropack/runtime"; import { resolveSecurityRules } from "../context/index.js"; import { headerStringFromObject } from "../../../utils/headers"; const META_CSP_RE = /<meta\s+http-equiv=["']Content-Security-Policy["'][^>]*>/i; const HEAD_CHARSET_RE = /<meta\s+charset=["'][^"']*["'][^>]*>/i; const HEAD_OPEN_RE = /<head\b[^>]*>/i; export default defineNitroPlugin((nitroApp) => { if (!import.meta.prerender) { return; } nitroApp.hooks.hook("render:response", (response, { event }) => { const rules = resolveSecurityRules(event); if (!rules.enabled) { return; } if (rules.ssg && rules.ssg.meta && rules.headers && rules.headers.contentSecurityPolicy) { const body = response.body; if (typeof body !== "string" || !body) { return; } const csp = structuredClone(rules.headers.contentSecurityPolicy); csp["frame-ancestors"] = false; const headerValue = headerStringFromObject("contentSecurityPolicy", csp); const metaTag = `<meta http-equiv="Content-Security-Policy" content="${headerValue}">`; if (META_CSP_RE.test(body)) { response.body = body.replace(META_CSP_RE, metaTag); return; } const charsetMatch = HEAD_CHARSET_RE.exec(body); if (charsetMatch) { const insertAt = charsetMatch.index + charsetMatch[0].length; response.body = body.slice(0, insertAt) + metaTag + body.slice(insertAt); return; } const headMatch = HEAD_OPEN_RE.exec(body); if (headMatch) { const insertAt = headMatch.index + headMatch[0].length; response.body = body.slice(0, insertAt) + metaTag + body.slice(insertAt); } } }); });