From e5741c7085125ec7b30b0c15559a22899e0d5a9c Mon Sep 17 00:00:00 2001 From: Susan Lubar Date: Wed, 14 Dec 2022 11:19:05 -0500 Subject: [PATCH 1/4] #802 Update boolean query parameters to accept 0,1,true,false,yes,no in any casing --- api-docs/openapi.json | 4 ++-- package-lock.json | 18 +++++++++--------- package.json | 2 +- .../cve.controller/cve.controller.js | 7 +++++-- src/controller/cve.controller/index.js | 2 +- src/controller/org.controller/index.js | 2 +- .../org.controller/org.controller.js | 3 ++- src/swagger.js | 4 ++-- src/utils/utils.js | 10 ++++++++++ 9 files changed, 33 insertions(+), 19 deletions(-) diff --git a/api-docs/openapi.json b/api-docs/openapi.json index 134bdecf4..2ff699337 100644 --- a/api-docs/openapi.json +++ b/api-docs/openapi.json @@ -2383,7 +2383,7 @@ "active": { "in": "query", "name": "active", - "description": "The new active state for the user entry", + "description": "The new active state for the user entry. Accepted values are 1, true, or yes to indicate true, and 0, false, or no to indicate false", "required": false, "schema": { "type": "boolean" @@ -2515,7 +2515,7 @@ "countOnly": { "in": "query", "name": "count_only", - "description": "Get count of records that match query. Accepted values are 1, to indicate true, and 0, to indicate false", + "description": "Get count of records that match query. Accepted values are 1, true, or yes to indicate true, and 0, false, or no to indicate false", "required": false, "schema": { "type": "boolean" diff --git a/package-lock.json b/package-lock.json index 2abc22332..4bcdd916c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "express": "^4.15.4", "express-jsonschema": "^1.1.6", "express-rate-limit": "^6.5.2", - "express-validator": "^6.12.0", + "express-validator": "^6.14.2", "helmet": "^3.21.2", "html-entities": "^2.3.3", "jsonschema": "^1.4.0", @@ -3666,12 +3666,12 @@ } }, "node_modules/express-validator": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.12.0.tgz", - "integrity": "sha512-lcQAdVeAO+pBbHD33nIsDsd+QPakLX08tJ82iEsXj6ezyWCfYjE9RY/g9SVq5z4G0NaIkH8039Oe4r0G92DRyA==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.14.2.tgz", + "integrity": "sha512-8XfAUrQ6Y7dIIuy9KcUPCfG/uCbvREctrxf5EeeME+ulanJ4iiW71lWmm9r4YcKKYOCBMan0WpVg7FtHu4Z4Wg==", "dependencies": { "lodash": "^4.17.21", - "validator": "^13.5.2" + "validator": "^13.7.0" }, "engines": { "node": ">= 8.0.0" @@ -12935,12 +12935,12 @@ "requires": {} }, "express-validator": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.12.0.tgz", - "integrity": "sha512-lcQAdVeAO+pBbHD33nIsDsd+QPakLX08tJ82iEsXj6ezyWCfYjE9RY/g9SVq5z4G0NaIkH8039Oe4r0G92DRyA==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.14.2.tgz", + "integrity": "sha512-8XfAUrQ6Y7dIIuy9KcUPCfG/uCbvREctrxf5EeeME+ulanJ4iiW71lWmm9r4YcKKYOCBMan0WpVg7FtHu4Z4Wg==", "requires": { "lodash": "^4.17.21", - "validator": "^13.5.2" + "validator": "^13.7.0" } }, "extend": { diff --git a/package.json b/package.json index 1915a607d..0eb9a0085 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "express": "^4.15.4", "express-jsonschema": "^1.1.6", "express-rate-limit": "^6.5.2", - "express-validator": "^6.12.0", + "express-validator": "^6.14.2", "helmet": "^3.21.2", "html-entities": "^2.3.3", "jsonschema": "^1.4.0", diff --git a/src/controller/cve.controller/cve.controller.js b/src/controller/cve.controller/cve.controller.js index 908e0d544..3399d36d6 100644 --- a/src/controller/cve.controller/cve.controller.js +++ b/src/controller/cve.controller/cve.controller.js @@ -3,6 +3,7 @@ const logger = require('../../middleware/logger') const errors = require('./error') const getConstants = require('../../constants').getConstants const error = new errors.CveControllerError() +const booleanIsTrue = require('../../utils/utils').booleanIsTrue // Helper function to create providerMetadata object function createProviderMetadata (orgId, shortName, updateDate) { @@ -49,7 +50,8 @@ async function getFilteredCves (req, res, next) { // if count_only is the only parameter, return estimated count of full set of records if ((Object.keys(req.ctx.query).length === 1) && - (req.ctx.query.count_only === '1')) { + (req.ctx.query.count_only) && + (booleanIsTrue(req.ctx.query.count_only))) { const payload = {} payload.totalCount = await cveRepo.estimatedDocumentCount() logger.info({ uuid: req.ctx.uuid, message: 'The cve records estimated count was sent to the user.' }) @@ -122,7 +124,8 @@ async function getFilteredCves (req, res, next) { delete options.sort // check whether user requested count_only for filtered set of records - if (req.ctx.query.count_only === '1') { + if ((req.ctx.query.count_only) && + (booleanIsTrue(req.ctx.query.count_only))) { const payload = {} payload.totalCount = await cveRepo.countDocuments(query) logger.info({ uuid: req.ctx.uuid, message: 'The cve records count was sent to the user.' }) diff --git a/src/controller/cve.controller/index.js b/src/controller/cve.controller/index.js index a8042a996..c8bc5b6be 100644 --- a/src/controller/cve.controller/index.js +++ b/src/controller/cve.controller/index.js @@ -151,7 +151,7 @@ router.get('/cve', query(['time_modified.lt']).optional().isString().trim().escape().customSanitizer(val => { return toDate(val) }).not().isEmpty().withMessage(errorMsgs.TIMESTAMP_FORMAT), query(['time_modified.gt']).optional().isString().trim().escape().customSanitizer(val => { return toDate(val) }).not().isEmpty().withMessage(errorMsgs.TIMESTAMP_FORMAT), query(['state']).optional().isString().trim().escape().customSanitizer(val => { return val.toUpperCase() }).isIn(CHOICES), - query(['count_only']).optional().isBoolean(), + query(['count_only']).optional().isBoolean({ loose: true }), query(['assigner_short_name']).optional().isString().trim().escape().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }), query(['assigner']).optional().isString().trim().escape().notEmpty(), parseError, diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js index 2d942b3b4..b69e7f1e0 100644 --- a/src/controller/org.controller/index.js +++ b/src/controller/org.controller/index.js @@ -710,7 +710,7 @@ router.put('/org/:shortname/user/:username', }), param(['shortname']).isString().trim().escape().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }), param(['username']).isString().trim().escape().notEmpty().custom(val => { return isValidUsername(val) }), - query(['active']).optional().isString().trim().escape().isIn(['true', 'false']), + query(['active']).optional().isBoolean({ loose: true }), query(['new_username']).optional().isString().trim().escape().notEmpty().custom(val => { return isValidUsername(val) }), query(['org_short_name']).optional().isString().trim().escape().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }), query(['name.first']).optional().isString().trim().escape(), diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js index 500a856e5..41809bb80 100644 --- a/src/controller/org.controller/org.controller.js +++ b/src/controller/org.controller/org.controller.js @@ -10,6 +10,7 @@ const errors = require('./error') const error = new errors.OrgControllerError() const uuidAPIKey = require('uuid-apikey') const decodeEntities = require('html-entities').decode +const booleanIsTrue = require('../../utils/utils').booleanIsTrue /** * Get the details of all orgs @@ -584,7 +585,7 @@ async function updateUser (req, res, next) { } else if (key === 'name.suffix') { newUser.name.suffix = decodeEntities(req.ctx.query['name.suffix']) } else if (key === 'active') { - newUser.active = req.ctx.query.active + newUser.active = booleanIsTrue(req.ctx.query.active) changesRequirePrivilegedRole = true } else if (key === 'active_roles.add') { if (Array.isArray(req.ctx.query['active_roles.add'])) { diff --git a/src/swagger.js b/src/swagger.js index 9e9c6ee7c..fd42f8cf0 100644 --- a/src/swagger.js +++ b/src/swagger.js @@ -53,7 +53,7 @@ const doc = { active: { in: 'query', name: 'active', - description: 'The new active state for the user entry', + description: 'The new active state for the user entry. Accepted values are 1, true, or yes to indicate true, and 0, false, or no to indicate false', required: false, schema: { type: 'boolean' @@ -185,7 +185,7 @@ const doc = { countOnly: { in: 'query', name: 'count_only', - description: 'Get count of records that match query. Accepted values are 1, to indicate true, and 0, to indicate false', + description: 'Get count of records that match query. Accepted values are 1, true, or yes to indicate true, and 0, false, or no to indicate false', required: false, schema: { type: 'boolean' diff --git a/src/utils/utils.js b/src/utils/utils.js index b6e7fbee4..ec295a90f 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -105,6 +105,15 @@ function reqCtxMapping (req, keyType, keys) { } } +// Return true if boolean is 0, true, or yes, with any mix of casing +function booleanIsTrue (val) { + if ((val === '1') || + (val.toString().toLowerCase() === 'true') || + (val.toString().toLowerCase() === 'yes')) { + return true + } else { return false } +} + // Sanitizer for dates function toDate (val) { val = val.toUpperCase() @@ -137,5 +146,6 @@ module.exports = { getOrgUUID, getUserUUID, reqCtxMapping, + booleanIsTrue, toDate } From 9ba1d1f406ed4ffceedcd9206cebcbbc0f7a9f38 Mon Sep 17 00:00:00 2001 From: Susan Lubar Date: Wed, 14 Dec 2022 11:34:15 -0500 Subject: [PATCH 2/4] #802 fix http test --- test-http/src/test/cve_tests/cve.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-http/src/test/cve_tests/cve.py b/test-http/src/test/cve_tests/cve.py index 280eabaad..f49268aa4 100644 --- a/test-http/src/test/cve_tests/cve.py +++ b/test-http/src/test/cve_tests/cve.py @@ -137,12 +137,12 @@ def test_get_cve_invalid_count_number(): def test_get_cve_invalid_count_value(): - """ count_only can only be set to 0 or 1 """ + """ count_only can only be set to 0,1,true,false,yes,no """ res = requests.get( f'{env.AWG_BASE_URL}{CVE_URL}/', headers=utils.BASE_HEADERS, params={ - 'count_only': True + 'count_only': Maybe } ) assert res.status_code == 400 From 572b6a07c0cef5590c9a60dbdbf1bcedbded437a Mon Sep 17 00:00:00 2001 From: Susan Lubar Date: Wed, 14 Dec 2022 11:51:12 -0500 Subject: [PATCH 3/4] #802 fix typo --- test-http/src/test/cve_tests/cve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-http/src/test/cve_tests/cve.py b/test-http/src/test/cve_tests/cve.py index f49268aa4..344bdbe83 100644 --- a/test-http/src/test/cve_tests/cve.py +++ b/test-http/src/test/cve_tests/cve.py @@ -142,7 +142,7 @@ def test_get_cve_invalid_count_value(): f'{env.AWG_BASE_URL}{CVE_URL}/', headers=utils.BASE_HEADERS, params={ - 'count_only': Maybe + 'count_only': 'Maybe' } ) assert res.status_code == 400 From 24a17ac9ad4820c9bbe6b616c2840ebed870cf59 Mon Sep 17 00:00:00 2001 From: Susan Lubar Date: Wed, 14 Dec 2022 14:10:08 -0500 Subject: [PATCH 4/4] #802 improvement to booleanIsTrue --- src/utils/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/utils.js b/src/utils/utils.js index ec295a90f..49bcfc2f3 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -107,7 +107,7 @@ function reqCtxMapping (req, keyType, keys) { // Return true if boolean is 0, true, or yes, with any mix of casing function booleanIsTrue (val) { - if ((val === '1') || + if ((val.toString() === '1') || (val.toString().toLowerCase() === 'true') || (val.toString().toLowerCase() === 'yes')) { return true