Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 1 addition & 33 deletions src/controller/registry-org.controller/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,41 +213,9 @@ router.post('/registryOrg',
}
}
*/
mw.useRegistry(),
mw.validateUser,
mw.onlySecretariat,
body(['short_name']).isString().trim().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
body(['long_name']).isString().trim().notEmpty(),
body(['cve_program_org_function']).isString().trim().default('CNA'),
body(['root_or_tlr']).default(false).isBoolean(),
body(['oversees']).default([]).isArray(),
body(
[
'charter_or_scope',
'disclosure_policy',
'product_list',
'reports_to',
'contact_info.poc',
'contact_info.poc_email',
'contact_info.poc_phone',
'contact_info.org_email',
'contact_info.website'
])
.default('')
.isString(),
body(['authority.active_roles']).optional()
.custom(isFlatStringArray)
.customSanitizer(toUpperCaseArray)
.custom(isOrgRole),
body(['soft_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),
body(['hard_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),
body(['contact_info.additional_contact_users']).optional()
.custom(isFlatStringArray),
body(['contact_info.admins']).optional()
.custom(isFlatStringArray),
body(['aliases']).optional()
.custom(isFlatStringArray)
.customSanitizer(toLowerCaseArray),
// TO-DO: validate users here once implemented
parseError,
parsePostParams,
controller.CREATE_ORG
Expand Down
137 changes: 48 additions & 89 deletions src/controller/registry-org.controller/registry-org.controller.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const argon2 = require('argon2')
const mongoose = require('mongoose')
const uuid = require('uuid')
const logger = require('../../middleware/logger')
const { getConstants } = require('../../constants')
Expand Down Expand Up @@ -89,110 +90,68 @@ async function getOrg (req, res, next) {

async function createOrg (req, res, next) {
try {
const CONSTANTS = getConstants()
const userRepo = req.ctx.repositories.getRegistryUserRepository()
const registryOrgRepo = req.ctx.repositories.getRegistryOrgRepository()
const session = await mongoose.startSession()
const repo = req.ctx.repositories.getBaseOrgRepository()
const body = req.ctx.body
let createdOrg

// Short circuit if UUID provided
const bodyKeys = Object.keys(body).map(k => k.toLowerCase())
if (bodyKeys.includes('uuid')) {
// Do not allow the user to pass in a UUID
if ((body?.UUID ?? null) || (body?.uuid ?? null)) {
return res.status(400).json(error.uuidProvided('org'))
}

const newOrg = new RegistryOrg()
bodyKeys.forEach(k => {
if (k === 'long_name') {
newOrg.long_name = body[k]
} else if (k === 'short_name') {
newOrg.short_name = body[k]
} else if (k === 'aliases') {
newOrg.aliases = [...new Set(body[k])]
} else if (k === 'cve_program_org_function') {
newOrg.cve_program_org_function = body[k]
} else if (k === 'authority') {
if ('active_roles' in body[k]) {
newOrg.authority.active_roles = [...new Set(body[k].active_roles)]
}
} else if (k === 'reports_to') {
// TODO: org check logic?
} else if (k === 'oversees') {
// TODO: org check logic?
} else if (k === 'root_or_tlr') {
newOrg.root_or_tlr = body[k]
} else if (k === 'users') {
// TODO: users logic?
} else if (k === 'charter_or_scope') {
newOrg.charter_or_scope = body[k]
} else if (k === 'disclosure_policy') {
newOrg.disclosure_policy = body[k]
} else if (k === 'product_list') {
newOrg.product_list = body[k]
} else if (k === 'soft_quota') {
newOrg.soft_quota = body[k]
} else if (k === 'hard_quota') {
newOrg.hard_quota = body[k]
} else if (k === 'contact_info') {
const { additionalContactUsers, admins, ...contactInfo } = body[k]
newOrg.contact_info = {
additional_contact_users: [...(additionalContactUsers || [])],
poc: '',
poc_email: '',
poc_phone: '',
admins: [...(admins || [])],
org_email: '',
website: '',
...contactInfo
}
try {
session.startTransaction()
const result = repo.validateOrg(req.ctx.body, { session })
if (!result.isValid) {
logger.error(JSON.stringify({ uuid: req.ctx.uuid, message: 'CVE JSON schema validation FAILED.' }))
await session.abortTransaction()

// TODO: Investigate this, right now we are accepting either a one one-dimensional array of strings or just a string.
// However, we are taking the "highest" authority
//
//
// if (!Array.isArray(body?.authority) || body?.authority.some(item => typeof item !== 'string')) {
// return res.status(400).json({ message: 'Parameters were invalid', details: [{ param: 'authority', msg: 'Parameter must be a one-dimensional array of strings' }] })
// }
return res.status(400).json({ message: 'Parameters were invalid', errors: result.errors })
}
})

const doesExist = await registryOrgRepo.findOneByShortName(newOrg.short_name)
if (doesExist) {
logger.info({ uuid: req.ctx.uuid, message: newOrg.short_name + ' organization was not created because it already exists.' })
return res.status(400).json(error.orgExists(newOrg.short_name))
}
// Check for duplicate short_name
if (await repo.orgExists(body?.short_name, { session })) {
logger.info({
uuid: req.ctx.uuid,
message: `${body?.short_name} organization was not created because it already exists.`
})
await session.abortTransaction()
return res.status(400).json(error.orgExists(body?.short_name))
}

if (newOrg.reports_to === undefined) {
// TODO: This may need to be set to mitre, will ask the awg
newOrg.reports_to = null
}
if (newOrg.root_or_tlr === undefined) {
newOrg.root_or_tlr = false
}
if (newOrg.soft_quota === undefined) { // set to default quota if none is specified
newOrg.soft_quota = CONSTANTS.DEFAULT_ID_QUOTA
}
if (newOrg.hard_quota === undefined) { // set to default quota if none is specified
newOrg.hard_quota = CONSTANTS.DEFAULT_ID_QUOTA
}
if (newOrg.authority.active_roles.length === 1 && newOrg.authority.active_roles[0] === 'ADP') { // ADPs have quota of 0
newOrg.soft_quota = 0
newOrg.hard_quota = 0
}
// Create the org – repo.createOrg will handle field mapping
createdOrg = await repo.createOrg(body, { session, upsert: true })

newOrg.in_use = false
newOrg.UUID = uuid.v4()
await session.commitTransaction()
} catch (createErr) {
await session.abortTransaction()
throw createErr
} finally {
await session.endSession()
}

await registryOrgRepo.updateByUUID(newOrg.UUID, newOrg, { upsert: true })
const agt = setAggregateOrgObj({ UUID: newOrg.UUID })
let result = await registryOrgRepo.aggregate(agt)
result = result.length > 0 ? result[0] : null
const responseMessage = {
message: `${body?.short_name} organization was successfully created.`,
created: createdOrg
}

const payload = {
action: 'create_registry_org',
change: result.short_name + ' was successfully created.',
action: 'create_org',
change: `${body?.short_name} organization was successfully created.`,
req_UUID: req.ctx.uuid,
org_UUID: await registryOrgRepo.getOrgUUID(req.ctx.org),
org: result
org_UUID: createdOrg.UUID,
org: createdOrg
}
payload.user_UUID = await userRepo.getUserUUID(req.ctx.user, payload.org_UUID)
logger.info(JSON.stringify(payload))

const responseMessage = {
message: result.short_name + ' was successfully created.',
created: result
}
logger.info(JSON.stringify(payload))
return res.status(200).json(responseMessage)
} catch (err) {
next(err)
Expand Down
33 changes: 23 additions & 10 deletions src/repositories/baseOrgRepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -407,16 +407,29 @@ class BaseOrgRepository extends BaseRepository {

validateOrg (org) {
let validateObject = {}

if (org.authority === 'ADP') {
validateObject = ADPOrgModel.validateOrg(org)
}
if (org.authority === 'SECRETARIAT') {
validateObject = SecretariatOrgModel.validateOrg(org)
}
// We will default to CNA if a type is not given
if (org.authority === 'CNA' || !org.authority) {
validateObject = CNAOrgModel.validateOrg(org)
if (Array.isArray(org.authority)) {
// User passed in an array, we need to decide how we handle this.
if (org.authority.includes('SECRETARIAT')) {
org.authority = 'SECRETARIAT'
validateObject = SecretariatOrgModel.validateOrg(org)
} else {
// We are not a secretariat, so we need to take most priv
if (org.authority.includes('CNA') || org.authority.length === 0) {
org.authority = 'CNA'
validateObject = CNAOrgModel.validateOrg(org)
}
}
} else {
if (org.authority === 'ADP') {
validateObject = ADPOrgModel.validateOrg(org)
}
if (org.authority === 'SECRETARIAT') {
validateObject = SecretariatOrgModel.validateOrg(org)
}
// We will default to CNA if a type is not given
if (org.authority === 'CNA' || !org.authority) {
validateObject = CNAOrgModel.validateOrg(org)
}
}

return validateObject
Expand Down
Loading