Skip to content

Commit

Permalink
chore: block POST requests to next.js routes except a whitelist
Browse files Browse the repository at this point in the history
  • Loading branch information
hbjORbj committed Feb 18, 2025
1 parent 9a271f3 commit 9421fbe
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 75 deletions.
62 changes: 0 additions & 62 deletions apps/web/abTest/middlewareFactory.ts

This file was deleted.

9 changes: 0 additions & 9 deletions apps/web/abTest/utils.ts

This file was deleted.

55 changes: 55 additions & 0 deletions apps/web/middleware.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { NextRequest } from "next/server";
import { describe, it, expect } from "vitest";

import { WEBAPP_URL } from "@calcom/lib/constants";

import { checkPostMethod, POST_METHODS_ALLOWED_APP_ROUTES } from "./middleware";

describe("Middleware - POST requests restriction", () => {
const createRequest = (path: string, method: string) => {
return new NextRequest(
new Request(`${WEBAPP_URL}${path}`, {
method,
})
);
};

it("should allow POST requests to /api routes", async () => {
const req1 = createRequest("/api/auth/signup", "POST");
const res1 = checkPostMethod(req1);
expect(res1).toBeNull();

const req2 = createRequest("/api/trpc/book/event", "POST");
const res2 = checkPostMethod(req2);
expect(res2).toBeNull();
});

it("should allow POST requests to allowed app routes", async () => {
POST_METHODS_ALLOWED_APP_ROUTES.forEach(async (route) => {
const req = createRequest(route, "POST");
const res = checkPostMethod(req);
expect(res).toBeNull();
});
});

it("should block POST requests to not-allowed app routes", async () => {
const req = createRequest("/team/xyz", "POST");
const res = checkPostMethod(req);
expect(res).not.toBeNull();
expect(res?.status).toBe(405);
expect(res?.statusText).toBe("Method Not Allowed");
expect(res?.headers.get("Allow")).toBe("GET");
});

it("should allow GET requests to app routes", async () => {
const req = createRequest("/team/xyz", "GET");
const res = checkPostMethod(req);
expect(res).toBeNull();
});

it("should allow GET requests to /api routes", async () => {
const req = createRequest("/api/auth/signup", "GET");
const res = checkPostMethod(req);
expect(res).toBeNull();
});
});
32 changes: 28 additions & 4 deletions apps/web/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import { NextResponse } from "next/server";
import { getLocale } from "@calcom/features/auth/lib/getLocale";
import { extendEventData, nextCollectBasicSettings } from "@calcom/lib/telemetry";

import { csp } from "@lib/csp";

import { abTestMiddlewareFactory } from "./abTest/middlewareFactory";
import { csp } from "./lib/csp";

const safeGet = async <T = any>(key: string): Promise<T | undefined> => {
try {
Expand All @@ -18,7 +16,33 @@ const safeGet = async <T = any>(key: string): Promise<T | undefined> => {
}
};

export const POST_METHODS_ALLOWED_API_ROUTES = ["/api/auth/signup", "/api/trpc"];
// Some app routes are allowed because "revalidatePath()" is used to revalidate the cache for them
export const POST_METHODS_ALLOWED_APP_ROUTES = ["/settings/my-account/general"];

export function checkPostMethod(req: NextRequest) {
const pathname = req.nextUrl.pathname;
if (
![...POST_METHODS_ALLOWED_API_ROUTES, ...POST_METHODS_ALLOWED_APP_ROUTES].some((route) =>
pathname.startsWith(route)
) &&
req.method === "POST"
) {
return new NextResponse(null, {
status: 405,
statusText: "Method Not Allowed",
headers: {
Allow: "GET",
},
});
}
return null;
}

const middleware = async (req: NextRequest): Promise<NextResponse<unknown>> => {
const postCheckResult = checkPostMethod(req);
if (postCheckResult) return postCheckResult;

const url = req.nextUrl;
const requestHeaders = new Headers(req.headers);
requestHeaders.set("x-url", req.url);
Expand Down Expand Up @@ -178,7 +202,7 @@ export const config = {
};

export default collectEvents({
middleware: abTestMiddlewareFactory(middleware),
middleware,
...nextCollectBasicSettings,
cookieName: "__clnds",
extend: extendEventData,
Expand Down

0 comments on commit 9421fbe

Please sign in to comment.