@verii/server-credentialagent 1.0.0-pre.1752076816

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 (395) hide show
  1. package/.localdev.e2e.env +40 -0
  2. package/.localdev.env +41 -0
  3. package/.standalone.env +5 -0
  4. package/LICENSE +202 -0
  5. package/NOTICE +1 -0
  6. package/README.md +19 -0
  7. package/docker/compose.yml +33 -0
  8. package/e2e/README.md +12 -0
  9. package/e2e/org-registration-and-issuing.e2e.test.js +624 -0
  10. package/jest.config.js +20 -0
  11. package/migrate-mongo.config.js +36 -0
  12. package/migrations/20210317133137-add-index-to-offers-repo.js +57 -0
  13. package/migrations/20210416145639-add-index-to-revocation-list.js +27 -0
  14. package/migrations/20210719120225-add_unique_did_index_to_tenant.js +45 -0
  15. package/migrations/20230524053029-add-vendorUserIdMappings-index.js +32 -0
  16. package/migrations/20230616111907-add-configuration-type-index.js +32 -0
  17. package/package.json +108 -0
  18. package/src/assets/public/favicon.ico +0 -0
  19. package/src/assets/public/logo192.png +0 -0
  20. package/src/assets/public/logo512.png +0 -0
  21. package/src/assets/public/manifest.json +28 -0
  22. package/src/assets/templates/app-redirect.hbs +16 -0
  23. package/src/config/config.js +44 -0
  24. package/src/config/core-config.js +143 -0
  25. package/src/config/holder-config.js +104 -0
  26. package/src/config/index.js +22 -0
  27. package/src/config/operator-config.js +64 -0
  28. package/src/controllers/autoload-holder-api-controllers.js +30 -0
  29. package/src/controllers/autoload-operator-api-controllers.js +31 -0
  30. package/src/controllers/autoload-root-api-controller.js +30 -0
  31. package/src/controllers/autoload-saasoperator-api-controllers.js +31 -0
  32. package/src/controllers/holder/autohooks.js +55 -0
  33. package/src/controllers/holder/get-exchange-progress/autohooks.js +27 -0
  34. package/src/controllers/holder/get-exchange-progress/controller.js +50 -0
  35. package/src/controllers/holder/inspect/autohooks.js +35 -0
  36. package/src/controllers/holder/inspect/get-presentation-request/controller.js +100 -0
  37. package/src/controllers/holder/inspect/schemas/holder-disclosure.schema.json +73 -0
  38. package/src/controllers/holder/inspect/schemas/index.js +33 -0
  39. package/src/controllers/holder/inspect/schemas/presentation-definition.v1.schema.json +461 -0
  40. package/src/controllers/holder/inspect/schemas/presentation-request.schema.json +279 -0
  41. package/src/controllers/holder/inspect/schemas/presentation-submission.schema.json +41 -0
  42. package/src/controllers/holder/inspect/schemas/siop-presentation-submission.schema.json +74 -0
  43. package/src/controllers/holder/inspect/schemas/velocity-presentation-submission.response.200.schema.json +36 -0
  44. package/src/controllers/holder/inspect/schemas/velocity-presentation-submission.schema.json +34 -0
  45. package/src/controllers/holder/inspect/submit-presentation/controller.js +89 -0
  46. package/src/controllers/holder/issue/autohooks.js +23 -0
  47. package/src/controllers/holder/issue/get-credential-manifest/controller.js +193 -0
  48. package/src/controllers/holder/issue/offers/autohooks.js +35 -0
  49. package/src/controllers/holder/issue/offers/controller.js +164 -0
  50. package/src/controllers/holder/issue/offers/credential-offers/controller.js +460 -0
  51. package/src/controllers/holder/issue/submit-identification/autohooks.js +37 -0
  52. package/src/controllers/holder/issue/submit-identification/controller.js +63 -0
  53. package/src/controllers/holder/oauth/autohooks.js +19 -0
  54. package/src/controllers/holder/oauth/controller.js +140 -0
  55. package/src/controllers/index.js +22 -0
  56. package/src/controllers/operator/tenants/_tenantId/autohooks.js +40 -0
  57. package/src/controllers/operator/tenants/_tenantId/check-credentials/autohooks.js +24 -0
  58. package/src/controllers/operator/tenants/_tenantId/check-credentials/controller-v0.8.js +200 -0
  59. package/src/controllers/operator/tenants/_tenantId/check-credentials/schemas/index.js +19 -0
  60. package/src/controllers/operator/tenants/_tenantId/check-credentials/schemas/vendor-credential.schema.json +244 -0
  61. package/src/controllers/operator/tenants/_tenantId/controller-v0.8.js +221 -0
  62. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/autohooks.js +30 -0
  63. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/controller-v0.8.js +271 -0
  64. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/feeds/autohooks.js +45 -0
  65. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/feeds/controller-v0.8.js +199 -0
  66. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/feeds/schemas/add-feed.schema.js +14 -0
  67. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/feeds/schemas/feed.schema.json +27 -0
  68. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/feeds/schemas/index.js +25 -0
  69. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/feeds/schemas/modify-feed-update-body.schema.js +18 -0
  70. package/src/controllers/operator/tenants/_tenantId/disclosures/_id/feeds/schemas/modify-feed.schema.json +19 -0
  71. package/src/controllers/operator/tenants/_tenantId/disclosures/autohooks.js +34 -0
  72. package/src/controllers/operator/tenants/_tenantId/disclosures/controller-v0.8.js +100 -0
  73. package/src/controllers/operator/tenants/_tenantId/disclosures/schemas/agent-disclosure-presentation-definition.schema.json +404 -0
  74. package/src/controllers/operator/tenants/_tenantId/disclosures/schemas/agent-disclosure.schema.js +24 -0
  75. package/src/controllers/operator/tenants/_tenantId/disclosures/schemas/index.js +29 -0
  76. package/src/controllers/operator/tenants/_tenantId/disclosures/schemas/new-agent-disclosure.schema.json +166 -0
  77. package/src/controllers/operator/tenants/_tenantId/disclosures/schemas/update-agent-disclosure.schema.js +20 -0
  78. package/src/controllers/operator/tenants/_tenantId/exchanges/_exchangeId/autohooks.js +30 -0
  79. package/src/controllers/operator/tenants/_tenantId/exchanges/_exchangeId/controller-v0.8.js +73 -0
  80. package/src/controllers/operator/tenants/_tenantId/exchanges/autohooks.js +19 -0
  81. package/src/controllers/operator/tenants/_tenantId/exchanges/controller-v0.8.js +150 -0
  82. package/src/controllers/operator/tenants/_tenantId/exchanges/schemas/get-exchange.response.body.json +147 -0
  83. package/src/controllers/operator/tenants/_tenantId/exchanges/schemas/index.js +21 -0
  84. package/src/controllers/operator/tenants/_tenantId/issued-credentials/autohooks.js +27 -0
  85. package/src/controllers/operator/tenants/_tenantId/issued-credentials/controller-v0.8.js +303 -0
  86. package/src/controllers/operator/tenants/_tenantId/issued-credentials/schemas/index.js +23 -0
  87. package/src/controllers/operator/tenants/_tenantId/issued-credentials/schemas/issued-credential.schema.json +115 -0
  88. package/src/controllers/operator/tenants/_tenantId/issued-credentials/schemas/revoke-credentials.schema.json +18 -0
  89. package/src/controllers/operator/tenants/_tenantId/keys/controller-v0.8.js +168 -0
  90. package/src/controllers/operator/tenants/_tenantId/offer-data/controller-v0.8.js +78 -0
  91. package/src/controllers/operator/tenants/_tenantId/offers/autohooks.js +34 -0
  92. package/src/controllers/operator/tenants/_tenantId/offers/controller-v0.8.js +253 -0
  93. package/src/controllers/operator/tenants/_tenantId/offers/schemas/index.js +23 -0
  94. package/src/controllers/operator/tenants/_tenantId/offers/schemas/new-vendor-offer.schema.js +47 -0
  95. package/src/controllers/operator/tenants/_tenantId/offers/schemas/vendor-offer.schema.json +56 -0
  96. package/src/controllers/operator/tenants/_tenantId/users/autohooks.js +24 -0
  97. package/src/controllers/operator/tenants/_tenantId/users/controller-v0.8.js +92 -0
  98. package/src/controllers/operator/tenants/_tenantId/users/schemas/index.js +23 -0
  99. package/src/controllers/operator/tenants/_tenantId/users/schemas/new-user.schema.json +13 -0
  100. package/src/controllers/operator/tenants/_tenantId/users/schemas/user.schema.json +16 -0
  101. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/autohooks.js +34 -0
  102. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/controller-v0.8.js +110 -0
  103. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/schemas/Credential.schema.js +18 -0
  104. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/schemas/IssueCredentialOptions.schema.json +42 -0
  105. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/schemas/IssueCredentialRequest.schema.json +13 -0
  106. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/schemas/IssueCredentialResponse.schema.json +19 -0
  107. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/schemas/LinkedDataProof.schema.json +43 -0
  108. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/schemas/VerifiableCredential.schema.js +16 -0
  109. package/src/controllers/operator/tenants/_tenantId/vc-api/credentials/schemas/index.js +31 -0
  110. package/src/controllers/operator/tenants/autohooks.js +65 -0
  111. package/src/controllers/operator/tenants/controller-v0.8.js +167 -0
  112. package/src/controllers/operator/tenants/schemas/index.js +41 -0
  113. package/src/controllers/operator/tenants/schemas/modify-secret.schema.json +11 -0
  114. package/src/controllers/operator/tenants/schemas/modify-tenant-v0.8.schema.json +44 -0
  115. package/src/controllers/operator/tenants/schemas/new-tenant-v0.8.schema.json +19 -0
  116. package/src/controllers/operator/tenants/schemas/new-tenant.response.200.schema.json +7 -0
  117. package/src/controllers/operator/tenants/schemas/secret-key-metadata.schema.json +31 -0
  118. package/src/controllers/operator/tenants/schemas/secret-key.schema.json +29 -0
  119. package/src/controllers/operator/tenants/schemas/secret-kid.schema.json +13 -0
  120. package/src/controllers/operator/tenants/schemas/secret-new-tenant-v0.8.schema.json +28 -0
  121. package/src/controllers/operator/tenants/schemas/secret-tenant-key-v0.8.schema.json +13 -0
  122. package/src/controllers/operator/tenants/schemas/tenant-key-v0.8.schema.json +14 -0
  123. package/src/controllers/operator/tenants/schemas/tenant-v0.8.schema.json +62 -0
  124. package/src/controllers/root/autohooks.js +23 -0
  125. package/src/controllers/root/controller.js +173 -0
  126. package/src/controllers/saasoperator/groups/_id/autohooks.js +9 -0
  127. package/src/controllers/saasoperator/groups/_id/controller.js +121 -0
  128. package/src/controllers/saasoperator/groups/autohooks.js +19 -0
  129. package/src/controllers/saasoperator/groups/controller.js +65 -0
  130. package/src/controllers/saasoperator/groups/schemas/group.schema.js +17 -0
  131. package/src/controllers/saasoperator/groups/schemas/index.js +4 -0
  132. package/src/controllers/saasoperator/groups/schemas/new-group.schema.js +13 -0
  133. package/src/entities/common/domains/get-json-at-path.js +28 -0
  134. package/src/entities/common/domains/index.js +17 -0
  135. package/src/entities/common/index.js +17 -0
  136. package/src/entities/credentials/domains/credential-format.js +22 -0
  137. package/src/entities/credentials/domains/index.js +19 -0
  138. package/src/entities/credentials/index.js +17 -0
  139. package/src/entities/deep-links/domains/extract-did.js +11 -0
  140. package/src/entities/deep-links/domains/index.js +20 -0
  141. package/src/entities/deep-links/domains/velocity-protocol-uri-to-http-uri.js +32 -0
  142. package/src/entities/deep-links/index.js +19 -0
  143. package/src/entities/disclosures/domains/assert-disclosure-active.js +21 -0
  144. package/src/entities/disclosures/domains/compute-disclosure-configuration-type.js +29 -0
  145. package/src/entities/disclosures/domains/constants.js +61 -0
  146. package/src/entities/disclosures/domains/errors.js +34 -0
  147. package/src/entities/disclosures/domains/get-disclosure-configuration-type.js +60 -0
  148. package/src/entities/disclosures/domains/index.js +32 -0
  149. package/src/entities/disclosures/domains/is-issuing-disclosure.js +23 -0
  150. package/src/entities/disclosures/domains/parse-body-to-disclosure.js +17 -0
  151. package/src/entities/disclosures/domains/validate-by-identification-method.js +69 -0
  152. package/src/entities/disclosures/domains/validate-commercial-entity.js +26 -0
  153. package/src/entities/disclosures/domains/validate-disclosure-by-configuration-type.js +47 -0
  154. package/src/entities/disclosures/domains/validate-disclosure-default-issuing.js +77 -0
  155. package/src/entities/disclosures/domains/validate-disclosure.js +37 -0
  156. package/src/entities/disclosures/domains/validate-feed.js +16 -0
  157. package/src/entities/disclosures/domains/validate-presentation-definition.js +54 -0
  158. package/src/entities/disclosures/domains/validate-vendor-endpoint.js +22 -0
  159. package/src/entities/disclosures/domains/validate-vendor-webhook.js +18 -0
  160. package/src/entities/disclosures/factories/disclosure-factory.js +94 -0
  161. package/src/entities/disclosures/factories/index.js +19 -0
  162. package/src/entities/disclosures/index.js +22 -0
  163. package/src/entities/disclosures/orchestrators/get-disclosure.js +18 -0
  164. package/src/entities/disclosures/orchestrators/index.js +20 -0
  165. package/src/entities/disclosures/orchestrators/update-disclosure-configuration-type.js +32 -0
  166. package/src/entities/disclosures/repos/index.js +20 -0
  167. package/src/entities/disclosures/repos/repo.js +118 -0
  168. package/src/entities/disclosures/repos/set-configuration-type.js +33 -0
  169. package/src/entities/exchanges/adapters/index.js +17 -0
  170. package/src/entities/exchanges/adapters/sign-exchange-response.js +45 -0
  171. package/src/entities/exchanges/domains/build-exchange-progress.js +56 -0
  172. package/src/entities/exchanges/domains/constants.js +24 -0
  173. package/src/entities/exchanges/domains/ensure-exchange-state-valid.js +35 -0
  174. package/src/entities/exchanges/domains/errors.js +33 -0
  175. package/src/entities/exchanges/domains/index.js +25 -0
  176. package/src/entities/exchanges/domains/states.js +43 -0
  177. package/src/entities/exchanges/domains/types.js +31 -0
  178. package/src/entities/exchanges/factories/disclosure-exchange-factory.js +46 -0
  179. package/src/entities/exchanges/factories/index.js +20 -0
  180. package/src/entities/exchanges/factories/offer-exchange-factory.js +48 -0
  181. package/src/entities/exchanges/index.js +23 -0
  182. package/src/entities/exchanges/orchestrators/build-exchange-request-deep-link.js +50 -0
  183. package/src/entities/exchanges/orchestrators/index.js +19 -0
  184. package/src/entities/exchanges/repos/exchange-repo-projections.js +45 -0
  185. package/src/entities/exchanges/repos/exchange-state-repo-extension.js +76 -0
  186. package/src/entities/exchanges/repos/index.js +20 -0
  187. package/src/entities/exchanges/repos/repo.js +44 -0
  188. package/src/entities/feeds/factories/feed-factory.js +47 -0
  189. package/src/entities/feeds/factories/index.js +19 -0
  190. package/src/entities/feeds/index.js +20 -0
  191. package/src/entities/feeds/repos/index.js +19 -0
  192. package/src/entities/feeds/repos/repo.js +95 -0
  193. package/src/entities/groups/domains/format-group.js +11 -0
  194. package/src/entities/groups/domains/index.js +3 -0
  195. package/src/entities/groups/factories/group-factory.js +40 -0
  196. package/src/entities/groups/factories/index.js +19 -0
  197. package/src/entities/groups/index.js +22 -0
  198. package/src/entities/groups/orchestrators/find-group-or-error.js +16 -0
  199. package/src/entities/groups/orchestrators/index.js +6 -0
  200. package/src/entities/groups/orchestrators/validate-did.js +24 -0
  201. package/src/entities/groups/orchestrators/validate-group-by-user.js +16 -0
  202. package/src/entities/groups/orchestrators/validate-group.js +39 -0
  203. package/src/entities/groups/repos/delete-tenant-extension.js +13 -0
  204. package/src/entities/groups/repos/index.js +19 -0
  205. package/src/entities/groups/repos/repo.js +38 -0
  206. package/src/entities/groups/repos/update-or-error-extension.js +46 -0
  207. package/src/entities/index.js +37 -0
  208. package/src/entities/keys/domains/constants.js +37 -0
  209. package/src/entities/keys/domains/index.js +21 -0
  210. package/src/entities/keys/domains/is-matching-private-key-kid.js +41 -0
  211. package/src/entities/keys/domains/validate-key.js +62 -0
  212. package/src/entities/keys/factories/index.js +19 -0
  213. package/src/entities/keys/factories/key-factory.js +56 -0
  214. package/src/entities/keys/index.js +22 -0
  215. package/src/entities/keys/orchestrators/index.js +3 -0
  216. package/src/entities/keys/orchestrators/validate-did-doc-keys.js +69 -0
  217. package/src/entities/metadata-list-allocations/index.js +19 -0
  218. package/src/entities/metadata-list-allocations/repos/index.js +19 -0
  219. package/src/entities/metadata-list-allocations/repos/repo.js +40 -0
  220. package/src/entities/notifications/domains/index.js +19 -0
  221. package/src/entities/notifications/domains/notification-types.js +25 -0
  222. package/src/entities/notifications/index.js +19 -0
  223. package/src/entities/offers/domains/build-clean-pii-filter.js +35 -0
  224. package/src/entities/offers/domains/build-deeplink-url.js +120 -0
  225. package/src/entities/offers/domains/build-offer.js +88 -0
  226. package/src/entities/offers/domains/build-qr-code-url.js +37 -0
  227. package/src/entities/offers/domains/constants.js +32 -0
  228. package/src/entities/offers/domains/filter-object-ids.js +34 -0
  229. package/src/entities/offers/domains/generate-issuing-challenge.js +26 -0
  230. package/src/entities/offers/domains/generate-link-code.js +35 -0
  231. package/src/entities/offers/domains/index.js +31 -0
  232. package/src/entities/offers/domains/post-validation-offers-handler.js +31 -0
  233. package/src/entities/offers/domains/prepare-linked-credentials-for-holder.js +36 -0
  234. package/src/entities/offers/domains/resolve-subject.js +142 -0
  235. package/src/entities/offers/domains/validate-offer-commercial-entity.js +24 -0
  236. package/src/entities/offers/domains/validate-offer.js +90 -0
  237. package/src/entities/offers/factories/index.js +19 -0
  238. package/src/entities/offers/factories/offer-factory.js +119 -0
  239. package/src/entities/offers/index.js +22 -0
  240. package/src/entities/offers/orchestrators/create-verifiable-credentials.js +131 -0
  241. package/src/entities/offers/orchestrators/finalize-exchange.js +44 -0
  242. package/src/entities/offers/orchestrators/index.js +23 -0
  243. package/src/entities/offers/orchestrators/load-credential-refs.js +57 -0
  244. package/src/entities/offers/orchestrators/load-credential-types-map.js +44 -0
  245. package/src/entities/offers/orchestrators/prepare-offers.js +35 -0
  246. package/src/entities/offers/orchestrators/trigger-issued-credentials-webhook.js +63 -0
  247. package/src/entities/offers/repos/clean-pii-extension.js +85 -0
  248. package/src/entities/offers/repos/index.js +20 -0
  249. package/src/entities/offers/repos/issued-credential-projection.js +44 -0
  250. package/src/entities/offers/repos/repo.js +177 -0
  251. package/src/entities/presentations/domains/build-identity-doc.js +120 -0
  252. package/src/entities/presentations/domains/build-request-response-schema.js +46 -0
  253. package/src/entities/presentations/domains/build-vendor-data.js +31 -0
  254. package/src/entities/presentations/domains/check-payment-requirement.js +30 -0
  255. package/src/entities/presentations/domains/errors.js +28 -0
  256. package/src/entities/presentations/domains/extract-fields-from-id-credential.js +35 -0
  257. package/src/entities/presentations/domains/index.js +26 -0
  258. package/src/entities/presentations/domains/merge-credential-check-results.js +24 -0
  259. package/src/entities/presentations/domains/validate-presentation.js +128 -0
  260. package/src/entities/presentations/index.js +20 -0
  261. package/src/entities/presentations/orchestrators/create-presentation-request.js +148 -0
  262. package/src/entities/presentations/orchestrators/deduplicate-disclosure-exchange.js +52 -0
  263. package/src/entities/presentations/orchestrators/handle-presentation-submission.js +47 -0
  264. package/src/entities/presentations/orchestrators/index.js +20 -0
  265. package/src/entities/presentations/orchestrators/match-identity-on-exchange.js +114 -0
  266. package/src/entities/presentations/orchestrators/share-identification-credentials.js +110 -0
  267. package/src/entities/presentations/orchestrators/share-presentation.js +234 -0
  268. package/src/entities/push-delegate/get-push-delegate.js +37 -0
  269. package/src/entities/push-delegate/index.js +17 -0
  270. package/src/entities/redirect/index.js +3 -0
  271. package/src/entities/redirect/orchestrators/index.js +3 -0
  272. package/src/entities/redirect/orchestrators/load-org-info.js +40 -0
  273. package/src/entities/revocation-list-allocations/index.js +19 -0
  274. package/src/entities/revocation-list-allocations/repos/index.js +19 -0
  275. package/src/entities/revocation-list-allocations/repos/repo.js +40 -0
  276. package/src/entities/schemas/index.js +19 -0
  277. package/src/entities/schemas/orchestrators/index.js +19 -0
  278. package/src/entities/schemas/orchestrators/load-schema-validation.js +73 -0
  279. package/src/entities/tenants/domains/build-service-ids.js +27 -0
  280. package/src/entities/tenants/domains/extract-service.js +27 -0
  281. package/src/entities/tenants/domains/index.js +21 -0
  282. package/src/entities/tenants/domains/validate-service-ids.js +35 -0
  283. package/src/entities/tenants/factories/index.js +19 -0
  284. package/src/entities/tenants/factories/tenant-factory.js +37 -0
  285. package/src/entities/tenants/index.js +22 -0
  286. package/src/entities/tenants/orchestrators/add-primary-address-to-tenant.js +47 -0
  287. package/src/entities/tenants/orchestrators/create-tenant.js +91 -0
  288. package/src/entities/tenants/orchestrators/index.js +22 -0
  289. package/src/entities/tenants/orchestrators/refresh-tenant-dids.js +146 -0
  290. package/src/entities/tenants/orchestrators/set-tenant-default-issuing-disclosure.js +31 -0
  291. package/src/entities/tenants/repos/index.js +20 -0
  292. package/src/entities/tenants/repos/insert-tenant-extension.js +33 -0
  293. package/src/entities/tenants/repos/repo.js +52 -0
  294. package/src/entities/tenants/repos/tenant-default-projection.js +33 -0
  295. package/src/entities/tokens/adapters/access-token.js +49 -0
  296. package/src/entities/tokens/adapters/index.js +19 -0
  297. package/src/entities/tokens/index.js +19 -0
  298. package/src/entities/users/factories/index.js +19 -0
  299. package/src/entities/users/factories/user-factory.js +36 -0
  300. package/src/entities/users/index.js +20 -0
  301. package/src/entities/users/repos/add-anonymous-user-repo-extension.js +23 -0
  302. package/src/entities/users/repos/find-or-insert-vendor-user-repo-extension.js +30 -0
  303. package/src/entities/users/repos/index.js +19 -0
  304. package/src/entities/users/repos/repo.js +50 -0
  305. package/src/fetchers/index.js +20 -0
  306. package/src/fetchers/operator/identify-fetcher.js +36 -0
  307. package/src/fetchers/operator/index.js +21 -0
  308. package/src/fetchers/operator/inspection-fetcher.js +35 -0
  309. package/src/fetchers/operator/issuing-fetcher.js +50 -0
  310. package/src/fetchers/operator/webhook-auth-header.js +45 -0
  311. package/src/fetchers/push-gateway/generate-push-gateway-token.js +40 -0
  312. package/src/fetchers/push-gateway/index.js +19 -0
  313. package/src/fetchers/push-gateway/push-fetcher.js +39 -0
  314. package/src/index.js +19 -0
  315. package/src/init-holder-server.js +108 -0
  316. package/src/init-operator-server.js +101 -0
  317. package/src/init-server.js +120 -0
  318. package/src/main-holder.js +18 -0
  319. package/src/main-operator.js +19 -0
  320. package/src/main.js +18 -0
  321. package/src/plugins/autoload-repos.js +28 -0
  322. package/src/plugins/disclosure-loader-plugin.js +56 -0
  323. package/src/plugins/ensure-disclosure-active-plugin.js +30 -0
  324. package/src/plugins/ensure-disclosure-configuration-type-plugin.js +29 -0
  325. package/src/plugins/ensure-tenant-default-issuing-disclosure-id-plugin.js +60 -0
  326. package/src/plugins/ensure-tenant-primary-address-plugin.js +44 -0
  327. package/src/plugins/exchange-error-handler-plugin.js +51 -0
  328. package/src/plugins/exchange-loader-plugin.js +50 -0
  329. package/src/plugins/group-loader-plugin.js +51 -0
  330. package/src/plugins/index.js +32 -0
  331. package/src/plugins/kms-plugin.js +57 -0
  332. package/src/plugins/tenant-loader-plugin.js +91 -0
  333. package/src/plugins/validate-cao-plugin.js +81 -0
  334. package/src/plugins/vendor-routes-auth-plugin.js +24 -0
  335. package/src/plugins/verify-access-token-plugin.js +88 -0
  336. package/src/standalone.js +24 -0
  337. package/src/start-app-server.js +38 -0
  338. package/test/combined/app-redirect.test.js +199 -0
  339. package/test/combined/helpers/credentialagent-build-fastify.js +29 -0
  340. package/test/combined/helpers/index.js +22 -0
  341. package/test/combined/helpers/nock-registrar-app-schema-name.js +50 -0
  342. package/test/combined/helpers/nock-registrar-get-organization-diddoc.js +26 -0
  343. package/test/combined/helpers/nock-registrar-get-organization-verified-profile.js +33 -0
  344. package/test/combined/manifest.json.test.js +55 -0
  345. package/test/combined/root-controller.test.js +42 -0
  346. package/test/combined/schemas/education-degree.schema.json +166 -0
  347. package/test/combined/schemas/employment-current-v1.1.schema.json +253 -0
  348. package/test/combined/schemas/open-badge-credential.schema.json +1285 -0
  349. package/test/combined/schemas/past-employment-position-with-uri-id.schema.js +22 -0
  350. package/test/combined/schemas/past-employment-position.schema.json +148 -0
  351. package/test/combined/schemas/will-always-validate.json +10 -0
  352. package/test/combined/validate-cao-plugin.test.js +155 -0
  353. package/test/get-push-delegate.test.js +54 -0
  354. package/test/helpers/jwt-vc-expectation.js +109 -0
  355. package/test/holder/build-request-response-schema.test.js +55 -0
  356. package/test/holder/credential-manifest-controller.test.js +3192 -0
  357. package/test/holder/e2e-issuing-controller.test.js +425 -0
  358. package/test/holder/get-exchange-progress-controller.test.js +521 -0
  359. package/test/holder/get-presentation-request.test.js +906 -0
  360. package/test/holder/helpers/credential-type-metadata.js +98 -0
  361. package/test/holder/helpers/credentialagent-holder-build-fastify.js +32 -0
  362. package/test/holder/helpers/generate-presentation.js +441 -0
  363. package/test/holder/helpers/generate-test-access-token.js +54 -0
  364. package/test/holder/helpers/jwt-access-token-expectation.js +32 -0
  365. package/test/holder/helpers/jwt-vc-expectation.js +115 -0
  366. package/test/holder/issuing-controller.test.js +7076 -0
  367. package/test/holder/oauth-token-controller.test.js +412 -0
  368. package/test/holder/presentation-submission.test.js +2365 -0
  369. package/test/holder/submit-identification.test.js +4815 -0
  370. package/test/operator/check-credentials-controller-v0.8.test.js +832 -0
  371. package/test/operator/credentials-revoke.test.js +536 -0
  372. package/test/operator/disclosures-controller-v0.8.test.js +4157 -0
  373. package/test/operator/exchanges-controller-v0.8.test.js +414 -0
  374. package/test/operator/exchanges-id-controller-v0.8.test.js +162 -0
  375. package/test/operator/feeds-controller-v0.8.test.js +659 -0
  376. package/test/operator/generate-push-gateway-token.test.js +116 -0
  377. package/test/operator/groups-controller.test.js +145 -0
  378. package/test/operator/groups-id-controller.test.js +287 -0
  379. package/test/operator/helpers/create-test-org-doc.js +60 -0
  380. package/test/operator/helpers/credentialagent-operator-build-fastify.js +32 -0
  381. package/test/operator/helpers/find-kms-key.js +31 -0
  382. package/test/operator/helpers/generate-primary-and-add-operator-to-primary.js +63 -0
  383. package/test/operator/helpers/init-agent-kms.js +22 -0
  384. package/test/operator/issued-credentials-controller-v0.8.test.js +398 -0
  385. package/test/operator/keys-controller-v0.8.test.js +1130 -0
  386. package/test/operator/offer-data-controller-v0.8.test.js +253 -0
  387. package/test/operator/offers-controller-v0.8.test.js +3026 -0
  388. package/test/operator/set-configuration-type-modifier.test.js +75 -0
  389. package/test/operator/swagger.test.js +37 -0
  390. package/test/operator/tenant-controller-v0.8.test.js +730 -0
  391. package/test/operator/tenant-loader-plugin.test.js +96 -0
  392. package/test/operator/tenants-controller-v0.8.test.js +2093 -0
  393. package/test/operator/users-controller-v0.8.test.js +137 -0
  394. package/test/operator/vc-api-credentials.test.js +963 -0
  395. package/verification.env +28 -0
