Compare commits

...

2 Commits

Author SHA1 Message Date
zomars a61d10bc3d Create migration.sql 2023-10-23 15:23:44 -07:00
zomars a01928fcce feat: Hard limits for API keys 2023-10-23 15:22:42 -07:00
3 changed files with 34 additions and 12 deletions

View File

@ -1,3 +1,4 @@
import type { Prisma } from "@prisma/client";
import type { NextMiddleware } from "next-api-middleware";
import { hashAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys";
@ -39,6 +40,7 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => {
return res.status(401).json({ error: "This apiKey is expired" });
}
if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" });
await hardRateLimit(apiKey)(req, res, next);
// save the user id in the request for later use
req.userId = apiKey.userId;
// save the isAdmin boolean here for later use
@ -46,3 +48,20 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => {
req.isCustomPrisma = false;
await next();
};
const hardRateLimit =
(apiKey: Prisma.ApiKeyGetPayload<true>): NextMiddleware =>
async (req, res) => {
const { prisma } = req;
if (!IS_PRODUCTION) return;
if (apiKey.remainingCalls < 1) {
return res.status(429).json({
error: "API_CALLS_LIMIT_REACHED",
message: "You have reached your daily limit of API calls. Book cal.com/sales to increase your limit",
});
}
await prisma.apiKey.update({
where: { id: apiKey.id },
data: { lastUsedAt: new Date(), remainingCalls: apiKey.remainingCalls - 1 },
});
};

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "ApiKey" ADD COLUMN "remainingCalls" INTEGER;

View File

@ -584,18 +584,19 @@ model Impersonations {
}
model ApiKey {
id String @id @unique @default(cuid())
userId Int
teamId Int?
note String?
createdAt DateTime @default(now())
expiresAt DateTime?
lastUsedAt DateTime?
hashedKey String @unique()
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
app App? @relation(fields: [appId], references: [slug], onDelete: Cascade)
appId String?
id String @id @unique @default(cuid())
userId Int
teamId Int?
note String?
createdAt DateTime @default(now())
expiresAt DateTime?
lastUsedAt DateTime?
hashedKey String @unique()
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
app App? @relation(fields: [appId], references: [slug], onDelete: Cascade)
appId String?
remainingCalls Int?
@@index([userId])
}