From 83be0ccef20a575f0b7bbbcefeac44f1c937f1e2 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:18:54 +0330 Subject: [PATCH] Import source: vault/lib/server-rate-limit Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- vault/lib/server-rate-limit.ts | 37 ++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 vault/lib/server-rate-limit.ts diff --git a/vault/lib/server-rate-limit.ts b/vault/lib/server-rate-limit.ts new file mode 100644 index 0000000..b3f61c0 --- /dev/null +++ b/vault/lib/server-rate-limit.ts @@ -0,0 +1,37 @@ +import "server-only"; + +import { getRedis } from "@/lib/server-redis"; + +interface Bucket { + count: number; + resetAt: number; +} + +const buckets = new Map(); + +function clientIp(request: Request): string { + const forwardedFor = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim(); + return forwardedFor || request.headers.get("x-real-ip") || "local"; +} + +export async function isRateLimited(request: Request, scope: string, limit: number, windowMs: number): Promise { + const redis = await getRedis(); + const key = `cvault:rate:${scope}:${clientIp(request)}`; + + if (redis) { + const count = await redis.incr(key); + if (count === 1) await redis.pExpire(key, windowMs); + return count > limit; + } + + const now = Date.now(); + const bucket = buckets.get(key); + + if (!bucket || bucket.resetAt <= now) { + buckets.set(key, { count: 1, resetAt: now + windowMs }); + return false; + } + + bucket.count += 1; + return bucket.count > limit; +}