diff --git a/apps/remix/package.json b/apps/remix/package.json index 8cf9aa941..896826523 100644 --- a/apps/remix/package.json +++ b/apps/remix/package.json @@ -41,6 +41,7 @@ "colord": "^2.9.3", "framer-motion": "^10.12.8", "hono": "4.7.0", + "hono-rate-limiter": "^0.4.2", "hono-react-router-adapter": "^0.6.2", "input-otp": "^1.2.4", "isbot": "^5.1.17", diff --git a/apps/remix/server/router.ts b/apps/remix/server/router.ts index dfd9927b5..7d165d01f 100644 --- a/apps/remix/server/router.ts +++ b/apps/remix/server/router.ts @@ -1,4 +1,5 @@ import { Hono } from 'hono'; +import { rateLimiter } from 'hono-rate-limiter'; import { contextStorage } from 'hono/context-storage'; import { tsRestHonoApp } from '@documenso/api/hono'; @@ -21,6 +22,21 @@ export interface HonoEnv { const app = new Hono(); +/** + * Rate limiting for v1 and v2 API routes only. + * - 100 requests per minute per IP address + */ +const rateLimitMiddleware = rateLimiter({ + windowMs: 60 * 1000, // 1 minute + limit: 100, // 100 requests per window + keyGenerator: (c) => { + return c.req.header('x-forwarded-for') || c.req.header('x-real-ip') || 'unknown'; + }, + message: { + error: 'Too many requests, please try again later.', + }, +}); + /** * Attach session and context to requests. */ @@ -32,6 +48,10 @@ app.use(appContext); */ app.use('*', appMiddleware); +// Apply rate limit to /api/v1/* +app.use('/api/v1/*', rateLimitMiddleware); +app.use('/api/v2/*', rateLimitMiddleware); + // Auth server. app.route('/api/auth', auth); diff --git a/package-lock.json b/package-lock.json index 370f360b5..ce12af2b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -118,6 +118,7 @@ "colord": "^2.9.3", "framer-motion": "^10.12.8", "hono": "4.7.0", + "hono-rate-limiter": "^0.4.2", "hono-react-router-adapter": "^0.6.2", "input-otp": "^1.2.4", "isbot": "^5.1.17", @@ -20241,6 +20242,15 @@ "node": ">=16.9.0" } }, + "node_modules/hono-rate-limiter": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/hono-rate-limiter/-/hono-rate-limiter-0.4.2.tgz", + "integrity": "sha512-AAtFqgADyrmbDijcRTT/HJfwqfvhalya2Zo+MgfdrMPas3zSMD8SU03cv+ZsYwRU1swv7zgVt0shwN059yzhjw==", + "license": "MIT", + "peerDependencies": { + "hono": "^4.1.1" + } + }, "node_modules/hono-react-router-adapter": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/hono-react-router-adapter/-/hono-react-router-adapter-0.6.5.tgz",