From bb6d482ff9535e66ef630f31cc19fb78b39ee07d Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Tue, 16 Jan 2024 19:37:11 +0530 Subject: [PATCH] feat(infisical-pg): added global error handler, try catch in oauth passport --- backend-pg/src/ee/routes/v1/saml-router.ts | 2 + backend-pg/src/lib/errors/index.ts | 2 +- backend-pg/src/server/app.ts | 2 + .../src/server/plugins/error-handler.ts | 34 +++++++++++ backend-pg/src/server/routes/v1/sso-router.ts | 60 +++++++++++-------- .../src/server/routes/v3/secret-router.ts | 3 +- 6 files changed, 76 insertions(+), 27 deletions(-) create mode 100644 backend-pg/src/server/plugins/error-handler.ts diff --git a/backend-pg/src/ee/routes/v1/saml-router.ts b/backend-pg/src/ee/routes/v1/saml-router.ts index b8387f404..5a14c4b24 100644 --- a/backend-pg/src/ee/routes/v1/saml-router.ts +++ b/backend-pg/src/ee/routes/v1/saml-router.ts @@ -8,6 +8,7 @@ import { SamlConfigsSchema } from "@app/db/schemas"; import { SamlProviders } from "@app/ee/services/saml-config/saml-config-types"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError } from "@app/lib/errors"; +import { logger } from "@app/lib/logger"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -79,6 +80,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { }); cb(null, { isUserCompleted, providerAuthToken }); } catch (error) { + logger.error(error); cb(null, {}); } }, diff --git a/backend-pg/src/lib/errors/index.ts b/backend-pg/src/lib/errors/index.ts index 55c90d922..b4376f007 100644 --- a/backend-pg/src/lib/errors/index.ts +++ b/backend-pg/src/lib/errors/index.ts @@ -54,7 +54,7 @@ export class BadRequestError extends Error { constructor({ name, error, message }: { message?: string; name?: string; error?: unknown }) { super(message ?? "The request is invalid"); - this.name = name || ""; + this.name = name || "BadRequest"; this.error = error; } } diff --git a/backend-pg/src/server/app.ts b/backend-pg/src/server/app.ts index 70c140d5c..3269e29c2 100644 --- a/backend-pg/src/server/app.ts +++ b/backend-pg/src/server/app.ts @@ -16,6 +16,7 @@ import { TSmtpService } from "@app/services/smtp/smtp-service"; import { getConfig } from "@lib/config/env"; import { globalRateLimiterCfg } from "./config/rateLimiter"; +import { fastifyErrHandler } from "./plugins/error-handler"; import { serializerCompiler, validatorCompiler, ZodTypeProvider } from "./plugins/fastify-zod"; import { fastifyIp } from "./plugins/ip"; import { fastifySwagger } from "./plugins/swagger"; @@ -53,6 +54,7 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => { await server.register(fastifySwagger); await server.register(fastifyFormBody); + await server.register(fastifyErrHandler); // allow empty body on post request // server.addContentTypeParser("application/json", { bodyLimit: 0 }, (_request, _payload, done) => // done(null, null) diff --git a/backend-pg/src/server/plugins/error-handler.ts b/backend-pg/src/server/plugins/error-handler.ts new file mode 100644 index 000000000..da3162ef8 --- /dev/null +++ b/backend-pg/src/server/plugins/error-handler.ts @@ -0,0 +1,34 @@ +import { ForbiddenError } from "@casl/ability"; +import fastifyPlugin from "fastify-plugin"; +import { ZodError } from "zod"; + +import { + BadRequestError, + DatabaseError, + ForbiddenRequestError, + InternalServerError, + UnauthorizedError +} from "@app/lib/errors"; + +export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider) => { + server.setErrorHandler((error, req, res) => { + req.log.error(error); + if (error instanceof BadRequestError) { + res.status(400).send({ statusCode: 400, message: error.message, error: error.name }); + } else if (error instanceof UnauthorizedError || error instanceof ForbiddenRequestError) { + res.status(403).send({ statusCode: 403, message: error.message, error: error.name }); + } else if (error instanceof DatabaseError || error instanceof InternalServerError) { + res.status(500).send({ statusCode: 500, message: "Something went wrong", error: error.name }); + } else if (error instanceof ZodError) { + res.status(403).send({ statusCode: 403, error: "ValidationFailure", message: error.issues }); + } else if (error instanceof ForbiddenError) { + res.status(403).send({ + statusCode: 403, + error: "PermissionDenied", + message: `You are not allowed to ${error.action} on ${error.subjectType}` + }); + } else { + res.send(error); + } + }); +}); diff --git a/backend-pg/src/server/routes/v1/sso-router.ts b/backend-pg/src/server/routes/v1/sso-router.ts index 5a09968ad..7ade3e923 100644 --- a/backend-pg/src/server/routes/v1/sso-router.ts +++ b/backend-pg/src/server/routes/v1/sso-router.ts @@ -7,6 +7,7 @@ import { z } from "zod"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError } from "@app/lib/errors"; +import { logger } from "@app/lib/logger"; import { fetchGithubEmails } from "@app/lib/requests/github"; import { AuthMethod } from "@app/services/auth/auth-type"; @@ -50,6 +51,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { }); cb(null, { isUserCompleted, providerAuthToken }); } catch (error) { + logger.error(error); cb(null, false); } } @@ -72,20 +74,23 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { scope: ["user:email"] }, async (req, accessToken, _refreshToken, profile, cb) => { - const serverCfg = server.services.superAdmin.getServerCfg(); - const ghEmails = await fetchGithubEmails(accessToken); - const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0]; - - const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({ - email, - firstName: profile.displayName, - lastName: "", - authMethod: AuthMethod.GITHUB, - callbackPort: req.query.state as string, - isSignupAllowed: Boolean(serverCfg.allowSignUp) - }); - - return cb(null, { isUserCompleted, providerAuthToken }); + try { + const ghEmails = await fetchGithubEmails(accessToken); + const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0]; + const serverCfg = server.services.superAdmin.getServerCfg(); + const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({ + email, + firstName: profile.displayName, + lastName: "", + authMethod: AuthMethod.GITHUB, + callbackPort: req.query.state as string, + isSignupAllowed: Boolean(serverCfg.allowSignUp), + }); + return cb(null, { isUserCompleted, providerAuthToken }); + } catch (error) { + logger.error(error); + cb(null, false); + } } ) ); @@ -108,18 +113,23 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { baseURL: appCfg.CLIENT_GITLAB_LOGIN_URL }, async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => { - const serverCfg = server.services.superAdmin.getServerCfg(); - const email = profile.emails[0].value; - const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({ - email, - firstName: profile.displayName, - lastName: "", - authMethod: AuthMethod.GITLAB, - callbackPort: req.query.state as string, - isSignupAllowed: Boolean(serverCfg.allowSignUp) - }); + try { + const email = profile.emails[0].value; + const serverCfg = server.services.superAdmin.getServerCfg(); + const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({ + email, + firstName: profile.displayName, + lastName: "", + authMethod: AuthMethod.GITLAB, + callbackPort: req.query.state as string, + isSignupAllowed: Boolean(serverCfg.allowSignUp), + }); - return cb(null, { isUserCompleted, providerAuthToken }); + return cb(null, { isUserCompleted, providerAuthToken }); + } catch (error) { + logger.error(error); + cb(null, false); + } } ) ); diff --git a/backend-pg/src/server/routes/v3/secret-router.ts b/backend-pg/src/server/routes/v3/secret-router.ts index 881895090..e7c53c275 100644 --- a/backend-pg/src/server/routes/v3/secret-router.ts +++ b/backend-pg/src/server/routes/v3/secret-router.ts @@ -470,7 +470,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { skipMultilineEncoding: z.boolean().optional() }), params: z.object({ - secretName: z.string().trim() + secretName: z.string().trim(), + test: z.string() }), response: { 200: z.union([