feat(authz): Workspace.canInvite and Project.canInvite (#4419)

This commit is contained in:
Chuck Driesler
2025-04-16 09:01:53 +01:00
committed by GitHub
parent e31f4c5a47
commit cebae959ae
10 changed files with 283 additions and 54 deletions
@@ -1,5 +1,8 @@
import { db } from '@/db/knex'
import { Resolvers } from '@/modules/core/graph/generated/graphql'
import {
Resolvers,
TokenResourceIdentifierType
} from '@/modules/core/graph/generated/graphql'
import { removePrivateFields } from '@/modules/core/helpers/userHelper'
import {
updateProjectFactory,
@@ -205,6 +208,7 @@ import {
getWorkspaceRolesAndSeatsFactory,
getWorkspaceUserSeatFactory
} from '@/modules/gatekeeper/repositories/workspaceSeat'
import { throwIfResourceAccessNotAllowed } from '@/modules/core/helpers/token'
import {
mapAuthToServerError,
throwIfAuthNotOk
@@ -368,12 +372,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
},
ProjectInviteMutations: {
async createForWorkspace(_parent, args, ctx) {
await authorizeResolver(
ctx.userId,
args.projectId,
Roles.Stream.Owner,
ctx.resourceAccessRules
)
const { projectId } = args
const inviteCount = args.inputs.length
if (inviteCount > 10 && ctx.role !== Roles.Server.Admin) {
@@ -382,6 +381,20 @@ export = FF_WORKSPACES_MODULE_ENABLED
)
}
throwIfResourceAccessNotAllowed({
resourceId: args.projectId,
resourceType: TokenResourceIdentifierType.Project,
resourceAccessRules: ctx.resourceAccessRules
})
const canInvite = await ctx.authPolicies.project.canInvite({
userId: ctx.userId,
projectId
})
if (!canInvite.isOk) {
throw mapAuthToServerError(canInvite.error)
}
const createProjectInvite = createProjectInviteFactory({
createAndSendInvite: buildCreateAndSendServerOrProjectInvite(),
getStream
@@ -838,12 +851,19 @@ export = FF_WORKSPACES_MODULE_ENABLED
input: { inviteId, workspaceId }
} = args
await authorizeResolver(
ctx.userId!,
workspaceId,
Roles.Workspace.Admin,
ctx.resourceAccessRules
)
throwIfResourceAccessNotAllowed({
resourceId: workspaceId,
resourceType: TokenResourceIdentifierType.Workspace,
resourceAccessRules: ctx.resourceAccessRules
})
const canInvite = await ctx.authPolicies.workspace.canInvite({
userId: ctx.userId,
workspaceId
})
if (!canInvite.isOk) {
throw mapAuthToServerError(canInvite.error)
}
const resendInviteEmail = resendInviteEmailFactory({
buildInviteEmailContents: buildWorkspaceInviteEmailContentsFactory({
@@ -871,6 +891,22 @@ export = FF_WORKSPACES_MODULE_ENABLED
return true
},
create: async (_parent, args, ctx) => {
const { workspaceId } = args
throwIfResourceAccessNotAllowed({
resourceId: workspaceId,
resourceType: TokenResourceIdentifierType.Workspace,
resourceAccessRules: ctx.resourceAccessRules
})
const canInvite = await ctx.authPolicies.workspace.canInvite({
userId: ctx.userId,
workspaceId
})
if (!canInvite.isOk) {
throw mapAuthToServerError(canInvite.error)
}
const createInvite = createWorkspaceInviteFactory({
createAndSendInvite: buildCreateAndSendWorkspaceInvite()
})
@@ -884,6 +920,8 @@ export = FF_WORKSPACES_MODULE_ENABLED
return ctx.loaders.workspaces!.getWorkspace.load(args.workspaceId)
},
batchCreate: async (_parent, args, ctx) => {
const { workspaceId } = args
const inviteCount = args.input.length
if (inviteCount > 10 && ctx.role !== Roles.Server.Admin) {
throw new InviteCreateValidationError(
@@ -891,6 +929,20 @@ export = FF_WORKSPACES_MODULE_ENABLED
)
}
throwIfResourceAccessNotAllowed({
resourceId: workspaceId,
resourceType: TokenResourceIdentifierType.Workspace,
resourceAccessRules: ctx.resourceAccessRules
})
const canInvite = await ctx.authPolicies.workspace.canInvite({
userId: ctx.userId,
workspaceId
})
if (!canInvite.isOk) {
throw mapAuthToServerError(canInvite.error)
}
const createInvite = createWorkspaceInviteFactory({
createAndSendInvite: buildCreateAndSendWorkspaceInvite()
})
@@ -970,12 +1022,21 @@ export = FF_WORKSPACES_MODULE_ENABLED
return true
},
cancel: async (_parent, args, ctx) => {
await authorizeResolver(
ctx.userId,
args.workspaceId,
Roles.Workspace.Admin,
ctx.resourceAccessRules
)
const { workspaceId } = args
throwIfResourceAccessNotAllowed({
resourceId: workspaceId,
resourceType: TokenResourceIdentifierType.Workspace,
resourceAccessRules: ctx.resourceAccessRules
})
const canInvite = await ctx.authPolicies.workspace.canInvite({
userId: ctx.userId,
workspaceId
})
if (!canInvite.isOk) {
throw mapAuthToServerError(canInvite.error)
}
const cancelInvite = cancelResourceInviteFactory({
findInvite: findInviteFactory({