feat: Add rate limting to API (#11783)

pull/11817/head
sean-brydon 2023-10-11 23:44:00 +01:00 committed by GitHub
parent 891a656449
commit dc9a4f0dba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 1 deletions

View File

@ -0,0 +1,15 @@
import type { NextMiddleware } from "next-api-middleware";
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
export const rateLimitApiKey: NextMiddleware = async (req, res, next) => {
if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" });
// TODO: Add a way to add trusted api keys
await checkRateLimitAndThrowError({
identifier: req.query.apiKey as string,
rateLimitingType: "api",
});
await next();
};

View File

@ -12,6 +12,7 @@ import {
HTTP_GET_OR_POST, HTTP_GET_OR_POST,
HTTP_GET_DELETE_PATCH, HTTP_GET_DELETE_PATCH,
} from "./httpMethods"; } from "./httpMethods";
import { rateLimitApiKey } from "./rateLimitApiKey";
import { verifyApiKey } from "./verifyApiKey"; import { verifyApiKey } from "./verifyApiKey";
import { withPagination } from "./withPagination"; import { withPagination } from "./withPagination";
@ -25,6 +26,7 @@ const withMiddleware = label(
HTTP_DELETE, HTTP_DELETE,
addRequestId, addRequestId,
verifyApiKey, verifyApiKey,
rateLimitApiKey,
customPrismaClient, customPrismaClient,
extendRequest, extendRequest,
pagination: withPagination, pagination: withPagination,
@ -37,6 +39,7 @@ const withMiddleware = label(
// - Put customPrismaClient before verifyApiKey always. // - Put customPrismaClient before verifyApiKey always.
"customPrismaClient", "customPrismaClient",
"verifyApiKey", "verifyApiKey",
"rateLimitApiKey",
"addRequestId", "addRequestId",
] // <-- Provide a list of middleware to call automatically ] // <-- Provide a list of middleware to call automatically
); );

View File

@ -7,7 +7,7 @@ import logger from "./logger";
const log = logger.getChildLogger({ prefix: ["RateLimit"] }); const log = logger.getChildLogger({ prefix: ["RateLimit"] });
export type RateLimitHelper = { export type RateLimitHelper = {
rateLimitingType?: "core" | "forcedSlowMode" | "common"; rateLimitingType?: "core" | "forcedSlowMode" | "common" | "api";
identifier: string; identifier: string;
}; };
@ -69,6 +69,12 @@ export function rateLimiter() {
prefix: "ratelimit:slowmode", prefix: "ratelimit:slowmode",
limiter: Ratelimit.fixedWindow(1, "30s"), limiter: Ratelimit.fixedWindow(1, "30s"),
}), }),
api: new Ratelimit({
redis,
analytics: true,
prefix: "ratelimit:api",
limiter: Ratelimit.fixedWindow(10, "60s"),
}),
}; };
async function rateLimit({ rateLimitingType = "core", identifier }: RateLimitHelper) { async function rateLimit({ rateLimitingType = "core", identifier }: RateLimitHelper) {