@verii/server-credentialing-hub 2.0.0

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 (237) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +13 -0
  3. package/package.json +87 -0
  4. package/src/assets/templates/app-redirect.hbs +22 -0
  5. package/src/config/config.js +118 -0
  6. package/src/config/index.js +19 -0
  7. package/src/controllers/app-redirect/controller.js +85 -0
  8. package/src/controllers/openid4vc/autohooks.js +22 -0
  9. package/src/controllers/openid4vc/oauth-controller.js +96 -0
  10. package/src/controllers/openid4vc/openid4vc-metadata-controller.js +66 -0
  11. package/src/controllers/openid4vc/openid4vci-controller.js +125 -0
  12. package/src/controllers/openid4vp/autohooks.js +22 -0
  13. package/src/controllers/openid4vp/openid4vp-controller.js +177 -0
  14. package/src/controllers/operator/autohooks.js +31 -0
  15. package/src/controllers/operator/credentials/credentials-controller.js +212 -0
  16. package/src/controllers/operator/credentials/schemas/credential.schema.js +46 -0
  17. package/src/controllers/operator/credentials/schemas/index.js +7 -0
  18. package/src/controllers/operator/credentials/schemas/new-credential.schema.json +23 -0
  19. package/src/controllers/operator/depots/depots-controller.js +154 -0
  20. package/src/controllers/operator/depots/schemas/depot.schema.js +34 -0
  21. package/src/controllers/operator/depots/schemas/index.js +24 -0
  22. package/src/controllers/operator/depots/schemas/new-depot.schema.json +30 -0
  23. package/src/controllers/operator/issue-links/issue-links-controller.js +74 -0
  24. package/src/controllers/operator/issuer-services/issuer-services-controller.js +200 -0
  25. package/src/controllers/operator/issuer-services/schemas/index.js +7 -0
  26. package/src/controllers/operator/issuer-services/schemas/issuer-service.schema.js +26 -0
  27. package/src/controllers/operator/issuer-services/schemas/new-issuer-service.schema.js +137 -0
  28. package/src/controllers/operator/presentation-links/presentation-links-controller.js +76 -0
  29. package/src/controllers/operator/presentations/presentations-controller.js +174 -0
  30. package/src/controllers/operator/presentations/schemas/base-presentation.schema.js +39 -0
  31. package/src/controllers/operator/presentations/schemas/credential-verification.schema.js +83 -0
  32. package/src/controllers/operator/presentations/schemas/index.js +23 -0
  33. package/src/controllers/operator/presentations/schemas/presentation-verification.schema.js +42 -0
  34. package/src/controllers/operator/presentations/schemas/presentation.schema.js +53 -0
  35. package/src/controllers/operator/presentations/schemas/w3c-presentation.js +52 -0
  36. package/src/controllers/operator/relying-party-services/relying-party-services-controller.js +202 -0
  37. package/src/controllers/operator/relying-party-services/schemas/index.js +7 -0
  38. package/src/controllers/operator/relying-party-services/schemas/new-relying-party-service.schema.js +91 -0
  39. package/src/controllers/operator/relying-party-services/schemas/relying-party-service.schema.js +26 -0
  40. package/src/controllers/operator/tenants/schemas/index.js +33 -0
  41. package/src/controllers/operator/tenants/schemas/jwk.schema.json +56 -0
  42. package/src/controllers/operator/tenants/schemas/key-metadata.schema.json +12 -0
  43. package/src/controllers/operator/tenants/schemas/new-key-metadata.schema.json +42 -0
  44. package/src/controllers/operator/tenants/schemas/new-key.schema.json +12 -0
  45. package/src/controllers/operator/tenants/schemas/new-tenant.schema.json +33 -0
  46. package/src/controllers/operator/tenants/schemas/secret-key.schema.json +33 -0
  47. package/src/controllers/operator/tenants/schemas/tenant.schema.json +44 -0
  48. package/src/controllers/operator/tenants/tenants-controller.js +165 -0
  49. package/src/controllers/root-controller.js +43 -0
  50. package/src/controllers/vn-api/schemas/index.js +25 -0
  51. package/src/controllers/vn-api/schemas/presentation-submission.schema.json +41 -0
  52. package/src/controllers/vn-api/schemas/velocity-presentation-submission.response.200.schema.json +36 -0
  53. package/src/controllers/vn-api/schemas/velocity-presentation-submission.schema.json +31 -0
  54. package/src/controllers/vn-api/vn-api-presentation-controller.js +158 -0
  55. package/src/controllers/vn-api/vn-issuing-controller.js +295 -0
  56. package/src/entities/credential-types/fetchers/fetch-credential-type-descriptors.js +36 -0
  57. package/src/entities/credential-types/fetchers/index.js +19 -0
  58. package/src/entities/credential-types/index.js +19 -0
  59. package/src/entities/credentials/domain/canonicalize-credentials.js +70 -0
  60. package/src/entities/credentials/domain/credential-errors.js +25 -0
  61. package/src/entities/credentials/domain/credential-format.js +21 -0
  62. package/src/entities/credentials/domain/index.js +22 -0
  63. package/src/entities/credentials/domain/validate-credential.js +74 -0
  64. package/src/entities/credentials/facades/anchor-verii-credentials-facade.js +45 -0
  65. package/src/entities/credentials/facades/build-verii-issuer.js +44 -0
  66. package/src/entities/credentials/facades/index.js +22 -0
  67. package/src/entities/credentials/facades/issue-verii-credentials-facade.js +62 -0
  68. package/src/entities/credentials/facades/sign-verii-credentials-facade.js +56 -0
  69. package/src/entities/credentials/factories/credential-factory.js +53 -0
  70. package/src/entities/credentials/factories/index.js +19 -0
  71. package/src/entities/credentials/index.js +23 -0
  72. package/src/entities/credentials/orchestrators/create-credentials.js +118 -0
  73. package/src/entities/credentials/orchestrators/index.js +19 -0
  74. package/src/entities/credentials/repo/finders-extension.js +94 -0
  75. package/src/entities/credentials/repo/index.js +19 -0
  76. package/src/entities/credentials/repo/repo.js +62 -0
  77. package/src/entities/credentials/repo/update-issued-credential.js +60 -0
  78. package/src/entities/depots/domain/depot-errors.js +23 -0
  79. package/src/entities/depots/domain/index.js +20 -0
  80. package/src/entities/depots/domain/validate-depot.js +38 -0
  81. package/src/entities/depots/factories/depot-factory.js +50 -0
  82. package/src/entities/depots/factories/index.js +19 -0
  83. package/src/entities/depots/index.js +22 -0
  84. package/src/entities/depots/orchestrators/create-depot.js +31 -0
  85. package/src/entities/depots/orchestrators/delete-depot.js +43 -0
  86. package/src/entities/depots/orchestrators/index.js +20 -0
  87. package/src/entities/depots/repo/find-depot-by-preauth-code.js +30 -0
  88. package/src/entities/depots/repo/find-depots-extension.js +34 -0
  89. package/src/entities/depots/repo/index.js +19 -0
  90. package/src/entities/depots/repo/refresh-preauth-code.js +30 -0
  91. package/src/entities/depots/repo/repo.js +61 -0
  92. package/src/entities/exchanges/adapters/index.js +17 -0
  93. package/src/entities/exchanges/adapters/sign-exchange-response.js +37 -0
  94. package/src/entities/exchanges/domain/authorize-exchange.js +29 -0
  95. package/src/entities/exchanges/domain/build-exchange-event.js +19 -0
  96. package/src/entities/exchanges/domain/build-presentation-request.js +174 -0
  97. package/src/entities/exchanges/domain/exchange-errors.js +28 -0
  98. package/src/entities/exchanges/domain/exchange-protocols.js +29 -0
  99. package/src/entities/exchanges/domain/exchange-states.js +53 -0
  100. package/src/entities/exchanges/domain/exchange-types.js +22 -0
  101. package/src/entities/exchanges/domain/generate-issuing-challenge.js +48 -0
  102. package/src/entities/exchanges/domain/index.js +32 -0
  103. package/src/entities/exchanges/domain/validate-message-settings.js +33 -0
  104. package/src/entities/exchanges/domain/validate-new-exchange.js +25 -0
  105. package/src/entities/exchanges/domain/validate-preauth.js +45 -0
  106. package/src/entities/exchanges/domain/validate-referenced-service.js +33 -0
  107. package/src/entities/exchanges/domain/verify-issuing-challenge.js +42 -0
  108. package/src/entities/exchanges/domain/verify-proof-of-key-possession.js +128 -0
  109. package/src/entities/exchanges/factories/index.js +19 -0
  110. package/src/entities/exchanges/factories/init-exchange-factory.js +58 -0
  111. package/src/entities/exchanges/hooks/exchange-error-hook.js +30 -0
  112. package/src/entities/exchanges/hooks/index.js +17 -0
  113. package/src/entities/exchanges/index.js +24 -0
  114. package/src/entities/exchanges/orchestrators/authenticate.js +67 -0
  115. package/src/entities/exchanges/orchestrators/credential-offer-request.js +70 -0
  116. package/src/entities/exchanges/orchestrators/get-credential-manifest.js +84 -0
  117. package/src/entities/exchanges/orchestrators/get-presentation-request.js +114 -0
  118. package/src/entities/exchanges/orchestrators/index.js +24 -0
  119. package/src/entities/exchanges/orchestrators/issue-credentials.js +132 -0
  120. package/src/entities/exchanges/orchestrators/post-presentation.js +58 -0
  121. package/src/entities/exchanges/repo/exchange-state-repo-extension.js +78 -0
  122. package/src/entities/exchanges/repo/index.js +19 -0
  123. package/src/entities/exchanges/repo/repo.js +52 -0
  124. package/src/entities/issuer-services/domain/index.js +20 -0
  125. package/src/entities/issuer-services/domain/issuer-services-errors.js +23 -0
  126. package/src/entities/issuer-services/domain/validate-issuer-service.js +23 -0
  127. package/src/entities/issuer-services/factories/index.js +19 -0
  128. package/src/entities/issuer-services/factories/issuer-service-factory.js +44 -0
  129. package/src/entities/issuer-services/index.js +21 -0
  130. package/src/entities/issuer-services/repo/find-issuer-services-extension.js +30 -0
  131. package/src/entities/issuer-services/repo/index.js +19 -0
  132. package/src/entities/issuer-services/repo/repo.js +59 -0
  133. package/src/entities/keys/adapters/index.js +19 -0
  134. package/src/entities/keys/adapters/load-primary-account.js +39 -0
  135. package/src/entities/keys/domain/cih-key-purposes.js +23 -0
  136. package/src/entities/keys/domain/get-key-with-purpose.js +22 -0
  137. package/src/entities/keys/domain/index.js +22 -0
  138. package/src/entities/keys/domain/key-errors.js +25 -0
  139. package/src/entities/keys/domain/normalize-tenant-key.js +33 -0
  140. package/src/entities/keys/domain/validate-tenant-keys.js +78 -0
  141. package/src/entities/keys/factories/index.js +19 -0
  142. package/src/entities/keys/factories/key-factory.js +61 -0
  143. package/src/entities/keys/index.js +22 -0
  144. package/src/entities/keys/plugins/index.js +17 -0
  145. package/src/entities/keys/plugins/kms-plugin.js +61 -0
  146. package/src/entities/links/domain/build-deep-link-url.js +58 -0
  147. package/src/entities/links/domain/build-openid4vci-credential-offer-link.js +31 -0
  148. package/src/entities/links/domain/build-openid4vp-authorization-request-link.js +36 -0
  149. package/src/entities/links/domain/build-redirect-url.js +29 -0
  150. package/src/entities/links/domain/build-vn-api-issuing-link.js +54 -0
  151. package/src/entities/links/domain/build-vn-api-presentation-link.js +49 -0
  152. package/src/entities/links/domain/index.js +28 -0
  153. package/src/entities/links/domain/is-preauth-code-auth.js +19 -0
  154. package/src/entities/links/domain/link-errors.js +23 -0
  155. package/src/entities/links/domain/validate-issue-link.js +39 -0
  156. package/src/entities/links/domain/validate-presentation-link.js +39 -0
  157. package/src/entities/links/index.js +20 -0
  158. package/src/entities/links/orchestrators/index.js +17 -0
  159. package/src/entities/links/orchestrators/refresh-links.js +139 -0
  160. package/src/entities/openid4vci/domain/index.js +20 -0
  161. package/src/entities/openid4vci/domain/openid4vci-errors.js +24 -0
  162. package/src/entities/openid4vci/domain/to-credential-configuration-id.js +21 -0
  163. package/src/entities/openid4vci/index.js +21 -0
  164. package/src/entities/openid4vci/orchestrators/create-access-token.js +85 -0
  165. package/src/entities/openid4vci/orchestrators/create-credential.js +108 -0
  166. package/src/entities/openid4vci/orchestrators/get-authorization-server-metadata.js +22 -0
  167. package/src/entities/openid4vci/orchestrators/get-credential-issuer-metadata.js +22 -0
  168. package/src/entities/openid4vci/orchestrators/handle-notification.js +94 -0
  169. package/src/entities/openid4vci/orchestrators/index.js +24 -0
  170. package/src/entities/openid4vci/plugins/index.js +19 -0
  171. package/src/entities/openid4vci/plugins/openid4vci-plugin.js +427 -0
  172. package/src/entities/openid4vp/domain/index.js +21 -0
  173. package/src/entities/openid4vp/domain/openid4vp-request-id.js +47 -0
  174. package/src/entities/openid4vp/domain/presentation-request-expiry.js +37 -0
  175. package/src/entities/openid4vp/domain/wallet-metadata.js +30 -0
  176. package/src/entities/openid4vp/index.js +21 -0
  177. package/src/entities/openid4vp/orchestrators/create-authorization-request.js +183 -0
  178. package/src/entities/openid4vp/orchestrators/index.js +20 -0
  179. package/src/entities/openid4vp/orchestrators/post-authorization-response.js +353 -0
  180. package/src/entities/openid4vp/plugins/index.js +19 -0
  181. package/src/entities/openid4vp/plugins/openid4vp-plugin.js +174 -0
  182. package/src/entities/presentations/domain/index.js +20 -0
  183. package/src/entities/presentations/domain/presentation-format.js +20 -0
  184. package/src/entities/presentations/domain/validate-presentation.js +178 -0
  185. package/src/entities/presentations/factories/index.js +19 -0
  186. package/src/entities/presentations/factories/presentation-factory.js +96 -0
  187. package/src/entities/presentations/index.js +21 -0
  188. package/src/entities/presentations/orchestrators/index.js +19 -0
  189. package/src/entities/presentations/orchestrators/verify-presentation.js +131 -0
  190. package/src/entities/presentations/repo/add-verification.js +31 -0
  191. package/src/entities/presentations/repo/finders-extension.js +50 -0
  192. package/src/entities/presentations/repo/index.js +19 -0
  193. package/src/entities/presentations/repo/repo.js +58 -0
  194. package/src/entities/relying-party-services/factories/index.js +19 -0
  195. package/src/entities/relying-party-services/factories/relying-party-service-factory.js +43 -0
  196. package/src/entities/relying-party-services/index.js +20 -0
  197. package/src/entities/relying-party-services/repo/find-relying-party-services-extension.js +30 -0
  198. package/src/entities/relying-party-services/repo/index.js +19 -0
  199. package/src/entities/relying-party-services/repo/repo.js +55 -0
  200. package/src/entities/service-configurations/domain/canonicalize-service-configuration.js +12 -0
  201. package/src/entities/service-configurations/domain/index.js +22 -0
  202. package/src/entities/service-configurations/domain/service-configuration-errors.js +24 -0
  203. package/src/entities/service-configurations/domain/validate-service-configuration.js +31 -0
  204. package/src/entities/service-configurations/domain/validate-update-service-configuration.js +19 -0
  205. package/src/entities/service-configurations/index.js +20 -0
  206. package/src/entities/service-configurations/orchestrators/create-service-configuration.js +34 -0
  207. package/src/entities/service-configurations/orchestrators/delete-service-configuration.js +41 -0
  208. package/src/entities/service-configurations/orchestrators/index.js +21 -0
  209. package/src/entities/service-configurations/orchestrators/update-service-configuration.js +40 -0
  210. package/src/entities/tenants/adapters/index.js +20 -0
  211. package/src/entities/tenants/adapters/load-tenant-did-doc.js +47 -0
  212. package/src/entities/tenants/adapters/load-tenant-profile.js +40 -0
  213. package/src/entities/tenants/domain/index.js +20 -0
  214. package/src/entities/tenants/domain/tenant-errors.js +29 -0
  215. package/src/entities/tenants/domain/validate-new-tenant.js +49 -0
  216. package/src/entities/tenants/factories/index.js +19 -0
  217. package/src/entities/tenants/factories/tenant-factory.js +41 -0
  218. package/src/entities/tenants/index.js +24 -0
  219. package/src/entities/tenants/orchestrators/create-tenant.js +116 -0
  220. package/src/entities/tenants/orchestrators/delete-tenant.js +45 -0
  221. package/src/entities/tenants/orchestrators/find-tenants.js +22 -0
  222. package/src/entities/tenants/orchestrators/index.js +21 -0
  223. package/src/entities/tenants/plugins/index.js +3 -0
  224. package/src/entities/tenants/plugins/tenant-loader-plugin.js +64 -0
  225. package/src/entities/tenants/repo/index.js +19 -0
  226. package/src/entities/tenants/repo/insert-tenant-extension.js +36 -0
  227. package/src/entities/tenants/repo/repo.js +51 -0
  228. package/src/entities/tokens/domains/access-token.js +74 -0
  229. package/src/entities/tokens/domains/index.js +19 -0
  230. package/src/entities/tokens/index.js +19 -0
  231. package/src/index.js +3 -0
  232. package/src/init-server.js +88 -0
  233. package/src/main.js +25 -0
  234. package/src/schemas/index.js +20 -0
  235. package/src/schemas/oauth-error-response.schema.js +27 -0
  236. package/src/standalone.js +8 -0
  237. package/src/start-app-server.js +27 -0
