ml-testing-toolkit 18.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/.dockerignore +10 -0
  2. package/.grype.yaml +16 -0
  3. package/.ncurc.yaml +9 -0
  4. package/.nvmrc +1 -0
  5. package/.versionrc.js +16 -0
  6. package/CHANGELOG.md +504 -0
  7. package/CODEOWNERS +30 -0
  8. package/Dockerfile +42 -0
  9. package/Dockerfile-newman +13 -0
  10. package/LICENSE.md +9 -0
  11. package/README.md +119 -0
  12. package/assets/diagrams/architectural/architectural-diagram.svg +3 -0
  13. package/assets/diagrams/flow/flow-diagram.svg +3 -0
  14. package/assets/images/Sample-Response-Failure.png +0 -0
  15. package/assets/images/Screenshot 2020-04-16 at 22.58.04.png +0 -0
  16. package/assets/images/TLS-Enabled-on-Environment.png +0 -0
  17. package/assets/images/adapter-mutual-tls-enabled.png +0 -0
  18. package/assets/images/add-additional-input-values.png +0 -0
  19. package/assets/images/add-condition-button.png +0 -0
  20. package/assets/images/add-new-assertion.png +0 -0
  21. package/assets/images/add-new-input-value.png +0 -0
  22. package/assets/images/add-new-input-variable.png +0 -0
  23. package/assets/images/additional-transfers.png +0 -0
  24. package/assets/images/api-provisioning-add-new-api-confirmation.png +0 -0
  25. package/assets/images/api-provisioning-file-input-window.png +0 -0
  26. package/assets/images/api-provisioning-list-apis-view.png +0 -0
  27. package/assets/images/api-provisioning-menu-item.png +0 -0
  28. package/assets/images/apply_and_restart.jpg +0 -0
  29. package/assets/images/assess-request-or-response.png +0 -0
  30. package/assets/images/assess-response-equation-save.png +0 -0
  31. package/assets/images/assess-response-equation.png +0 -0
  32. package/assets/images/assess-response-status.png +0 -0
  33. package/assets/images/building-new-rules-file.png +0 -0
  34. package/assets/images/callback-rules-screen.png +0 -0
  35. package/assets/images/configurable-parameter-assertion.png +0 -0
  36. package/assets/images/configurable-parameter-currency.png +0 -0
  37. package/assets/images/configurable-parameter.png +0 -0
  38. package/assets/images/connection-manager-ui-opening.png +0 -0
  39. package/assets/images/create-inbound-user-simulator.png +0 -0
  40. package/assets/images/creating-new-rule-file.png +0 -0
  41. package/assets/images/dfsp-client-cacert.png +0 -0
  42. package/assets/images/dfsp-client-submit.png +0 -0
  43. package/assets/images/dfsp-client.png +0 -0
  44. package/assets/images/dfsp-p2p-happy-path.png +0 -0
  45. package/assets/images/dfsp-server-cacert.png +0 -0
  46. package/assets/images/dfsp-server-cert.png +0 -0
  47. package/assets/images/download-report.png +0 -0
  48. package/assets/images/drive_have_not_been_shared.jpg +0 -0
  49. package/assets/images/event-response-options.png +0 -0
  50. package/assets/images/expand-monitoring-messages.png +0 -0
  51. package/assets/images/fixed-response-sample.png +0 -0
  52. package/assets/images/header-selection.png +0 -0
  53. package/assets/images/heap_error_windows.jpg +0 -0
  54. package/assets/images/hosted-mode-docker-compose-intro.png +0 -0
  55. package/assets/images/hub-client-cert.png +0 -0
  56. package/assets/images/import-template.png +0 -0
  57. package/assets/images/inbound-requests-environment.png +0 -0
  58. package/assets/images/inbound-requests-scripts.png +0 -0
  59. package/assets/images/jws-certificate-submit.png +0 -0
  60. package/assets/images/jws-certificate.png +0 -0
  61. package/assets/images/jws-certs-keys.png +0 -0
  62. package/assets/images/jws-hub-certs-keys.png +0 -0
  63. package/assets/images/local-enable-jws-publickey.png +0 -0
  64. package/assets/images/local-mutual-tls-enabled.png +0 -0
  65. package/assets/images/local_drives_to_be_available.jpg +0 -0
  66. package/assets/images/mcm-environment-opening.png +0 -0
  67. package/assets/images/menu-items.png +0 -0
  68. package/assets/images/mock-response-sample.png +0 -0
  69. package/assets/images/monitoring-initial-state.png +0 -0
  70. package/assets/images/monitoring-messages.png +0 -0
  71. package/assets/images/new-empty-assertion.png +0 -0
  72. package/assets/images/opened-imported-template.png +0 -0
  73. package/assets/images/opening-default-settings.png +0 -0
  74. package/assets/images/opening-sync-response-rules.png +0 -0
  75. package/assets/images/opening-view.png +0 -0
  76. package/assets/images/outbound-display-opening-hub.png +0 -0
  77. package/assets/images/outbound-display-opening.png +0 -0
  78. package/assets/images/override-with-environment-variable.png +0 -0
  79. package/assets/images/populate-with-sample-body.png +0 -0
  80. package/assets/images/resource-selection.png +0 -0
  81. package/assets/images/rule-builder-select-api.png +0 -0
  82. package/assets/images/sample-condition-add-configurable-params.png +0 -0
  83. package/assets/images/sample-condition.png +0 -0
  84. package/assets/images/sample-editor.png +0 -0
  85. package/assets/images/sample-request.png +0 -0
  86. package/assets/images/sample-test-assertion.png +0 -0
  87. package/assets/images/send-transfer.png +0 -0
  88. package/assets/images/sending-single-test-case-1.png +0 -0
  89. package/assets/images/sending-single-test-case-2.png +0 -0
  90. package/assets/images/sending-test-cases.png +0 -0
  91. package/assets/images/server-certificates-submitted.png +0 -0
  92. package/assets/images/simulator-response.png +0 -0
  93. package/assets/images/simulator-scheme-adapter-endpoint.png +0 -0
  94. package/assets/images/summarized-view-of-rule.png +0 -0
  95. package/assets/images/template-window.png +0 -0
  96. package/assets/images/test-case-editor-console-log.png +0 -0
  97. package/assets/images/test-case-editor-environment-state.png +0 -0
  98. package/assets/images/test-case-editor-scripts.png +0 -0
  99. package/assets/images/test-case-editor.png +0 -0
  100. package/assets/images/testcase-definition-download.png +0 -0
  101. package/assets/images/testcase-definition-edit-meta-info.png +0 -0
  102. package/assets/images/testing-toolkit-mojaloop-testing-toolkit-endpoint.png +0 -0
  103. package/assets/images/tls-hub-certs-keys.png +0 -0
  104. package/assets/images/tls-jws-enabled-on-environment.png +0 -0
  105. package/assets/images/updated-sample-body-data.png +0 -0
  106. package/assets/images/using-configurable-parameter.png +0 -0
  107. package/assets/images/validation-rules-screen.png +0 -0
  108. package/assets/images/view-response.png +0 -0
  109. package/audit-ci.jsonc +7 -0
  110. package/connection-manager/docker-compose.yml +55 -0
  111. package/database/docker-compose.yml +16 -0
  112. package/docker/hosted-mode/docker-compose.yaml +107 -0
  113. package/docker/hosted-mode/keycloak/keycloak-realm.json +2298 -0
  114. package/docker/hosted-mode/mongo-init.sh +1 -0
  115. package/docker/hosted-mode-tls/docker-compose.yaml +171 -0
  116. package/docker/hosted-mode-tls/keycloak/keycloak-realm.json +2298 -0
  117. package/docker/hosted-mode-tls/mongo-init.sh +1 -0
  118. package/docker-compose.yml +62 -0
  119. package/documents/Mojaloop-Testing-Toolkit.md +296 -0
  120. package/documents/RULES_ENGINE.md +403 -0
  121. package/documents/User-Guide-API-Provisioning.md +121 -0
  122. package/documents/User-Guide-CLI.md +218 -0
  123. package/documents/User-Guide-Connection-Manager.md +282 -0
  124. package/documents/User-Guide-Frequently-Asked-Questions.md +39 -0
  125. package/documents/User-Guide-Hosted-Mode-Docker-Compose.md +110 -0
  126. package/documents/User-Guide-Installation.md +163 -0
  127. package/documents/User-Guide-Mojaloop-Testing-Toolkit.md +642 -0
  128. package/documents/User-Guide-OAuth-Server-Deployment.md +283 -0
  129. package/documents/User-Guide-Onboarding-DFSP.md +197 -0
  130. package/documents/User-Guide-Onboarding-HUB.md +191 -0
  131. package/documents/User-Guide.md +53 -0
  132. package/examples/collections/dfsp/p2p_failed_tests.json +7161 -0
  133. package/examples/collections/dfsp/p2p_fx_happy_path.json +502 -0
  134. package/examples/collections/dfsp/p2p_happy_path.json +350 -0
  135. package/examples/collections/dfsp/p2p_happy_path_extended.json +6106 -0
  136. package/examples/collections/dfsp/p2p_happy_path_jws.json +511 -0
  137. package/examples/collections/dfsp/p2p_payee_assertions_websocket.json +441 -0
  138. package/examples/collections/dfsp/sample.json +5029 -0
  139. package/examples/collections/dfsp/transaction_request_service.json +240 -0
  140. package/examples/collections/fxp/FXP.json +264 -0
  141. package/examples/collections/fxp/SDK_backend.json +98 -0
  142. package/examples/collections/fxp/SDK_outbound.json +163 -0
  143. package/examples/collections/hub/hub_01_p2p_happy_path/hub_p2p_receive_quote.json +400 -0
  144. package/examples/collections/hub/hub_01_p2p_happy_path/hub_p2p_send_quote.json +395 -0
  145. package/examples/collections/hub/hub_02_block_transfer/hub_block_transfer.json +393 -0
  146. package/examples/collections/hub/hub_03_funds_in_out/hub_funds_in.json +224 -0
  147. package/examples/collections/hub/hub_03_funds_in_out/hub_funds_out.json +780 -0
  148. package/examples/collections/hub/hub_04_settlements/hub_settlements.json +3138 -0
  149. package/examples/collections/hub/hub_05_transfer_negative_scenarios/hub_transfer_negative_payee_abort.json +475 -0
  150. package/examples/collections/hub/hub_05_transfer_negative_scenarios/hub_transfer_negative_payee_invalid_fulfillment.json +370 -0
  151. package/examples/collections/hub/hub_05_transfer_negative_scenarios/hub_transfer_negative_transfer_timeout.json +262 -0
  152. package/examples/collections/hub/hub_06_transaction_requests_service/hub_trs_authorizations.json +117 -0
  153. package/examples/collections/hub/hub_06_transaction_requests_service/hub_trs_error_framework.json +591 -0
  154. package/examples/collections/hub/hub_06_transaction_requests_service/hub_trs_received_state.json +379 -0
  155. package/examples/collections/hub/hub_06_transaction_requests_service/hub_trs_reject_state.json +361 -0
  156. package/examples/collections/hub/hub_07_quoting_service.json +525 -0
  157. package/examples/collections/hub/hub_08_participant_inactive_stop_transfers.json +706 -0
  158. package/examples/collections/hub/hub_09_duplicate_handling_transfers.json +1377 -0
  159. package/examples/collections/hub/hub_10_on_us_transfers.json +245 -0
  160. package/examples/collections/hub/hub_11_accented_and_spl_chars.json +629 -0
  161. package/examples/collections/hub/hub_12_fspiop_version_1.1.json +646 -0
  162. package/examples/collections/hub/hub_13_bulk_transfers.json +1857 -0
  163. package/examples/collections/iso20022/self_referencing_iso20022.json +926 -0
  164. package/examples/collections/provisioning/testingtoolkitdfsp.json +904 -0
  165. package/examples/environments/dfsp_local_environment.json +46 -0
  166. package/examples/environments/hub_local_environment.json +57 -0
  167. package/jest.config.js +17 -0
  168. package/package.json +199 -0
  169. package/sbom-v18.12.4.csv +1553 -0
  170. package/secrets/keygen.sh +5 -0
  171. package/secrets/privatekey.pem +27 -0
  172. package/secrets/publickey.cer +21 -0
  173. package/secrets/tls/01.pem +132 -0
  174. package/secrets/tls/createSecrets.sh +20 -0
  175. package/secrets/tls/hub_client.csr +32 -0
  176. package/secrets/tls/hub_client_cacert.pem +35 -0
  177. package/secrets/tls/hub_client_cakey.pem +52 -0
  178. package/secrets/tls/hub_client_key.key +52 -0
  179. package/secrets/tls/hub_server.csr +31 -0
  180. package/secrets/tls/hub_server_cacert.pem +35 -0
  181. package/secrets/tls/hub_server_cakey.pem +52 -0
  182. package/secrets/tls/hub_server_cert.pem +132 -0
  183. package/secrets/tls/hub_server_key.key +52 -0
  184. package/secrets/tls/index.txt +1 -0
  185. package/secrets/tls/index.txt.attr +1 -0
  186. package/secrets/tls/openssl-client.cnf +36 -0
  187. package/secrets/tls/openssl-clientca.cnf +71 -0
  188. package/secrets/tls/openssl-server.cnf +39 -0
  189. package/secrets/tls/openssl-serverca.cnf +71 -0
  190. package/secrets/tls/serial.txt +1 -0
  191. package/spec_files/api_definitions/als_admin_1.1/api_spec.yaml +804 -0
  192. package/spec_files/api_definitions/central_admin_1.0/api_spec.yaml +1850 -0
  193. package/spec_files/api_definitions/central_admin_1.0/response_map.json +96 -0
  194. package/spec_files/api_definitions/central_admin_old_9.3/api_spec.yaml +2467 -0
  195. package/spec_files/api_definitions/central_admin_old_9.3/response_map.json +96 -0
  196. package/spec_files/api_definitions/fspiop_1.0/api_spec.yaml +4187 -0
  197. package/spec_files/api_definitions/fspiop_1.0/callback_map.json +568 -0
  198. package/spec_files/api_definitions/fspiop_1.0/mockRef.json +79 -0
  199. package/spec_files/api_definitions/fspiop_1.0/trigger_templates/transaction_request_followup.json +126 -0
  200. package/spec_files/api_definitions/fspiop_1.0/trigger_templates/transaction_request_followup_quotes_only.json +97 -0
  201. package/spec_files/api_definitions/fspiop_1.1/api_spec.yaml +3778 -0
  202. package/spec_files/api_definitions/fspiop_1.1/callback_map.json +568 -0
  203. package/spec_files/api_definitions/fspiop_1.1/mockRef.json +79 -0
  204. package/spec_files/api_definitions/fspiop_1.1/trigger_templates/transaction_request_followup.json +125 -0
  205. package/spec_files/api_definitions/fspiop_2.0/api_spec.yaml +4839 -0
  206. package/spec_files/api_definitions/fspiop_2.0/callback_map.json +716 -0
  207. package/spec_files/api_definitions/fspiop_2.0/mockRef.json +79 -0
  208. package/spec_files/api_definitions/fspiop_2.0/trigger_templates/transaction_request_followup.json +125 -0
  209. package/spec_files/api_definitions/fspiop_2.0_iso20022/api_spec.yaml +8331 -0
  210. package/spec_files/api_definitions/fspiop_2.0_iso20022/callback_map.json +508 -0
  211. package/spec_files/api_definitions/fspiop_2.0_iso20022/mockRef.json +66 -0
  212. package/spec_files/api_definitions/fx-api_2.0/api_spec.yaml +1768 -0
  213. package/spec_files/api_definitions/fx-api_2.0/callback_map.json +188 -0
  214. package/spec_files/api_definitions/fx-api_2.0/mockRef.json +83 -0
  215. package/spec_files/api_definitions/mojaloop_sdk_outbound_scheme_adapter_1.0/api_spec.yaml +2612 -0
  216. package/spec_files/api_definitions/mojaloop_sdk_outbound_scheme_adapter_1.0/mockRef.json +22 -0
  217. package/spec_files/api_definitions/mojaloop_sdk_outbound_scheme_adapter_1.0/response_map.json +35 -0
  218. package/spec_files/api_definitions/mojaloop_simulator_0.1/api_spec.yaml +225 -0
  219. package/spec_files/api_definitions/mojaloop_simulator_sim_1.4/api_spec.yaml +1087 -0
  220. package/spec_files/api_definitions/mojaloop_simulator_sim_1.4/mockRef.json +75 -0
  221. package/spec_files/api_definitions/mojaloop_simulator_sim_1.4/response_map.json +55 -0
  222. package/spec_files/api_definitions/payment_manager_1.4/api_spec.yaml +1389 -0
  223. package/spec_files/api_definitions/sdk-scheme-adapter-backend-v2_1_0-openapi3-snippets_2.1/api_spec.yaml +2834 -0
  224. package/spec_files/api_definitions/sdk-scheme-adapter-outbound-v2_1_0-openapi3-snippets_2.1/api_spec.yaml +3449 -0
  225. package/spec_files/api_definitions/settlements_1.0/api_spec.yaml +983 -0
  226. package/spec_files/api_definitions/settlements_1.0/mockRef.json +38 -0
  227. package/spec_files/api_definitions/settlements_1.0/response_map.json +34 -0
  228. package/spec_files/api_definitions/settlements_2.0/api_spec.yaml +1001 -0
  229. package/spec_files/api_definitions/settlements_2.0/mockRef.json +38 -0
  230. package/spec_files/api_definitions/settlements_2.0/response_map.json +34 -0
  231. package/spec_files/api_definitions/thirdparty_sdk_outbound_0.1/api_spec.yaml +2139 -0
  232. package/spec_files/reports/templates/newman/html_template.html +1202 -0
  233. package/spec_files/reports/templates/newman/pdf_template.html +790 -0
  234. package/spec_files/reports/templates/testcase_definition/table_view.html +1602 -0
  235. package/spec_files/rules_callback/config.json +3 -0
  236. package/spec_files/rules_callback/default.json +2698 -0
  237. package/spec_files/rules_callback/p2p-limit.json +129 -0
  238. package/spec_files/rules_forward/config.json +3 -0
  239. package/spec_files/rules_forward/default.json +482 -0
  240. package/spec_files/rules_response/config.json +3 -0
  241. package/spec_files/rules_response/default.json +295 -0
  242. package/spec_files/rules_validation/config.json +3 -0
  243. package/spec_files/rules_validation/default.json +1 -0
  244. package/spec_files/rules_validation/p2p-limit.json +55 -0
  245. package/spec_files/system_config.json +175 -0
  246. package/spec_files/user_config.json +109 -0
  247. package/src/index.js +67 -0
  248. package/src/lib/MyEventEmitter.js +54 -0
  249. package/src/lib/api-management.js +143 -0
  250. package/src/lib/api-routes/config.js +83 -0
  251. package/src/lib/api-routes/history.js +139 -0
  252. package/src/lib/api-routes/keycloak.js +54 -0
  253. package/src/lib/api-routes/longpolling.js +70 -0
  254. package/src/lib/api-routes/oauth2.js +149 -0
  255. package/src/lib/api-routes/objectstore.js +53 -0
  256. package/src/lib/api-routes/openapi.js +224 -0
  257. package/src/lib/api-routes/outbound.js +134 -0
  258. package/src/lib/api-routes/reports.js +72 -0
  259. package/src/lib/api-routes/rules.js +356 -0
  260. package/src/lib/api-routes/samples.js +92 -0
  261. package/src/lib/api-routes/server-logs.js +44 -0
  262. package/src/lib/api-routes/settings.js +71 -0
  263. package/src/lib/api-server.js +135 -0
  264. package/src/lib/arrayStore.js +101 -0
  265. package/src/lib/callbackHandler.js +201 -0
  266. package/src/lib/config.js +177 -0
  267. package/src/lib/configuration-providers/mb-connection-manager.js +625 -0
  268. package/src/lib/db/adapters/dbAdapter.js +184 -0
  269. package/src/lib/db/dfspMockUsers.js +64 -0
  270. package/src/lib/db/models/mongoDBWrapper.js +78 -0
  271. package/src/lib/eventListenerClient/inboundEventListener.js +176 -0
  272. package/src/lib/fileAdapter.js +57 -0
  273. package/src/lib/httpAgentStore.js +135 -0
  274. package/src/lib/importExport.js +186 -0
  275. package/src/lib/jws/JwsSigning.js +141 -0
  276. package/src/lib/loadSamples.js +128 -0
  277. package/src/lib/logger.js +20 -0
  278. package/src/lib/longpollingEmitter.js +56 -0
  279. package/src/lib/metrics.js +51 -0
  280. package/src/lib/mocking/custom-functions/generic.js +57 -0
  281. package/src/lib/mocking/middleware-functions/ilpModel.js +238 -0
  282. package/src/lib/mocking/middleware-functions/quotesAssociation.js +75 -0
  283. package/src/lib/mocking/middleware-functions/transactionRequestsService.js +78 -0
  284. package/src/lib/mocking/openApiDefinitionsModel.js +64 -0
  285. package/src/lib/mocking/openApiMockHandler.js +466 -0
  286. package/src/lib/mocking/openApiRulesEngine.js +492 -0
  287. package/src/lib/mocking/openApiVersionTools.js +136 -0
  288. package/src/lib/mocking/transformers/fspiopToISO20022.js +230 -0
  289. package/src/lib/mocking/transformers/index.js +41 -0
  290. package/src/lib/notificationEmitter.js +64 -0
  291. package/src/lib/oauth/KeycloakHelper.js +220 -0
  292. package/src/lib/oauth/LoginService.js +133 -0
  293. package/src/lib/oauth/OAuthHelper.js +181 -0
  294. package/src/lib/oauth/OAuthValidator.js +118 -0
  295. package/src/lib/oauth/Wso2Client.js +64 -0
  296. package/src/lib/objectStore/inMemoryImpl.js +50 -0
  297. package/src/lib/objectStore/objectStoreInterface.js +51 -0
  298. package/src/lib/objectStore.js +122 -0
  299. package/src/lib/report-generator/generator.js +126 -0
  300. package/src/lib/report-generator/helpers.js +154 -0
  301. package/src/lib/requestLogger.js +190 -0
  302. package/src/lib/resources/wso2carbon-publickey.cert +20 -0
  303. package/src/lib/rulesEngine.js +95 -0
  304. package/src/lib/rulesEngineModel.js +463 -0
  305. package/src/lib/scripting-engines/postman-sandbox.js +142 -0
  306. package/src/lib/scripting-engines/vm-javascript-sandbox.js +294 -0
  307. package/src/lib/server-logs/adapters/elastic-search.js +102 -0
  308. package/src/lib/server-logs/adapters/grafana.js +0 -0
  309. package/src/lib/server-logs/index.js +75 -0
  310. package/src/lib/socket-server.js +55 -0
  311. package/src/lib/storageAdapter.js +109 -0
  312. package/src/lib/test-outbound/TestCaseRunner.js +173 -0
  313. package/src/lib/test-outbound/getTracing.js +19 -0
  314. package/src/lib/test-outbound/outbound-initiator.js +1107 -0
  315. package/src/lib/uniqueIdGenerator.js +35 -0
  316. package/src/lib/utils.js +89 -0
  317. package/src/lib/utilsInternal.js +56 -0
  318. package/src/lib/webSocketClient/WebSocketClientManager.js +197 -0
  319. package/src/server.js +218 -0
