From 623e82ff4d9d6daf1a9c4142139493c9e91ee688 Mon Sep 17 00:00:00 2001 From: Matti Nannt Date: Mon, 28 Oct 2024 21:36:30 +0100 Subject: [PATCH] fix: Add rate limit to forgot password route Add rate limiting to the `/auth/forgot-password` route. * Import `loginLimiter` in `apps/web/app/api/v1/users/forgot-password/route.ts` and apply it to the `POST` function. * Add `forgotPasswordLimiter` in `apps/web/app/middleware/bucket.ts` with the same limits as `loginLimiter`. * Add `forgotPasswordRoute` function in `apps/web/app/middleware/endpointValidator.ts` to identify the `/auth/forgot-password` route. * Update `apps/web/middleware.ts` to include `forgotPasswordLimiter` and `forgotPasswordRoute` in the rate limiting logic. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/formbricks/formbricks?shareId=XXXX-XXXX-XXXX-XXXX). --- apps/web/app/api/v1/users/forgot-password/route.ts | 3 +++ apps/web/app/middleware/bucket.ts | 5 +++++ apps/web/app/middleware/endpointValidator.ts | 2 ++ apps/web/middleware.ts | 5 +++++ 4 files changed, 15 insertions(+) diff --git a/apps/web/app/api/v1/users/forgot-password/route.ts b/apps/web/app/api/v1/users/forgot-password/route.ts index 343ebcab88..53cf2afcbc 100644 --- a/apps/web/app/api/v1/users/forgot-password/route.ts +++ b/apps/web/app/api/v1/users/forgot-password/route.ts @@ -1,10 +1,13 @@ import { prisma } from "@formbricks/database"; import { sendForgotPasswordEmail } from "@formbricks/email"; +import { loginLimiter } from "@/app/middleware/bucket"; export const POST = async (request: Request) => { const { email } = await request.json(); try { + await loginLimiter(request.headers.get("x-forwarded-for") || request.connection.remoteAddress); + const foundUser = await prisma.user.findUnique({ where: { email: email.toLowerCase(), diff --git a/apps/web/app/middleware/bucket.ts b/apps/web/app/middleware/bucket.ts index 6f8443fcc1..8452613d0e 100644 --- a/apps/web/app/middleware/bucket.ts +++ b/apps/web/app/middleware/bucket.ts @@ -29,3 +29,8 @@ export const syncUserIdentificationLimiter = rateLimit({ interval: SYNC_USER_IDENTIFICATION_RATE_LIMIT.interval, allowedPerInterval: SYNC_USER_IDENTIFICATION_RATE_LIMIT.allowedPerInterval, }); + +export const forgotPasswordLimiter = rateLimit({ + interval: LOGIN_RATE_LIMIT.interval, + allowedPerInterval: LOGIN_RATE_LIMIT.allowedPerInterval, +}); diff --git a/apps/web/app/middleware/endpointValidator.ts b/apps/web/app/middleware/endpointValidator.ts index c5d0cd8c82..450d69bc36 100644 --- a/apps/web/app/middleware/endpointValidator.ts +++ b/apps/web/app/middleware/endpointValidator.ts @@ -28,3 +28,5 @@ export const isSyncWithUserIdentificationEndpoint = ( const match = url.match(regex); return match ? { environmentId: match[1], userId: match[2] } : false; }; + +export const forgotPasswordRoute = (url: string) => url === "/api/v1/users/forgot-password"; diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index cdb7fd0011..fcdd47f08b 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -4,6 +4,7 @@ import { shareUrlLimiter, signUpLimiter, syncUserIdentificationLimiter, + forgotPasswordLimiter, } from "@/app/middleware/bucket"; import { clientSideApiRoute, @@ -12,6 +13,7 @@ import { loginRoute, shareUrlRoute, signupRoute, + forgotPasswordRoute, } from "@/app/middleware/endpointValidator"; import { getToken } from "next-auth/jwt"; import { NextResponse } from "next/server"; @@ -60,6 +62,8 @@ export const middleware = async (request: NextRequest) => { } } else if (shareUrlRoute(request.nextUrl.pathname)) { await shareUrlLimiter(`share-${ip}`); + } else if (forgotPasswordRoute(request.nextUrl.pathname)) { + await forgotPasswordLimiter(`forgot-password-${ip}`); } return NextResponse.next(); } catch (e) { @@ -83,5 +87,6 @@ export const config = { "/api/auth/signout", "/auth/login", "/api/packages/:path*", + "/api/v1/users/forgot-password", ], };