Skip to content

Commit bf1543f

Browse files
authored
Merge pull request #1592 from CVEProject/emathew/testing
Separate ParsePut Params in org middleware
2 parents af1417f + 0c02add commit bf1543f

File tree

10 files changed

+101
-78
lines changed

10 files changed

+101
-78
lines changed

api-docs/openapi.json

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,13 +3199,6 @@
31993199
},
32003200
"description": "The shortname of the organization"
32013201
},
3202-
{
3203-
"name": "registry",
3204-
"in": "query",
3205-
"schema": {
3206-
"type": "string"
3207-
}
3208-
},
32093202
{
32103203
"$ref": "#/components/parameters/id_quota"
32113204
},

src/controller/org.controller/index.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const mw = require('../../middleware/middleware')
44
const errorMsgs = require('../../middleware/errorMessages')
55
const controller = require('./org.controller')
66
const { body, param, query } = require('express-validator')
7-
const { parseGetParams, parsePostParams, parseError, isUserRole, isValidUsername, isOrgRole, validateUpdateOrgParameters } = require('./org.middleware')
7+
const { parseGetParams, parsePostParams, parsePutParams, parseError, isUserRole, isValidUsername, isOrgRole, validateUpdateOrgParameters } = require('./org.middleware')
88
// Only God and Javascript know swhy its saying it is not used when it is.....
99
// eslint-disable-next-line no-unused-vars
1010
const { toUpperCaseArray, isFlatStringArray, handleRegistryParameter } = require('../../middleware/middleware')
@@ -568,8 +568,9 @@ router.put('/registry/org/:shortname',
568568
mw.useRegistry(),
569569
mw.validateUser,
570570
mw.onlySecretariat,
571+
validateUpdateOrgParameters(),
571572
parseError,
572-
parsePostParams,
573+
parsePutParams,
573574
controller.REGISTRY_UPDATE_ORG
574575
)
575576

@@ -774,7 +775,7 @@ router.put('/registry/org/:shortname/user/:username',
774775
.customSanitizer(toUpperCaseArray)
775776
.custom(isUserRole).withMessage(errorMsgs.USER_ROLES),
776777
parseError,
777-
parsePostParams,
778+
parsePutParams,
778779
controller.USER_UPDATE_SINGLE)
779780

