@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.
- package/.env.example +140 -0
- package/.eslintignore +2 -0
- package/.eslintrc.json +30 -0
- package/.nvmrc +1 -0
- package/.versionrc +15 -0
- package/CHANGELOG.md +118 -0
- package/InboundServer/api.yaml +3594 -0
- package/InboundServer/api_template.yaml +69 -0
- package/InboundServer/handlers.js +940 -0
- package/InboundServer/index.js +205 -0
- package/InboundServer/middlewares.js +426 -0
- package/OAuthTestServer/index.js +66 -0
- package/OAuthTestServer/model.js +70 -0
- package/OutboundServer/api.yaml +2732 -0
- package/OutboundServer/api_interfaces/index.d.ts +117 -0
- package/OutboundServer/api_interfaces/openapi.d.ts +1475 -0
- package/OutboundServer/api_template/components/parameters/bulkQuoteId.yaml +9 -0
- package/OutboundServer/api_template/components/parameters/bulkTransferId.yaml +9 -0
- package/OutboundServer/api_template/components/parameters/requestToPayTransactionId.yaml +9 -0
- package/OutboundServer/api_template/components/parameters/transferId.yaml +9 -0
- package/OutboundServer/api_template/components/responses/accountsCreationCompleted.yaml +5 -0
- package/OutboundServer/api_template/components/responses/accountsCreationError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/accountsCreationTimeout.yaml +5 -0
- package/OutboundServer/api_template/components/responses/authorizationPostSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/authorizationsServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkQuoteBadRequest.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkQuoteServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkQuoteSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkQuoteTimeout.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkTransferBadRequest.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkTransferServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkTransferSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkTransferTimeout.yaml +5 -0
- package/OutboundServer/api_template/components/responses/partiesByIdError404.yaml +9 -0
- package/OutboundServer/api_template/components/responses/partiesByIdSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/quotesPostSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/quotesServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/requestToPaySuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/requestToPayTransferBadRequest.yaml +5 -0
- package/OutboundServer/api_template/components/responses/requestToPayTransferSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/simpleTransfersPostSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/simpleTransfersServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/transferBadRequest.yaml +5 -0
- package/OutboundServer/api_template/components/responses/transferServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/transferSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/transferTimeout.yaml +5 -0
- package/OutboundServer/api_template/components/schemas/accountCreationStatus.yaml +18 -0
- package/OutboundServer/api_template/components/schemas/accountsCreationState.yaml +4 -0
- package/OutboundServer/api_template/components/schemas/accountsRequest.yaml +20 -0
- package/OutboundServer/api_template/components/schemas/accountsResponse.yaml +15 -0
- package/OutboundServer/api_template/components/schemas/async2SyncCurrentState.yaml +5 -0
- package/OutboundServer/api_template/components/schemas/authorizationsPostRequest.yaml +15 -0
- package/OutboundServer/api_template/components/schemas/authorizationsPostResponse.yaml +19 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteErrorResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteRequest.yaml +26 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteResponse.yaml +21 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteStatus.yaml +4 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteStatusResponse.yaml +17 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferErrorResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferRequest.yaml +26 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferResponse.yaml +16 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferStatus.yaml +4 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferStatusResponse.yaml +17 -0
- package/OutboundServer/api_template/components/schemas/errorAccountsResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/errorAuthorizationsResponse.yaml +3 -0
- package/OutboundServer/api_template/components/schemas/errorQuotesResponse.yaml +9 -0
- package/OutboundServer/api_template/components/schemas/errorResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/errorSimpleTransfersResponse.yaml +3 -0
- package/OutboundServer/api_template/components/schemas/errorTransferResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/extensionListEmptiable.yaml +6 -0
- package/OutboundServer/api_template/components/schemas/individualQuote.yaml +32 -0
- package/OutboundServer/api_template/components/schemas/individualQuoteResult.yaml +28 -0
- package/OutboundServer/api_template/components/schemas/individualTransfer.yaml +32 -0
- package/OutboundServer/api_template/components/schemas/individualTransferFulfilment.yaml +13 -0
- package/OutboundServer/api_template/components/schemas/individualTransferResult.yaml +41 -0
- package/OutboundServer/api_template/components/schemas/mojaloopError.yaml +5 -0
- package/OutboundServer/api_template/components/schemas/mojaloopTransactionRequestState.yaml +2 -0
- package/OutboundServer/api_template/components/schemas/partiesByIdResponse.yaml +13 -0
- package/OutboundServer/api_template/components/schemas/quote.yaml +3 -0
- package/OutboundServer/api_template/components/schemas/quoteError.yaml +16 -0
- package/OutboundServer/api_template/components/schemas/quotesPostRequest.yaml +13 -0
- package/OutboundServer/api_template/components/schemas/quotesPostResponse.yaml +48 -0
- package/OutboundServer/api_template/components/schemas/requestToPayRequest.yaml +39 -0
- package/OutboundServer/api_template/components/schemas/requestToPayResponse.yaml +41 -0
- package/OutboundServer/api_template/components/schemas/requestToPayTransferRequest.yaml +42 -0
- package/OutboundServer/api_template/components/schemas/requestToPayTransferResponse.yaml +58 -0
- package/OutboundServer/api_template/components/schemas/simpleTransferServerError.yaml +5 -0
- package/OutboundServer/api_template/components/schemas/simpleTransfersPostRequest.yaml +12 -0
- package/OutboundServer/api_template/components/schemas/simpleTransfersPostResponse.yaml +11 -0
- package/OutboundServer/api_template/components/schemas/transactionType.yaml +4 -0
- package/OutboundServer/api_template/components/schemas/transferContinuationAcceptOTP.yaml +9 -0
- package/OutboundServer/api_template/components/schemas/transferContinuationAcceptParty.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/transferContinuationAcceptQuote.yaml +9 -0
- package/OutboundServer/api_template/components/schemas/transferError.yaml +16 -0
- package/OutboundServer/api_template/components/schemas/transferFulfilment.yaml +3 -0
- package/OutboundServer/api_template/components/schemas/transferParty.yaml +40 -0
- package/OutboundServer/api_template/components/schemas/transferRequest.yaml +37 -0
- package/OutboundServer/api_template/components/schemas/transferResponse.yaml +58 -0
- package/OutboundServer/api_template/components/schemas/transferStatus.yaml +6 -0
- package/OutboundServer/api_template/components/schemas/transferStatusResponse.yaml +13 -0
- package/OutboundServer/api_template/health.yaml +12 -0
- package/OutboundServer/api_template/openapi.yaml +55 -0
- package/OutboundServer/api_template/paths/accounts.yaml +26 -0
- package/OutboundServer/api_template/paths/authorizations.yaml +19 -0
- package/OutboundServer/api_template/paths/bulkQuotes.yaml +23 -0
- package/OutboundServer/api_template/paths/bulkQuotes_bulkQuoteId.yaml +24 -0
- package/OutboundServer/api_template/paths/bulkTransfers.yaml +23 -0
- package/OutboundServer/api_template/paths/bulkTransfers_bulkTransferId.yaml +24 -0
- package/OutboundServer/api_template/paths/parties_Type_ID.yaml +20 -0
- package/OutboundServer/api_template/paths/parties_Type_ID_SubId.yaml +22 -0
- package/OutboundServer/api_template/paths/quotes.yaml +20 -0
- package/OutboundServer/api_template/paths/requestToPay.yaml +22 -0
- package/OutboundServer/api_template/paths/requestToPayTransfer.yaml +57 -0
- package/OutboundServer/api_template/paths/requestToPayTransfer_requestToPayTransactionId.yaml +34 -0
- package/OutboundServer/api_template/paths/simpleTransfers.yaml +19 -0
- package/OutboundServer/api_template/paths/transfers.yaml +55 -0
- package/OutboundServer/api_template/paths/transfers_transferId.yaml +58 -0
- package/OutboundServer/handlers.js +622 -0
- package/OutboundServer/index.js +137 -0
- package/OutboundServer/middlewares.js +67 -0
- package/TestServer/api.yaml +62 -0
- package/TestServer/handlers.js +63 -0
- package/TestServer/index.js +215 -0
- package/audit-resolve.json +65 -0
- package/babel.config.js +3 -0
- package/config.js +158 -0
- package/index.d.ts +1 -0
- package/index.js +149 -0
- package/jest.config.js +15 -0
- package/lib/api/index.js +12 -0
- package/lib/cache.js +352 -0
- package/lib/check.js +25 -0
- package/lib/model/AccountsModel.js +396 -0
- package/lib/model/Async2SyncModel.js +283 -0
- package/lib/model/AuthorizationsModel.js +86 -0
- package/lib/model/InboundTransfersModel.js +730 -0
- package/lib/model/OutboundBulkQuotesModel.js +485 -0
- package/lib/model/OutboundBulkTransfersModel.js +479 -0
- package/lib/model/OutboundRequestToPayModel.js +517 -0
- package/lib/model/OutboundRequestToPayTransferModel.js +893 -0
- package/lib/model/OutboundTransfersModel.js +823 -0
- package/lib/model/PartiesModel.js +70 -0
- package/lib/model/ProxyModel/MatchRules/Expression.js +48 -0
- package/lib/model/ProxyModel/MatchRules/Headers.js +65 -0
- package/lib/model/ProxyModel/MatchRules/MatchRule.js +27 -0
- package/lib/model/ProxyModel/MatchRules/Path.js +36 -0
- package/lib/model/ProxyModel/MatchRules/Query.js +65 -0
- package/lib/model/ProxyModel/MatchRules/index.js +19 -0
- package/lib/model/ProxyModel/Route.js +82 -0
- package/lib/model/ProxyModel/configSchema.json +118 -0
- package/lib/model/ProxyModel/index.js +138 -0
- package/lib/model/QuotesModel.js +94 -0
- package/lib/model/TransfersModel.js +81 -0
- package/lib/model/common/BackendError.js +26 -0
- package/lib/model/common/PersistentStateMachine.js +93 -0
- package/lib/model/common/index.js +18 -0
- package/lib/model/index.js +43 -0
- package/lib/model/lib/deferredJob.js +113 -0
- package/lib/model/lib/index.js +9 -0
- package/lib/model/lib/requests/backendRequests.js +227 -0
- package/lib/model/lib/requests/common.js +76 -0
- package/lib/model/lib/requests/index.js +19 -0
- package/lib/model/lib/shared.js +468 -0
- package/lib/randomphrase/index.js +21 -0
- package/lib/randomphrase/words.json +3397 -0
- package/lib/router.js +28 -0
- package/lib/validate.js +205 -0
- package/package.json +102 -0
- package/test/__mocks__/@mojaloop/sdk-standard-components.js +152 -0
- package/test/__mocks__/javascript-state-machine.js +21 -0
- package/test/__mocks__/redis.js +49 -0
- package/test/__mocks__/uuidv4.js +16 -0
- package/test/config/integration.env +136 -0
- package/test/integration/lib/Outbound/authorizations.test.js +58 -0
- package/test/integration/lib/Outbound/data/authorizationsPostRequest.json +43 -0
- package/test/integration/lib/Outbound/data/quotesPostRequest.json +52 -0
- package/test/integration/lib/Outbound/data/transfersPostRequest.json +24 -0
- package/test/integration/lib/Outbound/parties.test.js +28 -0
- package/test/integration/lib/Outbound/quotes.test.js +58 -0
- package/test/integration/lib/Outbound/simpleTransfers.test.js +67 -0
- package/test/integration/lib/cache.test.js +80 -0
- package/test/integration/testEnv.js +7 -0
- package/test/unit/InboundServer.test.js +443 -0
- package/test/unit/TestServer.test.js +394 -0
- package/test/unit/api/accounts/accounts.test.js +128 -0
- package/test/unit/api/accounts/data/postAccountsBody.json +7 -0
- package/test/unit/api/accounts/data/postAccountsErrorMojaloopResponse.json +25 -0
- package/test/unit/api/accounts/data/postAccountsErrorTimeoutResponse.json +19 -0
- package/test/unit/api/accounts/data/postAccountsSuccessResponse.json +17 -0
- package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError1.json +21 -0
- package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError2.json +21 -0
- package/test/unit/api/accounts/utils.js +65 -0
- package/test/unit/api/proxy/data/proxyConfig.yaml +82 -0
- package/test/unit/api/proxy/data/requestBody.json +22 -0
- package/test/unit/api/proxy/data/requestHeaders.json +5 -0
- package/test/unit/api/proxy/data/requestQuery.json +6 -0
- package/test/unit/api/proxy/data/responseBody.json +21 -0
- package/test/unit/api/proxy/data/responseHeaders.json +5 -0
- package/test/unit/api/proxy/proxy.test.js +220 -0
- package/test/unit/api/proxy/utils.js +79 -0
- package/test/unit/api/transfers/data/getTransfersCommittedResponse.json +21 -0
- package/test/unit/api/transfers/data/getTransfersErrorNotFound.json +17 -0
- package/test/unit/api/transfers/data/postQuotesBody.json +52 -0
- package/test/unit/api/transfers/data/postTransfersBadBody.json +17 -0
- package/test/unit/api/transfers/data/postTransfersBody.json +24 -0
- package/test/unit/api/transfers/data/postTransfersErrorMojaloopResponse.json +53 -0
- package/test/unit/api/transfers/data/postTransfersErrorTimeoutResponse.json +47 -0
- package/test/unit/api/transfers/data/postTransfersSimpleBody.json +26 -0
- package/test/unit/api/transfers/data/postTransfersSuccessResponse.json +101 -0
- package/test/unit/api/transfers/data/putPartiesBody.json +20 -0
- package/test/unit/api/transfers/data/putQuotesBody.json +37 -0
- package/test/unit/api/transfers/data/putTransfersBody.json +17 -0
- package/test/unit/api/transfers/transfers.test.js +191 -0
- package/test/unit/api/transfers/utils.js +183 -0
- package/test/unit/api/utils.js +75 -0
- package/test/unit/config.test.js +119 -0
- package/test/unit/data/commonHttpHeaders.json +6 -0
- package/test/unit/data/defaultConfig.json +58 -0
- package/test/unit/data/postQuotesBody.json +52 -0
- package/test/unit/data/putParticipantsBody.json +12 -0
- package/test/unit/data/putPartiesBody.json +20 -0
- package/test/unit/data/testFile.json +29 -0
- package/test/unit/data/testFile.yaml +14 -0
- package/test/unit/inboundApi/data/mockArguments.json +117 -0
- package/test/unit/inboundApi/data/mockTransactionRequest.json +42 -0
- package/test/unit/inboundApi/handlers.test.js +799 -0
- package/test/unit/index.test.js +55 -0
- package/test/unit/lib/cache.test.js +146 -0
- package/test/unit/lib/model/AccountsModel.test.js +121 -0
- package/test/unit/lib/model/AuthorizationsModel.test.js +460 -0
- package/test/unit/lib/model/InboundTransfersModel.test.js +628 -0
- package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +249 -0
- package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +244 -0
- package/test/unit/lib/model/OutboundRequestToPayModel.test.js +166 -0
- package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +245 -0
- package/test/unit/lib/model/OutboundTransfersModel.test.js +836 -0
- package/test/unit/lib/model/PartiesModel.test.js +468 -0
- package/test/unit/lib/model/QuotesModel.test.js +470 -0
- package/test/unit/lib/model/TransfersModel.test.js +474 -0
- package/test/unit/lib/model/common/PersistentStateMachine.test.js +179 -0
- package/test/unit/lib/model/data/authorizationsResponse.json +13 -0
- package/test/unit/lib/model/data/bulkQuoteRequest.json +27 -0
- package/test/unit/lib/model/data/bulkQuoteResponse.json +35 -0
- package/test/unit/lib/model/data/bulkTransferFulfil.json +13 -0
- package/test/unit/lib/model/data/bulkTransferRequest.json +29 -0
- package/test/unit/lib/model/data/defaultConfig.json +47 -0
- package/test/unit/lib/model/data/getBulkTransfersBackendResponse.json +42 -0
- package/test/unit/lib/model/data/getBulkTransfersMojaloopResponse.json +22 -0
- package/test/unit/lib/model/data/getTransfersBackendResponse.json +34 -0
- package/test/unit/lib/model/data/getTransfersMojaloopResponse.json +17 -0
- package/test/unit/lib/model/data/mockArguments.json +131 -0
- package/test/unit/lib/model/data/mockTxnRequestsArguments.json +63 -0
- package/test/unit/lib/model/data/notificationToPayee.json +10 -0
- package/test/unit/lib/model/data/payeeParty.json +16 -0
- package/test/unit/lib/model/data/putAuthorizationsResponse.json +10 -0
- package/test/unit/lib/model/data/putQuotesResponse.json +33 -0
- package/test/unit/lib/model/data/putTransfersResponse.json +5 -0
- package/test/unit/lib/model/data/quoteResponse.json +31 -0
- package/test/unit/lib/model/data/requestToPayRequest.json +20 -0
- package/test/unit/lib/model/data/requestToPayTransferRequest.json +27 -0
- package/test/unit/lib/model/data/transactionRequestResponse.json +18 -0
- package/test/unit/lib/model/data/transferFulfil.json +8 -0
- package/test/unit/lib/model/data/transferRequest.json +26 -0
- package/test/unit/lib/model/mockedLibRequests.js +74 -0
- package/test/unit/mockLogger.js +39 -0
- package/test/unit/outboundApi/data/bulkQuoteRequest.json +28 -0
- package/test/unit/outboundApi/data/bulkTransferRequest.json +28 -0
- package/test/unit/outboundApi/data/mockBulkQuoteError.json +45 -0
- package/test/unit/outboundApi/data/mockBulkTransferError.json +48 -0
- package/test/unit/outboundApi/data/mockError.json +41 -0
- package/test/unit/outboundApi/data/mockGetPartiesError.json +4 -0
- package/test/unit/outboundApi/data/mockRequestToPayError.json +32 -0
- package/test/unit/outboundApi/data/mockRequestToPayTransferError.json +39 -0
- package/test/unit/outboundApi/data/requestToPay.json +21 -0
- package/test/unit/outboundApi/data/requestToPayTransferRequest.json +20 -0
- package/test/unit/outboundApi/data/transferRequest.json +21 -0
- 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;
|