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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 45x 45x 45x 75x 75x 120x 67x 67x 67x 8x 8x 8x 8x 1x 1x 1x 1x 1x 1x 1x 1x 68x 68x 68x 68x 68x 3x 3x 3x 3x 3x 3x 65x 65x 65x 65x 65x 65x 68x 68x 1x 1x 1x 1x 1x 161x 161x 161x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 50x 3x 3x 3x 50x 3x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | /**
* In-memory rate limiting utility
* Tracks requests per identifier with configurable time windows
* Note: For production with multiple instances, use Redis instead
*/
interface RateLimitEntry {
count: number;
resetTime: number;
}
const rateLimitMap = new Map<string, RateLimitEntry>();
/**
* Check if an identifier has exceeded their rate limit
* @param identifier Unique identifier (user ID, IP address, email, etc.)
* @param limit Maximum requests allowed per window
* @param windowMs Time window in milliseconds
* @returns true if request is allowed, false if rate limit exceeded
*/
export function checkRateLimit(
identifier: string,
limit: number = 100,
windowMs: number = 15 * 60 * 1000 // 15 minutes default
): boolean {
const now = Date.now();
const userLimit = rateLimitMap.get(identifier);
// No existing entry or window has expired
if (!userLimit || now > userLimit.resetTime) {
rateLimitMap.set(identifier, { count: 1, resetTime: now + windowMs });
return true;
}
// Check if under limit
if (userLimit.count < limit) {
userLimit.count++;
return true;
}
// Over limit
return false;
}
/**
* Get rate limit information for an identifier
* Useful for setting response headers
* @param identifier Unique identifier
* @param limit The limit being enforced
* @returns Object with rate limit header values
*/
export function getRateLimitInfo(identifier: string, limit: number = 100) {
const now = Date.now();
const userLimit = rateLimitMap.get(identifier);
if (!userLimit || now > userLimit.resetTime) {
return {
limit,
remaining: limit,
resetTime: new Date(now + 15 * 60 * 1000).toISOString(),
retryAfter: null};
}
const remaining = Math.max(0, limit - userLimit.count);
return {
limit,
remaining,
resetTime: new Date(userLimit.resetTime).toISOString(),
retryAfter: remaining === 0 ? Math.ceil((userLimit.resetTime - now) / 1000) : null};
}
/**
* Clear rate limit entry (useful for testing)
* @param identifier Unique identifier to clear
*/
export function clearRateLimit(identifier: string): void {
rateLimitMap.delete(identifier);
}
/**
* Clean up expired entries (run periodically in production)
* This prevents memory leaks from accumulating old entries
*/
export function cleanupExpiredEntries(): number {
const now = Date.now();
let removed = 0;
for (const [identifier, entry] of rateLimitMap.entries()) {
if (now > entry.resetTime) {
rateLimitMap.delete(identifier);
removed++;
}
}
return removed;
}
/**
* Common rate limit presets
*/
export const rateLimitPresets = {
// Strict: 5 requests per hour (for sensitive operations like signup)
signup: { limit: 5, windowMs: 60 * 60 * 1000 },
// Moderate: 30 requests per hour (for moderate operations)
moderate: { limit: 30, windowMs: 60 * 60 * 1000 },
// Standard: 100 requests per 15 minutes (for general API)
standard: { limit: 100, windowMs: 15 * 60 * 1000 },
// Generous: 1000 requests per hour (for public endpoints)
generous: { limit: 1000, windowMs: 60 * 60 * 1000 },
// Error reporting: 20 errors per minute per IP (prevents flooding)
errorReporting: { limit: 20, windowMs: 60 * 1000 },
// Error resolve: 50 operations per minute (for admin bulk operations)
errorResolve: { limit: 50, windowMs: 60 * 1000 },
// Data export: 10 exports per minute
dataExport: { limit: 10, windowMs: 60 * 1000 },
};
|