From 4a6a872d526f5ff78667d352d3edd8a0fe2daf67 Mon Sep 17 00:00:00 2001 From: WA11AX Date: Wed, 13 Aug 2025 21:19:11 +0300 Subject: [PATCH] refactor: use configurable rate limiter --- .env.example | 1 + server/README.md | 1 + server/rateLimiter.simple.ts | 27 ------------------- server/rateLimiter.ts | 52 +++--------------------------------- server/routes.ts | 2 +- 5 files changed, 6 insertions(+), 77 deletions(-) delete mode 100644 server/rateLimiter.simple.ts diff --git a/.env.example b/.env.example index 46a01fd..b47faf7 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,7 @@ TELEGRAM_WEBHOOK_URL=https://yourdomain.com/api/telegram/webhook # Development Settings (Optional) SKIP_TELEGRAM_VALIDATION=false +# Set to true to disable all rate limiting (use with caution) SKIP_RATE_LIMITING=false # Frontend Configuration (VITE_ prefix required for client access) diff --git a/server/README.md b/server/README.md index e2d8aed..e132fbc 100644 --- a/server/README.md +++ b/server/README.md @@ -112,6 +112,7 @@ const newUser = await db.insert(users).values(validatedUserData); - `DATABASE_URL`: PostgreSQL connection string - `SESSION_SECRET`: Session encryption secret - `PORT`: Server port (default: 3000) +- `SKIP_RATE_LIMITING`: Disable all rate limiting when set to `true` (defaults to enabled in development) ### Middleware Stack diff --git a/server/rateLimiter.simple.ts b/server/rateLimiter.simple.ts deleted file mode 100644 index bde108c..0000000 --- a/server/rateLimiter.simple.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Request, Response, NextFunction } from 'express'; -import { isDevelopment } from './config'; - -// Simple rate limiter that just passes through in development -export const generalLimiter = (req: Request, res: Response, next: NextFunction) => { - if (isDevelopment) { - return next(); - } - // In production, you could implement proper rate limiting here - next(); -}; - -export const authLimiter = generalLimiter; -export const tournamentCreationLimiter = generalLimiter; -export const tournamentRegistrationLimiter = generalLimiter; -export const adminLimiter = generalLimiter; -export const websocketLimiter = generalLimiter; -export const uploadLimiter = generalLimiter; - -export function createCustomLimiter() { - return generalLimiter; -} - -export function createSimpleRateLimit() { - // Placeholder for simple rate limiting implementation - return generalLimiter; -} diff --git a/server/rateLimiter.ts b/server/rateLimiter.ts index d80473b..550e1d1 100644 --- a/server/rateLimiter.ts +++ b/server/rateLimiter.ts @@ -48,20 +48,6 @@ export const generalLimiter = rateLimit({ }, }); -// Strict limiter for authentication attempts - 5 requests per 15 minutes -export const authLimiter = rateLimit({ - windowMs: 15 * 60 * 1000, // 15 minutes - max: 5, // Limit each IP to 5 auth attempts per windowMs - message: { - error: 'Too many authentication attempts', - message: 'Too many authentication attempts, please try again later.', - retryAfter: '15 minutes', - }, - standardHeaders: true, - legacyHeaders: false, - skipSuccessfulRequests: true, // Don't count successful requests -}); - // Tournament creation limiter - 10 requests per hour export const tournamentCreationLimiter = rateLimit({ windowMs: 60 * 60 * 1000, // 1 hour @@ -74,6 +60,7 @@ export const tournamentCreationLimiter = rateLimit({ standardHeaders: true, legacyHeaders: false, keyGenerator: (req: Request) => safeKeyGenerator(req), + skip: () => shouldSkipRateLimit(), }); // Tournament registration limiter - 20 requests per 10 minutes @@ -88,6 +75,7 @@ export const tournamentRegistrationLimiter = rateLimit({ standardHeaders: true, legacyHeaders: false, keyGenerator: (req: Request) => safeKeyGenerator(req), + skip: () => shouldSkipRateLimit(), }); // Admin operations limiter - 50 requests per 15 minutes @@ -102,19 +90,7 @@ export const adminLimiter = rateLimit({ standardHeaders: true, legacyHeaders: false, keyGenerator: (req: Request) => safeKeyGenerator(req, 'admin_'), -}); - -// WebSocket connection limiter - 10 connections per minute -export const websocketLimiter = rateLimit({ - windowMs: 60 * 1000, // 1 minute - max: 10, // Limit WebSocket connections - message: { - error: 'WebSocket connection limit exceeded', - message: 'Too many WebSocket connection attempts.', - retryAfter: '1 minute', - }, - standardHeaders: true, - legacyHeaders: false, + skip: () => shouldSkipRateLimit(), }); /** @@ -143,32 +119,10 @@ export function createCustomLimiter(options: { }); } -/** - * Rate limiter for file uploads - */ -export const uploadLimiter = createCustomLimiter({ - windowMs: 15 * 60 * 1000, // 15 minutes - max: 20, // 20 uploads per 15 minutes - message: 'Too many file uploads. Please try again later.', -}); - -/** - * Rate limiter for search operations - */ -export const searchLimiter = createCustomLimiter({ - windowMs: 60 * 1000, // 1 minute - max: 30, // 30 searches per minute - message: 'Too many search requests. Please slow down.', -}); - export default { general: generalLimiter, - auth: authLimiter, tournamentCreation: tournamentCreationLimiter, tournamentRegistration: tournamentRegistrationLimiter, admin: adminLimiter, - websocket: websocketLimiter, - upload: uploadLimiter, - search: searchLimiter, createCustom: createCustomLimiter, }; diff --git a/server/routes.ts b/server/routes.ts index 5b2083f..bf7ff1b 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -7,7 +7,7 @@ import { z } from 'zod'; import { telegramAuthMiddleware } from './auth'; import { telegramConfig, isDevelopment } from './config'; -import * as rateLimiters from './rateLimiter.simple'; +import * as rateLimiters from './rateLimiter'; import { storage } from './storage'; export async function registerRoutes(app: Express): Promise {