From ddf657669f35de404f7ba437b7a73f969daa0606 Mon Sep 17 00:00:00 2001 From: Weiko Date: Wed, 27 May 2026 19:19:17 +0200 Subject: [PATCH] use auth context guard + move build auth context logic from middleware to shared util --- .../workspace-auth-context.middleware.ts | 60 ++++++------------- .../build-workspace-auth-context.util.ts | 55 +++++++++++++++++ .../triggers/route/route-trigger.service.ts | 38 ++++++------ 3 files changed, 89 insertions(+), 64 deletions(-) create mode 100644 packages/twenty-server/src/engine/core-modules/auth/utils/build-workspace-auth-context.util.ts diff --git a/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts b/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts index bb1c0a992c6..0f46b4e4150 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts @@ -9,10 +9,7 @@ import { } from 'src/engine/core-modules/auth/auth.exception'; import { withWorkspaceAuthContext } from 'src/engine/core-modules/auth/storage/workspace-auth-context.storage'; import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; -import { buildApiKeyAuthContext } from 'src/engine/core-modules/auth/utils/build-api-key-auth-context.util'; -import { buildApplicationAuthContext } from 'src/engine/core-modules/auth/utils/build-application-auth-context.util'; -import { buildPendingActivationUserAuthContext } from 'src/engine/core-modules/auth/utils/build-pending-activation-user-auth-context.util'; -import { buildUserAuthContext } from 'src/engine/core-modules/auth/utils/build-user-auth-context.util'; +import { buildWorkspaceAuthContext } from 'src/engine/core-modules/auth/utils/build-workspace-auth-context.util'; import { applyWorkspaceSentryContext } from 'src/engine/core-modules/sentry/utils/apply-workspace-sentry-context.util'; @Injectable() @@ -34,46 +31,23 @@ export class WorkspaceAuthContextMiddleware implements NestMiddleware { } private buildAuthContext(req: Request): WorkspaceAuthContext { - if (isDefined(req.apiKey)) { - return buildApiKeyAuthContext({ - workspace: req.workspace!, - apiKey: req.apiKey, - }); + const authContext = buildWorkspaceAuthContext({ + workspace: req.workspace, + apiKey: req.apiKey, + userWorkspaceId: req.userWorkspaceId, + workspaceMemberId: req.workspaceMemberId, + workspaceMember: req.workspaceMember, + user: req.user, + application: req.application, + }); + + if (!isDefined(authContext)) { + throw new AuthException( + 'No authentication context found', + AuthExceptionCode.UNAUTHENTICATED, + ); } - if ( - isDefined(req.userWorkspaceId) && - isDefined(req.workspaceMemberId) && - isDefined(req.workspaceMember) && - isDefined(req.user) - ) { - return buildUserAuthContext({ - workspace: req.workspace!, - userWorkspaceId: req.userWorkspaceId, - user: req.user, - workspaceMemberId: req.workspaceMemberId, - workspaceMember: req.workspaceMember, - }); - } - - if (isDefined(req.application)) { - return buildApplicationAuthContext({ - workspace: req.workspace!, - application: req.application, - }); - } - - if (isDefined(req.userWorkspaceId) && isDefined(req.user)) { - return buildPendingActivationUserAuthContext({ - workspace: req.workspace!, - userWorkspaceId: req.userWorkspaceId, - user: req.user, - }); - } - - throw new AuthException( - 'No authentication context found', - AuthExceptionCode.UNAUTHENTICATED, - ); + return authContext; } } diff --git a/packages/twenty-server/src/engine/core-modules/auth/utils/build-workspace-auth-context.util.ts b/packages/twenty-server/src/engine/core-modules/auth/utils/build-workspace-auth-context.util.ts new file mode 100644 index 00000000000..d1309cde299 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/utils/build-workspace-auth-context.util.ts @@ -0,0 +1,55 @@ +import { isDefined } from 'twenty-shared/utils'; + +import { type RawAuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; +import { buildApiKeyAuthContext } from 'src/engine/core-modules/auth/utils/build-api-key-auth-context.util'; +import { buildApplicationAuthContext } from 'src/engine/core-modules/auth/utils/build-application-auth-context.util'; +import { buildPendingActivationUserAuthContext } from 'src/engine/core-modules/auth/utils/build-pending-activation-user-auth-context.util'; +import { buildUserAuthContext } from 'src/engine/core-modules/auth/utils/build-user-auth-context.util'; + +export const buildWorkspaceAuthContext = ( + authContext: RawAuthContext, +): WorkspaceAuthContext | null => { + if (!isDefined(authContext.workspace)) { + return null; + } + + if (isDefined(authContext.apiKey)) { + return buildApiKeyAuthContext({ + workspace: authContext.workspace, + apiKey: authContext.apiKey, + }); + } + + if ( + isDefined(authContext.userWorkspaceId) && + isDefined(authContext.workspaceMemberId) && + isDefined(authContext.workspaceMember) && + isDefined(authContext.user) + ) { + return buildUserAuthContext({ + workspace: authContext.workspace, + userWorkspaceId: authContext.userWorkspaceId, + user: authContext.user, + workspaceMemberId: authContext.workspaceMemberId, + workspaceMember: authContext.workspaceMember, + }); + } + + if (isDefined(authContext.application)) { + return buildApplicationAuthContext({ + workspace: authContext.workspace, + application: authContext.application, + }); + } + + if (isDefined(authContext.userWorkspaceId) && isDefined(authContext.user)) { + return buildPendingActivationUserAuthContext({ + workspace: authContext.workspace, + userWorkspaceId: authContext.userWorkspaceId, + user: authContext.user, + }); + } + + return null; +}; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service.ts index 6a6192ef594..2c67f0736c4 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service.ts @@ -9,6 +9,7 @@ import { HTTPMethod } from 'twenty-shared/types'; import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { buildWorkspaceAuthContext } from 'src/engine/core-modules/auth/utils/build-workspace-auth-context.util'; import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service'; import { RouteTriggerException, @@ -25,6 +26,8 @@ import { LogicFunctionExecutionExceptionCode, LogicFunctionExecutorService, } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service'; +import { getRoleIdFromRolePermissionConfig } from 'src/engine/twenty-orm/utils/get-role-id-from-role-permission-config.util'; +import { resolveRolePermissionConfig } from 'src/engine/twenty-orm/utils/resolve-role-permission-config.util'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; import { CustomException } from 'src/utils/custom-exception'; @@ -48,32 +51,25 @@ export class RouteTriggerService { authContext: AuthContext; workspaceId: string; }): Promise { - if (isDefined(authContext.apiKey)) { - const { apiKeyRoleMap } = await this.workspaceCacheService.getOrRecompute( - workspaceId, - ['apiKeyRoleMap'], - ); + const workspaceAuthContext = buildWorkspaceAuthContext(authContext); - return apiKeyRoleMap[authContext.apiKey.id]; + if (!isDefined(workspaceAuthContext)) { + return undefined; } - if ( - isDefined(authContext.application) && - isDefined(authContext.application.defaultRoleId) - ) { - return authContext.application.defaultRoleId; - } + const { userWorkspaceRoleMap, apiKeyRoleMap } = + await this.workspaceCacheService.getOrRecompute(workspaceId, [ + 'userWorkspaceRoleMap', + 'apiKeyRoleMap', + ]); - if (isDefined(authContext.userWorkspaceId)) { - const { userWorkspaceRoleMap } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'userWorkspaceRoleMap', - ]); + const rolePermissionConfig = resolveRolePermissionConfig({ + authContext: workspaceAuthContext, + userWorkspaceRoleMap, + apiKeyRoleMap, + }); - return userWorkspaceRoleMap[authContext.userWorkspaceId]; - } - - return undefined; + return getRoleIdFromRolePermissionConfig(rolePermissionConfig); } private async getLogicFunctionWithPathParamsOrFail({