@@ -0,0 +1,3192 @@
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, omit } = require('lodash/fp');
18
+ const { mongoDb } = require('@spencejs/spence-mongo-repos');
19
+ const { ObjectId } = require('mongodb');
20
+ const nock = require('nock');
21
+ const qs = require('qs');
22
+ const { jwtDecode } = require('@verii/jwt');
23
+ const { generateKeyPair } = require('@verii/crypto');
24
+ const {
25
+ sampleOrganizationProfile1,
26
+ sampleOrganizationVerifiedProfile1,
27
+ samplePresentationDefinition,
28
+ } = require('@verii/sample-data');
29
+ const { OBJECT_ID_FORMAT, JWT_FORMAT } = require('@verii/test-regexes');
30
+ const { mongoify, errorResponseMatcher } = require('@verii/tests-helpers');
31
+ const buildFastify = require('./helpers/credentialagent-holder-build-fastify');
32
+ const {
33
+ nockRegistrarGetOrganizationVerifiedProfile,
34
+ } = require('../combined/helpers/nock-registrar-get-organization-verified-profile');
35
+ const {
36
+ initOfferExchangeFactory,
37
+ initTenantFactory,
38
+ initKeysFactory,
39
+ initDisclosureFactory,
40
+ VendorEndpoint,
41
+ ExchangeProtocols,
42
+ ExchangeStates,
43
+ ExchangeTypes,
44
+ } = require('../../src/entities');
45
+ const {
46
+ nockRegistrarGetOrganizationDidDoc,
47
+ } = require('../combined/helpers/nock-registrar-get-organization-diddoc');
48
+ const { holderConfig } = require('../../src/config');
49
+
50
+ describe('get credential manifests', () => {
51
+ let fastify;
52
+ let persistTenant;
53
+ let tenant;
54
+ let persistKey;
55
+ let exchange;
56
+ let persistOfferExchange;
57
+ let persistDisclosure;
58
+ let disclosure;
59
+ let orgDidDoc;
60
+ let keyPair;
61
+
62
+ beforeAll(async () => {
63
+ fastify = buildFastify();
64
+ await fastify.ready();
65
+ ({ persistTenant } = initTenantFactory(fastify));
66
+ ({ persistKey } = initKeysFactory(fastify));
67
+ ({ persistOfferExchange } = initOfferExchangeFactory(fastify));
68
+ ({ persistDisclosure } = initDisclosureFactory(fastify));
69
+ });
70
+
71
+ beforeEach(async () => {
72
+ jest.resetAllMocks();
73
+ nock.cleanAll();
74
+ fastify.resetOverrides();
75
+
76
+ await mongoDb().collection('tenants').deleteMany({});
77
+ await mongoDb().collection('keys').deleteMany({});
78
+ await mongoDb().collection('disclosures').deleteMany({});
79
+ await mongoDb().collection('exchanges').deleteMany({});
80
+
81
+ tenant = await persistTenant();
82
+ const { publicKey } = generateKeyPair();
83
+ orgDidDoc = {
84
+ id: tenant.did,
85
+ publicKey: [{ id: `${tenant.did}#key-1`, publicKeyHex: publicKey }],
86
+ service: [
87
+ {
88
+ id: `${tenant.did}#service-1`,
89
+ type: 'BasicProfileInformation',
90
+ ...sampleOrganizationProfile1,
91
+ },
92
+ ],
93
+ };
94
+
95
+ nockRegistrarGetOrganizationDidDoc(orgDidDoc.id, orgDidDoc);
96
+ keyPair = generateKeyPair({ format: 'jwk' });
97
+ await persistKey({
98
+ tenant,
99
+ kidFragment: '#ID2',
100
+ keyPair,
101
+ });
102
+
103
+ disclosure = await persistDisclosure({
104
+ tenant,
105
+ description: 'Credential Issuance disclosure',
106
+ types: [{ type: 'EmailV1.0' }],
107
+ vendorEndpoint: VendorEndpoint.ISSUING_IDENTIFICATION,
108
+ purpose: 'Identification',
109
+ duration: '6y',
110
+ });
111
+ exchange = await persistOfferExchange({ tenant, disclosure });
112
+
113
+ nockRegistrarGetOrganizationDidDoc(orgDidDoc.id, orgDidDoc);
114
+ });
115
+
116
+ afterAll(async () => {
117
+ nock.cleanAll();
118
+ nock.restore();
119
+ await fastify.close();
120
+ });
121
+
122
+ const agentUrl = 'http://localhost.test';
123
+ const tenantUrl = ({ tenantId, queryParams }, suffix) => {
124
+ const baseUrl = `/api/holder/v0.6/org/${tenantId}${suffix}`;
125
+ if (isEmpty(queryParams)) {
126
+ return baseUrl;
127
+ }
128
+ const queryString = qs.stringify(queryParams, { indices: false });
129
+ return `${baseUrl}?${queryString}`;
130
+ };
131
+
132
+ const issuingUrl = (tenantId, suffix = '', queryParams) =>
133
+ tenantUrl({ tenantId, queryParams }, `/issue${suffix}`);
134
+
135
+ describe('get-credential-manifest', () => {
136
+ it('should 404 when disclosureId cant be found', async () => {
137
+ const tenant2 = await persistTenant({
138
+ kid: 'ID3',
139
+ key: 'KEY3',
140
+ });
141
+
142
+ const response = await fastify.injectJson({
143
+ method: 'GET',
144
+ url: issuingUrl(tenant2.did, '/get-credential-manifest', {
145
+ credential_types: 'PastEmploymentPosition',
146
+ }),
147
+ });
148
+
149
+ expect(response.statusCode).toEqual(404);
150
+ });
151
+
152
+ it('should 404 when an exchangeId contains a unknown disclosureId', async () => {
153
+ const customExchange = await persistOfferExchange({
154
+ tenant,
155
+ disclosure: { _id: new ObjectId() },
156
+ });
157
+
158
+ const response = await fastify.injectJson({
159
+ method: 'GET',
160
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
161
+ exchange_id: customExchange._id,
162
+ credential_types: ['PastEmploymentPosition'],
163
+ }),
164
+ });
165
+
166
+ expect(response.statusCode).toEqual(404);
167
+ });
168
+
169
+ it('should 500 if tenant doesnt have a private key defined', async () => {
170
+ const nonDidTenant = await persistTenant();
171
+ const nonDisclosure = await persistDisclosure({
172
+ tenant: nonDidTenant,
173
+ description: 'Credential Issuance disclosure',
174
+ types: [{ type: 'EmailV1.0' }],
175
+ vendorEndpoint: VendorEndpoint.ISSUING_IDENTIFICATION,
176
+ purpose: 'Identification',
177
+ duration: '6y',
178
+ });
179
+
180
+ nockRegistrarGetOrganizationDidDoc(nonDidTenant.did, orgDidDoc);
181
+ nockRegistrarGetOrganizationVerifiedProfile(
182
+ nonDidTenant.did,
183
+ sampleOrganizationVerifiedProfile1
184
+ );
185
+
186
+ nock('http://oracle.localhost.test')
187
+ .get(
188
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
189
+ )
190
+ .reply(200, {
191
+ id: 'EmailV1.0',
192
+ name: 'Email',
193
+ schema: [
194
+ {
195
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
196
+ },
197
+ ],
198
+ display: {
199
+ title: {
200
+ path: '$.email',
201
+ },
202
+ },
203
+ });
204
+ nock('http://oracle.localhost.test')
205
+ .get(
206
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
207
+ )
208
+ .reply(200, {
209
+ id: 'PastEmploymentPosition',
210
+ name: 'Past Role',
211
+ schema: [
212
+ {
213
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
214
+ },
215
+ ],
216
+ display: {
217
+ title: {
218
+ path: '$.employment',
219
+ },
220
+ },
221
+ });
222
+ nock('http://oracle.localhost.test')
223
+ .get(
224
+ '/api/v0.6/credential-type-descriptors/CurrentEmploymentPosition?includeDisplay=true'
225
+ )
226
+ .reply(200, {
227
+ id: 'CurrentEmploymentPosition',
228
+ name: 'Current Role',
229
+ schema: [
230
+ {
231
+ uri: 'http://oracle.localhost.test/schemas/CurrentEmploymentPosition.json',
232
+ },
233
+ ],
234
+ display: {
235
+ title: {
236
+ path: '$.current',
237
+ },
238
+ },
239
+ });
240
+
241
+ const response = await fastify.injectJson({
242
+ method: 'GET',
243
+ url: issuingUrl(nonDidTenant.did, '/get-credential-manifest', {
244
+ credential_types: [
245
+ 'PastEmploymentPosition',
246
+ 'CurrentEmploymentPosition',
247
+ ],
248
+ }),
249
+ });
250
+ expect(response.statusCode).toEqual(500);
251
+ expect(response.json).toEqual(
252
+ errorResponseMatcher({
253
+ error: 'Internal Server Error',
254
+ errorCode: 'tenant_exchanges_key_missing',
255
+ message: `No key matching the filter {"tenantId":"${nonDidTenant._id.toString()}","purposes":"EXCHANGES"} was found`,
256
+ statusCode: 500,
257
+ })
258
+ );
259
+
260
+ const dbExchange = await mongoDb()
261
+ .collection('exchanges')
262
+ .findOne({ tenantId: new ObjectId(nonDidTenant._id) });
263
+ expect(dbExchange).toEqual({
264
+ _id: expect.any(ObjectId),
265
+ type: ExchangeTypes.ISSUING,
266
+ credentialTypes: [
267
+ 'PastEmploymentPosition',
268
+ 'CurrentEmploymentPosition',
269
+ ],
270
+ disclosureId: new ObjectId(nonDisclosure._id),
271
+ events: [
272
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
273
+ {
274
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
275
+ timestamp: expect.any(Date),
276
+ },
277
+
278
+ {
279
+ state: ExchangeStates.UNEXPECTED_ERROR,
280
+ timestamp: expect.any(Date),
281
+ },
282
+ ],
283
+ protocolMetadata: {
284
+ protocol: ExchangeProtocols.VNF_API,
285
+ },
286
+ err: `No key matching the filter {"tenantId":"${nonDidTenant._id}","purposes":"EXCHANGES"} was found`,
287
+ tenantId: new ObjectId(nonDidTenant._id),
288
+ createdAt: expect.any(Date),
289
+ updatedAt: expect.any(Date),
290
+ });
291
+ });
292
+
293
+ it('should 500 when the credential type descriptor retrieval fails', async () => {
294
+ nockRegistrarGetOrganizationVerifiedProfile(
295
+ tenant.did,
296
+ sampleOrganizationVerifiedProfile1
297
+ );
298
+
299
+ nock('http://oracle.localhost.test')
300
+ .get(
301
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
302
+ )
303
+ .reply(200, {
304
+ id: 'EmailV1.0',
305
+ name: 'Email',
306
+ schema: [
307
+ {
308
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
309
+ },
310
+ ],
311
+ display: {
312
+ title: {
313
+ path: '$.email',
314
+ },
315
+ },
316
+ });
317
+ nock('http://oracle.localhost.test')
318
+ .get(
319
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
320
+ )
321
+ .reply(403, {});
322
+
323
+ const response = await fastify.injectJson({
324
+ method: 'GET',
325
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
326
+ credential_types: ['PastEmploymentPosition'],
327
+ exchange_id: exchange._id,
328
+ }),
329
+ });
330
+ expect(response.statusCode).toEqual(502);
331
+
332
+ const dbExchange = await mongoDb()
333
+ .collection('exchanges')
334
+ .findOne({ tenantId: new ObjectId(tenant._id) });
335
+ expect(dbExchange).toEqual({
336
+ _id: expect.any(ObjectId),
337
+ type: ExchangeTypes.ISSUING,
338
+ credentialTypes: ['PastEmploymentPosition'],
339
+ disclosureId: new ObjectId(disclosure._id),
340
+ protocolMetadata: {
341
+ protocol: ExchangeProtocols.VNF_API,
342
+ },
343
+ events: [
344
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
345
+ {
346
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
347
+ timestamp: expect.any(Date),
348
+ },
349
+ {
350
+ state: ExchangeStates.UNEXPECTED_ERROR,
351
+ timestamp: expect.any(Date),
352
+ },
353
+ ],
354
+ offerHashes: [],
355
+ err: 'Response code 403 (Forbidden)',
356
+ tenantId: new ObjectId(tenant._id),
357
+ createdAt: expect.any(Date),
358
+ updatedAt: expect.any(Date),
359
+ });
360
+ });
361
+
362
+ it('should 400 when exchange is already completed', async () => {
363
+ const customExchange = await persistOfferExchange({
364
+ tenant,
365
+ disclosure,
366
+ events: [
367
+ { state: ExchangeStates.NEW, timestamp: new Date() },
368
+ {
369
+ state: ExchangeStates.COMPLETE,
370
+ timestamp: new Date(),
371
+ },
372
+ {
373
+ state: ExchangeStates.OFFERS_SENT,
374
+ timestamp: new Date(),
375
+ },
376
+ ],
377
+ });
378
+
379
+ const response = await fastify.injectJson({
380
+ method: 'GET',
381
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
382
+ exchange_id: customExchange._id,
383
+ credential_types: ['PastEmploymentPosition'],
384
+ }),
385
+ });
386
+
387
+ expect(response.statusCode).toEqual(400);
388
+ const dbExchange = await mongoDb()
389
+ .collection('exchanges')
390
+ .findOne({ _id: new ObjectId(customExchange._id) });
391
+ expect(dbExchange).toEqual({
392
+ _id: expect.any(ObjectId),
393
+ type: ExchangeTypes.ISSUING,
394
+ credentialTypes: ['PastEmploymentPosition'],
395
+ disclosureId: new ObjectId(disclosure._id),
396
+ events: [
397
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
398
+ {
399
+ state: ExchangeStates.COMPLETE,
400
+ timestamp: expect.any(Date),
401
+ },
402
+ {
403
+ state: ExchangeStates.OFFERS_SENT,
404
+ timestamp: expect.any(Date),
405
+ },
406
+ {
407
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
408
+ timestamp: expect.any(Date),
409
+ },
410
+ {
411
+ state: ExchangeStates.UNEXPECTED_ERROR,
412
+ timestamp: expect.any(Date),
413
+ },
414
+ ],
415
+ protocolMetadata: {
416
+ protocol: ExchangeProtocols.VNF_API,
417
+ },
418
+ offerHashes: [],
419
+ err: expect.any(String),
420
+ tenantId: new ObjectId(tenant._id),
421
+ createdAt: expect.any(Date),
422
+ updatedAt: expect.any(Date),
423
+ });
424
+ });
425
+
426
+ it('should 400 when disclosure deactivated', async () => {
427
+ fastify.overrides.reqConfig = (config) => ({
428
+ ...config,
429
+ enableDeactivatedDisclosure: true,
430
+ });
431
+
432
+ const customDisclosure = await persistDisclosure({
433
+ tenant,
434
+ deactivationDate: '2000-12-01T00:00:00.000Z',
435
+ });
436
+ const customExchange = await persistOfferExchange({
437
+ tenant,
438
+ disclosure: customDisclosure,
439
+ events: [{ state: ExchangeStates.NEW, timestamp: new Date() }],
440
+ });
441
+
442
+ const response = await fastify.injectJson({
443
+ method: 'GET',
444
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
445
+ exchange_id: customExchange._id,
446
+ id: customDisclosure._id,
447
+ credential_types: ['PastEmploymentPosition'],
448
+ }),
449
+ });
450
+
451
+ expect(response.statusCode).toEqual(400);
452
+ expect(response.json).toEqual(
453
+ errorResponseMatcher({
454
+ error: 'Bad Request',
455
+ errorCode: 'disclosure_not_active',
456
+ message: 'Disclosure is not active',
457
+ statusCode: 400,
458
+ })
459
+ );
460
+ });
461
+
462
+ it('should 400 when default issuing disclosure deactivated', async () => {
463
+ fastify.overrides.reqConfig = (config) => ({
464
+ ...config,
465
+ enableDeactivatedDisclosure: true,
466
+ });
467
+
468
+ const customDisclosure = await persistDisclosure({
469
+ tenant,
470
+ deactivationDate: '2000-12-01T00:00:00.000Z',
471
+ });
472
+ await mongoDb()
473
+ .collection('tenants')
474
+ .updateOne(
475
+ {
476
+ _id: new ObjectId(tenant._id),
477
+ },
478
+ {
479
+ $set: {
480
+ defaultIssuingDisclosureId: new ObjectId(customDisclosure._id),
481
+ },
482
+ }
483
+ );
484
+
485
+ const response = await fastify.injectJson({
486
+ method: 'GET',
487
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
488
+ credential_types: ['PastEmploymentPosition'],
489
+ }),
490
+ });
491
+
492
+ expect(response.statusCode).toEqual(400);
493
+ expect(response.json).toEqual(
494
+ errorResponseMatcher({
495
+ error: 'Bad Request',
496
+ errorCode: 'disclosure_not_active',
497
+ message: 'Disclosure is not active',
498
+ statusCode: 400,
499
+ })
500
+ );
501
+ });
502
+
503
+ it('should 404 when a bad exchangeId is passed', async () => {
504
+ const response = await fastify.injectJson({
505
+ method: 'GET',
506
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
507
+ exchange_id: 'no-exchange-id',
508
+ credential_types: [
509
+ 'PastEmploymentPosition',
510
+ 'CurrentEmploymentPosition',
511
+ ],
512
+ }),
513
+ });
514
+
515
+ expect(response.statusCode).toEqual(404);
516
+ expect(response.json).toEqual(
517
+ errorResponseMatcher({
518
+ error: 'Not Found',
519
+ errorCode: 'exchange_not_found',
520
+ message: 'Exchange no-exchange-id not found',
521
+ statusCode: 404,
522
+ })
523
+ );
524
+ });
525
+
526
+ it('should 200, when types provided but no exchangeId, no disclosureId', async () => {
527
+ nockRegistrarGetOrganizationVerifiedProfile(
528
+ tenant.did,
529
+ sampleOrganizationVerifiedProfile1
530
+ );
531
+ nock('http://oracle.localhost.test')
532
+ .get(
533
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
534
+ )
535
+ .reply(200, {
536
+ id: 'EmailV1.0',
537
+ name: 'Email',
538
+ schema: [
539
+ {
540
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
541
+ },
542
+ ],
543
+ });
544
+ nock('http://oracle.localhost.test')
545
+ .get(
546
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
547
+ )
548
+ .reply(200, {
549
+ id: 'PastEmploymentPosition',
550
+ name: 'Past Role',
551
+ schema: [
552
+ {
553
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
554
+ },
555
+ ],
556
+ display: {
557
+ title: {
558
+ path: '$.employment',
559
+ },
560
+ },
561
+ });
562
+ nock('http://oracle.localhost.test')
563
+ .get(
564
+ '/api/v0.6/credential-type-descriptors/CurrentEmploymentPosition?includeDisplay=true'
565
+ )
566
+ .reply(200, {
567
+ id: 'CurrentEmploymentPosition',
568
+ name: 'Current Role',
569
+ schema: [
570
+ {
571
+ uri: 'http://oracle.localhost.test/schemas/CurrentEmploymentPosition.json',
572
+ },
573
+ ],
574
+ display: {
575
+ title: {
576
+ path: '$.current',
577
+ },
578
+ },
579
+ });
580
+
581
+ const response = await fastify.injectJson({
582
+ method: 'GET',
583
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
584
+ credential_types: [
585
+ 'PastEmploymentPosition',
586
+ 'CurrentEmploymentPosition',
587
+ ],
588
+ }),
589
+ });
590
+
591
+ expect(response.statusCode).toEqual(200);
592
+ expect(response.json).toEqual({
593
+ issuing_request: expect.any(String),
594
+ });
595
+ const { payload } = jwtDecode(response.json.issuing_request);
596
+ expect(payload).toEqual({
597
+ exchange_id: expect.stringMatching(OBJECT_ID_FORMAT),
598
+ output_descriptors: [
599
+ {
600
+ id: 'PastEmploymentPosition',
601
+ name: 'Past Role',
602
+ schema: [
603
+ {
604
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
605
+ },
606
+ ],
607
+ display: {
608
+ title: {
609
+ path: '$.employment',
610
+ },
611
+ },
612
+ },
613
+ {
614
+ id: 'CurrentEmploymentPosition',
615
+ name: 'Current Role',
616
+ schema: [
617
+ {
618
+ uri: 'http://oracle.localhost.test/schemas/CurrentEmploymentPosition.json',
619
+ },
620
+ ],
621
+ display: {
622
+ title: {
623
+ path: '$.current',
624
+ },
625
+ },
626
+ },
627
+ ],
628
+ issuer: {
629
+ id: tenant.did,
630
+ },
631
+ presentation_definition: {
632
+ id: `${payload.exchange_id}.${disclosure._id}`,
633
+ name: disclosure.description,
634
+ purpose: 'Identification',
635
+ format: { jwt_vp: { alg: ['secp256k1'] } },
636
+ input_descriptors: [
637
+ {
638
+ id: 'EmailV1.0',
639
+ name: 'Email',
640
+ group: ['A'],
641
+ schema: [
642
+ {
643
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
644
+ },
645
+ ],
646
+ },
647
+ ],
648
+ submission_requirements: [
649
+ {
650
+ rule: 'all',
651
+ from: 'A',
652
+ min: 1,
653
+ },
654
+ ],
655
+ },
656
+ metadata: {
657
+ client_name: sampleOrganizationProfile1.name,
658
+ logo_uri: sampleOrganizationProfile1.logo,
659
+ tos_uri: disclosure.termsUrl,
660
+ auth_token_uri: `${agentUrl}${tenantUrl(
661
+ { tenantId: tenant.did },
662
+ '/oauth/token'
663
+ )}`,
664
+ max_retention_period: disclosure.duration,
665
+ progress_uri: `${agentUrl}${tenantUrl(
666
+ { tenantId: tenant.did },
667
+ '/get-exchange-progress'
668
+ )}`,
669
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
670
+ tenant.did,
671
+ '/submit-identification'
672
+ )}`,
673
+ check_offers_uri: `${agentUrl}${issuingUrl(
674
+ tenant.did,
675
+ '/credential-offers'
676
+ )}`,
677
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
678
+ tenant.did,
679
+ '/finalize-offers'
680
+ )}`,
681
+ },
682
+ iss: tenant.did,
683
+ iat: expect.any(Number),
684
+ exp: expect.any(Number),
685
+ nbf: expect.any(Number),
686
+ });
687
+ const dbExchange = await mongoDb()
688
+ .collection('exchanges')
689
+ .findOne({ _id: new ObjectId(payload.exchange_id) });
690
+ expect(dbExchange).toEqual({
691
+ _id: new ObjectId(payload.exchange_id),
692
+ type: ExchangeTypes.ISSUING,
693
+ tenantId: new ObjectId(tenant._id),
694
+ disclosureId: new ObjectId(disclosure._id),
695
+ events: [
696
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
697
+ {
698
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
699
+ timestamp: expect.any(Date),
700
+ },
701
+ ],
702
+ credentialTypes: [
703
+ 'PastEmploymentPosition',
704
+ 'CurrentEmploymentPosition',
705
+ ],
706
+ protocolMetadata: {
707
+ protocol: ExchangeProtocols.VNF_API,
708
+ },
709
+ createdAt: expect.any(Date),
710
+ updatedAt: expect.any(Date),
711
+ });
712
+ });
713
+
714
+ it('should 200, when a disclosureId, no exchangeId nor types are passed', async () => {
715
+ fastify.overrides.reqConfig = (config) => ({
716
+ ...config,
717
+ enableDeactivatedDisclosure: true,
718
+ });
719
+
720
+ const customDisclosure = await persistDisclosure({
721
+ tenant,
722
+ description: 'Integrated Credential Issuance disclosure',
723
+ types: [{ type: 'EmailV1.0' }],
724
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
725
+ purpose: 'Identification',
726
+ deactivationDate: '2025-12-01T00:00:00.000Z',
727
+ duration: '6y',
728
+ });
729
+ nockRegistrarGetOrganizationVerifiedProfile(
730
+ tenant.did,
731
+ sampleOrganizationVerifiedProfile1
732
+ );
733
+ nock('http://oracle.localhost.test')
734
+ .get(
735
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
736
+ )
737
+ .reply(200, {
738
+ id: 'EmailV1.0',
739
+ name: 'Email',
740
+ schema: [
741
+ {
742
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
743
+ },
744
+ ],
745
+ });
746
+ nock('http://oracle.localhost.test')
747
+ .get(
748
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
749
+ )
750
+ .reply(200, {
751
+ id: 'PastEmploymentPosition',
752
+ name: 'Past Role',
753
+ schema: [
754
+ {
755
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
756
+ },
757
+ ],
758
+ display: {
759
+ title: {
760
+ path: '$.employment',
761
+ },
762
+ },
763
+ });
764
+
765
+ const response = await fastify.injectJson({
766
+ method: 'GET',
767
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
768
+ id: customDisclosure._id,
769
+ credential_types: ['PastEmploymentPosition'],
770
+ }),
771
+ });
772
+ expect(response.statusCode).toEqual(200);
773
+ expect(response.json).toEqual({
774
+ issuing_request: expect.any(String),
775
+ });
776
+ const { payload } = jwtDecode(response.json.issuing_request);
777
+ expect(payload).toEqual({
778
+ exchange_id: expect.any(String),
779
+ output_descriptors: [
780
+ {
781
+ id: 'PastEmploymentPosition',
782
+ name: 'Past Role',
783
+ schema: [
784
+ {
785
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
786
+ },
787
+ ],
788
+ display: {
789
+ title: {
790
+ path: '$.employment',
791
+ },
792
+ },
793
+ },
794
+ ],
795
+ issuer: {
796
+ id: tenant.did,
797
+ },
798
+ presentation_definition: {
799
+ id: `${payload.exchange_id}.${customDisclosure._id}`,
800
+ name: customDisclosure.description,
801
+ purpose: customDisclosure.purpose,
802
+ format: {
803
+ jwt_vp: { alg: ['secp256k1'] },
804
+ },
805
+ input_descriptors: [
806
+ {
807
+ id: 'EmailV1.0',
808
+ name: 'Email',
809
+ group: ['A'],
810
+ schema: [
811
+ {
812
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
813
+ },
814
+ ],
815
+ },
816
+ ],
817
+ submission_requirements: [
818
+ {
819
+ from: 'A',
820
+ min: 1,
821
+ rule: 'all',
822
+ },
823
+ ],
824
+ },
825
+ metadata: {
826
+ client_name: orgDidDoc.service[0].name,
827
+ logo_uri: orgDidDoc.service[0].logo,
828
+ tos_uri: customDisclosure.termsUrl,
829
+ auth_token_uri: `${agentUrl}${tenantUrl(
830
+ { tenantId: tenant.did },
831
+ '/oauth/token'
832
+ )}`,
833
+ max_retention_period: customDisclosure.duration,
834
+ progress_uri: `${agentUrl}${tenantUrl(
835
+ { tenantId: tenant.did },
836
+ '/get-exchange-progress'
837
+ )}`,
838
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
839
+ tenant.did,
840
+ '/submit-identification'
841
+ )}`,
842
+ check_offers_uri: `${agentUrl}${issuingUrl(
843
+ tenant.did,
844
+ '/credential-offers'
845
+ )}`,
846
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
847
+ tenant.did,
848
+ '/finalize-offers'
849
+ )}`,
850
+ },
851
+ iss: tenant.did,
852
+ exp: expect.any(Number),
853
+ iat: expect.any(Number),
854
+ nbf: expect.any(Number),
855
+ });
856
+ const dbExchange = await mongoDb()
857
+ .collection('exchanges')
858
+ .findOne({ disclosureId: new ObjectId(customDisclosure._id) });
859
+ expect(dbExchange).toEqual(
860
+ expect.objectContaining({
861
+ ...mongoify({
862
+ protocolMetadata: {
863
+ protocol: ExchangeProtocols.VNF_API,
864
+ },
865
+ events: expect.arrayContaining([
866
+ {
867
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
868
+ timestamp: expect.any(Date),
869
+ },
870
+ ]),
871
+ tenantId: tenant._id,
872
+ updatedAt: expect.any(Date),
873
+ }),
874
+ })
875
+ );
876
+ });
877
+
878
+ it('should 200, when route has a tenantId', async () => {
879
+ fastify.overrides.reqConfig = (config) => ({
880
+ ...config,
881
+ enableDeactivatedDisclosure: true,
882
+ });
883
+
884
+ const customDisclosure = await persistDisclosure({
885
+ tenant,
886
+ description: 'Integrated Credential Issuance disclosure',
887
+ types: [{ type: 'EmailV1.0' }],
888
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
889
+ purpose: 'Identification',
890
+ deactivationDate: '2025-12-01T00:00:00.000Z',
891
+ duration: '6y',
892
+ });
893
+ nockRegistrarGetOrganizationVerifiedProfile(
894
+ tenant.did,
895
+ sampleOrganizationVerifiedProfile1
896
+ );
897
+ nock('http://oracle.localhost.test')
898
+ .get(
899
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
900
+ )
901
+ .reply(200, {
902
+ id: 'EmailV1.0',
903
+ name: 'Email',
904
+ schema: [
905
+ {
906
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
907
+ },
908
+ ],
909
+ });
910
+ nock('http://oracle.localhost.test')
911
+ .get(
912
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
913
+ )
914
+ .reply(200, {
915
+ id: 'PastEmploymentPosition',
916
+ name: 'Past Role',
917
+ schema: [
918
+ {
919
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
920
+ },
921
+ ],
922
+ display: {
923
+ title: {
924
+ path: '$.employment',
925
+ },
926
+ },
927
+ });
928
+
929
+ const response = await fastify.injectJson({
930
+ method: 'GET',
931
+ url: issuingUrl(tenant._id, '/get-credential-manifest', {
932
+ id: customDisclosure._id,
933
+ credential_types: ['PastEmploymentPosition'],
934
+ }),
935
+ });
936
+ expect(response.statusCode).toEqual(200);
937
+ expect(response.json).toEqual({
938
+ issuing_request: expect.any(String),
939
+ });
940
+ const { payload } = jwtDecode(response.json.issuing_request);
941
+ expect(payload).toEqual({
942
+ exchange_id: expect.any(String),
943
+ output_descriptors: [
944
+ {
945
+ id: 'PastEmploymentPosition',
946
+ name: 'Past Role',
947
+ schema: [
948
+ {
949
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
950
+ },
951
+ ],
952
+ display: {
953
+ title: {
954
+ path: '$.employment',
955
+ },
956
+ },
957
+ },
958
+ ],
959
+ issuer: {
960
+ id: tenant.did,
961
+ },
962
+ presentation_definition: {
963
+ id: `${payload.exchange_id}.${customDisclosure._id}`,
964
+ name: customDisclosure.description,
965
+ purpose: customDisclosure.purpose,
966
+ format: {
967
+ jwt_vp: { alg: ['secp256k1'] },
968
+ },
969
+ input_descriptors: [
970
+ {
971
+ id: 'EmailV1.0',
972
+ name: 'Email',
973
+ group: ['A'],
974
+ schema: [
975
+ {
976
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
977
+ },
978
+ ],
979
+ },
980
+ ],
981
+ submission_requirements: [
982
+ {
983
+ from: 'A',
984
+ min: 1,
985
+ rule: 'all',
986
+ },
987
+ ],
988
+ },
989
+ metadata: {
990
+ client_name: orgDidDoc.service[0].name,
991
+ logo_uri: orgDidDoc.service[0].logo,
992
+ tos_uri: customDisclosure.termsUrl,
993
+ auth_token_uri: `${agentUrl}${tenantUrl(
994
+ { tenantId: tenant.did },
995
+ '/oauth/token'
996
+ )}`,
997
+ max_retention_period: customDisclosure.duration,
998
+ progress_uri: `${agentUrl}${tenantUrl(
999
+ { tenantId: tenant.did },
1000
+ '/get-exchange-progress'
1001
+ )}`,
1002
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
1003
+ tenant.did,
1004
+ '/submit-identification'
1005
+ )}`,
1006
+ check_offers_uri: `${agentUrl}${issuingUrl(
1007
+ tenant.did,
1008
+ '/credential-offers'
1009
+ )}`,
1010
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
1011
+ tenant.did,
1012
+ '/finalize-offers'
1013
+ )}`,
1014
+ },
1015
+ iss: tenant.did,
1016
+ exp: expect.any(Number),
1017
+ iat: expect.any(Number),
1018
+ nbf: expect.any(Number),
1019
+ });
1020
+ const dbExchange = await mongoDb()
1021
+ .collection('exchanges')
1022
+ .findOne({ disclosureId: new ObjectId(customDisclosure._id) });
1023
+ expect(dbExchange).toEqual(
1024
+ expect.objectContaining({
1025
+ ...mongoify({
1026
+ protocolMetadata: {
1027
+ protocol: ExchangeProtocols.VNF_API,
1028
+ },
1029
+ events: expect.arrayContaining([
1030
+ {
1031
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
1032
+ timestamp: expect.any(Date),
1033
+ },
1034
+ ]),
1035
+ tenantId: tenant._id,
1036
+ updatedAt: expect.any(Date),
1037
+ }),
1038
+ })
1039
+ );
1040
+ });
1041
+
1042
+ it("should 200, when route has a tenant's did alias", async () => {
1043
+ const didAlias = 'did:aka:foo';
1044
+ const customTenant = await persistTenant({ dids: [didAlias] });
1045
+ const { publicKey } = generateKeyPair();
1046
+ const customOrgDidDoc = {
1047
+ id: customTenant.did,
1048
+ publicKey: [
1049
+ { id: `${customTenant.did}#key-1`, publicKeyHex: publicKey },
1050
+ ],
1051
+ service: [
1052
+ {
1053
+ id: `${customTenant.did}#service-1`,
1054
+ type: 'BasicProfileInformation',
1055
+ ...sampleOrganizationProfile1,
1056
+ },
1057
+ ],
1058
+ };
1059
+
1060
+ nockRegistrarGetOrganizationDidDoc(customOrgDidDoc.id, customOrgDidDoc);
1061
+
1062
+ await persistKey({
1063
+ tenant: customTenant,
1064
+ kidFragment: '#ID2',
1065
+ keyPair,
1066
+ });
1067
+
1068
+ const customDisclosure = await persistDisclosure({
1069
+ tenant: customTenant,
1070
+ description: 'Integrated Credential Issuance disclosure',
1071
+ types: [{ type: 'EmailV1.0' }],
1072
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
1073
+ purpose: 'Identification',
1074
+ duration: '6y',
1075
+ });
1076
+ nockRegistrarGetOrganizationVerifiedProfile(
1077
+ customTenant.did,
1078
+ sampleOrganizationVerifiedProfile1
1079
+ );
1080
+ nock('http://oracle.localhost.test')
1081
+ .get(
1082
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
1083
+ )
1084
+ .reply(200, {
1085
+ id: 'EmailV1.0',
1086
+ name: 'Email',
1087
+ schema: [
1088
+ {
1089
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1090
+ },
1091
+ ],
1092
+ });
1093
+
1094
+ const response = await fastify.injectJson({
1095
+ method: 'GET',
1096
+ url: issuingUrl(didAlias, '/get-credential-manifest'),
1097
+ });
1098
+ expect(response.statusCode).toEqual(200);
1099
+ expect(response.json).toEqual({
1100
+ issuing_request: expect.any(String),
1101
+ });
1102
+ const { payload } = jwtDecode(response.json.issuing_request);
1103
+ expect(payload).toEqual({
1104
+ exchange_id: expect.any(String),
1105
+ output_descriptors: [],
1106
+ issuer: {
1107
+ id: customTenant.did,
1108
+ },
1109
+ presentation_definition: {
1110
+ id: `${payload.exchange_id}.${customDisclosure._id}`,
1111
+ name: customDisclosure.description,
1112
+ purpose: customDisclosure.purpose,
1113
+ format: {
1114
+ jwt_vp: { alg: ['secp256k1'] },
1115
+ },
1116
+ input_descriptors: [
1117
+ {
1118
+ id: 'EmailV1.0',
1119
+ name: 'Email',
1120
+ group: ['A'],
1121
+ schema: [
1122
+ {
1123
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1124
+ },
1125
+ ],
1126
+ },
1127
+ ],
1128
+ submission_requirements: [
1129
+ {
1130
+ from: 'A',
1131
+ min: 1,
1132
+ rule: 'all',
1133
+ },
1134
+ ],
1135
+ },
1136
+ metadata: {
1137
+ client_name: orgDidDoc.service[0].name,
1138
+ logo_uri: orgDidDoc.service[0].logo,
1139
+ tos_uri: customDisclosure.termsUrl,
1140
+ auth_token_uri: `${agentUrl}${tenantUrl(
1141
+ { tenantId: customTenant.did },
1142
+ '/oauth/token'
1143
+ )}`,
1144
+ max_retention_period: customDisclosure.duration,
1145
+ progress_uri: `${agentUrl}${tenantUrl(
1146
+ { tenantId: customTenant.did },
1147
+ '/get-exchange-progress'
1148
+ )}`,
1149
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
1150
+ customTenant.did,
1151
+ '/submit-identification'
1152
+ )}`,
1153
+ check_offers_uri: `${agentUrl}${issuingUrl(
1154
+ customTenant.did,
1155
+ '/credential-offers'
1156
+ )}`,
1157
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
1158
+ customTenant.did,
1159
+ '/finalize-offers'
1160
+ )}`,
1161
+ },
1162
+ iss: customTenant.did,
1163
+ exp: expect.any(Number),
1164
+ iat: expect.any(Number),
1165
+ nbf: expect.any(Number),
1166
+ });
1167
+ const dbExchange = await mongoDb()
1168
+ .collection('exchanges')
1169
+ .findOne({ disclosureId: new ObjectId(customDisclosure._id) });
1170
+ expect(dbExchange).toEqual(
1171
+ expect.objectContaining({
1172
+ ...mongoify({
1173
+ protocolMetadata: {
1174
+ protocol: ExchangeProtocols.VNF_API,
1175
+ },
1176
+ events: expect.arrayContaining([
1177
+ {
1178
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
1179
+ timestamp: expect.any(Date),
1180
+ },
1181
+ ]),
1182
+ tenantId: customTenant._id,
1183
+ updatedAt: expect.any(Date),
1184
+ }),
1185
+ })
1186
+ );
1187
+ });
1188
+
1189
+ it('should 200, when disclosureId is passed and disclosure has a presentationDefinition without purpose', async () => {
1190
+ fastify.overrides.reqConfig = (config) => ({
1191
+ ...config,
1192
+ enableDeactivatedDisclosure: true,
1193
+ });
1194
+
1195
+ const customDisclosure = await persistDisclosure({
1196
+ tenant,
1197
+ description: 'Integrated Credential Issuance disclosure',
1198
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
1199
+ purpose: 'fooPurpose from disclosure',
1200
+ deactivationDate: '2025-12-01T00:00:00.000Z',
1201
+ duration: '6y',
1202
+ presentationDefinition: omit(['purpose'], samplePresentationDefinition),
1203
+ });
1204
+ nockRegistrarGetOrganizationVerifiedProfile(
1205
+ tenant.did,
1206
+ sampleOrganizationVerifiedProfile1
1207
+ );
1208
+ nock('http://oracle.localhost.test')
1209
+ .get(
1210
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
1211
+ )
1212
+ .reply(200, {
1213
+ id: 'EmailV1.0',
1214
+ name: 'Email',
1215
+ schema: [
1216
+ {
1217
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1218
+ },
1219
+ ],
1220
+ });
1221
+ nock('http://oracle.localhost.test')
1222
+ .get(
1223
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
1224
+ )
1225
+ .reply(200, {
1226
+ id: 'PastEmploymentPosition',
1227
+ name: 'Past Role',
1228
+ schema: [
1229
+ {
1230
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
1231
+ },
1232
+ ],
1233
+ display: {
1234
+ title: {
1235
+ path: '$.employment',
1236
+ },
1237
+ },
1238
+ });
1239
+
1240
+ const response = await fastify.injectJson({
1241
+ method: 'GET',
1242
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
1243
+ id: customDisclosure._id,
1244
+ credential_types: ['PastEmploymentPosition'],
1245
+ }),
1246
+ });
1247
+ expect(response.statusCode).toEqual(200);
1248
+ expect(response.json).toEqual({
1249
+ issuing_request: expect.any(String),
1250
+ });
1251
+ const { payload } = jwtDecode(response.json.issuing_request);
1252
+ expect(payload).toEqual({
1253
+ exchange_id: expect.any(String),
1254
+ output_descriptors: [
1255
+ {
1256
+ id: 'PastEmploymentPosition',
1257
+ name: 'Past Role',
1258
+ schema: [
1259
+ {
1260
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
1261
+ },
1262
+ ],
1263
+ display: {
1264
+ title: {
1265
+ path: '$.employment',
1266
+ },
1267
+ },
1268
+ },
1269
+ ],
1270
+ issuer: {
1271
+ id: tenant.did,
1272
+ },
1273
+ presentation_definition: {
1274
+ id: `${payload.exchange_id}.${customDisclosure._id}`,
1275
+ purpose: 'fooPurpose from disclosure',
1276
+ name: 'fooName',
1277
+ format: {
1278
+ jwt_vp: { alg: ['secp256k1'] },
1279
+ },
1280
+ input_descriptors: [
1281
+ {
1282
+ id: 'CurrentEmployment',
1283
+ name: 'Current Employment',
1284
+ schema: [
1285
+ {
1286
+ uri: 'https://example.com/employment-current-v1.1.schema.json',
1287
+ },
1288
+ ],
1289
+ group: ['A'],
1290
+ },
1291
+ {
1292
+ id: 'PastEmployment',
1293
+ name: 'Past Employment',
1294
+ schema: [
1295
+ {
1296
+ uri: 'https://example.com/employment-past-v1.1.schema.json',
1297
+ },
1298
+ ],
1299
+ group: ['A'],
1300
+ },
1301
+ {
1302
+ id: 'OpenBadge',
1303
+ name: 'Badges',
1304
+ schema: [
1305
+ {
1306
+ uri: 'https://example.com/open-badge-credential.schema.json',
1307
+ },
1308
+ ],
1309
+ group: ['B'],
1310
+ },
1311
+ ],
1312
+ submission_requirements: [
1313
+ {
1314
+ rule: 'all',
1315
+ from: 'A',
1316
+ min: 1,
1317
+ },
1318
+ ],
1319
+ },
1320
+ metadata: {
1321
+ client_name: orgDidDoc.service[0].name,
1322
+ logo_uri: orgDidDoc.service[0].logo,
1323
+ tos_uri: customDisclosure.termsUrl,
1324
+ auth_token_uri: `${agentUrl}${tenantUrl(
1325
+ { tenantId: tenant.did },
1326
+ '/oauth/token'
1327
+ )}`,
1328
+ max_retention_period: customDisclosure.duration,
1329
+ progress_uri: `${agentUrl}${tenantUrl(
1330
+ { tenantId: tenant.did },
1331
+ '/get-exchange-progress'
1332
+ )}`,
1333
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
1334
+ tenant.did,
1335
+ '/submit-identification'
1336
+ )}`,
1337
+ check_offers_uri: `${agentUrl}${issuingUrl(
1338
+ tenant.did,
1339
+ '/credential-offers'
1340
+ )}`,
1341
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
1342
+ tenant.did,
1343
+ '/finalize-offers'
1344
+ )}`,
1345
+ },
1346
+ iss: tenant.did,
1347
+ exp: expect.any(Number),
1348
+ iat: expect.any(Number),
1349
+ nbf: expect.any(Number),
1350
+ });
1351
+ const dbExchange = await mongoDb()
1352
+ .collection('exchanges')
1353
+ .findOne({ disclosureId: new ObjectId(customDisclosure._id) });
1354
+ expect(dbExchange).toEqual(
1355
+ expect.objectContaining({
1356
+ ...mongoify({
1357
+ protocolMetadata: {
1358
+ protocol: ExchangeProtocols.VNF_API,
1359
+ },
1360
+ events: expect.arrayContaining([
1361
+ {
1362
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
1363
+ timestamp: expect.any(Date),
1364
+ },
1365
+ ]),
1366
+ tenantId: tenant._id,
1367
+ updatedAt: expect.any(Date),
1368
+ }),
1369
+ })
1370
+ );
1371
+ });
1372
+
1373
+ it('should 200, when disclosureId is passed and disclosure has a presentationDefinition with purpose', async () => {
1374
+ fastify.overrides.reqConfig = (config) => ({
1375
+ ...config,
1376
+ enableDeactivatedDisclosure: true,
1377
+ });
1378
+
1379
+ const customDisclosure = await persistDisclosure({
1380
+ tenant,
1381
+ description: 'Integrated Credential Issuance disclosure',
1382
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
1383
+ purpose: 'Identification',
1384
+ deactivationDate: '2025-12-01T00:00:00.000Z',
1385
+ duration: '6y',
1386
+ presentationDefinition: {
1387
+ ...samplePresentationDefinition,
1388
+ purpose: 'fooPurpose',
1389
+ },
1390
+ });
1391
+ nockRegistrarGetOrganizationVerifiedProfile(
1392
+ tenant.did,
1393
+ sampleOrganizationVerifiedProfile1
1394
+ );
1395
+ nock('http://oracle.localhost.test')
1396
+ .get(
1397
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
1398
+ )
1399
+ .reply(200, {
1400
+ id: 'EmailV1.0',
1401
+ name: 'Email',
1402
+ schema: [
1403
+ {
1404
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1405
+ },
1406
+ ],
1407
+ });
1408
+ nock('http://oracle.localhost.test')
1409
+ .get(
1410
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
1411
+ )
1412
+ .reply(200, {
1413
+ id: 'PastEmploymentPosition',
1414
+ name: 'Past Role',
1415
+ schema: [
1416
+ {
1417
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
1418
+ },
1419
+ ],
1420
+ display: {
1421
+ title: {
1422
+ path: '$.employment',
1423
+ },
1424
+ },
1425
+ });
1426
+
1427
+ const response = await fastify.injectJson({
1428
+ method: 'GET',
1429
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
1430
+ id: customDisclosure._id,
1431
+ credential_types: ['PastEmploymentPosition'],
1432
+ }),
1433
+ });
1434
+ expect(response.statusCode).toEqual(200);
1435
+ expect(response.json).toEqual({
1436
+ issuing_request: expect.any(String),
1437
+ });
1438
+ const { payload } = jwtDecode(response.json.issuing_request);
1439
+ expect(payload).toEqual({
1440
+ exchange_id: expect.any(String),
1441
+ output_descriptors: [
1442
+ {
1443
+ id: 'PastEmploymentPosition',
1444
+ name: 'Past Role',
1445
+ schema: [
1446
+ {
1447
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
1448
+ },
1449
+ ],
1450
+ display: {
1451
+ title: {
1452
+ path: '$.employment',
1453
+ },
1454
+ },
1455
+ },
1456
+ ],
1457
+ issuer: {
1458
+ id: tenant.did,
1459
+ },
1460
+ presentation_definition: {
1461
+ id: `${payload.exchange_id}.${customDisclosure._id}`,
1462
+ purpose: 'fooPurpose',
1463
+ name: 'fooName',
1464
+ format: {
1465
+ jwt_vp: { alg: ['secp256k1'] },
1466
+ },
1467
+ input_descriptors: [
1468
+ {
1469
+ id: 'CurrentEmployment',
1470
+ name: 'Current Employment',
1471
+ schema: [
1472
+ {
1473
+ uri: 'https://example.com/employment-current-v1.1.schema.json',
1474
+ },
1475
+ ],
1476
+ group: ['A'],
1477
+ },
1478
+ {
1479
+ id: 'PastEmployment',
1480
+ name: 'Past Employment',
1481
+ schema: [
1482
+ {
1483
+ uri: 'https://example.com/employment-past-v1.1.schema.json',
1484
+ },
1485
+ ],
1486
+ group: ['A'],
1487
+ },
1488
+ {
1489
+ id: 'OpenBadge',
1490
+ name: 'Badges',
1491
+ schema: [
1492
+ {
1493
+ uri: 'https://example.com/open-badge-credential.schema.json',
1494
+ },
1495
+ ],
1496
+ group: ['B'],
1497
+ },
1498
+ ],
1499
+ submission_requirements: [
1500
+ {
1501
+ rule: 'all',
1502
+ from: 'A',
1503
+ min: 1,
1504
+ },
1505
+ ],
1506
+ },
1507
+ metadata: {
1508
+ client_name: orgDidDoc.service[0].name,
1509
+ logo_uri: orgDidDoc.service[0].logo,
1510
+ tos_uri: customDisclosure.termsUrl,
1511
+ auth_token_uri: `${agentUrl}${tenantUrl(
1512
+ { tenantId: tenant.did },
1513
+ '/oauth/token'
1514
+ )}`,
1515
+ max_retention_period: customDisclosure.duration,
1516
+ progress_uri: `${agentUrl}${tenantUrl(
1517
+ { tenantId: tenant.did },
1518
+ '/get-exchange-progress'
1519
+ )}`,
1520
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
1521
+ tenant.did,
1522
+ '/submit-identification'
1523
+ )}`,
1524
+ check_offers_uri: `${agentUrl}${issuingUrl(
1525
+ tenant.did,
1526
+ '/credential-offers'
1527
+ )}`,
1528
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
1529
+ tenant.did,
1530
+ '/finalize-offers'
1531
+ )}`,
1532
+ },
1533
+ iss: tenant.did,
1534
+ exp: expect.any(Number),
1535
+ iat: expect.any(Number),
1536
+ nbf: expect.any(Number),
1537
+ });
1538
+ const dbExchange = await mongoDb()
1539
+ .collection('exchanges')
1540
+ .findOne({ disclosureId: new ObjectId(customDisclosure._id) });
1541
+ expect(dbExchange).toEqual(
1542
+ expect.objectContaining({
1543
+ ...mongoify({
1544
+ protocolMetadata: {
1545
+ protocol: ExchangeProtocols.VNF_API,
1546
+ },
1547
+ events: expect.arrayContaining([
1548
+ {
1549
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
1550
+ timestamp: expect.any(Date),
1551
+ },
1552
+ ]),
1553
+ tenantId: tenant._id,
1554
+ updatedAt: expect.any(Date),
1555
+ }),
1556
+ })
1557
+ );
1558
+ });
1559
+
1560
+ it('should 200, when disclosureId and include disclosure commercial entity data in issuing request', async () => {
1561
+ const customDisclosure = await persistDisclosure({
1562
+ tenant,
1563
+ types: [{ type: 'EmailV1.0' }],
1564
+ vendorEndpoint: VendorEndpoint.ISSUING_IDENTIFICATION,
1565
+ purpose: 'Identification',
1566
+ commercialEntityName: 'fooCommercialEntityName',
1567
+ commercialEntityLogo: 'fooCommercialEntityLogo',
1568
+ });
1569
+ nockRegistrarGetOrganizationVerifiedProfile(
1570
+ tenant.did,
1571
+ sampleOrganizationVerifiedProfile1
1572
+ );
1573
+ nock('http://oracle.localhost.test')
1574
+ .get(
1575
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
1576
+ )
1577
+ .reply(200, {
1578
+ id: 'EmailV1.0',
1579
+ name: 'Email',
1580
+ schema: [
1581
+ {
1582
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1583
+ },
1584
+ ],
1585
+ });
1586
+
1587
+ const response = await fastify.injectJson({
1588
+ method: 'GET',
1589
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
1590
+ id: customDisclosure._id,
1591
+ }),
1592
+ });
1593
+ expect(response.statusCode).toEqual(200);
1594
+ expect(response.json).toEqual({
1595
+ issuing_request: expect.any(String),
1596
+ });
1597
+ const { payload } = jwtDecode(response.json.issuing_request);
1598
+ expect(payload).toEqual({
1599
+ exchange_id: expect.any(String),
1600
+ output_descriptors: [],
1601
+ issuer: {
1602
+ id: tenant.did,
1603
+ },
1604
+ presentation_definition: {
1605
+ id: `${payload.exchange_id}.${customDisclosure._id}`,
1606
+ name: customDisclosure.description,
1607
+ purpose: customDisclosure.purpose,
1608
+ format: {
1609
+ jwt_vp: { alg: ['secp256k1'] },
1610
+ },
1611
+ input_descriptors: [
1612
+ {
1613
+ id: 'EmailV1.0',
1614
+ name: 'Email',
1615
+ group: ['A'],
1616
+ schema: [
1617
+ {
1618
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1619
+ },
1620
+ ],
1621
+ },
1622
+ ],
1623
+ submission_requirements: [
1624
+ {
1625
+ from: 'A',
1626
+ min: 1,
1627
+ rule: 'all',
1628
+ },
1629
+ ],
1630
+ },
1631
+ metadata: {
1632
+ client_name: 'fooCommercialEntityName',
1633
+ logo_uri: 'fooCommercialEntityLogo',
1634
+ tos_uri: customDisclosure.termsUrl,
1635
+ auth_token_uri: `${agentUrl}${tenantUrl(
1636
+ { tenantId: tenant.did },
1637
+ '/oauth/token'
1638
+ )}`,
1639
+ max_retention_period: customDisclosure.duration,
1640
+ progress_uri: `${agentUrl}${tenantUrl(
1641
+ { tenantId: tenant.did },
1642
+ '/get-exchange-progress'
1643
+ )}`,
1644
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
1645
+ tenant.did,
1646
+ '/submit-identification'
1647
+ )}`,
1648
+ check_offers_uri: `${agentUrl}${issuingUrl(
1649
+ tenant.did,
1650
+ '/credential-offers'
1651
+ )}`,
1652
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
1653
+ tenant.did,
1654
+ '/finalize-offers'
1655
+ )}`,
1656
+ },
1657
+ iss: tenant.did,
1658
+ exp: expect.any(Number),
1659
+ iat: expect.any(Number),
1660
+ nbf: expect.any(Number),
1661
+ });
1662
+ const dbExchange = await mongoDb()
1663
+ .collection('exchanges')
1664
+ .findOne({ disclosureId: new ObjectId(customDisclosure._id) });
1665
+ expect(dbExchange).toEqual(
1666
+ expect.objectContaining({
1667
+ ...mongoify({
1668
+ protocolMetadata: {
1669
+ protocol: ExchangeProtocols.VNF_API,
1670
+ },
1671
+ events: expect.arrayContaining([
1672
+ {
1673
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
1674
+ timestamp: expect.any(Date),
1675
+ },
1676
+ ]),
1677
+ tenantId: tenant._id,
1678
+ updatedAt: expect.any(Date),
1679
+ }),
1680
+ })
1681
+ );
1682
+ });
1683
+
1684
+ it('should 200, when no disclosureId, no exchangeId nor types are passed', async () => {
1685
+ const customTenant = await persistTenant();
1686
+ const { publicKey } = generateKeyPair();
1687
+ const customOrgDidDoc = {
1688
+ id: customTenant.did,
1689
+ publicKey: [
1690
+ { id: `${customTenant.did}#key-1`, publicKeyHex: publicKey },
1691
+ ],
1692
+ service: [
1693
+ {
1694
+ id: `${customTenant.did}#service-1`,
1695
+ type: 'BasicProfileInformation',
1696
+ ...sampleOrganizationProfile1,
1697
+ },
1698
+ ],
1699
+ };
1700
+
1701
+ nockRegistrarGetOrganizationDidDoc(customOrgDidDoc.id, customOrgDidDoc);
1702
+
1703
+ await persistKey({
1704
+ tenant: customTenant,
1705
+ kidFragment: '#ID2',
1706
+ keyPair,
1707
+ });
1708
+
1709
+ const customDisclosure = await persistDisclosure({
1710
+ tenant: customTenant,
1711
+ description: 'Integrated Credential Issuance disclosure',
1712
+ types: [{ type: 'EmailV1.0' }],
1713
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
1714
+ purpose: 'Identification',
1715
+ duration: '6y',
1716
+ });
1717
+ nockRegistrarGetOrganizationVerifiedProfile(
1718
+ customTenant.did,
1719
+ sampleOrganizationVerifiedProfile1
1720
+ );
1721
+ nock('http://oracle.localhost.test')
1722
+ .get(
1723
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
1724
+ )
1725
+ .reply(200, {
1726
+ id: 'EmailV1.0',
1727
+ name: 'Email',
1728
+ schema: [
1729
+ {
1730
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1731
+ },
1732
+ ],
1733
+ });
1734
+
1735
+ const response = await fastify.injectJson({
1736
+ method: 'GET',
1737
+ url: issuingUrl(customTenant.did, '/get-credential-manifest'),
1738
+ });
1739
+ expect(response.statusCode).toEqual(200);
1740
+ expect(response.json).toEqual({
1741
+ issuing_request: expect.any(String),
1742
+ });
1743
+ const { payload } = jwtDecode(response.json.issuing_request);
1744
+ expect(payload).toEqual({
1745
+ exchange_id: expect.any(String),
1746
+ output_descriptors: [],
1747
+ issuer: {
1748
+ id: customTenant.did,
1749
+ },
1750
+ presentation_definition: {
1751
+ id: `${payload.exchange_id}.${customDisclosure._id}`,
1752
+ name: customDisclosure.description,
1753
+ purpose: customDisclosure.purpose,
1754
+ format: {
1755
+ jwt_vp: { alg: ['secp256k1'] },
1756
+ },
1757
+ input_descriptors: [
1758
+ {
1759
+ id: 'EmailV1.0',
1760
+ name: 'Email',
1761
+ group: ['A'],
1762
+ schema: [
1763
+ {
1764
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1765
+ },
1766
+ ],
1767
+ },
1768
+ ],
1769
+ submission_requirements: [
1770
+ {
1771
+ from: 'A',
1772
+ min: 1,
1773
+ rule: 'all',
1774
+ },
1775
+ ],
1776
+ },
1777
+ metadata: {
1778
+ client_name: orgDidDoc.service[0].name,
1779
+ logo_uri: orgDidDoc.service[0].logo,
1780
+ tos_uri: customDisclosure.termsUrl,
1781
+ auth_token_uri: `${agentUrl}${tenantUrl(
1782
+ { tenantId: customTenant.did },
1783
+ '/oauth/token'
1784
+ )}`,
1785
+ max_retention_period: customDisclosure.duration,
1786
+ progress_uri: `${agentUrl}${tenantUrl(
1787
+ { tenantId: customTenant.did },
1788
+ '/get-exchange-progress'
1789
+ )}`,
1790
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
1791
+ customTenant.did,
1792
+ '/submit-identification'
1793
+ )}`,
1794
+ check_offers_uri: `${agentUrl}${issuingUrl(
1795
+ customTenant.did,
1796
+ '/credential-offers'
1797
+ )}`,
1798
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
1799
+ customTenant.did,
1800
+ '/finalize-offers'
1801
+ )}`,
1802
+ },
1803
+ iss: customTenant.did,
1804
+ exp: expect.any(Number),
1805
+ iat: expect.any(Number),
1806
+ nbf: expect.any(Number),
1807
+ });
1808
+ const dbExchange = await mongoDb()
1809
+ .collection('exchanges')
1810
+ .findOne({ disclosureId: new ObjectId(customDisclosure._id) });
1811
+ expect(dbExchange).toEqual(
1812
+ expect.objectContaining({
1813
+ ...mongoify({
1814
+ protocolMetadata: {
1815
+ protocol: ExchangeProtocols.VNF_API,
1816
+ },
1817
+ events: expect.arrayContaining([
1818
+ {
1819
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
1820
+ timestamp: expect.any(Date),
1821
+ },
1822
+ ]),
1823
+ tenantId: customTenant._id,
1824
+ updatedAt: expect.any(Date),
1825
+ }),
1826
+ })
1827
+ );
1828
+ });
1829
+
1830
+ it('should 200, when no exchangeId, no disclosureId, and an unknown credential type', async () => {
1831
+ nockRegistrarGetOrganizationVerifiedProfile(
1832
+ tenant.did,
1833
+ sampleOrganizationVerifiedProfile1
1834
+ );
1835
+ nock('http://oracle.localhost.test')
1836
+ .get(
1837
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
1838
+ )
1839
+ .reply(200, {
1840
+ id: 'EmailV1.0',
1841
+ name: 'Email',
1842
+ schema: [
1843
+ {
1844
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1845
+ },
1846
+ ],
1847
+ });
1848
+ nock('http://oracle.localhost.test')
1849
+ .get(
1850
+ '/api/v0.6/credential-type-descriptors/WhateverType?includeDisplay=true'
1851
+ )
1852
+ .reply(404, {});
1853
+
1854
+ const response = await fastify.injectJson({
1855
+ method: 'GET',
1856
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
1857
+ credential_types: ['WhateverType'],
1858
+ }),
1859
+ });
1860
+
1861
+ expect(response.statusCode).toEqual(200);
1862
+ expect(response.json).toEqual({
1863
+ issuing_request: expect.any(String),
1864
+ });
1865
+ const { payload } = jwtDecode(response.json.issuing_request);
1866
+ expect(payload).toEqual({
1867
+ exchange_id: expect.stringMatching(OBJECT_ID_FORMAT),
1868
+ output_descriptors: [
1869
+ {
1870
+ id: 'WhateverType',
1871
+ name: 'WhateverType',
1872
+ schema: [
1873
+ {
1874
+ uri: 'WhateverType',
1875
+ },
1876
+ ],
1877
+ },
1878
+ ],
1879
+ issuer: {
1880
+ id: tenant.did,
1881
+ },
1882
+ presentation_definition: {
1883
+ id: `${payload.exchange_id}.${disclosure._id}`,
1884
+ name: disclosure.description,
1885
+ purpose: 'Identification',
1886
+ format: { jwt_vp: { alg: ['secp256k1'] } },
1887
+ input_descriptors: [
1888
+ {
1889
+ id: 'EmailV1.0',
1890
+ name: 'Email',
1891
+ group: ['A'],
1892
+ schema: [
1893
+ {
1894
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1895
+ },
1896
+ ],
1897
+ },
1898
+ ],
1899
+ submission_requirements: [
1900
+ {
1901
+ rule: 'all',
1902
+ from: 'A',
1903
+ min: 1,
1904
+ },
1905
+ ],
1906
+ },
1907
+ metadata: {
1908
+ client_name: sampleOrganizationProfile1.name,
1909
+ logo_uri: sampleOrganizationProfile1.logo,
1910
+ tos_uri: disclosure.termsUrl,
1911
+ auth_token_uri: `${agentUrl}${tenantUrl(
1912
+ { tenantId: tenant.did },
1913
+ '/oauth/token'
1914
+ )}`,
1915
+ max_retention_period: disclosure.duration,
1916
+ progress_uri: `${agentUrl}${tenantUrl(
1917
+ { tenantId: tenant.did },
1918
+ '/get-exchange-progress'
1919
+ )}`,
1920
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
1921
+ tenant.did,
1922
+ '/submit-identification'
1923
+ )}`,
1924
+ check_offers_uri: `${agentUrl}${issuingUrl(
1925
+ tenant.did,
1926
+ '/credential-offers'
1927
+ )}`,
1928
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
1929
+ tenant.did,
1930
+ '/finalize-offers'
1931
+ )}`,
1932
+ },
1933
+ iss: tenant.did,
1934
+ iat: expect.any(Number),
1935
+ exp: expect.any(Number),
1936
+ nbf: expect.any(Number),
1937
+ });
1938
+ const dbExchange = await mongoDb()
1939
+ .collection('exchanges')
1940
+ .findOne({ _id: new ObjectId(payload.exchange_id) });
1941
+ expect(dbExchange).toEqual({
1942
+ _id: new ObjectId(payload.exchange_id),
1943
+ type: ExchangeTypes.ISSUING,
1944
+ tenantId: new ObjectId(tenant._id),
1945
+ disclosureId: new ObjectId(disclosure._id),
1946
+ events: [
1947
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
1948
+ {
1949
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
1950
+ timestamp: expect.any(Date),
1951
+ },
1952
+ ],
1953
+ credentialTypes: ['WhateverType'],
1954
+ protocolMetadata: {
1955
+ protocol: ExchangeProtocols.VNF_API,
1956
+ },
1957
+ createdAt: expect.any(Date),
1958
+ updatedAt: expect.any(Date),
1959
+ });
1960
+ });
1961
+
1962
+ it('should 200 when no credential types, exchangeId or disclosureId is provided', async () => {
1963
+ nockRegistrarGetOrganizationVerifiedProfile(
1964
+ tenant.did,
1965
+ sampleOrganizationVerifiedProfile1
1966
+ );
1967
+
1968
+ nock('http://oracle.localhost.test')
1969
+ .get(
1970
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
1971
+ )
1972
+ .reply(200, {
1973
+ id: 'EmailV1.0',
1974
+ name: 'Email',
1975
+ schema: [
1976
+ {
1977
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
1978
+ },
1979
+ ],
1980
+ });
1981
+
1982
+ const response = await fastify.injectJson({
1983
+ method: 'GET',
1984
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {}),
1985
+ });
1986
+
1987
+ expect(response.statusCode).toEqual(200);
1988
+ expect(response.json).toEqual({
1989
+ issuing_request: expect.any(String),
1990
+ });
1991
+ const { payload } = jwtDecode(response.json.issuing_request);
1992
+ expect(payload).toEqual({
1993
+ exchange_id: expect.stringMatching(OBJECT_ID_FORMAT),
1994
+ output_descriptors: [],
1995
+ issuer: {
1996
+ id: tenant.did,
1997
+ },
1998
+ presentation_definition: {
1999
+ id: `${payload.exchange_id}.${disclosure._id}`,
2000
+ name: disclosure.description,
2001
+ purpose: 'Identification',
2002
+ format: { jwt_vp: { alg: ['secp256k1'] } },
2003
+ input_descriptors: [
2004
+ {
2005
+ id: 'EmailV1.0',
2006
+ name: 'Email',
2007
+ group: ['A'],
2008
+ schema: [
2009
+ {
2010
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2011
+ },
2012
+ ],
2013
+ },
2014
+ ],
2015
+ submission_requirements: [
2016
+ {
2017
+ rule: 'all',
2018
+ from: 'A',
2019
+ min: 1,
2020
+ },
2021
+ ],
2022
+ },
2023
+ metadata: {
2024
+ client_name: sampleOrganizationProfile1.name,
2025
+ logo_uri: sampleOrganizationProfile1.logo,
2026
+ tos_uri: disclosure.termsUrl,
2027
+ auth_token_uri: `${agentUrl}${tenantUrl(
2028
+ { tenantId: tenant.did },
2029
+ '/oauth/token'
2030
+ )}`,
2031
+ max_retention_period: disclosure.duration,
2032
+ progress_uri: `${agentUrl}${tenantUrl(
2033
+ { tenantId: tenant.did },
2034
+ '/get-exchange-progress'
2035
+ )}`,
2036
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
2037
+ tenant.did,
2038
+ '/submit-identification'
2039
+ )}`,
2040
+ check_offers_uri: `${agentUrl}${issuingUrl(
2041
+ tenant.did,
2042
+ '/credential-offers'
2043
+ )}`,
2044
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
2045
+ tenant.did,
2046
+ '/finalize-offers'
2047
+ )}`,
2048
+ },
2049
+ iss: tenant.did,
2050
+ iat: expect.any(Number),
2051
+ exp: expect.any(Number),
2052
+ nbf: expect.any(Number),
2053
+ });
2054
+ const dbExchange = await mongoDb()
2055
+ .collection('exchanges')
2056
+ .findOne({ _id: new ObjectId(payload.exchange_id) });
2057
+ expect(dbExchange).toEqual({
2058
+ _id: new ObjectId(payload.exchange_id),
2059
+ type: ExchangeTypes.ISSUING,
2060
+ tenantId: new ObjectId(tenant._id),
2061
+ disclosureId: new ObjectId(disclosure._id),
2062
+ events: [
2063
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
2064
+ {
2065
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
2066
+ timestamp: expect.any(Date),
2067
+ },
2068
+ ],
2069
+ credentialTypes: [],
2070
+ protocolMetadata: {
2071
+ protocol: ExchangeProtocols.VNF_API,
2072
+ },
2073
+ createdAt: expect.any(Date),
2074
+ updatedAt: expect.any(Date),
2075
+ });
2076
+ });
2077
+
2078
+ it('should 200 when an exchangeId and types are provided', async () => {
2079
+ const customDisclosure = await persistDisclosure({
2080
+ tenant,
2081
+ description: 'Integrated Credential Issuance disclosure',
2082
+ types: [{ type: 'EmailV1.0' }],
2083
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
2084
+ purpose: 'Identification',
2085
+ duration: '6y',
2086
+ });
2087
+ const customExchange = await persistOfferExchange({
2088
+ tenant,
2089
+ disclosure: customDisclosure,
2090
+ });
2091
+
2092
+ nockRegistrarGetOrganizationVerifiedProfile(
2093
+ tenant.did,
2094
+ sampleOrganizationVerifiedProfile1
2095
+ );
2096
+ nock('http://oracle.localhost.test')
2097
+ .get(
2098
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
2099
+ )
2100
+ .reply(200, {
2101
+ id: 'EmailV1.0',
2102
+ name: 'Email',
2103
+ schema: [
2104
+ {
2105
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2106
+ },
2107
+ ],
2108
+ });
2109
+ nock('http://oracle.localhost.test')
2110
+ .get(
2111
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
2112
+ )
2113
+ .reply(200, {
2114
+ id: 'PastEmploymentPosition',
2115
+ name: 'Past Role',
2116
+ schema: [
2117
+ {
2118
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2119
+ },
2120
+ ],
2121
+ display: {
2122
+ title: {
2123
+ path: '$.employment',
2124
+ },
2125
+ },
2126
+ });
2127
+
2128
+ const response = await fastify.injectJson({
2129
+ method: 'GET',
2130
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
2131
+ exchange_id: customExchange._id,
2132
+ credential_types: ['PastEmploymentPosition'],
2133
+ }),
2134
+ });
2135
+
2136
+ expect(response.statusCode).toEqual(200);
2137
+ expect(response.json).toEqual({
2138
+ issuing_request: expect.any(String),
2139
+ });
2140
+ const { payload } = jwtDecode(response.json.issuing_request);
2141
+ expect(payload).toEqual({
2142
+ exchange_id: customExchange._id,
2143
+ output_descriptors: [
2144
+ {
2145
+ id: 'PastEmploymentPosition',
2146
+ name: 'Past Role',
2147
+ schema: [
2148
+ {
2149
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2150
+ },
2151
+ ],
2152
+ display: {
2153
+ title: {
2154
+ path: '$.employment',
2155
+ },
2156
+ },
2157
+ },
2158
+ ],
2159
+ issuer: {
2160
+ id: tenant.did,
2161
+ },
2162
+ presentation_definition: {
2163
+ id: `${customExchange._id}.${customDisclosure._id}`,
2164
+ name: customDisclosure.description,
2165
+ purpose: 'Identification',
2166
+ format: { jwt_vp: { alg: ['secp256k1'] } },
2167
+ input_descriptors: [
2168
+ {
2169
+ id: 'EmailV1.0',
2170
+ name: 'Email',
2171
+ group: ['A'],
2172
+ schema: [
2173
+ {
2174
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2175
+ },
2176
+ ],
2177
+ },
2178
+ ],
2179
+ submission_requirements: [
2180
+ {
2181
+ rule: 'all',
2182
+ from: 'A',
2183
+ min: 1,
2184
+ },
2185
+ ],
2186
+ },
2187
+ metadata: {
2188
+ client_name: orgDidDoc.service[0].name,
2189
+ logo_uri: orgDidDoc.service[0].logo,
2190
+ tos_uri: customDisclosure.termsUrl,
2191
+ auth_token_uri: `${agentUrl}${tenantUrl(
2192
+ { tenantId: tenant.did },
2193
+ '/oauth/token'
2194
+ )}`,
2195
+ max_retention_period: customDisclosure.duration,
2196
+ progress_uri: `${agentUrl}${tenantUrl(
2197
+ { tenantId: tenant.did },
2198
+ '/get-exchange-progress'
2199
+ )}`,
2200
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
2201
+ tenant.did,
2202
+ '/submit-identification'
2203
+ )}`,
2204
+ check_offers_uri: `${agentUrl}${issuingUrl(
2205
+ tenant.did,
2206
+ '/credential-offers'
2207
+ )}`,
2208
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
2209
+ tenant.did,
2210
+ '/finalize-offers'
2211
+ )}`,
2212
+ },
2213
+ iss: tenant.did,
2214
+ iat: expect.any(Number),
2215
+ exp: expect.any(Number),
2216
+ nbf: expect.any(Number),
2217
+ });
2218
+
2219
+ const dbExchange = await mongoDb()
2220
+ .collection('exchanges')
2221
+ .findOne({ _id: new ObjectId(customExchange._id) });
2222
+ expect(dbExchange).toEqual({
2223
+ ...mongoify({
2224
+ ...customExchange,
2225
+ protocolMetadata: {
2226
+ protocol: ExchangeProtocols.VNF_API,
2227
+ },
2228
+ events: [
2229
+ ...customExchange.events,
2230
+ {
2231
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
2232
+ timestamp: expect.any(Date),
2233
+ },
2234
+ ],
2235
+ tenantId: tenant._id,
2236
+ updatedAt: expect.any(Date),
2237
+ }),
2238
+ });
2239
+ });
2240
+
2241
+ it('should 200 when exchangeId, types and english locale provided', async () => {
2242
+ const customDisclosure = await persistDisclosure({
2243
+ tenant,
2244
+ description: 'Integrated Credential Issuance disclosure',
2245
+ types: [{ type: 'EmailV1.0' }],
2246
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
2247
+ purpose: 'Identification',
2248
+ duration: '6y',
2249
+ });
2250
+ const customExchange = await persistOfferExchange({
2251
+ tenant,
2252
+ disclosure: customDisclosure,
2253
+ });
2254
+
2255
+ nockRegistrarGetOrganizationVerifiedProfile(
2256
+ tenant.did,
2257
+ sampleOrganizationVerifiedProfile1
2258
+ );
2259
+ nock('http://oracle.localhost.test')
2260
+ .get(
2261
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
2262
+ )
2263
+ .reply(200, {
2264
+ id: 'EmailV1.0',
2265
+ name: 'Email',
2266
+ schema: [
2267
+ {
2268
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2269
+ },
2270
+ ],
2271
+ });
2272
+ nock('http://oracle.localhost.test')
2273
+ .get(
2274
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true&locale=en'
2275
+ )
2276
+ .reply(200, {
2277
+ id: 'PastEmploymentPosition',
2278
+ name: 'Past Role',
2279
+ schema: [
2280
+ {
2281
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2282
+ },
2283
+ ],
2284
+ display: {
2285
+ title: {
2286
+ path: '$.employment',
2287
+ },
2288
+ },
2289
+ });
2290
+
2291
+ const response = await fastify.injectJson({
2292
+ method: 'GET',
2293
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
2294
+ exchange_id: customExchange._id,
2295
+ credential_types: ['PastEmploymentPosition'],
2296
+ locale: 'en',
2297
+ }),
2298
+ });
2299
+
2300
+ expect(response.statusCode).toEqual(200);
2301
+ expect(response.json).toEqual({
2302
+ issuing_request: expect.any(String),
2303
+ });
2304
+ const { payload } = jwtDecode(response.json.issuing_request);
2305
+ expect(payload).toEqual({
2306
+ exchange_id: customExchange._id,
2307
+ output_descriptors: [
2308
+ {
2309
+ id: 'PastEmploymentPosition',
2310
+ name: 'Past Role',
2311
+ schema: [
2312
+ {
2313
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2314
+ },
2315
+ ],
2316
+ display: {
2317
+ title: {
2318
+ path: '$.employment',
2319
+ },
2320
+ },
2321
+ },
2322
+ ],
2323
+ issuer: {
2324
+ id: tenant.did,
2325
+ },
2326
+ presentation_definition: {
2327
+ id: `${customExchange._id}.${customDisclosure._id}`,
2328
+ name: customDisclosure.description,
2329
+ purpose: 'Identification',
2330
+ format: { jwt_vp: { alg: ['secp256k1'] } },
2331
+ input_descriptors: [
2332
+ {
2333
+ id: 'EmailV1.0',
2334
+ name: 'Email',
2335
+ group: ['A'],
2336
+ schema: [
2337
+ {
2338
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2339
+ },
2340
+ ],
2341
+ },
2342
+ ],
2343
+ submission_requirements: [
2344
+ {
2345
+ rule: 'all',
2346
+ from: 'A',
2347
+ min: 1,
2348
+ },
2349
+ ],
2350
+ },
2351
+ metadata: {
2352
+ client_name: orgDidDoc.service[0].name,
2353
+ logo_uri: orgDidDoc.service[0].logo,
2354
+ tos_uri: customDisclosure.termsUrl,
2355
+ auth_token_uri: `${agentUrl}${tenantUrl(
2356
+ { tenantId: tenant.did },
2357
+ '/oauth/token'
2358
+ )}`,
2359
+ max_retention_period: customDisclosure.duration,
2360
+ progress_uri: `${agentUrl}${tenantUrl(
2361
+ { tenantId: tenant.did },
2362
+ '/get-exchange-progress'
2363
+ )}`,
2364
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
2365
+ tenant.did,
2366
+ '/submit-identification'
2367
+ )}`,
2368
+ check_offers_uri: `${agentUrl}${issuingUrl(
2369
+ tenant.did,
2370
+ '/credential-offers'
2371
+ )}`,
2372
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
2373
+ tenant.did,
2374
+ '/finalize-offers'
2375
+ )}`,
2376
+ },
2377
+ iss: tenant.did,
2378
+ iat: expect.any(Number),
2379
+ exp: expect.any(Number),
2380
+ nbf: expect.any(Number),
2381
+ });
2382
+
2383
+ const dbExchange = await mongoDb()
2384
+ .collection('exchanges')
2385
+ .findOne({ _id: new ObjectId(customExchange._id) });
2386
+ expect(dbExchange).toEqual({
2387
+ ...mongoify({
2388
+ ...customExchange,
2389
+ protocolMetadata: {
2390
+ protocol: ExchangeProtocols.VNF_API,
2391
+ },
2392
+ events: [
2393
+ ...customExchange.events,
2394
+ {
2395
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
2396
+ timestamp: expect.any(Date),
2397
+ },
2398
+ ],
2399
+ tenantId: tenant._id,
2400
+ updatedAt: expect.any(Date),
2401
+ }),
2402
+ });
2403
+ });
2404
+
2405
+ it('should 200, when credential type & push_delegate provided', async () => {
2406
+ nockRegistrarGetOrganizationVerifiedProfile(
2407
+ tenant.did,
2408
+ sampleOrganizationVerifiedProfile1
2409
+ );
2410
+
2411
+ const pushDelegate = {
2412
+ pushToken: '123',
2413
+ pushUrl: 'https://serivces.com/push_gateway',
2414
+ };
2415
+
2416
+ nock('http://oracle.localhost.test')
2417
+ .get(
2418
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
2419
+ )
2420
+ .reply(200, {
2421
+ id: 'EmailV1.0',
2422
+ name: 'Email',
2423
+ schema: [
2424
+ {
2425
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2426
+ },
2427
+ ],
2428
+ });
2429
+ nock('http://oracle.localhost.test')
2430
+ .get(
2431
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
2432
+ )
2433
+ .reply(200, {
2434
+ id: 'PastEmploymentPosition',
2435
+ name: 'Past Role',
2436
+ schema: [
2437
+ {
2438
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2439
+ },
2440
+ ],
2441
+ display: {
2442
+ title: {
2443
+ path: '$.employment',
2444
+ },
2445
+ },
2446
+ });
2447
+
2448
+ const response = await fastify.injectJson({
2449
+ method: 'GET',
2450
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
2451
+ credential_types: 'PastEmploymentPosition',
2452
+ 'push_delegate.push_token': pushDelegate.pushToken,
2453
+ 'push_delegate.push_url': pushDelegate.pushUrl,
2454
+ }),
2455
+ });
2456
+
2457
+ expect(response.statusCode).toEqual(200);
2458
+ expect(response.statusCode).toEqual(200);
2459
+ expect(response.json).toEqual({
2460
+ issuing_request: expect.any(String),
2461
+ });
2462
+ const { payload } = jwtDecode(response.json.issuing_request);
2463
+ expect(payload).toEqual({
2464
+ exchange_id: expect.stringMatching(OBJECT_ID_FORMAT),
2465
+ output_descriptors: [
2466
+ {
2467
+ id: 'PastEmploymentPosition',
2468
+ name: 'Past Role',
2469
+ schema: [
2470
+ {
2471
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2472
+ },
2473
+ ],
2474
+ display: {
2475
+ title: {
2476
+ path: '$.employment',
2477
+ },
2478
+ },
2479
+ },
2480
+ ],
2481
+ issuer: {
2482
+ id: tenant.did,
2483
+ },
2484
+ presentation_definition: {
2485
+ id: `${payload.exchange_id}.${disclosure._id}`,
2486
+ name: disclosure.description,
2487
+ purpose: 'Identification',
2488
+ format: { jwt_vp: { alg: ['secp256k1'] } },
2489
+ input_descriptors: [
2490
+ {
2491
+ id: 'EmailV1.0',
2492
+ name: 'Email',
2493
+ group: ['A'],
2494
+ schema: [
2495
+ {
2496
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2497
+ },
2498
+ ],
2499
+ },
2500
+ ],
2501
+ submission_requirements: [
2502
+ {
2503
+ rule: 'all',
2504
+ from: 'A',
2505
+ min: 1,
2506
+ },
2507
+ ],
2508
+ },
2509
+ metadata: {
2510
+ client_name: orgDidDoc.service[0].name,
2511
+ logo_uri: orgDidDoc.service[0].logo,
2512
+ tos_uri: disclosure.termsUrl,
2513
+ auth_token_uri: `${agentUrl}${tenantUrl(
2514
+ { tenantId: tenant.did },
2515
+ '/oauth/token'
2516
+ )}`,
2517
+ max_retention_period: disclosure.duration,
2518
+ progress_uri: `${agentUrl}${tenantUrl(
2519
+ { tenantId: tenant.did },
2520
+ '/get-exchange-progress'
2521
+ )}`,
2522
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
2523
+ tenant.did,
2524
+ '/submit-identification'
2525
+ )}`,
2526
+ check_offers_uri: `${agentUrl}${issuingUrl(
2527
+ tenant.did,
2528
+ '/credential-offers'
2529
+ )}`,
2530
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
2531
+ tenant.did,
2532
+ '/finalize-offers'
2533
+ )}`,
2534
+ },
2535
+ iss: tenant.did,
2536
+ iat: expect.any(Number),
2537
+ exp: expect.any(Number),
2538
+ nbf: expect.any(Number),
2539
+ });
2540
+
2541
+ const dbExchange = await mongoDb()
2542
+ .collection('exchanges')
2543
+ .findOne({ _id: new ObjectId(payload.exchange_id) });
2544
+ expect(dbExchange).toEqual({
2545
+ _id: new ObjectId(payload.exchange_id),
2546
+ type: ExchangeTypes.ISSUING,
2547
+ tenantId: new ObjectId(tenant._id),
2548
+ disclosureId: new ObjectId(disclosure._id),
2549
+ events: [
2550
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
2551
+ {
2552
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
2553
+ timestamp: expect.any(Date),
2554
+ },
2555
+ ],
2556
+ credentialTypes: ['PastEmploymentPosition'],
2557
+ protocolMetadata: {
2558
+ protocol: ExchangeProtocols.VNF_API,
2559
+ },
2560
+ pushDelegate,
2561
+ createdAt: expect.any(Date),
2562
+ updatedAt: expect.any(Date),
2563
+ });
2564
+ });
2565
+
2566
+ it('should 200, when credential type & invalid push_delegate provided (pushUrl not provided)', async () => {
2567
+ nockRegistrarGetOrganizationVerifiedProfile(
2568
+ tenant.did,
2569
+ sampleOrganizationVerifiedProfile1
2570
+ );
2571
+
2572
+ const pushDelegate = {
2573
+ pushToken: '123',
2574
+ };
2575
+
2576
+ nock('http://oracle.localhost.test')
2577
+ .get(
2578
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
2579
+ )
2580
+ .reply(200, {
2581
+ id: 'EmailV1.0',
2582
+ name: 'Email',
2583
+ schema: [
2584
+ {
2585
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2586
+ },
2587
+ ],
2588
+ });
2589
+ nock('http://oracle.localhost.test')
2590
+ .get(
2591
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
2592
+ )
2593
+ .reply(200, {
2594
+ id: 'PastEmploymentPosition',
2595
+ name: 'Past Role',
2596
+ schema: [
2597
+ {
2598
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2599
+ },
2600
+ ],
2601
+ display: {
2602
+ title: {
2603
+ path: '$.employment',
2604
+ },
2605
+ },
2606
+ });
2607
+
2608
+ const response = await fastify.injectJson({
2609
+ method: 'GET',
2610
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
2611
+ credential_types: 'PastEmploymentPosition',
2612
+ 'push_delegate.push_token': pushDelegate.pushToken,
2613
+ }),
2614
+ });
2615
+
2616
+ expect(response.statusCode).toEqual(200);
2617
+ expect(response.json).toEqual({
2618
+ issuing_request: expect.any(String),
2619
+ });
2620
+ const { payload } = jwtDecode(response.json.issuing_request);
2621
+
2622
+ const dbExchange = await mongoDb()
2623
+ .collection('exchanges')
2624
+ .findOne({ _id: new ObjectId(payload.exchange_id) });
2625
+ expect(dbExchange).toEqual({
2626
+ _id: new ObjectId(payload.exchange_id),
2627
+ type: ExchangeTypes.ISSUING,
2628
+ tenantId: new ObjectId(tenant._id),
2629
+ disclosureId: new ObjectId(disclosure._id),
2630
+ events: [
2631
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
2632
+ {
2633
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
2634
+ timestamp: expect.any(Date),
2635
+ },
2636
+ ],
2637
+ credentialTypes: ['PastEmploymentPosition'],
2638
+ protocolMetadata: {
2639
+ protocol: ExchangeProtocols.VNF_API,
2640
+ },
2641
+ createdAt: expect.any(Date),
2642
+ updatedAt: expect.any(Date),
2643
+ });
2644
+ });
2645
+
2646
+ it('should 200, when credential type & invalid push_delegate provided (pushToken not provided)', async () => {
2647
+ nockRegistrarGetOrganizationVerifiedProfile(
2648
+ tenant.did,
2649
+ sampleOrganizationVerifiedProfile1
2650
+ );
2651
+
2652
+ const pushDelegate = {
2653
+ pushUrl: '123',
2654
+ };
2655
+
2656
+ nock('http://oracle.localhost.test')
2657
+ .get(
2658
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
2659
+ )
2660
+ .reply(200, {
2661
+ id: 'EmailV1.0',
2662
+ name: 'Email',
2663
+ schema: [
2664
+ {
2665
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2666
+ },
2667
+ ],
2668
+ });
2669
+ nock('http://oracle.localhost.test')
2670
+ .get(
2671
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
2672
+ )
2673
+ .reply(200, {
2674
+ id: 'PastEmploymentPosition',
2675
+ name: 'Past Role',
2676
+ schema: [
2677
+ {
2678
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2679
+ },
2680
+ ],
2681
+ display: {
2682
+ title: {
2683
+ path: '$.employment',
2684
+ },
2685
+ },
2686
+ });
2687
+
2688
+ const response = await fastify.injectJson({
2689
+ method: 'GET',
2690
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
2691
+ credential_types: 'PastEmploymentPosition',
2692
+ 'push_delegate.push_url': pushDelegate.pushUrl,
2693
+ }),
2694
+ });
2695
+
2696
+ expect(response.statusCode).toEqual(200);
2697
+ expect(response.json).toEqual({
2698
+ issuing_request: expect.any(String),
2699
+ });
2700
+ const { payload } = jwtDecode(response.json.issuing_request);
2701
+
2702
+ const dbExchange = await mongoDb()
2703
+ .collection('exchanges')
2704
+ .findOne({ _id: new ObjectId(payload.exchange_id) });
2705
+ expect(dbExchange).toEqual({
2706
+ _id: new ObjectId(payload.exchange_id),
2707
+ type: ExchangeTypes.ISSUING,
2708
+ tenantId: new ObjectId(tenant._id),
2709
+ disclosureId: new ObjectId(disclosure._id),
2710
+ events: [
2711
+ { state: ExchangeStates.NEW, timestamp: expect.any(Date) },
2712
+ {
2713
+ state: ExchangeStates.CREDENTIAL_MANIFEST_REQUESTED,
2714
+ timestamp: expect.any(Date),
2715
+ },
2716
+ ],
2717
+ credentialTypes: ['PastEmploymentPosition'],
2718
+ protocolMetadata: {
2719
+ protocol: ExchangeProtocols.VNF_API,
2720
+ },
2721
+ createdAt: expect.any(Date),
2722
+ updatedAt: expect.any(Date),
2723
+ });
2724
+ });
2725
+
2726
+ it('should 200 & return `json` when json format query param is used', async () => {
2727
+ nockRegistrarGetOrganizationVerifiedProfile(
2728
+ tenant.did,
2729
+ sampleOrganizationVerifiedProfile1
2730
+ );
2731
+ nock('http://oracle.localhost.test')
2732
+ .get(
2733
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
2734
+ )
2735
+ .reply(200, {
2736
+ id: 'EmailV1.0',
2737
+ name: 'Email',
2738
+ schema: [
2739
+ {
2740
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2741
+ },
2742
+ ],
2743
+ });
2744
+ nock('http://oracle.localhost.test')
2745
+ .get(
2746
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
2747
+ )
2748
+ .reply(200, {
2749
+ id: 'PastEmploymentPosition',
2750
+ name: 'Past Role',
2751
+ schema: [
2752
+ {
2753
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2754
+ },
2755
+ ],
2756
+ display: {
2757
+ title: {
2758
+ path: '$.employment',
2759
+ },
2760
+ },
2761
+ });
2762
+ nock('http://oracle.localhost.test')
2763
+ .get(
2764
+ '/api/v0.6/credential-type-descriptors/CurrentEmploymentPosition?includeDisplay=true'
2765
+ )
2766
+ .reply(200, {
2767
+ id: 'CurrentEmploymentPosition',
2768
+ name: 'Current Role',
2769
+ schema: [
2770
+ {
2771
+ uri: 'http://oracle.localhost.test/schemas/CurrentEmploymentPosition.json',
2772
+ },
2773
+ ],
2774
+ display: {
2775
+ title: {
2776
+ path: '$.current',
2777
+ },
2778
+ },
2779
+ });
2780
+
2781
+ const response = await fastify.injectJson({
2782
+ method: 'GET',
2783
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
2784
+ credential_types: [
2785
+ 'PastEmploymentPosition',
2786
+ 'CurrentEmploymentPosition',
2787
+ ],
2788
+ format: 'json',
2789
+ }),
2790
+ });
2791
+ expect(response.statusCode).toEqual(200);
2792
+ expect(response.json).toEqual({
2793
+ issuing_request: expect.anything(),
2794
+ });
2795
+ const parsedResponse = response.json.issuing_request;
2796
+ expect(parsedResponse).toEqual({
2797
+ exchange_id: expect.stringMatching(OBJECT_ID_FORMAT),
2798
+ output_descriptors: [
2799
+ {
2800
+ id: 'PastEmploymentPosition',
2801
+ name: 'Past Role',
2802
+ schema: [
2803
+ {
2804
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2805
+ },
2806
+ ],
2807
+ display: {
2808
+ title: {
2809
+ path: '$.employment',
2810
+ },
2811
+ },
2812
+ },
2813
+ {
2814
+ id: 'CurrentEmploymentPosition',
2815
+ name: 'Current Role',
2816
+ schema: [
2817
+ {
2818
+ uri: 'http://oracle.localhost.test/schemas/CurrentEmploymentPosition.json',
2819
+ },
2820
+ ],
2821
+ display: {
2822
+ title: {
2823
+ path: '$.current',
2824
+ },
2825
+ },
2826
+ },
2827
+ ],
2828
+ issuer: {
2829
+ id: tenant.did,
2830
+ },
2831
+ presentation_definition: {
2832
+ id: `${parsedResponse.exchange_id}.${disclosure._id}`,
2833
+ name: 'Credential Issuance disclosure',
2834
+ purpose: 'Identification',
2835
+ format: { jwt_vp: { alg: ['secp256k1'] } },
2836
+ input_descriptors: [
2837
+ {
2838
+ id: 'EmailV1.0',
2839
+ name: 'Email',
2840
+ group: ['A'],
2841
+ schema: [
2842
+ {
2843
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2844
+ },
2845
+ ],
2846
+ },
2847
+ ],
2848
+ submission_requirements: [
2849
+ {
2850
+ rule: 'all',
2851
+ from: 'A',
2852
+ min: 1,
2853
+ },
2854
+ ],
2855
+ },
2856
+ metadata: {
2857
+ client_name: sampleOrganizationProfile1.name,
2858
+ logo_uri: sampleOrganizationProfile1.logo,
2859
+ tos_uri: disclosure.termsUrl,
2860
+ auth_token_uri: `${agentUrl}${tenantUrl(
2861
+ { tenantId: tenant.did },
2862
+ '/oauth/token'
2863
+ )}`,
2864
+ max_retention_period: disclosure.duration,
2865
+ progress_uri: `${agentUrl}${tenantUrl(
2866
+ { tenantId: tenant.did },
2867
+ '/get-exchange-progress'
2868
+ )}`,
2869
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
2870
+ tenant.did,
2871
+ '/submit-identification'
2872
+ )}`,
2873
+ check_offers_uri: `${agentUrl}${issuingUrl(
2874
+ tenant.did,
2875
+ '/credential-offers'
2876
+ )}`,
2877
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
2878
+ tenant.did,
2879
+ '/finalize-offers'
2880
+ )}`,
2881
+ },
2882
+ });
2883
+ });
2884
+
2885
+ it('should 200 & return `jwt` when json format query param in production environment', async () => {
2886
+ await fastify.close();
2887
+ fastify = await buildFastify({ ...holderConfig, isProd: true });
2888
+ nockRegistrarGetOrganizationVerifiedProfile(
2889
+ tenant.did,
2890
+ sampleOrganizationVerifiedProfile1
2891
+ );
2892
+ nock('http://oracle.localhost.test')
2893
+ .get(
2894
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
2895
+ )
2896
+ .reply(200, {
2897
+ id: 'EmailV1.0',
2898
+ name: 'Email',
2899
+ schema: [
2900
+ {
2901
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2902
+ },
2903
+ ],
2904
+ });
2905
+ nock('http://oracle.localhost.test')
2906
+ .get(
2907
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
2908
+ )
2909
+ .reply(200, {
2910
+ id: 'PastEmploymentPosition',
2911
+ name: 'Past Role',
2912
+ schema: [
2913
+ {
2914
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
2915
+ },
2916
+ ],
2917
+ display: {
2918
+ title: {
2919
+ path: '$.employment',
2920
+ },
2921
+ },
2922
+ });
2923
+ nock('http://oracle.localhost.test')
2924
+ .get(
2925
+ '/api/v0.6/credential-type-descriptors/CurrentEmploymentPosition?includeDisplay=true'
2926
+ )
2927
+ .reply(200, {
2928
+ id: 'CurrentEmploymentPosition',
2929
+ name: 'Current Role',
2930
+ schema: [
2931
+ {
2932
+ uri: 'http://oracle.localhost.test/schemas/CurrentEmploymentPosition.json',
2933
+ },
2934
+ ],
2935
+ display: {
2936
+ title: {
2937
+ path: '$.current',
2938
+ },
2939
+ },
2940
+ });
2941
+
2942
+ const response = await fastify.injectJson({
2943
+ method: 'GET',
2944
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
2945
+ credential_types: [
2946
+ 'PastEmploymentPosition',
2947
+ 'CurrentEmploymentPosition',
2948
+ ],
2949
+ format: 'json',
2950
+ }),
2951
+ });
2952
+ expect(response.statusCode).toEqual(200);
2953
+ expect(response.json.issuing_request).toEqual(
2954
+ expect.stringMatching(JWT_FORMAT)
2955
+ );
2956
+ await fastify.close();
2957
+ fastify = await buildFastify();
2958
+ });
2959
+
2960
+ it('should 200 and add configuration type to disclosure', async () => {
2961
+ const { insertedId } = await mongoDb()
2962
+ .collection('disclosures')
2963
+ .insertOne({
2964
+ description: 'Integrated Credential Issuance disclosure',
2965
+ types: [{ type: 'EmailV1.0' }],
2966
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
2967
+ purpose: 'Identification',
2968
+ duration: '6y',
2969
+ tenantId: new ObjectId(tenant._id),
2970
+ vendorDisclosureId: 'HR-PKG-USPS-CLRK',
2971
+ termsUrl: 'https://www.lipsum.com/feed/html',
2972
+ sendPushOnVerification: false,
2973
+ createdAt: new Date(),
2974
+ updatedAt: new Date(),
2975
+ });
2976
+ const customDisclosure = await mongoDb()
2977
+ .collection('disclosures')
2978
+ .findOne({ _id: insertedId });
2979
+
2980
+ expect(customDisclosure.configurationType).toBeUndefined();
2981
+
2982
+ nockRegistrarGetOrganizationVerifiedProfile(
2983
+ tenant.did,
2984
+ sampleOrganizationVerifiedProfile1
2985
+ );
2986
+ nock('http://oracle.localhost.test')
2987
+ .get(
2988
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
2989
+ )
2990
+ .reply(200, {
2991
+ id: 'EmailV1.0',
2992
+ name: 'Email',
2993
+ schema: [
2994
+ {
2995
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
2996
+ },
2997
+ ],
2998
+ });
2999
+ nock('http://oracle.localhost.test')
3000
+ .get(
3001
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
3002
+ )
3003
+ .reply(200, {
3004
+ id: 'PastEmploymentPosition',
3005
+ name: 'Past Role',
3006
+ schema: [
3007
+ {
3008
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
3009
+ },
3010
+ ],
3011
+ display: {
3012
+ title: {
3013
+ path: '$.employment',
3014
+ },
3015
+ },
3016
+ });
3017
+
3018
+ const response = await fastify.injectJson({
3019
+ method: 'GET',
3020
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
3021
+ id: customDisclosure._id.toString(),
3022
+ credential_types: ['PastEmploymentPosition'],
3023
+ }),
3024
+ });
3025
+ expect(response.statusCode).toEqual(200);
3026
+ expect(response.json).toEqual({
3027
+ issuing_request: expect.any(String),
3028
+ });
3029
+
3030
+ const dbDisclosure = await mongoDb()
3031
+ .collection('disclosures')
3032
+ .findOne({ _id: new ObjectId(customDisclosure._id) });
3033
+ expect(dbDisclosure.configurationType).toEqual('issuing');
3034
+ });
3035
+
3036
+ it('should 200 and add defaultIssuingDisclosureId to tenant and use defaultIssuingDisclosureId for finding disclosure', async () => {
3037
+ const customDisclosure = await persistDisclosure({
3038
+ tenant,
3039
+ description: 'Integrated Credential Issuance disclosure',
3040
+ types: [{ type: 'EmailV1.0' }],
3041
+ vendorEndpoint: VendorEndpoint.INTEGRATED_ISSUING_IDENTIFICATION,
3042
+ purpose: 'Identification',
3043
+ duration: '6y',
3044
+ });
3045
+
3046
+ expect(tenant.defaultIssuingDisclosureId).toBeUndefined();
3047
+
3048
+ nockRegistrarGetOrganizationVerifiedProfile(
3049
+ tenant.did,
3050
+ sampleOrganizationVerifiedProfile1
3051
+ );
3052
+ nock('http://oracle.localhost.test')
3053
+ .get(
3054
+ '/api/v0.6/credential-type-descriptors/EmailV1.0?includeDisplay=false'
3055
+ )
3056
+ .reply(200, {
3057
+ id: 'EmailV1.0',
3058
+ name: 'Email',
3059
+ schema: [
3060
+ {
3061
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
3062
+ },
3063
+ ],
3064
+ });
3065
+ nock('http://oracle.localhost.test')
3066
+ .get(
3067
+ '/api/v0.6/credential-type-descriptors/PastEmploymentPosition?includeDisplay=true'
3068
+ )
3069
+ .reply(200, {
3070
+ id: 'PastEmploymentPosition',
3071
+ name: 'Past Role',
3072
+ schema: [
3073
+ {
3074
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
3075
+ },
3076
+ ],
3077
+ display: {
3078
+ title: {
3079
+ path: '$.employment',
3080
+ },
3081
+ },
3082
+ });
3083
+
3084
+ const response = await fastify.injectJson({
3085
+ method: 'GET',
3086
+ url: issuingUrl(tenant.did, '/get-credential-manifest', {
3087
+ credential_types: ['PastEmploymentPosition'],
3088
+ }),
3089
+ });
3090
+ expect(response.statusCode).toEqual(200);
3091
+ expect(response.json).toEqual({
3092
+ issuing_request: expect.any(String),
3093
+ });
3094
+
3095
+ const { payload } = jwtDecode(response.json.issuing_request);
3096
+ expect(payload).toEqual({
3097
+ exchange_id: expect.any(String),
3098
+ output_descriptors: [
3099
+ {
3100
+ id: 'PastEmploymentPosition',
3101
+ name: 'Past Role',
3102
+ schema: [
3103
+ {
3104
+ uri: 'http://oracle.localhost.test/schemas/PastEmploymentPosition.json',
3105
+ },
3106
+ ],
3107
+ display: {
3108
+ title: {
3109
+ path: '$.employment',
3110
+ },
3111
+ },
3112
+ },
3113
+ ],
3114
+ issuer: {
3115
+ id: tenant.did,
3116
+ },
3117
+ presentation_definition: {
3118
+ id: `${payload.exchange_id}.${customDisclosure._id}`,
3119
+ name: customDisclosure.description,
3120
+ purpose: customDisclosure.purpose,
3121
+ format: {
3122
+ jwt_vp: { alg: ['secp256k1'] },
3123
+ },
3124
+ input_descriptors: [
3125
+ {
3126
+ id: 'EmailV1.0',
3127
+ name: 'Email',
3128
+ group: ['A'],
3129
+ schema: [
3130
+ {
3131
+ uri: 'http://oracle.localhost.test/schemas/Email.json',
3132
+ },
3133
+ ],
3134
+ },
3135
+ ],
3136
+ submission_requirements: [
3137
+ {
3138
+ from: 'A',
3139
+ min: 1,
3140
+ rule: 'all',
3141
+ },
3142
+ ],
3143
+ },
3144
+ metadata: {
3145
+ client_name: orgDidDoc.service[0].name,
3146
+ logo_uri: orgDidDoc.service[0].logo,
3147
+ tos_uri: customDisclosure.termsUrl,
3148
+ auth_token_uri: `${agentUrl}${tenantUrl(
3149
+ { tenantId: tenant.did },
3150
+ '/oauth/token'
3151
+ )}`,
3152
+ max_retention_period: customDisclosure.duration,
3153
+ progress_uri: `${agentUrl}${tenantUrl(
3154
+ { tenantId: tenant.did },
3155
+ '/get-exchange-progress'
3156
+ )}`,
3157
+ submit_presentation_uri: `${agentUrl}${issuingUrl(
3158
+ tenant.did,
3159
+ '/submit-identification'
3160
+ )}`,
3161
+ check_offers_uri: `${agentUrl}${issuingUrl(
3162
+ tenant.did,
3163
+ '/credential-offers'
3164
+ )}`,
3165
+ finalize_offers_uri: `${agentUrl}${issuingUrl(
3166
+ tenant.did,
3167
+ '/finalize-offers'
3168
+ )}`,
3169
+ },
3170
+ iss: tenant.did,
3171
+ exp: expect.any(Number),
3172
+ iat: expect.any(Number),
3173
+ nbf: expect.any(Number),
3174
+ });
3175
+
3176
+ const dbExchange = await mongoDb()
3177
+ .collection('exchanges')
3178
+ .findOne({ _id: new ObjectId(payload.exchange_id) });
3179
+
3180
+ expect(dbExchange.disclosureId.toString()).toEqual(
3181
+ customDisclosure._id.toString()
3182
+ );
3183
+
3184
+ const dbTenant = await mongoDb()
3185
+ .collection('tenants')
3186
+ .findOne({ _id: new ObjectId(tenant._id) });
3187
+ expect(dbTenant.defaultIssuingDisclosureId.toString()).toEqual(
3188
+ customDisclosure._id.toString()
3189
+ );
3190
+ });
3191
+ });
3192
+ });