From dc9a4f0dba8b1c9ebf6a4efebf3e605558caf00d Mon Sep 17 00:00:00 2001 From: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Date: Wed, 11 Oct 2023 23:44:00 +0100 Subject: [PATCH] feat: Add rate limting to API (#11783) --- apps/api/lib/helpers/rateLimitApiKey.ts | 15 +++++++++++++++ apps/api/lib/helpers/withMiddleware.ts | 3 +++ packages/lib/rateLimit.ts | 8 +++++++- 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 apps/api/lib/helpers/rateLimitApiKey.ts diff --git a/apps/api/lib/helpers/rateLimitApiKey.ts b/apps/api/lib/helpers/rateLimitApiKey.ts new file mode 100644 index 0000000000..7f1469ea7f --- /dev/null +++ b/apps/api/lib/helpers/rateLimitApiKey.ts @@ -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(); +}; diff --git a/apps/api/lib/helpers/withMiddleware.ts b/apps/api/lib/helpers/withMiddleware.ts index 37a7b0aa3e..d8cc9d6a13 100644 --- a/apps/api/lib/helpers/withMiddleware.ts +++ b/apps/api/lib/helpers/withMiddleware.ts @@ -12,6 +12,7 @@ import { HTTP_GET_OR_POST, HTTP_GET_DELETE_PATCH, } from "./httpMethods"; +import { rateLimitApiKey } from "./rateLimitApiKey"; import { verifyApiKey } from "./verifyApiKey"; import { withPagination } from "./withPagination"; @@ -25,6 +26,7 @@ const withMiddleware = label( HTTP_DELETE, addRequestId, verifyApiKey, + rateLimitApiKey, customPrismaClient, extendRequest, pagination: withPagination, @@ -37,6 +39,7 @@ const withMiddleware = label( // - Put customPrismaClient before verifyApiKey always. "customPrismaClient", "verifyApiKey", + "rateLimitApiKey", "addRequestId", ] // <-- Provide a list of middleware to call automatically ); diff --git a/packages/lib/rateLimit.ts b/packages/lib/rateLimit.ts index 57bf9f3e80..0608d47eea 100644 --- a/packages/lib/rateLimit.ts +++ b/packages/lib/rateLimit.ts @@ -7,7 +7,7 @@ import logger from "./logger"; const log = logger.getChildLogger({ prefix: ["RateLimit"] }); export type RateLimitHelper = { - rateLimitingType?: "core" | "forcedSlowMode" | "common"; + rateLimitingType?: "core" | "forcedSlowMode" | "common" | "api"; identifier: string; }; @@ -69,6 +69,12 @@ export function rateLimiter() { prefix: "ratelimit:slowmode", 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) {