@mojaloop/sdk-scheme-adapter 14.0.0 → 16.0.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.
- package/CHANGELOG.md +24 -0
- package/audit-resolve.json +59 -473
- package/docs/dfspInboundApi.yaml +11 -0
- package/package.json +27 -25
- package/src/ControlAgent/index.js +8 -11
- package/src/ControlServer/index.js +13 -13
- package/src/InboundServer/index.js +12 -61
- package/src/OAuthTestServer/index.js +0 -13
- package/src/OutboundServer/api.yaml +370 -44
- package/src/OutboundServer/index.js +11 -54
- package/src/TestServer/index.js +6 -33
- package/src/config.js +1 -4
- package/src/index.js +163 -146
- package/src/lib/cache.js +93 -186
- package/src/lib/metrics.js +1 -1
- package/src/lib/model/InboundTransfersModel.js +10 -6
- package/src/lib/model/OutboundTransfersModel.js +1 -1
- package/test/__mocks__/redis.js +51 -26
- package/test/config/integration.env +1 -2
- package/test/integration/lib/cache.test.js +1 -2
- package/test/integration/testEnv.js +1 -4
- package/test/unit/ControlClient.test.js +1 -45
- package/test/unit/ControlServer/index.js +18 -22
- package/test/unit/ControlServer.test.js +0 -60
- package/test/unit/InboundServer.test.js +8 -8
- package/test/unit/TestServer.test.js +1 -1
- package/test/unit/api/accounts/accounts.test.js +2 -2
- package/test/unit/api/transfers/transfers.test.js +1 -1
- package/test/unit/api/utils.js +12 -4
- package/test/unit/config.test.js +1 -2
- package/test/unit/data/defaultConfig.json +1 -5
- package/test/unit/index.test.js +5 -64
- package/test/unit/lib/cache.test.js +5 -6
- package/test/unit/lib/model/AccountsModel.test.js +3 -4
- package/test/unit/lib/model/InboundTransfersModel.test.js +55 -16
- package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +3 -4
- package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +1 -2
- package/test/unit/lib/model/OutboundRequestToPayModel.test.js +3 -4
- package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +3 -4
- package/test/unit/lib/model/OutboundTransfersModel.test.js +2 -3
- package/test/unit/lib/model/common/PersistentStateMachine.test.js +3 -4
- package/test/unit/lib/model/data/defaultConfig.json +1 -4
- package/test/unit/lib/model/data/notificationAbortedToPayee.json +10 -0
- package/test/unit/lib/model/data/notificationReservedToPayee.json +10 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mojaloop/sdk-scheme-adapter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.0",
|
|
4
4
|
"description": "An adapter for connecting to Mojaloop API enabled switches.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"updates:update": "npm run dep:update && npm install",
|
|
30
30
|
"dep:check": "npx ncu -e 2",
|
|
31
31
|
"dep:update": "npx ncu -u",
|
|
32
|
-
"release": "standard-version --releaseCommitMessageFormat 'chore(release): {{currentTag}} [skip ci]'"
|
|
32
|
+
"release": "standard-version --releaseCommitMessageFormat 'chore(release): {{currentTag}} [skip ci]'",
|
|
33
|
+
"snapshot": "standard-version --no-verify --skip.changelog --prerelease snapshot --releaseCommitMessageFormat 'chore(snapshot): {{currentTag}}'"
|
|
33
34
|
},
|
|
34
35
|
"author": "Matt Kingston, James Bush, ModusBox Inc.",
|
|
35
36
|
"contributors": [
|
|
@@ -39,7 +40,8 @@
|
|
|
39
40
|
"Shashikant Hirugade <shashikant.hirugade@modusbox.com>",
|
|
40
41
|
"Paweł Marzec <pawel.marzec@modusbox.com>",
|
|
41
42
|
"Kevin Leyow <kevin.leyow@modusbox.com",
|
|
42
|
-
"Miguel de Barros <miguel.debarros@modusbox.com>"
|
|
43
|
+
"Miguel de Barros <miguel.debarros@modusbox.com>",
|
|
44
|
+
"Yevhen Kyriukha <yevhen.kyriukha@modusbox.com>"
|
|
43
45
|
],
|
|
44
46
|
"license": "Apache-2.0",
|
|
45
47
|
"licenses": [
|
|
@@ -55,11 +57,11 @@
|
|
|
55
57
|
"dependencies": {
|
|
56
58
|
"@koa/cors": "^3.1.0",
|
|
57
59
|
"@mojaloop/central-services-shared": "17.0.2",
|
|
58
|
-
"@mojaloop/sdk-standard-components": "^17.0.
|
|
60
|
+
"@mojaloop/sdk-standard-components": "^17.0.4",
|
|
59
61
|
"ajv": "8.11.0",
|
|
60
|
-
"axios": "^0.
|
|
62
|
+
"axios": "^0.27.2",
|
|
61
63
|
"co-body": "^6.1.0",
|
|
62
|
-
"dotenv": "^
|
|
64
|
+
"dotenv": "^16.0.1",
|
|
63
65
|
"env-var": "^7.0.1",
|
|
64
66
|
"express": "^4.17.2",
|
|
65
67
|
"fast-json-patch": "^3.1.1",
|
|
@@ -67,36 +69,36 @@
|
|
|
67
69
|
"js-yaml": "^4.1.0",
|
|
68
70
|
"json-schema-ref-parser": "^9.0.9",
|
|
69
71
|
"koa": "^2.13.1",
|
|
70
|
-
"koa-body": "^
|
|
72
|
+
"koa-body": "^5.0.0",
|
|
71
73
|
"lodash": "^4.17.21",
|
|
72
74
|
"module-alias": "^2.2.2",
|
|
73
75
|
"oauth2-server": "^4.0.0-dev.2",
|
|
74
|
-
"openapi-jsonschema-parameters": "^
|
|
75
|
-
"prom-client": "^
|
|
76
|
+
"openapi-jsonschema-parameters": "^12.0.0",
|
|
77
|
+
"prom-client": "^14.0.1",
|
|
76
78
|
"promise-timeout": "^1.3.0",
|
|
77
79
|
"random-word-slugs": "^0.1.6",
|
|
78
|
-
"redis": "^
|
|
80
|
+
"redis": "^4.1.1",
|
|
79
81
|
"uuidv4": "^6.2.12",
|
|
80
|
-
"ws": "^
|
|
82
|
+
"ws": "^8.8.0"
|
|
81
83
|
},
|
|
82
84
|
"devDependencies": {
|
|
83
|
-
"@babel/core": "^7.
|
|
84
|
-
"@babel/preset-env": "^7.
|
|
85
|
-
"@mojaloop/api-snippets": "^
|
|
85
|
+
"@babel/core": "^7.18.6",
|
|
86
|
+
"@babel/preset-env": "^7.18.6",
|
|
87
|
+
"@mojaloop/api-snippets": "^14.0.0",
|
|
86
88
|
"@redocly/openapi-cli": "^1.0.0-beta.59",
|
|
87
|
-
"@types/jest": "^
|
|
88
|
-
"babel-jest": "^
|
|
89
|
-
"eslint": "^
|
|
90
|
-
"eslint-config-airbnb-base": "^
|
|
89
|
+
"@types/jest": "^28.1.4",
|
|
90
|
+
"babel-jest": "^28.1.2",
|
|
91
|
+
"eslint": "^8.18.0",
|
|
92
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
91
93
|
"eslint-plugin-import": "^2.24.2",
|
|
92
|
-
"eslint-plugin-jest": "^
|
|
93
|
-
"jest": "^
|
|
94
|
-
"jest-junit": "^
|
|
95
|
-
"nock": "^13.
|
|
94
|
+
"eslint-plugin-jest": "^26.5.3",
|
|
95
|
+
"jest": "^28.1.2",
|
|
96
|
+
"jest-junit": "^14.0.0",
|
|
97
|
+
"nock": "^13.2.8",
|
|
96
98
|
"npm-audit-resolver": "^3.0.0-0",
|
|
97
|
-
"npm-check-updates": "^
|
|
98
|
-
"openapi-response-validator": "^
|
|
99
|
-
"openapi-typescript": "^4.0
|
|
99
|
+
"npm-check-updates": "^15.0.1",
|
|
100
|
+
"openapi-response-validator": "^12.0.0",
|
|
101
|
+
"openapi-typescript": "^5.4.0",
|
|
100
102
|
"redis-mock": "^0.56.3",
|
|
101
103
|
"standard-version": "^9.3.1",
|
|
102
104
|
"supertest": "^6.1.6",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
// It expects new configuration to be supplied as an array of JSON patches. It therefore exposes
|
|
23
23
|
// the current configuration to
|
|
24
24
|
|
|
25
|
-
const assert = require('assert').strict;
|
|
26
25
|
const ws = require('ws');
|
|
27
26
|
const jsonPatch = require('fast-json-patch');
|
|
28
27
|
const { generateSlug } = require('random-word-slugs');
|
|
28
|
+
const _ = require('lodash');
|
|
29
29
|
|
|
30
30
|
/**************************************************************************
|
|
31
31
|
* The message protocol messages, verbs, and errors
|
|
@@ -163,15 +163,6 @@ class Client extends ws {
|
|
|
163
163
|
this.close();
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
reconfigure({ logger = this._logger, port = 0, appConfig = this._appConfig }) {
|
|
167
|
-
assert(port === this._socket.remotePort, 'Cannot reconfigure running port');
|
|
168
|
-
return () => {
|
|
169
|
-
this._logger = logger;
|
|
170
|
-
this._appConfig = appConfig;
|
|
171
|
-
this._logger.log('restarted');
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
166
|
// Handle incoming message from the server.
|
|
176
167
|
_handle(data) {
|
|
177
168
|
// TODO: json-schema validation of received message- should be pretty straight-forward
|
|
@@ -187,7 +178,13 @@ class Client extends ws {
|
|
|
187
178
|
switch (msg.msg) {
|
|
188
179
|
case MESSAGE.CONFIGURATION:
|
|
189
180
|
switch (msg.verb) {
|
|
190
|
-
case VERB.NOTIFY:
|
|
181
|
+
case VERB.NOTIFY: {
|
|
182
|
+
const dup = JSON.parse(JSON.stringify(this._appConfig)); // fast-json-patch explicitly mutates
|
|
183
|
+
_.merge(dup, msg.data);
|
|
184
|
+
this._logger.push({ oldConf: this._appConfig, newConf: dup }).log('Emitting new configuration');
|
|
185
|
+
this.emit(EVENT.RECONFIGURE, dup);
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
191
188
|
case VERB.PATCH: {
|
|
192
189
|
const dup = JSON.parse(JSON.stringify(this._appConfig)); // fast-json-patch explicitly mutates
|
|
193
190
|
jsonPatch.applyPatch(dup, msg.data);
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
// It expects new configuration to be supplied as an array of JSON patches. It therefore exposes
|
|
23
23
|
// the current configuration to
|
|
24
24
|
|
|
25
|
-
const assert = require('assert').strict;
|
|
26
25
|
|
|
27
26
|
const ws = require('ws');
|
|
28
27
|
const jsonPatch = require('fast-json-patch');
|
|
29
28
|
const { generateSlug } = require('random-word-slugs');
|
|
29
|
+
const _ = require('lodash');
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
/**************************************************************************
|
|
@@ -213,21 +213,14 @@ class Server extends ws.Server {
|
|
|
213
213
|
|
|
214
214
|
// Close the server then wait for all the client sockets to close
|
|
215
215
|
async stop() {
|
|
216
|
-
|
|
216
|
+
const closing = new Promise(resolve => this.close(resolve));
|
|
217
|
+
for (const client of this.clients) {
|
|
218
|
+
client.terminate();
|
|
219
|
+
}
|
|
220
|
+
await closing;
|
|
217
221
|
this._logger.log('Control server shutdown complete');
|
|
218
222
|
}
|
|
219
223
|
|
|
220
|
-
reconfigure({ logger = this._logger, port = 0, appConfig = this._appConfig }) {
|
|
221
|
-
assert(port === this._port, 'Cannot reconfigure running port');
|
|
222
|
-
return () => {
|
|
223
|
-
const reconfigureClientLogger =
|
|
224
|
-
({ logger: clientLogger }) => clientLogger.configure(logger);
|
|
225
|
-
this._clientData.values(reconfigureClientLogger);
|
|
226
|
-
this._logger = logger;
|
|
227
|
-
this._appConfig = appConfig;
|
|
228
|
-
this._logger.log('restarted');
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
224
|
|
|
232
225
|
async notifyClientsOfCurrentConfig() {
|
|
233
226
|
const updateConfMsg = build.CONFIGURATION.NOTIFY(this._appConfig);
|
|
@@ -261,6 +254,13 @@ class Server extends ws.Server {
|
|
|
261
254
|
case VERB.READ:
|
|
262
255
|
client.send(build.CONFIGURATION.NOTIFY(this._appConfig, msg.id));
|
|
263
256
|
break;
|
|
257
|
+
case VERB.NOTIFY: {
|
|
258
|
+
const dup = JSON.parse(JSON.stringify(this._appConfig)); // fast-json-patch explicitly mutates
|
|
259
|
+
_.merge(dup, msg.data);
|
|
260
|
+
this._logger.push({ oldConf: this._appConfig, newConf: dup }).log('Emitting new configuration');
|
|
261
|
+
this.emit(EVENT.RECONFIGURE, dup);
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
264
|
case VERB.PATCH: {
|
|
265
265
|
// TODO: validate the incoming patch? Or assume clients have used the
|
|
266
266
|
// client library?
|
|
@@ -18,33 +18,22 @@ const fs = require('fs');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const EventEmitter = require('events');
|
|
20
20
|
|
|
21
|
-
const { WSO2Auth } = require('@mojaloop/sdk-standard-components');
|
|
22
|
-
|
|
23
21
|
const Validate = require('../lib/validate');
|
|
24
22
|
const router = require('../lib/router');
|
|
25
23
|
const handlers = require('./handlers');
|
|
26
24
|
const middlewares = require('./middlewares');
|
|
27
|
-
const check = require('../lib/check');
|
|
28
25
|
|
|
29
26
|
class InboundApi extends EventEmitter {
|
|
30
|
-
constructor(conf, logger, cache, validator) {
|
|
27
|
+
constructor(conf, logger, cache, validator, wso2) {
|
|
31
28
|
super({ captureExceptions: true });
|
|
32
29
|
this._conf = conf;
|
|
33
30
|
this._cache = cache;
|
|
34
|
-
this._wso2 = {
|
|
35
|
-
auth: new WSO2Auth({
|
|
36
|
-
...conf.wso2.auth,
|
|
37
|
-
logger,
|
|
38
|
-
tlsCreds: conf.inbound.tls.mutualTLS.enabled && conf.inbound.tls.creds,
|
|
39
|
-
}),
|
|
40
|
-
retryWso2AuthFailureTimes: conf.wso2.requestAuthFailureRetryTimes,
|
|
41
|
-
};
|
|
42
|
-
this._wso2.auth.on('error', (msg) => {
|
|
43
|
-
this.emit('error', 'WSO2 auth error in InboundApi', msg);
|
|
44
|
-
});
|
|
45
31
|
|
|
46
32
|
if (conf.validateInboundJws) {
|
|
47
|
-
|
|
33
|
+
// peerJWSKey is a special config option specifically for Payment Manager for Mojaloop
|
|
34
|
+
// that is populated by a management api.
|
|
35
|
+
// This map supersedes local keys that would be loaded in by jwsVerificationKeysDirectory.
|
|
36
|
+
this._jwsVerificationKeys = conf.pm4mlEnabled ? conf.peerJWSKeys : InboundApi._GetJwsKeys(conf.jwsVerificationKeysDirectory);
|
|
48
37
|
}
|
|
49
38
|
this._api = InboundApi._SetupApi({
|
|
50
39
|
conf,
|
|
@@ -52,19 +41,15 @@ class InboundApi extends EventEmitter {
|
|
|
52
41
|
validator,
|
|
53
42
|
cache,
|
|
54
43
|
jwsVerificationKeys: this._jwsVerificationKeys,
|
|
55
|
-
wso2
|
|
44
|
+
wso2,
|
|
56
45
|
});
|
|
57
46
|
}
|
|
58
47
|
|
|
59
48
|
async start() {
|
|
60
49
|
this._startJwsWatcher();
|
|
61
|
-
if (!this._conf.testingDisableWSO2AuthStart) {
|
|
62
|
-
await this._wso2.auth.start();
|
|
63
|
-
}
|
|
64
50
|
}
|
|
65
51
|
|
|
66
52
|
stop() {
|
|
67
|
-
this._wso2.auth.stop();
|
|
68
53
|
if (this._keyWatcher) {
|
|
69
54
|
this._keyWatcher.close();
|
|
70
55
|
this._keyWatcher = null;
|
|
@@ -145,7 +130,7 @@ class InboundApi extends EventEmitter {
|
|
|
145
130
|
}
|
|
146
131
|
|
|
147
132
|
class InboundServer extends EventEmitter {
|
|
148
|
-
constructor(conf, logger, cache) {
|
|
133
|
+
constructor(conf, logger, cache, wso2) {
|
|
149
134
|
super({ captureExceptions: true });
|
|
150
135
|
this._conf = conf;
|
|
151
136
|
this._validator = new Validate();
|
|
@@ -154,7 +139,8 @@ class InboundServer extends EventEmitter {
|
|
|
154
139
|
conf,
|
|
155
140
|
this._logger.push({ component: 'api' }),
|
|
156
141
|
cache,
|
|
157
|
-
this._validator
|
|
142
|
+
this._validator,
|
|
143
|
+
wso2,
|
|
158
144
|
);
|
|
159
145
|
this._api.on('error', (...args) => {
|
|
160
146
|
this.emit('error', ...args);
|
|
@@ -173,52 +159,17 @@ class InboundServer extends EventEmitter {
|
|
|
173
159
|
await this._validator.initialise(apiSpecs);
|
|
174
160
|
await this._api.start();
|
|
175
161
|
await new Promise((resolve) => this._server.listen(this._conf.inbound.port, resolve));
|
|
176
|
-
this._logger.log(`Serving
|
|
162
|
+
this._logger.log(`Serving inbound API on port ${this._conf.inbound.port}`);
|
|
177
163
|
}
|
|
178
164
|
|
|
179
165
|
async stop() {
|
|
180
|
-
if (this._server) {
|
|
166
|
+
if (this._server.listening) {
|
|
181
167
|
await new Promise(resolve => this._server.close(resolve));
|
|
182
|
-
this._server = null;
|
|
183
|
-
}
|
|
184
|
-
if (this._api) {
|
|
185
|
-
await this._api.stop();
|
|
186
|
-
this._api = null;
|
|
187
168
|
}
|
|
169
|
+
await this._api.stop();
|
|
188
170
|
this._logger.log('inbound shut down complete');
|
|
189
171
|
}
|
|
190
172
|
|
|
191
|
-
async reconfigure(conf, logger, cache) {
|
|
192
|
-
// It may be possible to extract the socket from an existing HTTP/HTTPS server and replace
|
|
193
|
-
// it in a new server of the other type, as Node's HTTP and HTTPS servers both eventually
|
|
194
|
-
// are subclasses of net.Server. This wasn't considered as a requirement at the time of
|
|
195
|
-
// writing.
|
|
196
|
-
assert(
|
|
197
|
-
this._conf.inbound.tls.mutualTLS.enabled === conf.inbound.tls.mutualTLS.enabled,
|
|
198
|
-
'Cannot live-restart an HTTPS server as HTTP or vice versa',
|
|
199
|
-
);
|
|
200
|
-
const newApi = new InboundApi(conf, logger, cache, this._validator);
|
|
201
|
-
await newApi.start();
|
|
202
|
-
return () => {
|
|
203
|
-
this._logger = logger;
|
|
204
|
-
this._cache = cache;
|
|
205
|
-
// TODO: .tls might be undefined, causing an.. err.. undefined dereference..
|
|
206
|
-
const tlsCredsChanged = check.notDeepEqual(
|
|
207
|
-
conf.inbound.tls.creds,
|
|
208
|
-
this._conf.inbound.tls.creds
|
|
209
|
-
);
|
|
210
|
-
if (this._conf.inbound.tls.mutualTLS.enabled && tlsCredsChanged) {
|
|
211
|
-
this._server.setSecureContext(conf.inbound.tls.creds);
|
|
212
|
-
}
|
|
213
|
-
this._server.removeAllListeners('request');
|
|
214
|
-
this._server.on('request', newApi.callback());
|
|
215
|
-
this._api.stop();
|
|
216
|
-
this._api = newApi;
|
|
217
|
-
this._conf = conf;
|
|
218
|
-
this._logger.log('restarted');
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
|
|
222
173
|
_createServer(tlsEnabled, tlsCreds, handler) {
|
|
223
174
|
if (!tlsEnabled) {
|
|
224
175
|
return http.createServer(handler);
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
const { assert } = require('assert');
|
|
14
13
|
const express = require('express');
|
|
15
14
|
const bodyParser = require('body-parser');
|
|
16
15
|
const OAuth2Server = require('oauth2-server');
|
|
@@ -28,7 +27,6 @@ class OAuthTestServer {
|
|
|
28
27
|
* @param {Logger} conf.logger Logger
|
|
29
28
|
*/
|
|
30
29
|
constructor({ port, clientKey, clientSecret, logger }) {
|
|
31
|
-
this._api = null;
|
|
32
30
|
this._port = port;
|
|
33
31
|
this._logger = logger;
|
|
34
32
|
this._clientKey = clientKey;
|
|
@@ -65,17 +63,6 @@ class OAuthTestServer {
|
|
|
65
63
|
this._logger.log('OAuth2 Test Server shut down complete');
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
async reconfigure({ port, clientKey, clientSecret, logger }) {
|
|
69
|
-
assert(port === this._port, 'Cannot reconfigure running port');
|
|
70
|
-
return () => {
|
|
71
|
-
this._port = port;
|
|
72
|
-
this._logger = logger;
|
|
73
|
-
this.stop().then(() => this.start());
|
|
74
|
-
this._api = OAuthTestServer._SetupApi({ clientKey, clientSecret });
|
|
75
|
-
this._logger.log('restarted');
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
66
|
handleResponse(req, res, response) {
|
|
80
67
|
if (response.status === 302) {
|
|
81
68
|
const location = response.headers.location;
|