From 7951a8733242d35327aded88583a14c97d819dfa Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Thu, 18 Dec 2025 12:09:34 +0100 Subject: [PATCH] refactor: don't apply strict rate limit on /me and /status endpoints --- app/server/index.ts | 7 ++- app/server/modules/auth/auth.controller.ts | 65 ++++++++++++---------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/app/server/index.ts b/app/server/index.ts index a390a9c6..20139a11 100644 --- a/app/server/index.ts +++ b/app/server/index.ts @@ -46,9 +46,12 @@ const app = new Hono() .use(secureHeaders()) .use( rateLimiter({ - windowMs: 15 * 60 * 1000, - limit: 100, + windowMs: 60 * 5 * 1000, + limit: 1000, keyGenerator: (c) => c.req.header("x-forwarded-for") ?? "", + skip: () => { + return config.__prod__ === false; + }, }), ) .get("healthcheck", (c) => c.json({ status: "ok" })) diff --git a/app/server/modules/auth/auth.controller.ts b/app/server/modules/auth/auth.controller.ts index e2aaecea..45ba5518 100644 --- a/app/server/modules/auth/auth.controller.ts +++ b/app/server/modules/auth/auth.controller.ts @@ -21,6 +21,7 @@ import { } from "./auth.dto"; import { authService } from "./auth.service"; import { toMessage } from "../../utils/errors"; +import { config } from "~/server/core/config"; const COOKIE_NAME = "session_id"; const COOKIE_OPTIONS = { @@ -30,15 +31,17 @@ const COOKIE_OPTIONS = { path: "/", }; +const authRateLimiter = rateLimiter({ + windowMs: 15 * 60 * 1000, + limit: 20, + keyGenerator: (c) => c.req.header("x-forwarded-for") ?? "", + skip: () => { + return config.__prod__ === false; + }, +}); + export const authController = new Hono() - .use( - rateLimiter({ - windowMs: 15 * 60 * 1000, - limit: 5, - keyGenerator: (c) => c.req.header("x-forwarded-for") ?? "", - }), - ) - .post("/register", registerDto, validator("json", registerBodySchema), async (c) => { + .post("/register", authRateLimiter, registerDto, validator("json", registerBodySchema), async (c) => { const body = c.req.valid("json"); try { @@ -65,7 +68,7 @@ export const authController = new Hono() return c.json({ success: false, message: toMessage(error) }, 400); } }) - .post("/login", loginDto, validator("json", loginBodySchema), async (c) => { + .post("/login", authRateLimiter, loginDto, validator("json", loginBodySchema), async (c) => { const body = c.req.valid("json"); try { @@ -89,7 +92,7 @@ export const authController = new Hono() return c.json({ success: false, message: toMessage(error) }, 401); } }) - .post("/logout", logoutDto, async (c) => { + .post("/logout", authRateLimiter, logoutDto, async (c) => { const sessionId = getCookie(c, COOKIE_NAME); if (sessionId) { @@ -123,26 +126,32 @@ export const authController = new Hono() const hasUsers = await authService.hasUsers(); return c.json({ hasUsers }); }) - .post("/change-password", changePasswordDto, validator("json", changePasswordBodySchema), async (c) => { - const sessionId = getCookie(c, COOKIE_NAME); + .post( + "/change-password", + authRateLimiter, + changePasswordDto, + validator("json", changePasswordBodySchema), + async (c) => { + const sessionId = getCookie(c, COOKIE_NAME); - if (!sessionId) { - return c.json({ success: false, message: "Not authenticated" }, 401); - } + if (!sessionId) { + return c.json({ success: false, message: "Not authenticated" }, 401); + } - const session = await authService.verifySession(sessionId); + const session = await authService.verifySession(sessionId); - if (!session) { - deleteCookie(c, COOKIE_NAME, COOKIE_OPTIONS); - return c.json({ success: false, message: "Not authenticated" }, 401); - } + if (!session) { + deleteCookie(c, COOKIE_NAME, COOKIE_OPTIONS); + return c.json({ success: false, message: "Not authenticated" }, 401); + } - const body = c.req.valid("json"); + const body = c.req.valid("json"); - try { - await authService.changePassword(session.user.id, body.currentPassword, body.newPassword); - return c.json({ success: true, message: "Password changed successfully" }); - } catch (error) { - return c.json({ success: false, message: toMessage(error) }, 400); - } - }); + try { + await authService.changePassword(session.user.id, body.currentPassword, body.newPassword); + return c.json({ success: true, message: "Password changed successfully" }); + } catch (error) { + return c.json({ success: false, message: toMessage(error) }, 400); + } + }, + );