@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,67 @@
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 { split } = require('lodash/fp');
18
+ const newError = require('http-errors');
19
+ const { isPreauthCodeAuth } = require('../../links');
20
+ const {
21
+ ExchangeErrors,
22
+ ExchangeStates,
23
+ validatePreauth,
24
+ validateReferencedService,
25
+ } = require('../domain');
26
+
27
+ const authenticate = async (exchangeId, authJwtPayload, context) => {
28
+ const { repos } = context;
29
+ const exchange = await repos.exchanges.addState(
30
+ exchangeId,
31
+ ExchangeStates.AUTHENTICATION_REQUEST,
32
+ {
33
+ disclosureConsentedAt: new Date(),
34
+ },
35
+ );
36
+ const issuerService = await repos.issuerServices.findOne({
37
+ filter: { _id: exchange.serviceId },
38
+ });
39
+
40
+ validateReferencedService(issuerService);
41
+ if (!isPreauthCodeAuth(issuerService)) {
42
+ throw newError(400, ExchangeErrors.AUTHENTICATION_METHOD_UNSUPPORTED, {
43
+ errorCode: ExchangeErrors.AUTHENTICATION_METHOD_UNSUPPORTED,
44
+ });
45
+ }
46
+ const depot = await preauthCodeAuthHandler(authJwtPayload, context);
47
+
48
+ const authenticatedExchange = await repos.exchanges.addState(
49
+ exchangeId,
50
+ ExchangeStates.AUTHENTICATION_SUCCESS,
51
+ { depotId: depot._id },
52
+ );
53
+
54
+ return [issuerService, authenticatedExchange];
55
+ };
56
+
57
+ const preauthCodeAuthHandler = async ({ vendorOriginContext }, context) => {
58
+ const { repos } = context;
59
+ const preauthCodeParts = split(':', vendorOriginContext);
60
+ const depot = await repos.depots.findOne({
61
+ filter: { _id: preauthCodeParts?.[1] },
62
+ });
63
+ validatePreauth(preauthCodeParts?.[2], depot, context);
64
+ return depot;
65
+ };
66
+
67
+ module.exports = { authenticate };
@@ -0,0 +1,70 @@
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 { map, uniqBy } = require('lodash/fp');
18
+ const newError = require('http-errors');
19
+ const {
20
+ ExchangeStates,
21
+ authorizeExchange,
22
+ generateIssuingChallenge,
23
+ } = require('../domain');
24
+ const { parseAccessToken } = require('../../tokens');
25
+
26
+ // eslint-disable-next-line default-param-last
27
+ const credentialOfferRequest = async (token, offerHashes = [], context) => {
28
+ const { log, repos } = context;
29
+ const { exchangeId, depotId } = parseAccessToken(token);
30
+ const exchange = await repos.exchanges
31
+ .addState(exchangeId, ExchangeStates.OFFERS_REQUESTED)
32
+ .catch((error) => {
33
+ log.error(error);
34
+ throw newError(401, 'Unauthorized');
35
+ });
36
+ authorizeExchange(exchange, depotId);
37
+
38
+ const credentials = await repos.credentials.findByDepotId({
39
+ depotId,
40
+ credentialTypes: exchange.credentialTypes,
41
+ omitContentHashes: offerHashes,
42
+ claimable: true,
43
+ });
44
+
45
+ const { challenge } = await generateIssuingChallenge(exchangeId, context);
46
+
47
+ await repos.exchanges.addState(exchangeId, ExchangeStates.OFFERS_SENT, {
48
+ credentialIds: map('_id', credentials),
49
+ });
50
+
51
+ return {
52
+ challenge,
53
+ offers: map(
54
+ (credential) => buildOffer(credential, context),
55
+ uniqBy('contentHash', credentials),
56
+ ),
57
+ };
58
+ };
59
+
60
+ const buildOffer = (credential, { tenant }) => ({
61
+ ...credential.content,
62
+ id: credential._id,
63
+ hash: credential.contentHash,
64
+ issuer: {
65
+ ...(credential.content?.issuer ?? {}),
66
+ id: tenant.did,
67
+ },
68
+ });
69
+
70
+ module.exports = { credentialOfferRequest };
@@ -0,0 +1,84 @@
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 { map } = require('lodash/fp');
18
+ const { ObjectId } = require('mongodb');
19
+ const {
20
+ validateNewExchange,
21
+ buildCredentialManifest,
22
+ ExchangeTypes,
23
+ ExchangeProtocols,
24
+ ExchangeStates,
25
+ } = require('../domain');
26
+ const { fetchCredentialTypeDescriptors } = require('../../credential-types');
27
+
28
+ const getCredentialManifest = async (
29
+ serviceId,
30
+ credentialTypes,
31
+ locale,
32
+ messagingSettings,
33
+ context,
34
+ ) => {
35
+ const { repos, tenant } = context;
36
+
37
+ // setup exchange
38
+ const newExchange = {
39
+ type: ExchangeTypes.ISSUER,
40
+ serviceId: new ObjectId(serviceId),
41
+ protocolMetadata: {
42
+ protocol: ExchangeProtocols.VN_API,
43
+ },
44
+ credentialTypes,
45
+ messagingSettings,
46
+ };
47
+
48
+ // load issuer service
49
+ const issuerService = await repos.issuerServices.findOne({
50
+ filter: { _id: serviceId },
51
+ });
52
+
53
+ validateNewExchange(newExchange, issuerService);
54
+
55
+ const exchange = await repos.exchanges.insertWithInitialState(newExchange, [
56
+ ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
57
+ ]);
58
+ // eslint-disable-next-line better-mutation/no-mutation
59
+ context.exchange = exchange; // added onto the request for the exchange error handler
60
+
61
+ const inputDescriptors = await fetchCredentialTypeDescriptors(
62
+ map('type', issuerService?.disclosureRequest?.types),
63
+ false,
64
+ undefined,
65
+ context,
66
+ );
67
+
68
+ const outputDescriptors = await fetchCredentialTypeDescriptors(
69
+ credentialTypes,
70
+ true,
71
+ locale,
72
+ context,
73
+ );
74
+
75
+ return buildCredentialManifest(
76
+ tenant,
77
+ issuerService,
78
+ exchange,
79
+ inputDescriptors,
80
+ outputDescriptors,
81
+ );
82
+ };
83
+
84
+ module.exports = { getCredentialManifest };
@@ -0,0 +1,114 @@
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
+ const { ObjectId } = require('mongodb');
18
+ const newError = require('http-errors');
19
+ const { map, split, startsWith } = require('lodash/fp');
20
+ const {
21
+ ExchangeErrors,
22
+ ExchangeTypes,
23
+ ExchangeProtocols,
24
+ ExchangeStates,
25
+ buildPresentationRequest,
26
+ validateMessagingSettings,
27
+ } = require('../domain');
28
+ const { fetchCredentialTypeDescriptors } = require('../../credential-types');
29
+ const {
30
+ validateReferencedService,
31
+ } = require('../domain/validate-referenced-service');
32
+
33
+ const getPresentationRequest = async (
34
+ serviceId,
35
+ locale,
36
+ messagingSettings,
37
+ vendorOriginContext,
38
+ context,
39
+ ) => {
40
+ const { repos, tenant } = context;
41
+
42
+ // load issuer service
43
+ const relyingPartyService = await repos.relyingPartyServices.findOne({
44
+ filter: { _id: serviceId },
45
+ });
46
+
47
+ validateMessagingSettings(messagingSettings);
48
+ validateReferencedService(relyingPartyService);
49
+
50
+ const depot = await loadDepot(serviceId, vendorOriginContext, context);
51
+
52
+ // setup exchange
53
+ const newExchange = {
54
+ type: ExchangeTypes.RELYING_PARTY,
55
+ serviceId: new ObjectId(serviceId),
56
+ protocolMetadata: {
57
+ protocol: ExchangeProtocols.VN_API,
58
+ },
59
+ locale,
60
+ messagingSettings,
61
+ depotId: depot._id,
62
+ };
63
+
64
+ const exchange = await repos.exchanges.insertWithInitialState(newExchange, [
65
+ ExchangeStates.PRESENTATION_REQUEST_REQUESTED,
66
+ ]);
67
+ // eslint-disable-next-line better-mutation/no-mutation
68
+ context.exchange = exchange; // added onto the request for the exchange error handler
69
+
70
+ const inputDescriptors = await fetchCredentialTypeDescriptors(
71
+ map('type', relyingPartyService?.disclosureRequest?.types),
72
+ false,
73
+ undefined,
74
+ context,
75
+ );
76
+
77
+ return buildPresentationRequest(
78
+ tenant,
79
+ relyingPartyService,
80
+ exchange,
81
+ inputDescriptors,
82
+ );
83
+ };
84
+
85
+ const loadDepot = async (serviceId, vendorOriginContext, context) => {
86
+ const depotId = parseDepotId(vendorOriginContext);
87
+ if (depotId == null) {
88
+ return context.repos.depots.insert({
89
+ serviceId: new ObjectId(serviceId),
90
+ });
91
+ }
92
+
93
+ const depot = await context.repos.depots.findOne({
94
+ filter: { _id: depotId },
95
+ });
96
+ if (!isMatchingDepot(depot, serviceId)) {
97
+ throw newError(400, ExchangeErrors.REFERENCED_DEPOT_NOT_FOUND, {
98
+ errorCode: ExchangeErrors.REFERENCED_DEPOT_NOT_FOUND,
99
+ });
100
+ }
101
+ return depot;
102
+ };
103
+
104
+ const parseDepotId = (vendorOriginContext) => {
105
+ if (!startsWith('depot:', vendorOriginContext)) {
106
+ return undefined;
107
+ }
108
+ return split(':', vendorOriginContext)[1];
109
+ };
110
+
111
+ const isMatchingDepot = (depot, serviceId) =>
112
+ depot != null && depot.serviceId?.toString() === serviceId.toString();
113
+
114
+ module.exports = { getPresentationRequest };
@@ -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('./authenticate'),
19
+ ...require('./credential-offer-request'),
20
+ ...require('./get-credential-manifest'),
21
+ ...require('./get-presentation-request'),
22
+ ...require('./post-presentation'),
23
+ ...require('./issue-credentials'),
24
+ };
@@ -0,0 +1,132 @@
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 newError = require('http-errors');
19
+ const { isEmpty, map, uniq } = require('lodash/fp');
20
+ const { mapWithIndex } = require('@verii/common-functions');
21
+ const { jwtDecode } = require('@verii/jwt');
22
+ const { parseAccessToken } = require('../../tokens');
23
+ const { ExchangeStates, verifyProofOfKeyPossession } = require('../domain');
24
+ const { authorizeExchange } = require('../domain/authorize-exchange');
25
+ const { issueVeriiCredentialsFacade } = require('../../credentials');
26
+
27
+ const issueCredentials = async (
28
+ token,
29
+ approvedCredentialIds,
30
+ rejectedCredentialIds,
31
+ keyPossessionProof,
32
+ context,
33
+ ) => {
34
+ const { log, repos } = context;
35
+ const { exchangeId, depotId } = parseAccessToken(token);
36
+ const exchange = await repos.exchanges
37
+ .addState(exchangeId, ExchangeStates.CLAIMING_IN_PROGRESS)
38
+ .catch((error) => {
39
+ log.error(error);
40
+ throw newError(401, 'Unauthorized');
41
+ });
42
+ authorizeExchange(exchange, depotId);
43
+ const issuerService = await repos.issuerServices.findById(exchange.serviceId);
44
+
45
+ const rejectedCredentials = await rejectCredentials(
46
+ rejectedCredentialIds,
47
+ context,
48
+ );
49
+
50
+ const [issuedCredentials, jwtVcs] = await issueApprovedCredentials(
51
+ approvedCredentialIds,
52
+ keyPossessionProof,
53
+ exchange,
54
+ issuerService,
55
+ context,
56
+ );
57
+
58
+ await repos.exchanges.addState(exchange._id, ExchangeStates.COMPLETE, {
59
+ finalizedCredentialIds: uniq([
60
+ ...(exchange.finalizedCredentialIds ?? []),
61
+ ...map('_id', rejectedCredentials),
62
+ ...map('_id', issuedCredentials),
63
+ ]),
64
+ });
65
+
66
+ return jwtVcs;
67
+ };
68
+
69
+ const rejectCredentials = (credentialIds, { repos }) => {
70
+ if (!isEmpty(credentialIds)) {
71
+ return repos.credentials.updateUsingFilter(
72
+ { filter: { _id: { $in: credentialIds } } },
73
+ { rejectedAt: new Date() },
74
+ );
75
+ }
76
+
77
+ return Promise.resolve([]);
78
+ };
79
+
80
+ const issueApprovedCredentials = async (
81
+ credentialIds,
82
+ proof,
83
+ exchange,
84
+ issuerService,
85
+ context,
86
+ ) => {
87
+ const { repos, log } = context;
88
+
89
+ if (isEmpty(credentialIds)) {
90
+ return Promise.resolve([[], []]);
91
+ }
92
+
93
+ const approvedCredentials =
94
+ await repos.credentials.findNonFinal(credentialIds);
95
+
96
+ if (isEmpty(approvedCredentials)) {
97
+ log.info('approved credentials not found');
98
+ return [[], []];
99
+ }
100
+
101
+ const credentialSubjectId = await verifyProofOfKeyPossession(
102
+ proof,
103
+ exchange,
104
+ context,
105
+ );
106
+
107
+ const jwtVcs = await issueVeriiCredentialsFacade(
108
+ map('content', approvedCredentials),
109
+ credentialSubjectId,
110
+ map('typeMetadata', approvedCredentials),
111
+ issuerService,
112
+ context,
113
+ );
114
+
115
+ const issuedCredentials = await Promise.all(
116
+ mapWithIndex(
117
+ async (credential, i) =>
118
+ repos.credentials.updateIssuedCredential(
119
+ credential._id,
120
+ jwtDecode(jwtVcs[i]).payload.vc.id,
121
+ jwtVcs[i],
122
+ credentialSubjectId,
123
+ true,
124
+ ),
125
+ approvedCredentials,
126
+ ),
127
+ );
128
+
129
+ return [issuedCredentials, jwtVcs];
130
+ };
131
+
132
+ module.exports = { issueCredentials };
@@ -0,0 +1,58 @@
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
+ const {
18
+ verifyVerifiablePresentationJwt,
19
+ } = require('@verii/verii-verification');
20
+ const { ExchangeStates, validateReferencedService } = require('../domain');
21
+ const {
22
+ PresentationFormat,
23
+ validatePresentation,
24
+ } = require('../../presentations');
25
+
26
+ const postPresentation = async (
27
+ exchangeId,
28
+ jwtPresentationSubmission,
29
+ context,
30
+ ) => {
31
+ const { repos } = context;
32
+
33
+ const vp = await verifyVerifiablePresentationJwt(jwtPresentationSubmission, {
34
+ vnfProtocolVersion: 2,
35
+ });
36
+
37
+ const exchange = await repos.exchanges.addState(
38
+ exchangeId,
39
+ ExchangeStates.PRESENTATION_SUBMISSION_RECEIVED,
40
+ {
41
+ disclosureConsentedAt: new Date(),
42
+ },
43
+ );
44
+ const relyingPartyService = await repos.relyingPartyServices.findOne({
45
+ filter: { _id: exchange.serviceId },
46
+ });
47
+ validateReferencedService(relyingPartyService);
48
+ validatePresentation(vp, exchange, context, vp.presentation_submission);
49
+ const presentation = await repos.presentations.insert({
50
+ depotId: exchange.depotId,
51
+ exchangeId,
52
+ format: PresentationFormat.JWT_VP,
53
+ presentation: jwtPresentationSubmission,
54
+ });
55
+ return [relyingPartyService, exchange, presentation];
56
+ };
57
+
58
+ module.exports = { postPresentation };
@@ -0,0 +1,78 @@
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 { isEmpty, map } = require('lodash/fp');
18
+ const newError = require('http-errors');
19
+ const { ExchangeStates } = require('../domain');
20
+ const { ExchangeErrors } = require('../domain/exchange-errors');
21
+
22
+ const exchangeStateRepoExtension = (parent) => ({
23
+ insertWithInitialState: (val, states, ...args) => {
24
+ const timestamp = new Date();
25
+ return parent.insert(
26
+ {
27
+ events: [
28
+ {
29
+ state: ExchangeStates.NEW,
30
+ timestamp,
31
+ },
32
+ ...map((state) => ({ state, timestamp }), states),
33
+ ],
34
+ ...val,
35
+ },
36
+ ...args,
37
+ );
38
+ },
39
+ addState: async (
40
+ exchangeId,
41
+ state,
42
+ $set,
43
+ projection = parent.defaultColumnsSelection,
44
+ ) => {
45
+ const filter = {
46
+ _id: exchangeId,
47
+ 'events.state': { $ne: ExchangeStates.COMPLETE },
48
+ };
49
+
50
+ let updateStatement = {
51
+ $push: { events: { state, timestamp: new Date() } },
52
+ };
53
+ if ($set) {
54
+ updateStatement = {
55
+ ...updateStatement,
56
+ $set: parent.prepModification($set),
57
+ };
58
+ }
59
+ const result = await parent
60
+ .collection()
61
+ .findOneAndUpdate(parent.prepFilter(filter), updateStatement, {
62
+ returnDocument: 'after',
63
+ includeResultMetadata: true,
64
+ projection,
65
+ });
66
+
67
+ if (isEmpty(result.value)) {
68
+ throw newError(400, 'Referenced exchange not found', {
69
+ errorCode: ExchangeErrors.REFERENCED_EXCHANGE_NOT_FOUND,
70
+ });
71
+ }
72
+
73
+ return result.value;
74
+ },
75
+ extensions: parent.extensions.concat(['exchangeStateRepoExtension']),
76
+ });
77
+
78
+ module.exports = { exchangeStateRepoExtension };
@@ -0,0 +1,19 @@
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
+ exchangesRepoPlugin: require('./repo'),
19
+ };
@@ -0,0 +1,52 @@
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
+ } = require('@spencejs/spence-mongo-repos');
21
+ const { multitenantExtension } = require('@verii/spencer-mongo-extensions');
22
+ const {
23
+ exchangeStateRepoExtension,
24
+ } = require('./exchange-state-repo-extension');
25
+
26
+ module.exports = (app, options, next = () => {}) => {
27
+ next();
28
+ return repoFactory(
29
+ {
30
+ name: 'exchanges',
31
+ entityName: 'exchange',
32
+ defaultProjection: {
33
+ _id: 1,
34
+ serviceId: 1,
35
+ depotId: 1,
36
+ type: 1,
37
+ protocolMetadata: 1,
38
+ credentialTypes: 1,
39
+ messagingSettings: 1,
40
+ locale: 1,
41
+ events: 1,
42
+ createdAt: 1,
43
+ },
44
+ extensions: [
45
+ autoboxIdsExtension,
46
+ multitenantExtension(),
47
+ exchangeStateRepoExtension,
48
+ ],
49
+ },
50
+ app,
51
+ );
52
+ };