@@ -0,0 +1,47 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { resolveDid } = require('@verii/common-fetchers');
19
+ const newError = require('http-errors');
20
+ const { isEmpty } = require('lodash/fp');
21
+ const { TenantErrors } = require('../domain/tenant-errors');
22
+
23
+ const loadTenantDidDoc = async (did, context) => {
24
+ const didDoc = await resolveDidWithErrorHandling(
25
+ did,
26
+ TenantErrors.DID_DOCUMENT_NOT_FOUND,
27
+ context,
28
+ );
29
+ if (isEmpty(didDoc)) {
30
+ context.log.error('Tenant DID Document is null or {}');
31
+ throw newError(400, TenantErrors.DID_DOCUMENT_NOT_FOUND, {
32
+ errorCode: TenantErrors.DID_DOCUMENT_NOT_FOUND,
33
+ });
34
+ }
35
+ return didDoc;
36
+ };
37
+
38
+ const resolveDidWithErrorHandling = async (did, errorCode, context) => {
39
+ try {
40
+ return await resolveDid(did, context);
41
+ } catch (error) {
42
+ context.log.error(error, 'Error retrieving DID Document');
43
+ throw newError(400, errorCode, { errorCode });
44
+ }
45
+ };
46
+
47
+ module.exports = { loadTenantDidDoc };
@@ -0,0 +1,40 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { getOrganizationVerifiedProfile } = require('@verii/common-fetchers');
19
+ const newError = require('http-errors');
20
+ const { TenantErrors } = require('../domain/tenant-errors');
21
+
22
+ const loadTenantProfile = async (did, context) => {
23
+ const orgProfile = await resolveOrgVcWithErrorHandling(
24
+ did,
25
+ TenantErrors.ORG_PROFILE_NOT_FOUND,
26
+ context,
27
+ );
28
+ return orgProfile.credentialSubject;
29
+ };
30
+
31
+ const resolveOrgVcWithErrorHandling = async (did, errorCode, context) => {
32
+ try {
33
+ return await getOrganizationVerifiedProfile(did, context);
34
+ } catch (error) {
35
+ context.log.error(error, 'Error retrieving organization profile');
36
+ throw newError(400, errorCode, { errorCode });
37
+ }
38
+ };
39
+
40
+ module.exports = { loadTenantProfile };
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ module.exports = {
18
+ ...require('./tenant-errors'),
19
+ ...require('./validate-new-tenant'),
20
+ };
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const TenantErrors = {
19
+ DID_DOCUMENT_NOT_FOUND: 'did_document_not_found',
20
+ ORG_PROFILE_NOT_FOUND: 'org_profile_not_found',
21
+ KEY_PURPOSES_MUST_BE_UNIQUE: 'key_purposes_must_be_unique',
22
+ KEY_KID_FRAGMENT_NOT_FOUND: 'key_kidFragment_not_found',
23
+ TENANTS_MUST_BE_UNIQUE: 'tenant_must_be_unique',
24
+ CAO_DID_REQUIRED: 'cao_did_required',
25
+ RELATED_SERVICE_UNDELETED: 'related_service_undeleted',
26
+ NAME_MUST_MATCH_PROFILE: 'name_must_match_profile',
27
+ LOGO_MUST_MATCH_PROFILE: 'logo_must_match_profile',
28
+ };
29
+ module.exports = { TenantErrors };
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ const newError = require('http-errors');
18
+ const { find } = require('lodash/fp');
19
+ const { TenantErrors } = require('./tenant-errors');
20
+
21
+ const validateNewTenant = (newTenant, orgProfile, context) => {
22
+ if (newTenant.caoDid == null && context.config.defaultCaoDid == null) {
23
+ throw newError(400, TenantErrors.CAO_DID_REQUIRED, {
24
+ errorCode: TenantErrors.CAO_DID_REQUIRED,
25
+ });
26
+ }
27
+ validateNameAndLogo(newTenant, orgProfile);
28
+ };
29
+
30
+ const validateNameAndLogo = (newTenant, orgProfile) => {
31
+ if (
32
+ newTenant.name !== orgProfile.name &&
33
+ !find({ name: newTenant.name }, orgProfile.commercialEntities)
34
+ ) {
35
+ throw newError(400, TenantErrors.NAME_MUST_MATCH_PROFILE, {
36
+ errorCode: TenantErrors.NAME_MUST_MATCH_PROFILE,
37
+ });
38
+ }
39
+ if (
40
+ newTenant.logo !== orgProfile.logo &&
41
+ !find({ logo: newTenant.logo }, orgProfile.commercialEntities)
42
+ ) {
43
+ throw newError(400, TenantErrors.LOGO_MUST_MATCH_PROFILE, {
44
+ errorCode: TenantErrors.LOGO_MUST_MATCH_PROFILE,
45
+ });
46
+ }
47
+ };
48
+
49
+ module.exports = { validateNewTenant };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright 2023 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ module.exports = {
18
+ ...require('./tenant-factory'),
19
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Copyright 2023 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ const { register } = require('@spencejs/spence-factories');
18
+ const { tenantRepoPlugin } = require('../repo');
19
+
20
+ const initTenantFactory = (app) =>
21
+ register(
22
+ 'tenant',
23
+ tenantRepoPlugin(app)({ config: app.config }),
24
+ (overrides) => {
25
+ const didSuffix = Array(40)
26
+ .fill(0)
27
+ .map(() => Math.random().toString(36).charAt(2))
28
+ .join('');
29
+ return {
30
+ did: `did:test:${didSuffix}`,
31
+ primaryAccount: `0x${didSuffix}`,
32
+ caoDid: 'did:test:e89fYWr0Lkfd_pa18fdk',
33
+ hostUrl: 'https://localhost.test',
34
+ name: 'fooName',
35
+ logo: 'https://localhost.test/logo.png',
36
+ ...overrides(),
37
+ };
38
+ },
39
+ );
40
+
41
+ module.exports = { initTenantFactory };
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ module.exports = {
18
+ ...require('./adapters'),
19
+ ...require('./domain'),
20
+ ...require('./factories'),
21
+ ...require('./orchestrators'),
22
+ ...require('./plugins'),
23
+ ...require('./repo'),
24
+ };
@@ -0,0 +1,116 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { KeyPurposes, KeyEncodings } = require('@verii/crypto');
19
+ const { flatMap, flow, fromPairs, map, pick } = require('lodash/fp');
20
+ const { ObjectId } = require('mongodb');
21
+ const { nanoid } = require('nanoid');
22
+ const {
23
+ loadPrimaryAccount,
24
+ normalizeTenantKey,
25
+ validateTenantKeys,
26
+ getKeyWithPurpose,
27
+ CihKeyPurposes,
28
+ } = require('../../keys');
29
+ const { loadTenantDidDoc, loadTenantProfile } = require('../adapters');
30
+ const { validateNewTenant } = require('../domain');
31
+
32
+ const createTenant = async (newTenant, tenantKeys, context) => {
33
+ const { repos, kms } = context;
34
+
35
+ const [didDoc, orgProfile] = await Promise.all([
36
+ loadTenantDidDoc(newTenant.did, context),
37
+ loadTenantProfile(newTenant.did, context),
38
+ ]);
39
+
40
+ validateNewTenant(newTenant, orgProfile, context);
41
+
42
+ validateTenantKeys(tenantKeys, didDoc);
43
+ const normalizedKeys = [
44
+ generateAccessTokenSecret(CihKeyPurposes.HOLDER_ACCESS_TOKENS),
45
+ ].concat(map(normalizeTenantKey, tenantKeys));
46
+ const primaryAccount = await resolvePrimaryAccount(
47
+ newTenant,
48
+ normalizedKeys,
49
+ context,
50
+ );
51
+
52
+ const preparedTenant = await prepareTenant(
53
+ newTenant,
54
+ normalizedKeys,
55
+ primaryAccount,
56
+ context,
57
+ );
58
+ // eslint-disable-next-line better-mutation/no-mutation
59
+ context.tenant = preparedTenant;
60
+ const keys = await Promise.all(
61
+ map((normalizedKey) => kms.importKey(normalizedKey), normalizedKeys),
62
+ );
63
+
64
+ const tenant = await repos.tenants.insertTenant(preparedTenant);
65
+
66
+ return {
67
+ tenant,
68
+ keyMetadatas: keys.slice(1),
69
+ };
70
+ };
71
+
72
+ const resolvePrimaryAccount = async (newTenant, keys, context) => {
73
+ if (newTenant.primaryAccount != null) {
74
+ return newTenant.primaryAccount;
75
+ }
76
+ const dltKey = getKeyWithPurpose(KeyPurposes.DLT_TRANSACTIONS, keys);
77
+ return loadPrimaryAccount(dltKey, context);
78
+ };
79
+
80
+ /* eslint-disable better-mutation/no-mutation */
81
+ const prepareTenant = async (
82
+ newTenant,
83
+ normalizedKeys,
84
+ primaryAccount,
85
+ context,
86
+ ) => {
87
+ newTenant._id = new ObjectId();
88
+ newTenant.primaryAccount = primaryAccount;
89
+ if (newTenant.hostUrl == null) {
90
+ newTenant.hostUrl = context.config.hostUrl;
91
+ }
92
+ if (newTenant.caoDid == null) {
93
+ newTenant.caoDid = context.config.defaultCaoDid;
94
+ }
95
+ newTenant.keysByPurpose = flow(
96
+ flatMap((key) => {
97
+ const keyMetadata = pick(
98
+ ['_id', 'kidFragment', 'algorithm', 'encoding', 'publicJwk'],
99
+ key,
100
+ );
101
+ return map((purpose) => [purpose, keyMetadata], key.purposes);
102
+ }),
103
+ fromPairs,
104
+ )(normalizedKeys);
105
+ return newTenant;
106
+ };
107
+ /* eslint-enable */
108
+
109
+ const generateAccessTokenSecret = (purpose) => ({
110
+ _id: new ObjectId(),
111
+ purposes: [purpose],
112
+ encoding: KeyEncodings.BASE64URL,
113
+ secret: nanoid(16),
114
+ });
115
+
116
+ module.exports = { createTenant };
@@ -0,0 +1,45 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ const { ObjectId } = require('mongodb');
18
+ const { isEmpty, map } = require('lodash/fp');
19
+ const newError = require('http-errors');
20
+ const { TenantErrors } = require('../domain');
21
+
22
+ const deleteTenant = async (tenantId, { repos }) => {
23
+ const filter = { tenantId: new ObjectId(tenantId) };
24
+ const issuerServices = await repos.issuerServices.find({ filter });
25
+
26
+ if (!isEmpty(issuerServices)) {
27
+ throw newError(
28
+ 400,
29
+ `Issuer Service(s) ${map('_id')(
30
+ issuerServices,
31
+ )} must be deleted before deleting tenant`,
32
+ {
33
+ errorCode: TenantErrors.RELATED_SERVICE_UNDELETED,
34
+ },
35
+ );
36
+ }
37
+ return Promise.all([
38
+ repos.keys.delUsingFilter({
39
+ filter: { tenantId: new ObjectId(tenantId) },
40
+ }),
41
+ repos.tenants.del(tenantId),
42
+ ]);
43
+ };
44
+
45
+ module.exports = { deleteTenant };
@@ -0,0 +1,22 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ const findTenants = (tenantIds, { repos }) => {
18
+ const filter = tenantIds == null ? {} : { _id: { $in: tenantIds } };
19
+ return repos.tenants.find({ filter });
20
+ };
21
+
22
+ module.exports = { findTenants };
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ module.exports = {
18
+ ...require('./create-tenant'),
19
+ ...require('./delete-tenant'),
20
+ ...require('./find-tenants'),
21
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ ...require('./tenant-loader-plugin'),
3
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Copyright 2024 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ const fp = require('fastify-plugin');
18
+ const newError = require('http-errors');
19
+
20
+ const extractTenantId = (req) => {
21
+ if (req.params.tenantId != null) {
22
+ return req.params.tenantId;
23
+ }
24
+ if (req.query.tenantId != null) {
25
+ return req.query.tenantId;
26
+ }
27
+ if (req.body.tenantId != null) {
28
+ return req.body.tenantId;
29
+ }
30
+ return null;
31
+ };
32
+
33
+ const loadTenant = async (options, req) => {
34
+ const tenantId = extractTenantId(req);
35
+ if (tenantId == null) {
36
+ throwTenantNotFound(options);
37
+ }
38
+
39
+ const filter = options.useDID ? { did: tenantId } : { _id: tenantId };
40
+ const tenant = await req.repos.tenants.findOne({ filter });
41
+ if (tenant == null) {
42
+ throwTenantNotFound(options);
43
+ }
44
+ return tenant;
45
+ };
46
+
47
+ const tenantLoaderPlugin = async (fastify, options = { useDID: false }) => {
48
+ fastify.decorateRequest('tenant', null);
49
+ fastify.addHook('preHandler', async (req) => {
50
+ req.tenant = await loadTenant(options, req);
51
+ });
52
+ };
53
+
54
+ const throwTenantNotFound = ({ notFoundStatusCode = 404 }) => {
55
+ throw newError(notFoundStatusCode, 'Tenant not found', {
56
+ errorCode: 'tenant_not_found',
57
+ });
58
+ };
59
+
60
+ module.exports = {
61
+ tenantLoaderPlugin: fp(tenantLoaderPlugin, {
62
+ name: 'tenant-loader-plugin',
63
+ }),
64
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright 2023 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ module.exports = {
18
+ tenantRepoPlugin: require('./repo'),
19
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Copyright 2023 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ const newError = require('http-errors');
18
+ const { TenantErrors } = require('../domain/tenant-errors');
19
+
20
+ const insertTenantExtension = (parent) => ({
21
+ insertTenant: async (newTenant) => {
22
+ try {
23
+ return await parent.insert(newTenant);
24
+ } catch (e) {
25
+ if (e.name === 'MongoServerError' && e.code === 11000) {
26
+ throw newError(400, TenantErrors.TENANTS_MUST_BE_UNIQUE, {
27
+ errorCode: TenantErrors.TENANTS_MUST_BE_UNIQUE,
28
+ });
29
+ }
30
+ throw e;
31
+ }
32
+ },
33
+ extensions: parent.extensions.concat(['insertTenantExtension']),
34
+ });
35
+
36
+ module.exports = { insertTenantExtension };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright 2023 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ const {
18
+ repoFactory,
19
+ autoboxIdsExtension,
20
+ mongoDb,
21
+ } = require('@spencejs/spence-mongo-repos');
22
+ const { insertTenantExtension } = require('./insert-tenant-extension');
23
+
24
+ module.exports = (app, options, next = () => {}) => {
25
+ app.ready(async () => {
26
+ await mongoDb()
27
+ .collection('tenants')
28
+ .createIndex({ did: 1 }, { unique: true });
29
+ });
30
+ next();
31
+ return repoFactory(
32
+ {
33
+ name: 'tenants',
34
+ entityName: 'tenant',
35
+ defaultProjection: {
36
+ _id: 1,
37
+ did: 1,
38
+ primaryAccount: 1,
39
+ keysByPurpose: 1,
40
+ hostUrl: 1,
41
+ caoDid: 1,
42
+ name: 1,
43
+ logo: 1,
44
+ createdAt: 1,
45
+ updatedAt: 1,
46
+ },
47
+ extensions: [autoboxIdsExtension, insertTenantExtension],
48
+ },
49
+ app,
50
+ );
51
+ };