refactor: audit improvements - rate limit ceiling, map route protection, lazy DevToolbar, lang=de

- lib/rate-limit.ts: add MAX_STORE_ENTRIES=10k ceiling + evictIfFull() to prevent DDoS memory exhaustion
- app/api/map/route.ts: add IP-based rate limiting (30 req/min) with proper Retry-After headers
- app/layout.tsx: lang='en' → 'de', DevToolbar loaded via dynamic import (reduces main bundle)
- app/layout.tsx: lazy DevToolbar keeps ~17KB out of production bundle via next/dynamic
This commit is contained in:
ralksta
2026-03-13 11:41:56 +01:00
parent 3b657b625c
commit d64a7239d1
3 changed files with 42 additions and 3 deletions

View File

@@ -16,6 +16,9 @@ interface RateLimitEntry {
const store = new Map<string, RateLimitEntry>();
// Hard ceiling to prevent unbounded memory growth under DDoS conditions
const MAX_STORE_ENTRIES = 10_000;
// Evict expired entries periodically (every 60s)
let lastCleanup = Date.now();
const CLEANUP_INTERVAL = 60_000;
@@ -29,6 +32,15 @@ function cleanup() {
}
}
/**
* Evict oldest entry when store is at capacity (FIFO).
*/
function evictIfFull() {
if (store.size < MAX_STORE_ENTRIES) return;
const firstKey = store.keys().next().value;
if (firstKey) store.delete(firstKey);
}
/**
* Check if a request should be allowed.
* @param ip - Client IP address
@@ -49,6 +61,7 @@ export function checkRateLimit(
// New window or expired
if (!entry || now > entry.expiresAt) {
evictIfFull();
const resetAt = now + windowMs;
store.set(key, { count: 1, expiresAt: resetAt });
return { success: true, remaining: maxRpm - 1, resetAt };