@contember/engine-tenant-api 1.3.6 → 1.4.0-alpha.2

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 (200) hide show
  1. package/dist/src/TenantContainer.d.ts +14 -5
  2. package/dist/src/TenantContainer.d.ts.map +1 -1
  3. package/dist/src/TenantContainer.js +10 -8
  4. package/dist/src/TenantContainer.js.map +1 -1
  5. package/dist/src/migrations/2023-09-01-165000-idp-return-config.d.ts +3 -0
  6. package/dist/src/migrations/2023-09-01-165000-idp-return-config.d.ts.map +1 -0
  7. package/dist/src/migrations/2023-09-01-165000-idp-return-config.js +11 -0
  8. package/dist/src/migrations/2023-09-01-165000-idp-return-config.js.map +1 -0
  9. package/dist/src/migrations/runner.d.ts.map +1 -1
  10. package/dist/src/migrations/runner.js +2 -0
  11. package/dist/src/migrations/runner.js.map +1 -1
  12. package/dist/src/migrations/snapshot.d.ts.map +1 -1
  13. package/dist/src/migrations/snapshot.js +2 -1
  14. package/dist/src/migrations/snapshot.js.map +1 -1
  15. package/dist/src/model/authorization/PermissionActions.d.ts +5 -0
  16. package/dist/src/model/authorization/PermissionActions.d.ts.map +1 -1
  17. package/dist/src/model/authorization/PermissionActions.js +1 -0
  18. package/dist/src/model/authorization/PermissionActions.js.map +1 -1
  19. package/dist/src/model/authorization/PermissionsFactory.d.ts.map +1 -1
  20. package/dist/src/model/authorization/PermissionsFactory.js +1 -0
  21. package/dist/src/model/authorization/PermissionsFactory.js.map +1 -1
  22. package/dist/src/model/commands/apiKey/ApiKeyHelper.d.ts +1 -1
  23. package/dist/src/model/commands/apiKey/ApiKeyHelper.d.ts.map +1 -1
  24. package/dist/src/model/commands/apiKey/ApiKeyHelper.js.map +1 -1
  25. package/dist/src/model/commands/apiKey/ProlongApiKeyCommand.d.ts +3 -2
  26. package/dist/src/model/commands/apiKey/ProlongApiKeyCommand.d.ts.map +1 -1
  27. package/dist/src/model/commands/apiKey/ProlongApiKeyCommand.js +10 -2
  28. package/dist/src/model/commands/apiKey/ProlongApiKeyCommand.js.map +1 -1
  29. package/dist/src/model/commands/idp/CreateIdpCommand.d.ts.map +1 -1
  30. package/dist/src/model/commands/idp/CreateIdpCommand.js +2 -1
  31. package/dist/src/model/commands/idp/CreateIdpCommand.js.map +1 -1
  32. package/dist/src/model/commands/idp/UpdateIdpCommand.d.ts +1 -1
  33. package/dist/src/model/commands/idp/UpdateIdpCommand.d.ts.map +1 -1
  34. package/dist/src/model/commands/idp/UpdateIdpCommand.js +3 -2
  35. package/dist/src/model/commands/idp/UpdateIdpCommand.js.map +1 -1
  36. package/dist/src/model/commands/person/ChangeProfileCommand.d.ts +12 -0
  37. package/dist/src/model/commands/person/ChangeProfileCommand.d.ts.map +1 -0
  38. package/dist/src/model/commands/person/ChangeProfileCommand.js +21 -0
  39. package/dist/src/model/commands/person/ChangeProfileCommand.js.map +1 -0
  40. package/dist/src/model/queries/idp/helpers.d.ts +1 -1
  41. package/dist/src/model/queries/idp/helpers.d.ts.map +1 -1
  42. package/dist/src/model/queries/idp/helpers.js +3 -2
  43. package/dist/src/model/queries/idp/helpers.js.map +1 -1
  44. package/dist/src/model/queries/idp/types.d.ts +1 -0
  45. package/dist/src/model/queries/idp/types.d.ts.map +1 -1
  46. package/dist/src/model/service/EmailValidator.d.ts +8 -0
  47. package/dist/src/model/service/EmailValidator.d.ts.map +1 -0
  48. package/dist/src/model/service/EmailValidator.js +23 -0
  49. package/dist/src/model/service/EmailValidator.js.map +1 -0
  50. package/dist/src/model/service/IDPSignInManager.d.ts +2 -6
  51. package/dist/src/model/service/IDPSignInManager.d.ts.map +1 -1
  52. package/dist/src/model/service/IDPSignInManager.js +7 -1
  53. package/dist/src/model/service/IDPSignInManager.js.map +1 -1
  54. package/dist/src/model/service/PersonManager.d.ts +10 -0
  55. package/dist/src/model/service/PersonManager.d.ts.map +1 -1
  56. package/dist/src/model/service/PersonManager.js +15 -0
  57. package/dist/src/model/service/PersonManager.js.map +1 -1
  58. package/dist/src/model/service/SignUpManager.d.ts +3 -1
  59. package/dist/src/model/service/SignUpManager.d.ts.map +1 -1
  60. package/dist/src/model/service/SignUpManager.js +6 -11
  61. package/dist/src/model/service/SignUpManager.js.map +1 -1
  62. package/dist/src/model/service/apiKey/ApiKeyManager.d.ts +1 -1
  63. package/dist/src/model/service/apiKey/ApiKeyManager.d.ts.map +1 -1
  64. package/dist/src/model/service/apiKey/ApiKeyManager.js +3 -3
  65. package/dist/src/model/service/apiKey/ApiKeyManager.js.map +1 -1
  66. package/dist/src/model/service/idp/IDPHandlerRegistry.d.ts +1 -0
  67. package/dist/src/model/service/idp/IDPHandlerRegistry.d.ts.map +1 -1
  68. package/dist/src/model/service/idp/IDPHandlerRegistry.js +4 -0
  69. package/dist/src/model/service/idp/IDPHandlerRegistry.js.map +1 -1
  70. package/dist/src/model/service/idp/IDPManager.d.ts +3 -1
  71. package/dist/src/model/service/idp/IDPManager.d.ts.map +1 -1
  72. package/dist/src/model/service/idp/IDPManager.js +35 -5
  73. package/dist/src/model/service/idp/IDPManager.js.map +1 -1
  74. package/dist/src/model/service/idp/IdentityProviderHandler.d.ts +1 -0
  75. package/dist/src/model/service/idp/IdentityProviderHandler.d.ts.map +1 -1
  76. package/dist/src/model/service/idp/index.d.ts +1 -0
  77. package/dist/src/model/service/idp/index.d.ts.map +1 -1
  78. package/dist/src/model/service/idp/index.js +1 -0
  79. package/dist/src/model/service/idp/index.js.map +1 -1
  80. package/dist/src/model/service/idp/providers/AppleProvider.d.ts +1 -0
  81. package/dist/src/model/service/idp/providers/AppleProvider.d.ts.map +1 -1
  82. package/dist/src/model/service/idp/providers/AppleProvider.js +3 -0
  83. package/dist/src/model/service/idp/providers/AppleProvider.js.map +1 -1
  84. package/dist/src/model/service/idp/providers/FacebookProvider.d.ts +1 -0
  85. package/dist/src/model/service/idp/providers/FacebookProvider.d.ts.map +1 -1
  86. package/dist/src/model/service/idp/providers/FacebookProvider.js +3 -0
  87. package/dist/src/model/service/idp/providers/FacebookProvider.js.map +1 -1
  88. package/dist/src/model/service/idp/providers/OIDCProvider.d.ts +1 -0
  89. package/dist/src/model/service/idp/providers/OIDCProvider.d.ts.map +1 -1
  90. package/dist/src/model/service/idp/providers/OIDCProvider.js +3 -0
  91. package/dist/src/model/service/idp/providers/OIDCProvider.js.map +1 -1
  92. package/dist/src/model/service/index.d.ts +7 -5
  93. package/dist/src/model/service/index.d.ts.map +1 -1
  94. package/dist/src/model/service/index.js +7 -5
  95. package/dist/src/model/service/index.js.map +1 -1
  96. package/dist/src/model/type/IdentityProvider.d.ts +1 -0
  97. package/dist/src/model/type/IdentityProvider.d.ts.map +1 -1
  98. package/dist/src/model/utils/DatabaseContext.d.ts +0 -6
  99. package/dist/src/model/utils/DatabaseContext.d.ts.map +1 -1
  100. package/dist/src/model/utils/DatabaseContext.js +1 -11
  101. package/dist/src/model/utils/DatabaseContext.js.map +1 -1
  102. package/dist/src/resolvers/ResolverFactory.d.ts +2 -1
  103. package/dist/src/resolvers/ResolverFactory.d.ts.map +1 -1
  104. package/dist/src/resolvers/ResolverFactory.js +1 -0
  105. package/dist/src/resolvers/ResolverFactory.js.map +1 -1
  106. package/dist/src/resolvers/mutation/idp/AddIDPMutationResolver.d.ts.map +1 -1
  107. package/dist/src/resolvers/mutation/idp/AddIDPMutationResolver.js +2 -1
  108. package/dist/src/resolvers/mutation/idp/AddIDPMutationResolver.js.map +1 -1
  109. package/dist/src/resolvers/mutation/idp/UpdateIDPMutationResolver.d.ts.map +1 -1
  110. package/dist/src/resolvers/mutation/idp/UpdateIDPMutationResolver.js +3 -2
  111. package/dist/src/resolvers/mutation/idp/UpdateIDPMutationResolver.js.map +1 -1
  112. package/dist/src/resolvers/mutation/person/ChangeProfileMutationResolver.d.ts +10 -0
  113. package/dist/src/resolvers/mutation/person/ChangeProfileMutationResolver.d.ts.map +1 -0
  114. package/dist/src/resolvers/mutation/person/ChangeProfileMutationResolver.js +33 -0
  115. package/dist/src/resolvers/mutation/person/ChangeProfileMutationResolver.js.map +1 -0
  116. package/dist/src/resolvers/mutation/person/index.d.ts +1 -0
  117. package/dist/src/resolvers/mutation/person/index.d.ts.map +1 -1
  118. package/dist/src/resolvers/mutation/person/index.js +1 -0
  119. package/dist/src/resolvers/mutation/person/index.js.map +1 -1
  120. package/dist/src/resolvers/query/IDPQueryResolver.d.ts +3 -0
  121. package/dist/src/resolvers/query/IDPQueryResolver.d.ts.map +1 -1
  122. package/dist/src/resolvers/query/IDPQueryResolver.js +4 -1
  123. package/dist/src/resolvers/query/IDPQueryResolver.js.map +1 -1
  124. package/dist/src/schema/index.d.ts +38 -0
  125. package/dist/src/schema/index.d.ts.map +1 -1
  126. package/dist/src/schema/tenant.graphql.d.ts.map +1 -1
  127. package/dist/src/schema/tenant.graphql.js +23 -1
  128. package/dist/src/schema/tenant.graphql.js.map +1 -1
  129. package/dist/src/tsconfig.tsbuildinfo +1 -1
  130. package/dist/tests/cases/integration/mocked/changeMyProfileMutation.test.d.ts +2 -0
  131. package/dist/tests/cases/integration/mocked/changeMyProfileMutation.test.d.ts.map +1 -0
  132. package/dist/tests/cases/integration/mocked/changeMyProfileMutation.test.js +182 -0
  133. package/dist/tests/cases/integration/mocked/changeMyProfileMutation.test.js.map +1 -0
  134. package/dist/tests/cases/integration/mocked/gql/changeMyProfile.d.ts +6 -0
  135. package/dist/tests/cases/integration/mocked/gql/changeMyProfile.d.ts.map +1 -0
  136. package/dist/tests/cases/integration/mocked/gql/changeMyProfile.js +17 -0
  137. package/dist/tests/cases/integration/mocked/gql/changeMyProfile.js.map +1 -0
  138. package/dist/tests/cases/integration/mocked/signInIdpMutation.test.js +2 -0
  139. package/dist/tests/cases/integration/mocked/signInIdpMutation.test.js.map +1 -1
  140. package/dist/tests/cases/integration/mocked/sql/getIdpBySlugSql.js +1 -1
  141. package/dist/tests/cases/integration/mocked/sql/getPersonByIdentity.d.ts +1 -0
  142. package/dist/tests/cases/integration/mocked/sql/getPersonByIdentity.d.ts.map +1 -1
  143. package/dist/tests/cases/integration/mocked/sql/getPersonByIdentity.js +1 -0
  144. package/dist/tests/cases/integration/mocked/sql/getPersonByIdentity.js.map +1 -1
  145. package/dist/tests/cases/integration/mocked/sql/updatePesonNameSql.d.ts +15 -0
  146. package/dist/tests/cases/integration/mocked/sql/updatePesonNameSql.d.ts.map +1 -0
  147. package/dist/tests/cases/integration/mocked/sql/updatePesonNameSql.js +29 -0
  148. package/dist/tests/cases/integration/mocked/sql/updatePesonNameSql.js.map +1 -0
  149. package/dist/tests/src/testTenant.d.ts.map +1 -1
  150. package/dist/tests/src/testTenant.js +1 -0
  151. package/dist/tests/src/testTenant.js.map +1 -1
  152. package/dist/tests/src/testTenantDb.d.ts.map +1 -1
  153. package/dist/tests/src/testTenantDb.js +1 -0
  154. package/dist/tests/src/testTenantDb.js.map +1 -1
  155. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  156. package/package.json +14 -14
  157. package/src/TenantContainer.ts +28 -14
  158. package/src/migrations/2023-09-01-165000-idp-return-config.ts +10 -0
  159. package/src/migrations/runner.ts +3 -0
  160. package/src/migrations/snapshot.ts +2 -1
  161. package/src/model/authorization/PermissionActions.ts +1 -0
  162. package/src/model/authorization/PermissionsFactory.ts +1 -0
  163. package/src/model/commands/apiKey/ApiKeyHelper.ts +1 -1
  164. package/src/model/commands/apiKey/ProlongApiKeyCommand.ts +17 -2
  165. package/src/model/commands/idp/CreateIdpCommand.ts +2 -1
  166. package/src/model/commands/idp/UpdateIdpCommand.ts +3 -2
  167. package/src/model/commands/person/ChangeProfileCommand.ts +21 -0
  168. package/src/model/queries/idp/helpers.ts +3 -2
  169. package/src/model/queries/idp/types.ts +1 -0
  170. package/src/model/service/EmailValidator.ts +26 -0
  171. package/src/model/service/IDPSignInManager.ts +11 -8
  172. package/src/model/service/PersonManager.ts +23 -0
  173. package/src/model/service/SignUpManager.ts +9 -11
  174. package/src/model/service/apiKey/ApiKeyManager.ts +8 -2
  175. package/src/model/service/idp/IDPHandlerRegistry.ts +4 -0
  176. package/src/model/service/idp/IDPManager.ts +43 -5
  177. package/src/model/service/idp/IdentityProviderHandler.ts +2 -0
  178. package/src/model/service/idp/index.ts +1 -0
  179. package/src/model/service/idp/providers/AppleProvider.ts +4 -1
  180. package/src/model/service/idp/providers/FacebookProvider.ts +5 -1
  181. package/src/model/service/idp/providers/OIDCProvider.ts +4 -0
  182. package/src/model/service/index.ts +8 -5
  183. package/src/model/type/IdentityProvider.ts +1 -0
  184. package/src/model/utils/DatabaseContext.ts +1 -12
  185. package/src/resolvers/ResolverFactory.ts +5 -1
  186. package/src/resolvers/mutation/idp/AddIDPMutationResolver.ts +1 -0
  187. package/src/resolvers/mutation/idp/UpdateIDPMutationResolver.ts +2 -1
  188. package/src/resolvers/mutation/person/ChangeProfileMutationResolver.ts +42 -0
  189. package/src/resolvers/mutation/person/index.ts +1 -0
  190. package/src/resolvers/query/IDPQueryResolver.ts +9 -2
  191. package/src/schema/index.ts +48 -0
  192. package/src/schema/tenant.graphql.ts +23 -1
  193. package/tests/cases/integration/mocked/changeMyProfileMutation.test.ts +187 -0
  194. package/tests/cases/integration/mocked/gql/changeMyProfile.ts +14 -0
  195. package/tests/cases/integration/mocked/signInIdpMutation.test.ts +2 -0
  196. package/tests/cases/integration/mocked/sql/getIdpBySlugSql.ts +1 -1
  197. package/tests/cases/integration/mocked/sql/getPersonByIdentity.ts +3 -2
  198. package/tests/cases/integration/mocked/sql/updatePesonNameSql.ts +26 -0
  199. package/tests/src/testTenant.ts +1 -0
  200. package/tests/src/testTenantDb.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/engine-tenant-api",
