fleet/ee/vulnerability-dashboard/api/controllers/download-one-vulnerability-csv.js
Eric b1945b2128
Add fleet-vulnerability-dashboard repo to ee/ folder (#17428)
Closes: https://github.com/fleetdm/confidential/issues/4057

Changes:
- Added the contents of the fleet-vulnerability-dashboard repo to
ee/vulnerability-dashboard
- Added a github workflow to deploy the vulnerability dashboard on
Heroku
- Added a github workflow to test changes to the vulnerability-dashboard
- Updated the website's custom configuration to enable
auto-approvals/review requests to files in the
ee/vulnerability-dashboard folder
2024-03-13 13:06:11 -05:00

110 lines
4 KiB
JavaScript

module.exports = {
friendlyName: 'Download one vulnerability CSV',
description: 'Download a CSV containing information about a single vulnerability',
inputs: {
cveId: {
decription: 'The CVE ID of the vulnerability that an CSV export will be created for.',
type: 'string',
required: true
},
teamApid: {
description: 'The ID of the Team to filter by, or 0 to only include hosts with no team, or undefined to not filter by any team.',
type: 'number',
},
},
exits: {
success: {
outputFriendlyName: 'File',
outputDescription: 'The streaming bytes of the file.',
outputType: 'ref'
},
},
fn: async function ({cveId, teamApid}) {
// Generate a random room name.
let roomId = await sails.helpers.strings.random();
if(this.req.isSocket) {
// Add the requesting socket to the room.
sails.sockets.join(this.req, roomId);
}
let report = await sails.helpers.getVulnerabilities.with({cveId: cveId, teamApid: teamApid});
if(report.entries.length === 0) {
throw new Error(`Unexpected error: When generating a CSV export for a single vulnerability (with the CVE id ${cveId}), the vulnerability was not found in the database.`);
}
let thisVulnerability = report.entries[0];
let stream = require('stream');
let csvString = '';
// Create a writeable stream we'll use to create the csvString.
let writableStream = new stream.Writable({//[?]: https://nodejs.org/api/stream.html#writable_writechunk-encoding-callback
write(chunk, encoding, callback) {
csvString += chunk.toString();
callback();
}
});
let csv = require('fast-csv');
let generatingCsv = csv.format({ headers: true });
// Pass the writableStream into generatingCsv.
generatingCsv.pipe(writableStream);// [?]: https://c2fo.github.io/fast-csv/docs/formatting/methods#write
// Build the CSV report
for(let host of thisVulnerability.affectedHosts){
let installsForThisHost = thisVulnerability.affectedInstalls.filter((install) => {
return install.affectedHost === host.id;
});
// Add a row for each vulnerable install.
for(let install of installsForThisHost) {
let csvRow = {};
csvRow['CVE ID'] = thisVulnerability.cveId;
csvRow['Severity'] = thisVulnerability.severity;
csvRow['Has known exploit'] = !! thisVulnerability.hasKnownExploit;
csvRow['CVE description'] = thisVulnerability.cveDescription ? thisVulnerability.cveDescription : 'N/A';
csvRow['Publish date'] = new Date(thisVulnerability.publishedAt);
csvRow['Affected software name'] = install.name;
csvRow['Affected software version'] = install.version;
csvRow['Resolved in version'] = install.resolvedInVersion ? install.resolvedInVersion : 'N/A';
csvRow['Affected software URL'] = install.url;
csvRow['Vulnerable software detected on'] = new Date(install.installedAt);
csvRow['Host Fleet URL'] = sails.config.custom.fleetBaseUrl + '/hosts/' + encodeURIComponent(host.fleetApid);
csvRow['Host display name'] = host.displayName;
csvRow['Host team'] = host.teamDisplayName;
csvRow['Host serial number'] = host.hardwareSerialNumber;
csvRow['Host UUID'] = host.uuid;
csvRow['Host team ID'] = host.teamApid !== 0 ? host.teamApid : 'N/A';
// Add this row to the generatingCsv
generatingCsv.write(csvRow);
}//∞
}
generatingCsv.end();
// After the the csvString has been generated by the writableStream, broadcast the csvString to the requesting user's socket.
writableStream.on('finish', () => {
if(this.req.isSocket){
// Note: we're sending the cveId with the cvsString, this is so we can set the filename in our frontend code.
sails.sockets.broadcast(roomId, 'singleCsvExportDone', {csv: csvString, cveId});
// Unsubscribe the socket from the room.
sails.sockets.leave(this.req, roomId);
} else {
return csvString;
}
});
}
};