@@ -0,0 +1,186 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ - Name Surname <name.surname@mojaloop.io>
24
+
25
+ * ModusBox
26
+ * Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
27
+ --------------
28
+ ******/
29
+
30
+ const { rmdirAsync } = require('./utils')
31
+ const AdmZip = require('adm-zip')
32
+ const Config = require('./config')
33
+ const { Engine } = require('json-rules-engine')
34
+ const CONFIG_FILE_NAME = 'config.json'
35
+ const storageAdapter = require('./storageAdapter')
36
+
37
+ const exportSpecFiles = async (ruleTypes, user) => {
38
+ const zip = new AdmZip()
39
+
40
+ for (const index in ruleTypes) {
41
+ const ruleType = ruleTypes[index]
42
+ if (user) {
43
+ if (ruleType.endsWith('.json')) {
44
+ const filename = `spec_files/${ruleType}`
45
+ const document = await storageAdapter.read(filename, user)
46
+ zip.addFile(filename, Buffer.from(JSON.stringify(document.data)))
47
+ } else {
48
+ const filename = `spec_files/${ruleType}/`
49
+ const documents = await storageAdapter.read(filename, user)
50
+ for (const index in documents) {
51
+ const id = filename + documents[index]
52
+ const document = await storageAdapter.read(id, user)
53
+ zip.addFile(id, Buffer.from(JSON.stringify(document.data)))
54
+ }
55
+ }
56
+ } else {
57
+ if (ruleType.endsWith('.json')) {
58
+ const filename = `spec_files/${ruleType}`
59
+ zip.addLocalFile(filename)
60
+ } else {
61
+ const filename = `spec_files/${ruleType}/`
62
+ zip.addLocalFolder(filename, ruleType)
63
+ }
64
+ }
65
+ }
66
+ return {
67
+ namePrefix: ruleTypes.length > 1 ? 'spec_files' : ruleTypes[0],
68
+ buffer: zip.toBuffer()
69
+ }
70
+ }
71
+
72
+ const validateRules = (entryName, ruleType, ruleVersion, rules) => {
73
+ const engine = new Engine()
74
+ rules.forEach(rule => {
75
+ if (rule.type !== ruleType) {
76
+ throw new Error(`validation error: rule ${rule.ruleId} in ${entryName} should be of type ${ruleType}`)
77
+ }
78
+ if (rule.version > ruleVersion) {
79
+ throw new Error(`validation error: rule ${rule.ruleId} in ${entryName} version should at most ${ruleVersion}`)
80
+ }
81
+ try {
82
+ engine.addRule(rule)
83
+ } catch (err) {
84
+ throw new Error(`validation error: rule ${rule.ruleId} in ${entryName} is not valid: ${err.message}`)
85
+ }
86
+ })
87
+ }
88
+
89
+ const validateInputData = (zipEntries, options) => {
90
+ const entries = []
91
+ zipEntries.forEach((zipEntry) => {
92
+ const entryName = zipEntry.entryName
93
+ const entryData = JSON.parse(zipEntry.getData().toString('utf-8'))
94
+ entries.push({
95
+ name: entryName,
96
+ data: entryData
97
+ })
98
+ const element = entryName.split('/')[0]
99
+ if (options.includes(element)) {
100
+ switch (element) {
101
+ case 'rules_response': {
102
+ if (entryName !== `rules_response/${CONFIG_FILE_NAME}`) {
103
+ validateRules(entryName, 'response', Config.getSystemConfig().CONFIG_VERSIONS.response, entryData)
104
+ }
105
+ break
106
+ }
107
+ case 'rules_validation': {
108
+ if (entryName !== `rules_validation/${CONFIG_FILE_NAME}`) {
109
+ validateRules(entryName, 'validation', Config.getSystemConfig().CONFIG_VERSIONS.validation, entryData)
110
+ }
111
+ break
112
+ }
113
+ case 'rules_callback': {
114
+ if (entryName !== `rules_callback/${CONFIG_FILE_NAME}`) {
115
+ validateRules(entryName, 'callback', Config.getSystemConfig().CONFIG_VERSIONS.callback, entryData)
116
+ }
117
+ break
118
+ }
119
+ case 'user_config.json': {
120
+ const userSettingsVersion = Config.getSystemConfig().CONFIG_VERSIONS.userSettings
121
+ if (entryData.VERSION > userSettingsVersion) {
122
+ throw new Error(`validation error: user_config.json version ${entryData.VERSION} not supproted be at most ${userSettingsVersion}`)
123
+ }
124
+ break
125
+ }
126
+ }
127
+ }
128
+ })
129
+ return entries
130
+ }
131
+
132
+ const extractData = async (zip, options, entries, user) => {
133
+ for (const index in options) {
134
+ if (user) {
135
+ for (const index in entries) {
136
+ const id = entries[index].name
137
+ const data = entries[index].data
138
+ await storageAdapter.upsert(id, data, user)
139
+ }
140
+ } else {
141
+ const option = options[index]
142
+ if (option === 'user_config.json') {
143
+ zip.extractEntryTo(option, 'spec_files', false, true)
144
+ } else {
145
+ let deleted = false
146
+ for (const index in entries) {
147
+ const entry = entries[index].name
148
+ if (entry.startsWith(option)) {
149
+ if (!deleted) {
150
+ await rmdirAsync(`spec_files/${option}`, { recursive: true })
151
+ deleted = true
152
+ }
153
+ zip.extractEntryTo(entry, `spec_files/${option}`, false)
154
+ }
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ const importSpecFiles = async (data, options, user) => {
162
+ const zip = new AdmZip(Buffer.from(data))
163
+ const entries = validateInputData(zip.getEntries(), options)
164
+ await extractData(zip, options, entries, user)
165
+ }
166
+
167
+ const exportSpecFile = async (filepath, user) => {
168
+ const filename = `spec_files/${filepath}`
169
+ const document = await storageAdapter.read(filename, user)
170
+ const documentBuffer = Buffer.from(JSON.stringify(document.data))
171
+ return {
172
+ buffer: documentBuffer
173
+ }
174
+ }
175
+
176
+ const importSpecFile = async (data, filePath, user) => {
177
+ const dataBuffer = JSON.parse(Buffer.from(data).toString())
178
+ await storageAdapter.upsert(`spec_files/${filePath}`, dataBuffer, user)
179
+ }
180
+
181
+ module.exports = {
182
+ exportSpecFiles,
183
+ importSpecFiles,
184
+ exportSpecFile,
185
+ importSpecFile
186
+ }
@@ -0,0 +1,141 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ - Name Surname <name.surname@mojaloop.io>
24
+
25
+ * ModusBox
26
+ * Vijaya Kumar Guthi <vijaya.guthi@modusbox.com> (Original Author)
27
+ --------------
28
+ ******/
29
+
30
+ // const config = {}
31
+
32
+ const Config = require('../config')
33
+ const { Jws } = require('@mojaloop/sdk-standard-components')
34
+ const ConnectionProvider = require('../configuration-providers/mb-connection-manager')
35
+ const atob = require('atob')
36
+
37
+ const validate = async (req) => {
38
+ const userConfig = await Config.getUserConfig()
39
+ if (userConfig.VALIDATE_INBOUND_JWS) {
40
+ if (req.method === 'get') {
41
+ return false
42
+ }
43
+ if (req.method === 'put' && req.path.startsWith('/parties/') && !userConfig.VALIDATE_INBOUND_PUT_PARTIES_JWS) {
44
+ return false
45
+ }
46
+
47
+ const certificate = await ConnectionProvider.getUserDfspJWSCerts(req.headers['fspiop-source'])
48
+ return validateWithCert(req.headers, req.payload, certificate)
49
+ }
50
+ }
51
+
52
+ const validateWithCert = (headers, body, certificate) => {
53
+ const reqOpts = {
54
+ headers,
55
+ body,
56
+ resolveWithFullResponse: true,
57
+ simple: false
58
+ }
59
+ const keys = {}
60
+ keys[headers['fspiop-source']] = certificate
61
+
62
+ const jwsValidator = new Jws.validator({ // eslint-disable-line
63
+ validationKeys: keys
64
+ })
65
+
66
+ try {
67
+ jwsValidator.validate(reqOpts)
68
+ return true
69
+ } catch (err) {
70
+ throw new Error(err.toString())
71
+ }
72
+ }
73
+
74
+ const validateProtectedHeaders = (headers) => {
75
+ if (!headers['fspiop-signature']) {
76
+ throw new Error('fspiop-signature is missing in the headers')
77
+ }
78
+ const { protectedHeader } = JSON.parse(headers['fspiop-signature'])
79
+ const decodedProtectedHeader = JSON.parse(atob(protectedHeader))
80
+ const jwsValidator = new Jws.validator({ // eslint-disable-line
81
+ validationKeys: []
82
+ })
83
+ jwsValidator._validateProtectedHeader(headers, decodedProtectedHeader)
84
+ return true
85
+ }
86
+
87
+ const sign = async (req) => {
88
+ const userConfig = await Config.getUserConfig()
89
+ if (userConfig.JWS_SIGN) {
90
+ if (req.method === 'get') {
91
+ return false
92
+ }
93
+
94
+ if (req.method === 'put' && req.path.startsWith('/parties/') && !userConfig.JWS_SIGN_PUT_PARTIES) {
95
+ return false
96
+ }
97
+ const jwsSigningKey = await ConnectionProvider.getTestingToolkitDfspJWSPrivateKey()
98
+ return signWithKey(req, jwsSigningKey)
99
+ }
100
+ }
101
+
102
+ const signWithKey = (req, jwsSigningKey) => {
103
+ const jwsSigner = new Jws.signer({ // eslint-disable-line
104
+ signingKey: jwsSigningKey
105
+ })
106
+ const reqOpts = {
107
+ method: req.method,
108
+ uri: req.url,
109
+ headers: req.headers,
110
+ body: JSON.stringify(req.data),
111
+ agent: 'testingtoolkit',
112
+ resolveWithFullResponse: true,
113
+ simple: false
114
+ }
115
+ if (reqOpts.headers['FSPIOP-Source']) {
116
+ reqOpts.headers['fspiop-source'] = reqOpts.headers['FSPIOP-Source']
117
+ delete reqOpts.headers['FSPIOP-Source']
118
+ }
119
+ if (reqOpts.headers['FSPIOP-Destination']) {
120
+ reqOpts.headers['fspiop-destination'] = reqOpts.headers['FSPIOP-Destination']
121
+ delete reqOpts.headers['FSPIOP-Destination']
122
+ }
123
+ delete reqOpts.headers['FSPIOP-Signature']
124
+ delete reqOpts.headers['FSPIOP-URI']
125
+ delete reqOpts.headers['FSPIOP-HTTP-Method']
126
+
127
+ try {
128
+ jwsSigner.sign(reqOpts)
129
+ return true
130
+ } catch (err) {
131
+ throw new Error(err.toString())
132
+ }
133
+ }
134
+
135
+ module.exports = {
136
+ validate,
137
+ validateWithCert,
138
+ validateProtectedHeaders,
139
+ sign,
140
+ signWithKey
141
+ }
@@ -0,0 +1,128 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ - Name Surname <name.surname@mojaloop.io>
24
+
25
+ * ModusBox
26
+ * Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
27
+ --------------
28
+ ******/
29
+ const { readFileAsync, readRecursiveAsync, fileStatAsync } = require('./utils')
30
+ const fs = require('fs')
31
+
32
+ // load collections or environments
33
+ const getCollectionsOrEnvironments = async (exampleType, type) => {
34
+ const data = await readRecursiveAsync(`examples/${exampleType}/${type || ''}`)
35
+ return data.filter(filename => filename.endsWith('.json'))
36
+ }
37
+
38
+ // load collections or environments with file sizes
39
+ const getCollectionsOrEnvironmentsWithFileSize = async (exampleType, type) => {
40
+ const dir = `examples/${exampleType}/${type || ''}`
41
+ const data = await readRecursiveAsync(dir)
42
+ const jsonFileList = data.filter(filename => filename.endsWith('.json'))
43
+ const jsonFileListWithFileSize = jsonFileList.map(file => {
44
+ return {
45
+ name: file,
46
+ size: fs.statSync(file).size
47
+ }
48
+ })
49
+ return jsonFileListWithFileSize
50
+ }
51
+
52
+ // load samples content
53
+ const getSample = async (queryParams) => {
54
+ const collections = []
55
+ if (queryParams.collections) {
56
+ for (const i in queryParams.collections) {
57
+ const collection = await readFileAsync(queryParams.collections[i], 'utf8')
58
+ collections.push(JSON.parse(collection))
59
+ }
60
+ }
61
+ const sample = {
62
+ name: null,
63
+ options: null,
64
+ inputValues: null,
65
+ test_cases: null
66
+ }
67
+
68
+ if (queryParams.environment) {
69
+ const envContent = JSON.parse(await readFileAsync(queryParams.environment, 'utf8'))
70
+ sample.inputValues = envContent.inputValues
71
+ sample.options = envContent.options
72
+ }
73
+
74
+ if (collections.length > 1) {
75
+ sample.name = 'multi'
76
+ sample.test_cases = []
77
+ let index = 1
78
+ collections.forEach(collection => {
79
+ collection.test_cases.forEach(testCase => {
80
+ const { id, ...remainingTestCaseProps } = testCase
81
+ sample.test_cases.push({
82
+ id: index++,
83
+ ...remainingTestCaseProps
84
+ })
85
+ })
86
+ })
87
+ } else if (collections.length === 1) {
88
+ sample.name = collections[0].name
89
+ sample.test_cases = collections[0].test_cases
90
+ }
91
+ return sample
92
+ }
93
+
94
+ // load samples content
95
+ const getSampleWithFolderWise = async (queryParams) => {
96
+ const collections = []
97
+ if (queryParams.collections) {
98
+ for (const i in queryParams.collections) {
99
+ const fileContent = await readFileAsync(queryParams.collections[i], 'utf8')
100
+ const fileStat = await fileStatAsync(queryParams.collections[i])
101
+ // collections.push(JSON.parse(collection))
102
+ collections.push({
103
+ name: queryParams.collections[i],
104
+ path: queryParams.collections[i],
105
+ size: fileStat.size,
106
+ modified: fileStat.mtime,
107
+ content: JSON.parse(fileContent)
108
+ })
109
+ }
110
+ }
111
+
112
+ let environment = {}
113
+ if (queryParams.environment) {
114
+ environment = JSON.parse(await readFileAsync(queryParams.environment, 'utf8')).inputValues
115
+ }
116
+
117
+ return {
118
+ collections,
119
+ environment
120
+ }
121
+ }
122
+
123
+ module.exports = {
124
+ getCollectionsOrEnvironments,
125
+ getCollectionsOrEnvironmentsWithFileSize,
126
+ getSample,
127
+ getSampleWithFolderWise
128
+ }
@@ -0,0 +1,20 @@
1
+ const { loggerFactory, LOG_LEVELS } = require('@mojaloop/sdk-standard-components').Logger
2
+ const { hostname } = require('node:os')
3
+
4
+ const createLogger = (conf = {}) => {
5
+ const {
6
+ context = {
7
+ hostname: hostname()
8
+ },
9
+ isJsonOutput = false
10
+ } = conf
11
+
12
+ return loggerFactory({ context, isJsonOutput })
13
+ }
14
+
15
+ const logger = createLogger() // global logger
16
+
17
+ module.exports = {
18
+ logger,
19
+ LOG_LEVELS
20
+ }
@@ -0,0 +1,56 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ - Name Surname <name.surname@mojaloop.io>
24
+
25
+ * ModusBox
26
+ * Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
27
+ --------------
28
+ ******/
29
+
30
+ const MyEventEmitter = require('./MyEventEmitter')
31
+ const objectStore = require('./objectStore')
32
+
33
+ const LONGPOLLING_TIMEOUT = 5000
34
+
35
+ const setAssertionStoreEmitter = (storedObject, eventPath, res, user) => {
36
+ let emitterType
37
+ switch (storedObject) {
38
+ case 'requests': emitterType = 'assertionRequest'; break
39
+ case 'callbacks': emitterType = 'assertionCallback'; break
40
+ }
41
+ const emitter = MyEventEmitter.getEmitter(emitterType, user)
42
+ const timer = setTimeout(() => {
43
+ emitter.removeAllListeners(eventPath)
44
+ res.status(500).json({ error: 'Timed out' })
45
+ }, LONGPOLLING_TIMEOUT)
46
+
47
+ emitter.once(eventPath, (data) => {
48
+ clearTimeout(timer)
49
+ objectStore.popObject(storedObject, eventPath, user)
50
+ res.status(200).json(data)
51
+ })
52
+ }
53
+
54
+ module.exports = {
55
+ setAssertionStoreEmitter
56
+ }
@@ -0,0 +1,51 @@
1
+ const Metrics = require('@mojaloop/central-services-metrics')
2
+
3
+ module.exports = function metricsMiddleware (config = {}) {
4
+ Metrics.getDefaultRegister().clear()
5
+ Metrics.setup({
6
+ timeout: 5000,
7
+ defaultLabels: {},
8
+ ...config
9
+ })
10
+
11
+ const client = Metrics.getClient()
12
+ const assertSuccess = new client.Counter({
13
+ name: 'assert_success_total',
14
+ help: 'Successful assertions',
15
+ labelNames: ['request', 'test']
16
+ })
17
+ const assertFail = new client.Counter({
18
+ name: 'assert_fail_total',
19
+ help: 'Failed assertions',
20
+ labelNames: ['request', 'test']
21
+ })
22
+ const testSuccess = new client.Counter({
23
+ name: 'test_success_total',
24
+ help: 'Successful tests',
25
+ labelNames: ['template']
26
+ })
27
+ const testFail = new client.Counter({
28
+ name: 'test_fail_total',
29
+ help: 'Failed tests',
30
+ labelNames: ['template']
31
+ })
32
+
33
+ const metrics = {
34
+ assertSuccess: { add (value, labels) { assertSuccess.inc(labels, value) } },
35
+ assertFail: { add (value, labels) { assertFail.inc(labels, value) } },
36
+ testSuccess: { add (value, labels) { testSuccess.inc(labels, value) } },
37
+ testFail: { add (value, labels) { testFail.inc(labels, value) } }
38
+ }
39
+
40
+ return (req, res, next) => {
41
+ if (req.url === '/metrics') {
42
+ res.set('Content-Type', 'text/plain; version=0.0.4')
43
+ Metrics.getMetricsForPrometheus().then(metrics => {
44
+ res.send(metrics)
45
+ })
46
+ } else {
47
+ req.metrics = metrics
48
+ next()
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,57 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ - Name Surname <name.surname@mojaloop.io>
24
+
25
+ * ModusBox
26
+ * Vijaya Kumar Guthi <vijaya.guthi@modusbox.com> (Original Author)
27
+ --------------
28
+ ******/
29
+
30
+ const { monotonicFactory } = require('ulidx')
31
+
32
+ const generateUUID = () => {
33
+ const uuid = require('uuid')
34
+ return uuid.v4()
35
+ }
36
+
37
+ const curDate = () => {
38
+ return (new Date()).toUTCString()
39
+ }
40
+
41
+ const curDateISO = () => {
42
+ return (new Date()).toISOString()
43
+ }
44
+
45
+ const generateULID = monotonicFactory()
46
+
47
+ const generateID = (options) => {
48
+ return options.generateIDType === 'uuid' ? generateUUID() : generateULID()
49
+ }
50
+
51
+ module.exports = {
52
+ generateUUID,
53
+ generateULID,
54
+ generateID,
55
+ curDate,
56
+ curDateISO
57
+ }