var mongoose = require('mongoose'); var _ = require('lodash'); var Schema = mongoose.Schema; var customField = { _id: false, customField: { type: Schema.Types.ObjectId, ref: 'CustomField' }, text: Schema.Types.Mixed, }; var VulnerabilityUpdateSchema = new Schema( { vulnerability: { type: Schema.Types.ObjectId, ref: 'Vulnerability', required: true, }, creator: { type: Schema.Types.ObjectId, ref: 'User', required: true }, cvssv3: String, priority: { type: Number, enum: [1, 2, 3, 4] }, remediationComplexity: { type: Number, enum: [1, 2, 3] }, references: [String], locale: String, title: String, vulnType: String, description: String, observation: String, remediation: String, category: String, customFields: [customField], }, { timestamps: true }, ); /* *** Statics *** */ // Get all vulnerabilities VulnerabilityUpdateSchema.statics.getAll = () => { return new Promise((resolve, reject) => { var query = VulnerabilityUpdate.find(); query .exec() .then(rows => { resolve(rows); }) .catch(err => { reject(err); }); }); }; // Get all updates of vulnerability VulnerabilityUpdateSchema.statics.getAllByVuln = vulnId => { return new Promise((resolve, reject) => { var query = VulnerabilityUpdate.find({ vulnerability: vulnId }); query.populate('creator', '-_id username'); query.populate('customFields.customField', 'fieldType label'); query .exec() .then(rows => { resolve(rows); }) .catch(err => { reject(err); }); }); }; // Create vulnerability VulnerabilityUpdateSchema.statics.create = (username, vulnerability) => { return new Promise((resolve, reject) => { var created = true; var User = mongoose.model('User'); var creator = ''; var Vulnerability = mongoose.model('Vulnerability'); var query = User.findOne({ username: username }); query .exec() .then(row => { if (row) { creator = row._id; var query = Vulnerability.findOne({ 'details.title': vulnerability.title, }); return query.exec(); } else throw { fn: 'NotFound', message: 'User not found' }; }) .then(row => { if (row) { if (row.status === 1) throw { fn: 'Forbidden', message: 'Vulnerability not approved yet', }; else { // Check if there are any changes from the original vulnerability var detail = row.details.find( d => d.locale === vulnerability.locale, ); // console.log(vulnerability.customFields) // console.log(detail.customFields) if ( typeof detail !== 'undefined' && (row.cvssv3 || '').includes(vulnerability.cvssv3) && vulnerability.priority === (row.priority || null) && vulnerability.remediationComplexity === (row.remediationComplexity || null) && _.isEqual(vulnerability.references, detail.references || []) && vulnerability.category === (row.category || null) && vulnerability.vulnType === (detail.vulnType || null) && vulnerability.description === (detail.description || null) && vulnerability.observation === (detail.observation || null) && vulnerability.remediation === (detail.remediation || null) && vulnerability.customFields.length === detail.customFields.length && vulnerability.customFields.every((e, idx) => { return ( e.customField._id == detail.customFields[idx].customField && e.text === detail.customFields[idx].text ); }) ) { throw { fn: 'BadParameters', message: 'No changes from the original vulnerability', }; } vulnerability.vulnerability = row._id; vulnerability.creator = creator; var query = new VulnerabilityUpdate(vulnerability); created = false; return query.save(); } } else { var vuln = {}; vuln.cvssv3 = vulnerability.cvssv3 || null; vuln.priority = vulnerability.priority || null; vuln.remediationComplexity = vulnerability.remediationComplexity || null; vuln.category = vulnerability.category || null; vuln.creator = creator; var details = {}; details.locale = vulnerability.locale || null; details.title = vulnerability.title || null; details.vulnType = vulnerability.vulnType || null; details.description = vulnerability.description || null; details.observation = vulnerability.observation || null; details.remediation = vulnerability.remediation || null; details.references = vulnerability.references || null; details.customFields = vulnerability.customFields || []; vuln.details = [details]; var query = new Vulnerability(vuln); return query.save(); } }) .then(row => { if (created) resolve('Finding created as new Vulnerability'); else { var query = Vulnerability.findOneAndUpdate( { 'details.title': vulnerability.title }, { status: 2 }, ); return query.exec(); } }) .then(row => { resolve('Update proposed for existing vulnerability'); }) .catch(err => { reject(err); }); }); }; VulnerabilityUpdateSchema.statics.deleteAllByVuln = async vulnId => { return await VulnerabilityUpdate.deleteMany({ vulnerability: vulnId }); }; /* *** Methods *** */ var VulnerabilityUpdate = mongoose.model( 'VulnerabilityUpdate', VulnerabilityUpdateSchema, ); module.exports = VulnerabilityUpdate;