@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.
Files changed (374) hide show
  1. package/dist/src/TenantContainer.d.ts +17 -3
  2. package/dist/src/TenantContainer.d.ts.map +1 -1
  3. package/dist/src/TenantContainer.js +7 -0
  4. package/dist/src/TenantContainer.js.map +1 -1
  5. package/dist/src/bridges/system/IdentityFetcher.d.ts +1 -1
  6. package/dist/src/bridges/system/IdentityFetcher.d.ts.map +1 -1
  7. package/dist/src/migrations/2023-01-20-135500-person-email-normalize.d.ts +3 -0
  8. package/dist/src/migrations/2023-01-20-135500-person-email-normalize.d.ts.map +1 -0
  9. package/dist/src/migrations/2023-01-20-135500-person-email-normalize.js +28 -0
  10. package/dist/src/migrations/2023-01-20-135500-person-email-normalize.js.map +1 -0
  11. package/dist/src/migrations/2023-06-03-104000-person-disabled.d.ts +3 -0
  12. package/dist/src/migrations/2023-06-03-104000-person-disabled.d.ts.map +1 -0
  13. package/dist/src/migrations/2023-06-03-104000-person-disabled.js +11 -0
  14. package/dist/src/migrations/2023-06-03-104000-person-disabled.js.map +1 -0
  15. package/dist/src/migrations/runner.d.ts.map +1 -1
  16. package/dist/src/migrations/runner.js +4 -0
  17. package/dist/src/migrations/runner.js.map +1 -1
  18. package/dist/src/migrations/snapshot.d.ts.map +1 -1
  19. package/dist/src/migrations/snapshot.js +1 -0
  20. package/dist/src/migrations/snapshot.js.map +1 -1
  21. package/dist/src/model/authorization/AclSchemaAccessNodeFactory.d.ts.map +1 -1
  22. package/dist/src/model/authorization/AclSchemaAccessNodeFactory.js +14 -9
  23. package/dist/src/model/authorization/AclSchemaAccessNodeFactory.js.map +1 -1
  24. package/dist/src/model/authorization/MembershipMatcher.d.ts +1 -1
  25. package/dist/src/model/authorization/MembershipMatcher.d.ts.map +1 -1
  26. package/dist/src/model/authorization/PermissionActions.d.ts +21 -0
  27. package/dist/src/model/authorization/PermissionActions.d.ts.map +1 -1
  28. package/dist/src/model/authorization/PermissionActions.js +4 -2
  29. package/dist/src/model/authorization/PermissionActions.js.map +1 -1
  30. package/dist/src/model/authorization/PermissionContext.d.ts +1 -1
  31. package/dist/src/model/authorization/PermissionContext.d.ts.map +1 -1
  32. package/dist/src/model/authorization/PermissionsFactory.d.ts.map +1 -1
  33. package/dist/src/model/authorization/PermissionsFactory.js +6 -3
  34. package/dist/src/model/authorization/PermissionsFactory.js.map +1 -1
  35. package/dist/src/model/authorization/Roles.js +1 -1
  36. package/dist/src/model/authorization/Roles.js.map +1 -1
  37. package/dist/src/model/commands/apiKey/CreateApiKeyCommand.d.ts +1 -1
  38. package/dist/src/model/commands/apiKey/CreateApiKeyCommand.d.ts.map +1 -1
  39. package/dist/src/model/commands/identity/PatchIdentityGlobalRoles.d.ts +9 -0
  40. package/dist/src/model/commands/identity/PatchIdentityGlobalRoles.d.ts.map +1 -0
  41. package/dist/src/model/commands/identity/PatchIdentityGlobalRoles.js +29 -0
  42. package/dist/src/model/commands/identity/PatchIdentityGlobalRoles.js.map +1 -0
  43. package/dist/src/model/commands/identity/index.d.ts +1 -0
  44. package/dist/src/model/commands/identity/index.d.ts.map +1 -1
  45. package/dist/src/model/commands/identity/index.js +1 -0
  46. package/dist/src/model/commands/identity/index.js.map +1 -1
  47. package/dist/src/model/commands/idp/UpdateIdpCommand.d.ts +1 -1
  48. package/dist/src/model/commands/idp/UpdateIdpCommand.d.ts.map +1 -1
  49. package/dist/src/model/commands/membership/AddProjectMemberCommand.d.ts +2 -6
  50. package/dist/src/model/commands/membership/AddProjectMemberCommand.d.ts.map +1 -1
  51. package/dist/src/model/commands/membership/AddProjectMemberCommand.js +5 -11
  52. package/dist/src/model/commands/membership/AddProjectMemberCommand.js.map +1 -1
  53. package/dist/src/model/commands/membership/RemoveProjectMemberCommand.d.ts +1 -1
  54. package/dist/src/model/commands/membership/RemoveProjectMemberCommand.d.ts.map +1 -1
  55. package/dist/src/model/commands/membership/RemoveProjectMemberCommand.js +1 -2
  56. package/dist/src/model/commands/membership/RemoveProjectMemberCommand.js.map +1 -1
  57. package/dist/src/model/commands/membership/UpdateProjectMemberCommand.d.ts +1 -1
  58. package/dist/src/model/commands/membership/UpdateProjectMemberCommand.d.ts.map +1 -1
  59. package/dist/src/model/commands/membership/UpdateProjectMemberCommand.js +2 -3
  60. package/dist/src/model/commands/membership/UpdateProjectMemberCommand.js.map +1 -1
  61. package/dist/src/model/commands/membership/types.d.ts +3 -3
  62. package/dist/src/model/commands/membership/types.d.ts.map +1 -1
  63. package/dist/src/model/commands/passwordReset/ResetPasswordCommand.d.ts +2 -6
  64. package/dist/src/model/commands/passwordReset/ResetPasswordCommand.d.ts.map +1 -1
  65. package/dist/src/model/commands/passwordReset/ResetPasswordCommand.js +5 -11
  66. package/dist/src/model/commands/passwordReset/ResetPasswordCommand.js.map +1 -1
  67. package/dist/src/model/commands/person/CreatePersonCommand.d.ts.map +1 -1
  68. package/dist/src/model/commands/person/CreatePersonCommand.js +10 -5
  69. package/dist/src/model/commands/person/CreatePersonCommand.js.map +1 -1
  70. package/dist/src/model/commands/person/DisablePersonCommand.d.ts +7 -0
  71. package/dist/src/model/commands/person/DisablePersonCommand.d.ts.map +1 -0
  72. package/dist/src/model/commands/person/DisablePersonCommand.js +22 -0
  73. package/dist/src/model/commands/person/DisablePersonCommand.js.map +1 -0
  74. package/dist/src/model/dtos/Password.d.ts +1 -1
  75. package/dist/src/model/dtos/Password.d.ts.map +1 -1
  76. package/dist/src/model/mailing/type.js +1 -1
  77. package/dist/src/model/mailing/type.js.map +1 -1
  78. package/dist/src/model/queries/apiKey/ApiKeyQuery.d.ts +23 -0
  79. package/dist/src/model/queries/apiKey/ApiKeyQuery.d.ts.map +1 -0
  80. package/dist/src/model/queries/apiKey/ApiKeyQuery.js +45 -0
  81. package/dist/src/model/queries/apiKey/ApiKeyQuery.js.map +1 -0
  82. package/dist/src/model/queries/apiKey/index.d.ts +1 -1
  83. package/dist/src/model/queries/apiKey/index.d.ts.map +1 -1
  84. package/dist/src/model/queries/apiKey/index.js +1 -1
  85. package/dist/src/model/queries/apiKey/index.js.map +1 -1
  86. package/dist/src/model/queries/idp/types.d.ts +4 -4
  87. package/dist/src/model/queries/idp/types.d.ts.map +1 -1
  88. package/dist/src/model/queries/membership/ProjectMembersQuery.d.ts +1 -1
  89. package/dist/src/model/queries/membership/ProjectMembersQuery.d.ts.map +1 -1
  90. package/dist/src/model/queries/membership/ProjectMembersQuery.js +3 -4
  91. package/dist/src/model/queries/membership/ProjectMembersQuery.js.map +1 -1
  92. package/dist/src/model/queries/person/PersonQuery.d.ts +4 -3
  93. package/dist/src/model/queries/person/PersonQuery.d.ts.map +1 -1
  94. package/dist/src/model/queries/person/PersonQuery.js +22 -0
  95. package/dist/src/model/queries/person/PersonQuery.js.map +1 -1
  96. package/dist/src/model/queries/person/PersonQueryBuilderFactory.d.ts.map +1 -1
  97. package/dist/src/model/queries/person/PersonQueryBuilderFactory.js +1 -0
  98. package/dist/src/model/queries/person/PersonQueryBuilderFactory.js.map +1 -1
  99. package/dist/src/model/queries/person/types.d.ts +4 -3
  100. package/dist/src/model/queries/person/types.d.ts.map +1 -1
  101. package/dist/src/model/queries/project/ProjectSecretsQuery.d.ts +1 -1
  102. package/dist/src/model/queries/project/ProjectSecretsQuery.d.ts.map +1 -1
  103. package/dist/src/model/service/IDPSignInManager.d.ts.map +1 -1
  104. package/dist/src/model/service/IDPSignInManager.js +8 -6
  105. package/dist/src/model/service/IDPSignInManager.js.map +1 -1
  106. package/dist/src/model/service/InviteManager.d.ts +1 -1
  107. package/dist/src/model/service/InviteManager.d.ts.map +1 -1
  108. package/dist/src/model/service/InviteManager.js +2 -3
  109. package/dist/src/model/service/InviteManager.js.map +1 -1
  110. package/dist/src/model/service/OtpAuthenticator.d.ts +1 -1
  111. package/dist/src/model/service/OtpAuthenticator.d.ts.map +1 -1
  112. package/dist/src/model/service/PasswordChangeManager.js +4 -5
  113. package/dist/src/model/service/PasswordChangeManager.js.map +1 -1
  114. package/dist/src/model/service/PasswordResetManager.d.ts +2 -4
  115. package/dist/src/model/service/PasswordResetManager.d.ts.map +1 -1
  116. package/dist/src/model/service/PasswordResetManager.js +2 -6
  117. package/dist/src/model/service/PasswordResetManager.js.map +1 -1
  118. package/dist/src/model/service/PersonAccessManager.d.ts +14 -0
  119. package/dist/src/model/service/PersonAccessManager.d.ts.map +1 -0
  120. package/dist/src/model/service/PersonAccessManager.js +42 -0
  121. package/dist/src/model/service/PersonAccessManager.js.map +1 -0
  122. package/dist/src/model/service/PersonManager.d.ts +7 -0
  123. package/dist/src/model/service/PersonManager.d.ts.map +1 -0
  124. package/dist/src/model/service/PersonManager.js +11 -0
  125. package/dist/src/model/service/PersonManager.js.map +1 -0
  126. package/dist/src/model/service/ProjectManager.d.ts +1 -1
  127. package/dist/src/model/service/ProjectManager.d.ts.map +1 -1
  128. package/dist/src/model/service/ProjectManager.js +2 -3
  129. package/dist/src/model/service/ProjectManager.js.map +1 -1
  130. package/dist/src/model/service/ProjectMemberManager.d.ts +2 -2
  131. package/dist/src/model/service/ProjectMemberManager.d.ts.map +1 -1
  132. package/dist/src/model/service/ProjectMemberManager.js +3 -16
  133. package/dist/src/model/service/ProjectMemberManager.js.map +1 -1
  134. package/dist/src/model/service/RolesManager.d.ts +11 -0
  135. package/dist/src/model/service/RolesManager.d.ts.map +1 -0
  136. package/dist/src/model/service/RolesManager.js +35 -0
  137. package/dist/src/model/service/RolesManager.js.map +1 -0
  138. package/dist/src/model/service/SignInManager.d.ts +2 -2
  139. package/dist/src/model/service/SignInManager.d.ts.map +1 -1
  140. package/dist/src/model/service/SignInManager.js +13 -8
  141. package/dist/src/model/service/SignInManager.js.map +1 -1
  142. package/dist/src/model/service/SignUpManager.d.ts +2 -2
  143. package/dist/src/model/service/SignUpManager.d.ts.map +1 -1
  144. package/dist/src/model/service/SignUpManager.js +2 -3
  145. package/dist/src/model/service/SignUpManager.js.map +1 -1
  146. package/dist/src/model/service/apiKey/ApiKeyManager.d.ts +3 -1
  147. package/dist/src/model/service/apiKey/ApiKeyManager.d.ts.map +1 -1
  148. package/dist/src/model/service/apiKey/ApiKeyManager.js +4 -1
  149. package/dist/src/model/service/apiKey/ApiKeyManager.js.map +1 -1
  150. package/dist/src/model/service/apiKey/ApiKeyService.d.ts +1 -1
  151. package/dist/src/model/service/apiKey/ApiKeyService.d.ts.map +1 -1
  152. package/dist/src/model/service/idp/IDPManager.d.ts +4 -4
  153. package/dist/src/model/service/idp/IDPManager.d.ts.map +1 -1
  154. package/dist/src/model/service/idp/IDPManager.js +7 -8
  155. package/dist/src/model/service/idp/IDPManager.js.map +1 -1
  156. package/dist/src/model/service/idp/providers/AppleProvider.d.ts +1 -1
  157. package/dist/src/model/service/idp/providers/AppleProvider.d.ts.map +1 -1
  158. package/dist/src/model/service/idp/providers/FacebookProvider.d.ts +1 -1
  159. package/dist/src/model/service/idp/providers/FacebookProvider.d.ts.map +1 -1
  160. package/dist/src/model/service/idp/providers/OIDCTypes.d.ts +3 -3
  161. package/dist/src/model/service/idp/providers/OIDCTypes.d.ts.map +1 -1
  162. package/dist/src/model/service/index.d.ts +2 -0
  163. package/dist/src/model/service/index.d.ts.map +1 -1
  164. package/dist/src/model/service/index.js +2 -0
  165. package/dist/src/model/service/index.js.map +1 -1
  166. package/dist/src/model/type/Variables.d.ts +1 -1
  167. package/dist/src/model/type/Variables.d.ts.map +1 -1
  168. package/dist/src/model/utils/Response.d.ts +2 -2
  169. package/dist/src/model/utils/Response.d.ts.map +1 -1
  170. package/dist/src/model/utils/email.d.ts +2 -0
  171. package/dist/src/model/utils/email.d.ts.map +1 -0
  172. package/dist/src/model/utils/email.js +8 -0
  173. package/dist/src/model/utils/email.js.map +1 -0
  174. package/dist/src/model/utils/tokenUtils.d.ts +1 -1
  175. package/dist/src/model/utils/tokenUtils.d.ts.map +1 -1
  176. package/dist/src/model/utils/typeUtils.d.ts +1 -1
  177. package/dist/src/model/utils/typeUtils.d.ts.map +1 -1
  178. package/dist/src/resolvers/ResolverFactory.d.ts +4 -1
  179. package/dist/src/resolvers/ResolverFactory.d.ts.map +1 -1
  180. package/dist/src/resolvers/ResolverFactory.js +3 -0
  181. package/dist/src/resolvers/ResolverFactory.js.map +1 -1
  182. package/dist/src/resolvers/errorUtils.d.ts +3 -3
  183. package/dist/src/resolvers/errorUtils.d.ts.map +1 -1
  184. package/dist/src/resolvers/errorUtils.js.map +1 -1
  185. package/dist/src/resolvers/membershipUtils.d.ts +4 -9
  186. package/dist/src/resolvers/membershipUtils.d.ts.map +1 -1
  187. package/dist/src/resolvers/membershipUtils.js +10 -18
  188. package/dist/src/resolvers/membershipUtils.js.map +1 -1
  189. package/dist/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.js +1 -2
  190. package/dist/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.js.map +1 -1
  191. package/dist/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.js +1 -2
  192. package/dist/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.js.map +1 -1
  193. package/dist/src/resolvers/mutation/identity/GlobalRolesMutationResolver.d.ts +11 -0
  194. package/dist/src/resolvers/mutation/identity/GlobalRolesMutationResolver.d.ts.map +1 -0
  195. package/dist/src/resolvers/mutation/identity/GlobalRolesMutationResolver.js +44 -0
  196. package/dist/src/resolvers/mutation/identity/GlobalRolesMutationResolver.js.map +1 -0
  197. package/dist/src/resolvers/mutation/identity/index.d.ts +2 -0
  198. package/dist/src/resolvers/mutation/identity/index.d.ts.map +1 -0
  199. package/dist/src/resolvers/mutation/identity/index.js +18 -0
  200. package/dist/src/resolvers/mutation/identity/index.js.map +1 -0
  201. package/dist/src/resolvers/mutation/index.d.ts +1 -0
  202. package/dist/src/resolvers/mutation/index.d.ts.map +1 -1
  203. package/dist/src/resolvers/mutation/index.js +1 -0
  204. package/dist/src/resolvers/mutation/index.js.map +1 -1
  205. package/dist/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.js +6 -7
  206. package/dist/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.js.map +1 -1
  207. package/dist/src/resolvers/mutation/person/ChangePasswordMutationResolver.js +2 -3
  208. package/dist/src/resolvers/mutation/person/ChangePasswordMutationResolver.js.map +1 -1
  209. package/dist/src/resolvers/mutation/person/DisablePersonMutationResolver.d.ts +11 -0
  210. package/dist/src/resolvers/mutation/person/DisablePersonMutationResolver.d.ts.map +1 -0
  211. package/dist/src/resolvers/mutation/person/DisablePersonMutationResolver.js +36 -0
  212. package/dist/src/resolvers/mutation/person/DisablePersonMutationResolver.js.map +1 -0
  213. package/dist/src/resolvers/mutation/person/InviteMutationResolver.d.ts.map +1 -1
  214. package/dist/src/resolvers/mutation/person/InviteMutationResolver.js +3 -4
  215. package/dist/src/resolvers/mutation/person/InviteMutationResolver.js.map +1 -1
  216. package/dist/src/resolvers/mutation/person/OtpMutationResolver.d.ts.map +1 -1
  217. package/dist/src/resolvers/mutation/person/OtpMutationResolver.js +3 -4
  218. package/dist/src/resolvers/mutation/person/OtpMutationResolver.js.map +1 -1
  219. package/dist/src/resolvers/mutation/person/ResetPasswordMutationResolver.d.ts.map +1 -1
  220. package/dist/src/resolvers/mutation/person/ResetPasswordMutationResolver.js +2 -10
  221. package/dist/src/resolvers/mutation/person/ResetPasswordMutationResolver.js.map +1 -1
  222. package/dist/src/resolvers/mutation/person/SignInMutationResolver.d.ts.map +1 -1
  223. package/dist/src/resolvers/mutation/person/SignInMutationResolver.js.map +1 -1
  224. package/dist/src/resolvers/mutation/person/SignOutMutationResolver.d.ts.map +1 -1
  225. package/dist/src/resolvers/mutation/person/SignOutMutationResolver.js +5 -2
  226. package/dist/src/resolvers/mutation/person/SignOutMutationResolver.js.map +1 -1
  227. package/dist/src/resolvers/mutation/project/CreateProjectMutationResolver.d.ts.map +1 -1
  228. package/dist/src/resolvers/mutation/project/CreateProjectMutationResolver.js +1 -2
  229. package/dist/src/resolvers/mutation/project/CreateProjectMutationResolver.js.map +1 -1
  230. package/dist/src/resolvers/mutation/project/SetProjectSecretMutationResolver.js +1 -2
  231. package/dist/src/resolvers/mutation/project/SetProjectSecretMutationResolver.js.map +1 -1
  232. package/dist/src/resolvers/mutation/project/UpdateProjectMutationResolver.d.ts.map +1 -1
  233. package/dist/src/resolvers/mutation/project/UpdateProjectMutationResolver.js +1 -2
  234. package/dist/src/resolvers/mutation/project/UpdateProjectMutationResolver.js.map +1 -1
  235. package/dist/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.js +1 -2
  236. package/dist/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.js.map +1 -1
  237. package/dist/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.js +1 -2
  238. package/dist/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.js.map +1 -1
  239. package/dist/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.js +1 -2
  240. package/dist/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.js.map +1 -1
  241. package/dist/src/resolvers/types/ProjectTypeResolver.d.ts.map +1 -1
  242. package/dist/src/resolvers/types/ProjectTypeResolver.js +5 -6
  243. package/dist/src/resolvers/types/ProjectTypeResolver.js.map +1 -1
  244. package/dist/src/schema/index.d.ts +431 -397
  245. package/dist/src/schema/index.d.ts.map +1 -1
  246. package/dist/src/schema/index.js +0 -188
  247. package/dist/src/schema/index.js.map +1 -1
  248. package/dist/src/schema/tenant.graphql.d.ts.map +1 -1
  249. package/dist/src/schema/tenant.graphql.js +97 -21
  250. package/dist/src/schema/tenant.graphql.js.map +1 -1
  251. package/dist/src/tsconfig.tsbuildinfo +1 -1
  252. package/dist/src/utils/Mailer.d.ts +1 -1
  253. package/dist/src/utils/Mailer.d.ts.map +1 -1
  254. package/dist/src/utils/array.d.ts +1 -1
  255. package/dist/src/utils/array.d.ts.map +1 -1
  256. package/dist/src/utils/batchQuery.d.ts +2 -2
  257. package/dist/src/utils/batchQuery.d.ts.map +1 -1
  258. package/dist/tests/cases/integration/db/updateRoles.test.d.ts +2 -0
  259. package/dist/tests/cases/integration/db/updateRoles.test.d.ts.map +1 -0
  260. package/dist/tests/cases/integration/db/updateRoles.test.js +67 -0
  261. package/dist/tests/cases/integration/db/updateRoles.test.js.map +1 -0
  262. package/dist/tests/cases/integration/mocked/confirmOtpMutation.test.js +1 -2
  263. package/dist/tests/cases/integration/mocked/confirmOtpMutation.test.js.map +1 -1
  264. package/dist/tests/cases/integration/mocked/gql/signUp.d.ts.map +1 -1
  265. package/dist/tests/cases/integration/mocked/gql/signUp.js +4 -0
  266. package/dist/tests/cases/integration/mocked/gql/signUp.js.map +1 -1
  267. package/dist/tests/cases/integration/mocked/gql/types.d.ts +1 -1
  268. package/dist/tests/cases/integration/mocked/gql/types.d.ts.map +1 -1
  269. package/dist/tests/cases/integration/mocked/signInMutation.test.js +36 -4
  270. package/dist/tests/cases/integration/mocked/signInMutation.test.js.map +1 -1
  271. package/dist/tests/cases/integration/mocked/signOutMutation.test.js +53 -0
  272. package/dist/tests/cases/integration/mocked/signOutMutation.test.js.map +1 -1
  273. package/dist/tests/cases/integration/mocked/signUpMutation.test.js +9 -0
  274. package/dist/tests/cases/integration/mocked/signUpMutation.test.js.map +1 -1
  275. package/dist/tests/cases/integration/mocked/sql/getApiKeySql.d.ts +11 -0
  276. package/dist/tests/cases/integration/mocked/sql/getApiKeySql.d.ts.map +1 -0
  277. package/dist/tests/cases/integration/mocked/sql/getApiKeySql.js +31 -0
  278. package/dist/tests/cases/integration/mocked/sql/getApiKeySql.js.map +1 -0
  279. package/dist/tests/cases/integration/mocked/sql/getPersonByEmailSql.d.ts.map +1 -1
  280. package/dist/tests/cases/integration/mocked/sql/getPersonByEmailSql.js +2 -1
  281. package/dist/tests/cases/integration/mocked/sql/getPersonByEmailSql.js.map +1 -1
  282. package/dist/tests/cases/integration/mocked/sql/getPersonByIdSql.js +1 -1
  283. package/dist/tests/cases/integration/mocked/sql/getPersonByIdentity.js +1 -1
  284. package/dist/tests/cases/integration/mocked/sql/getPersonByIdpSql.d.ts.map +1 -1
  285. package/dist/tests/cases/integration/mocked/sql/getPersonByIdpSql.js +2 -1
  286. package/dist/tests/cases/integration/mocked/sql/getPersonByIdpSql.js.map +1 -1
  287. package/dist/tests/cases/unit/authorization/membershipAwareAccessNode.test.js +27 -0
  288. package/dist/tests/cases/unit/authorization/membershipAwareAccessNode.test.js.map +1 -1
  289. package/dist/tests/src/mailer.d.ts +2 -2
  290. package/dist/tests/src/mailer.d.ts.map +1 -1
  291. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  292. package/graphql-tenant.codegen.yml +2 -1
  293. package/package.json +14 -14
  294. package/src/TenantContainer.ts +19 -2
  295. package/src/migrations/2023-01-20-135500-person-email-normalize.ts +28 -0
  296. package/src/migrations/2023-06-03-104000-person-disabled.ts +10 -0
  297. package/src/migrations/runner.ts +4 -0
  298. package/src/migrations/snapshot.ts +1 -0
  299. package/src/model/authorization/AclSchemaAccessNodeFactory.ts +16 -6
  300. package/src/model/authorization/PermissionActions.ts +5 -0
  301. package/src/model/authorization/PermissionsFactory.ts +11 -3
  302. package/src/model/commands/identity/PatchIdentityGlobalRoles.ts +28 -0
  303. package/src/model/commands/identity/index.ts +1 -0
  304. package/src/model/commands/membership/AddProjectMemberCommand.ts +9 -10
  305. package/src/model/commands/membership/RemoveProjectMemberCommand.ts +1 -1
  306. package/src/model/commands/membership/UpdateProjectMemberCommand.ts +2 -2
  307. package/src/model/commands/passwordReset/ResetPasswordCommand.ts +9 -16
  308. package/src/model/commands/person/CreatePersonCommand.ts +9 -4
  309. package/src/model/commands/person/DisablePersonCommand.ts +18 -0
  310. package/src/model/queries/apiKey/ApiKeyQuery.ts +64 -0
  311. package/src/model/queries/apiKey/index.ts +1 -1
  312. package/src/model/queries/idp/types.ts +2 -2
  313. package/src/model/queries/membership/ProjectMembersQuery.ts +3 -3
  314. package/src/model/queries/person/PersonQuery.ts +30 -3
  315. package/src/model/queries/person/PersonQueryBuilderFactory.ts +1 -0
  316. package/src/model/queries/person/types.ts +3 -2
  317. package/src/model/service/IDPSignInManager.ts +11 -6
  318. package/src/model/service/InviteManager.ts +2 -2
  319. package/src/model/service/PasswordChangeManager.ts +4 -4
  320. package/src/model/service/PasswordResetManager.ts +3 -5
  321. package/src/model/service/PersonAccessManager.ts +56 -0
  322. package/src/model/service/PersonManager.ts +14 -0
  323. package/src/model/service/ProjectManager.ts +3 -3
  324. package/src/model/service/ProjectMemberManager.ts +3 -15
  325. package/src/model/service/RolesManager.ts +40 -0
  326. package/src/model/service/SignInManager.ts +25 -7
  327. package/src/model/service/SignUpManager.ts +2 -2
  328. package/src/model/service/apiKey/ApiKeyManager.ts +8 -1
  329. package/src/model/service/idp/IDPManager.ts +8 -8
  330. package/src/model/service/index.ts +2 -0
  331. package/src/model/utils/Response.ts +1 -1
  332. package/src/model/utils/email.ts +5 -0
  333. package/src/resolvers/ResolverFactory.ts +10 -1
  334. package/src/resolvers/errorUtils.ts +1 -1
  335. package/src/resolvers/membershipUtils.ts +21 -21
  336. package/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.ts +2 -2
  337. package/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.ts +1 -1
  338. package/src/resolvers/mutation/identity/GlobalRolesMutationResolver.ts +69 -0
  339. package/src/resolvers/mutation/identity/index.ts +1 -0
  340. package/src/resolvers/mutation/index.ts +1 -0
  341. package/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.ts +6 -6
  342. package/src/resolvers/mutation/person/ChangePasswordMutationResolver.ts +2 -2
  343. package/src/resolvers/mutation/person/DisablePersonMutationResolver.ts +48 -0
  344. package/src/resolvers/mutation/person/InviteMutationResolver.ts +5 -12
  345. package/src/resolvers/mutation/person/OtpMutationResolver.ts +4 -6
  346. package/src/resolvers/mutation/person/ResetPasswordMutationResolver.ts +2 -10
  347. package/src/resolvers/mutation/person/SignInMutationResolver.ts +1 -0
  348. package/src/resolvers/mutation/person/SignOutMutationResolver.ts +13 -3
  349. package/src/resolvers/mutation/project/CreateProjectMutationResolver.ts +2 -7
  350. package/src/resolvers/mutation/project/SetProjectSecretMutationResolver.ts +1 -1
  351. package/src/resolvers/mutation/project/UpdateProjectMutationResolver.ts +2 -7
  352. package/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.ts +2 -2
  353. package/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.ts +1 -1
  354. package/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.ts +2 -2
  355. package/src/resolvers/types/ProjectTypeResolver.ts +2 -2
  356. package/src/schema/index.ts +321 -159
  357. package/src/schema/tenant.graphql.ts +97 -21
  358. package/tests/cases/integration/db/updateRoles.test.ts +74 -0
  359. package/tests/cases/integration/mocked/confirmOtpMutation.test.ts +1 -1
  360. package/tests/cases/integration/mocked/gql/signUp.ts +4 -0
  361. package/tests/cases/integration/mocked/signInMutation.test.ts +37 -3
  362. package/tests/cases/integration/mocked/signOutMutation.test.ts +58 -0
  363. package/tests/cases/integration/mocked/signUpMutation.test.ts +9 -0
  364. package/tests/cases/integration/mocked/sql/getApiKeySql.ts +33 -0
  365. package/tests/cases/integration/mocked/sql/getPersonByEmailSql.ts +2 -1
  366. package/tests/cases/integration/mocked/sql/getPersonByIdSql.ts +1 -1
  367. package/tests/cases/integration/mocked/sql/getPersonByIdentity.ts +1 -1
  368. package/tests/cases/integration/mocked/sql/getPersonByIdpSql.ts +2 -1
  369. package/tests/cases/unit/authorization/membershipAwareAccessNode.test.ts +36 -0
  370. package/dist/src/model/queries/apiKey/ApiKeyByTokenQuery.d.ts +0 -22
  371. package/dist/src/model/queries/apiKey/ApiKeyByTokenQuery.d.ts.map +0 -1
  372. package/dist/src/model/queries/apiKey/ApiKeyByTokenQuery.js +0 -33
  373. package/dist/src/model/queries/apiKey/ApiKeyByTokenQuery.js.map +0 -1
  374. 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): PersonQuery {
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): PersonQuery {
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?: string
8
- readonly name?: string
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(SignInIdpErrorCode.InvalidIdpResponse, e.message)
39
+ return new ResponseError('INVALID_IDP_RESPONSE', e.message)
40
40
  }
