/** * Middleware de rate limiting renforcé * Protège contre les abus et les attaques par force brute */ const rateLimit = require('express-rate-limit'); const { logger } = require('../config/logs'); /** * Rate limiter général pour toutes les requêtes */ const generalLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 1000, // Limite de 1000 requêtes par fenêtre message: { error: 'Trop de requêtes depuis cette adresse IP, veuillez réessayer plus tard.', retryAfter: '15 minutes' }, standardHeaders: true, legacyHeaders: false, skip: (req) => { // Skip pour localhost return req.ip === '127.0.0.1' || req.ip === '::1' || req.ip === '::ffff:127.0.0.1'; }, handler: (req, res) => { logger.warn(`Rate limit exceeded for ${req.ip} on ${req.path}`); res.status(429).json({ error: 'Trop de requêtes', message: 'Vous avez dépassé la limite de requêtes autorisées. Veuillez réessayer dans 15 minutes.', retryAfter: 900 }); } }); /** * Rate limiter strict pour les endpoints sensibles (authentification) */ const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 5, // Seulement 5 tentatives de connexion skipSuccessfulRequests: true, // Ne pas compter les tentatives réussies message: { error: 'Trop de tentatives de connexion, votre compte est temporairement verrouillé.', retryAfter: '15 minutes' }, standardHeaders: true, legacyHeaders: false, skip: (req) => { return req.ip === '127.0.0.1' || req.ip === '::1' || req.ip === '::ffff:127.0.0.1'; }, handler: (req, res) => { logger.warn(`Auth rate limit exceeded for ${req.ip} on ${req.path}`); res.status(429).json({ error: 'Compte temporairement verrouillé', message: 'Trop de tentatives de connexion. Veuillez réessayer dans 15 minutes.', retryAfter: 900 }); } }); /** * Rate limiter pour les uploads */ const uploadLimiter = rateLimit({ windowMs: 60 * 60 * 1000, // 1 heure max: 100, // 100 uploads par heure message: { error: 'Limite d\'upload atteinte', retryAfter: '1 heure' }, standardHeaders: true, legacyHeaders: false, skip: (req) => { return req.ip === '127.0.0.1' || req.ip === '::1' || req.ip === '::ffff:127.0.0.1'; }, handler: (req, res) => { logger.warn(`Upload rate limit exceeded for ${req.ip}`); res.status(429).json({ error: 'Limite d\'upload dépassée', message: 'Vous avez atteint la limite d\'uploads autorisés. Veuillez réessayer dans 1 heure.', retryAfter: 3600 }); } }); /** * Rate limiter pour les API */ const apiLimiter = rateLimit({ windowMs: 1 * 60 * 1000, // 1 minute max: 60, // 60 requêtes par minute message: { error: 'Limite d\'API atteinte', retryAfter: '1 minute' }, standardHeaders: true, legacyHeaders: false, skip: (req) => { return req.ip === '127.0.0.1' || req.ip === '::1' || req.ip === '::ffff:127.0.0.1'; }, handler: (req, res) => { logger.warn(`API rate limit exceeded for ${req.ip} on ${req.path}`); res.status(429).json({ error: 'Limite d\'API dépassée', message: 'Vous avez dépassé la limite de requêtes API autorisées. Veuillez réessayer dans 1 minute.', retryAfter: 60 }); } }); /** * Rate limiter pour la création de dossiers/fichiers */ const createLimiter = rateLimit({ windowMs: 10 * 60 * 1000, // 10 minutes max: 50, // 50 créations par 10 minutes message: { error: 'Limite de création atteinte', retryAfter: '10 minutes' }, standardHeaders: true, legacyHeaders: false, skip: (req) => { return req.ip === '127.0.0.1' || req.ip === '::1' || req.ip === '::ffff:127.0.0.1'; }, handler: (req, res) => { logger.warn(`Create rate limit exceeded for ${req.ip} on ${req.path}`); res.status(429).json({ error: 'Limite de création dépassée', message: 'Vous avez dépassé la limite de créations autorisées. Veuillez réessayer dans 10 minutes.', retryAfter: 600 }); } }); /** * Rate limiter pour les suppressions */ const deleteLimiter = rateLimit({ windowMs: 5 * 60 * 1000, // 5 minutes max: 30, // 30 suppressions par 5 minutes message: { error: 'Limite de suppression atteinte', retryAfter: '5 minutes' }, standardHeaders: true, legacyHeaders: false, skip: (req) => { return req.ip === '127.0.0.1' || req.ip === '::1' || req.ip === '::ffff:127.0.0.1'; }, handler: (req, res) => { logger.warn(`Delete rate limit exceeded for ${req.ip} on ${req.path}`); res.status(429).json({ error: 'Limite de suppression dépassée', message: 'Vous avez dépassé la limite de suppressions autorisées. Veuillez réessayer dans 5 minutes.', retryAfter: 300 }); } }); /** * Rate limiter strict pour la recherche d'utilisateurs (prévient l'énumération) */ const userSearchLimiter = rateLimit({ windowMs: 1 * 60 * 1000, // 1 minute max: 10, // 10 recherches par minute message: { error: 'Limite de recherche atteinte', retryAfter: '1 minute' }, standardHeaders: true, legacyHeaders: false, skip: (req) => { return req.ip === '127.0.0.1' || req.ip === '::1' || req.ip === '::ffff:127.0.0.1'; }, handler: (req, res) => { logger.warn(`User search rate limit exceeded for ${req.ip}`); res.status(429).json({ error: 'Limite de recherche dépassée', message: 'Vous avez dépassé la limite de recherches autorisées. Veuillez réessayer dans 1 minute.', retryAfter: 60 }); } }); module.exports = { generalLimiter, authLimiter, uploadLimiter, apiLimiter, createLimiter, deleteLimiter, userSearchLimiter };