From b458bb3af96759812e43087318b6c453d2eff8bd Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 6 Apr 2024 21:43:15 -0400 Subject: [PATCH] Refactor required route role --- .../server/api/webhookSubscriptions.ts | 9 ++++---- server/middlewares/authentication.ts | 21 +++++++------------ server/routes/api/apiKeys/apiKeys.ts | 7 ++++--- .../authenticationProviders.ts | 7 ++++--- server/routes/api/documents/documents.ts | 10 ++++----- .../api/fileOperations/fileOperations.ts | 11 +++++----- .../routes/api/integrations/integrations.ts | 6 +++--- server/routes/api/users/users.ts | 6 +++--- 8 files changed, 37 insertions(+), 40 deletions(-) diff --git a/plugins/webhooks/server/api/webhookSubscriptions.ts b/plugins/webhooks/server/api/webhookSubscriptions.ts index 4c5337a0c..f8c383259 100644 --- a/plugins/webhooks/server/api/webhookSubscriptions.ts +++ b/plugins/webhooks/server/api/webhookSubscriptions.ts @@ -1,6 +1,7 @@ import Router from "koa-router"; import compact from "lodash/compact"; import isEmpty from "lodash/isEmpty"; +import { UserRole } from "@shared/types"; import auth from "@server/middlewares/authentication"; import validate from "@server/middlewares/validate"; import { WebhookSubscription, Event } from "@server/models"; @@ -14,7 +15,7 @@ const router = new Router(); router.post( "webhookSubscriptions.list", - auth({ admin: true }), + auth({ role: UserRole.Admin }), pagination(), async (ctx: APIContext) => { const { user } = ctx.state.auth; @@ -37,7 +38,7 @@ router.post( router.post( "webhookSubscriptions.create", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.WebhookSubscriptionsCreateSchema), async (ctx: APIContext) => { const { user } = ctx.state.auth; @@ -78,7 +79,7 @@ router.post( router.post( "webhookSubscriptions.delete", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.WebhookSubscriptionsDeleteSchema), async (ctx: APIContext) => { const { id } = ctx.input.body; @@ -111,7 +112,7 @@ router.post( router.post( "webhookSubscriptions.update", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.WebhookSubscriptionsUpdateSchema), async (ctx: APIContext) => { const { id, name, url, secret } = ctx.input.body; diff --git a/server/middlewares/authentication.ts b/server/middlewares/authentication.ts index 35fb6e2f2..5e80b8b1a 100644 --- a/server/middlewares/authentication.ts +++ b/server/middlewares/authentication.ts @@ -1,4 +1,7 @@ import { Next } from "koa"; +import capitalize from "lodash/capitalize"; +import { UserRole } from "@shared/types"; +import { UserRoleHelper } from "@shared/utils/UserRoleHelper"; import Logger from "@server/logging/Logger"; import tracer, { addTags, @@ -14,10 +17,8 @@ import { } from "../errors"; type AuthenticationOptions = { - /** An admin user role is required to access the route. */ - admin?: boolean; - /** A member or admin user role is required to access the route. */ - member?: boolean; + /** Role requuired to access the route. */ + role?: UserRole; /** Authentication is parsed, but optional. */ optional?: boolean; }; @@ -110,16 +111,8 @@ export default function auth(options: AuthenticationOptions = {}) { }); } - if (options.admin) { - if (!user.isAdmin) { - throw AuthorizationError("Admin role required"); - } - } - - if (options.member) { - if (user.isViewer) { - throw AuthorizationError("Member role required"); - } + if (options.role && UserRoleHelper.isRoleLower(user.role, options.role)) { + throw AuthorizationError(`${capitalize(options.role)} role required`); } // not awaiting the promises here so that the request is not blocked diff --git a/server/routes/api/apiKeys/apiKeys.ts b/server/routes/api/apiKeys/apiKeys.ts index 970eba562..33affd791 100644 --- a/server/routes/api/apiKeys/apiKeys.ts +++ b/server/routes/api/apiKeys/apiKeys.ts @@ -1,4 +1,5 @@ import Router from "koa-router"; +import { UserRole } from "@shared/types"; import auth from "@server/middlewares/authentication"; import validate from "@server/middlewares/validate"; import { ApiKey, Event } from "@server/models"; @@ -12,7 +13,7 @@ const router = new Router(); router.post( "apiKeys.create", - auth({ member: true }), + auth({ role: UserRole.Member }), validate(T.APIKeysCreateSchema), async (ctx: APIContext) => { const { name } = ctx.input.body; @@ -43,7 +44,7 @@ router.post( router.post( "apiKeys.list", - auth({ member: true }), + auth({ role: UserRole.Member }), pagination(), async (ctx: APIContext) => { const { user } = ctx.state.auth; @@ -65,7 +66,7 @@ router.post( router.post( "apiKeys.delete", - auth({ member: true }), + auth({ role: UserRole.Member }), validate(T.APIKeysDeleteSchema), async (ctx: APIContext) => { const { id } = ctx.input.body; diff --git a/server/routes/api/authenticationProviders/authenticationProviders.ts b/server/routes/api/authenticationProviders/authenticationProviders.ts index 58f7309a0..ca4895c54 100644 --- a/server/routes/api/authenticationProviders/authenticationProviders.ts +++ b/server/routes/api/authenticationProviders/authenticationProviders.ts @@ -1,4 +1,5 @@ import Router from "koa-router"; +import { UserRole } from "@shared/types"; import auth from "@server/middlewares/authentication"; import { transaction } from "@server/middlewares/transaction"; import validate from "@server/middlewares/validate"; @@ -16,7 +17,7 @@ const router = new Router(); router.post( "authenticationProviders.info", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.AuthenticationProvidersInfoSchema), async (ctx: APIContext) => { const { id } = ctx.input.body; @@ -34,7 +35,7 @@ router.post( router.post( "authenticationProviders.update", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.AuthenticationProvidersUpdateSchema), transaction(), async (ctx: APIContext) => { @@ -79,7 +80,7 @@ router.post( router.post( "authenticationProviders.list", - auth({ admin: true }), + auth({ role: UserRole.Admin }), async (ctx: APIContext) => { const { user } = ctx.state.auth; authorize(user, "read", user.team); diff --git a/server/routes/api/documents/documents.ts b/server/routes/api/documents/documents.ts index ff0ed4857..8f4581fb3 100644 --- a/server/routes/api/documents/documents.ts +++ b/server/routes/api/documents/documents.ts @@ -8,7 +8,7 @@ import escapeRegExp from "lodash/escapeRegExp"; import mime from "mime-types"; import { Op, ScopeOptions, Sequelize, WhereOptions } from "sequelize"; import { v4 as uuidv4 } from "uuid"; -import { StatusFilter, TeamPreference } from "@shared/types"; +import { StatusFilter, TeamPreference, UserRole } from "@shared/types"; import { subtractDate } from "@shared/utils/date"; import slugify from "@shared/utils/slugify"; import documentCreator from "@server/commands/documentCreator"; @@ -203,7 +203,7 @@ router.post( router.post( "documents.archived", - auth({ member: true }), + auth({ role: UserRole.Member }), pagination(), validate(T.DocumentsArchivedSchema), async (ctx: APIContext) => { @@ -247,7 +247,7 @@ router.post( router.post( "documents.deleted", - auth({ member: true }), + auth({ role: UserRole.Member }), pagination(), validate(T.DocumentsDeletedSchema), async (ctx: APIContext) => { @@ -629,7 +629,7 @@ router.post( router.post( "documents.restore", - auth({ member: true }), + auth({ role: UserRole.Member }), validate(T.DocumentsRestoreSchema), async (ctx: APIContext) => { const { id, collectionId, revisionId } = ctx.input.body; @@ -904,7 +904,7 @@ router.post( router.post( "documents.templatize", - auth({ member: true }), + auth({ role: UserRole.Member }), rateLimiter(RateLimiterStrategy.TwentyFivePerMinute), validate(T.DocumentsTemplatizeSchema), transaction(), diff --git a/server/routes/api/fileOperations/fileOperations.ts b/server/routes/api/fileOperations/fileOperations.ts index 215c548bd..c20f2822f 100644 --- a/server/routes/api/fileOperations/fileOperations.ts +++ b/server/routes/api/fileOperations/fileOperations.ts @@ -1,5 +1,6 @@ import Router from "koa-router"; import { WhereOptions } from "sequelize"; +import { UserRole } from "@shared/types"; import fileOperationDeleter from "@server/commands/fileOperationDeleter"; import { ValidationError } from "@server/errors"; import auth from "@server/middlewares/authentication"; @@ -17,7 +18,7 @@ const router = new Router(); router.post( "fileOperations.info", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.FileOperationsInfoSchema), async (ctx: APIContext) => { const { id } = ctx.input.body; @@ -37,7 +38,7 @@ router.post( router.post( "fileOperations.list", - auth({ admin: true }), + auth({ role: UserRole.Admin }), pagination(), validate(T.FileOperationsListSchema), async (ctx: APIContext) => { @@ -91,20 +92,20 @@ const handleFileOperationsRedirect = async ( router.get( "fileOperations.redirect", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.FileOperationsRedirectSchema), handleFileOperationsRedirect ); router.post( "fileOperations.redirect", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.FileOperationsRedirectSchema), handleFileOperationsRedirect ); router.post( "fileOperations.delete", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.FileOperationsDeleteSchema), transaction(), async (ctx: APIContext) => { diff --git a/server/routes/api/integrations/integrations.ts b/server/routes/api/integrations/integrations.ts index 7c2002456..1ebc523f2 100644 --- a/server/routes/api/integrations/integrations.ts +++ b/server/routes/api/integrations/integrations.ts @@ -1,6 +1,6 @@ import Router from "koa-router"; import { WhereOptions, Op } from "sequelize"; -import { IntegrationType } from "@shared/types"; +import { IntegrationType, UserRole } from "@shared/types"; import auth from "@server/middlewares/authentication"; import { transaction } from "@server/middlewares/transaction"; import validate from "@server/middlewares/validate"; @@ -68,7 +68,7 @@ router.post( router.post( "integrations.create", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.IntegrationsCreateSchema), async (ctx: APIContext) => { const { type, service, settings } = ctx.input.body; @@ -113,7 +113,7 @@ router.post( router.post( "integrations.update", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.IntegrationsUpdateSchema), async (ctx: APIContext) => { const { id, events, settings } = ctx.input.body; diff --git a/server/routes/api/users/users.ts b/server/routes/api/users/users.ts index 9c1f26686..cccb85d7d 100644 --- a/server/routes/api/users/users.ts +++ b/server/routes/api/users/users.ts @@ -263,7 +263,7 @@ router.post( */ router.post( "users.promote", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.UsersPromoteSchema), transaction(), (ctx: APIContext) => { @@ -286,7 +286,7 @@ router.post( */ router.post( "users.demote", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.UsersDemoteSchema), transaction(), (ctx: APIContext) => { @@ -304,7 +304,7 @@ router.post( router.post( "users.update_role", - auth({ admin: true }), + auth({ role: UserRole.Admin }), validate(T.UsersChangeRoleSchema), transaction(), updateRole