import { defineMiddleware } from "astro:middleware"; import { getActionContext } from "astro:actions"; import type { APIContext, MiddlewareNext } from "astro"; // htmz -> frame-ancestors 'self' & X-Frame-Options SAMEORIGIN // astro -> 'unsafe-inline' const SECURITY_HEADERS: Record = { "Content-Security-Policy": [ "default-src 'self'", "script-src 'self' 'unsafe-inline'", "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https://badblocks.goatcounter.com", "font-src 'self'", "connect-src 'self' https://badblocks.goatcounter.com https://api.iconify.design", "object-src 'none'", "frame-ancestors 'self'", "base-uri 'self'", "form-action 'self'", ].join("; "), "X-Content-Type-Options": "nosniff", "X-Frame-Options": "SAMEORIGIN", "Referrer-Policy": "strict-origin-when-cross-origin", "Permissions-Policy": "camera=(), microphone=(), geolocation=()", }; async function handle(context: APIContext, next: MiddlewareNext) { if (context.isPrerendered) return next(); const { action, setActionResult, serializeActionResult } = getActionContext(context); const currentAction = await context.session?.get("currentAction"); if (currentAction) { context.session?.delete("currentAction"); try { const { actionName, actionResult } = JSON.parse(currentAction); setActionResult(actionName, actionResult); } catch {} return next(); } if (action?.calledFrom === "form") { const formData = await context.request.clone().formData(); const actionResult = await action.handler(); context.session?.set( "currentAction", JSON.stringify({ actionName: action.name, actionResult: serializeActionResult(actionResult), }), ); if (actionResult.error) { const draft = { action: formData.get("action")?.toString() ?? "", name: formData.get("name")?.toString() ?? "", phone: formData.get("phone")?.toString() ?? "", msg: formData.get("msg")?.toString() ?? "", }; context.session?.set("contactFormDraft", draft); let redirectPath = context.originPathname; try { const referer = new URL(context.request.headers.get("Referer") ?? ""); if (referer.origin === context.url.origin) { redirectPath = referer.pathname; } } catch {} return context.redirect(redirectPath); } context.session?.delete("contactFormDraft"); return context.redirect(context.originPathname); } return next(); } export const onRequest = defineMiddleware(async (context, next) => { const response = await handle(context, next); for (const [header, value] of Object.entries(SECURITY_HEADERS)) { response.headers.set(header, value); } return response; });