serverless-openapi-documenter 0.0.100 → 0.0.102
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 +3 -1
- package/package.json +1 -1
- package/src/definitionGenerator.js +1 -7
- package/src/openAPIGenerator.js +33 -21
- package/src/owasp.js +147 -118
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ Options:
|
|
|
48
48
|
--format -f Whether to output the OpenAPI Description as json or yaml. Default: json
|
|
49
49
|
--indent -i File indentation in spaces. Default: 2
|
|
50
50
|
--openApiVersion -a OpenAPI version to generate for. Default: 3.0.0
|
|
51
|
-
--postmanCollection -p Will generate a postman collection (from the generated OpenAPI Description), in json only, if passed in. Default postman.json
|
|
51
|
+
--postmanCollection -p Will generate a postman collection (from the generated OpenAPI Description), in json only, if passed in. Default: postman.json
|
|
52
52
|
--validationWarn -w Warn about validation errors only. Will write the OpenAPI file if generation is successful. Default: false
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -968,6 +968,8 @@ However, you can configure your own rules from the [ruleset available on the Red
|
|
|
968
968
|
}
|
|
969
969
|
```
|
|
970
970
|
|
|
971
|
+
Since rules can be set to "warn", you no longer are required to tell the plugin to ignore errors with the `--validationWarn` flag.
|
|
972
|
+
|
|
971
973
|
## Example configuration
|
|
972
974
|
|
|
973
975
|
Please view the example [serverless.yml](test/serverless-tests/best/serverless.yml).
|
package/package.json
CHANGED
|
@@ -1021,19 +1021,13 @@ class DefinitionGenerator {
|
|
|
1021
1021
|
|
|
1022
1022
|
const apiDesc = stringifyYaml(this.openAPI);
|
|
1023
1023
|
|
|
1024
|
-
|
|
1024
|
+
return await lintFromString({
|
|
1025
1025
|
source: apiDesc,
|
|
1026
1026
|
config: config,
|
|
1027
1027
|
}).catch((err) => {
|
|
1028
1028
|
console.error(err);
|
|
1029
1029
|
throw err;
|
|
1030
1030
|
});
|
|
1031
|
-
|
|
1032
|
-
if (results.length) {
|
|
1033
|
-
throw results;
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
return true;
|
|
1037
1031
|
}
|
|
1038
1032
|
}
|
|
1039
1033
|
|
package/src/openAPIGenerator.js
CHANGED
|
@@ -195,23 +195,29 @@ class OpenAPIGenerator {
|
|
|
195
195
|
|
|
196
196
|
this.log(`Validating generated OpenAPI Description`, this.logTypes.NOTICE);
|
|
197
197
|
|
|
198
|
-
await generator.validate().catch((err) => {
|
|
198
|
+
const validationResults = await generator.validate().catch((err) => {
|
|
199
199
|
this.log(
|
|
200
200
|
`ERROR: An error was thrown validating the OpenAPI v3 Description`,
|
|
201
201
|
this.logTypes.ERROR
|
|
202
202
|
);
|
|
203
203
|
|
|
204
|
-
this.
|
|
204
|
+
throw new this.serverless.classes.Error(err);
|
|
205
|
+
});
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
let message = "Error validating OpenAPI Description:\r\n";
|
|
208
|
-
for (const errorMessage of err) {
|
|
209
|
-
message += `${errorMessage.message}\r\n`;
|
|
210
|
-
}
|
|
207
|
+
this.validationErrorDetails(validationResults);
|
|
211
208
|
|
|
212
|
-
|
|
209
|
+
if (validationResults.length && this.config.validationWarn === false) {
|
|
210
|
+
let message = "Error validating OpenAPI Description:\r\n";
|
|
211
|
+
let shouldThrow = false;
|
|
212
|
+
for (const error of validationResults) {
|
|
213
|
+
message += `${error.message}\r\n`;
|
|
214
|
+
if (error.severity === "error") {
|
|
215
|
+
shouldThrow = true;
|
|
216
|
+
}
|
|
213
217
|
}
|
|
214
|
-
|
|
218
|
+
|
|
219
|
+
if (shouldThrow) throw new this.serverless.classes.Error(message);
|
|
220
|
+
}
|
|
215
221
|
|
|
216
222
|
this.log(
|
|
217
223
|
"OpenAPI v3 Description Successfully Generated",
|
|
@@ -306,24 +312,30 @@ class OpenAPIGenerator {
|
|
|
306
312
|
this.config = config;
|
|
307
313
|
}
|
|
308
314
|
|
|
309
|
-
validationErrorDetails(
|
|
310
|
-
|
|
311
|
-
`${chalk.bold.yellow(
|
|
312
|
-
"[VALIDATION]"
|
|
313
|
-
)} Validation errors found in OpenAPI Description: \n`,
|
|
314
|
-
this.logTypes.ERROR
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
for (const error of validationError) {
|
|
315
|
+
validationErrorDetails(validationErrors) {
|
|
316
|
+
if (validationErrors.length) {
|
|
318
317
|
this.log(
|
|
319
|
-
`${chalk.bold.yellow(
|
|
318
|
+
`${chalk.bold.yellow(
|
|
319
|
+
"[VALIDATION]"
|
|
320
|
+
)} Validation errors found in OpenAPI Description: \n`,
|
|
320
321
|
this.logTypes.ERROR
|
|
321
322
|
);
|
|
322
|
-
|
|
323
|
+
|
|
324
|
+
for (const error of validationErrors) {
|
|
323
325
|
this.log(
|
|
324
|
-
`${chalk.bold.
|
|
326
|
+
`${chalk.bold.red("Severity:")} ${error.severity}`,
|
|
325
327
|
this.logTypes.ERROR
|
|
326
328
|
);
|
|
329
|
+
this.log(
|
|
330
|
+
`${chalk.bold.yellow("Message:")} ${error.message}`,
|
|
331
|
+
this.logTypes.ERROR
|
|
332
|
+
);
|
|
333
|
+
for (const location of error.location) {
|
|
334
|
+
this.log(
|
|
335
|
+
`${chalk.bold.yellow("found at location:")} ${location.pointer}`,
|
|
336
|
+
this.logTypes.ERROR
|
|
337
|
+
);
|
|
338
|
+
}
|
|
327
339
|
}
|
|
328
340
|
}
|
|
329
341
|
}
|
package/src/owasp.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const https = require(
|
|
3
|
+
const https = require("https");
|
|
4
4
|
|
|
5
|
-
const defaultOWASP = require(
|
|
5
|
+
const defaultOWASP = require("../json/owasp.json");
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @typedef {Object} Header
|
|
@@ -17,125 +17,154 @@ const defaultOWASP = require('../json/owasp.json')
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
class OWASP {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
20
|
+
constructor() {
|
|
21
|
+
this.DEFAULT_OWASP_HEADERS = {
|
|
22
|
+
"Cache-Control": {
|
|
23
|
+
description:
|
|
24
|
+
"The Cache-Control HTTP header field holds directives (instructions) — in both requests and responses — that control [caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching) in browsers and shared caches (e.g. Proxies, CDNs). - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)",
|
|
25
|
+
},
|
|
26
|
+
"Clear-Site-Data": {
|
|
27
|
+
description:
|
|
28
|
+
"The Clear-Site-Data header clears browsing data (cookies, storage, cache) associated with the requesting website. It allows web developers to have more control over the data stored by a client browser for their origins. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data)",
|
|
29
|
+
},
|
|
30
|
+
"Content-Security-Policy": {
|
|
31
|
+
description:
|
|
32
|
+
"The HTTP Content-Security-Policy response header allows website administrators to control resources the user agent is allowed to load for a given page. With a few exceptions, policies mostly involve specifying server origins and script endpoints. This helps guard against cross-site scripting attacks ([Cross-site scripting](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting)). - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)",
|
|
33
|
+
},
|
|
34
|
+
"Cross-Origin-Embedder-Policy": {
|
|
35
|
+
description:
|
|
36
|
+
"The HTTP Cross-Origin-Embedder-Policy (COEP) response header configures embedding cross-origin resources into the document. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy)",
|
|
37
|
+
},
|
|
38
|
+
"Cross-Origin-Opener-Policy": {
|
|
39
|
+
description:
|
|
40
|
+
"The HTTP Cross-Origin-Opener-Policy (COOP) response header allows you to ensure a top-level document does not share a browsing context group with cross-origin documents. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy)",
|
|
41
|
+
},
|
|
42
|
+
"Cross-Origin-Resource-Policy": {
|
|
43
|
+
description:
|
|
44
|
+
"Cross-Origin Resource Policy is a policy set by the Cross-Origin-Resource-Policy HTTP header that lets websites and applications opt in to protection against certain requests from other origins (such as those issued with elements like <script> and <img>), to mitigate speculative side-channel attacks, like Spectre, as well as Cross-Site Script Inclusion attacks. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy)",
|
|
45
|
+
},
|
|
46
|
+
"Permissions-Policy": {
|
|
47
|
+
description:
|
|
48
|
+
"The HTTP Permissions-Policy header provides a mechanism to allow and deny the use of browser features in a document or within any [<iframe>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) elements in the document. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy)",
|
|
49
|
+
},
|
|
50
|
+
Pragma: {
|
|
51
|
+
description:
|
|
52
|
+
"The Pragma HTTP/1.0 general header is an implementation-specific header that may have various effects along the request-response chain. This header serves for backwards compatibility with the HTTP/1.0 caches that do not have a [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) HTTP/1.1 header. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Pragma)",
|
|
53
|
+
deprecated: true,
|
|
54
|
+
},
|
|
55
|
+
"Referrer-Policy": {
|
|
56
|
+
description:
|
|
57
|
+
"The Referrer-Policy [HTTP header](https://developer.mozilla.org/en-US/docs/Glossary/HTTP_header) controls how much [referrer information](https://developer.mozilla.org/en-US/docs/Web/Security/Referer_header:_privacy_and_security_concerns) (sent with the [Referer](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer) header) should be included with requests. Aside from the HTTP header, you can [set this policy in HTML](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#integration_with_html). - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)",
|
|
58
|
+
},
|
|
59
|
+
"Strict-Transport-Security": {
|
|
60
|
+
description:
|
|
61
|
+
"The HTTP Strict-Transport-Security response header (often abbreviated as [HSTS](https://developer.mozilla.org/en-US/docs/Glossary/HSTS)) informs browsers that the site should only be accessed using HTTPS, and that any future attempts to access it using HTTP should automatically be converted to HTTPS. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)",
|
|
62
|
+
},
|
|
63
|
+
"X-Content-Type-Options": {
|
|
64
|
+
description:
|
|
65
|
+
"The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) advertised in the [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) headers should be followed and not be changed. The header allows you to avoid [MIME type sniffing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing) by saying that the MIME types are deliberately configured. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)",
|
|
66
|
+
},
|
|
67
|
+
"X-Frame-Options": {
|
|
68
|
+
description:
|
|
69
|
+
"The X-Frame-Options [HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP) response header can be used to indicate whether or not a browser should be allowed to render a page in a [<frame>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/frame), [<iframe>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe), [<embed>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed) or [<object>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object). Sites can use this to avoid [click-jacking](https://developer.mozilla.org/en-US/docs/Web/Security/Types_of_attacks#click-jacking) attacks, by ensuring that their content is not embedded into other sites. - [MDN Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)",
|
|
70
|
+
},
|
|
71
|
+
"X-Permitted-Cross-Domain-Policies": {
|
|
72
|
+
description:
|
|
73
|
+
"A cross-domain policy file is an XML document that grants a web client, such as Adobe Flash Player or Adobe Acrobat (though not necessarily limited to these), permission to handle data across domains. When clients request content hosted on a particular source domain and that content makes requests directed towards a domain other than its own, the remote domain needs to host a cross-domain policy file that grants access to the source domain, allowing the client to continue the transaction. Normally a meta-policy is declared in the master policy file, but for those who can't write to the root directory, they can also declare a meta-policy using the X-Permitted-Cross-Domain-Policies HTTP response header. - [OWASP Link](https://owasp.org/www-project-secure-headers/#x-permitted-cross-domain-policies)",
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
this.headerMap = {
|
|
78
|
+
cacheControl: "Cache-Control",
|
|
79
|
+
clearSiteData: "Clear-Site-Data",
|
|
80
|
+
contentSecurityPolicy: "Content-Security-Policy",
|
|
81
|
+
crossOriginEmbedderPolicy: "Cross-Origin-Embedder-Policy",
|
|
82
|
+
crossOriginOpenerPolicy: "Cross-Origin-Opener-Policy",
|
|
83
|
+
crossOriginResourcePolicy: "Cross-Origin-Resource-Policy",
|
|
84
|
+
permissionsPolicy: "Permissions-Policy",
|
|
85
|
+
pragma: "Pragma",
|
|
86
|
+
referrerPolicy: "Referrer-Policy",
|
|
87
|
+
strictTransportSecurity: "Strict-Transport-Security",
|
|
88
|
+
xContentTypeOptions: "X-Content-Type-Options",
|
|
89
|
+
xFrameOptions: "X-Frame-Options",
|
|
90
|
+
xPermittedCrossDomainPolicies: "X-Permitted-Cross-Domain-Policies",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async getLatest() {
|
|
95
|
+
const headerJSON = await new Promise((resolve, reject) => {
|
|
96
|
+
const req = https
|
|
97
|
+
.get(
|
|
98
|
+
"https://owasp.org/www-project-secure-headers/ci/headers_add.json",
|
|
99
|
+
(res) => {
|
|
100
|
+
let data = [];
|
|
101
|
+
|
|
102
|
+
if (res.statusCode !== 200) {
|
|
103
|
+
resolve(defaultOWASP);
|
|
61
104
|
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
this.headerMap = {
|
|
65
|
-
cacheControl: 'Cache-Control',
|
|
66
|
-
clearSiteData: 'Clear-Site-Data',
|
|
67
|
-
contentSecurityPolicy: 'Content-Security-Policy',
|
|
68
|
-
crossOriginEmbedderPolicy: 'Cross-Origin-Embedder-Policy',
|
|
69
|
-
crossOriginOpenerPolicy: 'Cross-Origin-Opener-Policy',
|
|
70
|
-
crossOriginResourcePolicy: 'Cross-Origin-Resource-Policy',
|
|
71
|
-
permissionsPolicy: 'Permissions-Policy',
|
|
72
|
-
pragma: 'Pragma',
|
|
73
|
-
referrerPolicy: 'Referrer-Policy',
|
|
74
|
-
strictTransportSecurity: 'Strict-Transport-Security',
|
|
75
|
-
xContentTypeOptions: 'X-Content-Type-Options',
|
|
76
|
-
xFrameOptions: 'X-Frame-Options',
|
|
77
|
-
xPermittedCrossDomainPolicies: 'X-Permitted-Cross-Domain-Policies'
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async getLatest() {
|
|
82
|
-
const headerJSON = await new Promise((resolve, reject) => {
|
|
83
|
-
const req = https.get('https://owasp.org/www-project-secure-headers/ci/headers_add.json', (res) => {
|
|
84
|
-
let data = []
|
|
85
|
-
|
|
86
|
-
if (res.statusCode !== 200) {
|
|
87
|
-
resolve(defaultOWASP)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
res.on('error', (err) => {
|
|
91
|
-
resolve(defaultOWASP)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
res.on('data', (chunk) => {
|
|
95
|
-
data.push(chunk)
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
res.on('end', () => {
|
|
99
|
-
resolve(JSON.parse(Buffer.concat(data).toString()))
|
|
100
|
-
})
|
|
101
|
-
})
|
|
102
|
-
.on('error', (err) => {
|
|
103
|
-
resolve(defaultOWASP)
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
req.end()
|
|
107
|
-
})
|
|
108
105
|
|
|
109
|
-
|
|
106
|
+
res.on("error", (err) => {
|
|
107
|
+
resolve(defaultOWASP);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
res.on("data", (chunk) => {
|
|
111
|
+
data.push(chunk);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
res.on("end", () => {
|
|
115
|
+
resolve(JSON.parse(Buffer.concat(data).toString()));
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
.on("error", (err) => {
|
|
120
|
+
resolve(defaultOWASP);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
req.end();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
this.populateDefaults(headerJSON);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @funtion populateDefaults
|
|
131
|
+
* @param {OWASPHeaders} headerJSON
|
|
132
|
+
*/
|
|
133
|
+
populateDefaults(headerJSON) {
|
|
134
|
+
for (const header of headerJSON.headers) {
|
|
135
|
+
const headerObj = {
|
|
136
|
+
schema: {
|
|
137
|
+
type: "string",
|
|
138
|
+
default: header.value,
|
|
139
|
+
example: header.value,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
if (this.DEFAULT_OWASP_HEADERS?.[header.name]) {
|
|
144
|
+
Object.assign(this.DEFAULT_OWASP_HEADERS[header.name], headerObj);
|
|
145
|
+
} else {
|
|
146
|
+
Object.assign(this.DEFAULT_OWASP_HEADERS, {
|
|
147
|
+
[header.name]: headerObj,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
110
150
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
getHeaders(headerList) {
|
|
154
|
+
const obj = {};
|
|
155
|
+
for (const headerName of Object.keys(headerList)) {
|
|
156
|
+
const defaultHeader =
|
|
157
|
+
this.DEFAULT_OWASP_HEADERS[this.headerMap[headerName]];
|
|
158
|
+
Object.assign(obj, { [this.headerMap[headerName]]: defaultHeader });
|
|
159
|
+
|
|
160
|
+
if (typeof headerList[headerName] !== "boolean") {
|
|
161
|
+
obj[this.headerMap[headerName]].schema.default =
|
|
162
|
+
headerList[headerName].value;
|
|
163
|
+
}
|
|
124
164
|
}
|
|
125
165
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
for (const headerName of Object.keys(headerList)) {
|
|
129
|
-
const defaultHeader = this.DEFAULT_OWASP_HEADERS[this.headerMap[headerName]]
|
|
130
|
-
Object.assign(obj, {[this.headerMap[headerName]]: defaultHeader})
|
|
131
|
-
|
|
132
|
-
if (typeof headerList[headerName] !== 'boolean') {
|
|
133
|
-
obj[this.headerMap[headerName]].schema.default = headerList[headerName].value
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return obj
|
|
138
|
-
}
|
|
166
|
+
return obj;
|
|
167
|
+
}
|
|
139
168
|
}
|
|
140
169
|
|
|
141
|
-
module.exports = new OWASP()
|
|
170
|
+
module.exports = new OWASP();
|