diff --git a/packages/backend/src/errors/not-authorized.js b/packages/backend/src/errors/not-authorized.js new file mode 100644 index 00000000..ff0621bd --- /dev/null +++ b/packages/backend/src/errors/not-authorized.js @@ -0,0 +1,3 @@ +import BaseError from './base.js'; + +export default class NotAuthorized extends BaseError {} diff --git a/packages/backend/src/helpers/authorization.js b/packages/backend/src/helpers/authorization.js index d6a0d3e7..2ad150f3 100644 --- a/packages/backend/src/helpers/authorization.js +++ b/packages/backend/src/helpers/authorization.js @@ -1,3 +1,5 @@ +import NotAuthorizedError from '../errors/not-authorized.js'; + const authorizationList = { 'GET /api/v1/users/:userId': { action: 'read', @@ -86,12 +88,8 @@ export const authorizeUser = async (request, response, next) => { request.method + ' ' + request.baseUrl + request.route.path; const currentRouteRule = authorizationList[currentRoute]; - try { - request.currentUser.can(currentRouteRule.action, currentRouteRule.subject); - next(); - } catch (error) { - return response.status(403).end(); - } + request.currentUser.can(currentRouteRule.action, currentRouteRule.subject); + next(); }; export const authorizeAdmin = async (request, response, next) => { @@ -100,6 +98,6 @@ export const authorizeAdmin = async (request, response, next) => { if (role?.isAdmin) { next(); } else { - return response.status(403).end(); + throw new NotAuthorizedError(); } }; diff --git a/packages/backend/src/helpers/error-handler.js b/packages/backend/src/helpers/error-handler.js index f4880812..ecfa9c18 100644 --- a/packages/backend/src/helpers/error-handler.js +++ b/packages/backend/src/helpers/error-handler.js @@ -3,6 +3,7 @@ import objection from 'objection'; import * as Sentry from './sentry.ee.js'; const { NotFoundError, DataError, ValidationError, UniqueViolationError } = objection; +import NotAuthorizedError from '../errors/not-authorized.js'; import HttpError from '../errors/http.js'; import { renderObjectionError, @@ -43,6 +44,10 @@ const errorHandler = (error, request, response, next) => { response.status(200).json(httpErrorPayload); } + if (error instanceof NotAuthorizedError) { + response.status(403).end(); + } + const statusCode = error.statusCode || 500; logger.error(request.method + ' ' + request.url + ' ' + statusCode); diff --git a/packages/backend/src/models/user.js b/packages/backend/src/models/user.js index bd610d72..483cf403 100644 --- a/packages/backend/src/models/user.js +++ b/packages/backend/src/models/user.js @@ -20,6 +20,7 @@ import Step from './step.js'; import Subscription from './subscription.ee.js'; import UsageData from './usage-data.ee.js'; import Billing from '../helpers/billing/index.ee.js'; +import NotAuthorizedError from '../errors/not-authorized.js'; import deleteUserQueue from '../queues/delete-user.ee.js'; import emailQueue from '../queues/email.js'; @@ -533,7 +534,7 @@ class User extends Base { can(action, subject) { const can = this.ability.can(action, subject); - if (!can) throw new Error('Not authorized!'); + if (!can) throw new NotAuthorizedError(); const relevantRule = this.ability.relevantRuleFor(action, subject); @@ -548,7 +549,7 @@ class User extends Base { cannot(action, subject) { const cannot = this.ability.cannot(action, subject); - if (cannot) throw new Error('Not authorized!'); + if (cannot) throw new NotAuthorizedError(); return cannot; }