@asyncapi/parser
Advanced tools
Comparing version 0.31.0 to 0.32.0
@@ -138,2 +138,4 @@ const ParserError = require('./errors/parser-error'); | ||
/* eslint-disable sonarjs/cognitive-complexity */ | ||
/* spliting it because it is 18 and not 15 lines would only make it more complex */ | ||
/** | ||
@@ -156,5 +158,7 @@ * Validates if server security is declared properly and the name has a corresponding security schema definition in components with the same name | ||
const missingSecSchema = new Map(); | ||
const invalidSecurityValues = new Map(); | ||
const missingSecSchema = new Map(), | ||
invalidSecurityValues = new Map(), | ||
missingScopesList = new Map(); | ||
//we need to validate every server specified in the document | ||
srvsMap.forEach((server, serverName) => { | ||
@@ -165,4 +169,6 @@ const serverSecInfo = server.security; | ||
//server security info is an array of many possible values | ||
serverSecInfo.forEach(secObj => { | ||
Object.keys(secObj).forEach(secName => { | ||
//security schema is located in components object, we need to find if there is security schema with the same name as the server security info object | ||
const schema = findSecuritySchema(secName, parsedJSON.components); | ||
@@ -173,4 +179,6 @@ const srvrSecurityPath = `${serverName}/security/${secName}`; | ||
//findSecuritySchema returns type always on index 1. Type is needed further to validate if server security info can be or not an empty array | ||
const schemaType = schema[1]; | ||
if (!isSrvrSecProperArray(schemaType, specialSecTypes, secObj, secName)) invalidSecurityValues.set(srvrSecurityPath, schemaType); | ||
if (!hasSrvrSecScopes(schemaType, specialSecTypes, secObj, secName)) missingScopesList.set(srvrSecurityPath, schemaType); | ||
}); | ||
@@ -198,2 +206,11 @@ }); | ||
if (missingScopesList.size) { | ||
throw new ParserError({ | ||
type: validationError, | ||
title: 'Server security value must not be an empty array if corresponding security schema type is oauth2 or openIdConnect. Add list of required scopes.', | ||
parsedJSON, | ||
validationErrors: groupValidationErrors(root, 'security info must not have an empty array because its corresponding security schema type is', missingScopesList, asyncapiYAMLorJSON, initialFormat) | ||
}); | ||
} | ||
return true; | ||
@@ -243,2 +260,21 @@ } | ||
/** | ||
* Validates if given server security is not an empty array when security type requires it | ||
* @private | ||
* @param {String} schemaType security type, like httpApiKey or userPassword | ||
* @param {String[]} specialSecTypes list of special types that do not have to be an empty array | ||
* @param {Object} secObj server security object | ||
* @param {String} secName name os server security object | ||
* @returns {String[]} there are 2 elements in array, index 0 is the name of the security schema object and index 1 is it's type | ||
*/ | ||
function hasSrvrSecScopes(schemaType, specialSecTypes, secObj, secName) { | ||
if (specialSecTypes.includes(schemaType)) { | ||
const securityObjValue = secObj[String(secName)]; | ||
return !!securityObjValue.length; | ||
} | ||
return true; | ||
} | ||
module.exports = { | ||
@@ -245,0 +281,0 @@ validateChannelParams, |
@@ -6,2 +6,4 @@ const YAML = require('js-yaml'); | ||
const ParserError = require('./errors/parser-error'); | ||
const { EOL } = require('os'); | ||
const eolLength = EOL.length; | ||
@@ -300,1 +302,13 @@ const jsonPointerToArray = jsonPointer => (jsonPointer || '/').split('/').splice(1); | ||
}; | ||
/** | ||
* Tests helper for testing start and end offset position of error in file to make sure tests work on Windows too | ||
* | ||
* @function offset | ||
* @private | ||
* @param {Number} oset end or start offset number | ||
* @param {Number} line end or start line number | ||
* @returns {Number} calculated offset number | ||
*/ | ||
utils.offset = (oset, line) => (oset + ((eolLength - 1) * (line - 1))); |
{ | ||
"name": "@asyncapi/parser", | ||
"version": "0.31.0", | ||
"version": "0.32.0", | ||
"description": "JavaScript AsyncAPI parser.", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -5,2 +5,4 @@ const parser = require('../lib'); | ||
const path = require('path'); | ||
const { offset } = require('../lib/utils'); | ||
const expect = chai.expect; | ||
@@ -24,6 +26,6 @@ | ||
startColumn: 38, | ||
startOffset: 252, | ||
startOffset: offset(252, 13), | ||
endLine: 15, | ||
endColumn: 15, | ||
endOffset: 297 | ||
endOffset: offset(297, 15) | ||
} | ||
@@ -37,6 +39,6 @@ }, | ||
startColumn: 38, | ||
startOffset: 252, | ||
startOffset: offset(252, 13), | ||
endLine: 15, | ||
endColumn: 15, | ||
endOffset: 297 | ||
endOffset: offset(297, 15) | ||
} | ||
@@ -50,6 +52,6 @@ }, | ||
startColumn: 38, | ||
startOffset: 252, | ||
startOffset: offset(252, 13), | ||
endLine: 15, | ||
endColumn: 15, | ||
endOffset: 297 | ||
endOffset: offset(297, 15) | ||
} | ||
@@ -63,6 +65,6 @@ }, | ||
startColumn: 38, | ||
startOffset: 252, | ||
startOffset: offset(252, 13), | ||
endLine: 15, | ||
endColumn: 15, | ||
endOffset: 297 | ||
endOffset: offset(297, 15) | ||
} | ||
@@ -76,6 +78,6 @@ }, | ||
startColumn: 38, | ||
startOffset: 252, | ||
startOffset: offset(252, 13), | ||
endLine: 15, | ||
endColumn: 15, | ||
endOffset: 297 | ||
endOffset: offset(297, 15) | ||
} | ||
@@ -86,3 +88,2 @@ } | ||
}); | ||
it('should not throw error if payload not provided', async function() { | ||
@@ -89,0 +90,0 @@ const inputString = `{ |
const { validateChannelParams, validateServerVariables, validateOperationId, validateServerSecurity } = require('../lib/customValidators.js'); | ||
const chai = require('chai'); | ||
const { offset } = require('../lib/utils'); | ||
@@ -62,6 +63,6 @@ const expect = chai.expect; | ||
startColumn: 19, | ||
startOffset: 39, | ||
startOffset: offset(39, 3), | ||
endLine: 10, | ||
endColumn: 11, | ||
endOffset: 196 | ||
endOffset: offset(196, 10), | ||
} | ||
@@ -96,6 +97,6 @@ } | ||
startColumn: 19, | ||
startOffset: 39, | ||
startOffset: offset(39, 3), | ||
endLine: 5, | ||
endColumn: 11, | ||
endOffset: 89 | ||
endOffset: offset(89, 5), | ||
} | ||
@@ -135,6 +136,6 @@ } | ||
startColumn: 19, | ||
startOffset: 39, | ||
startOffset: offset(39, 3), | ||
endLine: 10, | ||
endColumn: 11, | ||
endOffset: 200 | ||
endOffset: offset(200, 10), | ||
} | ||
@@ -215,6 +216,6 @@ } | ||
startColumn: 34, | ||
startOffset: 54, | ||
startOffset: offset(54, 3), | ||
endLine: 11, | ||
endColumn: 11, | ||
endOffset: 214 | ||
endOffset: offset(214, 11) | ||
} | ||
@@ -255,6 +256,6 @@ } | ||
startColumn: 25, | ||
startOffset: 45, | ||
startOffset: offset(45, 3), | ||
endLine: 11, | ||
endColumn: 11, | ||
endOffset: 206 | ||
endOffset: offset(206, 11) | ||
} | ||
@@ -288,6 +289,6 @@ } | ||
startColumn: 34, | ||
startOffset: 54, | ||
startOffset: offset(54, 3), | ||
endLine: 4, | ||
endColumn: 11, | ||
endOffset: 65 | ||
endOffset: offset(65, 4) | ||
} | ||
@@ -390,6 +391,6 @@ } | ||
startColumn: 29, | ||
startOffset: 273, | ||
startOffset: offset(273, 14), | ||
endLine: 14, | ||
endColumn: 35, | ||
endOffset: 279 | ||
endOffset: offset(279, 14) | ||
} | ||
@@ -403,6 +404,6 @@ }, | ||
startColumn: 29, | ||
startOffset: 375, | ||
startOffset: offset(375, 19), | ||
endLine: 19, | ||
endColumn: 35, | ||
endOffset: 381 | ||
endOffset: offset(381, 19) | ||
} | ||
@@ -450,2 +451,42 @@ } | ||
it('should successfully validate server security for oauth2 that requires scopes', async function() { | ||
const inputString = `{ | ||
"asyncapi": "2.0.0", | ||
"info": { | ||
"version": "1.0.0" | ||
}, | ||
"servers": { | ||
"dummy": { | ||
"url": "http://localhost", | ||
"protocol": "kafka", | ||
"security": [ | ||
{ | ||
"oauthsec": ["read:pets"] | ||
} | ||
] | ||
} | ||
}, | ||
"components": { | ||
"securitySchemes": { | ||
"oauthsec": { | ||
"type": "oauth2", | ||
"flows": { | ||
"implicit": { | ||
"authorizationUrl": "https://example.com/api/oauth/auth", | ||
"refreshUrl": "https://example.com/api/oauth/refresh", | ||
"scopes": { | ||
"write:pets": "modify pets in your account", | ||
"read:pets": "read your pets" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}`; | ||
const parsedInput = JSON.parse(inputString); | ||
expect(validateServerSecurity(parsedInput, inputString, input, specialSecTypes)).to.equal(true); | ||
}); | ||
it('should successfully validate if server security not provided', async function() { | ||
@@ -545,6 +586,6 @@ const inputString = `{ | ||
startColumn: 27, | ||
startOffset: 250, | ||
startOffset: offset(250, 12), | ||
endLine: 12, | ||
endColumn: 29, | ||
endOffset: 252 | ||
endOffset: offset(252, 12) | ||
} | ||
@@ -556,2 +597,62 @@ } | ||
it('should throw error that server security is missing scopes that are required for special security types like oauth2 and openIdConnect', async function() { | ||
const inputString = `{ | ||
"asyncapi": "2.0.0", | ||
"info": { | ||
"version": "1.0.0" | ||
}, | ||
"servers": { | ||
"dummy": { | ||
"url": "http://localhost", | ||
"protocol": "kafka", | ||
"security": [ | ||
{ | ||
"oauthsec": [] | ||
} | ||
] | ||
} | ||
}, | ||
"components": { | ||
"securitySchemes": { | ||
"oauthsec": { | ||
"type": "oauth2", | ||
"flows": { | ||
"implicit": { | ||
"authorizationUrl": "https://example.com/api/oauth/auth", | ||
"refreshUrl": "https://example.com/api/oauth/refresh", | ||
"scopes": { | ||
"write:pets": "modify pets in your account", | ||
"read:pets": "read your pets" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}`; | ||
const parsedInput = JSON.parse(inputString); | ||
try { | ||
validateServerSecurity(parsedInput, inputString, input, specialSecTypes); | ||
} catch (e) { | ||
expect(e.type).to.equal('https://github.com/asyncapi/parser-js/validation-errors'); | ||
expect(e.title).to.equal('Server security value must not be an empty array if corresponding security schema type is oauth2 or openIdConnect. Add list of required scopes.'); | ||
expect(e.parsedJSON).to.deep.equal(parsedInput); | ||
expect(e.validationErrors).to.deep.equal([ | ||
{ | ||
title: 'dummy/security/oauthsec security info must not have an empty array because its corresponding security schema type is: oauth2', | ||
location: { | ||
jsonPointer: '/servers/dummy/security/oauthsec', | ||
startLine: 12, | ||
startColumn: 28, | ||
startOffset: offset(251, 12), | ||
endLine: 12, | ||
endColumn: 30, | ||
endOffset: offset(253, 12) | ||
} | ||
} | ||
]); | ||
} | ||
}); | ||
it('should throw error that server has no security schema provided when components schema object is not in the document', async function() { | ||
@@ -592,6 +693,6 @@ const inputString = `{ | ||
startColumn: 27, | ||
startOffset: 250, | ||
startOffset: offset(250, 12), | ||
endLine: 12, | ||
endColumn: 29, | ||
endOffset: 252 | ||
endOffset: offset(252, 12) | ||
} | ||
@@ -649,6 +750,6 @@ } | ||
startColumn: 25, | ||
startOffset: 248, | ||
startOffset: offset(248, 12), | ||
endLine: 12, | ||
endColumn: 45, | ||
endOffset: 268 | ||
endOffset: offset(268, 12) | ||
} | ||
@@ -662,6 +763,6 @@ }, | ||
startColumn: 26, | ||
startOffset: 322, | ||
startOffset: offset(322, 15), | ||
endLine: 15, | ||
endColumn: 36, | ||
endOffset: 332 | ||
endOffset: offset(332, 15) | ||
} | ||
@@ -668,0 +769,0 @@ } |
@@ -1,2 +0,1 @@ | ||
const { EOL } = require('os'); | ||
const chai = require('chai'); | ||
@@ -8,2 +7,3 @@ const chaiAsPromised = require('chai-as-promised'); | ||
const ParserError = require('../lib/errors/parser-error'); | ||
const { offset } = require('../lib/utils'); | ||
@@ -25,4 +25,2 @@ chai.use(chaiAsPromised); | ||
const eolLength = EOL.length; | ||
/* eslint-disable sonarjs/cognitive-complexity */ | ||
@@ -58,4 +56,2 @@ /** | ||
const offset = (oset, line) => (oset + ((eolLength - 1) * (line - 1))); | ||
describe('parse()', function() { | ||
@@ -77,7 +73,7 @@ it('should parse YAML', async function() { | ||
endLine: 1, | ||
endOffset: 29, | ||
endOffset: offset(29, 1), | ||
jsonPointer: '/info', | ||
startColumn: 29, | ||
startLine: 1, | ||
startOffset: 27 | ||
startOffset: offset(27, 1) | ||
} | ||
@@ -87,9 +83,11 @@ }, | ||
title: '/info should have required property \'version\'', | ||
location: { endColumn: 31, | ||
location: { | ||
endColumn: 31, | ||
endLine: 1, | ||
endOffset: 29, | ||
endOffset: offset(29, 1), | ||
jsonPointer: '/info', | ||
startColumn: 29, | ||
startLine: 1, | ||
startOffset: 27 } | ||
startOffset: offset(27, 1) | ||
} | ||
}, | ||
@@ -221,3 +219,3 @@ { | ||
startColumn: 1, | ||
startOffset: 0, | ||
startOffset: offset(0, 1), | ||
endLine: 1, | ||
@@ -240,3 +238,3 @@ endColumn: 16, | ||
detail: 'duplicated mapping key at line 2, column -4:\n bad:\n ^', | ||
location: { startOffset: 5, startLine: 2, startColumn: -4 } | ||
location: { startOffset: offset(5, 2), startLine: 2, startColumn: -4 } | ||
}; | ||
@@ -259,6 +257,6 @@ | ||
startColumn: 11, | ||
startOffset: 736, | ||
startOffset: offset(736, 35), | ||
endLine: 35, | ||
endColumn: 34, | ||
endOffset: 759 | ||
endOffset: offset(759, 35) | ||
} | ||
@@ -281,6 +279,6 @@ ] | ||
startColumn: 11, | ||
startOffset: 736, | ||
startOffset: offset(736, 35), | ||
endLine: 35, | ||
endColumn: 34, | ||
endOffset: 759 | ||
endOffset: offset(759, 35) | ||
} | ||
@@ -419,3 +417,3 @@ ] | ||
detail: 'bad indentation of a mapping entry at line 19, column 11:\n $ref: "#/components/schemas/sentAt"\n ^', | ||
location: { startOffset: 460, startLine: 19, startColumn: 11 } | ||
location: { startOffset: offset(460, 19), startLine: 19, startColumn: 11 } | ||
}; | ||
@@ -433,3 +431,3 @@ | ||
detail: 'Unexpected token j in JSON at position 12 while parsing near \' {"invalid "json" }\'', | ||
location: { startOffset: 12, startLine: 1, startColumn: 12 } | ||
location: { startOffset: offset(12, 1), startLine: 1, startColumn: 12 } | ||
}; | ||
@@ -436,0 +434,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1125038
9722