import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { Request, Response } from 'express'; import { rateLimit } from 'express-rate-limit'; @Injectable() export class IpRateLimiterGuard implements CanActivate { private readonly limiter: ReturnType; constructor(private readonly configService: ConfigService) { const isProduction = this.configService.get('NODE_ENV') === 'production'; this.limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: isProduction ? 50 : 100, // Stricter in production standardHeaders: false, legacyHeaders: false, skip: () => !isProduction && this.configService.get('DISABLE_RATE_LIMIT') === 'true', // Skip in dev if needed keyGenerator: (req) => { // Use IP or user ID if available return isProduction ? req.ip : ''; // Less strict in development }, handler: (req, res) => { res.status(429).json({ statusCode: 429, message: isProduction ? 'Too many requests' : 'Dev Mode: Rate limit warning (not enforced)', }); }, }); } async canActivate(context: ExecutionContext): Promise { const httpContext = context.switchToHttp(); const req = httpContext.getRequest(); const res = httpContext.getResponse(); return new Promise((resolve) => { this.limiter(req, res, (err?: unknown) => { if (err) { return resolve(false); } resolve(true); }); }); } }