fix: Redact prisma errors (#10536)
This commit is contained in:
parent
669065cebd
commit
5491821baf
|
@ -1,6 +1,8 @@
|
|||
import * as Sentry from "@sentry/nextjs";
|
||||
import type { NextMiddleware } from "next-api-middleware";
|
||||
|
||||
import { redactError } from "@calcom/lib/redactError";
|
||||
|
||||
export const captureErrors: NextMiddleware = async (_req, res, next) => {
|
||||
try {
|
||||
// Catch any errors that are thrown in remaining
|
||||
|
@ -8,7 +10,11 @@ export const captureErrors: NextMiddleware = async (_req, res, next) => {
|
|||
await next();
|
||||
} catch (error) {
|
||||
Sentry.captureException(error);
|
||||
console.log(error);
|
||||
const redactedError = redactError(error);
|
||||
if (redactedError instanceof Error) {
|
||||
res.status(400).json({ message: redactedError.message, error: redactedError });
|
||||
return;
|
||||
}
|
||||
res.status(400).json({ message: "Something went wrong", error });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -28,10 +28,17 @@ const withMiddleware = label(
|
|||
customPrismaClient,
|
||||
extendRequest,
|
||||
pagination: withPagination,
|
||||
sentry: captureErrors,
|
||||
captureErrors,
|
||||
},
|
||||
// The order here, determines the order of execution, put customPrismaClient before verifyApiKey always.
|
||||
["extendRequest", "sentry", "customPrismaClient", "verifyApiKey", "addRequestId"] // <-- Provide a list of middleware to call automatically
|
||||
// The order here, determines the order of execution
|
||||
[
|
||||
"extendRequest",
|
||||
"captureErrors",
|
||||
// - Put customPrismaClient before verifyApiKey always.
|
||||
"customPrismaClient",
|
||||
"verifyApiKey",
|
||||
"addRequestId",
|
||||
] // <-- Provide a list of middleware to call automatically
|
||||
);
|
||||
|
||||
export { withMiddleware };
|
||||
|
|
|
@ -10,6 +10,7 @@ import React from "react";
|
|||
import { getErrorFromUnknown } from "@calcom/lib/errors";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { redactError } from "@calcom/lib/redactError";
|
||||
|
||||
import { ErrorPage } from "@components/error/error-page";
|
||||
|
||||
|
@ -59,10 +60,17 @@ CustomError.getInitialProps = async (ctx: AugmentedNextPageContext) => {
|
|||
|
||||
// If a HttpError message, let's override defaults
|
||||
if (err instanceof HttpError) {
|
||||
const redactedError = redactError(err);
|
||||
errorInitialProps.statusCode = err.statusCode;
|
||||
errorInitialProps.title = err.name;
|
||||
errorInitialProps.message = err.message;
|
||||
errorInitialProps.err = err;
|
||||
errorInitialProps.title = redactedError.name;
|
||||
errorInitialProps.message = redactedError.message;
|
||||
errorInitialProps.err = {
|
||||
...redactedError,
|
||||
url: err.url,
|
||||
statusCode: err.statusCode,
|
||||
cause: err.cause,
|
||||
method: err.method,
|
||||
};
|
||||
}
|
||||
|
||||
if (res) {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
|
||||
import logger from "@calcom/lib/logger";
|
||||
|
||||
const log = logger.getChildLogger({ prefix: [`[[redactError]`] });
|
||||
|
||||
function shouldRedact<T extends Error>(error: T) {
|
||||
return (
|
||||
error instanceof Prisma.PrismaClientInitializationError ||
|
||||
error instanceof Prisma.PrismaClientKnownRequestError ||
|
||||
error instanceof Prisma.PrismaClientUnknownRequestError ||
|
||||
error instanceof Prisma.PrismaClientValidationError
|
||||
);
|
||||
}
|
||||
|
||||
export const redactError = <T extends Error | unknown>(error: T) => {
|
||||
if (!(error instanceof Error)) {
|
||||
return error;
|
||||
}
|
||||
log.debug("Type of Error: ", error.constructor);
|
||||
if (shouldRedact(error)) {
|
||||
log.error("Error: ", JSON.stringify(error));
|
||||
return new Error("An error occured while querying the database.");
|
||||
}
|
||||
return error;
|
||||
};
|
|
@ -4,6 +4,7 @@ import type { ZodIssue } from "zod";
|
|||
import { ZodError } from "zod";
|
||||
|
||||
import { HttpError } from "../http-error";
|
||||
import { redactError } from "../redactError";
|
||||
|
||||
function hasName(cause: unknown): cause is { name: string } {
|
||||
return !!cause && typeof cause === "object" && "name" in cause;
|
||||
|
@ -40,20 +41,28 @@ export function getServerErrorFromUnknown(cause: unknown): HttpError {
|
|||
message: "Unexpected error, please reach out for our customer support.",
|
||||
});
|
||||
}
|
||||
|
||||
if (cause instanceof PrismaClientKnownRequestError) {
|
||||
return new HttpError({ statusCode: 400, message: cause.message, cause });
|
||||
return getHttpError({ statusCode: 400, cause });
|
||||
}
|
||||
if (cause instanceof NotFoundError) {
|
||||
return new HttpError({ statusCode: 404, message: cause.message, cause });
|
||||
return getHttpError({ statusCode: 404, cause });
|
||||
}
|
||||
if (cause instanceof Stripe.errors.StripeInvalidRequestError) {
|
||||
return new HttpError({ statusCode: 400, message: cause.message, cause });
|
||||
return getHttpError({ statusCode: 400, cause });
|
||||
}
|
||||
if (cause instanceof HttpError) {
|
||||
return cause;
|
||||
const redactedCause = redactError(cause);
|
||||
return {
|
||||
...redactedCause,
|
||||
cause: cause.cause,
|
||||
url: cause.url,
|
||||
statusCode: cause.statusCode,
|
||||
method: cause.method,
|
||||
};
|
||||
}
|
||||
if (cause instanceof Error) {
|
||||
return new HttpError({ statusCode: 500, message: cause.message, cause });
|
||||
return getHttpError({ statusCode: 500, cause });
|
||||
}
|
||||
if (typeof cause === "string") {
|
||||
// @ts-expect-error https://github.com/tc39/proposal-error-cause
|
||||
|
@ -65,3 +74,8 @@ export function getServerErrorFromUnknown(cause: unknown): HttpError {
|
|||
message: `Unhandled error of type '${typeof cause}'. Please reach out for our customer support.`,
|
||||
});
|
||||
}
|
||||
|
||||
function getHttpError<T extends Error>({ statusCode, cause }: { statusCode: number; cause: T }) {
|
||||
const redacted = redactError(cause);
|
||||
return new HttpError({ statusCode, message: redacted.message, cause: redacted });
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { redactError } from "@calcom/lib/redactError";
|
||||
|
||||
import { middleware } from "../trpc";
|
||||
|
||||
const captureErrorsMiddleware = middleware(async ({ next }) => {
|
||||
const result = await next();
|
||||
if (result && !result.ok) {
|
||||
const cause = result.error.cause;
|
||||
if (!cause) {
|
||||
return result;
|
||||
}
|
||||
throw redactError(cause);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
export default captureErrorsMiddleware;
|
|
@ -1,3 +1,4 @@
|
|||
import captureErrorsMiddleware from "../middlewares/captureErrorsMiddleware";
|
||||
import perfMiddleware from "../middlewares/perfMiddleware";
|
||||
import { isAdminMiddleware, isAuthed, isOrgAdminMiddleware } from "../middlewares/sessionMiddleware";
|
||||
import { procedure } from "../trpc";
|
||||
|
@ -23,10 +24,10 @@ const isRateLimitedByUserIdMiddleware = ({ intervalInMs, limit }: IRateLimitOpti
|
|||
return next({ ctx: { user: ctx.user, session: ctx.session } });
|
||||
});
|
||||
*/
|
||||
const authedProcedure = procedure.use(perfMiddleware).use(isAuthed);
|
||||
const authedProcedure = procedure.use(captureErrorsMiddleware).use(perfMiddleware).use(isAuthed);
|
||||
/*export const authedRateLimitedProcedure = ({ intervalInMs, limit }: IRateLimitOptions) =>
|
||||
authedProcedure.use(isRateLimitedByUserIdMiddleware({ intervalInMs, limit }));*/
|
||||
export const authedAdminProcedure = publicProcedure.use(isAdminMiddleware);
|
||||
export const authedOrgAdminProcedure = publicProcedure.use(isOrgAdminMiddleware);
|
||||
export const authedAdminProcedure = publicProcedure.use(captureErrorsMiddleware).use(isAdminMiddleware);
|
||||
export const authedOrgAdminProcedure = publicProcedure.use(captureErrorsMiddleware).use(isOrgAdminMiddleware);
|
||||
|
||||
export default authedProcedure;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import captureErrorsMiddleware from "../middlewares/captureErrorsMiddleware";
|
||||
import perfMiddleware from "../middlewares/perfMiddleware";
|
||||
import { tRPCContext } from "../trpc";
|
||||
|
||||
const publicProcedure = tRPCContext.procedure.use(perfMiddleware);
|
||||
const publicProcedure = tRPCContext.procedure.use(captureErrorsMiddleware).use(perfMiddleware);
|
||||
|
||||
export default publicProcedure;
|
||||
|
|
Loading…
Reference in New Issue
Block a user