1 | const fs = require('fs');
|
2 | const Handlebars = require('handlebars');
|
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 | return Handlebars.compile(htmlTemplate)(data);
|
19 | } catch (err) {
|
20 | throw err;
|
21 | }
|
22 | };
|
23 |
|
24 | const writeReport = async (report, output) => {
|
25 | try {
|
26 | const writeFile = promisify(fs.writeFile);
|
27 | await writeFile(output, report);
|
28 | } catch (err) {
|
29 | throw err;
|
30 | }
|
31 | };
|
32 |
|
33 | const modifyData = async (data, showUnique) => {
|
34 | const auditAdvisories = data.filter((vulnerability) => vulnerability.type === 'auditAdvisory');
|
35 | const reportDate = new Date();
|
36 | const summaryData = data.pop().data;
|
37 | const summary = {
|
38 | ...summaryData,
|
39 | vulnerabilities: Object.values(summaryData.vulnerabilities).reduce((sum, next) => (sum + next), 0),
|
40 | };
|
41 |
|
42 | let vulnerabilities = auditAdvisories.map((vulnerability) => ({
|
43 | ...vulnerability.data.advisory,
|
44 | paths: [vulnerability.data.resolution.path],
|
45 | }));
|
46 |
|
47 | if (showUnique) {
|
48 | const vulnerabilitiesSet = {};
|
49 |
|
50 | vulnerabilities.forEach((vulnerability) => {
|
51 | vulnerability.findings.forEach((finding) => {
|
52 | const key = `${vulnerability.module_name}@${finding.version}`;
|
53 |
|
54 | if (!(key in vulnerabilitiesSet)) {
|
55 | vulnerabilitiesSet[key] = {
|
56 | ...vulnerability,
|
57 | paths: finding.paths,
|
58 | version: finding.version,
|
59 | };
|
60 | }
|
61 | });
|
62 | });
|
63 |
|
64 | vulnerabilities = Object.values(vulnerabilitiesSet);
|
65 | }
|
66 |
|
67 | vulnerabilities.sort((left, right) => (
|
68 | severitySortPriority.indexOf(left.severity) - severitySortPriority.indexOf(right.severity))
|
69 | );
|
70 |
|
71 | return {
|
72 | showUnique,
|
73 | reportDate,
|
74 | vulnerabilities,
|
75 | summary,
|
76 | };
|
77 | };
|
78 |
|
79 | module.exports = async (data, templateFile, outputFile, showUnique) => {
|
80 | try {
|
81 | const modifiedData = await modifyData(data, showUnique);
|
82 | const report = await generateTemplate(modifiedData, templateFile);
|
83 |
|
84 | await writeReport(report, outputFile);
|
85 | } catch (err) {
|
86 | console.error(err);
|
87 | }
|
88 | };
|
89 |
|
90 | Handlebars.registerHelper('date', (dateStr) => (new Date(dateStr)).toLocaleString());
|
91 |
|
92 | Handlebars.registerHelper('severityClass', (severity) => bootstrapClassSeverityMap[ severity ]);
|
93 |
|
94 | Handlebars.registerHelper('markdown', (source) => marked(source));
|