3
- "version": "1.3.6",
3
+ "version": "1.4.0-alpha.2",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/src/index.js",
6
6
  "typings": "dist/src/index.d.ts",
@@ -13,17 +13,17 @@
13
13
  "test": "vitest --dir ./tests/cases --no-threads"
14
14
  },
15
15
  "dependencies": {
16
- "@contember/authorization": "1.3.6",
17
- "@contember/config-loader": "1.3.6",
18
- "@contember/database": "1.3.6",
19
- "@contember/database-migrations": "1.3.6",
20
- "@contember/dic": "1.3.6",
21
- "@contember/graphql-utils": "1.3.6",
22
- "@contember/logger": "1.3.6",
23
- "@contember/schema": "1.3.6",
24
- "@contember/schema-utils": "1.3.6",
25
- "@contember/typesafe": "1.3.6",
26
- "@graphql-tools/utils": "^8.6.13",
16
+ "@contember/authorization": "1.4.0-alpha.2",
17
+ "@contember/config-loader": "1.4.0-alpha.2",
18
+ "@contember/database": "1.4.0-alpha.2",
19
+ "@contember/database-migrations": "1.4.0-alpha.2",
20
+ "@contember/dic": "1.4.0-alpha.2",
21
+ "@contember/graphql-utils": "1.4.0-alpha.2",
22
+ "@contember/logger": "1.4.0-alpha.2",
23
+ "@contember/schema": "1.4.0-alpha.2",
24
+ "@contember/schema-utils": "1.4.0-alpha.2",
25
+ "@contember/typesafe": "1.4.0-alpha.2",
26
+ "@graphql-tools/utils": "^10.0.7",
27
27
  "graphql-tag": "^2.12.5",
28
28
  "jose": "^4.10",
29
29
  "mustache": "^4.0.0",
@@ -32,12 +32,12 @@
32
32
  "otpauth": "^7.0.6"
33
33
  },
