Skip to content

Commit 9c5f891

Browse files
fix: introduce security related linter and fix warnings (#106)
1 parent 5ef22a3 commit 9c5f891

17 files changed

+272
-327
lines changed

.eslintrc

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ env:
66
plugins:
77
- sonarjs
88
- mocha
9+
- security
910

1011
extends:
1112
- plugin:sonarjs/recommended
1213
- plugin:mocha/recommended
14+
- plugin:security/recommended
1315

1416
parserOptions:
1517
ecmaVersion: 2018
@@ -102,4 +104,6 @@ overrides:
102104
- files: "test/**"
103105
rules:
104106
prefer-arrow-callback: 0
105-
sonarjs/no-duplicate-string: 0
107+
sonarjs/no-duplicate-string: 0
108+
security/detect-object-injection: 0
109+
security/detect-non-literal-fs-filename: 0

lib/customValidators.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ function validateOperationId(parsedJSON, asyncapiYAMLorJSON, initialFormat, oper
116116

117117
chnlsMap.forEach((chnlObj,chnlName) => {
118118
operations.forEach(opName => {
119-
const op = chnlObj[opName];
119+
const op = chnlObj[String(opName)];
120120
if (op) addDuplicateToMap(op, chnlName, opName);
121121
});
122122
});

lib/models/asyncapi.js

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
const { createMapOfType, getMapKeyOfType, addExtensions } = require('../utils');
1+
const { createMapOfType, getMapValueOfType, addExtensions } = require('../utils');
22
const Base = require('./base');
33
const Info = require('./info');
44
const Server = require('./server');
55
const Channel = require('./channel');
66
const Components = require('./components');
77
const Tag = require('./tag');
8+
89
const xParserMessageName = 'x-parser-message-name';
910
const xParserSchemaId = 'x-parser-schema-id';
1011

@@ -66,7 +67,7 @@ class AsyncAPIDocument extends Base {
6667
* @returns {Server}
6768
*/
6869
server(name) {
69-
return getMapKeyOfType(this._json.servers, name, Server);
70+
return getMapValueOfType(this._json.servers, name, Server);
7071
}
7172

7273
/**
@@ -96,7 +97,7 @@ class AsyncAPIDocument extends Base {
9697
* @returns {Channel}
9798
*/
9899
channel(name) {
99-
return getMapKeyOfType(this._json.channels, name, Channel, this);
100+
return getMapValueOfType(this._json.channels, name, Channel, this);
100101
}
101102

102103
/**
@@ -199,7 +200,7 @@ function assignNameToComponentMessages(doc) {
199200
if (doc.hasComponents()) {
200201
for (const [key, m] of Object.entries(doc.components().messages())) {
201202
if (m.name() === undefined) {
202-
m.json()[xParserMessageName] = key;
203+
m.json()[String(xParserMessageName)] = key;
203204
}
204205
}
205206
}
@@ -214,7 +215,7 @@ function assignUidToParameterSchemas(doc) {
214215
doc.channelNames().forEach(channelName => {
215216
const channel = doc.channel(channelName);
216217
for (const [parameterKey, parameterSchema] of Object.entries(channel.parameters())) {
217-
parameterSchema.json()[xParserSchemaId] = parameterKey;
218+
parameterSchema.json()[String(xParserSchemaId)] = parameterKey;
218219
}
219220
});
220221
}
@@ -227,7 +228,7 @@ function assignUidToParameterSchemas(doc) {
227228
function assignUidToComponentSchemas(doc) {
228229
if (doc.hasComponents()) {
229230
for (const [key, s] of Object.entries(doc.components().schemas())) {
230-
s.json()[xParserSchemaId] = key;
231+
s.json()[String(xParserSchemaId)] = key;
231232
}
232233
}
233234
}
@@ -257,7 +258,7 @@ function assignNameToAnonymousMessages(doc) {
257258
function addNameToKey(messages, number) {
258259
messages.forEach(m => {
259260
if (m.name() === undefined) {
260-
m.json()[xParserMessageName] = `<anonymous-message-${number}>`;
261+
m.json()[String(xParserMessageName)] = `<anonymous-message-${number}>`;
261262
}
262263
});
263264
}
@@ -362,7 +363,7 @@ function assignIdToAnonymousSchemas(doc) {
362363
let anonymousSchemaCounter = 0;
363364
const callback = (schema) => {
364365
if (!schema.uid()) {
365-
schema.json()[xParserSchemaId] = `<anonymous-schema-${++anonymousSchemaCounter}>`;
366+
schema.json()[String(xParserSchemaId)] = `<anonymous-schema-${++anonymousSchemaCounter}>`;
366367
}
367368
};
368369
schemaDocument(doc, callback);

lib/models/base.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Base {
1717
json(key) {
1818
if (key === undefined) return this._json;
1919
if (!this._json) return;
20-
return this._json[key];
20+
return this._json[String(key)];
2121
}
2222
}
2323

lib/models/channel.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { createMapOfType, getMapKeyOfType, addExtensions } = require('../utils');
1+
const { createMapOfType, getMapValueOfType, getMapValueByKey, addExtensions } = require('../utils');
22
const Base = require('./base');
33
const ChannelParameter = require('./channel-parameter');
44
const PublishOperation = require('./publish-operation');
@@ -30,7 +30,7 @@ class Channel extends Base {
3030
* @returns {ChannelParameter}
3131
*/
3232
parameter(name) {
33-
return getMapKeyOfType(this._json.parameters, name, ChannelParameter);
33+
return getMapValueOfType(this._json.parameters, name, ChannelParameter);
3434
}
3535

3636
/**
@@ -82,7 +82,7 @@ class Channel extends Base {
8282
* @returns {Object}
8383
*/
8484
binding(name) {
85-
return this._json.bindings ? this._json.bindings[name] : null;
85+
return getMapValueByKey(this._json.bindings, name);
8686
}
8787
}
8888

lib/models/components.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { getMapKeyOfType, createMapOfType, addExtensions } = require('../utils');
1+
const { createMapOfType, getMapValueOfType, addExtensions } = require('../utils');
22
const Base = require('./base');
33
const Message = require('./message');
44
const Schema = require('./schema');
@@ -26,7 +26,7 @@ class Components extends Base {
2626
* @returns {Message}
2727
*/
2828
message(name) {
29-
return getMapKeyOfType(this._json.messages, name, Message);
29+
return getMapValueOfType(this._json.messages, name, Message);
3030
}
3131

3232
/**
@@ -40,7 +40,7 @@ class Components extends Base {
4040
* @returns {Schema}
4141
*/
4242
schema(name) {
43-
return getMapKeyOfType(this._json.schemas, name, Schema);
43+
return getMapValueOfType(this._json.schemas, name, Schema);
4444
}
4545

4646
/**
@@ -54,7 +54,7 @@ class Components extends Base {
5454
* @returns {SecurityScheme}
5555
*/
5656
securityScheme(name) {
57-
return getMapKeyOfType(this._json.securitySchemes, name, SecurityScheme);
57+
return getMapValueOfType(this._json.securitySchemes, name, SecurityScheme);
5858
}
5959

6060
/**
@@ -68,7 +68,7 @@ class Components extends Base {
6868
* @returns {ChannelParameter}
6969
*/
7070
parameter(name) {
71-
return getMapKeyOfType(this._json.parameters, name, ChannelParameter);
71+
return getMapValueOfType(this._json.parameters, name, ChannelParameter);
7272
}
7373

7474
/**
@@ -82,7 +82,7 @@ class Components extends Base {
8282
* @returns {CorrelationId}
8383
*/
8484
correlationId(name) {
85-
return getMapKeyOfType(this._json.correlationIds, name, CorrelationId);
85+
return getMapValueOfType(this._json.correlationIds, name, CorrelationId);
8686
}
8787

8888
/**
@@ -96,7 +96,7 @@ class Components extends Base {
9696
* @returns {OperationTrait}
9797
*/
9898
operationTrait(name) {
99-
return getMapKeyOfType(this._json.operationTraits, name, OperationTrait);
99+
return getMapValueOfType(this._json.operationTraits, name, OperationTrait);
100100
}
101101

102102
/**
@@ -110,7 +110,7 @@ class Components extends Base {
110110
* @returns {MessageTrait}
111111
*/
112112
messageTrait(name) {
113-
return getMapKeyOfType(this._json.messageTraits, name, MessageTrait);
113+
return getMapValueOfType(this._json.messageTraits, name, MessageTrait);
114114
}
115115
}
116116

lib/models/message-traitable.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { getMapKeyOfType, addExtensions } = require('../utils');
1+
const { getMapValueOfType, getMapValueByKey, addExtensions } = require('../utils');
22
const Base = require('./base');
33
const Tag = require('./tag');
44
const ExternalDocs = require('./external-docs');
@@ -26,7 +26,7 @@ class MessageTraitable extends Base {
2626
*/
2727
header(name) {
2828
if (!this._json.headers) return null;
29-
return getMapKeyOfType(this._json.headers.properties, name, Schema);
29+
return getMapValueOfType(this._json.headers.properties, name, Schema);
3030
}
3131

3232
/**
@@ -114,7 +114,7 @@ class MessageTraitable extends Base {
114114
* @returns {Object}
115115
*/
116116
binding(name) {
117-
return this._json.bindings ? this._json.bindings[name] : null;
117+
return getMapValueByKey(this._json.bindings, name);
118118
}
119119

120120
/**

lib/models/operation-traitable.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { addExtensions } = require('../utils');
1+
const { getMapValueByKey, addExtensions } = require('../utils');
22
const Base = require('./base');
33
const Tag = require('./tag');
44
const ExternalDocs = require('./external-docs');
@@ -66,7 +66,7 @@ class OperationTraitable extends Base {
6666
* @returns {Object}
6767
*/
6868
binding(name) {
69-
return this._json.bindings ? this._json.bindings[name] : null;
69+
return getMapValueByKey(this._json.bindings, name);
7070
}
7171
}
7272

lib/models/operation.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ class Operation extends OperationTraitable {
3030
* @returns {Message}
3131
*/
3232
message(index) {
33-
if (!this._json.message) return null;
33+
if (typeof index !== 'number' || !this._json.message) return null;
3434
if (!this._json.message.oneOf) return new Message(this._json.message);
3535
if (index > this._json.message.oneOf.length - 1) return null;
36-
return new Message(this._json.message.oneOf[index]);
36+
return new Message(this._json.message.oneOf[+index]);
3737
}
3838
}
3939

lib/models/schema.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,8 @@ class Schema extends Base {
232232
dependencies() {
233233
if (!this._json.dependencies) return null;
234234
const result = {};
235-
Object.keys(this._json.dependencies).forEach(k => {
236-
if (!Array.isArray(this._json.dependencies[k])) {
237-
result[k] = new Schema(this._json.dependencies[k]);
238-
} else {
239-
result[k] = this._json.dependencies[k];
240-
}
235+
Object.entries(this._json.dependencies).forEach(([key, value]) => {
236+
result[String(key)] = !Array.isArray(value) ? new Schema(value) : value;
241237
});
242238
return result;
243239
}

lib/models/server.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { createMapOfType, getMapKeyOfType, addExtensions } = require('../utils');
1+
const { createMapOfType, getMapValueOfType, getMapValueByKey, addExtensions } = require('../utils');
22
const Base = require('./base');
33
const ServerVariable = require('./server-variable');
44
const ServerSecurityRequirement = require('./server-security-requirement');
@@ -50,7 +50,7 @@ class Server extends Base {
5050
* @returns {ServerVariable}
5151
*/
5252
variable(name) {
53-
return getMapKeyOfType(this._json.variables, name, ServerVariable);
53+
return getMapValueOfType(this._json.variables, name, ServerVariable);
5454
}
5555

5656
/**
@@ -80,7 +80,7 @@ class Server extends Base {
8080
* @returns {Object}
8181
*/
8282
binding(name) {
83-
return this._json.bindings ? this._json.bindings[name] : null;
83+
return getMapValueByKey(this._json.bindings, name);
8484
}
8585
}
8686

lib/parser.js

+11-11
Original file line numberDiff line numberDiff line change
@@ -155,30 +155,30 @@ async function customDocumentOperations(js, asyncapiYAMLorJSON, initialFormat, o
155155
validateChannelParams(js, asyncapiYAMLorJSON, initialFormat);
156156
validateOperationId(js, asyncapiYAMLorJSON, initialFormat, OPERATIONS);
157157

158-
for (const channelName in js.channels) {
159-
const channel = js.channels[channelName];
160-
const convert = OPERATIONS.map(async (opName) => {
161-
const op = channel[opName];
158+
const promisesArray = [];
159+
Object.entries(js.channels).forEach(([channelName, channel]) => {
160+
promisesArray.push(...OPERATIONS.map(async (opName) => {
161+
const op = channel[String(opName)];
162162
if (op) {
163163
const messages = op.message ? (op.message.oneOf || [op.message]) : [];
164-
const pathToPayload = `/channels/${ channelName }/${ opName }/message/payload`;
165164
if (options.applyTraits) {
166165
applyTraits(op);
167166
messages.forEach(m => applyTraits(m));
168167
}
168+
const pathToPayload = `/channels/${channelName}/${opName}/message/payload`;
169169
for (const m of messages) {
170170
await validateAndConvertMessage(m, asyncapiYAMLorJSON, initialFormat, js, pathToPayload);
171171
}
172172
}
173-
});
174-
await Promise.all(convert);
175-
}
173+
}));
174+
});
175+
await Promise.all(promisesArray);
176176
}
177177

178178
async function validateAndConvertMessage(msg, originalAsyncAPIDocument, fileFormat, parsedAsyncAPIDocument, pathToPayload) {
179179
const schemaFormat = msg.schemaFormat || DEFAULT_SCHEMA_FORMAT;
180180

181-
await PARSERS[schemaFormat]({
181+
await PARSERS[String(schemaFormat)]({
182182
schemaFormat,
183183
message: msg,
184184
defaultSchemaFormat: DEFAULT_SCHEMA_FORMAT,
@@ -208,15 +208,15 @@ function registerSchemaParser(parserModule) {
208208
});
209209

210210
parserModule.getMimeTypes().forEach((schemaFormat) => {
211-
PARSERS[schemaFormat] = parserModule.parse;
211+
PARSERS[String(schemaFormat)] = parserModule.parse;
212212
});
213213
}
214214

215215
function applyTraits(js) {
216216
if (Array.isArray(js.traits)) {
217217
for (const trait of js.traits) {
218218
for (const key in trait) {
219-
js[key] = mergePatch(js[key], trait[key]);
219+
js[String(key)] = mergePatch(js[String(key)], trait[String(key)]);
220220
}
221221
}
222222

0 commit comments

Comments
 (0)