* add eslint config * migrate autoLock to features * migrate teamService to features * migrate userCreationService * migrate insights services to features * migrate ProfileRepository * update imports * migrate filter segmen tests * migrate filter segment repository * migrate getBusyTimes * migrate getLocaleFromRequest * refactor csvUtils * make filename clearer * migrate getLuckyUser integration test * migrate autoLock test to features * wip * refactors * migrate useBookerUrl * migrate more * wip * Migrate eventTypeRepository * membership repository * update imports * update imports * migrate * move organization repository * update imports * update imports * wip * wip * wip * wip * wip * wip * wip * wip * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix tests * fix type checks * fix * fix * migrate * update imports * fix tests * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix
49 lines
1.7 KiB
TypeScript
49 lines
1.7 KiB
TypeScript
import type { NextMiddleware } from "next-api-middleware";
|
|
|
|
import { handleAutoLock } from "@calcom/features/ee/api-keys/lib/autoLock";
|
|
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
|
import { HttpError } from "@calcom/lib/http-error";
|
|
|
|
export const rateLimitApiKey: NextMiddleware = async (req, res, next) => {
|
|
if (!req.userId) return res.status(401).json({ message: "No userId provided" });
|
|
if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" });
|
|
|
|
// TODO: Add a way to add trusted api keys
|
|
try {
|
|
const identifier = req.userId.toString();
|
|
await checkRateLimitAndThrowError({
|
|
identifier,
|
|
rateLimitingType: "api",
|
|
onRateLimiterResponse: async (response) => {
|
|
res.setHeader("X-RateLimit-Limit", response.limit);
|
|
res.setHeader("X-RateLimit-Remaining", response.remaining);
|
|
res.setHeader("X-RateLimit-Reset", response.reset);
|
|
|
|
try {
|
|
const didLock = await handleAutoLock({
|
|
identifier,
|
|
identifierType: "userId",
|
|
rateLimitResponse: response,
|
|
});
|
|
|
|
if (didLock) {
|
|
return res.status(429).json({ message: "Too many requests" });
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof Error && error.message === "No user found for this API key.") {
|
|
return res.status(401).json({ message: error.message });
|
|
}
|
|
throw error;
|
|
}
|
|
},
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof HttpError) {
|
|
return res.status(error.statusCode).json({ message: error.message });
|
|
}
|
|
return res.status(429).json({ message: "Rate limit exceeded" });
|
|
}
|
|
|
|
await next();
|
|
};
|