import { PermissionStructure } from '@axinom/mosaic-id-utils'; import { MosaicError, MosaicErrors, ensureError, } from '@axinom/mosaic-service-common'; import { getGqlClient } from '../common/gql-client'; import { IdLinkBeErrors } from '../common/id-link-be-errors'; import { ServiceAccountResult } from '../common/types'; import { DevDeleteServiceAccountDocument, DevDeleteServiceAccountMutation, DevDeleteServiceAccountMutationVariables, DevSetupServiceAccountWithPermissionsDocument, DevSetupServiceAccountWithPermissionsMutation, DevSetupServiceAccountWithPermissionsMutationVariables, UpdateServiceAccountDocument, UpdateServiceAccountMutation, UpdateServiceAccountMutationVariables, } from '../generated/graphql.types'; import { getWellKnownEndpoints } from '../well-known-endpoints'; /** * This function setups a new Service Account with a given permission structure. Depending on the param enforceValidPermissionStructure, if * any invalid permission(s) exists, the method will throw an error. * * @param authEndpoint URL for id-service authEndpoint. * @param accessToken A valid token with permission for DEV_SETUP_SERVICE_ACCOUNT_WITH_PERMISSIONS granted. * @param serviceAccountName Name of the new service account. * @param permissions The list of permissions to be assigned to the new service account. This is an array of shape {serviceId: string, permissions: string[]}. * @param enforceValidPermissionStructure A boolean indicating if the permissions passed should be validated against existing permissions. * @returns {ServiceAccountResult} Client ID and Client Secret. */ export const devSetupServiceAccountWithPermissions = async ( authEndpoint: string, accessToken: string, serviceAccountName: string, permissions: PermissionStructure[], enforceValidPermissionStructure = true, ): Promise => { try { // Authenticate using the token const client = getGqlClient( (await getWellKnownEndpoints(authEndpoint)).authGraphQlEndpoint, accessToken, ); const result = await client.mutate< DevSetupServiceAccountWithPermissionsMutation, DevSetupServiceAccountWithPermissionsMutationVariables >({ mutation: DevSetupServiceAccountWithPermissionsDocument, variables: { input: { serviceAccountName: serviceAccountName, permissionStructure: permissions, enforceValidPermissionStructure: enforceValidPermissionStructure, }, }, errorPolicy: 'all', fetchPolicy: 'no-cache', }); if (!result.errors) { if (result.data?.devSetupServiceAccountWithPermissions) { const serviceAccountResult: ServiceAccountResult = { clientId: result.data.devSetupServiceAccountWithPermissions.clientId, clientSecret: result.data.devSetupServiceAccountWithPermissions.clientSecret, }; return serviceAccountResult; } throw new MosaicError({ code: MosaicErrors.UnexpectedNullUndefined.code, message: `Unexpected null or undefined value received for 'devSetupServiceAccountWithPermissions' result.`, }); } else { const aggregatedErrorMessage = result.errors?.reduce( (aggregatedError, gqlError) => { return (aggregatedError += gqlError.message); }, '', ); throw new MosaicError({ ...IdLinkBeErrors.ServiceAccountSetupError, details: { originalError: aggregatedErrorMessage, }, }); } } catch (e) { const error = ensureError(e); throw new MosaicError({ ...IdLinkBeErrors.ServiceAccountSetupError, details: { originalError: error.message, }, }); } }; /** * This function deletes an existing Service Account given the Client ID. * * @param authEndpoint URL for id-service authEndpoint. * @param accessToken A valid token with permission for DEV_SETUP_SERVICE_ACCOUNT_WITH_PERMISSIONS granted. * @param clientId Client ID of the Service Account to be deleted. * @returns */ export const devDeleteServiceAccount = async ( authEndpoint: string, accessToken: string, clientId: string, ): Promise => { try { // Authenticate using the token const client = getGqlClient( (await getWellKnownEndpoints(authEndpoint)).authGraphQlEndpoint, accessToken, ); const result = await client.mutate< DevDeleteServiceAccountMutation, DevDeleteServiceAccountMutationVariables >({ mutation: DevDeleteServiceAccountDocument, variables: { input: { clientId, }, }, errorPolicy: 'all', fetchPolicy: 'no-cache', }); if (!result.errors) { if (result.data?.devDeleteServiceAccount) { return result.data?.devDeleteServiceAccount.isSuccess; } throw new MosaicError({ code: MosaicErrors.UnexpectedNullUndefined.code, message: `Unexpected null or undefined value received for 'devDeleteServiceAccount' result.`, }); } else { const aggregatedErrorMessage = result.errors?.reduce( (aggregatedError, gqlError) => { return (aggregatedError += gqlError.message); }, '', ); throw new MosaicError({ ...IdLinkBeErrors.ServiceAccountSetupError, details: { originalError: aggregatedErrorMessage, }, }); } } catch (e) { const error = ensureError(e); throw new MosaicError({ ...IdLinkBeErrors.ServiceAccountSetupError, details: { originalError: error.message, }, }); } }; /** * Update the name of an existing Service Account. * * @param name * @param authEndpoint * @param accessToken * @param clientId * @returns */ export const updateServiceAccount = async ( name: string, authEndpoint: string, accessToken: string, clientId: string, ): Promise => { try { // Authenticate using the token const client = getGqlClient( (await getWellKnownEndpoints(authEndpoint)).authGraphQlEndpoint, accessToken, ); const result = await client.mutate< UpdateServiceAccountMutation, UpdateServiceAccountMutationVariables >({ mutation: UpdateServiceAccountDocument, variables: { input: { patch: { name }, clientId, }, }, errorPolicy: 'all', fetchPolicy: 'no-cache', }); if (!result.errors) { if (result.data?.updateServiceAccount) { return result.data?.updateServiceAccount.isSuccess; } throw new MosaicError({ code: MosaicErrors.UnexpectedNullUndefined.code, message: `Unexpected null or undefined value received for 'updateServiceAccount' result.`, }); } else { const aggregatedErrorMessage = result.errors?.reduce( (aggregatedError, gqlError) => { return (aggregatedError += gqlError.message); }, '', ); throw new MosaicError({ ...IdLinkBeErrors.ServiceAccountSetupError, details: { originalError: aggregatedErrorMessage, }, }); } } catch (e) { const error = ensureError(e); throw new MosaicError({ ...IdLinkBeErrors.ServiceAccountSetupError, details: { originalError: error.message, }, }); } };