@contember/engine-tenant-api 1.3.5 → 1.4.0-alpha.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 (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
@@ -2,7 +2,7 @@ import { Response, ResponseError, ResponseOk } from '../../utils/Response'
2
2
  import { AddIdpErrorCode, DisableIdpErrorCode, EnableIdpErrorCode, UpdateIdpErrorCode } from '../../../schema'
3
3
  import { DatabaseContext } from '../../utils'
4
4
  import { IdentityProviderData } from '../../type'
5
- import { IdentityProviderBySlugQuery } from '../../queries'
5
+ import { IdentityProviderBySlugQuery, IdentityProvidersQuery } from '../../queries'
6
6
  import { CreateIdpCommand } from '../../commands/idp/CreateIdpCommand'
7
7
  import { IDPHandlerRegistry } from './IDPHandlerRegistry'
8
8
  import { IdentityProviderNotFoundError } from './IdentityProviderNotFoundError'
@@ -10,6 +10,7 @@ import { InvalidIDPConfigurationError } from './InvalidIDPConfigurationError'
10
10
  import { DisableIdpCommand } from '../../commands/idp/DisableIdpCommand'
11
11
  import { EnableIdpCommand } from '../../commands/idp/EnableIdpCommand'
12
12
  import { UpdateIdpCommand, UpdateIdpData } from '../../commands/idp/UpdateIdpCommand'
13
+ import { IdentityProviderDto } from '../../queries/idp/types'
13
14
 
14
15
  export class IDPManager {
15
16
  constructor(
@@ -68,18 +69,38 @@ export class IDPManager {
68
69
  })
69
70
  }
70
71
 
71
- public async updateIDP(db: DatabaseContext, slug: string, data: UpdateIdpData): Promise<UpdateIDPResponse> {
72
+ public async updateIDP(db: DatabaseContext, slug: string, data: UpdateIdpData, mergeConfiguration: boolean): Promise<UpdateIDPResponse> {
72
73
  return await db.transaction(async db => {
73
74
  const existing = await db.queryHandler.fetch(new IdentityProviderBySlugQuery(slug))
74
75
  if (!existing) {
75
76
  return new ResponseError('NOT_FOUND', `IDP ${slug} not found`)
76
77
  }
78
+
79
+ const newConfiguration = (() => {
80
+ if (!data.configuration) {
81
+ return existing.configuration
82
+ }
83
+ if (!mergeConfiguration) {
84
+ return data.configuration
85
+ }
86
+
87
+ const newConfiguration = { ...existing.configuration }
88
+ for (const [key, value] of Object.entries(data.configuration)) {
89
+ if (value === null) {
90
+ delete newConfiguration[key]
91
+ } else {
92
+ newConfiguration[key] = value
93
+ }
94
+ }
95
+
96
+ return newConfiguration
97
+ })()
98
+
77
99
  try {
78
100
  const type = data.type ?? existing.type
79
- const configuration = data.configuration ?? existing.configuration
80
101
  const providerService = this.idpRegistry.getHandler(type)
81
102
  if (data.configuration !== undefined || type !== existing.type) {
82
- providerService.validateConfiguration(configuration)
103
+ providerService.validateConfiguration(newConfiguration)
83
104
  }
84
105
  } catch (e) {
85
106
  if (e instanceof InvalidIDPConfigurationError) {
@@ -87,10 +108,27 @@ export class IDPManager {
87
108
  }
88
109
  throw e
89
110
  }
90
- await db.commandBus.execute(new UpdateIdpCommand(existing.id, data))
111
+
112
+ await db.commandBus.execute(new UpdateIdpCommand(existing.id, {
113
+ ...data,
114
+ configuration: data.configuration ? newConfiguration : undefined,
115
+ }))
116
+
91
117
  return new ResponseOk(null)
92
118
  })
93
119
  }
120
+
121
+ public async listIDP(db: DatabaseContext): Promise<IdentityProviderDto[]> {
122
+ const result = await db.queryHandler.fetch(new IdentityProvidersQuery())
123
+ return result.map(it => {
124
+ const providerService = this.idpRegistry.getHandlerOrNull(it.type)
125
+ const configuration = providerService?.getPublicConfiguration
126
+ ? providerService.getPublicConfiguration(it.configuration)
127
+ : it.configuration
128
+
129
+ return { ...it, configuration }
130
+ })
131
+ }
94
132
  }
95
133
 
96
134
  export type RegisterIDPResponse = Response<null, AddIdpErrorCode>
@@ -16,4 +16,6 @@ export interface IdentityProviderHandler<Configuration extends {}> {
16
16
  processResponse: (configuration: Configuration, responseData: unknown) => Promise<IDPClaim>
17
17
 
18
18
  validateConfiguration: (config: unknown) => Configuration
19
+
20
+ getPublicConfiguration?: (config: Configuration) => Partial<Configuration>
19
21
  }
@@ -1,6 +1,7 @@
1
1
  export * from './IdentityProviderHandler'
2
2
  export * from './IdentityProviderNotFoundError'
3
3
  export * from './IDPHandlerRegistry'
4
+ export * from './IDPManager'
4
5
  export * from './IDPResponseError'
5
6
  export * from './IDPValidationError'
6
7
  export * from './InvalidIDPConfigurationError'
@@ -1,6 +1,6 @@
1
1
  import * as Typesafe from '@contember/typesafe'
2
2
  import { IdentityProviderHandler, IDPClaim, InitIDPAuthResult } from '../IdentityProviderHandler'
3
- import { OIDCConfigurationOptions, OIDCInitData, OIDCResponseData, OIDCSessionData } from './OIDCTypes'
3
+ import { OIDCConfiguration, OIDCConfigurationOptions, OIDCInitData, OIDCResponseData, OIDCSessionData } from './OIDCTypes'
4
4
  import { catchTypesafe } from './helpers'
5
5
  import { IDPValidationError } from '../IDPValidationError'
6
6
  import { InvalidIDPConfigurationError } from '../InvalidIDPConfigurationError'
@@ -42,6 +42,9 @@ export class AppleProvider implements IdentityProviderHandler<AppleConfiguration
42
42
  return await handleOIDCResponse(client, responseData)
43
43
  }
44
44
 
45
+ getPublicConfiguration({ privateKey, ...config }: AppleConfiguration): Partial<AppleConfiguration> {
46
+ return config
47
+ }
45
48
 
46
49
  private async createOIDCClient(configuration: AppleConfiguration): Promise<Client> {
47
50
  this.issuer ??= await Issuer.discover(APPLE_OIDC_CONFIGURATION_ENDPOINT)
@@ -4,7 +4,7 @@ import { IdentityProviderHandler, IDPClaim, InitIDPAuthResult } from '../Identit
4
4
  import { IDPValidationError } from '../IDPValidationError'
5
5
  import { InvalidIDPConfigurationError } from '../InvalidIDPConfigurationError'
6
6
  import { catchTypesafe } from './helpers'
7
- import { BaseOIDCConfiguration, OIDCInitData, OIDCResponseData } from './OIDCTypes'
7
+ import { BaseOIDCConfiguration, OIDCConfiguration, OIDCInitData, OIDCResponseData } from './OIDCTypes'
8
8
  import { handleOIDCResponse, initOIDCAuth } from './OIDCHelpers'
9
9
  import { createHmac } from 'node:crypto'
10
10
  import { IDPResponseError } from '../IDPResponseError'
@@ -115,6 +115,10 @@ export class FacebookProvider implements IdentityProviderHandler<FacebookConfigu
115
115
  }
116
116
  }
