1 | const fs = require('fs');
|
2 | const ejs = require('ejs');
|
3 | const marked = require('marked');
|
4 | const { promisify } = require('util');
|
5 |
|
6 | const bootstrapClassSeverityMap = {
|
7 | critical: 'danger',
|
8 | high: 'warning',
|
9 | moderate: 'secondary',
|
10 | low: 'primary',
|
11 | };
|
12 | const severitySortPriority = Object.keys(bootstrapClassSeverityMap);
|
13 |
|
14 | const generateTemplate = async (data, template) => {
|
15 | try {
|
16 | const readFile = promisify(fs.readFile);
|
17 | const htmlTemplate = await readFile(template, 'utf8');
|
18 |
|
19 | return ejs.render(htmlTemplate, {
|
20 | ...data,
|
21 | formatDate: (dateStr) => (new Date(dateStr)).toLocaleString(),
|
22 | severityClass: (severity) => bootstrapClassSeverityMap[ severity ],
|
23 | markdown: marked,
|
24 | });
|
25 | } catch (err) {
|
26 | throw err;
|
27 | }
|
28 | };
|
29 |
|
30 | const writeReport = async (report, output) => {
|
31 | try {
|
32 | const writeFile = promisify(fs.writeFile);
|
33 | await writeFile(output, report);
|
34 | } catch (err) {
|
35 | throw err;
|
36 | }
|
37 | };
|
38 |
|
39 | const modifyData = async (data, showUnique) => {
|
40 | const auditAdvisories = data.filter((vulnerability) => vulnerability.type === 'auditAdvisory');
|
41 | const reportDate = new Date();
|
42 | const summaryData = data.pop().data;
|
43 | const summary = {
|
44 | ...summaryData,
|
45 | vulnerabilities: Object.values(summaryData.vulnerabilities).reduce((sum, next) => (sum + next), 0),
|
46 | };
|
47 |
|
48 | let vulnerabilities = auditAdvisories.map((vulnerability) => ({
|
49 | ...vulnerability.data.advisory,
|
50 | paths: [vulnerability.data.resolution.path],
|
51 | }));
|
52 |
|
53 | if (showUnique) {
|
54 | const vulnerabilitiesMap = {};
|
55 |
|
56 | vulnerabilities.forEach((vulnerability) => {
|
57 | vulnerability.findings.forEach((finding) => {
|
58 | const key = `${vulnerability.module_name}@${finding.version}.${vulnerability.cwe}`;
|
59 |
|
60 | if (!(key in vulnerabilitiesMap)) {
|
61 | vulnerabilitiesMap[key] = {
|
62 | ...vulnerability,
|
63 | paths: finding.paths,
|
64 | version: finding.version,
|
65 | };
|
66 | } else {
|
67 |
|
68 | vulnerabilitiesMap[key].paths = Array.from(
|
69 | new Set(vulnerabilitiesMap[key].paths.concat(finding.paths))
|
70 | );
|
71 | }
|
72 | });
|
73 | });
|
74 |
|
75 | vulnerabilities = Object.values(vulnerabilitiesMap);
|
76 | }
|
77 |
|
78 | vulnerabilities.sort((left, right) => (
|
79 | severitySortPriority.indexOf(left.severity) - severitySortPriority.indexOf(right.severity))
|
80 | );
|
81 |
|
82 | return {
|
83 | showUnique,
|
84 | reportDate,
|
85 | vulnerabilities,
|
86 | summary,
|
87 | };
|
88 | };
|
89 |
|
90 | module.exports = async (data, templateFile, outputFile, showUnique) => {
|
91 | const modifiedData = await modifyData(data, showUnique);
|
92 | const report = await generateTemplate(modifiedData, templateFile);
|
93 |
|
94 | await writeReport(report, outputFile);
|
95 | return modifiedData;
|
96 | };
|