feat: Add rate limting to API (#11783)
parent
891a656449
commit
dc9a4f0dba
|
@ -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();
|
||||||
|
};
|
|
@ -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
|
||||||
);
|
);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue