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,463 @@
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>
27
+ * Vijaya Kumar Guthi <vijaya.guthi@modusbox.com> (Original Author)
28
+ --------------
29
+ ******/
30
+
31
+ const RulesEngine = require('./rulesEngine')
32
+ const customLogger = require('./requestLogger')
33
+ const Config = require('./config')
34
+ const storageAdapter = require('./storageAdapter')
35
+
36
+ const DEFAULT_RULES_FILE_NAME = 'default.json'
37
+ const CONFIG_FILE_NAME = 'config.json'
38
+
39
+ const model = {
40
+ data: {
41
+ response: {
42
+ rulesFilePathPrefix: 'spec_files/rules_response/',
43
+ rules: null,
44
+ rulesEngine: null,
45
+ activeRulesFile: DEFAULT_RULES_FILE_NAME,
46
+ ruleType: 'response'
47
+ },
48
+ validation: {
49
+ rulesFilePathPrefix: 'spec_files/rules_validation/',
50
+ rules: null,
51
+ rulesEngine: null,
52
+ activeRulesFile: DEFAULT_RULES_FILE_NAME,
53
+ ruleType: 'validation'
54
+ },
55
+ callback: {
56
+ rulesFilePathPrefix: 'spec_files/rules_callback/',
57
+ rules: null,
58
+ rulesEngine: null,
59
+ activeRulesFile: DEFAULT_RULES_FILE_NAME,
60
+ ruleType: 'callback'
61
+ },
62
+ forward: {
63
+ rulesFilePathPrefix: 'spec_files/rules_forward/',
64
+ rules: null,
65
+ rulesEngine: null,
66
+ activeRulesFile: DEFAULT_RULES_FILE_NAME,
67
+ ruleType: 'forward'
68
+ }
69
+ }
70
+ }
71
+
72
+ const getModel = async (user, dfspType) => {
73
+ if (user) {
74
+ const dfspId = user.dfspId
75
+ if (!model[dfspId]) {
76
+ model[dfspId] = {}
77
+ }
78
+ if (!model[dfspId][dfspType]) {
79
+ model[dfspId][dfspType] = { ...model.data[dfspType] }
80
+ await getRulesFiles(model[dfspId][dfspType], user)
81
+ }
82
+ return model[dfspId][dfspType]
83
+ }
84
+ return model.data[dfspType]
85
+ }
86
+
87
+ // response rules
88
+ const reloadResponseRules = async (user) => {
89
+ const model = await getModel(user, 'response')
90
+ await reloadRules(model, user)
91
+ }
92
+
93
+ const setActiveResponseRulesFile = async (fileName, user) => {
94
+ const model = await getModel(user, 'response')
95
+ await setActiveRulesFile(model, fileName, user)
96
+ }
97
+
98
+ const getResponseRules = async (user) => {
99
+ const model = await getModel(user, 'response')
100
+ const rules = await getRules(model, user)
101
+ return rules
102
+ }
103
+
104
+ const getResponseRulesEngine = async (convertedRules, user) => {
105
+ const model = await getModel(user, 'response')
106
+ const rulesEngine = await getRulesEngine(model, convertedRules, user)
107
+ return rulesEngine
108
+ }
109
+
110
+ const getResponseRulesFiles = async (user) => {
111
+ // await getResponseRules(user)
112
+ const model = await getModel(user, 'response')
113
+ const rulesFiles = await getRulesFiles(model, user)
114
+ return rulesFiles
115
+ }
116
+
117
+ const getResponseRulesFileContent = async (fileName, user) => {
118
+ const model = await getModel(user, 'response')
119
+ const rulesFileContent = await getRulesFileContent(model, fileName, user)
120
+ return rulesFileContent
121
+ }
122
+
123
+ const setResponseRulesFileContent = async (fileName, fileContent, user) => {
124
+ const model = await getModel(user, 'response')
125
+ const rulesFileContent = await setRulesFileContent(model, fileName, fileContent, user)
126
+ return rulesFileContent
127
+ }
128
+
129
+ const deleteResponseRulesFile = async (fileName, user) => {
130
+ const model = await getModel(user, 'response')
131
+ const deleted = await deleteRulesFile(model, fileName, user)
132
+ return deleted
133
+ }
134
+
135
+ // validation rules
136
+ const reloadValidationRules = async (user) => {
137
+ const model = await getModel(user, 'validation')
138
+ await reloadRules(model, user)
139
+ }
140
+
141
+ const setActiveValidationRulesFile = async (fileName, user) => {
142
+ const model = await getModel(user, 'validation')
143
+ await setActiveRulesFile(model, fileName, user)
144
+ }
145
+
146
+ const getValidationRules = async (user) => {
147
+ const model = await getModel(user, 'validation')
148
+ const rules = await getRules(model, user)
149
+ return rules
150
+ }
151
+
152
+ const getValidationRulesEngine = async (convertedRules, user) => {
153
+ const model = await getModel(user, 'validation')
154
+ const rulesEngine = await getRulesEngine(model, convertedRules, user)
155
+ return rulesEngine
156
+ }
157
+
158
+ const getValidationRulesFiles = async (user) => {
159
+ // await getValidationRules(user)
160
+ const model = await getModel(user, 'validation')
161
+ const rulesFiles = await getRulesFiles(model, user)
162
+ return rulesFiles
163
+ }
164
+
165
+ const getValidationRulesFileContent = async (fileName, user) => {
166
+ const model = await getModel(user, 'validation')
167
+ const rulesFileContent = await getRulesFileContent(model, fileName, user)
168
+ return rulesFileContent
169
+ }
170
+
171
+ const setValidationRulesFileContent = async (fileName, fileContent, user) => {
172
+ const model = await getModel(user, 'validation')
173
+ const rulesFileContent = await setRulesFileContent(model, fileName, fileContent, user)
174
+ return rulesFileContent
175
+ }
176
+
177
+ const deleteValidationRulesFile = async (fileName, user) => {
178
+ const model = await getModel(user, 'validation')
179
+ const deleted = await deleteRulesFile(model, fileName, user)
180
+ return deleted
181
+ }
182
+
183
+ // callback rules
184
+ const reloadCallbackRules = async (user) => {
185
+ const model = await getModel(user, 'callback')
186
+ await reloadRules(model, user)
187
+ }
188
+
189
+ const setActiveCallbackRulesFile = async (fileName, user) => {
190
+ const model = await getModel(user, 'callback')
191
+ await setActiveRulesFile(model, fileName, user)
192
+ }
193
+
194
+ const getCallbackRules = async (user) => {
195
+ const model = await getModel(user, 'callback')
196
+ const rules = await getRules(model, user)
197
+ return rules
198
+ }
199
+
200
+ const getCallbackRulesEngine = async (convertedRules, user) => {
201
+ const model = await getModel(user, 'callback')
202
+ const rulesEngine = await getRulesEngine(model, convertedRules, user)
203
+ return rulesEngine
204
+ }
205
+
206
+ const getCallbackRulesFiles = async (user) => {
207
+ // await getCallbackRules(user)
208
+ const model = await getModel(user, 'callback')
209
+ const rulesFiles = await getRulesFiles(model, user)
210
+ return rulesFiles
211
+ }
212
+
213
+ const getCallbackRulesFileContent = async (fileName, user) => {
214
+ const model = await getModel(user, 'callback')
215
+ const rulesFileContent = await getRulesFileContent(model, fileName, user)
216
+ return rulesFileContent
217
+ }
218
+
219
+ const setCallbackRulesFileContent = async (fileName, fileContent, user) => {
220
+ const model = await getModel(user, 'callback')
221
+ const rulesFileContent = await setRulesFileContent(model, fileName, fileContent, user)
222
+ return rulesFileContent
223
+ }
224
+
225
+ const deleteCallbackRulesFile = async (fileName, user) => {
226
+ const model = await getModel(user, 'callback')
227
+ const deleted = await deleteRulesFile(model, fileName, user)
228
+ return deleted
229
+ }
230
+
231
+ // forward rules
232
+ const reloadForwardRules = async (user) => {
233
+ const model = await getModel(user, 'forward')
234
+ await reloadRules(model, user)
235
+ }
236
+
237
+ const setActiveForwardRulesFile = async (fileName, user) => {
238
+ const model = await getModel(user, 'forward')
239
+ await setActiveRulesFile(model, fileName, user)
240
+ }
241
+
242
+ const getForwardRules = async (user) => {
243
+ const model = await getModel(user, 'forward')
244
+ const rules = await getRules(model, user)
245
+ return rules
246
+ }
247
+
248
+ const getForwardRulesEngine = async (convertedRules, user) => {
249
+ const model = await getModel(user, 'forward')
250
+ const rulesEngine = await getRulesEngine(model, convertedRules, user)
251
+ return rulesEngine
252
+ }
253
+
254
+ const getForwardRulesFiles = async (user) => {
255
+ // await getForwardRules(user)
256
+ const model = await getModel(user, 'forward')
257
+ const rulesFiles = await getRulesFiles(model, user)
258
+ return rulesFiles
259
+ }
260
+
261
+ const getForwardRulesFileContent = async (fileName, user) => {
262
+ const model = await getModel(user, 'forward')
263
+ const rulesFileContent = await getRulesFileContent(model, fileName, user)
264
+ return rulesFileContent
265
+ }
266
+
267
+ const setForwardRulesFileContent = async (fileName, fileContent, user) => {
268
+ const model = await getModel(user, 'forward')
269
+ const rulesFileContent = await setRulesFileContent(model, fileName, fileContent, user)
270
+ return rulesFileContent
271
+ }
272
+
273
+ const deleteForwardRulesFile = async (fileName, user) => {
274
+ const model = await getModel(user, 'forward')
275
+ const deleted = await deleteRulesFile(model, fileName, user)
276
+ return deleted
277
+ }
278
+
279
+ // common functions
280
+ const reloadRules = async (model, user) => {
281
+ const fetchedActiveRulesFile = await getActiveRulesFile(model, user)
282
+ if (fetchedActiveRulesFile) {
283
+ model.activeRulesFile = fetchedActiveRulesFile
284
+ }
285
+ customLogger.logMessage('info', `Reloading ${model.ruleType} Rules from file ` + model.activeRulesFile, { notification: false })
286
+ const userRules = await storageAdapter.read(model.rulesFilePathPrefix + model.activeRulesFile, user)
287
+ model.rules = userRules.data
288
+ if (!model.rules || !model.rules.length) {
289
+ model.rules = []
290
+ }
291
+ loadRules(model, model.rules)
292
+ }
293
+
294
+ const setActiveRulesFile = async (model, fileName, user) => {
295
+ const rulesConfig = {
296
+ activeRulesFile: fileName
297
+ }
298
+ await storageAdapter.upsert(model.rulesFilePathPrefix + CONFIG_FILE_NAME, rulesConfig, user)
299
+ model.activeRulesFile = fileName
300
+ await reloadRules(model, user)
301
+ }
302
+
303
+ const getActiveRulesFile = async (model, user) => {
304
+ const configFileContent = await storageAdapter.read(model.rulesFilePathPrefix + CONFIG_FILE_NAME, user)
305
+ return configFileContent.data.activeRulesFile
306
+ }
307
+
308
+ const getRules = async (model, user) => {
309
+ if (!model.rules || model.rules.length === 0) {
310
+ await reloadRules(model, user)
311
+ }
312
+ return model.rules
313
+ }
314
+
315
+ const getRulesEngine = async (model, convertedRules) => {
316
+ if (!model.rulesEngine) {
317
+ model.rulesEngine = new RulesEngine()
318
+ }
319
+ if (convertedRules) {
320
+ loadRules(model, convertedRules)
321
+ }
322
+ return model.rulesEngine
323
+ }
324
+
325
+ const loadRules = (model, rules) => {
326
+ rules.forEach(rule => {
327
+ rule.conditions.all.forEach(condition => {
328
+ if (condition.fact === 'headers') {
329
+ condition.path = condition.path.toLowerCase()
330
+ }
331
+ })
332
+ })
333
+ if (!model.rulesEngine) {
334
+ model.rulesEngine = new RulesEngine()
335
+ }
336
+ model.rulesEngine.loadRules(rules)
337
+ }
338
+
339
+ const getRulesFiles = async (model, user) => {
340
+ try {
341
+ const files = await storageAdapter.read(model.rulesFilePathPrefix, user)
342
+ const resp = {}
343
+ // Do not return the config file
344
+ resp.files = files.data.filter(item => {
345
+ return (item !== CONFIG_FILE_NAME)
346
+ })
347
+ if (model.rules === null) {
348
+ await reloadRules(model, user)
349
+ }
350
+ resp.activeRulesFile = model.activeRulesFile
351
+ return resp
352
+ } catch (err) {
353
+ return null
354
+ }
355
+ }
356
+
357
+ const deleteRulesFile = async (model, fileName, user) => {
358
+ if (fileName === DEFAULT_RULES_FILE_NAME) {
359
+ throw new Error('Default rules file cannot be deleted')
360
+ }
361
+
362
+ try {
363
+ await storageAdapter.remove(model.rulesFilePathPrefix + fileName, user)
364
+ await setActiveRulesFile(model, DEFAULT_RULES_FILE_NAME, user)
365
+ return true
366
+ } catch (err) {
367
+ return err
368
+ }
369
+ }
370
+
371
+ const setRulesFileContent = async (model, fileName, fileContent, user) => {
372
+ try {
373
+ addTypeAndVersion(model, fileContent)
374
+ await storageAdapter.upsert(model.rulesFilePathPrefix + fileName, fileContent, user)
375
+ await reloadRules(model, user)
376
+ return true
377
+ } catch (err) {
378
+ return err
379
+ }
380
+ }
381
+
382
+ const getRulesFileContent = async (model, fileName, user) => {
383
+ const userRules = await storageAdapter.read(model.rulesFilePathPrefix + fileName, user)
384
+ return userRules.data
385
+ }
386
+
387
+ const addTypeAndVersion = (model, fileContent) => {
388
+ for (const index in fileContent) {
389
+ if (!fileContent[index].type) {
390
+ fileContent[index].type = model.ruleType
391
+ }
392
+ if (!fileContent[index].version) {
393
+ fileContent[index].version = parseFloat(Config.getSystemConfig().CONFIG_VERSIONS[model.ruleType])
394
+ }
395
+ }
396
+ }
397
+
398
+ // used for integration tests
399
+ const setTestRules = async ({
400
+ response,
401
+ validation,
402
+ callback,
403
+ forward
404
+ }) => {
405
+ if (response) {
406
+ model.data.response.rules = (await storageAdapter.read(response)).data
407
+ loadRules(model.data.response, model.data.response.rules)
408
+ }
409
+ if (validation) {
410
+ model.data.validation.rules = (await storageAdapter.read(validation)).data
411
+ loadRules(model.data.validation, model.data.validation.rules)
412
+ }
413
+ if (callback) {
414
+ model.data.callback.rules = (await storageAdapter.read(callback)).data
415
+ loadRules(model.data.callback, model.data.callback.rules)
416
+ }
417
+ if (forward) {
418
+ model.data.forward.rules = (await storageAdapter.read(forward)).data
419
+ loadRules(model.data.forward, model.data.forward.rules)
420
+ }
421
+ }
422
+
423
+ module.exports = {
424
+ getModel,
425
+
426
+ reloadResponseRules,
427
+ setActiveResponseRulesFile,
428
+ getResponseRules,
429
+ getResponseRulesEngine,
430
+ getResponseRulesFiles,
431
+ getResponseRulesFileContent,
432
+ setResponseRulesFileContent,
433
+ deleteResponseRulesFile,
434
+
435
+ reloadValidationRules,
436
+ setActiveValidationRulesFile,
437
+ getValidationRules,
438
+ getValidationRulesEngine,
439
+ getValidationRulesFiles,
440
+ getValidationRulesFileContent,
441
+ setValidationRulesFileContent,
442
+ deleteValidationRulesFile,
443
+
444
+ reloadCallbackRules,
445
+ setActiveCallbackRulesFile,
446
+ getCallbackRules,
447
+ getCallbackRulesEngine,
448
+ getCallbackRulesFiles,
449
+ getCallbackRulesFileContent,
450
+ setCallbackRulesFileContent,
451
+ deleteCallbackRulesFile,
452
+
453
+ reloadForwardRules,
454
+ setActiveForwardRulesFile,
455
+ getForwardRules,
456
+ getForwardRulesEngine,
457
+ getForwardRulesFiles,
458
+ getForwardRulesFileContent,
459
+ setForwardRulesFileContent,
460
+ deleteForwardRulesFile,
461
+
462
+ setTestRules
463
+ }
@@ -0,0 +1,142 @@
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 Sandbox = require('postman-sandbox')
31
+ const util = require('util')
32
+ const axios = require('axios').default
33
+ const customLogger = require('../requestLogger')
34
+ const UniqueIdGenerator = require('../../lib/uniqueIdGenerator')
35
+
36
+ // const createContextAsync = util.promisify(Sandbox.createContext)
37
+ const createContextAsync = () => {
38
+ return new Promise((resolve, reject) => {
39
+ Sandbox.createContext(function (err, ctx) {
40
+ if (err) {
41
+ reject(err)
42
+ return console.error(err)
43
+ }
44
+ resolve(ctx)
45
+ })
46
+ })
47
+ }
48
+
49
+ const generateContextObj = async (environment = {}) => {
50
+ const ctx = await createContextAsync({ timeout: 30000 })
51
+ ctx.executeAsync = util.promisify(ctx.execute)
52
+ ctx.on('error', function (cursor, err) {
53
+ // log the error in postman sandbox
54
+ console.log(cursor, err)
55
+ })
56
+ const transformerObj = {
57
+ transformer: null,
58
+ transformerName: null,
59
+ options: {}
60
+ }
61
+ const contextObj = {
62
+ ctx,
63
+ environment,
64
+ transformerObj
65
+ }
66
+ return contextObj
67
+ }
68
+
69
+ const executeAsync = async (script, data, contextObj) => {
70
+ let consoleLog = []
71
+ const uniqueId = UniqueIdGenerator.generateUniqueId()
72
+ // Append ctx and environment to data.context
73
+ if (!data.context) {
74
+ data.context = {}
75
+ }
76
+ data.context.ctx = contextObj.ctx
77
+ data.context.environment = Object.entries(contextObj.environment || {}).map((item) => { return { type: 'any', key: item[0], value: item[1] } })
78
+
79
+ contextObj.ctx.on('console', function () {
80
+ consoleLog.push(Array.from(arguments))
81
+ })
82
+
83
+ contextObj.ctx.on(`execution.request.${data.id}`, async (cursor, id, requestId, req) => {
84
+ const host = `${req.url.protocol}://${req.url.host.join('.')}${req.url.port ? ':' + req.url.port : ''}/`
85
+ let response
86
+ try {
87
+ let queryParams = ''
88
+ if (req.url.query && req.url.query.length > 0) {
89
+ queryParams = '?'
90
+ req.url.query.forEach(queryParam => {
91
+ queryParams += `${queryParam.key}=${queryParam.value}&`
92
+ })
93
+ }
94
+ const reqObject = {
95
+ method: req.method,
96
+ url: host + req.url.path.join('/') + queryParams,
97
+ headers: req.header ? req.header.reduce((rObj, item) => { rObj[item.key] = item.value; return rObj }, {}) : null,
98
+ data: req.body && req.body.mode === 'raw' ? JSON.parse(req.body.raw) : null,
99
+ path: '/' + req.url.path.join('/'),
100
+ timeout: 3000
101
+ }
102
+ customLogger.logOutboundRequest('info', 'Request: ' + reqObject.method + ' ' + reqObject.path, { additionalData: { request: reqObject }, request: reqObject, uniqueId })
103
+ try {
104
+ response = await axios(reqObject)
105
+ customLogger.logOutboundRequest('info', 'Response: ' + response.status + ' ' + response.statusText, { additionalData: { response }, request: reqObject, uniqueId })
106
+ } catch (err) {
107
+ customLogger.logOutboundRequest('error', 'Error Response: ' + err.message, { additionalData: err, request: reqObject, uniqueId })
108
+ throw (err)
109
+ }
110
+ } catch (err) {
111
+ consoleLog.push([cursor, 'executionError', err])
112
+ response = err.response ? err.response : { status: 4001, data: err.message }
113
+ }
114
+ contextObj.ctx.dispatch(`execution.response.${id}`, requestId, null, {
115
+ code: response.status,
116
+ body: JSON.stringify(response.data)
117
+ })
118
+ })
119
+
120
+ contextObj.ctx.on(`execution.error.${data.id}`, function (cur, err) {
121
+ customLogger.logMessage('error', 'Script Execution Error' + err.message, { notification: false })
122
+ consoleLog.push([cur, 'executionError', err])
123
+ })
124
+
125
+ try {
126
+ const resp = await contextObj.ctx.executeAsync(script, data)
127
+ contextObj.environment = resp.environment.values.reduce((envObj, item) => { envObj[item.key] = item.value; return envObj }, {})
128
+ } catch (err) {
129
+ // consoleLog.push([{execution: 0}, 'executionError', err.message])
130
+ }
131
+ const result = {
132
+ consoleLog,
133
+ environment: { ...contextObj.environment }
134
+ }
135
+ consoleLog = []
136
+ return result
137
+ }
138
+
139
+ module.exports = {
140
+ generateContextObj,
141
+ executeAsync
142
+ }