@mojaloop/sdk-scheme-adapter 11.18.8

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 (277) hide show
  1. package/.env.example +140 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc.json +30 -0
  4. package/.nvmrc +1 -0
  5. package/.versionrc +15 -0
  6. package/CHANGELOG.md +118 -0
  7. package/InboundServer/api.yaml +3594 -0
  8. package/InboundServer/api_template.yaml +69 -0
  9. package/InboundServer/handlers.js +940 -0
  10. package/InboundServer/index.js +205 -0
  11. package/InboundServer/middlewares.js +426 -0
  12. package/OAuthTestServer/index.js +66 -0
  13. package/OAuthTestServer/model.js +70 -0
  14. package/OutboundServer/api.yaml +2732 -0
  15. package/OutboundServer/api_interfaces/index.d.ts +117 -0
  16. package/OutboundServer/api_interfaces/openapi.d.ts +1475 -0
  17. package/OutboundServer/api_template/components/parameters/bulkQuoteId.yaml +9 -0
  18. package/OutboundServer/api_template/components/parameters/bulkTransferId.yaml +9 -0
  19. package/OutboundServer/api_template/components/parameters/requestToPayTransactionId.yaml +9 -0
  20. package/OutboundServer/api_template/components/parameters/transferId.yaml +9 -0
  21. package/OutboundServer/api_template/components/responses/accountsCreationCompleted.yaml +5 -0
  22. package/OutboundServer/api_template/components/responses/accountsCreationError.yaml +5 -0
  23. package/OutboundServer/api_template/components/responses/accountsCreationTimeout.yaml +5 -0
  24. package/OutboundServer/api_template/components/responses/authorizationPostSuccess.yaml +5 -0
  25. package/OutboundServer/api_template/components/responses/authorizationsServerError.yaml +5 -0
  26. package/OutboundServer/api_template/components/responses/bulkQuoteBadRequest.yaml +5 -0
  27. package/OutboundServer/api_template/components/responses/bulkQuoteServerError.yaml +5 -0
  28. package/OutboundServer/api_template/components/responses/bulkQuoteSuccess.yaml +5 -0
  29. package/OutboundServer/api_template/components/responses/bulkQuoteTimeout.yaml +5 -0
  30. package/OutboundServer/api_template/components/responses/bulkTransferBadRequest.yaml +5 -0
  31. package/OutboundServer/api_template/components/responses/bulkTransferServerError.yaml +5 -0
  32. package/OutboundServer/api_template/components/responses/bulkTransferSuccess.yaml +5 -0
  33. package/OutboundServer/api_template/components/responses/bulkTransferTimeout.yaml +5 -0
  34. package/OutboundServer/api_template/components/responses/partiesByIdError404.yaml +9 -0
  35. package/OutboundServer/api_template/components/responses/partiesByIdSuccess.yaml +5 -0
  36. package/OutboundServer/api_template/components/responses/quotesPostSuccess.yaml +5 -0
  37. package/OutboundServer/api_template/components/responses/quotesServerError.yaml +5 -0
  38. package/OutboundServer/api_template/components/responses/requestToPaySuccess.yaml +5 -0
  39. package/OutboundServer/api_template/components/responses/requestToPayTransferBadRequest.yaml +5 -0
  40. package/OutboundServer/api_template/components/responses/requestToPayTransferSuccess.yaml +5 -0
  41. package/OutboundServer/api_template/components/responses/simpleTransfersPostSuccess.yaml +5 -0
  42. package/OutboundServer/api_template/components/responses/simpleTransfersServerError.yaml +5 -0
  43. package/OutboundServer/api_template/components/responses/transferBadRequest.yaml +5 -0
  44. package/OutboundServer/api_template/components/responses/transferServerError.yaml +5 -0
  45. package/OutboundServer/api_template/components/responses/transferSuccess.yaml +5 -0
  46. package/OutboundServer/api_template/components/responses/transferTimeout.yaml +5 -0
  47. package/OutboundServer/api_template/components/schemas/accountCreationStatus.yaml +18 -0
  48. package/OutboundServer/api_template/components/schemas/accountsCreationState.yaml +4 -0
  49. package/OutboundServer/api_template/components/schemas/accountsRequest.yaml +20 -0
  50. package/OutboundServer/api_template/components/schemas/accountsResponse.yaml +15 -0
  51. package/OutboundServer/api_template/components/schemas/async2SyncCurrentState.yaml +5 -0
  52. package/OutboundServer/api_template/components/schemas/authorizationsPostRequest.yaml +15 -0
  53. package/OutboundServer/api_template/components/schemas/authorizationsPostResponse.yaml +19 -0
  54. package/OutboundServer/api_template/components/schemas/bulkQuoteErrorResponse.yaml +8 -0
  55. package/OutboundServer/api_template/components/schemas/bulkQuoteRequest.yaml +26 -0
  56. package/OutboundServer/api_template/components/schemas/bulkQuoteResponse.yaml +21 -0
  57. package/OutboundServer/api_template/components/schemas/bulkQuoteStatus.yaml +4 -0
  58. package/OutboundServer/api_template/components/schemas/bulkQuoteStatusResponse.yaml +17 -0
  59. package/OutboundServer/api_template/components/schemas/bulkTransferErrorResponse.yaml +8 -0
  60. package/OutboundServer/api_template/components/schemas/bulkTransferRequest.yaml +26 -0
  61. package/OutboundServer/api_template/components/schemas/bulkTransferResponse.yaml +16 -0
  62. package/OutboundServer/api_template/components/schemas/bulkTransferStatus.yaml +4 -0
  63. package/OutboundServer/api_template/components/schemas/bulkTransferStatusResponse.yaml +17 -0
  64. package/OutboundServer/api_template/components/schemas/errorAccountsResponse.yaml +8 -0
  65. package/OutboundServer/api_template/components/schemas/errorAuthorizationsResponse.yaml +3 -0
  66. package/OutboundServer/api_template/components/schemas/errorQuotesResponse.yaml +9 -0
  67. package/OutboundServer/api_template/components/schemas/errorResponse.yaml +8 -0
  68. package/OutboundServer/api_template/components/schemas/errorSimpleTransfersResponse.yaml +3 -0
  69. package/OutboundServer/api_template/components/schemas/errorTransferResponse.yaml +8 -0
  70. package/OutboundServer/api_template/components/schemas/extensionListEmptiable.yaml +6 -0
  71. package/OutboundServer/api_template/components/schemas/individualQuote.yaml +32 -0
  72. package/OutboundServer/api_template/components/schemas/individualQuoteResult.yaml +28 -0
  73. package/OutboundServer/api_template/components/schemas/individualTransfer.yaml +32 -0
  74. package/OutboundServer/api_template/components/schemas/individualTransferFulfilment.yaml +13 -0
  75. package/OutboundServer/api_template/components/schemas/individualTransferResult.yaml +41 -0
  76. package/OutboundServer/api_template/components/schemas/mojaloopError.yaml +5 -0
  77. package/OutboundServer/api_template/components/schemas/mojaloopTransactionRequestState.yaml +2 -0
  78. package/OutboundServer/api_template/components/schemas/partiesByIdResponse.yaml +13 -0
  79. package/OutboundServer/api_template/components/schemas/quote.yaml +3 -0
  80. package/OutboundServer/api_template/components/schemas/quoteError.yaml +16 -0
  81. package/OutboundServer/api_template/components/schemas/quotesPostRequest.yaml +13 -0
  82. package/OutboundServer/api_template/components/schemas/quotesPostResponse.yaml +48 -0
  83. package/OutboundServer/api_template/components/schemas/requestToPayRequest.yaml +39 -0
  84. package/OutboundServer/api_template/components/schemas/requestToPayResponse.yaml +41 -0
  85. package/OutboundServer/api_template/components/schemas/requestToPayTransferRequest.yaml +42 -0
  86. package/OutboundServer/api_template/components/schemas/requestToPayTransferResponse.yaml +58 -0
  87. package/OutboundServer/api_template/components/schemas/simpleTransferServerError.yaml +5 -0
  88. package/OutboundServer/api_template/components/schemas/simpleTransfersPostRequest.yaml +12 -0
  89. package/OutboundServer/api_template/components/schemas/simpleTransfersPostResponse.yaml +11 -0
  90. package/OutboundServer/api_template/components/schemas/transactionType.yaml +4 -0
  91. package/OutboundServer/api_template/components/schemas/transferContinuationAcceptOTP.yaml +9 -0
  92. package/OutboundServer/api_template/components/schemas/transferContinuationAcceptParty.yaml +8 -0
  93. package/OutboundServer/api_template/components/schemas/transferContinuationAcceptQuote.yaml +9 -0
  94. package/OutboundServer/api_template/components/schemas/transferError.yaml +16 -0
  95. package/OutboundServer/api_template/components/schemas/transferFulfilment.yaml +3 -0
  96. package/OutboundServer/api_template/components/schemas/transferParty.yaml +40 -0
  97. package/OutboundServer/api_template/components/schemas/transferRequest.yaml +37 -0
  98. package/OutboundServer/api_template/components/schemas/transferResponse.yaml +58 -0
  99. package/OutboundServer/api_template/components/schemas/transferStatus.yaml +6 -0
  100. package/OutboundServer/api_template/components/schemas/transferStatusResponse.yaml +13 -0
  101. package/OutboundServer/api_template/health.yaml +12 -0
  102. package/OutboundServer/api_template/openapi.yaml +55 -0
  103. package/OutboundServer/api_template/paths/accounts.yaml +26 -0
  104. package/OutboundServer/api_template/paths/authorizations.yaml +19 -0
  105. package/OutboundServer/api_template/paths/bulkQuotes.yaml +23 -0
  106. package/OutboundServer/api_template/paths/bulkQuotes_bulkQuoteId.yaml +24 -0
  107. package/OutboundServer/api_template/paths/bulkTransfers.yaml +23 -0
  108. package/OutboundServer/api_template/paths/bulkTransfers_bulkTransferId.yaml +24 -0
  109. package/OutboundServer/api_template/paths/parties_Type_ID.yaml +20 -0
  110. package/OutboundServer/api_template/paths/parties_Type_ID_SubId.yaml +22 -0
  111. package/OutboundServer/api_template/paths/quotes.yaml +20 -0
  112. package/OutboundServer/api_template/paths/requestToPay.yaml +22 -0
  113. package/OutboundServer/api_template/paths/requestToPayTransfer.yaml +57 -0
  114. package/OutboundServer/api_template/paths/requestToPayTransfer_requestToPayTransactionId.yaml +34 -0
  115. package/OutboundServer/api_template/paths/simpleTransfers.yaml +19 -0
  116. package/OutboundServer/api_template/paths/transfers.yaml +55 -0
  117. package/OutboundServer/api_template/paths/transfers_transferId.yaml +58 -0
  118. package/OutboundServer/handlers.js +622 -0
  119. package/OutboundServer/index.js +137 -0
  120. package/OutboundServer/middlewares.js +67 -0
  121. package/TestServer/api.yaml +62 -0
  122. package/TestServer/handlers.js +63 -0
  123. package/TestServer/index.js +215 -0
  124. package/audit-resolve.json +65 -0
  125. package/babel.config.js +3 -0
  126. package/config.js +158 -0
  127. package/index.d.ts +1 -0
  128. package/index.js +149 -0
  129. package/jest.config.js +15 -0
  130. package/lib/api/index.js +12 -0
  131. package/lib/cache.js +352 -0
  132. package/lib/check.js +25 -0
  133. package/lib/model/AccountsModel.js +396 -0
  134. package/lib/model/Async2SyncModel.js +283 -0
  135. package/lib/model/AuthorizationsModel.js +86 -0
  136. package/lib/model/InboundTransfersModel.js +730 -0
  137. package/lib/model/OutboundBulkQuotesModel.js +485 -0
  138. package/lib/model/OutboundBulkTransfersModel.js +479 -0
  139. package/lib/model/OutboundRequestToPayModel.js +517 -0
  140. package/lib/model/OutboundRequestToPayTransferModel.js +893 -0
  141. package/lib/model/OutboundTransfersModel.js +823 -0
  142. package/lib/model/PartiesModel.js +70 -0
  143. package/lib/model/ProxyModel/MatchRules/Expression.js +48 -0
  144. package/lib/model/ProxyModel/MatchRules/Headers.js +65 -0
  145. package/lib/model/ProxyModel/MatchRules/MatchRule.js +27 -0
  146. package/lib/model/ProxyModel/MatchRules/Path.js +36 -0
  147. package/lib/model/ProxyModel/MatchRules/Query.js +65 -0
  148. package/lib/model/ProxyModel/MatchRules/index.js +19 -0
  149. package/lib/model/ProxyModel/Route.js +82 -0
  150. package/lib/model/ProxyModel/configSchema.json +118 -0
  151. package/lib/model/ProxyModel/index.js +138 -0
  152. package/lib/model/QuotesModel.js +94 -0
  153. package/lib/model/TransfersModel.js +81 -0
  154. package/lib/model/common/BackendError.js +26 -0
  155. package/lib/model/common/PersistentStateMachine.js +93 -0
  156. package/lib/model/common/index.js +18 -0
  157. package/lib/model/index.js +43 -0
  158. package/lib/model/lib/deferredJob.js +113 -0
  159. package/lib/model/lib/index.js +9 -0
  160. package/lib/model/lib/requests/backendRequests.js +227 -0
  161. package/lib/model/lib/requests/common.js +76 -0
  162. package/lib/model/lib/requests/index.js +19 -0
  163. package/lib/model/lib/shared.js +468 -0
  164. package/lib/randomphrase/index.js +21 -0
  165. package/lib/randomphrase/words.json +3397 -0
  166. package/lib/router.js +28 -0
  167. package/lib/validate.js +205 -0
  168. package/package.json +102 -0
  169. package/test/__mocks__/@mojaloop/sdk-standard-components.js +152 -0
  170. package/test/__mocks__/javascript-state-machine.js +21 -0
  171. package/test/__mocks__/redis.js +49 -0
  172. package/test/__mocks__/uuidv4.js +16 -0
  173. package/test/config/integration.env +136 -0
  174. package/test/integration/lib/Outbound/authorizations.test.js +58 -0
  175. package/test/integration/lib/Outbound/data/authorizationsPostRequest.json +43 -0
  176. package/test/integration/lib/Outbound/data/quotesPostRequest.json +52 -0
  177. package/test/integration/lib/Outbound/data/transfersPostRequest.json +24 -0
  178. package/test/integration/lib/Outbound/parties.test.js +28 -0
  179. package/test/integration/lib/Outbound/quotes.test.js +58 -0
  180. package/test/integration/lib/Outbound/simpleTransfers.test.js +67 -0
  181. package/test/integration/lib/cache.test.js +80 -0
  182. package/test/integration/testEnv.js +7 -0
  183. package/test/unit/InboundServer.test.js +443 -0
  184. package/test/unit/TestServer.test.js +394 -0
  185. package/test/unit/api/accounts/accounts.test.js +128 -0
  186. package/test/unit/api/accounts/data/postAccountsBody.json +7 -0
  187. package/test/unit/api/accounts/data/postAccountsErrorMojaloopResponse.json +25 -0
  188. package/test/unit/api/accounts/data/postAccountsErrorTimeoutResponse.json +19 -0
  189. package/test/unit/api/accounts/data/postAccountsSuccessResponse.json +17 -0
  190. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError1.json +21 -0
  191. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError2.json +21 -0
  192. package/test/unit/api/accounts/utils.js +65 -0
  193. package/test/unit/api/proxy/data/proxyConfig.yaml +82 -0
  194. package/test/unit/api/proxy/data/requestBody.json +22 -0
  195. package/test/unit/api/proxy/data/requestHeaders.json +5 -0
  196. package/test/unit/api/proxy/data/requestQuery.json +6 -0
  197. package/test/unit/api/proxy/data/responseBody.json +21 -0
  198. package/test/unit/api/proxy/data/responseHeaders.json +5 -0
  199. package/test/unit/api/proxy/proxy.test.js +220 -0
  200. package/test/unit/api/proxy/utils.js +79 -0
  201. package/test/unit/api/transfers/data/getTransfersCommittedResponse.json +21 -0
  202. package/test/unit/api/transfers/data/getTransfersErrorNotFound.json +17 -0
  203. package/test/unit/api/transfers/data/postQuotesBody.json +52 -0
  204. package/test/unit/api/transfers/data/postTransfersBadBody.json +17 -0
  205. package/test/unit/api/transfers/data/postTransfersBody.json +24 -0
  206. package/test/unit/api/transfers/data/postTransfersErrorMojaloopResponse.json +53 -0
  207. package/test/unit/api/transfers/data/postTransfersErrorTimeoutResponse.json +47 -0
  208. package/test/unit/api/transfers/data/postTransfersSimpleBody.json +26 -0
  209. package/test/unit/api/transfers/data/postTransfersSuccessResponse.json +101 -0
  210. package/test/unit/api/transfers/data/putPartiesBody.json +20 -0
  211. package/test/unit/api/transfers/data/putQuotesBody.json +37 -0
  212. package/test/unit/api/transfers/data/putTransfersBody.json +17 -0
  213. package/test/unit/api/transfers/transfers.test.js +191 -0
  214. package/test/unit/api/transfers/utils.js +183 -0
  215. package/test/unit/api/utils.js +75 -0
  216. package/test/unit/config.test.js +119 -0
  217. package/test/unit/data/commonHttpHeaders.json +6 -0
  218. package/test/unit/data/defaultConfig.json +58 -0
  219. package/test/unit/data/postQuotesBody.json +52 -0
  220. package/test/unit/data/putParticipantsBody.json +12 -0
  221. package/test/unit/data/putPartiesBody.json +20 -0
  222. package/test/unit/data/testFile.json +29 -0
  223. package/test/unit/data/testFile.yaml +14 -0
  224. package/test/unit/inboundApi/data/mockArguments.json +117 -0
  225. package/test/unit/inboundApi/data/mockTransactionRequest.json +42 -0
  226. package/test/unit/inboundApi/handlers.test.js +799 -0
  227. package/test/unit/index.test.js +55 -0
  228. package/test/unit/lib/cache.test.js +146 -0
  229. package/test/unit/lib/model/AccountsModel.test.js +121 -0
  230. package/test/unit/lib/model/AuthorizationsModel.test.js +460 -0
  231. package/test/unit/lib/model/InboundTransfersModel.test.js +628 -0
  232. package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +249 -0
  233. package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +244 -0
  234. package/test/unit/lib/model/OutboundRequestToPayModel.test.js +166 -0
  235. package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +245 -0
  236. package/test/unit/lib/model/OutboundTransfersModel.test.js +836 -0
  237. package/test/unit/lib/model/PartiesModel.test.js +468 -0
  238. package/test/unit/lib/model/QuotesModel.test.js +470 -0
  239. package/test/unit/lib/model/TransfersModel.test.js +474 -0
  240. package/test/unit/lib/model/common/PersistentStateMachine.test.js +179 -0
  241. package/test/unit/lib/model/data/authorizationsResponse.json +13 -0
  242. package/test/unit/lib/model/data/bulkQuoteRequest.json +27 -0
  243. package/test/unit/lib/model/data/bulkQuoteResponse.json +35 -0
  244. package/test/unit/lib/model/data/bulkTransferFulfil.json +13 -0
  245. package/test/unit/lib/model/data/bulkTransferRequest.json +29 -0
  246. package/test/unit/lib/model/data/defaultConfig.json +47 -0
  247. package/test/unit/lib/model/data/getBulkTransfersBackendResponse.json +42 -0
  248. package/test/unit/lib/model/data/getBulkTransfersMojaloopResponse.json +22 -0
  249. package/test/unit/lib/model/data/getTransfersBackendResponse.json +34 -0
  250. package/test/unit/lib/model/data/getTransfersMojaloopResponse.json +17 -0
  251. package/test/unit/lib/model/data/mockArguments.json +131 -0
  252. package/test/unit/lib/model/data/mockTxnRequestsArguments.json +63 -0
  253. package/test/unit/lib/model/data/notificationToPayee.json +10 -0
  254. package/test/unit/lib/model/data/payeeParty.json +16 -0
  255. package/test/unit/lib/model/data/putAuthorizationsResponse.json +10 -0
  256. package/test/unit/lib/model/data/putQuotesResponse.json +33 -0
  257. package/test/unit/lib/model/data/putTransfersResponse.json +5 -0
  258. package/test/unit/lib/model/data/quoteResponse.json +31 -0
  259. package/test/unit/lib/model/data/requestToPayRequest.json +20 -0
  260. package/test/unit/lib/model/data/requestToPayTransferRequest.json +27 -0
  261. package/test/unit/lib/model/data/transactionRequestResponse.json +18 -0
  262. package/test/unit/lib/model/data/transferFulfil.json +8 -0
  263. package/test/unit/lib/model/data/transferRequest.json +26 -0
  264. package/test/unit/lib/model/mockedLibRequests.js +74 -0
  265. package/test/unit/mockLogger.js +39 -0
  266. package/test/unit/outboundApi/data/bulkQuoteRequest.json +28 -0
  267. package/test/unit/outboundApi/data/bulkTransferRequest.json +28 -0
  268. package/test/unit/outboundApi/data/mockBulkQuoteError.json +45 -0
  269. package/test/unit/outboundApi/data/mockBulkTransferError.json +48 -0
  270. package/test/unit/outboundApi/data/mockError.json +41 -0
  271. package/test/unit/outboundApi/data/mockGetPartiesError.json +4 -0
  272. package/test/unit/outboundApi/data/mockRequestToPayError.json +32 -0
  273. package/test/unit/outboundApi/data/mockRequestToPayTransferError.json +39 -0
  274. package/test/unit/outboundApi/data/requestToPay.json +21 -0
  275. package/test/unit/outboundApi/data/requestToPayTransferRequest.json +20 -0
  276. package/test/unit/outboundApi/data/transferRequest.json +21 -0
  277. package/test/unit/outboundApi/handlers.test.js +986 -0
