@mimik/api-helper 1.0.2 → 1.1.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/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
- By default System and Admin security are automatically registered
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, and the existing know security schemes.
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 know securitySchemes that are in the API definition.
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
- * By default System and Admin security are automatically registered
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 { SystemSecurity, AdminSecurity } = securityLib(config);
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
- api.registerSecurityHandler(SYSTEM_SECURITY, SystemSecurity[mode]);
96
- api.registerSecurityHandler(ADMIN_SECURITY, AdminSecurity[mode]);
97
- // api.registerSecurityHandler('ApiKeySecurity', ApiKeySecurity[mode]);
108
+ const appliedSecurities = [];
109
+ const registerDefault = (securitySchemeName, securityHandler) => {
110
+ if (existingSecuritySchemes.includes(securitySchemeName) && 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
- existingSecuritySchemes.forEach((securityScheme) => {
102
- if (!securityHandlerNames.includes(securityScheme)) throw getRichError('System', 'missing handler for security Scheme', { 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
- api.registerSecurityHandler(securityHandlerName, securityHandlers[securityHandlerName][mode]);
131
+ if (typeof securityHandlers[securityHandlerName][mode] === 'function') {
132
+ api.registerSecurityHandler(securityHandlerName, securityHandlers[securityHandlerName][mode]);
133
+ }
106
134
  });
107
135
  }
108
- else if (existingSecuritySchemes.length !== 0) throw getRichError('System', 'missing handlers for security Scheme', { existingSecuritySchemes });
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 know securitySchemes that are in the API definition.
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, and the existing know security schemes.
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
- return { apiDefinition, apiFilename, existingSecuritySchemes };
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.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "helper for openAPI backend and mimik service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -30,31 +30,31 @@
30
30
  "url": "https://bitbucket.org/mimiktech/api-helper"
31
31
  },
32
32
  "dependencies": {
33
- "@mimik/request-helper":"^1.7.10",
33
+ "@mimik/request-helper":"^1.7.11",
34
34
  "@mimik/request-retry": "^3.0.1",
35
- "@mimik/response-helper": "^3.0.1",
36
- "@mimik/sumologic-winston-logger": "^1.6.20",
35
+ "@mimik/response-helper": "^3.1.0",
36
+ "@mimik/sumologic-winston-logger": "^1.6.21",
37
37
  "@mimik/swagger-helper": "^4.0.9",
38
- "ajv-formats": "3.0.0-rc.0",
39
- "js-base64": "3.7.5",
38
+ "ajv-formats": "3.0.1",
39
+ "js-base64": "3.7.7",
40
40
  "js-yaml":"4.1.0",
41
41
  "jsonwebtoken": "9.0.2",
42
42
  "lodash.compact": "3.0.1",
43
43
  "lodash.difference": "4.5.0",
44
44
  "lodash.intersection": "4.4.0",
45
- "openapi-backend": "5.10.5",
46
- "swagger-client": "3.24.5"
45
+ "openapi-backend": "5.10.6",
46
+ "swagger-client": "3.28.2"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@mimik/eslint-plugin-dependencies": "^2.4.6",
50
50
  "@mimik/eslint-plugin-document-env": "^1.0.6",
51
- "eslint": "8.55.0",
51
+ "eslint": "8.57.0",
52
52
  "eslint-config-airbnb": "19.0.4",
53
- "eslint-plugin-import": "2.29.0",
54
- "eslint-plugin-jsx-a11y": "6.8.0",
55
- "eslint-plugin-react": "7.33.2",
56
- "eslint-plugin-react-hooks": "4.6.0",
57
- "husky": "8.0.3",
58
- "jsdoc-to-markdown": "8.0.0"
53
+ "eslint-plugin-import": "2.29.1",
54
+ "eslint-plugin-jsx-a11y": "6.9.0",
55
+ "eslint-plugin-react": "7.35.0",
56
+ "eslint-plugin-react-hooks": "4.6.2",
57
+ "husky": "9.1.4",
58
+ "jsdoc-to-markdown": "8.0.3"
59
59
  }
60
60
  }