@itentialopensource/adapter-utils 4.49.0 → 5.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 +10 -0
- package/README.md +2 -0
- package/lib/brokerHandler.js +730 -0
- package/lib/cacheHandler.js +968 -0
- package/lib/connectorRest.js +28 -13
- package/lib/dbUtil.js +0 -3
- package/lib/genericHandler.js +280 -0
- package/lib/propertyUtil.js +134 -3
- package/lib/requestHandler.js +683 -209
- package/lib/translatorUtil.js +5 -4
- package/package.json +26 -26
- package/refs?service=git-upload-pack +0 -0
- package/schemas/propertiesSchema.json +576 -1
package/lib/connectorRest.js
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
/* global adapters brokers g_redis log */
|
|
5
5
|
/* eslint class-methods-use-this:warn */
|
|
6
6
|
/* eslint consistent-return:warn */
|
|
7
|
+
/* eslint no-promise-executor-return:warn */
|
|
7
8
|
/* eslint import/no-dynamic-require:warn */
|
|
9
|
+
/* eslint camelcase:warn */
|
|
8
10
|
/* eslint no-underscore-dangle: [2, { "allow": ["_id"] }] */
|
|
9
11
|
/* eslint no-unused-vars:warn */
|
|
10
12
|
/* eslint no-use-before-define:warn */
|
|
@@ -368,10 +370,17 @@ function returnStub(request, entitySchema, callProperties) {
|
|
|
368
370
|
const reqBody = request.body;
|
|
369
371
|
const reqPath = request.header.path;
|
|
370
372
|
|
|
371
|
-
// these logs are very useful when debugging - however
|
|
373
|
+
// these logs are very useful when debugging - however had to change so we do not log credentials
|
|
372
374
|
if (authLogging) {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
+
// Can only mask values if header is an object - so can not log anything else
|
|
376
|
+
if (request.header) {
|
|
377
|
+
log.debug(`FULL STUB REQUEST: ${JSON.stringify(propUtilInst.scrubSensitiveInfo(request.header))}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Can only mask values if body is an object - so can not log anything else
|
|
381
|
+
if (request.body) {
|
|
382
|
+
log.debug(`FULL STUB BODY: ${JSON.stringify(propUtilInst.scrubSensitiveInfo(request.body))}`);
|
|
383
|
+
}
|
|
375
384
|
}
|
|
376
385
|
|
|
377
386
|
const callResp = {
|
|
@@ -744,8 +753,8 @@ function makeRequest(request, entitySchema, callProperties, startTrip, attempt,
|
|
|
744
753
|
|
|
745
754
|
// these logs are very useful when debugging - however there is the potential for credentials to be exposed.
|
|
746
755
|
if (authLogging) {
|
|
747
|
-
log.debug(`FULL REQUEST: ${JSON.stringify(request.header)}`);
|
|
748
|
-
log.debug(`FULL BODY: ${request.body}`);
|
|
756
|
+
log.debug(`FULL REQUEST: ${JSON.stringify(propUtilInst.scrubSensitiveInfo(request.header))}`);
|
|
757
|
+
log.debug(`FULL BODY: ${JSON.stringify(propUtilInst.scrubSensitiveInfo(request.body))}`);
|
|
749
758
|
}
|
|
750
759
|
|
|
751
760
|
// make the call to System
|
|
@@ -867,7 +876,7 @@ function makeRequest(request, entitySchema, callProperties, startTrip, attempt,
|
|
|
867
876
|
healthy = true;
|
|
868
877
|
doneH2(true);
|
|
869
878
|
}, (retH2) => {
|
|
870
|
-
log.debug(`${origin}: CALL RETURN ${JSON.stringify(callResp)}`);
|
|
879
|
+
log.debug(`${origin}: CALL RETURN ${JSON.stringify(propUtilInst.scrubSensitiveInfo(callResp))}`);
|
|
871
880
|
useProt = undefined;
|
|
872
881
|
callResp.reqHdr = request.header.headers;
|
|
873
882
|
return callback(callResp);
|
|
@@ -1203,7 +1212,7 @@ async function getToken(reqPath, options, tokenSchema, bodyString, callPropertie
|
|
|
1203
1212
|
return resolve({ token: 'faketoken', tokenp2: 'faketoken' });
|
|
1204
1213
|
}
|
|
1205
1214
|
|
|
1206
|
-
log.debug(`${origin}: OPTIONS: ${JSON.stringify(options)}`);
|
|
1215
|
+
log.debug(`${origin}: OPTIONS: ${JSON.stringify(propUtilInst.scrubSensitiveInfo(options))}`);
|
|
1207
1216
|
|
|
1208
1217
|
// request the token
|
|
1209
1218
|
return makeRequest(request, tokenSchema, callProperties, null, 0, (result, merror) => {
|
|
@@ -1728,10 +1737,16 @@ async function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
|
|
|
1728
1737
|
tokenSchema.sso.protocol = sso.protocol;
|
|
1729
1738
|
}
|
|
1730
1739
|
}
|
|
1731
|
-
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.host) {
|
|
1740
|
+
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.host && (sso == null || sso.host === '') && entity === 'getToken') {
|
|
1741
|
+
options.hostname = tokenSchema.sso.host;
|
|
1742
|
+
}
|
|
1743
|
+
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.port && (sso == null || sso.port === '') && entity === 'getToken') {
|
|
1744
|
+
options.port = tokenSchema.sso.port;
|
|
1745
|
+
}
|
|
1746
|
+
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.host && entity !== 'getToken') {
|
|
1732
1747
|
options.hostname = tokenSchema.sso.host;
|
|
1733
1748
|
}
|
|
1734
|
-
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.port) {
|
|
1749
|
+
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.port && entity !== 'getToken') {
|
|
1735
1750
|
options.port = tokenSchema.sso.port;
|
|
1736
1751
|
}
|
|
1737
1752
|
|
|
@@ -4403,10 +4418,10 @@ class ConnectorRest {
|
|
|
4403
4418
|
log.info(`${origin}: Connector SSL connections enabled`);
|
|
4404
4419
|
}
|
|
4405
4420
|
|
|
4406
|
-
log.debug(`${origin}: HEALTHCHECK OPTIONS: ${JSON.stringify(options)}`);
|
|
4421
|
+
log.debug(`${origin}: HEALTHCHECK OPTIONS: ${JSON.stringify(this.propUtil.scrubSensitiveInfo(options))}`);
|
|
4407
4422
|
|
|
4408
4423
|
if (payload !== undefined && payload !== null && payload !== '') {
|
|
4409
|
-
log.debug(`${origin}: REQUEST: ${payload}`);
|
|
4424
|
+
log.debug(`${origin}: REQUEST: ${JSON.stringify(this.propUtil.scrubSensitiveInfo(payload))}`);
|
|
4410
4425
|
|
|
4411
4426
|
// save it in memory
|
|
4412
4427
|
cacheHPay = payload;
|
|
@@ -4598,10 +4613,10 @@ class ConnectorRest {
|
|
|
4598
4613
|
log.info(`${origin}: Connector SSL connections enabled`);
|
|
4599
4614
|
}
|
|
4600
4615
|
|
|
4601
|
-
log.debug(`${origin}: OPTIONS: ${JSON.stringify(options)}`);
|
|
4616
|
+
log.debug(`${origin}: OPTIONS: ${JSON.stringify(this.propUtil.scrubSensitiveInfo(options))}`);
|
|
4602
4617
|
|
|
4603
4618
|
if (incoming.body !== undefined && incoming.body !== null && incoming.body !== '') {
|
|
4604
|
-
log.debug(`${origin}:REQUEST: ${incoming.body}`);
|
|
4619
|
+
log.debug(`${origin}:REQUEST: ${JSON.stringify(this.propUtil.scrubSensitiveInfo(incoming.body))}`);
|
|
4605
4620
|
}
|
|
4606
4621
|
|
|
4607
4622
|
const request = {
|
package/lib/dbUtil.js
CHANGED
|
@@ -595,7 +595,6 @@ class DBUtil {
|
|
|
595
595
|
*/
|
|
596
596
|
determineStorage(dbInfo, callback) {
|
|
597
597
|
const origin = `${this.myid}-dbUtil-determineStorage`;
|
|
598
|
-
|
|
599
598
|
if (dbInfo) {
|
|
600
599
|
// priority 1 - use the dbInfo passed in
|
|
601
600
|
if (dbInfo.dburl && dbInfo.database) {
|
|
@@ -1208,7 +1207,6 @@ class DBUtil {
|
|
|
1208
1207
|
find(collectionName, options, dbInfo, fsWrite, callback) {
|
|
1209
1208
|
const origin = `${this.myid}-dbUtil-find`;
|
|
1210
1209
|
log.trace(origin);
|
|
1211
|
-
|
|
1212
1210
|
try {
|
|
1213
1211
|
// verify the required data has been provided
|
|
1214
1212
|
if (!collectionName) {
|
|
@@ -1272,7 +1270,6 @@ class DBUtil {
|
|
|
1272
1270
|
log.debug(`${origin}: Data retrieved from file storage`);
|
|
1273
1271
|
return callback(null, toReturn);
|
|
1274
1272
|
}
|
|
1275
|
-
|
|
1276
1273
|
// if using MongoDB storage
|
|
1277
1274
|
if (storage === Storage.DBINFO || storage === Storage.ADAPTERDB) {
|
|
1278
1275
|
// Find the data in the database
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/* @copyright Itential, LLC 2023 */
|
|
2
|
+
|
|
3
|
+
// Set globals
|
|
4
|
+
/* global log */
|
|
5
|
+
|
|
6
|
+
/* NodeJS internal utilities */
|
|
7
|
+
|
|
8
|
+
class GenericHandler {
|
|
9
|
+
/**
|
|
10
|
+
* Adapter Generic Handler
|
|
11
|
+
* @constructor
|
|
12
|
+
*/
|
|
13
|
+
constructor(prongId, properties, reqH) {
|
|
14
|
+
this.myid = prongId;
|
|
15
|
+
this.allProps = properties;
|
|
16
|
+
this.requestHandlerInst = reqH;
|
|
17
|
+
|
|
18
|
+
// set up the properties I care about
|
|
19
|
+
this.refreshProperties(properties);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* refreshProperties is used to set up all of the properties for the broker handler.
|
|
24
|
+
* It allows properties to be changed later by simply calling refreshProperties rather
|
|
25
|
+
* than having to restart the broker handler.
|
|
26
|
+
*
|
|
27
|
+
* @function refreshProperties
|
|
28
|
+
* @param {Object} properties - an object containing all of the properties
|
|
29
|
+
*/
|
|
30
|
+
refreshProperties(properties) {
|
|
31
|
+
const origin = `${this.myid}-genericHandler-refreshProperties`;
|
|
32
|
+
log.trace(origin);
|
|
33
|
+
|
|
34
|
+
if (!properties) {
|
|
35
|
+
log.error(`${origin}: Generic Handler received no properties!`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Makes the requested generic call
|
|
41
|
+
*
|
|
42
|
+
* @function expandedGenericAdapterRequest
|
|
43
|
+
* @param {Object} metadata - metadata for the call (optional).
|
|
44
|
+
* Can be a stringified Object.
|
|
45
|
+
* @param {String} uriPath - the path of the api call - do not include the host, port, base path or version (optional)
|
|
46
|
+
* @param {String} restMethod - the rest method (GET, POST, PUT, PATCH, DELETE) (optional)
|
|
47
|
+
* @param {Object} pathVars - the parameters to be put within the url path (optional).
|
|
48
|
+
* Can be a stringified Object.
|
|
49
|
+
* @param {Object} queryData - the parameters to be put on the url (optional).
|
|
50
|
+
* Can be a stringified Object.
|
|
51
|
+
* @param {Object} requestBody - the body to add to the request (optional).
|
|
52
|
+
* Can be a stringified Object.
|
|
53
|
+
* @param {Object} addlHeaders - additional headers to be put on the call (optional).
|
|
54
|
+
* Can be a stringified Object.
|
|
55
|
+
* @param {getCallback} callback - a callback function to return the result (Generics)
|
|
56
|
+
* or the error
|
|
57
|
+
*/
|
|
58
|
+
expandedGenericAdapterRequest(metadata, uriPath, restMethod, pathVars, queryData, requestBody, addlHeaders, callback) {
|
|
59
|
+
const meth = 'genericHandler-expandedGenericAdapterRequest';
|
|
60
|
+
const origin = `${this.myid}-${meth}`;
|
|
61
|
+
log.trace(origin);
|
|
62
|
+
|
|
63
|
+
// if metadata says not to use BasePath
|
|
64
|
+
if (metadata && metadata.basepath && metadata.basepath.toUpperCase() === 'NOBASE') {
|
|
65
|
+
this.genericAdapterRequestNoBasePath(uriPath, restMethod, queryData, requestBody, addlHeaders, callback);
|
|
66
|
+
}
|
|
67
|
+
// use BasePath
|
|
68
|
+
this.genericAdapterRequest(uriPath, restMethod, queryData, requestBody, addlHeaders, callback);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Makes the requested generic call
|
|
73
|
+
*
|
|
74
|
+
* @function genericAdapterRequest
|
|
75
|
+
* @param {String} uriPath - the path of the api call - do not include the host, port, base path or version (required)
|
|
76
|
+
* @param {String} restMethod - the rest method (GET, POST, PUT, PATCH, DELETE) (required)
|
|
77
|
+
* @param {Object} queryData - the parameters to be put on the url (optional).
|
|
78
|
+
* Can be a stringified Object.
|
|
79
|
+
* @param {Object} requestBody - the body to add to the request (optional).
|
|
80
|
+
* Can be a stringified Object.
|
|
81
|
+
* @param {Object} addlHeaders - additional headers to be put on the call (optional).
|
|
82
|
+
* Can be a stringified Object.
|
|
83
|
+
* @param {getCallback} callback - a callback function to return the result (Generics)
|
|
84
|
+
* or the error
|
|
85
|
+
*/
|
|
86
|
+
genericAdapterRequest(uriPath, restMethod, queryData, requestBody, addlHeaders, callback) {
|
|
87
|
+
const meth = 'genericHandler-genericAdapterRequest';
|
|
88
|
+
const origin = `${this.myid}-${meth}`;
|
|
89
|
+
log.trace(origin);
|
|
90
|
+
|
|
91
|
+
/* HERE IS WHERE YOU VALIDATE DATA */
|
|
92
|
+
if (uriPath === undefined || uriPath === null || uriPath === '') {
|
|
93
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Data', ['uriPath'], null, null, null);
|
|
94
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
95
|
+
return callback(null, errorObj);
|
|
96
|
+
}
|
|
97
|
+
if (restMethod === undefined || restMethod === null || restMethod === '') {
|
|
98
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Data', ['restMethod'], null, null, null);
|
|
99
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
100
|
+
return callback(null, errorObj);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* HERE IS WHERE YOU SET THE DATA TO PASS INTO REQUEST */
|
|
104
|
+
// remove any leading / and split the uripath into path variables
|
|
105
|
+
let myPath = uriPath;
|
|
106
|
+
while (myPath.indexOf('/') === 0) {
|
|
107
|
+
myPath = myPath.substring(1);
|
|
108
|
+
}
|
|
109
|
+
const pathVars = myPath.split('/');
|
|
110
|
+
const queryParamsAvailable = queryData;
|
|
111
|
+
const queryParams = {};
|
|
112
|
+
const bodyVars = requestBody;
|
|
113
|
+
|
|
114
|
+
// loop in template. long callback arg name to avoid identifier conflicts
|
|
115
|
+
Object.keys(queryParamsAvailable).forEach((thisKeyInQueryParamsAvailable) => {
|
|
116
|
+
if (queryParamsAvailable[thisKeyInQueryParamsAvailable] !== undefined && queryParamsAvailable[thisKeyInQueryParamsAvailable] !== null
|
|
117
|
+
&& queryParamsAvailable[thisKeyInQueryParamsAvailable] !== '') {
|
|
118
|
+
queryParams[thisKeyInQueryParamsAvailable] = queryParamsAvailable[thisKeyInQueryParamsAvailable];
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// set up the request object - payload, uriPathVars, uriQuery, uriOptions, addlHeaders
|
|
123
|
+
const reqObj = {
|
|
124
|
+
payload: bodyVars,
|
|
125
|
+
uriPathVars: pathVars,
|
|
126
|
+
uriQuery: queryParams,
|
|
127
|
+
uriOptions: {}
|
|
128
|
+
};
|
|
129
|
+
// add headers if provided
|
|
130
|
+
if (addlHeaders) {
|
|
131
|
+
reqObj.addlHeaders = addlHeaders;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// determine the call and return flag
|
|
135
|
+
let action = 'getGenerics';
|
|
136
|
+
let returnF = true;
|
|
137
|
+
if (restMethod.toUpperCase() === 'POST') {
|
|
138
|
+
action = 'createGeneric';
|
|
139
|
+
} else if (restMethod.toUpperCase() === 'PUT') {
|
|
140
|
+
action = 'updateGeneric';
|
|
141
|
+
} else if (restMethod.toUpperCase() === 'PATCH') {
|
|
142
|
+
action = 'patchGeneric';
|
|
143
|
+
} else if (restMethod.toUpperCase() === 'DELETE') {
|
|
144
|
+
action = 'deleteGeneric';
|
|
145
|
+
returnF = false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
// Make the call -
|
|
150
|
+
// identifyRequest(entity, action, requestObj, returnDataFlag, callback)
|
|
151
|
+
return this.requestHandlerInst.identifyRequest('.generic', action, reqObj, returnF, (irReturnData, irReturnError) => {
|
|
152
|
+
// if we received an error or their is no response on the results
|
|
153
|
+
// return an error
|
|
154
|
+
if (irReturnError) {
|
|
155
|
+
/* HERE IS WHERE YOU CAN ALTER THE ERROR MESSAGE */
|
|
156
|
+
return callback(null, irReturnError);
|
|
157
|
+
}
|
|
158
|
+
if (!Object.hasOwnProperty.call(irReturnData, 'response')) {
|
|
159
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Invalid Response', ['genericAdapterRequest'], null, null, null);
|
|
160
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
161
|
+
return callback(null, errorObj);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* HERE IS WHERE YOU CAN ALTER THE RETURN DATA */
|
|
165
|
+
// return the response
|
|
166
|
+
return callback(irReturnData, null);
|
|
167
|
+
});
|
|
168
|
+
} catch (ex) {
|
|
169
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Caught Exception', null, null, null, ex);
|
|
170
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
171
|
+
return callback(null, errorObj);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Makes the requested generic call with no base path or version
|
|
177
|
+
*
|
|
178
|
+
* @function genericAdapterRequestNoBasePath
|
|
179
|
+
* @param {String} uriPath - the path of the api call - do not include the host, port, base path or version (required)
|
|
180
|
+
* @param {String} restMethod - the rest method (GET, POST, PUT, PATCH, DELETE) (required)
|
|
181
|
+
* @param {Object} queryData - the parameters to be put on the url (optional).
|
|
182
|
+
* Can be a stringified Object.
|
|
183
|
+
* @param {Object} requestBody - the body to add to the request (optional).
|
|
184
|
+
* Can be a stringified Object.
|
|
185
|
+
* @param {Object} addlHeaders - additional headers to be put on the call (optional).
|
|
186
|
+
* Can be a stringified Object.
|
|
187
|
+
* @param {getCallback} callback - a callback function to return the result (Generics)
|
|
188
|
+
* or the error
|
|
189
|
+
*/
|
|
190
|
+
genericAdapterRequestNoBasePath(uriPath, restMethod, queryData, requestBody, addlHeaders, callback) {
|
|
191
|
+
const meth = 'genericHandler-genericAdapterRequestNoBasePath';
|
|
192
|
+
const origin = `${this.myid}-${meth}`;
|
|
193
|
+
log.trace(origin);
|
|
194
|
+
|
|
195
|
+
/* HERE IS WHERE YOU VALIDATE DATA */
|
|
196
|
+
if (uriPath === undefined || uriPath === null || uriPath === '') {
|
|
197
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Data', ['uriPath'], null, null, null);
|
|
198
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
199
|
+
return callback(null, errorObj);
|
|
200
|
+
}
|
|
201
|
+
if (restMethod === undefined || restMethod === null || restMethod === '') {
|
|
202
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Data', ['restMethod'], null, null, null);
|
|
203
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
204
|
+
return callback(null, errorObj);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* HERE IS WHERE YOU SET THE DATA TO PASS INTO REQUEST */
|
|
208
|
+
// remove any leading / and split the uripath into path variables
|
|
209
|
+
let myPath = uriPath;
|
|
210
|
+
while (myPath.indexOf('/') === 0) {
|
|
211
|
+
myPath = myPath.substring(1);
|
|
212
|
+
}
|
|
213
|
+
const pathVars = myPath.split('/');
|
|
214
|
+
const queryParamsAvailable = queryData;
|
|
215
|
+
const queryParams = {};
|
|
216
|
+
const bodyVars = requestBody;
|
|
217
|
+
|
|
218
|
+
// loop in template. long callback arg name to avoid identifier conflicts
|
|
219
|
+
Object.keys(queryParamsAvailable).forEach((thisKeyInQueryParamsAvailable) => {
|
|
220
|
+
if (queryParamsAvailable[thisKeyInQueryParamsAvailable] !== undefined && queryParamsAvailable[thisKeyInQueryParamsAvailable] !== null
|
|
221
|
+
&& queryParamsAvailable[thisKeyInQueryParamsAvailable] !== '') {
|
|
222
|
+
queryParams[thisKeyInQueryParamsAvailable] = queryParamsAvailable[thisKeyInQueryParamsAvailable];
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// set up the request object - payload, uriPathVars, uriQuery, uriOptions, addlHeaders
|
|
227
|
+
const reqObj = {
|
|
228
|
+
payload: bodyVars,
|
|
229
|
+
uriPathVars: pathVars,
|
|
230
|
+
uriQuery: queryParams,
|
|
231
|
+
uriOptions: {}
|
|
232
|
+
};
|
|
233
|
+
// add headers if provided
|
|
234
|
+
if (addlHeaders) {
|
|
235
|
+
reqObj.addlHeaders = addlHeaders;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// determine the call and return flag
|
|
239
|
+
let action = 'getGenericsNoBase';
|
|
240
|
+
let returnF = true;
|
|
241
|
+
if (restMethod.toUpperCase() === 'POST') {
|
|
242
|
+
action = 'createGenericNoBase';
|
|
243
|
+
} else if (restMethod.toUpperCase() === 'PUT') {
|
|
244
|
+
action = 'updateGenericNoBase';
|
|
245
|
+
} else if (restMethod.toUpperCase() === 'PATCH') {
|
|
246
|
+
action = 'patchGenericNoBase';
|
|
247
|
+
} else if (restMethod.toUpperCase() === 'DELETE') {
|
|
248
|
+
action = 'deleteGenericNoBase';
|
|
249
|
+
returnF = false;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
// Make the call -
|
|
254
|
+
// identifyRequest(entity, action, requestObj, returnDataFlag, callback)
|
|
255
|
+
return this.requestHandlerInst.identifyRequest('.generic', action, reqObj, returnF, (irReturnData, irReturnError) => {
|
|
256
|
+
// if we received an error or their is no response on the results
|
|
257
|
+
// return an error
|
|
258
|
+
if (irReturnError) {
|
|
259
|
+
/* HERE IS WHERE YOU CAN ALTER THE ERROR MESSAGE */
|
|
260
|
+
return callback(null, irReturnError);
|
|
261
|
+
}
|
|
262
|
+
if (!Object.hasOwnProperty.call(irReturnData, 'response')) {
|
|
263
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Invalid Response', ['genericAdapterRequestNoBasePath'], null, null, null);
|
|
264
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
265
|
+
return callback(null, errorObj);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* HERE IS WHERE YOU CAN ALTER THE RETURN DATA */
|
|
269
|
+
// return the response
|
|
270
|
+
return callback(irReturnData, null);
|
|
271
|
+
});
|
|
272
|
+
} catch (ex) {
|
|
273
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Caught Exception', null, null, null, ex);
|
|
274
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
275
|
+
return callback(null, errorObj);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
module.exports = GenericHandler;
|
package/lib/propertyUtil.js
CHANGED
|
@@ -363,10 +363,16 @@ class AdapterPropertyUtil {
|
|
|
363
363
|
if (entitySchema.responseDatatype && entitySchema.responseDatatype.toUpperCase() === 'PLAIN') {
|
|
364
364
|
// read the mock date from the file system
|
|
365
365
|
mockResponse.response = fs.readFileSync(mockFileName, 'utf-8');
|
|
366
|
+
if (!mockResponse.response) {
|
|
367
|
+
mockResponse.response = 'mock file empty!';
|
|
368
|
+
}
|
|
366
369
|
} else if (entitySchema.responseDatatype && (entitySchema.responseDatatype.toUpperCase() === 'XML'
|
|
367
370
|
|| entitySchema.responseDatatype.toUpperCase() === 'XML2JSON')) {
|
|
368
371
|
// read the mock date from the file system
|
|
369
372
|
mockResponse.response = fs.readFileSync(mockFileName, 'utf-8');
|
|
373
|
+
if (!mockResponse.response) {
|
|
374
|
+
mockResponse.response = '<mock>file empty!</mock>';
|
|
375
|
+
}
|
|
370
376
|
} else {
|
|
371
377
|
// read the mock date from the file system
|
|
372
378
|
try {
|
|
@@ -374,7 +380,7 @@ class AdapterPropertyUtil {
|
|
|
374
380
|
mockResponse.response = JSON.parse(fs.readFileSync(mockFileName, 'utf-8'));
|
|
375
381
|
} catch (excep) {
|
|
376
382
|
log.warn(`${origin}: Could not parse file - ${mockFileName}`);
|
|
377
|
-
mockResponse.response = '';
|
|
383
|
+
mockResponse.response = { mock: 'file empty or parse error!' };
|
|
378
384
|
}
|
|
379
385
|
}
|
|
380
386
|
} else {
|
|
@@ -435,7 +441,6 @@ class AdapterPropertyUtil {
|
|
|
435
441
|
origin,
|
|
436
442
|
isError: true
|
|
437
443
|
};
|
|
438
|
-
|
|
439
444
|
try {
|
|
440
445
|
// verify required data
|
|
441
446
|
if (!entityName || typeof entityName !== 'string') {
|
|
@@ -854,7 +859,6 @@ class AdapterPropertyUtil {
|
|
|
854
859
|
getEntitySchema(entityName, actionName, choosepath, dbUtils, callback) {
|
|
855
860
|
const origin = `${this.myid}-propertyUtil-getEntitySchema`;
|
|
856
861
|
log.trace(origin);
|
|
857
|
-
|
|
858
862
|
// need to try to get the entity schema from the adapter database
|
|
859
863
|
try {
|
|
860
864
|
// call to get the adapter schema from the database
|
|
@@ -948,6 +952,133 @@ class AdapterPropertyUtil {
|
|
|
948
952
|
return defaults;
|
|
949
953
|
}
|
|
950
954
|
|
|
955
|
+
/**
|
|
956
|
+
* @summary Takes in an item that may have sensitive data and scrubs it before
|
|
957
|
+
* it would get logged.
|
|
958
|
+
*
|
|
959
|
+
* @function scrubSensitiveInfo
|
|
960
|
+
* @param {String/Object} inData - the data to scrub
|
|
961
|
+
* @param {Array} addItems - additional items to scrub
|
|
962
|
+
*
|
|
963
|
+
* @return {Object} the object with default values from the property schema
|
|
964
|
+
*/
|
|
965
|
+
scrubSensitiveInfo(inData, addItems) {
|
|
966
|
+
const origin = `${this.myid}-propertyUtil-scrubSensitiveInfo`;
|
|
967
|
+
log.trace(origin);
|
|
968
|
+
|
|
969
|
+
// no reason to scan numbers, booleans or functions
|
|
970
|
+
if (!inData || typeof inData === 'number' || typeof inData === 'boolean' || typeof inData === 'function') {
|
|
971
|
+
return inData;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// This is the array of sensitive keys
|
|
975
|
+
let sensList = ['authorization', 'x-auth-token', 'x-csrf-token', 'x-amz-security-token', 'x-aws-ec2-metadata-token', 'cookie', 'set-cookie', 'token', 'tokenp2', 'user', 'username', 'passwd', 'password', 'api-key', 'client-id', 'client-secret', 'session', 'session-id'];
|
|
976
|
+
|
|
977
|
+
// add any additional items to scrub
|
|
978
|
+
if (addItems && Array.isArray(addItems) && addItems.length > 0) {
|
|
979
|
+
sensList = sensList.concat(addItems);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// going to use copy of data so we do not mess up input - if object will still need to assign it
|
|
983
|
+
let actualData = inData;
|
|
984
|
+
|
|
985
|
+
// if we are scrubbing an array
|
|
986
|
+
if (Array.isArray(actualData)) {
|
|
987
|
+
// need to go through each item in the array
|
|
988
|
+
for (let i = 0; i < actualData.length; i += 1) {
|
|
989
|
+
actualData[i] = this.scrubSensitiveInfo(actualData[i]);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// return the scrubbed array
|
|
993
|
+
return actualData;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// if we are scrubbbing a string (e.g. URL)
|
|
997
|
+
if (typeof actualData === 'string') {
|
|
998
|
+
// if it is a Stringified JSON
|
|
999
|
+
try {
|
|
1000
|
+
// need to see if it is stringified JSON
|
|
1001
|
+
actualData = JSON.parse(inData);
|
|
1002
|
+
// if this was able to be parsed, we should handle it as an object
|
|
1003
|
+
} catch (ex) {
|
|
1004
|
+
// if not JSON, can only scrub the query (e.g. after ?)
|
|
1005
|
+
actualData = inData;
|
|
1006
|
+
const dataParts = actualData.split('?');
|
|
1007
|
+
|
|
1008
|
+
// if there is no query data - we are done
|
|
1009
|
+
if (dataParts.length === 0) {
|
|
1010
|
+
return actualData;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// start what we return
|
|
1014
|
+
let retData = `${dataParts[0]}?`;
|
|
1015
|
+
let count = 0;
|
|
1016
|
+
|
|
1017
|
+
// query format - key=value& or key=value{end of url}
|
|
1018
|
+
const queryData = dataParts[1].split('&');
|
|
1019
|
+
|
|
1020
|
+
// analyze the query fields
|
|
1021
|
+
for (let i = 0; i < queryData.length; i += 1) {
|
|
1022
|
+
// key of the query field
|
|
1023
|
+
const key = queryData[i].split('=');
|
|
1024
|
+
let found = false;
|
|
1025
|
+
|
|
1026
|
+
// add any & to separate query params
|
|
1027
|
+
if (count > 0) {
|
|
1028
|
+
retData += '&';
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// go through sensitive word list - maybe can use find in
|
|
1032
|
+
for (let j = 0; j < sensList.length; j += 1) {
|
|
1033
|
+
if (key.toUpperCase() === sensList[j].toUpperCase()) {
|
|
1034
|
+
// if sensitive, mask
|
|
1035
|
+
retData += `${key}=** masked **`;
|
|
1036
|
+
found = true;
|
|
1037
|
+
count += 1;
|
|
1038
|
+
break;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// if not sensitive - just append back on url
|
|
1043
|
+
if (!found) {
|
|
1044
|
+
retData += queryData[i];
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// return the scrubbed string
|
|
1049
|
+
return retData;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// if we are scrubbing an object (or string that has been parsed)
|
|
1054
|
+
if (typeof actualData === 'object') {
|
|
1055
|
+
const retData = { ...actualData };
|
|
1056
|
+
|
|
1057
|
+
// go through each item in the object
|
|
1058
|
+
Object.keys(retData).forEach((key) => {
|
|
1059
|
+
// go deep through an object with recursive call
|
|
1060
|
+
if (typeof retData[key] === 'object') {
|
|
1061
|
+
retData[key] = this.scrubSensitiveInfo(retData[key]);
|
|
1062
|
+
} else {
|
|
1063
|
+
// go through sensitive word list - maybe can use find in
|
|
1064
|
+
for (let j = 0; j < sensList.length; j += 1) {
|
|
1065
|
+
if (key.toUpperCase() === sensList[j].toUpperCase()) {
|
|
1066
|
+
// if sensitive, mask
|
|
1067
|
+
retData[key] = '=** masked **';
|
|
1068
|
+
break;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
// return the scrubbed object
|
|
1075
|
+
return retData;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// if something we do not handle yet - just return the data
|
|
1079
|
+
return actualData;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
951
1082
|
/**
|
|
952
1083
|
* @summary Takes in properties and the secondary properties and merges them so the returned
|
|
953
1084
|
* object has secondary properties where no primary property values were provided.
|