svelte-guardian
Version:
Batteries included authentication for SvelteKit applications.
56 lines (55 loc) • 2.09 kB
JavaScript
export class InMemoryRateLimiter {
requestLog = new Map();
blockedUntil = new Map();
limit(event, config) {
const now = Date.now();
// Default key generation
const key = this.defaultKeyGenerator(event);
// Check if currently blocked
const blockExpiration = this.blockedUntil.get(key) || 0;
if (blockExpiration > now) {
return {
allowed: false,
remaining: 0,
resetTime: blockExpiration,
blockedUntil: blockExpiration
};
}
// Retrieve or initialize request log
const currentLog = this.requestLog.get(key) || [];
// Remove expired requests
const filteredLog = currentLog.filter((record) => now - record.timestamp < (config.windowMs || 60000));
// Default block duration to 5 minutes if not specified
const blockDuration = config.blockDuration || 5 * 60 * 1000;
// Check rate limit
if (filteredLog.length >= (config.maxRequests || 10)) {
// Block the key
const blockUntil = now + blockDuration;
this.blockedUntil.set(key, blockUntil);
return {
allowed: false,
remaining: 0,
resetTime: filteredLog[0].timestamp + config.windowMs,
blockedUntil: blockUntil
};
}
// Add current request
filteredLog.push({ timestamp: now, requestCount: 1 });
this.requestLog.set(key, filteredLog);
return {
allowed: true,
remaining: (config.maxRequests || 10) - filteredLog.length,
resetTime: now + (config.windowMs || 60000)
};
}
defaultKeyGenerator(event) {
// Prioritize user ID if available
const session = event.locals.auth?.() || event.locals.session;
if (session?.user?.id) {
return `user:${session.user.id}`;
}
// Fallback to IP address
const ip = event.getClientAddress();
return `ip:${ip}`;
}
}