website poc

This commit is contained in:
2025-12-02 01:31:31 +01:00
parent 747a77cb39
commit fd3b4171aa
15 changed files with 939 additions and 115 deletions

View File

@@ -1,35 +1,61 @@
import { kv } from '@vercel/kv';
/**
* Rate limit configuration
*/
const RATE_LIMIT_WINDOW = 60 * 60 * 1000; // 1 hour in milliseconds
const MAX_REQUESTS_PER_WINDOW = 5;
/**
* Rate limit key prefix
*/
const RATE_LIMIT_PREFIX = 'ratelimit:signup:';
/**
* Check if an IP address has exceeded rate limits
* @param identifier - IP address or unique identifier
* @returns Object with allowed status and retry information
*/
const isDev = !process.env.KV_REST_API_URL;
// In-memory fallback for development
const devRateLimits = new Map<string, { count: number; resetAt: number }>();
export async function checkRateLimit(identifier: string): Promise<{
allowed: boolean;
remaining: number;
resetAt: number;
}> {
const key = `${RATE_LIMIT_PREFIX}${identifier}`;
const now = Date.now();
if (isDev) {
console.warn('[DEV MODE] Using in-memory rate limiting - data will not persist');
const existing = devRateLimits.get(identifier);
if (existing && existing.resetAt > now) {
if (existing.count >= MAX_REQUESTS_PER_WINDOW) {
return {
allowed: false,
remaining: 0,
resetAt: existing.resetAt,
};
}
existing.count += 1;
devRateLimits.set(identifier, existing);
return {
allowed: true,
remaining: MAX_REQUESTS_PER_WINDOW - existing.count,
resetAt: existing.resetAt,
};
}
const resetAt = now + RATE_LIMIT_WINDOW;
devRateLimits.set(identifier, { count: 1, resetAt });
return {
allowed: true,
remaining: MAX_REQUESTS_PER_WINDOW - 1,
resetAt,
};
}
// Production: Use Vercel KV
const { kv } = await import('@vercel/kv');
const key = `${RATE_LIMIT_PREFIX}${identifier}`;
try {
// Get current count
const count = await kv.get<number>(key) || 0;
if (count >= MAX_REQUESTS_PER_WINDOW) {
// Get TTL to determine reset time
const ttl = await kv.ttl(key);
const resetAt = now + (ttl * 1000);
@@ -40,20 +66,16 @@ export async function checkRateLimit(identifier: string): Promise<{
};
}
// Increment counter
const newCount = count + 1;
if (count === 0) {
// First request - set with expiry
await kv.set(key, newCount, {
px: RATE_LIMIT_WINDOW,
});
} else {
// Subsequent request - increment without changing TTL
await kv.incr(key);
}
// Calculate reset time
const ttl = await kv.ttl(key);
const resetAt = now + (ttl * 1000);
@@ -63,7 +85,6 @@ export async function checkRateLimit(identifier: string): Promise<{
resetAt,
};
} catch (error) {
// If rate limiting fails, allow the request
console.error('Rate limit check failed:', error);
return {
allowed: true,