@mimik/api-helper 1.0.3 → 1.1.1
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/README.md +12 -5
- package/index.js +53 -16
- package/lib/ajvHelpers.js +10 -1
- package/lib/oauthValidation-helper.js +2 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<dd><p>Setup and validates files for the server</p>
|
|
12
12
|
</dd>
|
|
13
13
|
<dt><a href="#validateSecuritySchemes">validateSecuritySchemes(apiDefinition, correlationId)</a> ⇒</dt>
|
|
14
|
-
<dd><p>Validates the known SecuritySchemes: <code>SystemSecurity</code>, <code>AdminSecurity</code>, <code>UserSecurity</code>, <code>PeerSecurity</code>.</p>
|
|
14
|
+
<dd><p>Validates the known SecuritySchemes: <code>SystemSecurity</code>, <code>AdminSecurity</code>, <code>UserSecurity</code>, <code>PeerSecurity</code>, <code>ApiKeySecurity</code>.</p>
|
|
15
15
|
</dd>
|
|
16
16
|
<dt><a href="#extractProperties">extractProperties(apiDefinition, controllersDirectory, buidDirectory, correlationId)</a> ⇒</dt>
|
|
17
17
|
<dd><p>Extracts the properties from API definiton and creates a file binding the handler with the controller operations.</p>
|
|
@@ -31,7 +31,14 @@ Setup the API to be use for a service
|
|
|
31
31
|
|
|
32
32
|
- <code>Promise</code> An error is thrown if the initiatilization failed.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
For the security schemes, the following scheme names are reserved: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `PeerSecurity`, `ApiKeySecurity`.
|
|
35
|
+
The secOptions in the options porperty passed when using `init` allows the folloing operations:
|
|
36
|
+
- introduce a customer sevurity scheme, in this case secOptions contains: { newSecurityScheme: {function}newSecurityHandler },
|
|
37
|
+
- disable a security scheme that is defined in the swagger API, in this case secOptions contains: { securitySchemeToDisable: { {boolean}notEnabled: true } },
|
|
38
|
+
- overwite an existing security scheme, in this case secOptions contains: { securitySchemeToOverwrite: {function}newSecurityHandler }.
|
|
39
|
+
If the secOptions is not present either to introduce, disable or overwrite a security scheme that is present in the swagger API file an error is generated.
|
|
40
|
+
|
|
41
|
+
The default formats for validation are: `date`, `time`, `date-time`, `byte`, `uuid`, `uri`, `email`, `ipv4`, `ipv6`, `semver`, `ip`.
|
|
35
42
|
|
|
36
43
|
**Requires**: <code>module:@mimik/response-helper</code>, <code>module:@mimik/sumologic-winston-logger</code>, <code>module:@mimik/swagger-helper</code>, <code>module:ajv-formats</code>, <code>module:fs</code>, <code>module:jsonwebtoken</code>, <code>module:lodash</code>
|
|
37
44
|
|
|
@@ -83,7 +90,7 @@ Setup and validates files for the server
|
|
|
83
90
|
|
|
84
91
|
**Kind**: global function
|
|
85
92
|
**Returns**: <code>Promise</code> - .
|
|
86
|
-
&fulfil {object} The API file, the API filename,
|
|
93
|
+
&fulfil {object} The API file, the API filename, the existing known security schemes and the defined security schemes.
|
|
87
94
|
**Category**: async
|
|
88
95
|
**Throws**:
|
|
89
96
|
|
|
@@ -102,10 +109,10 @@ Setup and validates files for the server
|
|
|
102
109
|
<a name="validateSecuritySchemes"></a>
|
|
103
110
|
|
|
104
111
|
## validateSecuritySchemes(apiDefinition, correlationId) ⇒
|
|
105
|
-
Validates the known SecuritySchemes: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `PeerSecurity`.
|
|
112
|
+
Validates the known SecuritySchemes: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `PeerSecurity`, `ApiKeySecurity`.
|
|
106
113
|
|
|
107
114
|
**Kind**: global function
|
|
108
|
-
**Returns**: An array of the
|
|
115
|
+
**Returns**: An array of the known securitySchemes that are in the API definition.
|
|
109
116
|
**Category**: sync
|
|
110
117
|
**Throws**:
|
|
111
118
|
|
package/index.js
CHANGED
|
@@ -3,6 +3,7 @@ const fs = require('fs');
|
|
|
3
3
|
const pathLib = require('path');
|
|
4
4
|
const yaml = require('js-yaml');
|
|
5
5
|
const compact = require('lodash.compact');
|
|
6
|
+
const difference = require('lodash.difference');
|
|
6
7
|
const SwaggerClient = require('swagger-client');
|
|
7
8
|
const { Base64 } = require('js-base64');
|
|
8
9
|
|
|
@@ -65,11 +66,23 @@ const {
|
|
|
65
66
|
* &fulfil {object} The API file itself.
|
|
66
67
|
* @throws {Promise} An error is thrown if the initiatilization failed.
|
|
67
68
|
*
|
|
68
|
-
*
|
|
69
|
+
* For the security schemes, the following scheme names are reserved: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `PeerSecurity`, `ApiKeySecurity`.
|
|
70
|
+
* The secOptions in the options porperty passed when using `init` allows the folloing operations:
|
|
71
|
+
* - introduce a customer sevurity scheme, in this case secOptions contains: { newSecurityScheme: {function}newSecurityHandler },
|
|
72
|
+
* - disable a security scheme that is defined in the swagger API, in this case secOptions contains: { securitySchemeToDisable: { {boolean}notEnabled: true } },
|
|
73
|
+
* - overwite an existing security scheme, in this case secOptions contains: { securitySchemeToOverwrite: {function}newSecurityHandler }.
|
|
74
|
+
* If the secOptions is not present either to introduce, disable or overwrite a security scheme that is present in the swagger API file an error is generated.
|
|
75
|
+
*
|
|
76
|
+
* The default formats for validation are: `date`, `time`, `date-time`, `byte`, `uuid`, `uri`, `email`, `ipv4`, `ipv6`, `semver`, `ip`.
|
|
69
77
|
*/
|
|
70
78
|
const apiSetup = (setup, registeredOperations, securityHandlers, extraFormats, config, correlationId) => {
|
|
71
|
-
const { apiFilename, existingSecuritySchemes } = setup;
|
|
72
|
-
const {
|
|
79
|
+
const { apiFilename, existingSecuritySchemes, definedSecuritySchemes } = setup;
|
|
80
|
+
const {
|
|
81
|
+
SystemSecurity,
|
|
82
|
+
AdminSecurity,
|
|
83
|
+
UserSecurity,
|
|
84
|
+
ApiKeySecurity,
|
|
85
|
+
} = securityLib(config);
|
|
73
86
|
const api = new OpenAPIBackend({
|
|
74
87
|
definition: apiFilename,
|
|
75
88
|
apiRoot: config.serverSettings.basePath,
|
|
@@ -92,20 +105,35 @@ const apiSetup = (setup, registeredOperations, securityHandlers, extraFormats, c
|
|
|
92
105
|
logger.warn('security disabled: tokens will not be used and /me and /onbehalf will not work', correlationId);
|
|
93
106
|
mode = SECURITY_OFF;
|
|
94
107
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
108
|
+
const appliedSecurities = [];
|
|
109
|
+
const registerDefault = (securitySchemeName, securityHandler) => {
|
|
110
|
+
if (existingSecuritySchemes.includes(securitySchemeName) && (!securityHandlers || (securityHandlers && !securityHandlers[securitySchemeName]))) {
|
|
111
|
+
api.registerSecurityHandler(securitySchemeName, securityHandler);
|
|
112
|
+
appliedSecurities.push(securitySchemeName);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
registerDefault(SYSTEM_SECURITY, SystemSecurity[mode]);
|
|
117
|
+
registerDefault(ADMIN_SECURITY, AdminSecurity[mode]);
|
|
118
|
+
registerDefault(USER_SECURITY, UserSecurity[mode]);
|
|
119
|
+
registerDefault(API_KEY_SECURITY, ApiKeySecurity[mode]);
|
|
120
|
+
const remainingSecurities = difference(definedSecuritySchemes, appliedSecurities);
|
|
121
|
+
|
|
98
122
|
if (securityHandlers) {
|
|
99
123
|
const securityHandlerNames = Object.keys(securityHandlers);
|
|
100
124
|
|
|
101
|
-
|
|
102
|
-
if (!securityHandlerNames.includes(securityScheme)
|
|
125
|
+
remainingSecurities.forEach((securityScheme) => {
|
|
126
|
+
if (!securityHandlerNames.includes(securityScheme) && !securityHandlers[securityScheme].notEnabled) {
|
|
127
|
+
throw getRichError('System', 'missing handler for security scheme', { securityScheme });
|
|
128
|
+
}
|
|
103
129
|
});
|
|
104
130
|
Object.keys(securityHandlers).forEach((securityHandlerName) => {
|
|
105
|
-
|
|
131
|
+
if (typeof securityHandlers[securityHandlerName][mode] === 'function') {
|
|
132
|
+
api.registerSecurityHandler(securityHandlerName, securityHandlers[securityHandlerName][mode]);
|
|
133
|
+
}
|
|
106
134
|
});
|
|
107
135
|
}
|
|
108
|
-
else if (
|
|
136
|
+
else if (remainingSecurities.length !== 0) throw getRichError('System', 'missing handlers for security schemes', { missingSecuritySchemes: remainingSecurities });
|
|
109
137
|
api.init()
|
|
110
138
|
.catch((err) => {
|
|
111
139
|
throw getRichError('System', 'could not initialize the api', { api }, err);
|
|
@@ -290,7 +318,7 @@ const getAPIFile = (apiFilename, correlationId, options) => {
|
|
|
290
318
|
|
|
291
319
|
/**
|
|
292
320
|
*
|
|
293
|
-
* Validates the known SecuritySchemes: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `PeerSecurity`.
|
|
321
|
+
* Validates the known SecuritySchemes: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `PeerSecurity`, `ApiKeySecurity`.
|
|
294
322
|
*
|
|
295
323
|
* @function validateSecuritySchemes
|
|
296
324
|
* @category sync
|
|
@@ -298,7 +326,7 @@ const getAPIFile = (apiFilename, correlationId, options) => {
|
|
|
298
326
|
* @requires @mimik/response-helper
|
|
299
327
|
* @param {object} apiDefinition - JSON object containing the API definition.
|
|
300
328
|
* @param {UUID.<string>} correlationId - CorrelationId when logging activites.
|
|
301
|
-
* @return An array of the
|
|
329
|
+
* @return An array of the known securitySchemes that are in the API definition.
|
|
302
330
|
* @throws An error is thrown for the first validation fails.
|
|
303
331
|
*/
|
|
304
332
|
const validateSecuritySchemes = (apiDefinition, correlationId) => {
|
|
@@ -308,8 +336,8 @@ const validateSecuritySchemes = (apiDefinition, correlationId) => {
|
|
|
308
336
|
logger.info('validating known security schemes', correlationId);
|
|
309
337
|
const { securitySchemes } = apiDefinition.components;
|
|
310
338
|
|
|
311
|
-
validateOauth2(securitySchemes, ADMIN_SECURITY, CLIENT_CREDENTIALS);
|
|
312
|
-
validateOauth2(securitySchemes, SYSTEM_SECURITY, CLIENT_CREDENTIALS);
|
|
339
|
+
existingSecuritySchemes.push(validateOauth2(securitySchemes, ADMIN_SECURITY, CLIENT_CREDENTIALS));
|
|
340
|
+
existingSecuritySchemes.push(validateOauth2(securitySchemes, SYSTEM_SECURITY, CLIENT_CREDENTIALS));
|
|
313
341
|
existingSecuritySchemes.push(validateOauth2(securitySchemes, PEER_SECURITY, CLIENT_CREDENTIALS));
|
|
314
342
|
existingSecuritySchemes.push(validateOauth2(securitySchemes, USER_SECURITY, IMPLICIT));
|
|
315
343
|
existingSecuritySchemes.push(validateApiKey(securitySchemes, API_KEY_SECURITY));
|
|
@@ -416,7 +444,7 @@ const extractProperties = (apiDefinition, controllersDirectory, buildDirectory,
|
|
|
416
444
|
* @param {UUID.<string>} correlationId - CorrelationId when logging activites.
|
|
417
445
|
* @param {object} options - Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiKey`` to access private API.
|
|
418
446
|
* @return {Promise}.
|
|
419
|
-
* &fulfil {object} The API file, the API filename,
|
|
447
|
+
* &fulfil {object} The API file, the API filename, the existing known security schemes and the defined security schemes.
|
|
420
448
|
* @throws {Promise} An error is thrown for many reasons assocated with getAPIFile or validateSecuritySchemes or extractProperties.
|
|
421
449
|
*/
|
|
422
450
|
const setupServerFiles = (apiFilename, controllersDirectory, buildDirectory, correlationId, options) => getAPIFile(apiFilename, correlationId, options)
|
|
@@ -424,7 +452,16 @@ const setupServerFiles = (apiFilename, controllersDirectory, buildDirectory, cor
|
|
|
424
452
|
const existingSecuritySchemes = compact(validateSecuritySchemes(apiDefinition, correlationId));
|
|
425
453
|
|
|
426
454
|
extractProperties(apiDefinition, controllersDirectory, buildDirectory, correlationId);
|
|
427
|
-
|
|
455
|
+
const schemes = apiDefinition.components?.securitySchemes;
|
|
456
|
+
let definedSecuritySchemes = [];
|
|
457
|
+
|
|
458
|
+
if (schemes) definedSecuritySchemes = Object.keys(schemes);
|
|
459
|
+
return {
|
|
460
|
+
apiDefinition,
|
|
461
|
+
apiFilename,
|
|
462
|
+
existingSecuritySchemes,
|
|
463
|
+
definedSecuritySchemes,
|
|
464
|
+
};
|
|
428
465
|
});
|
|
429
466
|
|
|
430
467
|
module.exports = {
|
package/lib/ajvHelpers.js
CHANGED
|
@@ -3,7 +3,16 @@ const addFormats = require('ajv-formats');
|
|
|
3
3
|
const { DEFAULT_FORMATS } = require('./common');
|
|
4
4
|
|
|
5
5
|
const ajvFormats = (origFormats) => (ajv) => {
|
|
6
|
-
const extraFormats = {
|
|
6
|
+
const extraFormats = {
|
|
7
|
+
semver: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
validate: /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/,
|
|
10
|
+
},
|
|
11
|
+
ip: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
validate: /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))/,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
7
16
|
const libFormats = DEFAULT_FORMATS;
|
|
8
17
|
let formats = origFormats;
|
|
9
18
|
|
|
@@ -13,8 +13,10 @@ const validateOauth2 = (securitySchemes, securityType, flow) => {
|
|
|
13
13
|
if (!security.flows[flow]) {
|
|
14
14
|
throw getRichError('System', 'no flow type available', { securityType, flow });
|
|
15
15
|
}
|
|
16
|
+
return securityType;
|
|
16
17
|
}
|
|
17
18
|
}
|
|
19
|
+
return null;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
const validateApiKey = (securitySchemes, securityType) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mimik/api-helper",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "helper for openAPI backend and mimik service",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"url": "https://bitbucket.org/mimiktech/api-helper"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@mimik/request-helper":"^1.7.
|
|
33
|
+
"@mimik/request-helper":"^1.7.11",
|
|
34
34
|
"@mimik/request-retry": "^3.0.1",
|
|
35
35
|
"@mimik/response-helper": "^3.1.0",
|
|
36
36
|
"@mimik/sumologic-winston-logger": "^1.6.21",
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
"eslint": "8.57.0",
|
|
52
52
|
"eslint-config-airbnb": "19.0.4",
|
|
53
53
|
"eslint-plugin-import": "2.29.1",
|
|
54
|
-
"eslint-plugin-jsx-a11y": "6.
|
|
55
|
-
"eslint-plugin-react": "7.
|
|
54
|
+
"eslint-plugin-jsx-a11y": "6.9.0",
|
|
55
|
+
"eslint-plugin-react": "7.35.0",
|
|
56
56
|
"eslint-plugin-react-hooks": "4.6.2",
|
|
57
|
-
"husky": "9.
|
|
58
|
-
"jsdoc-to-markdown": "8.0.
|
|
57
|
+
"husky": "9.1.4",
|
|
58
|
+
"jsdoc-to-markdown": "8.0.3"
|
|
59
59
|
}
|
|
60
60
|
}
|