34
34
  "devDependencies": {
35
- "@contember/database-tester": "1.3.6",
35
+ "@contember/database-tester": "1.4.0-alpha.2",
36
36
  "@graphql-codegen/cli": "^2.6.2",
37
37
  "@graphql-codegen/typescript": "^2.5.1",
38
38
  "@graphql-codegen/typescript-operations": "^2.4.2",
39
39
  "@graphql-codegen/typescript-resolvers": "^2.6.6",
40
- "@graphql-tools/schema": "^8.3.5",
40
+ "@graphql-tools/schema": "^10.0.0",
41
41
  "@types/mustache": "^4.0.0",
42
42
  "@types/node": "^18",
43
43
  "@types/nodemailer": "^6.4.0",
@@ -7,11 +7,12 @@ import {
7
7
  ApiKeyService,
8
8
  AppleProvider,
9
9
  DatabaseContext,
10
- DatabaseContextFactory,
10
+ EmailValidator,
11
11
  FacebookProvider,
12
12
  Identity,
13
13
  IdentityFactory,
14
14
  IDPHandlerRegistry,
15
+ IDPManager,
15
16
  IDPSignInManager,
16
17
  InviteManager,
17
18
  MailTemplateManager,
@@ -23,6 +24,8 @@ import {
23
24
  PasswordResetManager,
24
25
  PermissionContextFactory,
25
26
  PermissionsFactory,
27
+ PersonAccessManager,
28
+ PersonManager,
26
29
  ProjectInitializer,
27
30
  ProjectManager,
28
31
  ProjectMemberManager,
@@ -34,12 +37,12 @@ import {
34
37
  SignInManager,
35
38
  SignUpManager,
36
39
  UserMailer,
37
- PersonAccessManager,
38
40
  } from './model'
39
41
  import {
40
42
  AddIDPMutationResolver,
41
43
  AddProjectMemberMutationResolver,
42
44
  ChangePasswordMutationResolver,
45
+ ChangeProfileMutationResolver,
43
46
  CreateApiKeyMutationResolver,
44
47
  CreateProjectMutationResolver,
45
48
  DisableApiKeyMutationResolver,
@@ -70,12 +73,10 @@ import * as Schema from './schema'
70
73
  import { createMailer, MailerOptions, TemplateRenderer } from './utils'
71
74
  import { IdentityFetcher } from './bridges/system/IdentityFetcher'
72
75
  import { SignInResponseFactory } from './resolvers/responseHelpers/SignInResponseFactory'
73
- import { IDPManager } from './model/service/idp/IDPManager'
74
76
  import { IDPQueryResolver } from './resolvers/query/IDPQueryResolver'
75
77
  import { UpdateIDPMutationResolver } from './resolvers/mutation/idp/UpdateIDPMutationResolver'
76
78
  import { TenantCredentials, TenantMigrationsRunner } from './migrations'
77
79
  import { DisablePersonMutationResolver } from './resolvers/mutation/person/DisablePersonMutationResolver'
78
- import { PersonManager } from './model/service/PersonManager'
79
80
 
80
81
  export interface TenantContainer {
81
82
  projectMemberManager: ProjectMemberManager
@@ -87,12 +88,15 @@ export interface TenantContainer {
87
88
  authorizator: Authorizator<Identity>
88
89
  identityFetcher: IdentityFetcher
89
90
  databaseContext: DatabaseContext
91
+ readDatabaseContext: DatabaseContext
90
92
  migrationsRunner: TenantMigrationsRunner
91
93
  connection: Connection.ConnectionType
94
+ readConnection: Connection.ConnectionType
92
95
  }
93
96
 
94
97
  export interface TenantContainerArgs {
95
98
  connection: Connection.ConnectionType
99
+ readConnection: Connection.ConnectionType
96
100
  dbCredentials: DatabaseConfig
97
101
  mailOptions: MailerOptions
98
102
  projectSchemaResolver: ProjectSchemaResolver
@@ -104,7 +108,7 @@ export interface TenantContainerArgs {
104
108
  export class TenantContainerFactory {
105
109
  constructor(
106
110
  private readonly providers: Omit<Providers, 'encrypt' | 'decrypt'>,
107
- ) {}
111
+ ) { }
108
112
 
109
113
  create(args: TenantContainerArgs): TenantContainer {
110
114
  return this.createBuilder(args)
@@ -119,8 +123,10 @@ export class TenantContainerFactory {
119
123
  'resolverContextFactory',
120
124
  'identityFetcher',
121
125
  'databaseContext',
126
+ 'readDatabaseContext',
122
127
  'migrationsRunner',
123
128
  'connection',
129
+ 'readConnection',
124
130
  )
125
131
  }
126
132
 
@@ -134,7 +140,7 @@ export class TenantContainerFactory {
134
140
  args.projectSchemaResolver)
135
141
  .addService('templateRenderer', () =>
136
142
  new TemplateRenderer())
137
- .addService('accessEvaluator', ({}) =>
143
+ .addService('accessEvaluator', ({ }) =>
138
144
  new AccessEvaluator.PermissionEvaluator(new PermissionsFactory().create()))
139
145
  .addService('authorizator', ({ accessEvaluator }) =>
140
146
  new Authorizator.Default(accessEvaluator))
@@ -144,8 +150,10 @@ export class TenantContainerFactory {
144
150
  new ApiKeyService())
145
151
  .addService('apiKeyManager', ({ apiKeyService }) =>
146
152
  new ApiKeyManager(apiKeyService))
147
- .addService('signUpManager', () =>
148
- new SignUpManager())
153
+ .addService('emailValidator', () =>
154
+ new EmailValidator())
155
+ .addService('signUpManager', ({ emailValidator }) =>
156
+ new SignUpManager(emailValidator))
149
157
  .addService('passwordChangeManager', ({ providers }) =>
150
158
  new PasswordChangeManager(providers))
151
159
  .addService('projectMemberManager', () =>
@@ -162,8 +170,8 @@ export class TenantContainerFactory {
162
170
  new ProjectManager(secretManager, args.projectInitializer, apiKeyService))
163
171
  .addService('personAccessManager', ({ apiKeyManager }) =>
164
172
  new PersonAccessManager(apiKeyManager))
165
- .addService('personManager', () =>
166
- new PersonManager())
173
+ .addService('personManager', ({ emailValidator }) =>
174
+ new PersonManager(emailValidator))
167
175
  .addService('passwordResetManager', ({ userMailer, projectManager }) =>
168
176
  new PasswordResetManager(userMailer, projectManager))
169
177
  .addService('idpRegistry', () => {
@@ -200,18 +208,20 @@ export class TenantContainerFactory {
200
208
  new SignInResponseFactory(permissionContextFactory, identityTypeResolver))
201
209
  .addService('meQueryResolver', () =>
202
210
  new MeQueryResolver())
203
- .addService('idpQueryResolver', () =>
204
- new IDPQueryResolver())
211
+ .addService('idpQueryResolver', ({ idpManager }) =>
212
+ new IDPQueryResolver(idpManager))
205
213
  .addService('projectQueryResolver', ({ projectManager }) =>
206
214
  new ProjectQueryResolver(projectManager))
207
215
  .addService('projectMembersQueryResolver', ({ projectManager, projectMemberManager }) =>
208
216
  new ProjectMembersQueryResolver(projectManager, projectMemberManager))
209
217
  .addService('signUpMutationResolver', ({ signUpManager, apiKeyManager }) =>
210
218
  new SignUpMutationResolver(signUpManager, apiKeyManager))
211
- .addService('signInMutationResolver', ({ signInManager, signInResponseFactory }) =>
219
+ .addService('signInMutationResolver', ({ signInManager, signInResponseFactory }) =>
212
220
  new SignInMutationResolver(signInManager, signInResponseFactory))
213
221
  .addService('signOutMutationResolver', ({ apiKeyManager }) =>
214
222
  new SignOutMutationResolver(apiKeyManager))
223
+ .addService('changeProfileMutationResolver', ({ personManager }) =>
224
+ new ChangeProfileMutationResolver(personManager))
215
225
  .addService('changePasswordMutationResolver', ({ passwordChangeManager }) =>
216
226
  new ChangePasswordMutationResolver(passwordChangeManager))
217
227
  .addService('resetPasswordMutationResolver', ({ passwordResetManager, permissionContextFactory }) =>
@@ -258,8 +268,12 @@ export class TenantContainerFactory {
258
268
  new ResolverFactory(container).create())
259
269
  .addService('connection', () =>
260
270
  args.connection)
271
+ .addService('readConnection', () =>
272
+ args.readConnection)
261
273
  .addService('databaseContext', ({ connection, providers }) =>
262
- new DatabaseContextFactory(connection, providers).create())
274
+ new DatabaseContext(connection.createClient('tenant', { module: 'tenant' }), providers))
275
+ .addService('readDatabaseContext', ({ readConnection, providers }) =>
276
+ new DatabaseContext(readConnection.createClient('tenant', { module: 'tenant' }), providers))
263
277
  .addService('identityFetcher', ({ databaseContext }) =>
264
278
  new IdentityFetcher(databaseContext.client))
265
279
  .addService('migrationsRunner', ({ providers }) =>
@@ -0,0 +1,10 @@
1
+ import { MigrationBuilder } from '@contember/database-migrations'
2
+
3
+ const sql = `
4
+ ALTER TABLE identity_provider
5
+ ADD COLUMN init_returns_config BOOLEAN NOT NULL DEFAULT FALSE;
6
+ `
7
+
8
+ export default async function (builder: MigrationBuilder) {
9
+ builder.sql(sql)
10
+ }
@@ -35,6 +35,8 @@ import _20220714145000personloginoptions from './2022-07-14-145000-person-login-
35
35
  import _20221108projectupdatenotification from './2022-11-08-project-update-notification'
36
36
  import _20230120135500personemailnormalize from './2023-01-20-135500-person-email-normalize'
37
37
  import _20230603104000persondisabled from './2023-06-03-104000-person-disabled'
38
+ import _20230901165000idpreturnconfig from './2023-09-01-165000-idp-return-config'
39
+
38
40
  import snapshot from './snapshot'
39
41
  import { computeTokenHash, Providers } from '../model'
40
42
  import { Logger } from '@contember/logger'
@@ -82,6 +84,7 @@ const migrations = {
82
84
  '2022-11-08-project-update-notification': _20221108projectupdatenotification,
83
85
  '2023-01-20-135500-person-email-normalize': _20230120135500personemailnormalize,
84
86
  '2023-06-03-104000-person-disabled': _20230603104000persondisabled,
87
+ '2023-09-01-165000-idp-return-config': _20230901165000idpreturnconfig,
85
88
  }
86
89
 
87
90
  export class TenantMigrationsRunner {
@@ -54,7 +54,8 @@ CREATE TABLE "identity_provider" (
54
54
  "configuration" "jsonb" NOT NULL,
55
55
  "disabled_at" timestamp with time zone,
56
56
  "auto_sign_up" boolean DEFAULT false NOT NULL,
57
- "exclusive" boolean DEFAULT false
57
+ "exclusive" boolean DEFAULT false,
58
+ "init_returns_config" boolean DEFAULT false NOT NULL
58
59
  );
59
60
  CREATE TABLE "mail_template" (
60
61
  "id" "uuid" NOT NULL,
@@ -23,6 +23,7 @@ namespace PermissionActions {
23
23
  export const PERSON_SIGN_UP = (roles?: readonly string[]) => Authorizator.createAction(Resources.person, 'signUp', { roles })
24
24
  export const PERSON_SIGN_OUT = Authorizator.createAction(Resources.person, 'signOut')
25
25
  export const PERSON_SETUP_OTP = Authorizator.createAction(Resources.person, 'setupOtp')
26
+ export const PERSON_CHANGE_MY_PROFILE = Authorizator.createAction(Resources.person, 'changeMyProfile')
26
27
  export const PERSON_CHANGE_PASSWORD = Authorizator.createAction(Resources.person, 'changePassword')
27
28
  export const PERSON_CHANGE_MY_PASSWORD = Authorizator.createAction(Resources.person, 'changeMyPassword')
28
29
  export const PERSON_RESET_PASSWORD = Authorizator.createAction(Resources.person, 'resetPassword')
@@ -26,6 +26,7 @@ class PermissionsFactory {
26
26
  permissions.allow(TenantRole.LOGIN, PermissionActions.PERSON_SIGN_IN_IDP)
27
27
 
28
28
  permissions.allow(TenantRole.PERSON, PermissionActions.PERSON_CHANGE_MY_PASSWORD)
29
+ permissions.allow(TenantRole.PERSON, PermissionActions.PERSON_CHANGE_MY_PROFILE)
29
30
  permissions.allow(TenantRole.PERSON, PermissionActions.PERSON_SIGN_OUT)
30
31
  permissions.allow(TenantRole.PERSON, PermissionActions.PERSON_SETUP_OTP)
31
32
 
@@ -4,7 +4,7 @@ import { plusMinutes } from '../../utils/time'
4
4
 
5
5
  const DEFAULT_EXPIRATION = 30
6
6
  export class ApiKeyHelper {
7
- public static getExpiration(providers: Providers, type: ApiKey.Type, expiration?: number): Date | null {
7
+ public static getExpiration(providers: Providers, type: ApiKey.Type, expiration?: number | null): Date | null {
8
8
  switch (type) {
9
9
  case ApiKey.Type.PERMANENT:
10
10
  return null
@@ -3,15 +3,30 @@ import { ApiKey } from '../../type'
3
3
  import { ApiKeyHelper } from './ApiKeyHelper'
4
4
  import { UpdateBuilder } from '@contember/database'
5
5
 
6
+ const PROLONG_THROTTLE_MS = 60_000
7
+
6
8
  export class ProlongApiKeyCommand implements Command<void> {
7
- constructor(private readonly id: string, private readonly type: ApiKey.Type, private readonly expiration?: number) {}
9
+ constructor(
10
+ private readonly id: string,
11
+ private readonly type: ApiKey.Type,
12
+ private readonly expiration: number | null,
13
+ private readonly currentExpiration: Date | null,
14
+ ) {}
8
15
 
9
16
  async execute({ db, providers }: Command.Args): Promise<void> {
10
17
  const newExpiration = ApiKeyHelper.getExpiration(providers, this.type, this.expiration)
11
18
  if (newExpiration === null) {
12
19
  return
13
20
  }
14
- const qb = UpdateBuilder.create() //
21
+
22
+ if (this.currentExpiration) {
23
+ const prolongMs = newExpiration.getTime() - this.currentExpiration.getTime()
24
+ if (prolongMs > 0 && prolongMs < PROLONG_THROTTLE_MS) {
25
+ return
26
+ }
27
+ }
28
+
29
+ const qb = UpdateBuilder.create()
15
30
  .table('api_key')
16
31
  .where({ id: this.id })
17
32
  .values({
@@ -9,7 +9,7 @@ export class CreateIdpCommand implements Command<void> {
9
9
  }
10
10
 
11
11
  async execute({ db, providers }: Command.Args): Promise<void> {
12
- const { configuration, options: { autoSignUp, exclusive }, slug, type } = this.data
12
+ const { configuration, options: { autoSignUp, exclusive, initReturnsConfig }, slug, type } = this.data
13
13
  await InsertBuilder.create()
14
14
  .into('identity_provider')
15
15
  .values({
@@ -19,6 +19,7 @@ export class CreateIdpCommand implements Command<void> {
19
19
  type,
20
20
  auto_sign_up: autoSignUp,
21
21
  exclusive,
22
+ init_returns_config: initReturnsConfig,
22
23
  })
23
24
  .execute(db)
24
25
  }
@@ -9,14 +9,15 @@ export class UpdateIdpCommand implements Command<void> {
9
9
  ) {
10
10
  }
11
11
 
12
- async execute({ db, providers }: Command.Args): Promise<void> {
13
- const { configuration, options: { autoSignUp, exclusive } = {} } = this.data
12
+ async execute({ db }: Command.Args): Promise<void> {
13
+ const { configuration, options: { autoSignUp, exclusive, initReturnsConfig } = {} } = this.data
14
14
  await UpdateBuilder.create()
15
15
  .table('identity_provider')
16
16
  .values({
17
17
  configuration,
18
18
  auto_sign_up: autoSignUp,
19
19
  exclusive,
20
+ init_returns_config: initReturnsConfig,
20
21
  })
21
22
  .where({
22
23
  id: this.id,
@@ -0,0 +1,21 @@
1
+ import { Command } from '../Command'
2
+ import { UpdateBuilder } from '@contember/database'
3
+
4
+ export type ChangeProfileData = {
5
+ readonly email?: string
6
+ readonly name?: string | null
7
+ }
8
+
9
+ export class ChangeProfileCommand implements Command<void> {
10
+ constructor(private readonly personId: string, private readonly data: ChangeProfileData) { }
11
+
12
+ async execute({ db }: Command.Args): Promise<void> {
13
+ await UpdateBuilder.create()
14
+ .table('person')
15
+ .values(this.data)
16
+ .where({
17
+ id: this.personId,
18
+ })
19
+ .execute(db)
20
+ }
21
+ }
@@ -10,11 +10,12 @@ export const createBaseIdpQuery = () =>
10
10
  .select('disabled_at', 'disabledAt')
11
11
  .select('auto_sign_up', 'autoSignUp')
12
12
  .select('exclusive')
13
+ .select('init_returns_config', 'initReturnsConfig')
13
14
  .from('identity_provider')
14
15
 
15
- export const createIdpDto = ({ exclusive, autoSignUp, ...row }: IdentityProviderRow): IdentityProviderDto => {
16
+ export const createIdpDto = ({ exclusive, autoSignUp, initReturnsConfig, ...row }: IdentityProviderRow): IdentityProviderDto => {
16
17
  return {
17
18
  ...row,
18
- options: { autoSignUp, exclusive },
19
+ options: { autoSignUp, exclusive, initReturnsConfig },
19
20
  }
20
21
  }
@@ -8,6 +8,7 @@ export type IdentityProviderRow = {
8
8
  configuration: Record<string, unknown>
9
9
  autoSignUp: boolean
10
10
  exclusive: boolean
11
+ initReturnsConfig: boolean
11
12
  }
12
13
 
13
14
  export type IdentityProviderDto =
@@ -0,0 +1,26 @@
1
+ import { DatabaseContext } from '../utils'
2
+ import { validateEmail } from '../utils/email'
3
+ import { ResponseError } from '../utils/Response'
4
+ import { PersonQuery } from '../queries'
5
+
6
+ export class EmailValidator {
7
+
8
+ public async validateEmail(db: DatabaseContext, email: string): Promise<ResponseError<EmailValidatorError> | null> {
9
+ if (!validateEmail(email.trim())) {
10
+ return new ResponseError('INVALID_EMAIL_FORMAT', 'E-mail address is not in a valid format')
11
+ }
12
+ if (await this.isEmailAlreadyUsed(db, email)) {
13
+ return new ResponseError('EMAIL_ALREADY_EXISTS', `User with email ${email} already exists`)
14
+ }
15
+ return null
16
+ }
17
+
18
+ private async isEmailAlreadyUsed(db: DatabaseContext, email: string): Promise<boolean> {
19
+ const personOrNull = await db.queryHandler.fetch(PersonQuery.byEmail(email))
20
+ return personOrNull !== null
21
+ }
22
+ }
23
+
24
+ export type EmailValidatorError =
25
+ | 'EMAIL_ALREADY_EXISTS'
26
+ | 'INVALID_EMAIL_FORMAT'
@@ -2,7 +2,7 @@ import { ApiKeyManager } from './apiKey'
2
2
  import { IdentityProviderBySlugQuery, PersonByIdPQuery, PersonQuery, PersonRow } from '../queries'
3
3
  import { IDPClaim, IDPHandlerRegistry, IDPResponseError, IDPValidationError } from './idp'
4
4
  import { Response, ResponseError, ResponseOk } from '../utils/Response'
5
- import { InitSignInIdpErrorCode, SignInIdpErrorCode } from '../../schema'
5
+ import { InitSignInIdpErrorCode, InitSignInIdpResult, SignInIdpErrorCode } from '../../schema'
6
6
  import { DatabaseContext } from '../utils'
7
7
  import { CreateIdentityCommand, CreatePersonCommand, CreatePersonIdentityProviderIdentifierCommand } from '../commands'
8
8
  import { TenantRole } from '../authorization'
@@ -67,7 +67,15 @@ class IDPSignInManager {
67
67
  const validatedConfig = providerService.validateConfiguration(provider.configuration)
68
68
  try {
69
69
  const initResponse = await providerService.initAuth(validatedConfig, data)
70
- return new ResponseOk(initResponse)
70
+
71
+ const publicConfig = providerService.getPublicConfiguration
72
+ ? providerService.getPublicConfiguration(validatedConfig)
73
+ : validatedConfig
74
+
75
+ return new ResponseOk({
76
+ ...initResponse,
77
+ idpConfiguration: provider.initReturnsConfig ? publicConfig : null,
78
+ })
71
79
  } catch (e) {
72
80
  if (e instanceof IDPValidationError) {
73
81
  return new ResponseError('IDP_VALIDATION_FAILED', e.message)
@@ -123,12 +131,7 @@ class IDPSignInManager {
123
131
  }
124
132
 
125
133
  namespace IDPSignInManager {
126
- export interface InitSignInIDPResult {
127
- readonly authUrl: string
128
- readonly sessionData: any
129
- }
130
-
131
- export type InitSignInIDPResponse = Response<InitSignInIDPResult, InitSignInIdpErrorCode>
134
+ export type InitSignInIDPResponse = Response<InitSignInIdpResult, InitSignInIdpErrorCode>
132
135
 
133
136
  interface SignInIDPResult {
134
137
  readonly person: PersonRow
@@ -1,7 +1,15 @@
1
+ import { ChangeMyProfileErrorCode } from '../../schema'
2
+ import { ChangeProfileCommand, ChangeProfileData } from '../commands/person/ChangeProfileCommand'
3
+ import { Response, ResponseError, ResponseOk } from '../utils/Response'
1
4
  import { PersonQuery, PersonRow } from '../queries'
2
5
  import { DatabaseContext } from '../utils'
6
+ import { EmailValidator } from './EmailValidator'
3
7
 
4
8
  class PersonManager {
9
+ constructor(
10
+ private readonly emailValidator: EmailValidator,
11
+ ) {
12
+ }
5
13
 
6
14
  async findPersonById(dbContext: DatabaseContext, personId: string): Promise<PersonRow | null> {
7
15
  return await dbContext.queryHandler.fetch(
@@ -9,6 +17,21 @@ class PersonManager {
9
17
  )
10
18
  }
11
19
 
20
+ async changeMyProfile(dbContext: DatabaseContext, person: PersonRow, data: ChangeProfileData): Promise<PersonManager.ProfileChangeResponse> {
21
+ if (data.email !== undefined && person.email !== data.email) {
22
+ const validationError = await this.emailValidator.validateEmail(dbContext, data.email)
23
+ if (validationError !== null) {
24
+ return new ResponseError(validationError.error, validationError.errorMessage)
25
+ }
26
+ }
27
+ await dbContext.commandBus.execute(new ChangeProfileCommand(person.id, data))
28
+ return new ResponseOk(null)
29
+ }
30
+
31
+ }
32
+
33
+ namespace PersonManager {
34
+ export type ProfileChangeResponse = Response<null, ChangeMyProfileErrorCode>
12
35
  }
13
36
 
14
37
  export { PersonManager }
@@ -6,7 +6,7 @@ import { getPasswordWeaknessMessage } from '../utils/password'
6
6
  import { Response, ResponseError, ResponseOk } from '../utils/Response'
7
7
  import { DatabaseContext } from '../utils'
8
8
  import { MaybePassword } from '../dtos'
9
- import { validateEmail } from '../utils/email'
9
+ import { EmailValidator } from './EmailValidator'
10
10
 
11
11
  type SignUpUser = {
12
12
  email: string
@@ -16,12 +16,15 @@ type SignUpUser = {
16
16
  }
17
17
 
18
18
  export class SignUpManager {
19
+ constructor(
20
+ private readonly emailValidator: EmailValidator,
21
+ ) {
22
+ }
23
+
19
24
  async signUp(dbContext: DatabaseContext, { email, password, roles = [] }: SignUpUser): Promise<SignUpResponse> {
20
- if (!validateEmail(email.trim())) {
21
- return new ResponseError('INVALID_EMAIL_FORMAT', 'E-mail address is not in a valid format')
22
- }
23
- if (await this.isEmailAlreadyUsed(dbContext, email)) {
24
- return new ResponseError('EMAIL_ALREADY_EXISTS', `User with email ${email} already exists`)
25
+ const validationError = await this.emailValidator.validateEmail(dbContext, email)
26
+ if (validationError !== null) {
27
+ return validationError
25
28
  }
26
29
  const plainPassword = password.getPlain()
27
30
  const weakPassword = plainPassword ? getPasswordWeaknessMessage(plainPassword) : null
@@ -34,11 +37,6 @@ export class SignUpManager {
34
37
  })
35
38
  return new ResponseOk(new SignUpResult(person))
36
39
  }
37
-
38
- private async isEmailAlreadyUsed(dbContext: DatabaseContext, email: string): Promise<boolean> {
39
- const personOrNull = await dbContext.queryHandler.fetch(PersonQuery.byEmail(email))
40
- return personOrNull !== null
41
- }
42
40
  }
43
41
 
44
42
  export class SignUpResult {
@@ -21,9 +21,10 @@ export class ApiKeyManager {
21
21
 
22
22
  async verifyAndProlong(
23
23
  dbContext: DatabaseContext,
24
+ readDbContext: DatabaseContext,
24
25
  token: string,
25
26
  ): Promise<VerifyResponse> {
26
- const apiKeyRow = await dbContext.queryHandler.fetch(new ApiKeyByTokenQuery(token))
27
+ const apiKeyRow = await readDbContext.queryHandler.fetch(new ApiKeyByTokenQuery(token))
27
28
  if (apiKeyRow === null) {
28
29
  return new ResponseError(VerifyErrorCode.NOT_FOUND, 'API key was not found')
29
30
  }
@@ -42,7 +43,12 @@ export class ApiKeyManager {
42
43
 
43
44
  setImmediate(async () => {
44
45
  await dbContext.commandBus.execute(
45
- new ProlongApiKeyCommand(apiKeyRow.id, apiKeyRow.type, apiKeyRow.expiration || undefined),
46
+ new ProlongApiKeyCommand(
47
+ apiKeyRow.id,
48
+ apiKeyRow.type,
49
+ apiKeyRow.expiration,
50
+ apiKeyRow.expires_at,
51
+ ),
46
52
  )
47
53
  })
48
54
 
@@ -8,6 +8,10 @@ export class IDPHandlerRegistry {
8
8
  this.providers[type] = provider
9
9
  }
10
10
 
11
+ public getHandlerOrNull(type: string): IdentityProviderHandler<{}> | null {
12
+ return this.providers[type] ?? null
13
+ }
14
+
11
15
  public getHandler(type: string): IdentityProviderHandler<{}> {
12
16
  const provider = this.providers[type]
13
17
  if (!provider) {