780781
router.put('/registry/org/:shortname/user/:username/reset_secret',
@@ -1026,6 +1027,7 @@ router.post(
10261027
.customSanitizer(toUpperCaseArray)
10271028
.custom(isOrgRole),
10281029
body(['policies.id_quota']).optional().not().isArray().isInt({ min: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_min, max: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_max }).withMessage(errorMsgs.ID_QUOTA),
1030+
query().custom((query) => { return mw.validateQueryParameterNames(query, ['']) }),
10291031
parseError,
10301032
parsePostParams,
10311033
controller.ORG_CREATE_SINGLE
@@ -1179,7 +1181,7 @@ router.put('/org/:shortname',
11791181
mw.onlySecretariat,
11801182
validateUpdateOrgParameters(),
11811183
parseError,
1182-
parsePostParams,
1184+
parsePutParams,
11831185
controller.ORG_UPDATE_SINGLE)
11841186

11851187
router.get('/org/:shortname/id_quota',
@@ -1607,7 +1609,7 @@ router.put('/org/:shortname/user/:username',
16071609
.customSanitizer(toUpperCaseArray)
16081610
.custom(isUserRole).withMessage(errorMsgs.USER_ROLES),
16091611
parseError,
1610-
parsePostParams,
1612+
parsePutParams,
16111613
controller.USER_UPDATE_SINGLE)
16121614

16131615
router.put('/org/:shortname/user/:username/reset_secret',

src/controller/org.controller/org.controller.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ async function getOrgIdQuota (req, res, next) {
190190

191191
try {
192192
session.startTransaction()
193-
const requesterOrg = await orgRepo.findOneByShortName(requesterOrgShortName)
193+
const requesterOrg = await orgRepo.findOneByShortName(requesterOrgShortName, { session })
194194
const isSecretariat = await orgRepo.isSecretariat(requesterOrg, !req.useRegistry)
195195

196196
if (requesterOrgShortName !== shortName && !isSecretariat) {
@@ -351,12 +351,14 @@ async function registryUpdateOrg (req, res, next) {
351351
session.startTransaction()
352352
if (queryParametersJson['active_roles.add']) {
353353
if (!Array.isArray(queryParametersJson.active_roles?.add) || queryParametersJson.active_roles?.add.some(item => typeof item !== 'string')) {
354+
await session.abortTransaction()
354355
return res.status(400).json({ message: 'Parameters were invalid', details: [{ param: 'authority', msg: 'Parameter must be a one-dimensional array of strings' }] })
355356
}
356357
}
357358

358359
if (queryParametersJson['active_roles.remove']) {
359360
if (!Array.isArray(queryParametersJson.active_roles?.remove) || queryParametersJson.active_roles?.remove.some(item => typeof item !== 'string')) {
361+
await session.abortTransaction()
360362
return res.status(400).json({ message: 'Parameters were invalid', details: [{ param: 'authority', msg: 'Parameter must be a one-dimensional array of strings' }] })
361363
}
362364
}

src/controller/org.controller/org.middleware.js

Lines changed: 64 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ function validateCreateOrgParameters () {
161161

162162
function validateUserIdOrUsername () {
163163
return async (req, res, next) => {
164-
const useRegistry = req.query.registry === 'true'
164+
const useRegistry = req.useRegistry === 'true'
165165
const validations = []
166166
if (useRegistry) {
167167
validations.push(
@@ -188,18 +188,15 @@ function validateUserIdOrUsername () {
188188

189189
function validateUpdateOrgParameters () {
190190
return async (req, res, next) => {
191-
const useRegistry = req.query.registry === 'true'
192-
193-
const legacyParametersOnly = ['id_quota', 'name']
194-
const registryParametersOnly = ['hard_quota', 'long_name', 'cve_program_org_function', 'oversees', 'root_or_tlr', 'charter_or_scope', 'disclosure_policy', 'product_list', 'cna_role_type', 'cna_country', 'vulnerability_advisory_locations', 'advisory_location_require_credentials', 'industry', 'tl_root_start_date', 'is_cna_discussion_list']
195-
const sharedParameters = ['new_short_name', 'active_roles.add', 'active_roles.remove', 'registry']
191+
const useRegistry = req.query === 'true'
192+
const allowedParams = [...QUERY_PARAMETERS.shared]
193+
const registryParametersOnly = [...QUERY_PARAMETERS.registryOnly]
196194

197-
const allParameters = [
198-
...legacyParametersOnly, ...registryParametersOnly, ...sharedParameters
199-
]
200-
201-
const validations = [query().custom((query) => { return mw.validateQueryParameterNames(query, allParameters) }),
202-
query(allParameters).custom((val) => { return mw.containsNoInvalidCharacters(val) }),
195+
const validations = [query().custom((query) => { return mw.validateQueryParameterNames(query, allowedParams) }),
196+
query(allowedParams).custom((val) => { return mw.containsNoInvalidCharacters(val) }),
197+
query(['id_quota']).optional().not().isArray().isInt({ min: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_min, max: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_max }).withMessage(errorMsgs.ID_QUOTA),
198+
query(['name']).optional().isString().trim().notEmpty(),
199+
// Shared parameter validations
203200
query(['new_short_name']).optional().isString().trim().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
204201
query(['active_roles.add']).optional().toArray()
205202
.custom(isFlatStringArray)
@@ -209,27 +206,17 @@ function validateUpdateOrgParameters () {
209206
.custom(isFlatStringArray)
210207
.customSanitizer(toUpperCaseArray)
211208
.custom(isOrgRole).withMessage(errorMsgs.ORG_ROLES),
209+
// Path parameter validation
212210
param(['shortname']).isString().trim().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH })]
213-
214211
if (useRegistry) {
215212
validations.push(
216-
query(['hard_quota'])
217-
.optional()
218-
.not()
219-
.isArray()
220-
.isInt({
221-
min: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_min,
222-
max: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_max
223-
})
224-
.withMessage(errorMsgs.ID_QUOTA),
225-
query(['long_name']).optional().isString().trim().notEmpty(),
226213
query(['oversees']).optional().isArray(),
227214
query(['root_or_tlr']).optional().isBoolean(),
228215
query([
229-
'cve_program_org_function',
230216
'charter_or_scope',
231217
'disclosure_policy',
232218
'product_list',
219+
'reports_to',
233220
'contact_info.poc',
234221
'contact_info.poc_email',
235222
'contact_info.poc_phone',
@@ -244,17 +231,13 @@ function validateUpdateOrgParameters () {
244231
'is_cna_discussion_list'
245232
])
246233
.optional()
247-
.isString(),
248-
...isNotAllowedQuery(...legacyParametersOnly)
249-
// if we decide that we want to allow more, we can add them here.
234+
.isString()
235+
.trim()
250236
)
251237
} else {
252238
validations.push(
253-
254-
query(['id_quota']).optional().not().isArray().isInt({ min: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_min, max: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_max }).withMessage(errorMsgs.ID_QUOTA),
255-
query(['name']).optional().isString().trim().notEmpty(),
239+
// Block registry-only parameters
256240
...isNotAllowedQuery(...registryParametersOnly)
257-
258241
)
259242
}
260243

@@ -304,49 +287,76 @@ function isUserRole (val) {
304287
return true
305288
}
306289

307-
function parsePostParams (req, res, next) {
308-
utils.reqCtxMapping(req, 'body', [])
309-
utils.reqCtxMapping(req, 'query', [
290+
const QUERY_PARAMETERS = {
291+
// Parameters that apply to BOTH systems
292+
shared: [
310293
'new_short_name',
311-
'name',
312-
'id_quota',
313-
'active',
294+
'name', // Updates 'name' in legacy, 'long_name' in registry
295+
'active_roles',
314296
'active_roles.add',
315297
'active_roles.remove',
316-
'new_username',
317-
'org_short_name',
318-
'name.first',
319-
'name.last',
320-
'name.middle',
321-
'name.suffix',
322-
'long_name',
323-
'cve_program_org_function',
298+
'id_quota' // For registry, maps to 'hard_quota' for CNAOrg
299+
],
300+
// Registry-only parameters
301+
registryOnly: [
302+
'root_or_tlr',
324303
'charter_or_scope',
325304
'disclosure_policy',
326305
'product_list',
306+
'oversees',
307+
'reports_to',
308+
'contact_info',
327309
'contact_info.poc',
328310
'contact_info.poc_email',
329311
'contact_info.poc_phone',
330312
'contact_info.org_email',
331-
'hard_quota',
332313
'contact_info.website',
333-
'root_or_tlr',
334-
'oversees',
335314
'cna_role_type',
336315
'cna_country',
337316
'vulnerability_advisory_locations',
338317
'advisory_location_require_credentials',
339318
'industry',
340319
'tl_root_start_date',
341-
'is_cna_discussion_list'
342-
])
343-
utils.reqCtxMapping(req, 'params', ['shortname', 'username'])
320+
'is_cna_discussion_list',
321+
'hard_quota' // not directly used in query parameters
322+
],
323+
// User-related parameters
324+
userParams: [
325+
'active',
326+
'new_username',
327+
'org_short_name',
328+
'name.first',
329+
'name.last',
330+
'name.middle',
331+
'name.suffix',
332+
'active_roles.add', // For user roles
333+
'active_roles.remove' // For user roles
334+
]
335+
}
336+
337+
function parsePutParams (req, res, next) {
338+
utils.reqCtxMapping(req, 'body', [])
339+
// Extract all possible query parameters
340+
const allQueryParams = [
341+
...QUERY_PARAMETERS.shared,
342+
...QUERY_PARAMETERS.registryOnly,
343+
...QUERY_PARAMETERS.userParams
344+
]
345+
utils.reqCtxMapping(req, 'query', allQueryParams)
346+
utils.reqCtxMapping(req, 'params', ['shortname', 'username', 'identifier'])
347+
next()
348+
}
349+
350+
function parsePostParams (req, res, next) {
351+
utils.reqCtxMapping(req, 'body', [])
352+
utils.reqCtxMapping(req, 'query', [])
353+
utils.reqCtxMapping(req, 'params', ['shortname', 'username', 'identifier'])
344354
next()
345355
}
346356

347357
function parseGetParams (req, res, next) {
348-
utils.reqCtxMapping(req, 'params', ['shortname', 'username', 'identifier', 'registry'])
349-
utils.reqCtxMapping(req, 'query', ['page', 'registry'])
358+
utils.reqCtxMapping(req, 'params', ['shortname', 'username', 'identifier'])
359+
utils.reqCtxMapping(req, 'query', ['page'])
350360
next()
351361
}
352362

@@ -369,6 +379,7 @@ function isValidUsername (val) {
369379
}
370380

371381
module.exports = {
382+
parsePutParams,
372383
parsePostParams,
373384
parseGetParams,
374385
parseError,

src/repositories/baseOrgRepository.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ class BaseOrgRepository extends BaseRepository {
788788

789789
convertLegacyToRegistry (legacyOrg) {
790790
let newRoles = []
791-
if (legacyOrg?.authority?.active_roles.includes('SECRETARIAT')) {
791+
if (legacyOrg?.authority?.active_roles?.includes('SECRETARIAT')) {
792792
newRoles.push('SECRETARIAT')
793793
} else {
794794
newRoles = legacyOrg?.authority?.active_roles

src/scripts/populate.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const BaseOrg = require('../model/baseorg')
2020
const BaseUser = require('../model/baseuser')
2121
const ReviewObject = require('../model/reviewobject')
2222
const Conversation = require('../model/conversation')
23+
const Audit = require('../model/audit')
2324

2425
const error = new errors.IDRError()
2526

@@ -32,7 +33,8 @@ const populateTheseCollections = {
3233
BaseOrg: BaseOrg,
3334
BaseUser: BaseUser,
3435
ReviewObject: ReviewObject,
35-
Conversation: Conversation
36+
Conversation: Conversation,
37+
Audit: Audit
3638
}
3739

3840
const indexesToCreate = {

test/integration-tests/audit/registryOrgCreatesAuditTest.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ describe('Create and Update Audit Collection with Org Endpoints', () => {
109109

110110
// Now update with same values
111111
const updateResAgain = await chai.request(app)
112-
.put(`/api/registry/org/${org.shortName}?long_name=${org.longName}`)
112+
.put(`/api/registry/org/${org.shortName}?name=${org.longName}`)
113113
.set(secretariatHeaders)
114114
expect(updateResAgain).to.have.status(200)
115+
expect(updateResAgain.body.updated.long_name).to.equal(org.longName)
115116

116117
// Check audit history
117118
const auditRes = await chai.request(app)

test/integration-tests/org/registryOrg.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,25 @@ describe('Testing Secretariat functionality for Orgs', () => {
101101
})
102102
})
103103

104-
it('Secretariat can update the ID quota for an org', async () => {
104+
it('Secretariat can update the ID quota for a CNA org', async () => {
105105
await chai.request(app)
106-
.put('/api/registry/org/mitre?hard_quota=100000')
106+
.post('/api/registry/org')
107+
.set(secretariatHeaders)
108+
.send({
109+
short_name: 'test_registry_org_cna',
110+
long_name: 'Testing Registry Org CNA',
111+
hard_quota: 123,
112+
authority: ['CNA']
113+
}).then((res) => {
114+
expect(res).to.have.status(200)
115+
})
116+
await chai.request(app)
117+
.put('/api/registry/org/test_registry_org_cna?id_quota=100000')
107118
.set(secretariatHeaders)
108119
.then((res) => {
109120
expect(res).to.have.status(200)
110-
expect(res.body.message).to.equal('mitre organization was successfully updated.')
121+
expect(res.body.updated.hard_quota).to.equal(100000)
122+
expect(res.body.message).to.equal('test_registry_org_cna organization was successfully updated.')
111123
})
112124
})
113125

@@ -412,7 +424,7 @@ describe('Testing Secretariat functionality for Orgs', () => {
412424
it('Fails to update an org that does not exist', async () => {
413425
const nonExistentOrg = 'nonexistent_org'
414426
await chai.request(app)
415-
.put(`/api/registry/org/${nonExistentOrg}?hard_quota=100`)
427+
.put(`/api/registry/org/${nonExistentOrg}?id_quota=100`)
416428
.set(secretariatHeaders)
417429
.then((res) => {
418430
expect(res).to.have.status(404)
@@ -433,7 +445,7 @@ describe('Testing Secretariat functionality for Orgs', () => {
433445
.then((res) => {
434446
expect(res).to.have.status(400)
435447
expect(res.body.message).to.equal('Parameters were invalid')
436-
expect(res.body.details[0].param).to.equal('authority')
448+
expect(res.body.details[0].param).to.equal('active_roles.add')
437449
expect(res.body.details[0].msg).to.equal('Parameter must be a one-dimensional array of strings')
438450
})
439451
})

test/unit-tests/org/orgUpdateTest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
165165
}
166166
req.ctx.repositories = factory
167167
next()
168-
}, orgParams.parsePostParams, orgController.ORG_UPDATE_SINGLE)
168+
}, orgParams.parsePutParams, orgController.ORG_UPDATE_SINGLE)
169169

170170
chai.request(app)
171171
.put(`/org-not-updated-shortname-exists/${orgFixtures.existentOrg.short_name}?new_short_name=cisco`)

0 commit comments

Comments
 (0)