diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 5082de68da..d5aeaf9749 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -4,7 +4,6 @@ import { NextMiddleware } from "next-api-middleware"; import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants"; // import prismaAdmin from "@calcom/console/modules/common/utils/prisma"; -import { asStringOrUndefined } from "@calcom/lib/asStringOrNull"; import { CONSOLE_URL } from "@calcom/lib/constants"; import { prisma, customPrisma } from "@calcom/prisma"; @@ -18,14 +17,9 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { req.prisma = prisma; await next(); } else { - const id = asStringOrUndefined(key); - - // If we have a key, we check if it is valid. - // const deployment = await prismaAdmin.deployment.findUnique({ - // where: { key }, - // }); + // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. const databaseUrl = await fetch( - `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${id}` + `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${key}` ) .then((res) => res.json()) .then((res) => res.databaseUrl); @@ -34,10 +28,11 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); return; } + // FIXME: Add some checks for the databaseUrl to make sure it is valid. (e.g. not a localhost) const hashedUrl = await hash(databaseUrl, 12); const cachedPrisma = cache.get(hashedUrl); - + /* We cache each cusotm prisma client for 24h to avoid too many requests to the database. */ if (!cachedPrisma) { cache.put( hashedUrl, @@ -46,6 +41,13 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { ); } req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); + /* @note: + In order to skip verifyApiKey for customPrisma requests, + we pass isAdmin true, and userId 0, if we detect them later, + we skip verifyApiKey logic and pass onto next middleware instead. + */ + req.isAdmin = true; + req.userId = 0; } await next(); }; diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 8c11cdb492..3ee1fad862 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -14,26 +14,26 @@ export const dateNotInPast = function (date: Date) { // This verifies the apiKey and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { - const { prisma } = req; + const { prisma, userId, isAdmin } = req; + // If the user is an admin and using a license key (from customPrisma), skip the apiKey check. + if (userId === 0 && isAdmin) await next(); + // Check if the apiKey query param is provided. if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); - - // We remove the prefix from the user provided api_key. If no env set default to "cal_" + // remove the prefix from the user provided api_key. If no env set default to "cal_" const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); - // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); // Check if the hashed api key exists in database. const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); - // console.log("apiKey", apiKey); - // If we cannot find any api key. Throw a 401 Unauthorized. + // If cannot find any api key. Throw a 401 Unauthorized. if (!apiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); if (apiKey.expiresAt && dateNotInPast(apiKey.expiresAt)) { 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" }); - /* We save the user id in the request for later use */ + // save the user id in the request for later use req.userId = apiKey.userId; - /* We save the isAdmin boolean here for later use */ + // save the isAdmin boolean here for later use req.isAdmin = await isAdminGuard(req.userId, prisma); await next();