Add API rate limit (#23)

This commit is contained in:
KM Koushik
2024-05-30 20:01:20 +10:00
committed by GitHub
parent d7b8a9cca6
commit 8b61223153
6 changed files with 86 additions and 45 deletions

View File

@@ -40,6 +40,10 @@ export const env = createEnv({
GOOGLE_CLIENT_SECRET: z.string(),
SES_QUEUE_LIMIT: z.string().transform((str) => parseInt(str, 10)),
AWS_DEFAULT_REGION: z.string().default("us-east-1"),
API_RATE_LIMIT: z
.string()
.transform((str) => parseInt(str, 10))
.default(2),
},
/**
@@ -72,6 +76,7 @@ export const env = createEnv({
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
SES_QUEUE_LIMIT: process.env.SES_QUEUE_LIMIT,
AWS_DEFAULT_REGION: process.env.AWS_DEFAULT_REGION,
API_RATE_LIMIT: process.env.API_RATE_LIMIT,
},
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially

View File

@@ -1,20 +1,30 @@
import TTLCache from "@isaacs/ttlcache";
import { Context } from "hono";
import { hashToken } from "../auth";
import { db } from "../db";
import { UnsendApiError } from "./api-error";
import { env } from "~/env";
const rateLimitCache = new TTLCache({
ttl: 1000, // 1 second
max: env.API_RATE_LIMIT,
});
/**
* Gets the team from the token. Also will check if the token is valid.
*/
export const getTeamFromToken = async (c: Context) => {
const authHeader = c.req.header("Authorization");
if (!authHeader) {
throw new UnsendApiError({
code: "UNAUTHORIZED",
message: "No Authorization header provided",
});
}
const token = authHeader.split(" ")[1];
if (!token) {
throw new UnsendApiError({
code: "UNAUTHORIZED",
@@ -22,6 +32,8 @@ export const getTeamFromToken = async (c: Context) => {
});
}
checkRateLimit(token);
const hashedToken = hashToken(token);
const team = await db.team.findFirst({
@@ -55,3 +67,18 @@ export const getTeamFromToken = async (c: Context) => {
return team;
};
const checkRateLimit = (token: string) => {
let rateLimit = rateLimitCache.get<number>(token);
rateLimit = rateLimit ?? 0;
if (rateLimit >= 2) {
throw new UnsendApiError({
code: "RATE_LIMITED",
message: `Rate limit exceeded, ${env.API_RATE_LIMIT} requests per second`,
});
}
rateLimitCache.set(token, rateLimit + 1);
};