feat: add severity summary, sort findings by impact, and sanitize email output
This commit is contained in:
+29
-1
@@ -3,9 +3,11 @@ package mailer
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html"
|
||||||
"log"
|
"log"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"nucleus/internal/models"
|
"nucleus/internal/models"
|
||||||
)
|
)
|
||||||
@@ -48,6 +50,27 @@ func SendReport(target models.Target, findings []models.Finding) {
|
|||||||
if len(findings) == 0 {
|
if len(findings) == 0 {
|
||||||
body.WriteString("<p>No findings were detected.</p>")
|
body.WriteString("<p>No findings were detected.</p>")
|
||||||
} else {
|
} else {
|
||||||
|
// Calculate summary
|
||||||
|
counts := map[string]int{"critical": 0, "high": 0, "medium": 0, "low": 0, "info": 0}
|
||||||
|
for _, f := range findings {
|
||||||
|
counts[f.Severity]++
|
||||||
|
}
|
||||||
|
|
||||||
|
body.WriteString("<h3>Summary</h3><ul>")
|
||||||
|
if counts["critical"] > 0 { body.WriteString(fmt.Sprintf("<li>Critical: %d</li>", counts["critical"])) }
|
||||||
|
if counts["high"] > 0 { body.WriteString(fmt.Sprintf("<li>High: %d</li>", counts["high"])) }
|
||||||
|
if counts["medium"] > 0 { body.WriteString(fmt.Sprintf("<li>Medium: %d</li>", counts["medium"])) }
|
||||||
|
if counts["low"] > 0 { body.WriteString(fmt.Sprintf("<li>Low: %d</li>", counts["low"])) }
|
||||||
|
if counts["info"] > 0 { body.WriteString(fmt.Sprintf("<li>Info: %d</li>", counts["info"])) }
|
||||||
|
body.WriteString("</ul>")
|
||||||
|
|
||||||
|
// Sort findings by severity
|
||||||
|
severityScore := map[string]int{"critical": 5, "high": 4, "medium": 3, "low": 2, "info": 1}
|
||||||
|
sort.Slice(findings, func(i, j int) bool {
|
||||||
|
return severityScore[findings[i].Severity] > severityScore[findings[j].Severity]
|
||||||
|
})
|
||||||
|
|
||||||
|
body.WriteString("<h3>Details</h3>")
|
||||||
body.WriteString("<table border='1' cellpadding='5' style='border-collapse: collapse; width: 100%;'>")
|
body.WriteString("<table border='1' cellpadding='5' style='border-collapse: collapse; width: 100%;'>")
|
||||||
body.WriteString("<tr style='background-color: #f2f2f2; text-align: left;'><th>Severity</th><th>Name</th><th>Host</th><th>Template</th></tr>")
|
body.WriteString("<tr style='background-color: #f2f2f2; text-align: left;'><th>Severity</th><th>Name</th><th>Host</th><th>Template</th></tr>")
|
||||||
for _, f := range findings {
|
for _, f := range findings {
|
||||||
@@ -59,7 +82,12 @@ func SendReport(target models.Target, findings []models.Finding) {
|
|||||||
case "low": color = "#e6f2ff"
|
case "low": color = "#e6f2ff"
|
||||||
case "info": color = "#f2f2f2"
|
case "info": color = "#f2f2f2"
|
||||||
}
|
}
|
||||||
body.WriteString(fmt.Sprintf("<tr style='background-color: %s;'><td><strong>%s</strong></td><td>%s</td><td>%s</td><td>%s</td></tr>", color, f.Severity, f.Name, f.Host, f.TemplateID))
|
body.WriteString(fmt.Sprintf("<tr style='background-color: %s;'><td><strong>%s</strong></td><td>%s</td><td>%s</td><td>%s</td></tr>",
|
||||||
|
color,
|
||||||
|
html.EscapeString(f.Severity),
|
||||||
|
html.EscapeString(f.Name),
|
||||||
|
html.EscapeString(f.Host),
|
||||||
|
html.EscapeString(f.TemplateID)))
|
||||||
}
|
}
|
||||||
body.WriteString("</table>")
|
body.WriteString("</table>")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user