@contember/engine-tenant-api 1.3.0-alpha.8 → 1.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/TenantContainer.d.ts +17 -3
- package/dist/src/TenantContainer.d.ts.map +1 -1
- package/dist/src/TenantContainer.js +7 -0
- package/dist/src/TenantContainer.js.map +1 -1
- package/dist/src/bridges/system/IdentityFetcher.d.ts +1 -1
- package/dist/src/bridges/system/IdentityFetcher.d.ts.map +1 -1
- package/dist/src/migrations/2023-01-20-135500-person-email-normalize.d.ts +3 -0
- package/dist/src/migrations/2023-01-20-135500-person-email-normalize.d.ts.map +1 -0
- package/dist/src/migrations/2023-01-20-135500-person-email-normalize.js +28 -0
- package/dist/src/migrations/2023-01-20-135500-person-email-normalize.js.map +1 -0
- package/dist/src/migrations/2023-06-03-104000-person-disabled.d.ts +3 -0
- package/dist/src/migrations/2023-06-03-104000-person-disabled.d.ts.map +1 -0
- package/dist/src/migrations/2023-06-03-104000-person-disabled.js +11 -0
- package/dist/src/migrations/2023-06-03-104000-person-disabled.js.map +1 -0
- package/dist/src/migrations/runner.d.ts.map +1 -1
- package/dist/src/migrations/runner.js +4 -0
- package/dist/src/migrations/runner.js.map +1 -1
- package/dist/src/migrations/snapshot.d.ts.map +1 -1
- package/dist/src/migrations/snapshot.js +1 -0
- package/dist/src/migrations/snapshot.js.map +1 -1
- package/dist/src/model/authorization/AclSchemaAccessNodeFactory.d.ts.map +1 -1
- package/dist/src/model/authorization/AclSchemaAccessNodeFactory.js +14 -9
- package/dist/src/model/authorization/AclSchemaAccessNodeFactory.js.map +1 -1
- package/dist/src/model/authorization/MembershipMatcher.d.ts +1 -1
- package/dist/src/model/authorization/MembershipMatcher.d.ts.map +1 -1
- package/dist/src/model/authorization/PermissionActions.d.ts +21 -0
- package/dist/src/model/authorization/PermissionActions.d.ts.map +1 -1
- package/dist/src/model/authorization/PermissionActions.js +4 -2
- package/dist/src/model/authorization/PermissionActions.js.map +1 -1
- package/dist/src/model/authorization/PermissionContext.d.ts +1 -1
- package/dist/src/model/authorization/PermissionContext.d.ts.map +1 -1
- package/dist/src/model/authorization/PermissionsFactory.d.ts.map +1 -1
- package/dist/src/model/authorization/PermissionsFactory.js +6 -3
- package/dist/src/model/authorization/PermissionsFactory.js.map +1 -1
- package/dist/src/model/authorization/Roles.js +1 -1
- package/dist/src/model/authorization/Roles.js.map +1 -1
- package/dist/src/model/commands/apiKey/CreateApiKeyCommand.d.ts +1 -1
- package/dist/src/model/commands/apiKey/CreateApiKeyCommand.d.ts.map +1 -1
- package/dist/src/model/commands/identity/PatchIdentityGlobalRoles.d.ts +9 -0
- package/dist/src/model/commands/identity/PatchIdentityGlobalRoles.d.ts.map +1 -0
- package/dist/src/model/commands/identity/PatchIdentityGlobalRoles.js +29 -0
- package/dist/src/model/commands/identity/PatchIdentityGlobalRoles.js.map +1 -0
- package/dist/src/model/commands/identity/index.d.ts +1 -0
- package/dist/src/model/commands/identity/index.d.ts.map +1 -1
- package/dist/src/model/commands/identity/index.js +1 -0
- package/dist/src/model/commands/identity/index.js.map +1 -1
- package/dist/src/model/commands/idp/UpdateIdpCommand.d.ts +1 -1
- package/dist/src/model/commands/idp/UpdateIdpCommand.d.ts.map +1 -1
- package/dist/src/model/commands/membership/AddProjectMemberCommand.d.ts +2 -6
- package/dist/src/model/commands/membership/AddProjectMemberCommand.d.ts.map +1 -1
- package/dist/src/model/commands/membership/AddProjectMemberCommand.js +5 -11
- package/dist/src/model/commands/membership/AddProjectMemberCommand.js.map +1 -1
- package/dist/src/model/commands/membership/RemoveProjectMemberCommand.d.ts +1 -1
- package/dist/src/model/commands/membership/RemoveProjectMemberCommand.d.ts.map +1 -1
- package/dist/src/model/commands/membership/RemoveProjectMemberCommand.js +1 -2
- package/dist/src/model/commands/membership/RemoveProjectMemberCommand.js.map +1 -1
- package/dist/src/model/commands/membership/UpdateProjectMemberCommand.d.ts +1 -1
- package/dist/src/model/commands/membership/UpdateProjectMemberCommand.d.ts.map +1 -1
- package/dist/src/model/commands/membership/UpdateProjectMemberCommand.js +2 -3
- package/dist/src/model/commands/membership/UpdateProjectMemberCommand.js.map +1 -1
- package/dist/src/model/commands/membership/types.d.ts +3 -3
- package/dist/src/model/commands/membership/types.d.ts.map +1 -1
- package/dist/src/model/commands/passwordReset/ResetPasswordCommand.d.ts +2 -6
- package/dist/src/model/commands/passwordReset/ResetPasswordCommand.d.ts.map +1 -1
- package/dist/src/model/commands/passwordReset/ResetPasswordCommand.js +5 -11
- package/dist/src/model/commands/passwordReset/ResetPasswordCommand.js.map +1 -1
- package/dist/src/model/commands/person/CreatePersonCommand.d.ts.map +1 -1
- package/dist/src/model/commands/person/CreatePersonCommand.js +10 -5
- package/dist/src/model/commands/person/CreatePersonCommand.js.map +1 -1
- package/dist/src/model/commands/person/DisablePersonCommand.d.ts +7 -0
- package/dist/src/model/commands/person/DisablePersonCommand.d.ts.map +1 -0
- package/dist/src/model/commands/person/DisablePersonCommand.js +22 -0
- package/dist/src/model/commands/person/DisablePersonCommand.js.map +1 -0
- package/dist/src/model/dtos/Password.d.ts +1 -1
- package/dist/src/model/dtos/Password.d.ts.map +1 -1
- package/dist/src/model/mailing/type.js +1 -1
- package/dist/src/model/mailing/type.js.map +1 -1
- package/dist/src/model/queries/apiKey/ApiKeyQuery.d.ts +23 -0
- package/dist/src/model/queries/apiKey/ApiKeyQuery.d.ts.map +1 -0
- package/dist/src/model/queries/apiKey/ApiKeyQuery.js +45 -0
- package/dist/src/model/queries/apiKey/ApiKeyQuery.js.map +1 -0
- package/dist/src/model/queries/apiKey/index.d.ts +1 -1
- package/dist/src/model/queries/apiKey/index.d.ts.map +1 -1
- package/dist/src/model/queries/apiKey/index.js +1 -1
- package/dist/src/model/queries/apiKey/index.js.map +1 -1
- package/dist/src/model/queries/idp/types.d.ts +4 -4
- package/dist/src/model/queries/idp/types.d.ts.map +1 -1
- package/dist/src/model/queries/membership/ProjectMembersQuery.d.ts +1 -1
- package/dist/src/model/queries/membership/ProjectMembersQuery.d.ts.map +1 -1
- package/dist/src/model/queries/membership/ProjectMembersQuery.js +3 -4
- package/dist/src/model/queries/membership/ProjectMembersQuery.js.map +1 -1
- package/dist/src/model/queries/person/PersonQuery.d.ts +4 -3
- package/dist/src/model/queries/person/PersonQuery.d.ts.map +1 -1
- package/dist/src/model/queries/person/PersonQuery.js +22 -0
- package/dist/src/model/queries/person/PersonQuery.js.map +1 -1
- package/dist/src/model/queries/person/PersonQueryBuilderFactory.d.ts.map +1 -1
- package/dist/src/model/queries/person/PersonQueryBuilderFactory.js +1 -0
- package/dist/src/model/queries/person/PersonQueryBuilderFactory.js.map +1 -1
- package/dist/src/model/queries/person/types.d.ts +4 -3
- package/dist/src/model/queries/person/types.d.ts.map +1 -1
- package/dist/src/model/queries/project/ProjectSecretsQuery.d.ts +1 -1
- package/dist/src/model/queries/project/ProjectSecretsQuery.d.ts.map +1 -1
- package/dist/src/model/service/IDPSignInManager.d.ts.map +1 -1
- package/dist/src/model/service/IDPSignInManager.js +8 -6
- package/dist/src/model/service/IDPSignInManager.js.map +1 -1
- package/dist/src/model/service/InviteManager.d.ts +1 -1
- package/dist/src/model/service/InviteManager.d.ts.map +1 -1
- package/dist/src/model/service/InviteManager.js +2 -3
- package/dist/src/model/service/InviteManager.js.map +1 -1
- package/dist/src/model/service/OtpAuthenticator.d.ts +1 -1
- package/dist/src/model/service/OtpAuthenticator.d.ts.map +1 -1
- package/dist/src/model/service/PasswordChangeManager.js +4 -5
- package/dist/src/model/service/PasswordChangeManager.js.map +1 -1
- package/dist/src/model/service/PasswordResetManager.d.ts +2 -4
- package/dist/src/model/service/PasswordResetManager.d.ts.map +1 -1
- package/dist/src/model/service/PasswordResetManager.js +2 -6
- package/dist/src/model/service/PasswordResetManager.js.map +1 -1
- package/dist/src/model/service/PersonAccessManager.d.ts +14 -0
- package/dist/src/model/service/PersonAccessManager.d.ts.map +1 -0
- package/dist/src/model/service/PersonAccessManager.js +42 -0
- package/dist/src/model/service/PersonAccessManager.js.map +1 -0
- package/dist/src/model/service/PersonManager.d.ts +7 -0
- package/dist/src/model/service/PersonManager.d.ts.map +1 -0
- package/dist/src/model/service/PersonManager.js +11 -0
- package/dist/src/model/service/PersonManager.js.map +1 -0
- package/dist/src/model/service/ProjectManager.d.ts +1 -1
- package/dist/src/model/service/ProjectManager.d.ts.map +1 -1
- package/dist/src/model/service/ProjectManager.js +2 -3
- package/dist/src/model/service/ProjectManager.js.map +1 -1
- package/dist/src/model/service/ProjectMemberManager.d.ts +2 -2
- package/dist/src/model/service/ProjectMemberManager.d.ts.map +1 -1
- package/dist/src/model/service/ProjectMemberManager.js +3 -16
- package/dist/src/model/service/ProjectMemberManager.js.map +1 -1
- package/dist/src/model/service/RolesManager.d.ts +11 -0
- package/dist/src/model/service/RolesManager.d.ts.map +1 -0
- package/dist/src/model/service/RolesManager.js +35 -0
- package/dist/src/model/service/RolesManager.js.map +1 -0
- package/dist/src/model/service/SignInManager.d.ts +2 -2
- package/dist/src/model/service/SignInManager.d.ts.map +1 -1
- package/dist/src/model/service/SignInManager.js +13 -8
- package/dist/src/model/service/SignInManager.js.map +1 -1
- package/dist/src/model/service/SignUpManager.d.ts +2 -2
- package/dist/src/model/service/SignUpManager.d.ts.map +1 -1
- package/dist/src/model/service/SignUpManager.js +2 -3
- package/dist/src/model/service/SignUpManager.js.map +1 -1
- package/dist/src/model/service/apiKey/ApiKeyManager.d.ts +3 -1
- package/dist/src/model/service/apiKey/ApiKeyManager.d.ts.map +1 -1
- package/dist/src/model/service/apiKey/ApiKeyManager.js +4 -1
- package/dist/src/model/service/apiKey/ApiKeyManager.js.map +1 -1
- package/dist/src/model/service/apiKey/ApiKeyService.d.ts +1 -1
- package/dist/src/model/service/apiKey/ApiKeyService.d.ts.map +1 -1
- package/dist/src/model/service/idp/IDPManager.d.ts +4 -4
- package/dist/src/model/service/idp/IDPManager.d.ts.map +1 -1
- package/dist/src/model/service/idp/IDPManager.js +7 -8
- package/dist/src/model/service/idp/IDPManager.js.map +1 -1
- package/dist/src/model/service/idp/providers/AppleProvider.d.ts +1 -1
- package/dist/src/model/service/idp/providers/AppleProvider.d.ts.map +1 -1
- package/dist/src/model/service/idp/providers/FacebookProvider.d.ts +1 -1
- package/dist/src/model/service/idp/providers/FacebookProvider.d.ts.map +1 -1
- package/dist/src/model/service/idp/providers/OIDCTypes.d.ts +3 -3
- package/dist/src/model/service/idp/providers/OIDCTypes.d.ts.map +1 -1
- package/dist/src/model/service/index.d.ts +2 -0
- package/dist/src/model/service/index.d.ts.map +1 -1
- package/dist/src/model/service/index.js +2 -0
- package/dist/src/model/service/index.js.map +1 -1
- package/dist/src/model/type/Variables.d.ts +1 -1
- package/dist/src/model/type/Variables.d.ts.map +1 -1
- package/dist/src/model/utils/Response.d.ts +2 -2
- package/dist/src/model/utils/Response.d.ts.map +1 -1
- package/dist/src/model/utils/email.d.ts +2 -0
- package/dist/src/model/utils/email.d.ts.map +1 -0
- package/dist/src/model/utils/email.js +8 -0
- package/dist/src/model/utils/email.js.map +1 -0
- package/dist/src/model/utils/tokenUtils.d.ts +1 -1
- package/dist/src/model/utils/tokenUtils.d.ts.map +1 -1
- package/dist/src/model/utils/typeUtils.d.ts +1 -1
- package/dist/src/model/utils/typeUtils.d.ts.map +1 -1
- package/dist/src/resolvers/ResolverFactory.d.ts +4 -1
- package/dist/src/resolvers/ResolverFactory.d.ts.map +1 -1
- package/dist/src/resolvers/ResolverFactory.js +3 -0
- package/dist/src/resolvers/ResolverFactory.js.map +1 -1
- package/dist/src/resolvers/errorUtils.d.ts +3 -3
- package/dist/src/resolvers/errorUtils.d.ts.map +1 -1
- package/dist/src/resolvers/errorUtils.js.map +1 -1
- package/dist/src/resolvers/membershipUtils.d.ts +4 -9
- package/dist/src/resolvers/membershipUtils.d.ts.map +1 -1
- package/dist/src/resolvers/membershipUtils.js +10 -18
- package/dist/src/resolvers/membershipUtils.js.map +1 -1
- package/dist/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.js +1 -2
- package/dist/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.js +1 -2
- package/dist/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/identity/GlobalRolesMutationResolver.d.ts +11 -0
- package/dist/src/resolvers/mutation/identity/GlobalRolesMutationResolver.d.ts.map +1 -0
- package/dist/src/resolvers/mutation/identity/GlobalRolesMutationResolver.js +44 -0
- package/dist/src/resolvers/mutation/identity/GlobalRolesMutationResolver.js.map +1 -0
- package/dist/src/resolvers/mutation/identity/index.d.ts +2 -0
- package/dist/src/resolvers/mutation/identity/index.d.ts.map +1 -0
- package/dist/src/resolvers/mutation/identity/index.js +18 -0
- package/dist/src/resolvers/mutation/identity/index.js.map +1 -0
- package/dist/src/resolvers/mutation/index.d.ts +1 -0
- package/dist/src/resolvers/mutation/index.d.ts.map +1 -1
- package/dist/src/resolvers/mutation/index.js +1 -0
- package/dist/src/resolvers/mutation/index.js.map +1 -1
- package/dist/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.js +6 -7
- package/dist/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/person/ChangePasswordMutationResolver.js +2 -3
- package/dist/src/resolvers/mutation/person/ChangePasswordMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/person/DisablePersonMutationResolver.d.ts +11 -0
- package/dist/src/resolvers/mutation/person/DisablePersonMutationResolver.d.ts.map +1 -0
- package/dist/src/resolvers/mutation/person/DisablePersonMutationResolver.js +36 -0
- package/dist/src/resolvers/mutation/person/DisablePersonMutationResolver.js.map +1 -0
- package/dist/src/resolvers/mutation/person/InviteMutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/mutation/person/InviteMutationResolver.js +3 -4
- package/dist/src/resolvers/mutation/person/InviteMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/person/OtpMutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/mutation/person/OtpMutationResolver.js +3 -4
- package/dist/src/resolvers/mutation/person/OtpMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/person/ResetPasswordMutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/mutation/person/ResetPasswordMutationResolver.js +2 -10
- package/dist/src/resolvers/mutation/person/ResetPasswordMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/person/SignInMutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/mutation/person/SignInMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/person/SignOutMutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/mutation/person/SignOutMutationResolver.js +5 -2
- package/dist/src/resolvers/mutation/person/SignOutMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/project/CreateProjectMutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/mutation/project/CreateProjectMutationResolver.js +1 -2
- package/dist/src/resolvers/mutation/project/CreateProjectMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/project/SetProjectSecretMutationResolver.js +1 -2
- package/dist/src/resolvers/mutation/project/SetProjectSecretMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/project/UpdateProjectMutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/mutation/project/UpdateProjectMutationResolver.js +1 -2
- package/dist/src/resolvers/mutation/project/UpdateProjectMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.js +1 -2
- package/dist/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.js +1 -2
- package/dist/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.js.map +1 -1
- package/dist/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.js +1 -2
- package/dist/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.js.map +1 -1
- package/dist/src/resolvers/types/ProjectTypeResolver.d.ts.map +1 -1
- package/dist/src/resolvers/types/ProjectTypeResolver.js +5 -6
- package/dist/src/resolvers/types/ProjectTypeResolver.js.map +1 -1
- package/dist/src/schema/index.d.ts +431 -397
- package/dist/src/schema/index.d.ts.map +1 -1
- package/dist/src/schema/index.js +0 -188
- package/dist/src/schema/index.js.map +1 -1
- package/dist/src/schema/tenant.graphql.d.ts.map +1 -1
- package/dist/src/schema/tenant.graphql.js +97 -21
- package/dist/src/schema/tenant.graphql.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/utils/Mailer.d.ts +1 -1
- package/dist/src/utils/Mailer.d.ts.map +1 -1
- package/dist/src/utils/array.d.ts +1 -1
- package/dist/src/utils/array.d.ts.map +1 -1
- package/dist/src/utils/batchQuery.d.ts +2 -2
- package/dist/src/utils/batchQuery.d.ts.map +1 -1
- package/dist/tests/cases/integration/db/updateRoles.test.d.ts +2 -0
- package/dist/tests/cases/integration/db/updateRoles.test.d.ts.map +1 -0
- package/dist/tests/cases/integration/db/updateRoles.test.js +67 -0
- package/dist/tests/cases/integration/db/updateRoles.test.js.map +1 -0
- package/dist/tests/cases/integration/mocked/confirmOtpMutation.test.js +1 -2
- package/dist/tests/cases/integration/mocked/confirmOtpMutation.test.js.map +1 -1
- package/dist/tests/cases/integration/mocked/gql/signUp.d.ts.map +1 -1
- package/dist/tests/cases/integration/mocked/gql/signUp.js +4 -0
- package/dist/tests/cases/integration/mocked/gql/signUp.js.map +1 -1
- package/dist/tests/cases/integration/mocked/gql/types.d.ts +1 -1
- package/dist/tests/cases/integration/mocked/gql/types.d.ts.map +1 -1
- package/dist/tests/cases/integration/mocked/signInMutation.test.js +36 -4
- package/dist/tests/cases/integration/mocked/signInMutation.test.js.map +1 -1
- package/dist/tests/cases/integration/mocked/signOutMutation.test.js +53 -0
- package/dist/tests/cases/integration/mocked/signOutMutation.test.js.map +1 -1
- package/dist/tests/cases/integration/mocked/signUpMutation.test.js +9 -0
- package/dist/tests/cases/integration/mocked/signUpMutation.test.js.map +1 -1
- package/dist/tests/cases/integration/mocked/sql/getApiKeySql.d.ts +11 -0
- package/dist/tests/cases/integration/mocked/sql/getApiKeySql.d.ts.map +1 -0
- package/dist/tests/cases/integration/mocked/sql/getApiKeySql.js +31 -0
- package/dist/tests/cases/integration/mocked/sql/getApiKeySql.js.map +1 -0
- package/dist/tests/cases/integration/mocked/sql/getPersonByEmailSql.d.ts.map +1 -1
- package/dist/tests/cases/integration/mocked/sql/getPersonByEmailSql.js +2 -1
- package/dist/tests/cases/integration/mocked/sql/getPersonByEmailSql.js.map +1 -1
- package/dist/tests/cases/integration/mocked/sql/getPersonByIdSql.js +1 -1
- package/dist/tests/cases/integration/mocked/sql/getPersonByIdentity.js +1 -1
- package/dist/tests/cases/integration/mocked/sql/getPersonByIdpSql.d.ts.map +1 -1
- package/dist/tests/cases/integration/mocked/sql/getPersonByIdpSql.js +2 -1
- package/dist/tests/cases/integration/mocked/sql/getPersonByIdpSql.js.map +1 -1
- package/dist/tests/cases/unit/authorization/membershipAwareAccessNode.test.js +27 -0
- package/dist/tests/cases/unit/authorization/membershipAwareAccessNode.test.js.map +1 -1
- package/dist/tests/src/mailer.d.ts +2 -2
- package/dist/tests/src/mailer.d.ts.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/graphql-tenant.codegen.yml +2 -1
- package/package.json +14 -14
- package/src/TenantContainer.ts +19 -2
- package/src/migrations/2023-01-20-135500-person-email-normalize.ts +28 -0
- package/src/migrations/2023-06-03-104000-person-disabled.ts +10 -0
- package/src/migrations/runner.ts +4 -0
- package/src/migrations/snapshot.ts +1 -0
- package/src/model/authorization/AclSchemaAccessNodeFactory.ts +16 -6
- package/src/model/authorization/PermissionActions.ts +5 -0
- package/src/model/authorization/PermissionsFactory.ts +11 -3
- package/src/model/commands/identity/PatchIdentityGlobalRoles.ts +28 -0
- package/src/model/commands/identity/index.ts +1 -0
- package/src/model/commands/membership/AddProjectMemberCommand.ts +9 -10
- package/src/model/commands/membership/RemoveProjectMemberCommand.ts +1 -1
- package/src/model/commands/membership/UpdateProjectMemberCommand.ts +2 -2
- package/src/model/commands/passwordReset/ResetPasswordCommand.ts +9 -16
- package/src/model/commands/person/CreatePersonCommand.ts +9 -4
- package/src/model/commands/person/DisablePersonCommand.ts +18 -0
- package/src/model/queries/apiKey/ApiKeyQuery.ts +64 -0
- package/src/model/queries/apiKey/index.ts +1 -1
- package/src/model/queries/idp/types.ts +2 -2
- package/src/model/queries/membership/ProjectMembersQuery.ts +3 -3
- package/src/model/queries/person/PersonQuery.ts +30 -3
- package/src/model/queries/person/PersonQueryBuilderFactory.ts +1 -0
- package/src/model/queries/person/types.ts +3 -2
- package/src/model/service/IDPSignInManager.ts +11 -6
- package/src/model/service/InviteManager.ts +2 -2
- package/src/model/service/PasswordChangeManager.ts +4 -4
- package/src/model/service/PasswordResetManager.ts +3 -5
- package/src/model/service/PersonAccessManager.ts +56 -0
- package/src/model/service/PersonManager.ts +14 -0
- package/src/model/service/ProjectManager.ts +3 -3
- package/src/model/service/ProjectMemberManager.ts +3 -15
- package/src/model/service/RolesManager.ts +40 -0
- package/src/model/service/SignInManager.ts +25 -7
- package/src/model/service/SignUpManager.ts +2 -2
- package/src/model/service/apiKey/ApiKeyManager.ts +8 -1
- package/src/model/service/idp/IDPManager.ts +8 -8
- package/src/model/service/index.ts +2 -0
- package/src/model/utils/Response.ts +1 -1
- package/src/model/utils/email.ts +5 -0
- package/src/resolvers/ResolverFactory.ts +10 -1
- package/src/resolvers/errorUtils.ts +1 -1
- package/src/resolvers/membershipUtils.ts +21 -21
- package/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.ts +2 -2
- package/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.ts +1 -1
- package/src/resolvers/mutation/identity/GlobalRolesMutationResolver.ts +69 -0
- package/src/resolvers/mutation/identity/index.ts +1 -0
- package/src/resolvers/mutation/index.ts +1 -0
- package/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.ts +6 -6
- package/src/resolvers/mutation/person/ChangePasswordMutationResolver.ts +2 -2
- package/src/resolvers/mutation/person/DisablePersonMutationResolver.ts +48 -0
- package/src/resolvers/mutation/person/InviteMutationResolver.ts +5 -12
- package/src/resolvers/mutation/person/OtpMutationResolver.ts +4 -6
- package/src/resolvers/mutation/person/ResetPasswordMutationResolver.ts +2 -10
- package/src/resolvers/mutation/person/SignInMutationResolver.ts +1 -0
- package/src/resolvers/mutation/person/SignOutMutationResolver.ts +13 -3
- package/src/resolvers/mutation/project/CreateProjectMutationResolver.ts +2 -7
- package/src/resolvers/mutation/project/SetProjectSecretMutationResolver.ts +1 -1
- package/src/resolvers/mutation/project/UpdateProjectMutationResolver.ts +2 -7
- package/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.ts +2 -2
- package/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.ts +1 -1
- package/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.ts +2 -2
- package/src/resolvers/types/ProjectTypeResolver.ts +2 -2
- package/src/schema/index.ts +321 -159
- package/src/schema/tenant.graphql.ts +97 -21
- package/tests/cases/integration/db/updateRoles.test.ts +74 -0
- package/tests/cases/integration/mocked/confirmOtpMutation.test.ts +1 -1
- package/tests/cases/integration/mocked/gql/signUp.ts +4 -0
- package/tests/cases/integration/mocked/signInMutation.test.ts +37 -3
- package/tests/cases/integration/mocked/signOutMutation.test.ts +58 -0
- package/tests/cases/integration/mocked/signUpMutation.test.ts +9 -0
- package/tests/cases/integration/mocked/sql/getApiKeySql.ts +33 -0
- package/tests/cases/integration/mocked/sql/getPersonByEmailSql.ts +2 -1
- package/tests/cases/integration/mocked/sql/getPersonByIdSql.ts +1 -1
- package/tests/cases/integration/mocked/sql/getPersonByIdentity.ts +1 -1
- package/tests/cases/integration/mocked/sql/getPersonByIdpSql.ts +2 -1
- package/tests/cases/unit/authorization/membershipAwareAccessNode.test.ts +36 -0
- package/dist/src/model/queries/apiKey/ApiKeyByTokenQuery.d.ts +0 -22
- package/dist/src/model/queries/apiKey/ApiKeyByTokenQuery.d.ts.map +0 -1
- package/dist/src/model/queries/apiKey/ApiKeyByTokenQuery.js +0 -33
- package/dist/src/model/queries/apiKey/ApiKeyByTokenQuery.js.map +0 -1
- package/src/model/queries/apiKey/ApiKeyByTokenQuery.ts +0 -49
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { DatabaseQuery, DatabaseQueryable, Operator, SelectBuilderSpecification } from '@contember/database'
|
|
1
|
+
import { DatabaseQuery, DatabaseQueryable, Literal, Operator, SelectBuilderSpecification } from '@contember/database'
|
|
2
2
|
import { MaybePersonRow } from './types'
|
|
3
3
|
import { PersonQueryBuilderFactory } from './PersonQueryBuilderFactory'
|
|
4
|
+
import { normalizeEmail } from '../../utils/email'
|
|
4
5
|
|
|
5
6
|
export type PersonUniqueIdentifier =
|
|
6
7
|
| { type: 'id'; id: string }
|
|
@@ -12,7 +13,7 @@ class PersonQuery extends DatabaseQuery<MaybePersonRow> {
|
|
|
12
13
|
super()
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
static byUniqueIdentifier(identifier: PersonUniqueIdentifier):
|
|
16
|
+
static byUniqueIdentifier(identifier: PersonUniqueIdentifier): DatabaseQuery<MaybePersonRow> {
|
|
16
17
|
switch (identifier.type) {
|
|
17
18
|
case 'email':
|
|
18
19
|
return PersonQuery.byEmail(identifier.email)
|
|
@@ -27,7 +28,11 @@ class PersonQuery extends DatabaseQuery<MaybePersonRow> {
|
|
|
27
28
|
return new PersonQuery(qb => qb.where(it => it.compare(['person', 'id'], Operator.eq, id)))
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
static byEmail(email: string):
|
|
31
|
+
static byEmail(email: string): DatabaseQuery<MaybePersonRow> {
|
|
32
|
+
return new PersonByEmailFallbackQuery(email)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static byExactEmail(email: string): PersonQuery {
|
|
31
36
|
return new PersonQuery(qb => qb.where(it => it.compare(['person', 'email'], Operator.eq, email)))
|
|
32
37
|
}
|
|
33
38
|
|
|
@@ -44,4 +49,26 @@ class PersonQuery extends DatabaseQuery<MaybePersonRow> {
|
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
51
|
|
|
52
|
+
class PersonByEmailFallbackQuery extends DatabaseQuery<MaybePersonRow> {
|
|
53
|
+
constructor(
|
|
54
|
+
private readonly email: string,
|
|
55
|
+
) {
|
|
56
|
+
super()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async fetch(ctx: DatabaseQueryable): Promise<MaybePersonRow> {
|
|
60
|
+
const handler = ctx.getHandler()
|
|
61
|
+
const exact = await handler.fetch(PersonQuery.byExactEmail(this.email))
|
|
62
|
+
if (exact) {
|
|
63
|
+
return exact
|
|
64
|
+
}
|
|
65
|
+
const normalizedEmail = normalizeEmail(this.email)
|
|
66
|
+
if (normalizedEmail === this.email) {
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
|
+
return await handler.fetch(PersonQuery.byExactEmail(normalizedEmail))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
47
74
|
export { PersonQuery }
|
|
@@ -11,6 +11,7 @@ export class PersonQueryBuilderFactory {
|
|
|
11
11
|
.select(['person', 'identity_id'])
|
|
12
12
|
.select(['person', 'email'])
|
|
13
13
|
.select(['person', 'name'])
|
|
14
|
+
.select(['person', 'disabled_at'])
|
|
14
15
|
.select(['identity', 'roles'])
|
|
15
16
|
.from('person')
|
|
16
17
|
.join('identity', 'identity', expr => expr.columnsEq(['identity', 'id'], ['person', 'identity_id']))
|
|
@@ -4,9 +4,10 @@ export interface PersonRow {
|
|
|
4
4
|
readonly identity_id: string
|
|
5
5
|
readonly otp_uri: string | null
|
|
6
6
|
readonly otp_activated_at: Date | null
|
|
7
|
-
readonly email
|
|
8
|
-
readonly name
|
|
7
|
+
readonly email: string | null
|
|
8
|
+
readonly name: string | null
|
|
9
9
|
readonly roles: string[]
|
|
10
|
+
readonly disabled_at: Date | null
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export type MaybePersonRow = PersonRow | null
|
|
@@ -21,7 +21,7 @@ class IDPSignInManager {
|
|
|
21
21
|
responseData: unknown,
|
|
22
22
|
expiration?: number,
|
|
23
23
|
): Promise<IDPSignInManager.SignInIDPResponse> {
|
|
24
|
-
return dbContext.transaction(async db => {
|
|
24
|
+
return dbContext.transaction(async (db): Promise<IDPSignInManager.SignInIDPResponse> => {
|
|
25
25
|
const provider = await db.queryHandler.fetch(new IdentityProviderBySlugQuery(idpSlug))
|
|
26
26
|
if (!provider || provider.disabledAt) {
|
|
27
27
|
throw new Error('provider not found')
|
|
@@ -36,16 +36,21 @@ class IDPSignInManager {
|
|
|
36
36
|
)
|
|
37
37
|
} catch (e) {
|
|
38
38
|
if (e instanceof IDPResponseError) {
|
|
39
|
-
return new ResponseError(
|
|
39
|
+
return new ResponseError('INVALID_IDP_RESPONSE', e.message)
|
|
40
40
|
}
|
|
41
41
|
if (e instanceof IDPValidationError) {
|
|
42
|
-
return new ResponseError(
|
|
42
|
+
return new ResponseError('IDP_VALIDATION_FAILED', e.message)
|
|
43
43
|
}
|
|
44
44
|
throw e
|
|
45
45
|
}
|
|
46
46
|
const personRow = await this.resolvePerson(db, claim, provider)
|
|
47
|
+
|
|
47
48
|
if (!personRow) {
|
|
48
|
-
return new ResponseError(
|
|
49
|
+
return new ResponseError('PERSON_NOT_FOUND', `Person ${claim.email} not found`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (personRow.disabled_at !== null) {
|
|
53
|
+
return new ResponseError('PERSON_DISABLED', `Person with e-mail ${claim.email} is disabled`)
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
const sessionToken = await this.apiKeyManager.createSessionApiKey(db, personRow.identity_id, expiration)
|
|
@@ -56,7 +61,7 @@ class IDPSignInManager {
|
|
|
56
61
|
async initSignInIDP(dbContext: DatabaseContext, idpSlug: string, data: unknown): Promise<IDPSignInManager.InitSignInIDPResponse> {
|
|
57
62
|
const provider = await dbContext.queryHandler.fetch(new IdentityProviderBySlugQuery(idpSlug))
|
|
58
63
|
if (!provider || provider.disabledAt) {
|
|
59
|
-
return new ResponseError(
|
|
64
|
+
return new ResponseError('PROVIDER_NOT_FOUND', `Identity provider ${idpSlug} not found`)
|
|
60
65
|
}
|
|
61
66
|
const providerService = this.idpRegistry.getHandler(provider.type)
|
|
62
67
|
const validatedConfig = providerService.validateConfiguration(provider.configuration)
|
|
@@ -65,7 +70,7 @@ class IDPSignInManager {
|
|
|
65
70
|
return new ResponseOk(initResponse)
|
|
66
71
|
} catch (e) {
|
|
67
72
|
if (e instanceof IDPValidationError) {
|
|
68
|
-
return new ResponseError(
|
|
73
|
+
return new ResponseError('IDP_VALIDATION_FAILED', e.message)
|
|
69
74
|
}
|
|
70
75
|
throw e
|
|
71
76
|
}
|
|
@@ -60,7 +60,7 @@ export class InviteManager {
|
|
|
60
60
|
const identityId = await trx.commandBus.execute(new CreateIdentityCommand([TenantRole.PERSON]))
|
|
61
61
|
|
|
62
62
|
generatedPassword = password ??
|
|
63
|
-
(method ===
|
|
63
|
+
(method === 'CREATE_PASSWORD' ? (await this.providers.randomBytes(9)).toString('base64') : null)
|
|
64
64
|
const passwordWrapper = generatedPassword !== null ? new PasswordPlain(generatedPassword) : NoPassword
|
|
65
65
|
|
|
66
66
|
person = await trx.commandBus.execute(new CreatePersonCommand({
|
|
@@ -69,7 +69,7 @@ export class InviteManager {
|
|
|
69
69
|
name,
|
|
70
70
|
password: passwordWrapper,
|
|
71
71
|
}))
|
|
72
|
-
if (method ===
|
|
72
|
+
if (method === 'RESET_PASSWORD') {
|
|
73
73
|
const result = await trx.commandBus.execute(new CreatePasswordResetRequestCommand(person.id, INVITATION_RESET_TOKEN_EXPIRATION_MINUTES))
|
|
74
74
|
resetToken = result.token
|
|
75
75
|
}
|
|
@@ -14,7 +14,7 @@ class PasswordChangeManager {
|
|
|
14
14
|
async changePassword(dbContext: DatabaseContext, personId: string, password: string): Promise<PasswordChangeManager.PasswordChangeResponse<ChangePasswordErrorCode>> {
|
|
15
15
|
const weakPassword = getPasswordWeaknessMessage(password)
|
|
16
16
|
if (weakPassword) {
|
|
17
|
-
return new ResponseError(
|
|
17
|
+
return new ResponseError('TOO_WEAK', weakPassword)
|
|
18
18
|
}
|
|
19
19
|
await dbContext.commandBus.execute(new ChangePasswordCommand(personId, password))
|
|
20
20
|
return new ResponseOk(null)
|
|
@@ -23,13 +23,13 @@ class PasswordChangeManager {
|
|
|
23
23
|
async changeMyPassword(dbContext: DatabaseContext, person: PersonRow, currentPassword: string, password: string): Promise<PasswordChangeManager.PasswordChangeResponse<ChangeMyPasswordErrorCode>> {
|
|
24
24
|
const weakPassword = getPasswordWeaknessMessage(password)
|
|
25
25
|
if (weakPassword) {
|
|
26
|
-
return new ResponseError(
|
|
26
|
+
return new ResponseError('TOO_WEAK', weakPassword)
|
|
27
27
|
}
|
|
28
28
|
if (!person.password_hash) {
|
|
29
|
-
return new ResponseError(
|
|
29
|
+
return new ResponseError('NO_PASSWORD_SET', 'No password set')
|
|
30
30
|
}
|
|
31
31
|
if (!(await this.providers.bcryptCompare(currentPassword, person.password_hash))) {
|
|
32
|
-
return new ResponseError(
|
|
32
|
+
return new ResponseError('INVALID_PASSWORD', 'Password does not match')
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
await dbContext.commandBus.execute(new ChangePasswordCommand(person.id, password))
|
|
@@ -56,14 +56,12 @@ export class PasswordResetManager {
|
|
|
56
56
|
public async resetPassword(dbContext: DatabaseContext, token: string, password: string): Promise<ResetPasswordResponse> {
|
|
57
57
|
const weakPassword = getPasswordWeaknessMessage(password)
|
|
58
58
|
if (weakPassword) {
|
|
59
|
-
return new ResponseError(
|
|
59
|
+
return new ResponseError('PASSWORD_TOO_WEAK', weakPassword)
|
|
60
60
|
}
|
|
61
61
|
return await dbContext.commandBus.execute(new ResetPasswordCommand(token, password))
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export
|
|
66
|
-
PASSWORD_TOO_WEAK = 'PASSWORD_TOO_WEAK',
|
|
67
|
-
}
|
|
65
|
+
export type ResetPasswordErrorCode = 'PASSWORD_TOO_WEAK'
|
|
68
66
|
|
|
69
|
-
export type ResetPasswordResponse = Response<
|
|
67
|
+
export type ResetPasswordResponse = Response<null, ResetPasswordErrorCode | ResetPasswordCommandErrorCode>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { PersonQuery } from '../queries'
|
|
2
|
+
import { DatabaseContext } from '../utils'
|
|
3
|
+
import { DisablePersonCommand } from '../commands/person/DisablePersonCommand'
|
|
4
|
+
import { ApiKeyManager } from './apiKey'
|
|
5
|
+
import { Response, ResponseError, ResponseOk } from '../utils/Response'
|
|
6
|
+
import { DisablePersonErrorCode } from '../../schema'
|
|
7
|
+
|
|
8
|
+
class PersonAccessManager {
|
|
9
|
+
|
|
10
|
+
constructor(private readonly apiKeyManager: ApiKeyManager) {}
|
|
11
|
+
|
|
12
|
+
async disablePerson(dbContext: DatabaseContext, personId: string): Promise<PersonDisableAccessResponse> {
|
|
13
|
+
const result = await dbContext.transaction(async trx => {
|
|
14
|
+
const personRow = await trx.queryHandler.fetch(
|
|
15
|
+
PersonQuery.byId(personId),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
if (personRow === null) {
|
|
19
|
+
return 'PERSON_NOT_FOUND'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (personRow.disabled_at !== null) {
|
|
23
|
+
return 'PERSON_ALREADY_DISABLED'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Deactivate person & invalidate all api keys associated with person identity
|
|
27
|
+
await this.disablePersonAccount(trx, personRow.id)
|
|
28
|
+
await this.disableIdentityApiKeys(trx, personRow.identity_id)
|
|
29
|
+
|
|
30
|
+
return null
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
switch (result) {
|
|
34
|
+
case null:
|
|
35
|
+
return new ResponseOk(null)
|
|
36
|
+
|
|
37
|
+
case 'PERSON_ALREADY_DISABLED':
|
|
38
|
+
return new ResponseError(result, 'Person is already disable')
|
|
39
|
+
|
|
40
|
+
case 'PERSON_NOT_FOUND':
|
|
41
|
+
return new ResponseError(result, 'Person not found')
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private async disablePersonAccount(dbContext: DatabaseContext, personId: string) {
|
|
46
|
+
await dbContext.commandBus.execute(new DisablePersonCommand(personId))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private async disableIdentityApiKeys(dbContext: DatabaseContext, personIdentityId: string) {
|
|
50
|
+
await this.apiKeyManager.disableIdentityApiKeys(dbContext, personIdentityId)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type PersonDisableAccessResponse = Response<null, DisablePersonErrorCode>
|
|
55
|
+
|
|
56
|
+
export { PersonAccessManager }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PersonQuery, PersonRow } from '../queries'
|
|
2
|
+
import { DatabaseContext } from '../utils'
|
|
3
|
+
|
|
4
|
+
class PersonManager {
|
|
5
|
+
|
|
6
|
+
async findPersonById(dbContext: DatabaseContext, personId: string): Promise<PersonRow | null> {
|
|
7
|
+
return await dbContext.queryHandler.fetch(
|
|
8
|
+
PersonQuery.byId(personId),
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { PersonManager }
|
|
@@ -34,13 +34,13 @@ export class ProjectManager {
|
|
|
34
34
|
noDeployToken?: boolean
|
|
35
35
|
},
|
|
36
36
|
): Promise<CreateProjectResponse> {
|
|
37
|
-
return await dbContext.transaction(async db => {
|
|
37
|
+
return await dbContext.transaction(async (db): Promise<CreateProjectResponse> => {
|
|
38
38
|
const bus = db.commandBus
|
|
39
39
|
|
|
40
40
|
const now = db.providers.now()
|
|
41
41
|
const projectId = await bus.execute(new CreateProjectCommand(project, now))
|
|
42
42
|
if (!projectId) {
|
|
43
|
-
return new ResponseError(
|
|
43
|
+
return new ResponseError('ALREADY_EXISTS', `Project ${project.slug} already exists`)
|
|
44
44
|
}
|
|
45
45
|
for (const [key, value] of Object.entries(project.secrets)) {
|
|
46
46
|
await bus.execute(new SetProjectSecretCommand(projectId, key, Buffer.from(value)))
|
|
@@ -70,7 +70,7 @@ export class ProjectManager {
|
|
|
70
70
|
logger.error(e, { message: 'Project initialization failed' })
|
|
71
71
|
await db.client.connection.rollback()
|
|
72
72
|
return new ResponseError(
|
|
73
|
-
|
|
73
|
+
'INIT_ERROR',
|
|
74
74
|
`Project initialization error: ${e instanceof Error && 'message' in e ? e.message : 'unknown'}`,
|
|
75
75
|
)
|
|
76
76
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AddProjectMemberCommand,
|
|
3
|
-
AddProjectMemberCommandError,
|
|
4
3
|
MembershipUpdateInput,
|
|
5
4
|
RemoveProjectMemberCommand,
|
|
6
5
|
RemoveProjectMemberResponse,
|
|
@@ -8,12 +7,12 @@ import {
|
|
|
8
7
|
UpdateProjectMemberResponse,
|
|
9
8
|
} from '../commands'
|
|
10
9
|
import { ProjectMembershipByIdentityQuery, ProjectMembersQuery } from '../queries'
|
|
11
|
-
import { AddProjectMemberErrorCode,
|
|
10
|
+
import { AddProjectMemberErrorCode, ProjectMembersInput } from '../../schema'
|
|
12
11
|
import { AccessVerifier, PermissionActions, TenantRole } from '../authorization'
|
|
13
12
|
import { indexListBy, notEmpty } from '../../utils/array'
|
|
14
13
|
import { createSetMembershipVariables } from './membershipUtils'
|
|
15
14
|
import { Acl, ProjectRole } from '@contember/schema'
|
|
16
|
-
import { Response
|
|
15
|
+
import { Response } from '../utils/Response'
|
|
17
16
|
import { DatabaseContext } from '../utils'
|
|
18
17
|
|
|
19
18
|
export class ProjectMemberManager {
|
|
@@ -24,20 +23,9 @@ export class ProjectMemberManager {
|
|
|
24
23
|
memberships: readonly Acl.Membership[],
|
|
25
24
|
): Promise<AddProjectMemberResponse> {
|
|
26
25
|
return await dbContext.transaction(async db => {
|
|
27
|
-
|
|
26
|
+
return await db.commandBus.execute(
|
|
28
27
|
new AddProjectMemberCommand(projectId, identityId, createSetMembershipVariables(memberships)),
|
|
29
28
|
)
|
|
30
|
-
if (result.ok) {
|
|
31
|
-
return new ResponseOk(null)
|
|
32
|
-
}
|
|
33
|
-
switch (result.error) {
|
|
34
|
-
case AddProjectMemberCommandError.alreadyMember:
|
|
35
|
-
return new ResponseError(AddProjectMemberErrorCode.AlreadyMember, result.errorMessage)
|
|
36
|
-
case AddProjectMemberCommandError.projectNotFound:
|
|
37
|
-
return new ResponseError(AddProjectMemberErrorCode.ProjectNotFound, result.errorMessage)
|
|
38
|
-
case AddProjectMemberCommandError.identityNotfound:
|
|
39
|
-
return new ResponseError(AddProjectMemberErrorCode.IdentityNotFound, result.errorMessage)
|
|
40
|
-
}
|
|
41
29
|
})
|
|
42
30
|
}
|
|
43
31
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DatabaseContext } from '../utils'
|
|
2
|
+
import { PatchIdentityGlobalRoles } from '../commands'
|
|
3
|
+
import { Response, ResponseError, ResponseOk } from '../utils/Response'
|
|
4
|
+
import { TenantRole } from '../authorization'
|
|
5
|
+
|
|
6
|
+
export class RolesManager {
|
|
7
|
+
async addGlobalRoles(dbContext: DatabaseContext, identityId: string, roles: readonly string[]): Promise<Response<null, GlobalRolesErrorCode>> {
|
|
8
|
+
return this.patchGlobalRoles(dbContext, identityId, roles, [])
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async removeGlobalRoles(dbContext: DatabaseContext, identityId: string, roles: readonly string[]): Promise<Response<null, GlobalRolesErrorCode>> {
|
|
12
|
+
return this.patchGlobalRoles(dbContext, identityId, [], roles)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private async patchGlobalRoles(dbContext: DatabaseContext, identityId: string, addRoles: readonly string[], removeRoles: readonly string[]): Promise<Response<null, GlobalRolesErrorCode>> {
|
|
16
|
+
const rolesValidationError = this.validateRoles([...addRoles, ...removeRoles])
|
|
17
|
+
if (rolesValidationError) {
|
|
18
|
+
return rolesValidationError
|
|
19
|
+
}
|
|
20
|
+
const result = await dbContext.commandBus.execute(new PatchIdentityGlobalRoles(identityId, addRoles, removeRoles))
|
|
21
|
+
if (!result) {
|
|
22
|
+
return new ResponseError('IDENTITY_NOT_FOUND', `Identity ${identityId} not found`)
|
|
23
|
+
}
|
|
24
|
+
return new ResponseOk(null)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
private validateRoles(roles: string[]): Response<null, GlobalRolesErrorCode> | null {
|
|
29
|
+
for (const role of roles) {
|
|
30
|
+
if (!Object.values(TenantRole).includes(role as TenantRole)) {
|
|
31
|
+
return new ResponseError('INVALID_ROLE', `Role ${role} is not valid`)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type GlobalRolesErrorCode =
|
|
39
|
+
| 'IDENTITY_NOT_FOUND'
|
|
40
|
+
| 'INVALID_ROLE'
|
|
@@ -15,26 +15,37 @@ class SignInManager {
|
|
|
15
15
|
|
|
16
16
|
async signIn(dbContext: DatabaseContext, email: string, password: string, expiration?: number, otpCode?: string): Promise<SignInResponse> {
|
|
17
17
|
const personRow = await dbContext.queryHandler.fetch(PersonQuery.byEmail(email))
|
|
18
|
+
|
|
18
19
|
if (personRow === null) {
|
|
19
|
-
return new ResponseError(
|
|
20
|
+
return new ResponseError('UNKNOWN_EMAIL', `Person with email ${email} not found`)
|
|
20
21
|
}
|
|
22
|
+
|
|
21
23
|
if (!personRow.password_hash) {
|
|
22
|
-
return new ResponseError(
|
|
24
|
+
return new ResponseError('NO_PASSWORD_SET', `No password set`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (personRow.disabled_at !== null) {
|
|
28
|
+
return new ResponseError('PERSON_DISABLED', `Person is disabled`)
|
|
23
29
|
}
|
|
30
|
+
|
|
24
31
|
const passwordValid = await this.providers.bcryptCompare(password, personRow.password_hash)
|
|
32
|
+
|
|
25
33
|
if (!passwordValid) {
|
|
26
|
-
return new ResponseError(
|
|
34
|
+
return new ResponseError('INVALID_PASSWORD', `Password does not match`)
|
|
27
35
|
}
|
|
36
|
+
|
|
28
37
|
if (personRow.otp_uri && personRow.otp_activated_at) {
|
|
29
38
|
if (!otpCode) {
|
|
30
|
-
return new ResponseError(
|
|
39
|
+
return new ResponseError('OTP_REQUIRED', `2FA is enabled. OTP token is required`)
|
|
31
40
|
}
|
|
41
|
+
|
|
32
42
|
if (!this.otpAuthenticator.validate({ uri: personRow.otp_uri }, otpCode)) {
|
|
33
|
-
return new ResponseError(
|
|
43
|
+
return new ResponseError('INVALID_OTP_TOKEN', 'OTP token validation has failed')
|
|
34
44
|
}
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
const sessionToken = await this.apiKeyManager.createSessionApiKey(dbContext, personRow.identity_id, expiration)
|
|
48
|
+
|
|
38
49
|
return new ResponseOk(new SignInResult(personRow, sessionToken))
|
|
39
50
|
}
|
|
40
51
|
|
|
@@ -45,15 +56,22 @@ class SignInManager {
|
|
|
45
56
|
verifier?: (person: PersonRow) => Promise<void>,
|
|
46
57
|
): Promise<CreateSessionTokenResponse> {
|
|
47
58
|
const personRow = await dbContext.queryHandler.fetch(PersonQuery.byUniqueIdentifier(personIdentifier))
|
|
59
|
+
|
|
48
60
|
if (personRow === null) {
|
|
49
61
|
if (personIdentifier.type === 'email') {
|
|
50
|
-
return new ResponseError(
|
|
62
|
+
return new ResponseError('UNKNOWN_EMAIL', `Person with email ${personIdentifier.email} not found`)
|
|
51
63
|
|
|
52
64
|
} else if (personIdentifier.type === 'id') {
|
|
53
|
-
return new ResponseError(
|
|
65
|
+
return new ResponseError('UNKNOWN_PERSON_ID', `Person with id ${personIdentifier.id} not found`)
|
|
54
66
|
}
|
|
67
|
+
|
|
55
68
|
throw new ImplementationException()
|
|
56
69
|
}
|
|
70
|
+
|
|
71
|
+
if (personRow.disabled_at !== null) {
|
|
72
|
+
return new ResponseError('PERSON_DISABLED', `Person with id ${personRow.id} is disabled`)
|
|
73
|
+
}
|
|
74
|
+
|
|
57
75
|
await verifier?.(personRow)
|
|
58
76
|
|
|
59
77
|
const sessionToken = await this.apiKeyManager.createSessionApiKey(dbContext, personRow.identity_id, expiration)
|
|
@@ -17,12 +17,12 @@ type SignUpUser = {
|
|
|
17
17
|
export class SignUpManager {
|
|
18
18
|
async signUp(dbContext: DatabaseContext, { email, password, roles = [] }: SignUpUser): Promise<SignUpResponse> {
|
|
19
19
|
if (await this.isEmailAlreadyUsed(dbContext, email)) {
|
|
20
|
-
return new ResponseError(
|
|
20
|
+
return new ResponseError('EMAIL_ALREADY_EXISTS', `User with email ${email} already exists`)
|
|
21
21
|
}
|
|
22
22
|
const plainPassword = password.getPlain()
|
|
23
23
|
const weakPassword = plainPassword ? getPasswordWeaknessMessage(plainPassword) : null
|
|
24
24
|
if (weakPassword) {
|
|
25
|
-
return new ResponseError(
|
|
25
|
+
return new ResponseError('TOO_WEAK', weakPassword)
|
|
26
26
|
}
|
|
27
27
|
const person = await dbContext.transaction(async db => {
|
|
28
28
|
const identityId = await db.commandBus.execute(new CreateIdentityCommand([...roles, TenantRole.PERSON]))
|
|
@@ -6,12 +6,13 @@ import {
|
|
|
6
6
|
ProlongApiKeyCommand,
|
|
7
7
|
} from '../../commands'
|
|
8
8
|
import { ApiKey } from '../../type'
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
import { Response, ResponseError, ResponseOk } from '../../utils/Response'
|
|
11
11
|
import { DatabaseContext, TokenHash } from '../../utils'
|
|
12
12
|
import { ApiKeyService, CreateApiKeyResponse } from './ApiKeyService'
|
|
13
13
|
import assert from 'node:assert'
|
|
14
14
|
import { Acl } from '@contember/schema'
|
|
15
|
+
import { ApiKeyByIdQuery, ApiKeyByTokenQuery, ApiKeyRow } from '../../queries'
|
|
15
16
|
|
|
16
17
|
export class ApiKeyManager {
|
|
17
18
|
constructor(
|
|
@@ -56,6 +57,12 @@ export class ApiKeyManager {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
|
|
60
|
+
async findApiKey(dbContext: DatabaseContext, apiKeyId: string): Promise<ApiKeyRow | null> {
|
|
61
|
+
return await dbContext.queryHandler.fetch(
|
|
62
|
+
new ApiKeyByIdQuery(apiKeyId),
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
59
66
|
async disableOneOffApiKey(dbContext: DatabaseContext, apiKeyId: string): Promise<void> {
|
|
60
67
|
await dbContext.commandBus.execute(new DisableOneOffApiKeyCommand(apiKeyId))
|
|
61
68
|
}
|
|
@@ -18,23 +18,23 @@ export class IDPManager {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
public async addIDP(db: DatabaseContext, idp: IdentityProviderData): Promise<RegisterIDPResponse> {
|
|
21
|
-
return await db.transaction(async db => {
|
|
21
|
+
return await db.transaction(async (db): Promise<RegisterIDPResponse> => {
|
|
22
22
|
try {
|
|
23
23
|
const providerService = this.idpRegistry.getHandler(idp.type)
|
|
24
24
|
providerService.validateConfiguration(idp.configuration)
|
|
25
25
|
} catch (e) {
|
|
26
26
|
if (e instanceof IdentityProviderNotFoundError) {
|
|
27
|
-
return new ResponseError(
|
|
27
|
+
return new ResponseError('UNKNOWN_TYPE', `IDP type ${idp.type} not found`)
|
|
28
28
|
}
|
|
29
29
|
if (e instanceof InvalidIDPConfigurationError) {
|
|
30
|
-
return new ResponseError(
|
|
30
|
+
return new ResponseError('INVALID_CONFIGURATION', `Invalid IDP configuration: ${e.message}`)
|
|
31
31
|
}
|
|
32
32
|
throw e
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
const existing = await db.queryHandler.fetch(new IdentityProviderBySlugQuery(idp.slug))
|
|
36
36
|
if (existing) {
|
|
37
|
-
return new ResponseError(
|
|
37
|
+
return new ResponseError('ALREADY_EXISTS', `IDP with slug ${idp.slug} already exists`)
|
|
38
38
|
}
|
|
39
39
|
await db.commandBus.execute(new CreateIdpCommand(idp))
|
|
40
40
|
return new ResponseOk(null)
|
|
@@ -45,7 +45,7 @@ export class IDPManager {
|
|
|
45
45
|
return await db.transaction(async db => {
|
|
46
46
|
const existing = await db.queryHandler.fetch(new IdentityProviderBySlugQuery(slug))
|
|
47
47
|
if (!existing) {
|
|
48
|
-
return new ResponseError(
|
|
48
|
+
return new ResponseError('NOT_FOUND', `IDP ${slug} not found`)
|
|
49
49
|
}
|
|
50
50
|
if (!existing.disabledAt) {
|
|
51
51
|
await db.commandBus.execute(new DisableIdpCommand(existing.id))
|
|
@@ -59,7 +59,7 @@ export class IDPManager {
|
|
|
59
59
|
return await db.transaction(async db => {
|
|
60
60
|
const existing = await db.queryHandler.fetch(new IdentityProviderBySlugQuery(slug))
|
|
61
61
|
if (!existing) {
|
|
62
|
-
return new ResponseError(
|
|
62
|
+
return new ResponseError('NOT_FOUND', `IDP ${slug} not found`)
|
|
63
63
|
}
|
|
64
64
|
if (existing.disabledAt) {
|
|
65
65
|
await db.commandBus.execute(new EnableIdpCommand(existing.id))
|
|
@@ -72,7 +72,7 @@ export class IDPManager {
|
|
|
72
72
|
return await db.transaction(async db => {
|
|
73
73
|
const existing = await db.queryHandler.fetch(new IdentityProviderBySlugQuery(slug))
|
|
74
74
|
if (!existing) {
|
|
75
|
-
return new ResponseError(
|
|
75
|
+
return new ResponseError('NOT_FOUND', `IDP ${slug} not found`)
|
|
76
76
|
}
|
|
77
77
|
try {
|
|
78
78
|
const type = data.type ?? existing.type
|
|
@@ -83,7 +83,7 @@ export class IDPManager {
|
|
|
83
83
|
}
|
|
84
84
|
} catch (e) {
|
|
85
85
|
if (e instanceof InvalidIDPConfigurationError) {
|
|
86
|
-
return new ResponseError(
|
|
86
|
+
return new ResponseError('INVALID_CONFIGURATION', `Invalid IDP configuration: ${e.message}`)
|
|
87
87
|
}
|
|
88
88
|
throw e
|
|
89
89
|
}
|
|
@@ -8,8 +8,10 @@ export * from './OtpManager'
|
|
|
8
8
|
export * from './PasswordChangeManager'
|
|
9
9
|
export * from './ProjectManager'
|
|
10
10
|
export * from './ProjectMemberManager'
|
|
11
|
+
export * from './RolesManager'
|
|
11
12
|
export * from './SignInManager'
|
|
12
13
|
export * from './SignUpManager'
|
|
13
14
|
export * from './PasswordResetManager'
|
|
14
15
|
export * from './SecretsManager'
|
|
15
16
|
export * from './OtpAuthenticator'
|
|
17
|
+
export * from './PersonAccessManager'
|
|
@@ -6,7 +6,7 @@ export class ResponseOk<Result> {
|
|
|
6
6
|
constructor(public readonly result: Result) {}
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export class ResponseError<Error> {
|
|
9
|
+
export class ResponseError<const Error> {
|
|
10
10
|
public readonly ok = false
|
|
11
11
|
|
|
12
12
|
constructor(public readonly error: Error, public readonly errorMessage: string) {}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
SignOutMutationResolver,
|
|
16
16
|
SignUpMutationResolver,
|
|
17
17
|
UpdateProjectMemberMutationResolver,
|
|
18
|
-
UpdateProjectMutationResolver,
|
|
18
|
+
UpdateProjectMutationResolver, IdentityGlobalRolesMutationResolver,
|
|
19
19
|
} from './mutation'
|
|
20
20
|
|
|
21
21
|
import { Resolvers } from '../schema'
|
|
@@ -24,6 +24,7 @@ import { IdentityTypeResolver, ProjectTypeResolver } from './types'
|
|
|
24
24
|
import { DateTimeType, JSONType } from '@contember/graphql-utils'
|
|
25
25
|
import { IDPQueryResolver } from './query/IDPQueryResolver'
|
|
26
26
|
import { UpdateIDPMutationResolver } from './mutation/idp/UpdateIDPMutationResolver'
|
|
27
|
+
import { DisablePersonMutationResolver } from './mutation/person/DisablePersonMutationResolver'
|
|
27
28
|
|
|
28
29
|
class ResolverFactory {
|
|
29
30
|
public constructor(
|
|
@@ -44,6 +45,8 @@ class ResolverFactory {
|
|
|
44
45
|
enableIdpMutationResolver: EnableIDPMutationResolver
|
|
45
46
|
updateIdpMutationResolver: UpdateIDPMutationResolver
|
|
46
47
|
|
|
48
|
+
disablePersonMutationResolver: DisablePersonMutationResolver
|
|
49
|
+
|
|
47
50
|
inviteMutationResolver: InviteMutationResolver
|
|
48
51
|
addProjectMemberMutationResolver: AddProjectMemberMutationResolver
|
|
49
52
|
updateProjectMemberMutationResolver: UpdateProjectMemberMutationResolver
|
|
@@ -63,6 +66,8 @@ class ResolverFactory {
|
|
|
63
66
|
identityTypeResolver: IdentityTypeResolver
|
|
64
67
|
projectTypeResolver: ProjectTypeResolver
|
|
65
68
|
|
|
69
|
+
identityGlobalRolesMutationResolver: IdentityGlobalRolesMutationResolver
|
|
70
|
+
|
|
66
71
|
},
|
|
67
72
|
) {}
|
|
68
73
|
|
|
@@ -107,6 +112,7 @@ class ResolverFactory {
|
|
|
107
112
|
disableIDP: this.resolvers.disableIdpMutationResolver.disableIDP.bind(this.resolvers.disableIdpMutationResolver),
|
|
108
113
|
enableIDP: this.resolvers.enableIdpMutationResolver.enableIDP.bind(this.resolvers.enableIdpMutationResolver),
|
|
109
114
|
updateIDP: this.resolvers.updateIdpMutationResolver.updateIDP.bind(this.resolvers.updateIdpMutationResolver),
|
|
115
|
+
disablePerson: this.resolvers.disablePersonMutationResolver.disablePerson.bind(this.resolvers.disablePersonMutationResolver),
|
|
110
116
|
|
|
111
117
|
invite: this.resolvers.inviteMutationResolver.invite.bind(this.resolvers.inviteMutationResolver),
|
|
112
118
|
unmanagedInvite: this.resolvers.inviteMutationResolver.unmanagedInvite.bind(this.resolvers.inviteMutationResolver),
|
|
@@ -132,6 +138,9 @@ class ResolverFactory {
|
|
|
132
138
|
createProject: this.resolvers.createProjectMutationResolver.createProject.bind(this.resolvers.createProjectMutationResolver),
|
|
133
139
|
updateProject: this.resolvers.updateProjectMutationResolver.updateProject.bind(this.resolvers.updateProjectMutationResolver),
|
|
134
140
|
setProjectSecret: this.resolvers.setProjectSecretMutationResolver.setProjectSecret.bind(this.resolvers.setProjectSecretMutationResolver),
|
|
141
|
+
|
|
142
|
+
addGlobalIdentityRoles: this.resolvers.identityGlobalRolesMutationResolver.addGlobalIdentityRoles.bind(this.resolvers.identityGlobalRolesMutationResolver),
|
|
143
|
+
removeGlobalIdentityRoles: this.resolvers.identityGlobalRolesMutationResolver.removeGlobalIdentityRoles.bind(this.resolvers.identityGlobalRolesMutationResolver),
|
|
135
144
|
},
|
|
136
145
|
}
|
|
137
146
|
}
|
|
@@ -4,5 +4,5 @@ export const createErrorResponse = <T>(code: T, developerMessage: string): Error
|
|
|
4
4
|
const error = { code, developerMessage }
|
|
5
5
|
return { ok: false, error, errors: [error] }
|
|
6
6
|
}
|
|
7
|
-
export const createProjectNotFoundResponse = <T>(code: T, projectSlug: string): ErrorResponse<T> =>
|
|
7
|
+
export const createProjectNotFoundResponse = <const T>(code: T, projectSlug: string): ErrorResponse<T> =>
|
|
8
8
|
createErrorResponse(code, `Project ${projectSlug} was not found or you are not allowed to access it.`)
|