117
117
 
118
+ getPublicConfiguration({ clientSecret, ...config }: FacebookConfiguration): Partial<FacebookConfiguration> {
119
+ return config
120
+ }
121
+
118
122
  private async createOIDCClient(configuration: FacebookConfiguration): Promise<Client> {
119
123
  return new this.facebookIssuer.Client(
120
124
  {
@@ -28,6 +28,10 @@ export class OIDCProvider implements IdentityProviderHandler<OIDCConfiguration>
28
28
  }
29
29
 
30
30
 
31
+ getPublicConfiguration({ clientSecret, ...config }: OIDCConfiguration): Partial<OIDCConfiguration> {
32
+ return config
33
+ }
34
+
31
35
  private async createOIDCClient(configuration: OIDCConfiguration): Promise<Client> {
32
36
  this.issuerCache[configuration.url] ??= await Issuer.discover(configuration.url)
33
37
 
@@ -1,17 +1,20 @@
1
- export * from './idp'
2
1
  export * from './apiKey'
2
+ export * from './idp'
3
+
4
+ export * from './EmailValidator'
3
5
  export * from './IDPSignInManager'
4
6
  export * from './InviteManager'
5
7
  export * from './MailTemplateManager'
6
8
  export * from './MembershipValidator'
9
+ export * from './OtpAuthenticator'
7
10
  export * from './OtpManager'
8
11
  export * from './PasswordChangeManager'
12
+ export * from './PasswordResetManager'
13
+ export * from './PersonAccessManager'
14
+ export * from './PersonManager'
9
15
  export * from './ProjectManager'
10
16
  export * from './ProjectMemberManager'
11
17
  export * from './RolesManager'
18
+ export * from './SecretsManager'
12
19
  export * from './SignInManager'
13
20
  export * from './SignUpManager'
14
- export * from './PasswordResetManager'
15
- export * from './SecretsManager'
16
- export * from './OtpAuthenticator'
17
- export * from './PersonAccessManager'
@@ -8,4 +8,5 @@ export interface IdentityProviderData {
8
8
  export interface IdentityProviderOptions {
9
9
  autoSignUp: boolean
10
10
  exclusive: boolean
11
+ initReturnsConfig: boolean
11
12
  }
@@ -3,6 +3,7 @@ import { Providers } from '../providers'
3
3
  import { CommandBus } from '../commands'
4
4
  import { BatchLoaderArgs, initBatchLoader, ItemLoader } from '../../utils/batchQuery'
5
5
 
6
+
6
7
  export class DatabaseContext<Conn extends Connection.ConnectionLike = Connection.ConnectionLike> {
7
8
  private loaders = new Map<BatchLoaderArgs<any, any, any>, ItemLoader<any, any>>()
8
9
 
@@ -43,15 +44,3 @@ export class DatabaseContext<Conn extends Connection.ConnectionLike = Connection
43
44
  return newLoader(arg)
44
45
  }
45
46
  }
46
-
47
- export class DatabaseContextFactory {
48
- constructor(
49
- private readonly connection: Connection.ClientFactory,
50
- private readonly providers: Providers,
51
- ) {
52
- }
53
-
54
- public create(): DatabaseContext {
55
- return new DatabaseContext(this.connection.createClient('tenant', { module: 'tenant' }), this.providers)
56
- }
57
- }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  AddProjectMemberMutationResolver,
3
+ ChangeProfileMutationResolver,
3
4
  ChangePasswordMutationResolver,
4
5
  CreateApiKeyMutationResolver,
5
6
  CreateProjectMutationResolver,
@@ -25,6 +26,7 @@ import { DateTimeType, JSONType } from '@contember/graphql-utils'
25
26
  import { IDPQueryResolver } from './query/IDPQueryResolver'
26
27
  import { UpdateIDPMutationResolver } from './mutation/idp/UpdateIDPMutationResolver'
27
28
  import { DisablePersonMutationResolver } from './mutation/person/DisablePersonMutationResolver'
29
+ import { } from './mutation/person/ChangeProfileMutationResolver'
28
30
 
29
31
  class ResolverFactory {
30
32
  public constructor(
@@ -37,6 +39,7 @@ class ResolverFactory {
37
39
  signUpMutationResolver: SignUpMutationResolver
38
40
  signInMutationResolver: SignInMutationResolver
39
41
  signOutMutationResolver: SignOutMutationResolver
42
+ changeProfileMutationResolver: ChangeProfileMutationResolver
40
43
  changePasswordMutationResolver: ChangePasswordMutationResolver
41
44
  resetPasswordMutationResolver: ResetPasswordMutationResolver
42
45
  idpMutationResolver: IDPMutationResolver
@@ -69,7 +72,7 @@ class ResolverFactory {
69
72
  identityGlobalRolesMutationResolver: IdentityGlobalRolesMutationResolver
70
73
 
71
74
  },
72
- ) {}
75
+ ) { }
73
76
 
74
77
  create(): Resolvers & { Mutation: Required<Resolvers['Mutation']> } & { Query: Required<Resolvers['Query']> } {
75
78
  return {
@@ -101,6 +104,7 @@ class ResolverFactory {
101
104
  createSessionToken: this.resolvers.signInMutationResolver.createSessionToken.bind(this.resolvers.signInMutationResolver),
102
105
  signOut: this.resolvers.signOutMutationResolver.signOut.bind(this.resolvers.signOutMutationResolver),
103
106
 
107
+ changeMyProfile: this.resolvers.changeProfileMutationResolver.changeMyProfile.bind(this.resolvers.changeProfileMutationResolver),
104
108
  changePassword: this.resolvers.changePasswordMutationResolver.changePassword.bind(this.resolvers.changePasswordMutationResolver),
105
109
  changeMyPassword: this.resolvers.changePasswordMutationResolver.changeMyPassword.bind(this.resolvers.changePasswordMutationResolver),
106
110
  createResetPasswordRequest: this.resolvers.resetPasswordMutationResolver.createResetPasswordRequest.bind(this.resolvers.resetPasswordMutationResolver),
@@ -20,6 +20,7 @@ export class AddIDPMutationResolver implements MutationResolvers {
20
20
  options: {
21
21
  autoSignUp: args.options?.autoSignUp ?? false,
22
22
  exclusive: args.options?.exclusive ?? false,
23
+ initReturnsConfig: args.options?.initReturnsConfig ?? false,
23
24
  },
24
25
  })
25
26
  if (!result.ok) {
@@ -19,8 +19,9 @@ export class UpdateIDPMutationResolver implements MutationResolvers {
19
19
  options: {
20
20
  autoSignUp: args.options?.autoSignUp ?? undefined,
21
21
  exclusive: args.options?.exclusive ?? undefined,
22
+ initReturnsConfig: args.options?.initReturnsConfig ?? undefined,
22
23
  },
23
- })
24
+ }, args.mergeConfiguration ?? false)
24
25
  if (!result.ok) {
25
26
  return createErrorResponse(result.error, result.errorMessage)
26
27
  }
@@ -0,0 +1,42 @@
1
+ import { ChangeMyProfileResponse, MutationChangeMyProfileArgs, MutationResolvers } from '../../../schema'
2
+ import { GraphQLResolveInfo } from 'graphql'
3
+ import { TenantResolverContext } from '../../TenantResolverContext'
4
+ import { PermissionActions, PersonManager, PersonQuery } from '../../../model'
5
+ import { createErrorResponse } from '../../errorUtils'
6
+
7
+ export class ChangeProfileMutationResolver implements MutationResolvers {
8
+ constructor(
9
+ private readonly personManager: PersonManager,
10
+ ) { }
11
+
12
+ async changeMyProfile(
13
+ parent: unknown,
14
+ args: MutationChangeMyProfileArgs,
15
+ context: TenantResolverContext,
16
+ info: GraphQLResolveInfo,
17
+ ): Promise<ChangeMyProfileResponse> {
18
+ const person = await context.db.queryHandler.fetch(PersonQuery.byIdentity(context.identity.id))
19
+ if (!person) {
20
+ return createErrorResponse('NOT_A_PERSON', 'Only a person can change a profile.')
21
+ }
22
+ if (args.email === null) {
23
+ return createErrorResponse('INVALID_EMAIL_FORMAT', 'E-mail address cannot be null.')
24
+ }
25
+
26
+ await context.requireAccess({
27
+ action: PermissionActions.PERSON_CHANGE_MY_PROFILE,
28
+ message: 'You are not allowed to change profile',
29
+ })
30
+
31
+ const result = await this.personManager.changeMyProfile(context.db, person, {
32
+ email: args.email,
33
+ name: args.name === '' ? null : args.name,
34
+ })
35
+
36
+ if (!result.ok) {
37
+ return createErrorResponse(result.error, result.errorMessage)
38
+ }
39
+
40
+ return { ok: true }
41
+ }
42
+ }
@@ -1,3 +1,4 @@
1
+ export * from './ChangeProfileMutationResolver'
1
2
  export * from './ChangePasswordMutationResolver'
2
3
  export * from './IDPMutationResolver'
3
4
  export * from './InviteMutationResolver'
@@ -1,14 +1,21 @@
1
1
  import { IdentityProvider, QueryResolvers } from '../../schema'
2
- import { IdentityProvidersQuery, PermissionActions } from '../../model'
2
+ import { PermissionActions } from '../../model'
3
3
  import { TenantResolverContext } from '../TenantResolverContext'
4
+ import { IDPManager } from '../../model/service/idp/IDPManager'
4
5
 
5
6
  export class IDPQueryResolver implements QueryResolvers {
7
+
8
+ constructor(
9
+ private readonly idpManager: IDPManager,
10
+ ) {
11
+ }
12
+
6
13
  async identityProviders(parent: unknown, args: unknown, context: TenantResolverContext): Promise<IdentityProvider[]> {
7
14
  await context.requireAccess({
8
15
  action: PermissionActions.IDP_LIST,
9
16
  message: 'You are not allowed to list IDP',
10
17
  })
11
18
 
12
- return await context.db.queryHandler.fetch(new IdentityProvidersQuery())
19
+ return await this.idpManager.listIDP(context.db)
13
20
  }
14
21
  }
@@ -131,6 +131,23 @@ export type ChangeMyPasswordResponse = {
131
131
  readonly ok: Scalars['Boolean']
132
132
  }
133
133
 
134
+ export type ChangeMyProfileError = {
135
+ readonly __typename?: 'ChangeMyProfileError'
136
+ readonly code: ChangeMyProfileErrorCode
137
+ readonly developerMessage: Scalars['String']
138
+ }
139
+
140
+ export type ChangeMyProfileErrorCode =
141
+ | 'EMAIL_ALREADY_EXISTS'
142
+ | 'INVALID_EMAIL_FORMAT'
143
+ | 'NOT_A_PERSON'
144
+
145
+ export type ChangeMyProfileResponse = {
146
+ readonly __typename?: 'ChangeMyProfileResponse'
147
+ readonly error?: Maybe<ChangeMyProfileError>
148
+ readonly ok: Scalars['Boolean']
149
+ }
150
+
134
151
  export type ChangePasswordError = {
135
152
  readonly __typename?: 'ChangePasswordError'
136
153
  readonly code: ChangePasswordErrorCode
@@ -379,6 +396,7 @@ export type EnableIdpResponse = {
379
396
  export type IdpOptions = {
380
397
  readonly autoSignUp?: InputMaybe<Scalars['Boolean']>
381
398
  readonly exclusive?: InputMaybe<Scalars['Boolean']>
399
+ readonly initReturnsConfig?: InputMaybe<Scalars['Boolean']>
382
400
  }
383
401
 
384
402
  export type IdpOptionsOutput = {
@@ -447,6 +465,7 @@ export type InitSignInIdpResponse = {
447
465
  export type InitSignInIdpResult = {
448
466
  readonly __typename?: 'InitSignInIDPResult'
449
467
  readonly authUrl: Scalars['String']
468
+ readonly idpConfiguration?: Maybe<Scalars['Json']>
450
469
  readonly sessionData: Scalars['Json']
451
470
  }
452
471
 
@@ -550,6 +569,7 @@ export type Mutation = {
550
569
  readonly addProjectMailTemplate?: Maybe<AddMailTemplateResponse>
551
570
  readonly addProjectMember?: Maybe<AddProjectMemberResponse>
552
571
  readonly changeMyPassword?: Maybe<ChangeMyPasswordResponse>
572
+ readonly changeMyProfile?: Maybe<ChangeMyProfileResponse>
553
573
  readonly changePassword?: Maybe<ChangePasswordResponse>
554
574
  readonly confirmOtp?: Maybe<ConfirmOtpResponse>
555
575
  readonly createApiKey?: Maybe<CreateApiKeyResponse>
@@ -620,6 +640,12 @@ export type MutationChangeMyPasswordArgs = {
620
640
  }
621
641
 
622
642
 
643
+ export type MutationChangeMyProfileArgs = {
644
+ email?: InputMaybe<Scalars['String']>
645
+ name?: InputMaybe<Scalars['String']>
646
+ }
647
+
648
+
623
649
  export type MutationChangePasswordArgs = {
624
650
  password: Scalars['String']
625
651
  personId: Scalars['String']
@@ -790,6 +816,7 @@ export type MutationUnmanagedInviteArgs = {
790
816
  export type MutationUpdateIdpArgs = {
791
817
  configuration?: InputMaybe<Scalars['Json']>
792
818
  identityProvider: Scalars['String']
819
+ mergeConfiguration?: InputMaybe<Scalars['Boolean']>
793
820
  options?: InputMaybe<IdpOptions>
794
821
  type?: InputMaybe<Scalars['String']>
795
822
  }
@@ -1289,6 +1316,9 @@ export type ResolversTypes = {
1289
1316
  ChangeMyPasswordError: ResolverTypeWrapper<ChangeMyPasswordError>
1290
1317
  ChangeMyPasswordErrorCode: ChangeMyPasswordErrorCode
1291
1318
  ChangeMyPasswordResponse: ResolverTypeWrapper<ChangeMyPasswordResponse>
1319
+ ChangeMyProfileError: ResolverTypeWrapper<ChangeMyProfileError>
1320
+ ChangeMyProfileErrorCode: ChangeMyProfileErrorCode
1321
+ ChangeMyProfileResponse: ResolverTypeWrapper<ChangeMyProfileResponse>
1292
1322
  ChangePasswordError: ResolverTypeWrapper<ChangePasswordError>
1293
1323
  ChangePasswordErrorCode: ChangePasswordErrorCode
1294
1324
  ChangePasswordResponse: ResolverTypeWrapper<ChangePasswordResponse>
@@ -1435,6 +1465,8 @@ export type ResolversParentTypes = {
1435
1465
  Boolean: Scalars['Boolean']
1436
1466
  ChangeMyPasswordError: ChangeMyPasswordError
1437
1467
  ChangeMyPasswordResponse: ChangeMyPasswordResponse
1468
+ ChangeMyProfileError: ChangeMyProfileError
1469
+ ChangeMyProfileResponse: ChangeMyProfileResponse
1438
1470
  ChangePasswordError: ChangePasswordError
1439
1471
  ChangePasswordResponse: ChangePasswordResponse
1440
1472
  CheckResetPasswordTokenResult: CheckResetPasswordTokenResult
@@ -1619,6 +1651,18 @@ export type ChangeMyPasswordResponseResolvers<ContextType = any, ParentType exte
1619
1651
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>
1620
1652
  }
1621
1653
 
1654
+ export type ChangeMyProfileErrorResolvers<ContextType = any, ParentType extends ResolversParentTypes['ChangeMyProfileError'] = ResolversParentTypes['ChangeMyProfileError']> = {
1655
+ code?: Resolver<ResolversTypes['ChangeMyProfileErrorCode'], ParentType, ContextType>
1656
+ developerMessage?: Resolver<ResolversTypes['String'], ParentType, ContextType>
1657
+ __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>
1658
+ }
1659
+
1660
+ export type ChangeMyProfileResponseResolvers<ContextType = any, ParentType extends ResolversParentTypes['ChangeMyProfileResponse'] = ResolversParentTypes['ChangeMyProfileResponse']> = {
1661
+ error?: Resolver<Maybe<ResolversTypes['ChangeMyProfileError']>, ParentType, ContextType>
1662
+ ok?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>
1663
+ __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>
1664
+ }
1665
+
1622
1666
  export type ChangePasswordErrorResolvers<ContextType = any, ParentType extends ResolversParentTypes['ChangePasswordError'] = ResolversParentTypes['ChangePasswordError']> = {
1623
1667
  code?: Resolver<ResolversTypes['ChangePasswordErrorCode'], ParentType, ContextType>
1624
1668
  developerMessage?: Resolver<ResolversTypes['String'], ParentType, ContextType>
@@ -1853,6 +1897,7 @@ export type InitSignInIdpResponseResolvers<ContextType = any, ParentType extends
1853
1897
 
1854
1898
  export type InitSignInIdpResultResolvers<ContextType = any, ParentType extends ResolversParentTypes['InitSignInIDPResult'] = ResolversParentTypes['InitSignInIDPResult']> = {
1855
1899
  authUrl?: Resolver<ResolversTypes['String'], ParentType, ContextType>
1900
+ idpConfiguration?: Resolver<Maybe<ResolversTypes['Json']>, ParentType, ContextType>
1856
1901
  sessionData?: Resolver<ResolversTypes['Json'], ParentType, ContextType>
1857
1902
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>
1858
1903
  }
@@ -1903,6 +1948,7 @@ export type MutationResolvers<ContextType = any, ParentType extends ResolversPar
1903
1948
  addProjectMailTemplate?: Resolver<Maybe<ResolversTypes['AddMailTemplateResponse']>, ParentType, ContextType, RequireFields<MutationAddProjectMailTemplateArgs, 'template'>>
1904
1949
  addProjectMember?: Resolver<Maybe<ResolversTypes['AddProjectMemberResponse']>, ParentType, ContextType, RequireFields<MutationAddProjectMemberArgs, 'identityId' | 'memberships' | 'projectSlug'>>
1905
1950
  changeMyPassword?: Resolver<Maybe<ResolversTypes['ChangeMyPasswordResponse']>, ParentType, ContextType, RequireFields<MutationChangeMyPasswordArgs, 'currentPassword' | 'newPassword'>>
1951
+ changeMyProfile?: Resolver<Maybe<ResolversTypes['ChangeMyProfileResponse']>, ParentType, ContextType, Partial<MutationChangeMyProfileArgs>>
1906
1952
  changePassword?: Resolver<Maybe<ResolversTypes['ChangePasswordResponse']>, ParentType, ContextType, RequireFields<MutationChangePasswordArgs, 'password' | 'personId'>>
1907
1953
  confirmOtp?: Resolver<Maybe<ResolversTypes['ConfirmOtpResponse']>, ParentType, ContextType, RequireFields<MutationConfirmOtpArgs, 'otpToken'>>
1908
1954
  createApiKey?: Resolver<Maybe<ResolversTypes['CreateApiKeyResponse']>, ParentType, ContextType, RequireFields<MutationCreateApiKeyArgs, 'description' | 'memberships' | 'projectSlug'>>
@@ -2215,6 +2261,8 @@ export type Resolvers<ContextType = any> = {
2215
2261
  ApiKeyWithToken?: ApiKeyWithTokenResolvers<ContextType>
2216
2262
  ChangeMyPasswordError?: ChangeMyPasswordErrorResolvers<ContextType>
2217
2263
  ChangeMyPasswordResponse?: ChangeMyPasswordResponseResolvers<ContextType>
2264
+ ChangeMyProfileError?: ChangeMyProfileErrorResolvers<ContextType>
2265
+ ChangeMyProfileResponse?: ChangeMyProfileResponseResolvers<ContextType>
2218
2266
  ChangePasswordError?: ChangePasswordErrorResolvers<ContextType>
2219
2267
  ChangePasswordResponse?: ChangePasswordResponseResolvers<ContextType>
2220
2268
  CheckResetPasswordTokenResult?: CheckResetPasswordTokenResultResolvers<ContextType>
@@ -25,6 +25,7 @@ const schema: DocumentNode = gql`
25
25
  signIn(email: String!, password: String!, expiration: Int, otpToken: String): SignInResponse
26
26
  createSessionToken(email: String, personId: String, expiration: Int): CreateSessionTokenResponse
27
27
  signOut(all: Boolean): SignOutResponse
28
+ changeMyProfile(email: String, name: String): ChangeMyProfileResponse
28
29
  changePassword(personId: String!, password: String!): ChangePasswordResponse
29
30
  changeMyPassword(currentPassword: String!, newPassword: String!): ChangeMyPasswordResponse
30
31
 
@@ -44,7 +45,7 @@ const schema: DocumentNode = gql`
44
45
 
45
46
  # IDP management
46
47
  addIDP(identityProvider: String!, type: String!, configuration: Json!, options: IDPOptions): AddIDPResponse
47
- updateIDP(identityProvider: String!, type: String, configuration: Json, options: IDPOptions): UpdateIDPResponse
48
+ updateIDP(identityProvider: String!, type: String, configuration: Json, options: IDPOptions, mergeConfiguration: Boolean): UpdateIDPResponse
48
49
  disableIDP(identityProvider: String!): DisableIDPResponse
49
50
  enableIDP(identityProvider: String!): EnableIDPResponse
50
51
 
@@ -202,6 +203,24 @@ const schema: DocumentNode = gql`
202
203
  NOT_POSSIBLE_SIGN_OUT_WITH_PERMANENT_API_KEY
203
204
  }
204
205
 
206
+ # === changeProfile ===
207
+
208
+ type ChangeMyProfileResponse {
209
+ ok: Boolean!
210
+ error: ChangeMyProfileError
211
+ }
212
+
213
+ type ChangeMyProfileError {
214
+ code: ChangeMyProfileErrorCode!
215
+ developerMessage: String!
216
+ }
217
+
218
+ enum ChangeMyProfileErrorCode {
219
+ NOT_A_PERSON
220
+ INVALID_EMAIL_FORMAT
221
+ EMAIL_ALREADY_EXISTS
222
+ }
223
+
205
224
  # === changePassword ===
206
225
 
207
226
  type ChangePasswordResponse {
@@ -251,6 +270,7 @@ const schema: DocumentNode = gql`
251
270
  type InitSignInIDPResult {
252
271
  authUrl: String!
253
272
  sessionData: Json!
273
+ idpConfiguration: Json
254
274
  }
255
275
 
256
276
  type InitSignInIDPError {
@@ -366,11 +386,13 @@ const schema: DocumentNode = gql`
366
386
  type IDPOptionsOutput {
367
387
  autoSignUp: Boolean!
368
388
  exclusive: Boolean!
389
+ initReturnsConfig: Boolean!
369
390
  }
370
391
 
371
392
  input IDPOptions {
372
393
  autoSignUp: Boolean
373
394
  exclusive: Boolean
395
+ initReturnsConfig: Boolean
374
396
  }
375
397
 
376
398