@@ -0,0 +1,137 @@
1
+ /**************************************************************************
2
+ * (C) Copyright ModusBox Inc. 2019 - All rights reserved. *
3
+ * *
4
+ * This file is made available under the terms of the license agreement *
5
+ * specified in the corresponding source code repository. *
6
+ * *
7
+ * ORIGINAL AUTHOR: *
8
+ * James Bush - james.bush@modusbox.com *
9
+ **************************************************************************/
10
+
11
+ const http = require('http');
12
+
13
+ const Koa = require('koa');
14
+ const koaBody = require('koa-body');
15
+ const yaml = require('js-yaml');
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const EventEmitter = require('events');
19
+ const cors = require('@koa/cors');
20
+
21
+ const { WSO2Auth } = require('@mojaloop/sdk-standard-components');
22
+
23
+ const Validate = require('../lib/validate');
24
+ const router = require('../lib/router');
25
+ const handlers = require('./handlers');
26
+ const middlewares = require('./middlewares');
27
+
28
+ const endpointRegex = /\/.*/g;
29
+
30
+ class OutboundApi extends EventEmitter {
31
+ constructor(conf, logger, cache, validator) {
32
+ super({ captureExceptions: true });
33
+ this._logger = logger;
34
+ this._api = new Koa();
35
+ this._conf = conf;
36
+ this._cache = cache;
37
+
38
+ this._wso2 = {
39
+ auth: new WSO2Auth({
40
+ ...this._conf.wso2.auth,
41
+ logger: this._logger,
42
+ tlsCreds: this._conf.mutualTLS.outboundRequests.enabled && this._conf.mutualTLS.outboundRequests.creds,
43
+ }),
44
+ retryWso2AuthFailureTimes: conf.wso2.requestAuthFailureRetryTimes,
45
+ };
46
+ this._wso2.auth.on('error', (msg) => {
47
+ this.emit('error', 'WSO2 auth error in OutboundApi', msg);
48
+ });
49
+
50
+ // use CORS
51
+ // https://github.com/koajs/cors
52
+ this._api.use(cors());
53
+
54
+ this._api.use(middlewares.createErrorHandler(this._logger));
55
+ this._api.use(middlewares.createRequestIdGenerator());
56
+ this._api.use(koaBody()); // outbound always expects application/json
57
+ this._api.use(middlewares.applyState({ cache, wso2: this._wso2, conf }));
58
+ this._api.use(middlewares.createLogger(this._logger));
59
+
60
+ //Note that we strip off any path on peerEndpoint config after the origin.
61
+ //this is to allow proxy routed requests to hit any path on the peer origin
62
+ //irrespective of any base path on the PEER_ENDPOINT setting
63
+ if (conf.proxyConfig) {
64
+ this._api.use(middlewares.createProxy({
65
+ ...conf,
66
+ peerEndpoint: conf.peerEndpoint.replace(endpointRegex, ''),
67
+ proxyConfig: conf.proxyConfig,
68
+ logger: this._logger,
69
+ wso2Auth: this._wso2.auth,
70
+ tls: conf.mutualTLS.outboundRequests,
71
+ }));
72
+ }
73
+
74
+ this._api.use(middlewares.createRequestValidator(validator));
75
+ this._api.use(router(handlers));
76
+ }
77
+
78
+ async start() {
79
+ if (!this._conf.testingDisableWSO2AuthStart) {
80
+ await this._wso2.auth.start();
81
+ }
82
+ }
83
+
84
+ async stop() {
85
+ this._wso2.auth.stop();
86
+ }
87
+
88
+ callback() {
89
+ return this._api.callback();
90
+ }
91
+ }
92
+
93
+ class OutboundServer extends EventEmitter {
94
+ constructor(conf, logger, cache) {
95
+ super({ captureExceptions: true });
96
+ this._validator = new Validate();
97
+ this._conf = conf;
98
+ this._logger = logger;
99
+ this._server = null;
100
+ this._api = new OutboundApi(
101
+ conf,
102
+ this._logger.push({ component: 'api' }),
103
+ cache,
104
+ this._validator
105
+ );
106
+ this._api.on('error', (...args) => {
107
+ this.emit('error', ...args);
108
+ });
109
+ this._server = http.createServer(this._api.callback());
110
+ }
111
+
112
+ async start() {
113
+ await this._api.start();
114
+
115
+ const specPath = path.join(__dirname, 'api.yaml');
116
+ const apiSpecs = yaml.load(fs.readFileSync(specPath));
117
+ await this._validator.initialise(apiSpecs);
118
+
119
+ await new Promise((resolve) => this._server.listen(this._conf.outboundServerPort, resolve));
120
+
121
+ this._logger.log(`Serving outbound API on port ${this._conf.outboundServerPort}`);
122
+ }
123
+
124
+ async stop() {
125
+ if (this._server) {
126
+ await new Promise(resolve => this._server.close(resolve));
127
+ this._server = null;
128
+ }
129
+ if (this._api) {
130
+ await this._api.stop();
131
+ this._api = null;
132
+ }
133
+ this._logger.log('Shut down complete');
134
+ }
135
+ }
136
+
137
+ module.exports = OutboundServer;
@@ -0,0 +1,67 @@
1
+ /**************************************************************************
2
+ * (C) Copyright ModusBox Inc. 2019 - All rights reserved. *
3
+ * *
4
+ * This file is made available under the terms of the license agreement *
5
+ * specified in the corresponding source code repository. *
6
+ * *
7
+ * ORIGINAL AUTHOR: *
8
+ * James Bush - james.bush@modusbox.com *
9
+ **************************************************************************/
10
+
11
+
12
+ const { ProxyModel } = require('../lib/model');
13
+ const { applyState, createErrorHandler, createLogger, createRequestIdGenerator } =
14
+ require('../InboundServer/middlewares');
15
+
16
+
17
+ /**
18
+ * Add validation for each inbound request
19
+ * @param validator
20
+ * @return {Function}
21
+ */
22
+ const createRequestValidator = (validator) => async (ctx, next) => {
23
+ ctx.state.logger.log('Validating request');
24
+ try {
25
+ ctx.state.path = validator.validateRequest(ctx, ctx.state.logger);
26
+ ctx.state.logger.log('Request passed validation');
27
+ await next();
28
+ } catch (err) {
29
+ ctx.state.logger.push({ err }).log('Request failed validation.');
30
+ ctx.response.status = 400;
31
+ ctx.response.body = {
32
+ message: `${err.dataPath ? err.dataPath + ' ' : ''}${err.message}`,
33
+ statusCode: 400
34
+ };
35
+ }
36
+ };
37
+
38
+ /**
39
+ * Create proxy middleware for forwarding matching DFSP requests
40
+ * (from provided routing rules) to corresponding switch endpoint
41
+ * @param opts
42
+ * @return {Function}
43
+ */
44
+ const createProxy = (opts) => {
45
+ const proxy = new ProxyModel(opts);
46
+ return async (ctx, next) => {
47
+ const response = await proxy.proxyRequest(ctx.request);
48
+ if (response === undefined) {
49
+ // Skip proxying request
50
+ await next();
51
+ } else {
52
+ // return the result
53
+ ctx.response.status = response.statusCode;
54
+ ctx.response.body = response.data;
55
+ ctx.set(response.headers);
56
+ }
57
+ };
58
+ };
59
+
60
+ module.exports = {
61
+ applyState,
62
+ createRequestIdGenerator,
63
+ createErrorHandler,
64
+ createLogger,
65
+ createRequestValidator,
66
+ createProxy,
67
+ };
@@ -0,0 +1,62 @@
1
+ openapi: 3.0.0
2
+ info:
3
+ version: '1.1'
4
+ title: Open API for FSP Interoperability (FSPIOP)
5
+ description: >-
6
+ Based on API Definition.docx updated on 2018-03-13 Version 1.0. Note - The
7
+ API supports a maximum size of 65536 bytes (64 Kilobytes) in the HTTP
8
+ header.
9
+ license:
10
+ name: Open API for FSP Interoperability (FSPIOP)
11
+ paths:
12
+ '/':
13
+ get:
14
+ description: Health check
15
+ summary: healthCheck
16
+ tags:
17
+ - test
18
+ operationId: healthCheck
19
+ responses:
20
+ '204':
21
+ description: Response
22
+ content: null
23
+ '/requests/{ID}':
24
+ get:
25
+ description: Test support method. Allows the caller to see the body of a previous request
26
+ summary: getRequestsById
27
+ tags:
28
+ - test
29
+ operationId: getRequestsById
30
+ parameters:
31
+ - $ref: '#/components/parameters/ID'
32
+ responses:
33
+ '200':
34
+ description: Response
35
+ content:
36
+ application/json:
37
+ schema:
38
+ type: object
39
+ '/callbacks/{ID}':
40
+ get:
41
+ description: Test support method. Allows the caller to see the body of a previous callback
42
+ summary: getRequestsById
43
+ tags:
44
+ - test
45
+ operationId: getCallbackById
46
+ parameters:
47
+ - $ref: '#/components/parameters/ID'
48
+ responses:
49
+ '200':
50
+ description: Response
51
+ content:
52
+ application/json:
53
+ schema:
54
+ type: object
55
+ components:
56
+ parameters:
57
+ ID:
58
+ name: ID
59
+ in: path
60
+ required: true
61
+ schema:
62
+ type: string
@@ -0,0 +1,63 @@
1
+ /**************************************************************************
2
+ * (C) Copyright ModusBox Inc. 2019 - All rights reserved. *
3
+ * *
4
+ * This file is made available under the terms of the license agreement *
5
+ * specified in the corresponding source code repository. *
6
+ * *
7
+ * ORIGINAL AUTHOR: *
8
+ * James Bush - james.bush@modusbox.com *
9
+ **************************************************************************/
10
+
11
+ 'use strict';
12
+
13
+ const healthCheck = async(ctx) => {
14
+ ctx.response.status = 204;
15
+ ctx.response.body = '';
16
+ };
17
+
18
+
19
+ /**
20
+ * Handles a GET /requests/{ID} request. This is a test support method that allows the caller
21
+ * to see the body of a previous incoming request.
22
+ */
23
+ const getRequestById = async(ctx) => {
24
+ try {
25
+ const req = await ctx.state.cache.get(`request_${ctx.state.path.params.ID}`);
26
+ ctx.response.status = 200;
27
+ ctx.response.body = req;
28
+ }
29
+ catch(err) {
30
+ ctx.status = 500;
31
+ ctx.response.body = err;
32
+ }
33
+ };
34
+
35
+
36
+ /**
37
+ * Handles a GET /callbacks/{ID} request. This is a test support method that allows the caller
38
+ * to see the body of a previous incoming callback.
39
+ */
40
+ const getCallbackById = async(ctx) => {
41
+ try {
42
+ const req = await ctx.state.cache.get(`callback_${ctx.state.path.params.ID}`);
43
+ ctx.response.status = 200;
44
+ ctx.response.body = req;
45
+ }
46
+ catch(err) {
47
+ ctx.status = 500;
48
+ ctx.response.body = err;
49
+ }
50
+ };
51
+
52
+
53
+ module.exports = {
54
+ '/': {
55
+ get: healthCheck
56
+ },
57
+ '/requests/{ID}': {
58
+ get: getRequestById
59
+ },
60
+ '/callbacks/{ID}': {
61
+ get: getCallbackById
62
+ },
63
+ };
@@ -0,0 +1,215 @@
1
+ /**************************************************************************
2
+ * (C) Copyright ModusBox Inc. 2019 - All rights reserved. *
3
+ * *
4
+ * This file is made available under the terms of the license agreement *
5
+ * specified in the corresponding source code repository. *
6
+ * *
7
+ * ORIGINAL AUTHOR: *
8
+ * James Bush - james.bush@modusbox.com *
9
+ **************************************************************************/
10
+
11
+ const Koa = require('koa');
12
+ const ws = require('ws');
13
+
14
+ const http = require('http');
15
+ const yaml = require('js-yaml');
16
+ const fs = require('fs').promises;
17
+ const path = require('path');
18
+
19
+ const Validate = require('../lib/validate');
20
+ const router = require('../lib/router');
21
+ const handlers = require('./handlers');
22
+ const middlewares = require('../InboundServer/middlewares');
23
+
24
+ const getWsIp = (req) => [
25
+ req.socket.remoteAddress,
26
+ ...(
27
+ req.headers['x-forwarded-for']
28
+ ? req.headers['x-forwarded-for'].split(/\s*,\s*/)
29
+ : []
30
+ )
31
+ ];
32
+
33
+ class TestApi {
34
+ constructor(logger, validator, cache) {
35
+ this._api = new Koa();
36
+
37
+ this._api.use(middlewares.createErrorHandler(logger));
38
+ this._api.use(middlewares.createRequestIdGenerator());
39
+ this._api.use(middlewares.applyState({ cache }));
40
+ this._api.use(middlewares.createLogger(logger));
41
+
42
+ this._api.use(middlewares.createRequestValidator(validator));
43
+ this._api.use(router(handlers));
44
+ this._api.use(middlewares.createResponseBodyHandler());
45
+ }
46
+
47
+ callback() {
48
+ return this._api.callback();
49
+ }
50
+ }
51
+
52
+ class WsServer extends ws.Server {
53
+ constructor(logger, cache) {
54
+ super({ noServer: true });
55
+ this._wsClients = new Map();
56
+ this._logger = logger;
57
+ this._cache = cache;
58
+
59
+ this.on('error', err => {
60
+ this._logger.push({ err })
61
+ .log('Unhandled websocket error occurred. Shutting down.');
62
+ process.exit(1);
63
+ });
64
+
65
+ this.on('connection', (socket, req) => {
66
+ const logger = this._logger.push({
67
+ url: req.url,
68
+ ip: getWsIp(req),
69
+ remoteAddress: req.socket.remoteAddress,
70
+ });
71
+ logger.log('Websocket connection received');
72
+ this._wsClients.set(socket, req);
73
+ socket.on('close', (code, reason) => {
74
+ logger.push({ code, reason }).log('Websocket connection closed');
75
+ this._wsClients.delete(socket);
76
+ });
77
+ });
78
+ }
79
+
80
+ async start() {
81
+ await this._cache.subscribe(this._cache.EVENT_SET, this._handleCacheKeySet.bind(this));
82
+ }
83
+
84
+ // Close the server then wait for all the client sockets to close
85
+ async stop() {
86
+ await new Promise(resolve => this.close(resolve));
87
+ // If we don't wait for all clients to close before shutting down, the socket close
88
+ // handlers will be called after we return from this function, resulting in behaviour
89
+ // occurring after the server tells the user it has shutdown.
90
+ await Promise.all([...this._wsClients.keys()].map(socket =>
91
+ new Promise(resolve => socket.on('close', resolve))
92
+ ));
93
+ }
94
+
95
+ // Send the received notification to subscribers where appropriate.
96
+ async _handleCacheKeySet(channel, key, id) {
97
+ const logger = this._logger.push({ key });
98
+ logger.push({ channel, id }).log('Received Redis keyevent notification');
99
+
100
+ // Only notify clients of callback and request keyevents, as we don't want to encourage
101
+ // dependency on unintended behaviour (i.e. create a proxy Redis client by sending all
102
+ // keyevent notifications to the client). Some of this is implicitly performed later in
103
+ // this method, but we use the root path `/` to enable clients to subscribe to all events,
104
+ // so we filter them here.
105
+ const allowedPrefixes = [this._cache.CALLBACK_PREFIX, this._cache.REQUEST_PREFIX];
106
+ if (!allowedPrefixes.some((prefix) => key.startsWith(prefix))) {
107
+ logger.push({ allowedPrefixes })
108
+ .log('Notification not of allowed message type. Ignored.');
109
+ return;
110
+ }
111
+
112
+ // Map urls to callback prefixes. For example, as a user of this service, if I want to
113
+ // subscribe to Redis keyevent notifications with the prefix this._cache.REQUEST_PREFIX (at
114
+ // the time of writing, that's 'request_') then I'll connect to `ws://this-server/requests`.
115
+ // The map here defines that mapping, and exists to decouple the interface (the url) from
116
+ // the implementation (the "callback prefix").
117
+ const endpoints = {
118
+ REQUEST: '/requests',
119
+ CALLBACK: '/callbacks',
120
+ };
121
+ const urlToMsgPrefixMap = new Map([
122
+ [endpoints.REQUEST, this._cache.REQUEST_PREFIX],
123
+ [endpoints.CALLBACK, this._cache.CALLBACK_PREFIX],
124
+ ]);
125
+ let keyData; // declare outside the loop here, then retrieve at most once
126
+ let keyDataStr;
127
+ for (let [socket, req] of this._wsClients) {
128
+ // If
129
+ // - the url is the catch-all root (i.e. `ws://this-server/`), or
130
+ // - the url corresponds (via urlToMsgPrefixMap) to the message prefix for this
131
+ // message. E.g. if the url is /callbacks and the key is
132
+ // `${this._cache.CALLBACK_PREFIX}whatever`, or
133
+ // - the url matches the key, e.g. we replace the url prefix with the key prefix and
134
+ // obtain a match. E.g. the url is /callbacks/hello and the key is callback_hello.
135
+ // send the message to the client.
136
+ const prefix = urlToMsgPrefixMap.get(req.url);
137
+ const urlMatchesPrefix = urlToMsgPrefixMap.has(req.url) && key.startsWith(prefix);
138
+ const urlMatchesKey =
139
+ req.url.replace(new RegExp(`^${endpoints.REQUEST}/`), this._cache.REQUEST_PREFIX) === key ||
140
+ req.url.replace(new RegExp(`^${endpoints.CALLBACK}/`), this._cache.CALLBACK_PREFIX) === key;
141
+ if (req.url === '/' || urlMatchesPrefix || urlMatchesKey) {
142
+ if (!keyData || !keyDataStr) {
143
+ // Strip off the prefix and send the user the id
144
+ const requestId = [...urlToMsgPrefixMap.values()].reduce(
145
+ (key, prefix) => key.replace(new RegExp(`^${prefix}`), ''),
146
+ key
147
+ );
148
+ keyData = await this._cache.get(key);
149
+ keyDataStr = JSON.stringify({
150
+ ...keyData,
151
+ id: requestId,
152
+ });
153
+ }
154
+ this._logger
155
+ .push({
156
+ url: req.url,
157
+ key,
158
+ ip: getWsIp(req),
159
+ value: keyData,
160
+ prefix,
161
+ })
162
+ .log('Pushing notification to subscribed client');
163
+ socket.send(keyDataStr);
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ class TestServer {
170
+ constructor({ port, logger, cache }) {
171
+ this._port = port;
172
+ this._logger = logger;
173
+ this._validator = new Validate();
174
+ this._api = new TestApi(this._logger.push({ component: 'api' }), this._validator, cache);
175
+ this._server = http.createServer(this._api.callback());
176
+ // TODO: why does this appear to need to be called after creating this._server (try reorder
177
+ // it then run the tests)
178
+ this._wsapi = new WsServer(this._logger.push({ component: 'websocket-server' }), cache);
179
+ }
180
+
181
+ async start() {
182
+ if (this._server.listening) {
183
+ return;
184
+ }
185
+ const fileData = await fs.readFile(path.join(__dirname, 'api.yaml'));
186
+ await this._validator.initialise(yaml.load(fileData));
187
+
188
+ await this._wsapi.start();
189
+
190
+ this._server.on('upgrade', (req, socket, head) => {
191
+ this._wsapi.handleUpgrade(req, socket, head, (ws) =>
192
+ this._wsapi.emit('connection', ws, req));
193
+ });
194
+
195
+ await new Promise((resolve) => this._server.listen(this._port, resolve));
196
+
197
+ this._logger.log(`Serving test API on port ${this._port}`);
198
+ }
199
+
200
+ async stop() {
201
+ if (this._wsapi) {
202
+ this._logger.log('Shutting down websocket server');
203
+ this._wsapi.stop();
204
+ this._wsapi = null;
205
+ }
206
+ if (this._server) {
207
+ this._logger.log('Shutting down http server');
208
+ await new Promise(resolve => this._server.close(resolve));
209
+ this._server = null;
210
+ }
211
+ this._logger.log('Test server shutdown complete');
212
+ }
213
+ }
214
+
215
+ module.exports = TestServer;