41
41
  if (e instanceof IDPValidationError) {
42
- return new ResponseError(SignInIdpErrorCode.IdpValidationFailed, e.message)
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(SignInIdpErrorCode.PersonNotFound, `Person ${claim.email} not found`)
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(InitSignInIdpErrorCode.ProviderNotFound, `Identity provider ${idpSlug} not found`)
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(InitSignInIdpErrorCode.IdpValidationFailed, e.message)
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 === InviteMethod.CreatePassword ? (await this.providers.randomBytes(9)).toString('base64') : null)
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 === InviteMethod.ResetPassword) {
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(ChangePasswordErrorCode.TooWeak, weakPassword)
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(ChangeMyPasswordErrorCode.TooWeak, weakPassword)
26
+ return new ResponseError('TOO_WEAK', weakPassword)
27
27
  }
28
28
  if (!person.password_hash) {
29
- return new ResponseError(ChangeMyPasswordErrorCode.NoPasswordSet, 'No password set')
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(ChangeMyPasswordErrorCode.InvalidPassword, 'Password does not match')
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(ResetPasswordErrorCode.PASSWORD_TOO_WEAK, weakPassword)
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 enum ResetPasswordErrorCode {
66
- PASSWORD_TOO_WEAK = 'PASSWORD_TOO_WEAK',
67
- }
65
+ export type ResetPasswordErrorCode = 'PASSWORD_TOO_WEAK'
68
66
 
69
- export type ResetPasswordResponse = Response<undefined, ResetPasswordErrorCode | ResetPasswordCommandErrorCode>
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(CreateProjectResponseErrorCode.AlreadyExists, `Project ${project.slug} already exists`)
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
- CreateProjectResponseErrorCode.InitError,
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, MemberType, ProjectMembersInput } from '../../schema'
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, ResponseError, ResponseOk } from '../utils/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
- const result = await db.commandBus.execute(
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(SignInErrorCode.UnknownEmail, `Person with email ${email} not found`)
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(SignInErrorCode.NoPasswordSet, `No password set`)
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(SignInErrorCode.InvalidPassword, `Password does not match`)
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(SignInErrorCode.OtpRequired, `2FA is enabled. OTP token is required`)
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(SignInErrorCode.InvalidOtpToken, 'OTP token validation has failed')
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(CreateSessionTokenErrorCode.UnknownEmail, `Person with email ${personIdentifier.email} not found`)
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(CreateSessionTokenErrorCode.UnknownPersonId, `Person with id ${personIdentifier.id} not found`)
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(SignUpErrorCode.EmailAlreadyExists, `User with email ${email} already exists`)
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(SignUpErrorCode.TooWeak, weakPassword)
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
- import { ApiKeyByTokenQuery } from '../../queries'
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(AddIdpErrorCode.UnknownType, `IDP type ${idp.type} not found`)
27
+ return new ResponseError('UNKNOWN_TYPE', `IDP type ${idp.type} not found`)
28
28
  }
29
29
  if (e instanceof InvalidIDPConfigurationError) {
30
- return new ResponseError(AddIdpErrorCode.InvalidConfiguration, `Invalid IDP configuration: ${e.message}`)
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(AddIdpErrorCode.AlreadyExists, `IDP with slug ${idp.slug} already exists`)
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(DisableIdpErrorCode.NotFound, `IDP ${slug} not found`)
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(EnableIdpErrorCode.NotFound, `IDP ${slug} not found`)
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(UpdateIdpErrorCode.NotFound, `IDP ${slug} not found`)
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(UpdateIdpErrorCode.InvalidConfiguration, `Invalid IDP configuration: ${e.message}`)
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) {}
@@ -0,0 +1,5 @@
1
+ import { Literal } from '@contember/database'
2
+
3
+ export const normalizeEmail = (email: string) => {
4
+ return email.replaceAll(/\s/g, '').toLocaleLowerCase()
5
+ }
@@ -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.`)