forked from Dshield-xyz/Dshield
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrateLimit.ts
More file actions
42 lines (36 loc) · 1.31 KB
/
Copy pathrateLimit.ts
File metadata and controls
42 lines (36 loc) · 1.31 KB
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
// Best-effort, in-memory, per-process rate limiter for server API routes.
// Not distributed-safe (each server instance/process has its own counters,
// and it resets on redeploy) — for a hackathon/testnet deployment this still
// meaningfully raises the cost of spamming the faucet or the relayer's RPC
// quota, which is the actual goal here.
const buckets = new Map<string, { count: number; resetAt: number }>();
export interface RateLimitResult {
allowed: boolean;
retryAfterSeconds: number;
}
export function checkRateLimit(
key: string,
limit: number,
windowMs: number,
): RateLimitResult {
const now = Date.now();
const bucket = buckets.get(key);
if (!bucket || bucket.resetAt <= now) {
buckets.set(key, { count: 1, resetAt: now + windowMs });
return { allowed: true, retryAfterSeconds: 0 };
}
if (bucket.count >= limit) {
return {
allowed: false,
retryAfterSeconds: Math.max(1, Math.ceil((bucket.resetAt - now) / 1000)),
};
}
bucket.count++;
return { allowed: true, retryAfterSeconds: 0 };
}
/** Best-effort client identifier from standard proxy headers. */
export function clientKey(headers: Headers): string {
const forwarded = headers.get("x-forwarded-for");
if (forwarded) return forwarded.split(",")[0].trim();
return headers.get("x-real-ip") || "unknown";
}