chore: [app dir bootstrapping 7] update middleware (#12044)
This commit is contained in:
+25
-12
@@ -1,10 +1,11 @@
|
||||
import type { IncomingMessage, OutgoingMessage } from "http";
|
||||
import type { NextRequest, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { IS_PRODUCTION } from "@calcom/lib/constants";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
import { buildNonce } from "@lib/buildNonce";
|
||||
import { buildNonce } from "./buildNonce";
|
||||
|
||||
function getCspPolicy(nonce: string) {
|
||||
//TODO: Do we need to explicitly define it in turbo.json
|
||||
@@ -46,11 +47,12 @@ const isPagePathRequest = (url: URL) => {
|
||||
return !isNonPagePathPrefix.test(pathname) && !isFile.test(pathname);
|
||||
};
|
||||
|
||||
export function csp(req: IncomingMessage | null, res: OutgoingMessage | null) {
|
||||
export function csp(req: IncomingMessage | NextRequest | null, res: OutgoingMessage | NextResponse | null) {
|
||||
if (!req) {
|
||||
return { nonce: undefined };
|
||||
}
|
||||
const existingNonce = req.headers["x-nonce"];
|
||||
const existingNonce = "cache" in req ? req.headers.get("x-nonce") : req.headers["x-nonce"];
|
||||
|
||||
if (existingNonce) {
|
||||
const existingNoneParsed = z.string().safeParse(existingNonce);
|
||||
return { nonce: existingNoneParsed.success ? existingNoneParsed.data : "" };
|
||||
@@ -71,17 +73,28 @@ export function csp(req: IncomingMessage | null, res: OutgoingMessage | null) {
|
||||
}
|
||||
// Set x-nonce request header to be used by `getServerSideProps` or similar fns and `Document.getInitialProps` to read the nonce from
|
||||
// It is generated for all page requests but only used by pages that need CSP
|
||||
req.headers["x-nonce"] = nonce;
|
||||
|
||||
if ("cache" in req) {
|
||||
req.headers.set("x-nonce", nonce);
|
||||
} else {
|
||||
req.headers["x-nonce"] = nonce;
|
||||
}
|
||||
|
||||
if (res) {
|
||||
res.setHeader(
|
||||
req.headers["x-csp-enforce"] === "true"
|
||||
? "Content-Security-Policy"
|
||||
: "Content-Security-Policy-Report-Only",
|
||||
getCspPolicy(nonce)
|
||||
.replace(/\s{2,}/g, " ")
|
||||
.trim()
|
||||
);
|
||||
const enforced =
|
||||
"cache" in req ? req.headers.get("x-csp-enforce") === "true" : req.headers["x-csp-enforce"] === "true";
|
||||
|
||||
const name = enforced ? "Content-Security-Policy" : "Content-Security-Policy-Report-Only";
|
||||
|
||||
const value = getCspPolicy(nonce)
|
||||
.replace(/\s{2,}/g, " ")
|
||||
.trim();
|
||||
|
||||
if ("body" in res) {
|
||||
res.headers.set(name, value);
|
||||
} else {
|
||||
res.setHeader(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
return { nonce };
|
||||
|
||||
@@ -5,10 +5,14 @@ import { NextResponse } from "next/server";
|
||||
|
||||
import { extendEventData, nextCollectBasicSettings } from "@calcom/lib/telemetry";
|
||||
|
||||
import { csp } from "@lib/csp";
|
||||
|
||||
const middleware: NextMiddleware = async (req) => {
|
||||
const url = req.nextUrl;
|
||||
const requestHeaders = new Headers(req.headers);
|
||||
|
||||
requestHeaders.set("x-url", req.url);
|
||||
|
||||
if (!url.pathname.startsWith("/api")) {
|
||||
//
|
||||
// NOTE: When tRPC hits an error a 500 is returned, when this is received
|
||||
@@ -32,6 +36,18 @@ const middleware: NextMiddleware = async (req) => {
|
||||
}
|
||||
|
||||
const res = routingForms.handle(url);
|
||||
|
||||
const { nonce } = csp(req, res ?? null);
|
||||
|
||||
if (!process.env.CSP_POLICY) {
|
||||
req.headers.set("x-csp", "not-opted-in");
|
||||
} else if (!req.headers.get("x-csp")) {
|
||||
// If x-csp not set by gSSP, then it's initialPropsOnly
|
||||
req.headers.set("x-csp", "initialPropsOnly");
|
||||
} else {
|
||||
req.headers.set("x-csp", nonce ?? "");
|
||||
}
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user