All files / src/middleware rateLimit.js

100% Statements 14/14
100% Branches 2/2
100% Functions 6/6
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64              17x 17x     276x         17x             414x   1x         17x               1x           17x             49x   6x         6x       17x  
/**
 * Rate limiting middleware — per-user (uid) limits for API abuse prevention.
 *
 * Uses in-memory store (no external deps, fits Oracle free tier's 1GB RAM).
 * Three tiers: general API, write-heavy routes, and sensitive operations.
 */
 
const { rateLimit } = require('express-rate-limit');
const log = require('../utils/log');
 
// Key by authenticated user ID (falls back to IP for unauthenticated requests)
const keyGenerator = (req) => req.auth?.uid || req.ip;
 
// General API rate limit: 200 requests per minute per user
// Admin users are exempt — the admin panel legitimately makes many parallel
// API calls (logs, alerts, economy, search) across multiple tabs.
const generalLimiter = rateLimit({
  windowMs: 60 * 1000,
  limit: 200,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  keyGenerator,
  validate: false,
  skip: (req) => req.auth?.token?.admin === true,
  handler: (req, res) => {
    res.status(429).json({ error: 'Too many requests, please try again later' });
  },
});
 
// Write-heavy routes (messages, gifts, gacha): 30 per minute per user
const writeLimiter = rateLimit({
  windowMs: 60 * 1000,
  limit: 30,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  keyGenerator,
  validate: false,
  handler: (req, res) => {
    res.status(429).json({ error: 'Too many requests, slow down' });
  },
});
 
// Sensitive operations (appeals, reports, purchases): 5 per minute per user
// Admin users are exempt — admin panel tests legitimately create reports/appeals.
const sensitiveLimiter = rateLimit({
  windowMs: 60 * 1000,
  limit: 5,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  keyGenerator,
  validate: false,
  skip: (req) => req.auth?.token?.admin === true,
  handler: (req, res) => {
    log.warn('rateLimit', 'Sensitive rate limit hit', {
      uid: req.auth?.uid,
      ip: req.ip,
      path: req.originalUrl,
    });
    res.status(429).json({ error: 'Rate limit exceeded for this operation' });
  },
});
 
module.exports = { generalLimiter, writeLimiter, sensitiveLimiter };