mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 19:26:38 +00:00
refactor: Refactored middlewares to use RequestError
Refactored middlewares to use RequestError rather than using
`try {...}catch (err){...}`. With this change it's possible to manage
all error details within one place.
Added:
- Added Sentry.captureException to Error Handler
This commit is contained in:
@@ -4,6 +4,7 @@ import helmet from 'helmet';
|
|||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import cookieParser from 'cookie-parser';
|
import cookieParser from 'cookie-parser';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
import * as Sentry from '@sentry/node';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
import { PORT, NODE_ENV, SITE_URL } from './config';
|
import { PORT, NODE_ENV, SITE_URL } from './config';
|
||||||
@@ -60,6 +61,11 @@ app.use((error: RequestError|Error, req: Request, res: Response, next: NextFunct
|
|||||||
error = InternalServerError({context: {exception: error.message}, stack: error.stack})
|
error = InternalServerError({context: {exception: error.message}, stack: error.stack})
|
||||||
getLogger('backend-main').log((<RequestError>error).levelName.toLowerCase(), (<RequestError>error).message)
|
getLogger('backend-main').log((<RequestError>error).levelName.toLowerCase(), (<RequestError>error).message)
|
||||||
}
|
}
|
||||||
|
//* Sentry Error Capture
|
||||||
|
if(req.user !== undefined || req.user !== null)
|
||||||
|
Sentry.setUser({ email: req.user.email })
|
||||||
|
Sentry.captureException(error)
|
||||||
|
|
||||||
res.status((<RequestError>error).statusCode).json((<RequestError>error).format(req))
|
res.status((<RequestError>error).statusCode).json((<RequestError>error).format(req))
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ const syncIntegrationsHelper = async ({
|
|||||||
*/
|
*/
|
||||||
const getIntegrationAuthRefreshHelper = async ({ integrationAuthId }: { integrationAuthId: string }) => {
|
const getIntegrationAuthRefreshHelper = async ({ integrationAuthId }: { integrationAuthId: string }) => {
|
||||||
let refreshToken;
|
let refreshToken;
|
||||||
|
//TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors
|
||||||
try {
|
try {
|
||||||
const integrationAuth = await IntegrationAuth
|
const integrationAuth = await IntegrationAuth
|
||||||
.findById(integrationAuthId)
|
.findById(integrationAuthId)
|
||||||
@@ -209,6 +210,7 @@ const syncIntegrationsHelper = async ({
|
|||||||
*/
|
*/
|
||||||
const getIntegrationAuthAccessHelper = async ({ integrationAuthId }: { integrationAuthId: string }) => {
|
const getIntegrationAuthAccessHelper = async ({ integrationAuthId }: { integrationAuthId: string }) => {
|
||||||
let accessToken;
|
let accessToken;
|
||||||
|
//TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors
|
||||||
try {
|
try {
|
||||||
const integrationAuth = await IntegrationAuth
|
const integrationAuth = await IntegrationAuth
|
||||||
.findById(integrationAuthId)
|
.findById(integrationAuthId)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const validateMembership = async ({
|
|||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
let membership;
|
let membership;
|
||||||
|
//TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors
|
||||||
try {
|
try {
|
||||||
membership = await Membership.findOne({
|
membership = await Membership.findOne({
|
||||||
user: userId,
|
user: userId,
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ const exchangeRefreshHeroku = async ({
|
|||||||
refreshToken: string;
|
refreshToken: string;
|
||||||
}) => {
|
}) => {
|
||||||
let accessToken;
|
let accessToken;
|
||||||
|
//TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(
|
const res = await axios.post(
|
||||||
INTEGRATION_HEROKU_TOKEN_URL,
|
INTEGRATION_HEROKU_TOKEN_URL,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
import * as Sentry from '@sentry/node';
|
|
||||||
import { User } from '../models';
|
import { User } from '../models';
|
||||||
import { JWT_AUTH_SECRET } from '../config';
|
import { JWT_AUTH_SECRET } from '../config';
|
||||||
|
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
declare module 'jsonwebtoken' {
|
declare module 'jsonwebtoken' {
|
||||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||||
@@ -20,32 +20,25 @@ declare module 'jsonwebtoken' {
|
|||||||
*/
|
*/
|
||||||
const requireAuth = async (req: Request, res: Response, next: NextFunction) => {
|
const requireAuth = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
// JWT authentication middleware
|
// JWT authentication middleware
|
||||||
try {
|
const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null]
|
||||||
if (!req.headers?.authorization)
|
if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`}))
|
||||||
throw new Error('Failed to locate authorization header');
|
if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(UnauthorizedRequestError({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 token = req.headers.authorization.split(' ')[1];
|
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
jwt.verify(AUTH_TOKEN_VALUE, JWT_AUTH_SECRET)
|
||||||
jwt.verify(token, JWT_AUTH_SECRET)
|
);
|
||||||
);
|
|
||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
_id: decodedToken.userId
|
_id: decodedToken.userId
|
||||||
}).select('+publicKey');
|
}).select('+publicKey');
|
||||||
|
|
||||||
if (!user) throw new Error('Failed to authenticate unfound user');
|
if (!user) return next(UnauthorizedRequestError({message: 'Failed to locate User account'}))
|
||||||
if (!user?.publicKey)
|
if (!user?.publicKey)
|
||||||
throw new Error('Failed to authenticate not fully set up account');
|
return next(UnauthorizedRequestError({message: 'Unable to authenticate due to partially set up account'}))
|
||||||
|
|
||||||
req.user = user;
|
req.user = user;
|
||||||
return next();
|
return next();
|
||||||
} catch (err) {
|
|
||||||
Sentry.setUser(null);
|
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error: 'Failed to authenticate user. Try logging in'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default requireAuth;
|
export default requireAuth;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as Sentry from '@sentry/node';
|
|||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
import { Bot } from '../models';
|
import { Bot } from '../models';
|
||||||
import { validateMembership } from '../helpers/membership';
|
import { validateMembership } from '../helpers/membership';
|
||||||
|
import { UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
type req = 'params' | 'body' | 'query';
|
type req = 'params' | 'body' | 'query';
|
||||||
|
|
||||||
@@ -15,30 +16,22 @@ const requireBotAuth = ({
|
|||||||
location?: req;
|
location?: req;
|
||||||
}) => {
|
}) => {
|
||||||
return async (req: Request, res: Response, next: NextFunction) => {
|
return async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
const bot = await Bot.findOne({ _id: req[location].botId });
|
||||||
const bot = await Bot.findOne({ _id: req[location].botId });
|
|
||||||
|
if (!bot) {
|
||||||
if (!bot) {
|
return next(UnauthorizedRequestError({message: 'Failed to locate Bot account'}))
|
||||||
throw new Error('Failed to find bot');
|
|
||||||
}
|
|
||||||
|
|
||||||
await validateMembership({
|
|
||||||
userId: req.user._id.toString(),
|
|
||||||
workspaceId: bot.workspace.toString(),
|
|
||||||
acceptedRoles,
|
|
||||||
acceptedStatuses
|
|
||||||
});
|
|
||||||
|
|
||||||
req.bot = bot;
|
|
||||||
|
|
||||||
next();
|
|
||||||
} catch (err) {
|
|
||||||
Sentry.setUser(null);
|
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error: 'Failed bot authorization'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await validateMembership({
|
||||||
|
userId: req.user._id.toString(),
|
||||||
|
workspaceId: bot.workspace.toString(),
|
||||||
|
acceptedRoles,
|
||||||
|
acceptedStatuses
|
||||||
|
});
|
||||||
|
|
||||||
|
req.bot = bot;
|
||||||
|
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Request, Response, NextFunction } from 'express';
|
|||||||
import { Bot, Integration, IntegrationAuth, Membership } from '../models';
|
import { Bot, Integration, IntegrationAuth, Membership } from '../models';
|
||||||
import { IntegrationService } from '../services';
|
import { IntegrationService } from '../services';
|
||||||
import { validateMembership } from '../helpers/membership';
|
import { validateMembership } from '../helpers/membership';
|
||||||
|
import { UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate if user on request is a member of workspace with proper roles associated
|
* Validate if user on request is a member of workspace with proper roles associated
|
||||||
@@ -21,48 +22,40 @@ const requireIntegrationAuth = ({
|
|||||||
return async (req: Request, res: Response, next: NextFunction) => {
|
return async (req: Request, res: Response, next: NextFunction) => {
|
||||||
// integration authorization middleware
|
// integration authorization middleware
|
||||||
|
|
||||||
try {
|
const { integrationId } = req.params;
|
||||||
const { integrationId } = req.params;
|
|
||||||
|
|
||||||
// validate integration accessibility
|
// validate integration accessibility
|
||||||
const integration = await Integration.findOne({
|
const integration = await Integration.findOne({
|
||||||
_id: integrationId
|
_id: integrationId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!integration) {
|
if (!integration) {
|
||||||
throw new Error('Failed to find integration');
|
return next(UnauthorizedRequestError({message: 'Failed to locate Integration'}))
|
||||||
}
|
|
||||||
|
|
||||||
await validateMembership({
|
|
||||||
userId: req.user._id.toString(),
|
|
||||||
workspaceId: integration.workspace.toString(),
|
|
||||||
acceptedRoles,
|
|
||||||
acceptedStatuses
|
|
||||||
});
|
|
||||||
|
|
||||||
const integrationAuth = await IntegrationAuth.findOne({
|
|
||||||
_id: integration.integrationAuth
|
|
||||||
}).select(
|
|
||||||
'+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!integrationAuth) {
|
|
||||||
throw new Error('Failed to find integration authorization');
|
|
||||||
}
|
|
||||||
|
|
||||||
req.integration = integration;
|
|
||||||
req.accessToken = await IntegrationService.getIntegrationAuthAccess({
|
|
||||||
integrationAuthId: integrationAuth._id.toString()
|
|
||||||
});
|
|
||||||
|
|
||||||
return next();
|
|
||||||
} catch (err) {
|
|
||||||
Sentry.setUser(null);
|
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error: 'Failed integration authorization'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await validateMembership({
|
||||||
|
userId: req.user._id.toString(),
|
||||||
|
workspaceId: integration.workspace.toString(),
|
||||||
|
acceptedRoles,
|
||||||
|
acceptedStatuses
|
||||||
|
});
|
||||||
|
|
||||||
|
const integrationAuth = await IntegrationAuth.findOne({
|
||||||
|
_id: integration.integrationAuth
|
||||||
|
}).select(
|
||||||
|
'+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!integrationAuth) {
|
||||||
|
return next(UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'}))
|
||||||
|
}
|
||||||
|
|
||||||
|
req.integration = integration;
|
||||||
|
req.accessToken = await IntegrationService.getIntegrationAuthAccess({
|
||||||
|
integrationAuthId: integrationAuth._id.toString()
|
||||||
|
});
|
||||||
|
|
||||||
|
return next();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Request, Response, NextFunction } from 'express';
|
|||||||
import { IntegrationAuth } from '../models';
|
import { IntegrationAuth } from '../models';
|
||||||
import { IntegrationService } from '../services';
|
import { IntegrationService } from '../services';
|
||||||
import { validateMembership } from '../helpers/membership';
|
import { validateMembership } from '../helpers/membership';
|
||||||
|
import { UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate if user on request is a member of workspace with proper roles associated
|
* Validate if user on request is a member of workspace with proper roles associated
|
||||||
@@ -22,41 +23,33 @@ const requireIntegrationAuthorizationAuth = ({
|
|||||||
attachAccessToken?: boolean;
|
attachAccessToken?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
return async (req: Request, res: Response, next: NextFunction) => {
|
return async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
const { integrationAuthId } = req.params;
|
||||||
const { integrationAuthId } = req.params;
|
|
||||||
|
|
||||||
const integrationAuth = await IntegrationAuth.findOne({
|
const integrationAuth = await IntegrationAuth.findOne({
|
||||||
_id: integrationAuthId
|
_id: integrationAuthId
|
||||||
}).select(
|
}).select(
|
||||||
'+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt'
|
'+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!integrationAuth) {
|
if (!integrationAuth) {
|
||||||
throw new Error('Failed to find integration authorization');
|
return next(UnauthorizedRequestError({message: 'Failed to locate Integration Authorization credentials'}))
|
||||||
}
|
}
|
||||||
|
|
||||||
await validateMembership({
|
await validateMembership({
|
||||||
userId: req.user._id.toString(),
|
userId: req.user._id.toString(),
|
||||||
workspaceId: integrationAuth.workspace.toString(),
|
workspaceId: integrationAuth.workspace.toString(),
|
||||||
acceptedRoles,
|
acceptedRoles,
|
||||||
acceptedStatuses
|
acceptedStatuses
|
||||||
});
|
});
|
||||||
|
|
||||||
req.integrationAuth = integrationAuth;
|
req.integrationAuth = integrationAuth;
|
||||||
if (attachAccessToken) {
|
if (attachAccessToken) {
|
||||||
req.accessToken = await IntegrationService.getIntegrationAuthAccess({
|
req.accessToken = await IntegrationService.getIntegrationAuthAccess({
|
||||||
integrationAuthId: integrationAuth._id.toString()
|
integrationAuthId: integrationAuth._id.toString()
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return next();
|
|
||||||
} catch (err) {
|
|
||||||
Sentry.setUser(null);
|
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error: 'Failed (authorization) integration authorizationt'
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as Sentry from '@sentry/node';
|
import * as Sentry from '@sentry/node';
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
import { IOrganization, MembershipOrg } from '../models';
|
import { IOrganization, MembershipOrg } from '../models';
|
||||||
|
import { UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate if user on request is a member with proper roles for organization
|
* Validate if user on request is a member with proper roles for organization
|
||||||
@@ -19,35 +20,27 @@ const requireOrganizationAuth = ({
|
|||||||
return async (req: Request, res: Response, next: NextFunction) => {
|
return async (req: Request, res: Response, next: NextFunction) => {
|
||||||
// organization authorization middleware
|
// organization authorization middleware
|
||||||
|
|
||||||
try {
|
// validate organization membership
|
||||||
// validate organization membership
|
const membershipOrg = await MembershipOrg.findOne({
|
||||||
const membershipOrg = await MembershipOrg.findOne({
|
user: req.user._id,
|
||||||
user: req.user._id,
|
organization: req.params.organizationId
|
||||||
organization: req.params.organizationId
|
}).populate<{ organization: IOrganization }>('organization');
|
||||||
}).populate<{ organization: IOrganization }>('organization');
|
|
||||||
|
|
||||||
if (!membershipOrg) {
|
if (!membershipOrg) {
|
||||||
throw new Error('Failed to find organization membership');
|
return next(UnauthorizedRequestError({message: 'Failed to locate Organization Membership'}))
|
||||||
}
|
|
||||||
|
|
||||||
if (!acceptedRoles.includes(membershipOrg.role)) {
|
|
||||||
throw new Error('Failed to validate organization membership role');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!acceptedStatuses.includes(membershipOrg.status)) {
|
|
||||||
throw new Error('Failed to validate organization membership status');
|
|
||||||
}
|
|
||||||
|
|
||||||
req.membershipOrg = membershipOrg;
|
|
||||||
|
|
||||||
return next();
|
|
||||||
} catch (err) {
|
|
||||||
Sentry.setUser(null);
|
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error: 'Failed organization authorization'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!acceptedRoles.includes(membershipOrg.role)) {
|
||||||
|
return next(UnauthorizedRequestError({message: 'Failed to validate Organization Membership Role'}))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acceptedStatuses.includes(membershipOrg.status)) {
|
||||||
|
return next(UnauthorizedRequestError({message: 'Failed to validate Organization Membership Status'}))
|
||||||
|
}
|
||||||
|
|
||||||
|
req.membershipOrg = membershipOrg;
|
||||||
|
|
||||||
|
return next();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Request, Response, NextFunction } from 'express';
|
|||||||
import * as Sentry from '@sentry/node';
|
import * as Sentry from '@sentry/node';
|
||||||
import { ServiceToken } from '../models';
|
import { ServiceToken } from '../models';
|
||||||
import { JWT_SERVICE_SECRET } from '../config';
|
import { JWT_SERVICE_SECRET } from '../config';
|
||||||
|
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
declare module 'jsonwebtoken' {
|
declare module 'jsonwebtoken' {
|
||||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||||
@@ -24,33 +25,27 @@ const requireServiceTokenAuth = async (
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
) => {
|
) => {
|
||||||
// JWT service token middleware
|
// JWT service token middleware
|
||||||
try {
|
|
||||||
if (!req.headers?.authorization)
|
const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null]
|
||||||
throw new Error('Failed to locate authorization header');
|
if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`}))
|
||||||
|
//TODO: Determine what is the actual Token Type for Service Token Authentication (ex. Bearer)
|
||||||
|
//if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(UnauthorizedRequestError({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 token = req.headers.authorization.split(' ')[1];
|
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||||
|
jwt.verify(AUTH_TOKEN_VALUE, JWT_SERVICE_SECRET)
|
||||||
|
);
|
||||||
|
|
||||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
const serviceToken = await ServiceToken.findOne({
|
||||||
jwt.verify(token, JWT_SERVICE_SECRET)
|
_id: decodedToken.serviceTokenId
|
||||||
);
|
})
|
||||||
|
.populate('user', '+publicKey')
|
||||||
|
.select('+encryptedKey +publicKey +nonce');
|
||||||
|
|
||||||
const serviceToken = await ServiceToken.findOne({
|
if (!serviceToken) return next(UnauthorizedRequestError({message: 'Failed to locate Service Token'}))
|
||||||
_id: decodedToken.serviceTokenId
|
|
||||||
})
|
|
||||||
.populate('user', '+publicKey')
|
|
||||||
.select('+encryptedKey +publicKey +nonce');
|
|
||||||
|
|
||||||
if (!serviceToken) throw new Error('Failed to find service token');
|
req.serviceToken = serviceToken;
|
||||||
|
return next();
|
||||||
req.serviceToken = serviceToken;
|
|
||||||
return next();
|
|
||||||
} catch (err) {
|
|
||||||
Sentry.setUser(null);
|
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error: 'Failed to authenticate service token'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default requireServiceTokenAuth;
|
export default requireServiceTokenAuth;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Request, Response, NextFunction } from 'express';
|
|||||||
import * as Sentry from '@sentry/node';
|
import * as Sentry from '@sentry/node';
|
||||||
import { User } from '../models';
|
import { User } from '../models';
|
||||||
import { JWT_SIGNUP_SECRET } from '../config';
|
import { JWT_SIGNUP_SECRET } from '../config';
|
||||||
|
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
declare module 'jsonwebtoken' {
|
declare module 'jsonwebtoken' {
|
||||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||||
@@ -21,32 +22,24 @@ const requireSignupAuth = async (
|
|||||||
) => {
|
) => {
|
||||||
// JWT (temporary) authentication middleware for complete signup
|
// JWT (temporary) authentication middleware for complete signup
|
||||||
|
|
||||||
try {
|
const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null]
|
||||||
if (!req.headers?.authorization)
|
if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`}))
|
||||||
throw new Error('Failed to locate authorization header');
|
if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(UnauthorizedRequestError({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>(
|
||||||
|
jwt.verify(AUTH_TOKEN_VALUE, JWT_SIGNUP_SECRET)
|
||||||
|
);
|
||||||
|
|
||||||
const token = req.headers.authorization.split(' ')[1];
|
const user = await User.findOne({
|
||||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
_id: decodedToken.userId
|
||||||
jwt.verify(token, JWT_SIGNUP_SECRET)
|
}).select('+publicKey');
|
||||||
);
|
|
||||||
|
|
||||||
const user = await User.findOne({
|
if (!user)
|
||||||
_id: decodedToken.userId
|
return next(UnauthorizedRequestError({message: 'Unable to authenticate for User account completion. Try logging in again'}))
|
||||||
}).select('+publicKey');
|
|
||||||
|
|
||||||
if (!user)
|
req.user = user;
|
||||||
throw new Error('Failed to temporarily authenticate unfound user');
|
return next();
|
||||||
|
|
||||||
req.user = user;
|
|
||||||
return next();
|
|
||||||
} catch (err) {
|
|
||||||
Sentry.setUser(null);
|
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error:
|
|
||||||
'Failed to temporarily authenticate user for complete account. Try logging in'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default requireSignupAuth;
|
export default requireSignupAuth;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as Sentry from '@sentry/node';
|
import * as Sentry from '@sentry/node';
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
import { validateMembership } from '../helpers/membership';
|
import { validateMembership } from '../helpers/membership';
|
||||||
|
import { UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
type req = 'params' | 'body' | 'query';
|
type req = 'params' | 'body' | 'query';
|
||||||
|
|
||||||
@@ -36,11 +37,7 @@ const requireWorkspaceAuth = ({
|
|||||||
|
|
||||||
return next();
|
return next();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Sentry.setUser(null);
|
return next(UnauthorizedRequestError({message: 'Unable to authenticate workspace'}))
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error: 'Failed workspace authorization'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
import * as Sentry from '@sentry/node';
|
import * as Sentry from '@sentry/node';
|
||||||
import { validationResult } from 'express-validator';
|
import { validationResult } from 'express-validator';
|
||||||
|
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate intended inputs on [req] via express-validator
|
* Validate intended inputs on [req] via express-validator
|
||||||
@@ -15,16 +16,12 @@ const validate = (req: Request, res: Response, next: NextFunction) => {
|
|||||||
try {
|
try {
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
return res.status(400).json({ errors: errors.array() });
|
return next(BadRequestError({context: {errors: errors.array}}))
|
||||||
}
|
}
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Sentry.setUser(null);
|
return next(UnauthorizedRequestError({message: 'Unauthenticated requests are not allowed. Try logging in'}))
|
||||||
Sentry.captureException(err);
|
|
||||||
return res.status(401).send({
|
|
||||||
error: "Looks like you're unauthenticated . Try logging in"
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user