Files
omnivore/packages/api/src/utils/rate_limit.ts
2024-08-29 18:18:17 +08:00

78 lines
2.2 KiB
TypeScript

import rateLimit, { MemoryStore, Options } from 'express-rate-limit'
import { RedisStore } from 'rate-limit-redis'
import { env } from '../env'
import { redisDataSource } from '../redis_data_source'
import { getClaimsByToken, getTokenByRequest, isSystemRequest } from './auth'
// use the redis store if we have a redis connection
const redisClient = redisDataSource.redisClient
const getStore = (prefix?: string) =>
redisClient
? new RedisStore({
sendCommand: (command: string, ...args: string[]) =>
redisClient.call(command, ...args) as never,
prefix,
})
: new MemoryStore()
const configs: Partial<Options> = {
windowMs: 60 * 1000, // 1 minute
max: 5,
// skip preflight requests and test requests and system requests
skip: (req) =>
req.method === 'OPTIONS' || env.dev.isLocal || isSystemRequest(req),
store: getStore('rate-limit'),
}
export const apiLimiter = rateLimit({
...configs,
max: async (req) => {
// 60 RPM for authenticated request, 15 for non-authenticated request
const token = getTokenByRequest(req)
try {
const claims = await getClaimsByToken(token)
return claims ? 60 : 15
} catch (e) {
return 15
}
},
keyGenerator: (req) => {
return getTokenByRequest(req) || req.ip
},
store: getStore('api-rate-limit'),
})
export const apiHourLimiter = rateLimit({
...configs,
windowMs: 60 * 60 * 1000, // 1 hour
max: async (req) => {
// 600 for authenticated request, 150 for non-authenticated request
const token = getTokenByRequest(req)
try {
const claims = await getClaimsByToken(token)
return claims ? 600 : 150
} catch (e) {
return 150
}
},
keyGenerator: (req) => {
return getTokenByRequest(req) || req.ip
},
store: getStore('api-hour-rate-limit'),
})
// 5 RPM for auth requests
export const authLimiter = rateLimit({
...configs,
store: getStore('auth-rate-limit'),
})
// The hourly limiter is used on the create account,
// and reset password endpoints
// this limits users to five operations per an hour
export const hourlyLimiter = rateLimit({
...configs,
windowMs: 60 * 60 * 1000,
store: getStore('hourly-rate-limit'),
})