refactor: Prefer use of RequestError and next() function on middlewares

Added:
- New error types such as `IntegrationNotFoundError`,
  `WorkspaceNotFoundError`, `AccountNotFoundError' and more.

Refactored:
- Refactored most of the middlewares and very little number of helper
  functions to use RequestError
- Deleted unused imports

Changed:
- Some of the error types in middlewares changed to more related error
  types.
- Environment variable of 'VERBOSE_ERROR_OUTPUT' changed to more
  reliable validation method in `config/index.ts` as per @dangtony98
  requested.
This commit is contained in:
Hüseyin Berke Bütün
2022-12-24 20:52:26 +01:00
parent 843757fcf5
commit 28818db757
12 changed files with 87 additions and 35 deletions
+3 -3
View File
@@ -2,7 +2,7 @@ import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';
import { User } from '../models';
import { JWT_AUTH_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
import { AccountNotFoundError, BadRequestError, UnauthorizedRequestError } from '../utils/errors';
declare module 'jsonwebtoken' {
export interface UserIDJwtPayload extends jwt.JwtPayload {
@@ -22,7 +22,7 @@ const requireAuth = async (req: Request, res: Response, next: NextFunction) => {
// JWT authentication middleware
const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null]
if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`}))
if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(UnauthorizedRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`}))
if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(BadRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`}))
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>(
@@ -33,7 +33,7 @@ const requireAuth = async (req: Request, res: Response, next: NextFunction) => {
_id: decodedToken.userId
}).select('+publicKey');
if (!user) return next(UnauthorizedRequestError({message: 'Failed to locate User account'}))
if (!user) return next(AccountNotFoundError({message: 'Failed to locate User account'}))
if (!user?.publicKey)
return next(UnauthorizedRequestError({message: 'Unable to authenticate due to partially set up account'}))
+2 -3
View File
@@ -1,8 +1,7 @@
import * as Sentry from '@sentry/node';
import { Request, Response, NextFunction } from 'express';
import { Bot } from '../models';
import { validateMembership } from '../helpers/membership';
import { UnauthorizedRequestError } from '../utils/errors';
import { AccountNotFoundError } from '../utils/errors';
type req = 'params' | 'body' | 'query';
@@ -19,7 +18,7 @@ const requireBotAuth = ({
const bot = await Bot.findOne({ _id: req[location].botId });
if (!bot) {
return next(UnauthorizedRequestError({message: 'Failed to locate Bot account'}))
return next(AccountNotFoundError({message: 'Failed to locate Bot account'}))
}
await validateMembership({
@@ -1,9 +1,8 @@
import * as Sentry from '@sentry/node';
import { Request, Response, NextFunction } from 'express';
import { Bot, Integration, IntegrationAuth, Membership } from '../models';
import { Integration, IntegrationAuth } from '../models';
import { IntegrationService } from '../services';
import { validateMembership } from '../helpers/membership';
import { UnauthorizedRequestError } from '../utils/errors';
import { IntegrationNotFoundError, UnauthorizedRequestError } from '../utils/errors';
/**
* Validate if user on request is a member of workspace with proper roles associated
@@ -30,7 +29,7 @@ const requireIntegrationAuth = ({
});
if (!integration) {
return next(UnauthorizedRequestError({message: 'Failed to locate Integration'}))
return next(IntegrationNotFoundError({message: 'Failed to locate Integration'}))
}
await validateMembership({
@@ -1,7 +1,6 @@
import * as Sentry from '@sentry/node';
import { Request, Response, NextFunction } from 'express';
import { IOrganization, MembershipOrg } from '../models';
import { UnauthorizedRequestError } from '../utils/errors';
import { UnauthorizedRequestError, ValidationError } from '../utils/errors';
/**
* Validate if user on request is a member with proper roles for organization
@@ -26,16 +25,17 @@ const requireOrganizationAuth = ({
organization: req.params.organizationId
}).populate<{ organization: IOrganization }>('organization');
if (!membershipOrg) {
return next(UnauthorizedRequestError({message: 'Failed to locate Organization Membership'}))
}
if (!membershipOrg) {
return next(UnauthorizedRequestError({message: "You're not a member of this Organization."}))
}
//TODO is this important to validate? I mean is it possible to save wrong role to database or get wrong role from databse? - Zamion101
if (!acceptedRoles.includes(membershipOrg.role)) {
return next(UnauthorizedRequestError({message: 'Failed to validate Organization Membership Role'}))
return next(ValidationError({message: 'Failed to validate Organization Membership Role'}))
}
if (!acceptedStatuses.includes(membershipOrg.status)) {
return next(UnauthorizedRequestError({message: 'Failed to validate Organization Membership Status'}))
return next(ValidationError({message: 'Failed to validate Organization Membership Status'}))
}
req.membershipOrg = membershipOrg;
@@ -1,6 +1,5 @@
import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';
import * as Sentry from '@sentry/node';
import { ServiceToken } from '../models';
import { JWT_SERVICE_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
@@ -42,7 +41,7 @@ const requireServiceTokenAuth = async (
.populate('user', '+publicKey')
.select('+encryptedKey +publicKey +nonce');
if (!serviceToken) return next(UnauthorizedRequestError({message: 'Failed to locate Service Token'}))
if (!serviceToken) return next(UnauthorizedRequestError({message: 'The service token does not match the record in the database'}))
req.serviceToken = serviceToken;
return next();
+1 -2
View File
@@ -1,6 +1,5 @@
import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';
import * as Sentry from '@sentry/node';
import { User } from '../models';
import { JWT_SIGNUP_SECRET } from '../config';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
@@ -24,7 +23,7 @@ const requireSignupAuth = async (
const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null]
if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`}))
if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(UnauthorizedRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`}))
if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(BadRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`}))
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
const decodedToken = <jwt.UserIDJwtPayload>(
@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/node';
import { Request, Response, NextFunction } from 'express';
import { validateMembership } from '../helpers/membership';
import { UnauthorizedRequestError } from '../utils/errors';
@@ -1,5 +1,4 @@
import { Request, Response, NextFunction } from 'express';
import * as Sentry from '@sentry/node';
import { validationResult } from 'express-validator';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';