Fixes: with hariom help for running api in prod for swagger even in dev

pull/9078/head
Agusti Fernandez Pardo 2022-04-30 23:07:21 +02:00
parent 167a42156d
commit a2d16800aa
4 changed files with 50 additions and 41 deletions

View File

@ -4,6 +4,21 @@ import { NextMiddleware } from "next-api-middleware";
export const addRequestId: NextMiddleware = async (_req, res, next) => {
// Apply header with unique ID to every request
res.setHeader("Calcom-Response-ID", nanoid());
// Add all headers here instead of next.config.js as it is throwing error( Cannot set headers after they are sent to the client) for OPTIONS method
// It is known to happen only in Dev Mode.
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS, PATCH, DELETE, POST, PUT");
res.setHeader(
"Access-Control-Allow-Headers",
"X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization"
);
// Ensure all OPTIONS request are automatically successful. Headers are already set above.
if (_req.method === "OPTIONS") {
res.status(200).end();
return;
}
// Let remaining middleware and API route execute
await next();
};

View File

@ -15,7 +15,7 @@ export const httpMethod = (allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE
// that checks if it's just a string or an array and apply the correct logic to both cases.
export const httpMethods = (allowedHttpMethod: string[]): NextMiddleware => {
return async function (req, res, next) {
if (allowedHttpMethod.map((method) => method === req.method)) {
if (allowedHttpMethod.some((method) => method === req.method || req.method == "OPTIONS")) {
await next();
} else {
res.status(405).json({ message: `Only ${allowedHttpMethod} Method allowed` });

View File

@ -8,8 +8,6 @@ import prisma from "@calcom/prisma";
declare module "next" {
export interface NextApiRequest extends IncomingMessage {
userId: number;
body: any;
query: { [key: string]: string | string[] };
}
}
@ -22,21 +20,21 @@ export const dateNotInPast = function (date: Date) {
};
// This verifies the apiKey and sets the user if it is valid.
export const verifyApiKey: NextMiddleware = async ({ query: { apiKey }, ...req }, res, next) => {
if (!apiKey) return res.status(401).json({ message: "No apiKey provided" });
export const verifyApiKey: NextMiddleware = async (req, res, next) => {
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_"
const strippedApiKey = `${apiKey}`.replace(process.env.API_KEY_PREFIX || " 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 validApiKey = await prisma.apiKey.findUnique({ where: { hashedKey } });
const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } });
// If we cannot find any api key. Throw a 401 Unauthorized.
if (!validApiKey) return res.status(401).json({ error: "Your apiKey is not valid" });
if (validApiKey.expiresAt && dateNotInPast(validApiKey.expiresAt)) {
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 (!validApiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" });
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 */
req.userId = validApiKey.userId;
req.userId = apiKey.userId;
await next();
};

View File

@ -1,3 +1,5 @@
// https://www.npmjs.com/package/next-transpile-modules
// This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API
const withTM = require("next-transpile-modules")([
"@calcom/app-store",
"@calcom/prisma",
@ -5,37 +7,31 @@ const withTM = require("next-transpile-modules")([
"@calcom/ee",
]);
// use something like withPlugins([withTM], {}) if more plugins added later.
module.exports = withTM({
async headers() {
return [
{
// @note: disabling CORS matching all API routes as this will be a our Public API
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "*" },
{ key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
{
key: "Access-Control-Allow-Headers",
value:
"X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization",
},
],
},
];
},
async rewrites() {
return [
// @note: redirects requests from: "/:rest*" the root level to the "/api/:rest*" folder by default.
{
source: "/:rest*",
destination: "/api/:rest*",
},
// @note: redirects requests from api/v*/:rest to /api/:rest?version=* passing version as a query parameter.
{
source: "/api/v:version/:rest*",
destination: "/api/:rest*?version=:version",
},
];
return {
beforeFiles: [
// This redirects requests recieved at / the root to the /api/ folder.
{
source: "/v:version/:rest*",
destination: "/api/v:version/:rest*",
},
// This redirects requests to api/v*/ to /api/ passing version as a query parameter.
{
source: "/api/v:version/:rest*",
destination: "/api/:rest*?version=:version",
},
],
fallback: [
// These rewrites are checked after both pages/public files
// and dynamic routes are checked
{
source: "/:path*",
destination: `/api/:path*`,
},
],
};
},
});