@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,1130 @@
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
+ // eslint-disable-next-line import/order
18
+ const nock = require('nock');
19
+ const { mongoDb } = require('@spencejs/spence-mongo-repos');
20
+ const { ObjectId } = require('mongodb');
21
+ const { map, omit } = require('lodash/fp');
22
+ const {
23
+ ISO_DATETIME_FORMAT,
24
+ OBJECT_ID_FORMAT,
25
+ } = require('@verii/test-regexes');
26
+ const { errorResponseMatcher, mongoify } = require('@verii/tests-helpers');
27
+ const { hexFromJwk, jwkFromSecp256k1Key } = require('@verii/jwt');
28
+ const { rootPrivateKey } = require('@verii/sample-data');
29
+ const { toEthereumAddress } = require('@verii/blockchain-functions');
30
+ const { KeyPurposes, generateKeyPair } = require('@verii/crypto');
31
+ const {
32
+ deployTestPermissionsContract,
33
+ } = require('@verii/contract-permissions/test/helpers/deploy-test-permissions-contract');
34
+ const buildFastify = require('./helpers/credentialagent-operator-build-fastify');
35
+ const { createOrgDoc } = require('./helpers/create-test-org-doc');
36
+ const {
37
+ nockRegistrarGetOrganizationDidDoc,
38
+ } = require('../combined/helpers/nock-registrar-get-organization-diddoc');
39
+ const {
40
+ initTenantFactory,
41
+ initKeysFactory,
42
+ tenantRepoPlugin,
43
+ KeyEncodings,
44
+ } = require('../../src/entities');
45
+ const {
46
+ generatePrimaryAndAddOperatorToPrimary,
47
+ } = require('./helpers/generate-primary-and-add-operator-to-primary');
48
+ const { initAgentKms } = require('./helpers/init-agent-kms');
49
+
50
+ const buildKeysUrl = ({ tenant }) =>
51
+ `/operator-api/v0.8/tenants/${tenant._id}/keys`;
52
+
53
+ describe('Tenant keys test suite', () => {
54
+ let fastify;
55
+ let persistTenant;
56
+ let persistKey;
57
+ let newKey;
58
+ let orgDoc;
59
+ let orgKey;
60
+ let tenant;
61
+ let orgPublicKey;
62
+ let primaryAddress;
63
+ let tenantRepo;
64
+ let kms;
65
+
66
+ beforeAll(async () => {
67
+ fastify = buildFastify();
68
+ await fastify.ready();
69
+
70
+ ({ persistTenant } = initTenantFactory(fastify));
71
+ ({ persistKey, newKey } = initKeysFactory(fastify));
72
+
73
+ ({ orgDoc, orgKey, orgPublicKey } = await createOrgDoc());
74
+ const deployedContract = await deployTestPermissionsContract(
75
+ rootPrivateKey,
76
+ fastify.config.rpcUrl
77
+ );
78
+ fastify.config.permissionsContractAddress =
79
+ await deployedContract.getAddress();
80
+
81
+ ({ orgDoc, orgKey, orgPublicKey } = await createOrgDoc());
82
+
83
+ const baseContext = {
84
+ config: fastify.config,
85
+ log: fastify.log,
86
+ };
87
+ primaryAddress = await generatePrimaryAndAddOperatorToPrimary(
88
+ toEthereumAddress(orgPublicKey),
89
+ baseContext
90
+ );
91
+ tenantRepo = tenantRepoPlugin(baseContext)();
92
+ }, 10000);
93
+
94
+ beforeEach(async () => {
95
+ nock.cleanAll();
96
+ await mongoDb().collection('tenants').deleteMany({});
97
+ await mongoDb().collection('keys').deleteMany({});
98
+ nockRegistrarGetOrganizationDidDoc(orgDoc.id, orgDoc);
99
+ tenant = await persistTenant({
100
+ did: orgDoc.id,
101
+ primaryAddress,
102
+ });
103
+ kms = initAgentKms(fastify)({ tenant: mongoify(tenant) });
104
+ });
105
+
106
+ afterAll(async () => {
107
+ await fastify.close();
108
+ nock.cleanAll();
109
+ nock.restore();
110
+ });
111
+
112
+ describe('Get keys of tenant tests', () => {
113
+ it('should be able to get keys of an existing tenant', async () => {
114
+ const key1 = await persistKey({ tenant });
115
+ const key2 = await persistKey({ tenant });
116
+
117
+ const response = await fastify.injectJson({
118
+ method: 'GET',
119
+ url: `${buildKeysUrl({ tenant })}`,
120
+ });
121
+
122
+ expect(response.statusCode).toEqual(200);
123
+ expect(response.json).toEqual(
124
+ map(
125
+ (key) => {
126
+ return {
127
+ ...omit(['_id', 'tenantId', 'updatedAt'], key),
128
+ id: key._id,
129
+ encoding: KeyEncodings.HEX,
130
+ createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
131
+ };
132
+ },
133
+ [key1, key2]
134
+ )
135
+ );
136
+ });
137
+
138
+ it('should 404 for non-existing tenant', async () => {
139
+ const fooTenant = { _id: new ObjectId() };
140
+ const response = await fastify.injectJson({
141
+ method: 'GET',
142
+ url: `${buildKeysUrl({ tenant: fooTenant })}`,
143
+ });
144
+
145
+ expect(response.statusCode).toEqual(404);
146
+ expect(response.json).toEqual(
147
+ errorResponseMatcher({
148
+ error: 'Not Found',
149
+ errorCode: 'tenant_not_found',
150
+ message: `Tenant ${JSON.stringify({
151
+ tenantId: fooTenant._id,
152
+ })} not found`,
153
+ statusCode: 404,
154
+ })
155
+ );
156
+ });
157
+ });
158
+
159
+ describe('Add key to tenant tests', () => {
160
+ it('should 404 for non-existing tenant', async () => {
161
+ const fooTenant = { _id: new ObjectId() };
162
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
163
+ const response = await fastify.injectJson({
164
+ method: 'POST',
165
+ url: `${buildKeysUrl({ tenant: fooTenant })}`,
166
+ payload: {
167
+ ...key1,
168
+ key: orgKey,
169
+ kidFragment: '#bad-kid-fragment',
170
+ },
171
+ });
172
+
173
+ expect(response.statusCode).toEqual(404);
174
+ expect(response.json).toEqual(
175
+ errorResponseMatcher({
176
+ error: 'Not Found',
177
+ errorCode: 'tenant_not_found',
178
+ message: `Tenant ${JSON.stringify({
179
+ tenantId: fooTenant._id,
180
+ })} not found`,
181
+ statusCode: 404,
182
+ })
183
+ );
184
+ });
185
+
186
+ it('should 400 with bad kidFragment', async () => {
187
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
188
+
189
+ const response = await fastify.injectJson({
190
+ method: 'POST',
191
+ url: buildKeysUrl({ tenant }),
192
+ payload: {
193
+ ...key1,
194
+ key: orgKey,
195
+ kidFragment: '#bad-kid-fragment',
196
+ },
197
+ });
198
+
199
+ expect(response.statusCode).toEqual(400);
200
+
201
+ const count = await mongoDb().collection('keys').countDocuments();
202
+ expect(count).toEqual(0);
203
+ });
204
+
205
+ it('should 400 with key that does not match the kid', async () => {
206
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
207
+
208
+ const response = await fastify.injectJson({
209
+ method: 'POST',
210
+ url: buildKeysUrl({ tenant }),
211
+ payload: {
212
+ ...key1,
213
+ key: 'not-a-key',
214
+ },
215
+ });
216
+
217
+ expect(response.statusCode).toEqual(400);
218
+
219
+ const count = await mongoDb().collection('keys').countDocuments();
220
+ expect(count).toEqual(0);
221
+ });
222
+
223
+ it('should 400 with an unrecognized purpose', async () => {
224
+ const key1 = omit(
225
+ ['tenantId'],
226
+ await newKey({ tenant, purposes: ['unrecognized-purpose'] })
227
+ );
228
+
229
+ const response = await fastify.injectJson({
230
+ method: 'POST',
231
+ url: buildKeysUrl({ tenant }),
232
+ payload: {
233
+ ...key1,
234
+ key: orgKey,
235
+ },
236
+ });
237
+
238
+ expect(response.statusCode).toEqual(400);
239
+ expect(response.json).toEqual(
240
+ errorResponseMatcher({
241
+ error: 'Bad Request',
242
+ errorCode: 'missing_error_code',
243
+ message: 'Unrecognized purpose detected',
244
+ statusCode: 400,
245
+ })
246
+ );
247
+
248
+ const count = await mongoDb().collection('keys').countDocuments();
249
+ expect(count).toEqual(0);
250
+ });
251
+
252
+ it('should 400 with no purposes', async () => {
253
+ const key1 = omit(['tenantId'], await newKey({ tenant, purposes: [] }));
254
+
255
+ const response = await fastify.injectJson({
256
+ method: 'POST',
257
+ url: buildKeysUrl({ tenant }),
258
+ payload: {
259
+ ...key1,
260
+ key: orgKey,
261
+ },
262
+ });
263
+
264
+ expect(response.statusCode).toEqual(400);
265
+ expect(response.json).toEqual(
266
+ errorResponseMatcher({
267
+ error: 'Bad Request',
268
+ errorCode: 'request_validation_failed',
269
+ message: 'body/purposes must NOT have fewer than 1 items',
270
+ statusCode: 400,
271
+ })
272
+ );
273
+
274
+ const count = await mongoDb().collection('keys').countDocuments();
275
+ expect(count).toEqual(0);
276
+ });
277
+
278
+ it('should 400 with duplicate purposes', async () => {
279
+ const key1 = omit(
280
+ ['tenantId'],
281
+ await newKey({
282
+ tenant,
283
+ purposes: ['DLT_TRANSACTIONS', 'DLT_TRANSACTIONS'],
284
+ })
285
+ );
286
+
287
+ const response = await fastify.injectJson({
288
+ method: 'POST',
289
+ url: buildKeysUrl({ tenant }),
290
+ payload: {
291
+ ...key1,
292
+ key: orgKey,
293
+ },
294
+ });
295
+
296
+ expect(response.statusCode).toEqual(400);
297
+ expect(response.json).toEqual(
298
+ errorResponseMatcher({
299
+ error: 'Bad Request',
300
+ errorCode: 'missing_error_code',
301
+ message: 'Duplicate key purposes detected',
302
+ statusCode: 400,
303
+ })
304
+ );
305
+
306
+ const count = await mongoDb().collection('keys').countDocuments();
307
+ expect(count).toEqual(0);
308
+ });
309
+
310
+ it('should 400 with unrecognized algorithm', async () => {
311
+ const key1 = omit(
312
+ ['tenantId'],
313
+ await newKey({ tenant, algorithm: 'unrecognized-algorithm' })
314
+ );
315
+
316
+ const response = await fastify.injectJson({
317
+ method: 'POST',
318
+ url: buildKeysUrl({ tenant }),
319
+ payload: {
320
+ ...key1,
321
+ key: orgKey,
322
+ },
323
+ });
324
+
325
+ expect(response.statusCode).toEqual(400);
326
+ expect(response.json).toEqual(
327
+ errorResponseMatcher({
328
+ error: 'Bad Request',
329
+ errorCode: 'missing_error_code',
330
+ message: 'Unrecognized algorithm',
331
+ statusCode: 400,
332
+ })
333
+ );
334
+
335
+ const count = await mongoDb().collection('keys').countDocuments();
336
+ expect(count).toEqual(0);
337
+ });
338
+
339
+ it('should 400 with unrecognized encoding', async () => {
340
+ const key1 = omit(
341
+ ['tenantId'],
342
+ await newKey({ tenant, encoding: 'unrecognized-encoding' })
343
+ );
344
+
345
+ const response = await fastify.injectJson({
346
+ method: 'POST',
347
+ url: buildKeysUrl({ tenant }),
348
+ payload: {
349
+ ...key1,
350
+ key: orgKey,
351
+ },
352
+ });
353
+
354
+ expect(response.statusCode).toEqual(400);
355
+ expect(response.json).toEqual(
356
+ errorResponseMatcher({
357
+ error: 'Bad Request',
358
+ message: 'Unrecognized encoding',
359
+ errorCode: 'missing_error_code',
360
+ statusCode: 400,
361
+ })
362
+ );
363
+
364
+ const count = await mongoDb().collection('keys').countDocuments();
365
+ expect(count).toEqual(0);
366
+ });
367
+
368
+ it('should 409 when adding a key with an existing purpose', async () => {
369
+ await persistKey({ tenant });
370
+ const key1 = omit(
371
+ ['tenantId'],
372
+ await newKey({ tenant, kidFragment: '#key2' })
373
+ );
374
+
375
+ const response = await fastify.injectJson({
376
+ method: 'POST',
377
+ url: buildKeysUrl({ tenant }),
378
+ payload: {
379
+ ...key1,
380
+ encoding: KeyEncodings.HEX,
381
+ key: orgKey,
382
+ },
383
+ });
384
+
385
+ expect(response.statusCode).toEqual(409);
386
+ expect(response.json).toEqual(
387
+ errorResponseMatcher({
388
+ statusCode: 409,
389
+ error: 'Conflict',
390
+ message: `Key with a purpose from ${JSON.stringify(
391
+ key1.purposes
392
+ )} already exists`,
393
+ })
394
+ );
395
+ const count = await mongoDb().collection('keys').countDocuments();
396
+ expect(count).toEqual(1);
397
+ });
398
+
399
+ it('should 409 when adding a key with an existing kidFragment', async () => {
400
+ await persistKey({ tenant });
401
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
402
+
403
+ const response = await fastify.injectJson({
404
+ method: 'POST',
405
+ url: buildKeysUrl({ tenant }),
406
+ payload: {
407
+ ...key1,
408
+ encoding: KeyEncodings.HEX,
409
+ key: orgKey,
410
+ },
411
+ });
412
+
413
+ expect(response.statusCode).toEqual(409);
414
+ expect(response.json).toEqual(
415
+ errorResponseMatcher({
416
+ statusCode: 409,
417
+ error: 'Conflict',
418
+ message: `Key with kidFragment ${key1.kidFragment} already exists`,
419
+ })
420
+ );
421
+ const count = await mongoDb().collection('keys').countDocuments();
422
+ expect(count).toEqual(1);
423
+ });
424
+
425
+ it('should 201 adding a key with 3 purposes to the tenant', async () => {
426
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
427
+
428
+ const response = await fastify.injectJson({
429
+ method: 'POST',
430
+ url: buildKeysUrl({ tenant }),
431
+ payload: {
432
+ ...key1,
433
+ encoding: KeyEncodings.HEX,
434
+ key: orgKey,
435
+ },
436
+ });
437
+
438
+ expect(response.statusCode).toEqual(201);
439
+ expect(response.json).toEqual({
440
+ ...omit(['tenantId', 'updatedAt', 'key', 'publicKey'], key1),
441
+ id: expect.stringMatching(OBJECT_ID_FORMAT),
442
+ encoding: KeyEncodings.HEX,
443
+ createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
444
+ });
445
+
446
+ const keyFromDb = await mongoDb().collection('keys').findOne();
447
+ expect(keyFromDb).toEqual({
448
+ _id: expect.any(ObjectId),
449
+ ...key1,
450
+ tenantId: new ObjectId(tenant._id),
451
+ key: expect.any(String),
452
+ createdAt: expect.any(Date),
453
+ updatedAt: expect.any(Date),
454
+ });
455
+
456
+ const decryptedKey = await kms.exportKeyOrSecret(response.json.id);
457
+ expect(decryptedKey).toEqual({
458
+ ...omit(['key', 'publicKey'], key1),
459
+ id: response.json.id,
460
+ privateJwk: jwkFromSecp256k1Key(orgKey, true),
461
+ tenantId: new ObjectId(tenant._id),
462
+ createdAt: expect.any(Date),
463
+ updatedAt: expect.any(Date),
464
+ });
465
+ const tenantFromDb = await tenantRepo.findOne(tenant._id);
466
+ expect(tenantFromDb).toEqual({
467
+ _id: new ObjectId(tenant._id),
468
+ did: orgDoc.id,
469
+ primaryAddress,
470
+ createdAt: expect.any(Date),
471
+ updatedAt: expect.any(Date),
472
+ });
473
+ });
474
+
475
+ it('should 201 adding a key with 1 purpose to the tenant', async () => {
476
+ const key1 = omit(
477
+ ['tenantId'],
478
+ await newKey({ tenant, purposes: ['DLT_TRANSACTIONS'] })
479
+ );
480
+
481
+ const response = await fastify.injectJson({
482
+ method: 'POST',
483
+ url: buildKeysUrl({ tenant }),
484
+ payload: {
485
+ ...key1,
486
+ encoding: KeyEncodings.HEX,
487
+ key: orgKey,
488
+ },
489
+ });
490
+
491
+ expect(response.statusCode).toEqual(201);
492
+ expect(response.json).toEqual({
493
+ ...omit(['_id', 'tenantId', 'updatedAt', 'key', 'publicKey'], key1),
494
+ id: expect.stringMatching(OBJECT_ID_FORMAT),
495
+ encoding: KeyEncodings.HEX,
496
+ createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
497
+ });
498
+
499
+ const keyFromDb = await mongoDb().collection('keys').findOne();
500
+ expect(keyFromDb).toEqual({
501
+ _id: expect.any(ObjectId),
502
+ ...key1,
503
+ tenantId: new ObjectId(tenant._id),
504
+ key: expect.any(String),
505
+ createdAt: expect.any(Date),
506
+ updatedAt: expect.any(Date),
507
+ });
508
+
509
+ const decryptedKey = await kms.exportKeyOrSecret(response.json.id);
510
+ expect(decryptedKey).toEqual({
511
+ ...omit(['key', 'publicKey'], key1),
512
+ id: response.json.id,
513
+ privateJwk: jwkFromSecp256k1Key(orgKey, true),
514
+ tenantId: new ObjectId(tenant._id),
515
+ createdAt: expect.any(Date),
516
+ updatedAt: expect.any(Date),
517
+ });
518
+
519
+ const tenantFromDb = await tenantRepo.findOne(tenant._id);
520
+ expect(tenantFromDb).toEqual({
521
+ _id: new ObjectId(tenant._id),
522
+ did: orgDoc.id,
523
+ primaryAddress,
524
+ createdAt: expect.any(Date),
525
+ updatedAt: expect.any(Date),
526
+ });
527
+ });
528
+
529
+ it('should not change primaryAddress if DLT_TRANSACTION key already exist in db', async () => {
530
+ await persistKey({ tenant, purposes: [KeyPurposes.DLT_TRANSACTIONS] });
531
+
532
+ const key1 = omit(
533
+ ['tenantId'],
534
+ await newKey({ tenant, purposes: [KeyPurposes.DLT_TRANSACTIONS] })
535
+ );
536
+
537
+ const response = await fastify.injectJson({
538
+ method: 'POST',
539
+ url: buildKeysUrl({ tenant }),
540
+ payload: {
541
+ ...key1,
542
+ encoding: KeyEncodings.HEX,
543
+ key: orgKey,
544
+ },
545
+ });
546
+
547
+ expect(response.statusCode).toEqual(409);
548
+ const tenantFromDb = await tenantRepo.findOne(tenant._id);
549
+ expect(tenantFromDb.primaryAddress).toEqual(primaryAddress);
550
+ });
551
+
552
+ it('should set primaryAddress if DLT_TRANSACTION key not exist in db', async () => {
553
+ tenantRepo.update(tenant._id, { primaryAddress: '' });
554
+ const key1 = omit(
555
+ ['tenantId'],
556
+ await newKey({ tenant, purposes: [KeyPurposes.DLT_TRANSACTIONS] })
557
+ );
558
+
559
+ const response = await fastify.injectJson({
560
+ method: 'POST',
561
+ url: buildKeysUrl({ tenant }),
562
+ payload: {
563
+ ...key1,
564
+ encoding: KeyEncodings.HEX,
565
+ key: orgKey,
566
+ },
567
+ });
568
+
569
+ expect(response.statusCode).toEqual(201);
570
+ const tenantFromDb = await tenantRepo.findOne(tenant._id);
571
+ expect(tenantFromDb.primaryAddress).toBe(primaryAddress);
572
+ });
573
+
574
+ it('should not add primaryAddress if purpose not DLT_TRANSACTION', async () => {
575
+ nockRegistrarGetOrganizationDidDoc('did:test', orgDoc);
576
+ const tenant1 = await persistTenant({
577
+ did: 'did:test',
578
+ primaryAddress: '',
579
+ });
580
+ const key1 = omit(
581
+ ['tenantId'],
582
+ await newKey({
583
+ tenant: tenant1,
584
+ purposes: [
585
+ KeyPurposes.EXCHANGES,
586
+ KeyPurposes.ISSUING_METADATA,
587
+ KeyPurposes.REVOCATIONS_FALLBACK,
588
+ KeyPurposes.ROTATION,
589
+ KeyPurposes.PERMISSIONING,
590
+ ],
591
+ })
592
+ );
593
+
594
+ const response = await fastify.injectJson({
595
+ method: 'POST',
596
+ url: buildKeysUrl({ tenant: tenant1 }),
597
+ payload: {
598
+ ...key1,
599
+ encoding: KeyEncodings.HEX,
600
+ key: orgKey,
601
+ },
602
+ });
603
+
604
+ expect(response.statusCode).toEqual(201);
605
+ const tenantFromDb = await tenantRepo.findOne(tenant1._id);
606
+ expect(tenantFromDb.primaryAddress).toBe('');
607
+ });
608
+
609
+ it('should not add primaryAddress if tenant has primaryAddress', async () => {
610
+ nockRegistrarGetOrganizationDidDoc('did:test', orgDoc);
611
+ const tenant1 = await persistTenant({
612
+ did: 'did:test',
613
+ });
614
+ const prevPrimaryAddress = tenant1.primaryAddress;
615
+ const key1 = omit(
616
+ ['tenantId'],
617
+ await newKey({ tenant, purposes: [KeyPurposes.DLT_TRANSACTIONS] })
618
+ );
619
+
620
+ const response = await fastify.injectJson({
621
+ method: 'POST',
622
+ url: buildKeysUrl({ tenant: tenant1 }),
623
+ payload: {
624
+ ...key1,
625
+ encoding: KeyEncodings.HEX,
626
+ key: orgKey,
627
+ },
628
+ });
629
+
630
+ expect(response.statusCode).toEqual(201);
631
+ const tenantFromDb = await tenantRepo.findOne(tenant1._id);
632
+ expect(tenantFromDb.primaryAddress).toBe(prevPrimaryAddress);
633
+ });
634
+ });
635
+
636
+ describe('Remove tenant key tests', () => {
637
+ it('should 404 for non-existing tenant', async () => {
638
+ const key1 = await persistKey({ tenant });
639
+
640
+ const fooTenant = { _id: new ObjectId() };
641
+ const response = await fastify.injectJson({
642
+ method: 'DELETE',
643
+ url: `${buildKeysUrl({ tenant: fooTenant })}/${encodeURIComponent(
644
+ key1.kidFragment
645
+ )}`,
646
+ });
647
+
648
+ expect(response.statusCode).toEqual(404);
649
+ expect(response.json).toEqual(
650
+ errorResponseMatcher({
651
+ error: 'Not Found',
652
+ message: `Tenant ${JSON.stringify({
653
+ tenantId: fooTenant._id,
654
+ })} not found`,
655
+ errorCode: 'tenant_not_found',
656
+ statusCode: 404,
657
+ })
658
+ );
659
+ });
660
+
661
+ it('should 404 when deleting a non-existent key', async () => {
662
+ await persistKey({ tenant });
663
+
664
+ const response = await fastify.injectJson({
665
+ method: 'DELETE',
666
+ url: `${buildKeysUrl({ tenant })}/not-a-fragment`,
667
+ });
668
+
669
+ expect(response.statusCode).toEqual(404);
670
+
671
+ const count = await mongoDb().collection('keys').countDocuments();
672
+ expect(count).toEqual(1);
673
+ });
674
+
675
+ it('should 204 when deleting an existing key', async () => {
676
+ const key1 = await persistKey({ tenant });
677
+
678
+ const response = await fastify.injectJson({
679
+ method: 'DELETE',
680
+ url: `${buildKeysUrl({ tenant })}/${encodeURIComponent(
681
+ key1.kidFragment
682
+ )}`,
683
+ });
684
+
685
+ expect(response.statusCode).toEqual(204);
686
+
687
+ const count = await mongoDb().collection('keys').countDocuments();
688
+ expect(count).toEqual(0);
689
+ });
690
+ });
691
+
692
+ describe('Did web document', () => {
693
+ const getDidWebDoc = (key, did = 'did:web:123') => ({
694
+ '@context': [
695
+ 'https://www.w3.org/ns/did/v1',
696
+ 'https://w3id.org/security/suites/jws-2020/v1',
697
+ ],
698
+ id: did,
699
+ authentication: [key.id],
700
+ assertionMethod: [key.id],
701
+ verificationMethod: [key],
702
+ publicKey: [key],
703
+ });
704
+ let keyPair;
705
+
706
+ beforeAll(async () => {
707
+ keyPair = await generateKeyPair({ format: 'jwk' });
708
+ orgKey = keyPair.privateKey;
709
+ orgDoc = getDidWebDoc({
710
+ id: 'did:web:123#key-0',
711
+ type: 'JsonWebKey2020',
712
+ controller: 'did:web:123',
713
+ publicKeyJwk: keyPair.publicKey,
714
+ });
715
+ nockRegistrarGetOrganizationDidDoc('did:web:123', orgDoc);
716
+ orgPublicKey = hexFromJwk(keyPair.publicKey, false);
717
+
718
+ const baseContext = {
719
+ config: fastify.config,
720
+ log: fastify.log,
721
+ };
722
+ primaryAddress = await generatePrimaryAndAddOperatorToPrimary(
723
+ toEthereumAddress(orgPublicKey),
724
+ baseContext
725
+ );
726
+ tenant = await persistTenant({
727
+ did: 'did:web:123',
728
+ primaryAddress,
729
+ });
730
+ });
731
+
732
+ it('should 201 adding a key with 3 purposes to the tenant', async () => {
733
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
734
+
735
+ const response = await fastify.injectJson({
736
+ method: 'POST',
737
+ url: buildKeysUrl({ tenant }),
738
+ payload: {
739
+ ...key1,
740
+ kidFragment: '#key-0',
741
+ encoding: KeyEncodings.HEX,
742
+ key: hexFromJwk(keyPair.privateKey, true),
743
+ },
744
+ });
745
+
746
+ expect(response.statusCode).toEqual(201);
747
+ expect(response.json).toEqual({
748
+ ...omit(['_id', 'tenantId', 'updatedAt', 'key', 'publicKey'], key1),
749
+ kidFragment: '#key-0',
750
+ id: expect.stringMatching(OBJECT_ID_FORMAT),
751
+ encoding: KeyEncodings.HEX,
752
+ createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
753
+ });
754
+
755
+ const keyFromDb = await mongoDb().collection('keys').findOne();
756
+ expect(keyFromDb).toEqual({
757
+ _id: expect.any(ObjectId),
758
+ ...key1,
759
+ kidFragment: '#key-0',
760
+ tenantId: new ObjectId(tenant._id),
761
+ key: expect.any(String),
762
+ createdAt: expect.any(Date),
763
+ updatedAt: expect.any(Date),
764
+ });
765
+
766
+ const decryptedKey = await kms.exportKeyOrSecret(response.json.id);
767
+ expect(decryptedKey).toEqual({
768
+ ...omit(['key', 'publicKey'], key1),
769
+ kidFragment: '#key-0',
770
+ id: response.json.id,
771
+ privateJwk: { use: 'sig', ...keyPair.privateKey },
772
+ tenantId: new ObjectId(tenant._id),
773
+ createdAt: expect.any(Date),
774
+ updatedAt: expect.any(Date),
775
+ });
776
+
777
+ const tenantFromDb = await tenantRepo.findOne(tenant._id);
778
+ expect(tenantFromDb).toEqual({
779
+ _id: new ObjectId(tenant._id),
780
+ did: orgDoc.id,
781
+ primaryAddress,
782
+ createdAt: expect.any(Date),
783
+ updatedAt: expect.any(Date),
784
+ });
785
+ });
786
+
787
+ it('should 201 adding a jwk to the tenant', async () => {
788
+ const key1 = omit(['tenantId', 'key'], await newKey({ tenant }));
789
+
790
+ const response = await fastify.injectJson({
791
+ method: 'POST',
792
+ url: buildKeysUrl({ tenant }),
793
+ payload: {
794
+ ...key1,
795
+ kidFragment: '#key-0',
796
+ encoding: KeyEncodings.JWK,
797
+ jwk: keyPair.privateKey,
798
+ },
799
+ });
800
+
801
+ expect(response.statusCode).toEqual(201);
802
+ expect(response.json).toEqual({
803
+ ...omit(['_id', 'tenantId', 'updatedAt', 'key', 'publicKey'], key1),
804
+ kidFragment: '#key-0',
805
+ id: expect.stringMatching(OBJECT_ID_FORMAT),
806
+ encoding: KeyEncodings.HEX,
807
+ createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
808
+ });
809
+
810
+ const keyFromDb = await mongoDb().collection('keys').findOne();
811
+ expect(keyFromDb).toEqual({
812
+ _id: expect.any(ObjectId),
813
+ ...key1,
814
+ kidFragment: '#key-0',
815
+ tenantId: new ObjectId(tenant._id),
816
+ key: expect.any(String),
817
+ createdAt: expect.any(Date),
818
+ updatedAt: expect.any(Date),
819
+ });
820
+
821
+ const decryptedKey = await kms.exportKeyOrSecret(response.json.id);
822
+ expect(decryptedKey).toEqual({
823
+ ...omit(['key', 'publicKey'], key1),
824
+ id: response.json.id,
825
+ kidFragment: '#key-0',
826
+ privateJwk: keyPair.privateKey,
827
+ tenantId: new ObjectId(tenant._id),
828
+ createdAt: expect.any(Date),
829
+ updatedAt: expect.any(Date),
830
+ });
831
+
832
+ const tenantFromDb = await tenantRepo.findOne(tenant._id);
833
+ expect(tenantFromDb).toEqual({
834
+ _id: new ObjectId(tenant._id),
835
+ did: orgDoc.id,
836
+ primaryAddress,
837
+ createdAt: expect.any(Date),
838
+ updatedAt: expect.any(Date),
839
+ });
840
+ });
841
+
842
+ it('should 201 adding a hex to the tenant', async () => {
843
+ const key1 = omit(['tenantId', 'key'], await newKey({ tenant }));
844
+
845
+ const response = await fastify.injectJson({
846
+ method: 'POST',
847
+ url: buildKeysUrl({ tenant }),
848
+ payload: {
849
+ ...key1,
850
+ kidFragment: '#key-0',
851
+ encoding: KeyEncodings.JWK,
852
+ publicKey: hexFromJwk(keyPair.publicKey, false),
853
+ hexKey: hexFromJwk(keyPair.privateKey, true),
854
+ },
855
+ });
856
+
857
+ expect(response.statusCode).toEqual(201);
858
+ expect(response.json).toEqual({
859
+ ...omit(['_id', 'tenantId', 'updatedAt', 'key', 'publicKey'], key1),
860
+ kidFragment: '#key-0',
861
+ id: expect.stringMatching(OBJECT_ID_FORMAT),
862
+ encoding: KeyEncodings.HEX,
863
+ createdAt: expect.stringMatching(ISO_DATETIME_FORMAT),
864
+ });
865
+
866
+ const keyFromDb = await mongoDb().collection('keys').findOne();
867
+ expect(keyFromDb).toEqual({
868
+ _id: expect.any(ObjectId),
869
+ ...key1,
870
+ kidFragment: '#key-0',
871
+ tenantId: new ObjectId(tenant._id),
872
+ key: expect.any(String),
873
+ publicKey: expect.any(Object),
874
+ createdAt: expect.any(Date),
875
+ updatedAt: expect.any(Date),
876
+ });
877
+
878
+ const decryptedKey = await kms.exportKeyOrSecret(response.json.id);
879
+ expect(decryptedKey).toEqual({
880
+ ...omit(['key', 'publicKey'], key1),
881
+ id: response.json.id,
882
+ kidFragment: '#key-0',
883
+ privateJwk: { ...keyPair.privateKey, use: 'sig' },
884
+ tenantId: new ObjectId(tenant._id),
885
+ createdAt: expect.any(Date),
886
+ updatedAt: expect.any(Date),
887
+ });
888
+ const tenantFromDb = await tenantRepo.findOne(tenant._id);
889
+ expect(tenantFromDb).toEqual({
890
+ _id: new ObjectId(tenant._id),
891
+ did: orgDoc.id,
892
+ primaryAddress,
893
+ createdAt: expect.any(Date),
894
+ updatedAt: expect.any(Date),
895
+ });
896
+ });
897
+
898
+ it('should 404 for non-existing tenant', async () => {
899
+ const fooTenant = { _id: new ObjectId() };
900
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
901
+ const response = await fastify.injectJson({
902
+ method: 'POST',
903
+ url: `${buildKeysUrl({ tenant: fooTenant })}`,
904
+ payload: {
905
+ ...key1,
906
+ key: orgKey,
907
+ kidFragment: '#bad-kid-fragment',
908
+ },
909
+ });
910
+
911
+ expect(response.statusCode).toEqual(404);
912
+ expect(response.json).toEqual(
913
+ errorResponseMatcher({
914
+ error: 'Not Found',
915
+ errorCode: 'tenant_not_found',
916
+ message: `Tenant ${JSON.stringify({
917
+ tenantId: fooTenant._id,
918
+ })} not found`,
919
+ statusCode: 404,
920
+ })
921
+ );
922
+ });
923
+
924
+ it('should 400 with bad kidFragment', async () => {
925
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
926
+
927
+ const response = await fastify.injectJson({
928
+ method: 'POST',
929
+ url: buildKeysUrl({ tenant }),
930
+ payload: {
931
+ ...key1,
932
+ key: orgKey,
933
+ kidFragment: '#bad-kid-fragment',
934
+ },
935
+ });
936
+
937
+ expect(response.statusCode).toEqual(400);
938
+
939
+ const count = await mongoDb().collection('keys').countDocuments();
940
+ expect(count).toEqual(0);
941
+ });
942
+
943
+ it('should 400 with key that does not match the kid', async () => {
944
+ const key1 = omit(['tenantId'], await newKey({ tenant }));
945
+
946
+ const response = await fastify.injectJson({
947
+ method: 'POST',
948
+ url: buildKeysUrl({ tenant }),
949
+ payload: {
950
+ ...key1,
951
+ key: 'not-a-key',
952
+ },
953
+ });
954
+
955
+ expect(response.statusCode).toEqual(400);
956
+
957
+ const count = await mongoDb().collection('keys').countDocuments();
958
+ expect(count).toEqual(0);
959
+ });
960
+
961
+ it('should 400 with an unrecognized purpose', async () => {
962
+ const key1 = omit(
963
+ ['tenantId'],
964
+ await newKey({ tenant, purposes: ['unrecognized-purpose'] })
965
+ );
966
+
967
+ const response = await fastify.injectJson({
968
+ method: 'POST',
969
+ url: buildKeysUrl({ tenant }),
970
+ payload: {
971
+ ...key1,
972
+ key: orgKey,
973
+ },
974
+ });
975
+
976
+ expect(response.statusCode).toEqual(400);
977
+ expect(response.json).toEqual(
978
+ errorResponseMatcher({
979
+ error: 'Bad Request',
980
+ errorCode: 'missing_error_code',
981
+ message: 'Unrecognized purpose detected',
982
+ statusCode: 400,
983
+ })
984
+ );
985
+
986
+ const count = await mongoDb().collection('keys').countDocuments();
987
+ expect(count).toEqual(0);
988
+ });
989
+
990
+ it('should 400 with no purposes', async () => {
991
+ const key1 = omit(['tenantId'], await newKey({ tenant, purposes: [] }));
992
+
993
+ const response = await fastify.injectJson({
994
+ method: 'POST',
995
+ url: buildKeysUrl({ tenant }),
996
+ payload: {
997
+ ...key1,
998
+ key: orgKey,
999
+ },
1000
+ });
1001
+
1002
+ expect(response.statusCode).toEqual(400);
1003
+ expect(response.json).toEqual(
1004
+ errorResponseMatcher({
1005
+ error: 'Bad Request',
1006
+ errorCode: 'request_validation_failed',
1007
+ message: 'body/purposes must NOT have fewer than 1 items',
1008
+ statusCode: 400,
1009
+ })
1010
+ );
1011
+
1012
+ const count = await mongoDb().collection('keys').countDocuments();
1013
+ expect(count).toEqual(0);
1014
+ });
1015
+
1016
+ it('should 400 with duplicate purposes', async () => {
1017
+ const key1 = omit(
1018
+ ['tenantId'],
1019
+ await newKey({
1020
+ tenant,
1021
+ purposes: ['DLT_TRANSACTIONS', 'DLT_TRANSACTIONS'],
1022
+ })
1023
+ );
1024
+
1025
+ const response = await fastify.injectJson({
1026
+ method: 'POST',
1027
+ url: buildKeysUrl({ tenant }),
1028
+ payload: {
1029
+ ...key1,
1030
+ key: orgKey,
1031
+ },
1032
+ });
1033
+
1034
+ expect(response.statusCode).toEqual(400);
1035
+ expect(response.json).toEqual(
1036
+ errorResponseMatcher({
1037
+ error: 'Bad Request',
1038
+ errorCode: 'missing_error_code',
1039
+ message: 'Duplicate key purposes detected',
1040
+ statusCode: 400,
1041
+ })
1042
+ );
1043
+
1044
+ const count = await mongoDb().collection('keys').countDocuments();
1045
+ expect(count).toEqual(0);
1046
+ });
1047
+
1048
+ it('should 400 with unrecognized algorithm', async () => {
1049
+ const key1 = omit(
1050
+ ['tenantId'],
1051
+ await newKey({ tenant, algorithm: 'unrecognized-algorithm' })
1052
+ );
1053
+
1054
+ const response = await fastify.injectJson({
1055
+ method: 'POST',
1056
+ url: buildKeysUrl({ tenant }),
1057
+ payload: {
1058
+ ...key1,
1059
+ key: orgKey,
1060
+ },
1061
+ });
1062
+
1063
+ expect(response.statusCode).toEqual(400);
1064
+ expect(response.json).toEqual(
1065
+ errorResponseMatcher({
1066
+ error: 'Bad Request',
1067
+ errorCode: 'missing_error_code',
1068
+ message: 'Unrecognized algorithm',
1069
+ statusCode: 400,
1070
+ })
1071
+ );
1072
+
1073
+ const count = await mongoDb().collection('keys').countDocuments();
1074
+ expect(count).toEqual(0);
1075
+ });
1076
+
1077
+ it('should 400 with unrecognized encoding', async () => {
1078
+ const key1 = omit(
1079
+ ['tenantId'],
1080
+ await newKey({ tenant, encoding: 'unrecognized-encoding' })
1081
+ );
1082
+
1083
+ const response = await fastify.injectJson({
1084
+ method: 'POST',
1085
+ url: buildKeysUrl({ tenant }),
1086
+ payload: {
1087
+ ...key1,
1088
+ key: orgKey,
1089
+ },
1090
+ });
1091
+
1092
+ expect(response.statusCode).toEqual(400);
1093
+ expect(response.json).toEqual(
1094
+ errorResponseMatcher({
1095
+ error: 'Bad Request',
1096
+ message: 'Unrecognized encoding',
1097
+ errorCode: 'missing_error_code',
1098
+ statusCode: 400,
1099
+ })
1100
+ );
1101
+
1102
+ const count = await mongoDb().collection('keys').countDocuments();
1103
+ expect(count).toEqual(0);
1104
+ });
1105
+
1106
+ it('should 400 if private key is not provided', async () => {
1107
+ const key1 = omit(['tenantId', 'key'], await newKey({ tenant }));
1108
+
1109
+ const response = await fastify.injectJson({
1110
+ method: 'POST',
1111
+ url: buildKeysUrl({ tenant }),
1112
+ payload: {
1113
+ ...key1,
1114
+ kidFragment: '#key-0',
1115
+ encoding: KeyEncodings.JWK,
1116
+ },
1117
+ });
1118
+
1119
+ expect(response.statusCode).toEqual(400);
1120
+ expect(response.json).toEqual(
1121
+ errorResponseMatcher({
1122
+ error: 'Bad Request',
1123
+ errorCode: 'private_key_not_found',
1124
+ message: 'Private key not found',
1125
+ statusCode: 400,
1126
+ })
1127
+ );
1128
+ });
1129
+ });
1130
+ });