Files
speckle-server/packages/server/modules/serverinvites/services/management.ts
T
Kristaps Fabians Geikins 37d51072fb feat(server): resource limits on app tokens (#1959)
* WIP new mutation arg

* limited resource token creation done

* token resource rule creation validation

* updated authorizeResolver implementation

* introduced resource access rule checks in authorizeResolver everywhere

* more checks added

* updated projects resolvers

* updated stream resolvers

* more checks added

* error page theme resolution fix

* WIP testss

* more tests

* implemented checks in REST auth pipeline

* REST API coverage & tests

* some tests fixed

* test fixess

* added tests

* feat(server): new automation result reporting scope (#1976)

* feat(server): new automation result reporting scope

* tests fix
2024-01-19 18:14:49 +01:00

95 lines
2.9 KiB
TypeScript

import { MaybeNullOrUndefined, Roles } from '@speckle/shared'
import {
MutationStreamInviteUseArgs,
ProjectInviteCreateInput,
ProjectInviteUseInput,
StreamInviteCreateInput,
TokenResourceIdentifier,
TokenResourceIdentifierType
} from '@/modules/core/graph/generated/graphql'
import { InviteCreateValidationError } from '@/modules/serverinvites/errors'
import {
buildUserTarget,
ResourceTargets
} from '@/modules/serverinvites/helpers/inviteHelper'
import { createAndSendInvite } from '@/modules/serverinvites/services/inviteCreationService'
import { has } from 'lodash'
import { finalizeStreamInvite } from '@/modules/serverinvites/services/inviteProcessingService'
import {
ContextResourceAccessRules,
isResourceAllowed
} from '@/modules/core/helpers/token'
import { StreamInvalidAccessError } from '@/modules/core/errors/stream'
type FullProjectInviteCreateInput = ProjectInviteCreateInput & { projectId: string }
const isStreamInviteCreateInput = (
i: StreamInviteCreateInput | FullProjectInviteCreateInput
): i is StreamInviteCreateInput => has(i, 'streamId')
export async function createStreamInviteAndNotify(
input: StreamInviteCreateInput | FullProjectInviteCreateInput,
inviterId: string,
inviterResourceAccessRules: MaybeNullOrUndefined<TokenResourceIdentifier[]>
) {
const { email, userId, role } = input
if (!email && !userId) {
throw new InviteCreateValidationError('Either email or userId must be specified')
}
const target = (userId ? buildUserTarget(userId) : email)!
await createAndSendInvite(
{
target,
inviterId,
resourceTarget: ResourceTargets.Streams,
resourceId: isStreamInviteCreateInput(input) ? input.streamId : input.projectId,
role: role || Roles.Stream.Contributor,
message: isStreamInviteCreateInput(input)
? input.message || undefined
: undefined,
serverRole: input.serverRole || undefined
},
inviterResourceAccessRules
)
}
const isStreamInviteUseArgs = (
i: MutationStreamInviteUseArgs | ProjectInviteUseInput
): i is MutationStreamInviteUseArgs => has(i, 'streamId')
export async function useStreamInviteAndNotify(
input: MutationStreamInviteUseArgs | ProjectInviteUseInput,
userId: string,
userResourceAccessRules: ContextResourceAccessRules
) {
const { accept, token } = input
if (
!isResourceAllowed({
resourceId: isStreamInviteUseArgs(input) ? input.streamId : input.projectId,
resourceType: TokenResourceIdentifierType.Project,
resourceAccessRules: userResourceAccessRules
})
) {
throw new StreamInvalidAccessError(
'You are not allowed to process an invite for this stream',
{
info: {
userId,
userResourceAccessRules,
input
}
}
)
}
await finalizeStreamInvite(
accept,
isStreamInviteUseArgs(input) ? input.streamId : input.projectId,
token,
userId
)
}