52 lines
1.9 KiB
TypeScript
52 lines
1.9 KiB
TypeScript
export const MAX_IN_FLIGHT_INSPECTIONS = 4;
|
|
export const RATE_LIMIT_WINDOW_MS = 60_000;
|
|
export const RATE_LIMIT_MAX_REQUESTS = 30;
|
|
const MAX_TRACKED_CLIENTS = 1_024;
|
|
|
|
let inFlight = 0;
|
|
const requestWindows = new Map<string, number[]>();
|
|
|
|
export function tryAcquireInspection() {
|
|
if (inFlight >= MAX_IN_FLIGHT_INSPECTIONS) return null;
|
|
|
|
inFlight += 1;
|
|
let released = false;
|
|
|
|
return () => {
|
|
if (released) return;
|
|
released = true;
|
|
inFlight = Math.max(0, inFlight - 1);
|
|
};
|
|
}
|
|
|
|
export function clientKeyFromHeaders(headers: { get(name: string): string | null }) {
|
|
if (process.env.CERTSCOPE_TRUST_PROXY !== "true") return "direct";
|
|
const forwarded = headers.get("x-forwarded-for") ?? headers.get("x-real-ip") ?? "unknown";
|
|
const client = forwarded.split(",", 1)[0]?.trim().slice(0, 128) || "unknown";
|
|
return "proxy:" + client;
|
|
}
|
|
|
|
export function checkRateLimit(key: string, now = Date.now()) {
|
|
const windowStart = now - RATE_LIMIT_WINDOW_MS;
|
|
const previous = requestWindows.get(key) ?? [];
|
|
const recent = previous.filter((timestamp) => timestamp > windowStart);
|
|
if (recent.length >= RATE_LIMIT_MAX_REQUESTS) {
|
|
const retryAfterMs = Math.max(1_000, (recent[0] ?? now) + RATE_LIMIT_WINDOW_MS - now);
|
|
requestWindows.set(key, recent);
|
|
return { allowed: false, retryAfterSeconds: Math.ceil(retryAfterMs / 1_000) };
|
|
}
|
|
recent.push(now);
|
|
requestWindows.set(key, recent);
|
|
if (requestWindows.size > MAX_TRACKED_CLIENTS) {
|
|
for (const [client, timestamps] of requestWindows) {
|
|
if (!timestamps.some((timestamp) => timestamp > windowStart)) requestWindows.delete(client);
|
|
if (requestWindows.size <= MAX_TRACKED_CLIENTS) break;
|
|
}
|
|
if (requestWindows.size > MAX_TRACKED_CLIENTS) {
|
|
const oldestClient = requestWindows.keys().next().value;
|
|
if (typeof oldestClient === "string" && oldestClient !== key) requestWindows.delete(oldestClient);
|
|
}
|
|
}
|
|
return { allowed: true, retryAfterSeconds: 0 };
|
|
}
|