All files / server rate-limit-policy.ts

100% Statements 7/7
87.5% Branches 7/8
100% Functions 2/2
100% Lines 6/6

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        2x                           5x                   11x 8x 8x   6x    
import type { IncomingMessage } from "node:http";
import { ipKeyGenerator } from "express-rate-limit";
import { getRequestAuthorization, type TrustConfig } from "./security/access-control";
 
const RATE_LIMIT_EXEMPT_API_PATHS = new Set([
  "/api/status",
  "/api/health",
  "/api/config",
]);
 
/**
 * Returns whether the global API rate limiter should ignore a request.
 * Keep this decision independent from Express so it can be tested directly.
 */
export function shouldSkipApiRateLimit(
  originalUrl: string,
  isTestMode: boolean,
): boolean {
  return isTestMode || RATE_LIMIT_EXEMPT_API_PATHS.has(originalUrl);
}
 
/**
 * Key of the global API rate limit. Behind the gateway, a whole course often
 * shares one public IP (campus NAT), so an authenticated subject gets its own
 * budget. Requests without a valid gateway identity, and local mode, where a
 * client can always obtain a fresh session, stay on the client IP.
 */
export function apiRateLimitKey(req: IncomingMessage & { ip?: string }, trust: TrustConfig): string {
  if (trust.mode === "gateway") {
    const authorization = getRequestAuthorization(req, trust);
    if (authorization.allowed) return `subject:${authorization.identity.subject}`;
  }
  return `ip:${ipKeyGenerator(req.ip ?? "")}`;
}