Fix tui
This commit is contained in:
@@ -24,6 +24,8 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
c "github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/report"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/google/subcommands"
|
||||
)
|
||||
@@ -144,41 +146,22 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s
|
||||
}
|
||||
|
||||
c.Conf.Pipe = p.pipe
|
||||
// jsonDir, err := report.JSONDir(f.Args())
|
||||
// if err != nil {
|
||||
// log.Errorf("Failed to read json dir under results: %s", err)
|
||||
// return subcommands.ExitFailure
|
||||
// }
|
||||
|
||||
// results, err := report.LoadScanResults(jsonDir)
|
||||
// if err != nil {
|
||||
// log.Errorf("Failed to read from JSON: %s", err)
|
||||
// return subcommands.ExitFailure
|
||||
// }
|
||||
dir, err := report.JSONDir(f.Args())
|
||||
if err != nil {
|
||||
util.Log.Errorf("Failed to read from JSON: %s", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
var res models.ScanResults
|
||||
if res, err = report.LoadScanResults(dir); err != nil {
|
||||
util.Log.Error(err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
util.Log.Infof("Loaded: %s", dir)
|
||||
|
||||
// var filledResults []models.ScanResult
|
||||
// for _, r := range results {
|
||||
// if p.refreshCve || needToRefreshCve(r) {
|
||||
// if c.Conf.CveDBType == "sqlite3" {
|
||||
// if _, err := os.Stat(c.Conf.CveDBPath); os.IsNotExist(err) {
|
||||
// log.Errorf("SQLite3 DB(CVE-Dictionary) is not exist: %s",
|
||||
// c.Conf.CveDBPath)
|
||||
// return subcommands.ExitFailure
|
||||
// }
|
||||
// }
|
||||
|
||||
// if err := fillCveInfoFromCveDB(&r); err != nil {
|
||||
// log.Errorf("Failed to fill CVE information: %s", err)
|
||||
// return subcommands.ExitFailure
|
||||
// }
|
||||
|
||||
// if err := overwriteJSONFile(jsonDir, r); err != nil {
|
||||
// log.Errorf("Failed to write JSON: %s", err)
|
||||
// return subcommands.ExitFailure
|
||||
// }
|
||||
// }
|
||||
// filledResults = append(filledResults, r)
|
||||
// }
|
||||
// return report.RunTui(filledResults)
|
||||
return subcommands.ExitFailure
|
||||
if res, err = report.FillCveInfos(res, dir); err != nil {
|
||||
util.Log.Error(err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
return report.RunTui(res)
|
||||
}
|
||||
|
||||
@@ -596,14 +596,6 @@ type Cpe struct {
|
||||
// References is a slice of Reference
|
||||
type References []Reference
|
||||
|
||||
// Find elements that matches the function passed in argument
|
||||
func (r References) Find(f func(r Reference) bool) (refs []Reference) {
|
||||
for _, rr := range r {
|
||||
refs = append(refs, rr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Reference has a related link of the CVE
|
||||
type Reference struct {
|
||||
Source string
|
||||
|
||||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
@@ -110,10 +111,39 @@ func (p Package) FormatNewVer() string {
|
||||
|
||||
// FormatVersionFromTo formats installed and new package version
|
||||
func (p Package) FormatVersionFromTo() string {
|
||||
return fmt.Sprintf("%s-%s -> %s",
|
||||
return fmt.Sprintf("%s-%s - %s",
|
||||
p.Name, p.FormatVer(), p.FormatNewVer())
|
||||
}
|
||||
|
||||
// FormatChangelog formats the changelog
|
||||
func (p Package) FormatChangelog() string {
|
||||
buf := []string{}
|
||||
if p.NewVersion == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
packVer := fmt.Sprintf("%s-%s -> %s",
|
||||
p.Name, p.FormatVer(), p.FormatNewVer())
|
||||
var delim bytes.Buffer
|
||||
for i := 0; i < len(packVer); i++ {
|
||||
delim.WriteString("-")
|
||||
}
|
||||
|
||||
clog := p.Changelog.Contents
|
||||
if lines := strings.Split(clog, "\n"); len(lines) != 0 {
|
||||
clog = strings.Join(lines[0:len(lines)-1], "\n")
|
||||
}
|
||||
|
||||
switch p.Changelog.Method {
|
||||
case FailedToGetChangelog:
|
||||
clog = "No changelogs"
|
||||
case FailedToFindVersionInChangelog:
|
||||
clog = "Failed to parse changelogs. For detials, check yourself"
|
||||
}
|
||||
buf = append(buf, packVer, delim.String(), clog)
|
||||
return strings.Join(buf, "\n")
|
||||
}
|
||||
|
||||
// Changelog has contents of changelog and how to get it.
|
||||
// Method: modesl.detectionMethodStr
|
||||
type Changelog struct {
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/oval"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/k0kubun/pp"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -72,9 +71,9 @@ func FillCveInfos(rs []models.ScanResult, dir string) ([]models.ScanResult, erro
|
||||
}
|
||||
|
||||
//TODO remove debug code
|
||||
for _, r := range filled {
|
||||
pp.Printf("filled: %d\n", len(r.ScannedCves))
|
||||
}
|
||||
// for _, r := range filled {
|
||||
// pp.Printf("filled: %d\n", len(r.ScannedCves))
|
||||
// }
|
||||
|
||||
filtered := []models.ScanResult{}
|
||||
for _, r := range filled {
|
||||
@@ -82,9 +81,9 @@ func FillCveInfos(rs []models.ScanResult, dir string) ([]models.ScanResult, erro
|
||||
}
|
||||
|
||||
//TODO remove debug code
|
||||
for _, r := range filtered {
|
||||
pp.Printf("filtered: %d\n", len(r.ScannedCves))
|
||||
}
|
||||
// for _, r := range filtered {
|
||||
// pp.Printf("filtered: %d\n", len(r.ScannedCves))
|
||||
// }
|
||||
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
324
report/tui.go
324
report/tui.go
@@ -20,21 +20,25 @@ package report
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/google/subcommands"
|
||||
"github.com/gosuri/uitable"
|
||||
"github.com/jroimartin/gocui"
|
||||
cve "github.com/kotakanbe/go-cve-dictionary/models"
|
||||
)
|
||||
|
||||
var scanResults models.ScanResults
|
||||
var currentScanResult models.ScanResult
|
||||
var currentCveInfo int
|
||||
var vinfos []models.VulnInfo
|
||||
var currentVinfo int
|
||||
var currentDetailLimitY int
|
||||
|
||||
// RunTui execute main logic
|
||||
@@ -220,8 +224,7 @@ func movable(v *gocui.View, nextY int) (ok bool, yLimit int) {
|
||||
}
|
||||
return true, yLimit
|
||||
case "summary":
|
||||
//TODO
|
||||
// yLimit = len(currentScanResult.AllCves()) - 1
|
||||
yLimit = len(currentScanResult.ScannedCves) - 1
|
||||
if yLimit < nextY {
|
||||
return false, yLimit
|
||||
}
|
||||
@@ -279,7 +282,7 @@ func cursorDown(g *gocui.Gui, v *gocui.View) error {
|
||||
// ok, := movable(v, oy+cy+1)
|
||||
// _, maxY := v.Size()
|
||||
ok, _ := movable(v, oy+cy+1)
|
||||
// log.Info(cy, oy, maxY, yLimit)
|
||||
// log.Info(cy, oy)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -290,6 +293,10 @@ func cursorDown(g *gocui.Gui, v *gocui.View) error {
|
||||
}
|
||||
onMovingCursorRedrawView(g, v)
|
||||
}
|
||||
|
||||
cx, cy := v.Cursor()
|
||||
ox, oy := v.Origin()
|
||||
debug(g, fmt.Sprintf("%v, %v, %v, %v", cx, cy, ox, oy))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -441,6 +448,7 @@ func changeHost(g *gocui.Gui, v *gocui.View) error {
|
||||
for _, r := range scanResults {
|
||||
if serverName == strings.TrimSpace(r.ServerInfoTui()) {
|
||||
currentScanResult = r
|
||||
vinfos = r.ScannedCves.ToSortedSlice()
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -509,7 +517,8 @@ func showMsg(g *gocui.Gui, v *gocui.View) error {
|
||||
// maxX, maxY := v.Size()
|
||||
_, maxY := v.Size()
|
||||
|
||||
l := fmt.Sprintf("cy: %d, oy: %d, maxY: %d, yLimit: %d, curCve %d, ok: %v", cy, oy, maxY, yLimit, currentCveInfo, ok)
|
||||
l := fmt.Sprintf("cy: %d, oy: %d, maxY: %d, yLimit: %d, curCve %d, ok: %v",
|
||||
cy, oy, maxY, yLimit, currentVinfo, ok)
|
||||
// if v, err := g.SetView("msg", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
|
||||
if v, err := g.SetView("msg", 10, maxY/2, 10+50, maxY/2+2); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
@@ -550,6 +559,20 @@ func layout(g *gocui.Gui) error {
|
||||
if err := setChangelogLayout(g); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func debug(g *gocui.Gui, str string) error {
|
||||
if config.Conf.Debug {
|
||||
maxX, maxY := g.Size()
|
||||
if _, err := g.View("debug"); err != gocui.ErrUnknownView {
|
||||
g.DeleteView("debug")
|
||||
}
|
||||
if v, err := g.SetView("debug", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil {
|
||||
fmt.Fprintf(v, str)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -568,6 +591,7 @@ func setSideLayout(g *gocui.Gui) error {
|
||||
return fmt.Errorf("No scan results")
|
||||
}
|
||||
currentScanResult = scanResults[0]
|
||||
vinfos = scanResults[0].ScannedCves.ToSortedSlice()
|
||||
if _, err := g.SetCurrentView("side"); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -601,72 +625,35 @@ func summaryLines() string {
|
||||
return "Error: Scan with --debug to view the details"
|
||||
}
|
||||
|
||||
//TODO
|
||||
// indexFormat := ""
|
||||
// if len(currentScanResult.AllCves()) < 10 {
|
||||
// indexFormat = "[%1d]"
|
||||
// } else if len(currentScanResult.AllCves()) < 100 {
|
||||
// indexFormat = "[%2d]"
|
||||
// } else {
|
||||
// indexFormat = "[%3d]"
|
||||
// }
|
||||
indexFormat := ""
|
||||
if len(currentScanResult.ScannedCves) < 10 {
|
||||
indexFormat = "[%1d]"
|
||||
} else if len(currentScanResult.ScannedCves) < 100 {
|
||||
indexFormat = "[%2d]"
|
||||
} else {
|
||||
indexFormat = "[%3d]"
|
||||
}
|
||||
|
||||
// for i, d := range currentScanResult.AllCves() {
|
||||
// var cols []string
|
||||
// //TODO
|
||||
// var summary string
|
||||
// if cont, found := d.Get(models.NVD); found {
|
||||
// summary = cont.Summary
|
||||
// }
|
||||
// var cvssScore string
|
||||
// if d.CvssV2Score() <= 0 {
|
||||
// cvssScore = "| ?"
|
||||
// } else {
|
||||
// cvssScore = fmt.Sprintf("| %4.1f", d.CvssV2Score())
|
||||
// }
|
||||
// cols = []string{
|
||||
// fmt.Sprintf(indexFormat, i+1),
|
||||
// d.VulnInfo.CveID,
|
||||
// cvssScore,
|
||||
// fmt.Sprintf("| %3d |", d.VulnInfo.Confidence.Score),
|
||||
// summary,
|
||||
// }
|
||||
// // if config.Conf.Lang == "ja" && 0 < d.CveDetail.Jvn.CvssScore() {
|
||||
// // summary := d.CveDetail.Jvn.CveTitle()
|
||||
// // cols = []string{
|
||||
// // fmt.Sprintf(indexFormat, i+1),
|
||||
// // d.CveDetail.CveID,
|
||||
// // fmt.Sprintf("| %4.1f",
|
||||
// // d.CveDetail.CvssScore(config.Conf.Lang)),
|
||||
// // fmt.Sprintf("| %3d |", d.VulnInfo.Confidence.Score),
|
||||
// // summary,
|
||||
// // }
|
||||
// // } else {
|
||||
// // summary := d.CveDetail.Nvd.CveSummary()
|
||||
for i, vinfo := range vinfos {
|
||||
summary := vinfo.CveContents.Summaries(
|
||||
config.Conf.Lang, currentScanResult.Family)[0].Value
|
||||
cvssScore := fmt.Sprintf("| %4.1f",
|
||||
vinfo.CveContents.MaxCvssScore().Value.Score)
|
||||
|
||||
// // var cvssScore string
|
||||
// // if d.CveDetail.CvssScore("en") <= 0 {
|
||||
// // cvssScore = "| ?"
|
||||
// // } else {
|
||||
// // cvssScore = fmt.Sprintf("| %4.1f",
|
||||
// // d.CveDetail.CvssScore(config.Conf.Lang))
|
||||
// // }
|
||||
|
||||
// // cols = []string{
|
||||
// // fmt.Sprintf(indexFormat, i+1),
|
||||
// // d.CveDetail.CveID,
|
||||
// // cvssScore,
|
||||
// // fmt.Sprintf("| %3d |", d.VulnInfo.Confidence.Score),
|
||||
// // summary,
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// icols := make([]interface{}, len(cols))
|
||||
// for j := range cols {
|
||||
// icols[j] = cols[j]
|
||||
// }
|
||||
// stable.AddRow(icols...)
|
||||
// }
|
||||
var cols []string
|
||||
cols = []string{
|
||||
fmt.Sprintf(indexFormat, i+1),
|
||||
vinfo.CveID,
|
||||
cvssScore,
|
||||
fmt.Sprintf("| %3d |", vinfo.Confidence.Score),
|
||||
summary,
|
||||
}
|
||||
icols := make([]interface{}, len(cols))
|
||||
for j := range cols {
|
||||
icols[j] = cols[j]
|
||||
}
|
||||
stable.AddRow(icols...)
|
||||
}
|
||||
return fmt.Sprintf("%s", stable)
|
||||
}
|
||||
|
||||
@@ -679,7 +666,7 @@ func setDetailLayout(g *gocui.Gui) error {
|
||||
}
|
||||
_, cy := summaryView.Cursor()
|
||||
_, oy := summaryView.Origin()
|
||||
currentCveInfo = cy + oy
|
||||
currentVinfo = cy + oy
|
||||
|
||||
if v, err := g.SetView("detail", -1, int(float64(maxY)*0.2), int(float64(maxX)*0.5), maxY); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
@@ -707,27 +694,26 @@ func setChangelogLayout(g *gocui.Gui) error {
|
||||
}
|
||||
_, cy := summaryView.Cursor()
|
||||
_, oy := summaryView.Origin()
|
||||
currentCveInfo = cy + oy
|
||||
currentVinfo = cy + oy
|
||||
|
||||
if v, err := g.SetView("changelog", int(float64(maxX)*0.5), int(float64(maxY)*0.2), maxX, maxY); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
//TODO
|
||||
// if len(currentScanResult.Errors) != 0 || len(currentScanResult.AllCves()) == 0 {
|
||||
// return nil
|
||||
// }
|
||||
if len(currentScanResult.Errors) != 0 || len(currentScanResult.ScannedCves) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
lines := []string{}
|
||||
//TODO
|
||||
// cveInfo := currentScanResult.AllCves()[currentCveInfo]
|
||||
// for _, pack := range cveInfo.Packages {
|
||||
// for _, p := range currentScanResult.Packages {
|
||||
// if pack.Name == p.Name {
|
||||
// lines = append(lines, formatOneChangelog(p), "\n")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
vinfo := vinfos[currentVinfo]
|
||||
for _, name := range vinfo.PackageNames {
|
||||
pack := currentScanResult.Packages[name]
|
||||
for _, p := range currentScanResult.Packages {
|
||||
if pack.Name == p.Name {
|
||||
lines = append(lines, p.FormatChangelog(), "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
text := strings.Join(lines, "\n")
|
||||
fmt.Fprint(v, text)
|
||||
v.Editable = false
|
||||
@@ -740,14 +726,12 @@ func setChangelogLayout(g *gocui.Gui) error {
|
||||
|
||||
type dataForTmpl struct {
|
||||
CveID string
|
||||
CvssScore string
|
||||
CvssVector string
|
||||
CvssSeverity string
|
||||
Cvsses []models.CveContentCvss
|
||||
Summary string
|
||||
Confidence models.Confidence
|
||||
CweURL string
|
||||
VulnSiteLinks []string
|
||||
References []cve.Reference
|
||||
Cwes []models.CveContentStr
|
||||
Links []string
|
||||
References []models.Reference
|
||||
Packages []string
|
||||
CpeNames []string
|
||||
PublishedDate time.Time
|
||||
@@ -755,123 +739,99 @@ type dataForTmpl struct {
|
||||
}
|
||||
|
||||
func detailLines() (string, error) {
|
||||
if len(currentScanResult.Errors) != 0 {
|
||||
r := currentScanResult
|
||||
if len(r.Errors) != 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
//TODO
|
||||
// if len(currentScanResult.AllCves()) == 0 {
|
||||
// return "No vulnerable packages", nil
|
||||
// }
|
||||
// cveInfo := currentScanResult.AllCves()[currentCveInfo]
|
||||
// cveID := cveInfo.VulnInfo.CveID
|
||||
|
||||
// tmpl, err := template.New("detail").Parse(detailTemplate())
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// var cvssSeverity, cvssVector, summary string
|
||||
// var refs []cve.Reference
|
||||
switch {
|
||||
//TODO
|
||||
// case config.Conf.Lang == "ja" &&
|
||||
// 0 < cveInfo.CveDetail.Jvn.CvssScore():
|
||||
// jvn := cveInfo.CveDetail.Jvn
|
||||
// cvssSeverity = jvn.CvssSeverity()
|
||||
// cvssVector = jvn.CvssVector()
|
||||
// summary = fmt.Sprintf("%s\n%s", jvn.CveTitle(), jvn.CveSummary())
|
||||
// refs = jvn.VulnSiteReferences()
|
||||
default:
|
||||
// var nvd *models.CveContent
|
||||
//TODO
|
||||
// if cont, found := cveInfo.Get(models.NVD); found {
|
||||
// nvd = cont
|
||||
// }
|
||||
// cvssSeverity = nvd.CvssSeverity()
|
||||
// cvssVector = nvd.CvssVector()
|
||||
// summary = nvd.Summary
|
||||
// refs = nvd.VulnSiteReferences()
|
||||
if len(r.ScannedCves) == 0 {
|
||||
return "No vulnerable packages", nil
|
||||
}
|
||||
|
||||
//TODO
|
||||
// cweURL := cweURL(cveInfo.CveDetail.CweID())
|
||||
// links := []string{
|
||||
// fmt.Sprintf("[NVD]( %s )", fmt.Sprintf("%s/%s", nvdBaseURL, cveID)),
|
||||
// fmt.Sprintf("[MITRE]( %s )", fmt.Sprintf("%s%s", mitreBaseURL, cveID)),
|
||||
// fmt.Sprintf("[CveDetais]( %s )", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID)),
|
||||
// fmt.Sprintf("[CVSSv2 Calc]( %s )", fmt.Sprintf(cvssV2CalcBaseURL, cveID)),
|
||||
// fmt.Sprintf("[CVSSv3 Calc]( %s )", fmt.Sprintf(cvssV3CalcBaseURL, cveID)),
|
||||
// }
|
||||
// dlinks := distroLinks(cveInfo, currentScanResult.Family)
|
||||
// for _, link := range dlinks {
|
||||
// links = append(links, fmt.Sprintf("[%s]( %s )", link.title, link.url))
|
||||
// }
|
||||
tmpl, err := template.New("detail").Parse(mdTemplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
//TODO
|
||||
// var cvssScore string
|
||||
// if cveInfo.CvssV2Score() == -1 {
|
||||
// cvssScore = "?"
|
||||
// // } else {
|
||||
// // cvssScore = fmt.Sprintf("%4.1f", cveInfo.CveDetail.CvssScore(config.Conf.Lang))
|
||||
// }
|
||||
vinfo := vinfos[currentVinfo]
|
||||
|
||||
// packages := []string{}
|
||||
// for _, pack := range cveInfo.Packages {
|
||||
// packages = append(packages,
|
||||
// fmt.Sprintf(
|
||||
// "%s -> %s",
|
||||
// pack.FormatCurrentVer(),
|
||||
// pack.FormatNewVer()))
|
||||
// }
|
||||
packsVer := []string{}
|
||||
sort.Strings(vinfo.PackageNames)
|
||||
for _, name := range vinfo.PackageNames {
|
||||
// packages detected by OVAL may not be actually installed
|
||||
if pack, ok := r.Packages[name]; ok {
|
||||
packsVer = append(packsVer, pack.FormatVersionFromTo())
|
||||
}
|
||||
}
|
||||
sort.Strings(vinfo.CpeNames)
|
||||
for _, name := range vinfo.CpeNames {
|
||||
packsVer = append(packsVer, name)
|
||||
}
|
||||
|
||||
// data := dataForTmpl{
|
||||
// CveID: cveID,
|
||||
// CvssScore: cvssScore,
|
||||
// CvssSeverity: cvssSeverity,
|
||||
// CvssVector: cvssVector,
|
||||
// Summary: summary,
|
||||
// Confidence: cveInfo.VulnInfo.Confidence,
|
||||
// //TODO
|
||||
// // CweURL: cweURL,
|
||||
// VulnSiteLinks: links,
|
||||
// References: refs,
|
||||
// Packages: packages,
|
||||
// CpeNames: cveInfo.CpeNames,
|
||||
// }
|
||||
links := []string{vinfo.CveContents.SourceLinks(
|
||||
config.Conf.Lang, r.Family, vinfo.CveID)[0].Value,
|
||||
vinfo.Cvss2CalcURL(),
|
||||
vinfo.Cvss3CalcURL()}
|
||||
for _, url := range vinfo.VendorLinks(r.Family) {
|
||||
links = append(links, url)
|
||||
}
|
||||
// links = util.Distinct(links)
|
||||
|
||||
refs := []models.Reference{}
|
||||
for _, rr := range vinfo.CveContents.References(r.Family) {
|
||||
for _, ref := range rr.Value {
|
||||
refs = append(refs, ref)
|
||||
}
|
||||
}
|
||||
|
||||
data := dataForTmpl{
|
||||
CveID: vinfo.CveID,
|
||||
Cvsses: append(vinfo.CveContents.Cvss3Scores(), vinfo.CveContents.MaxCvss2Score()),
|
||||
Summary: vinfo.CveContents.Summaries(r.Lang, r.Family)[0].Value,
|
||||
Confidence: vinfo.Confidence,
|
||||
Cwes: vinfo.CveContents.CweIDs(r.Family),
|
||||
Links: util.Distinct(links),
|
||||
Packages: packsVer,
|
||||
References: refs,
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil) // create empty buffer
|
||||
// if err := tmpl.Execute(buf, data); err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
if err := tmpl.Execute(buf, data); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(buf.Bytes()), nil
|
||||
}
|
||||
|
||||
func detailTemplate() string {
|
||||
return `
|
||||
const mdTemplate = `
|
||||
{{.CveID}}
|
||||
==============
|
||||
|
||||
CVSS Score
|
||||
CVSS Scores
|
||||
--------------
|
||||
|
||||
{{.CvssScore}} ({{.CvssSeverity}}) {{.CvssVector}}
|
||||
{{range .Cvsses -}}
|
||||
* {{.Value.Format}} ({{.Type}})
|
||||
{{end}}
|
||||
|
||||
Summary
|
||||
--------------
|
||||
|
||||
{{.Summary }}
|
||||
|
||||
Confidence
|
||||
Links
|
||||
--------------
|
||||
|
||||
{{.Confidence }}
|
||||
{{range $link := .Links -}}
|
||||
* {{$link}}
|
||||
{{end}}
|
||||
|
||||
CWE
|
||||
--------------
|
||||
|
||||
{{.CweURL }}
|
||||
{{range .Cwes -}}
|
||||
* {{.Value}} ({{.Type}})
|
||||
{{end}}
|
||||
|
||||
Package/CPE
|
||||
--------------
|
||||
@@ -882,12 +842,13 @@ Package/CPE
|
||||
{{range $name := .CpeNames -}}
|
||||
* {{$name}}
|
||||
{{end}}
|
||||
Links
|
||||
|
||||
Confidence
|
||||
--------------
|
||||
|
||||
{{range $link := .VulnSiteLinks -}}
|
||||
* {{$link}}
|
||||
{{end}}
|
||||
{{.Confidence }}
|
||||
|
||||
|
||||
References
|
||||
--------------
|
||||
|
||||
@@ -896,4 +857,3 @@ References
|
||||
{{end}}
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
174
report/util.go
174
report/util.go
@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package report
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -238,149 +237,6 @@ func formatFullPlainText(r models.ScanResult) string {
|
||||
return fmt.Sprintf("%s\n%s", header, table)
|
||||
}
|
||||
|
||||
//TODO
|
||||
func formatPlainTextDetails(r models.ScanResult, osFamily string) (scoredReport, unscoredReport []string) {
|
||||
// for _, cve := range r.KnownCves {
|
||||
// switch config.Conf.Lang {
|
||||
// case "en":
|
||||
// if 0 < cve.CveDetail.Nvd.CvssScore() {
|
||||
// scoredReport = append(
|
||||
// scoredReport, formatPlainTextDetailsLangEn(cve, osFamily))
|
||||
// } else {
|
||||
// scoredReport = append(
|
||||
// scoredReport, formatPlainTextUnknownCve(cve, osFamily))
|
||||
// }
|
||||
// case "ja":
|
||||
// if 0 < cve.CveDetail.Jvn.CvssScore() {
|
||||
// scoredReport = append(
|
||||
// scoredReport, formatPlainTextDetailsLangJa(cve, osFamily))
|
||||
// } else if 0 < cve.CveDetail.Nvd.CvssScore() {
|
||||
// scoredReport = append(
|
||||
// scoredReport, formatPlainTextDetailsLangEn(cve, osFamily))
|
||||
// } else {
|
||||
// scoredReport = append(
|
||||
// scoredReport, formatPlainTextUnknownCve(cve, osFamily))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// for _, cve := range r.UnknownCves {
|
||||
// unscoredReport = append(
|
||||
// unscoredReport, formatPlainTextUnknownCve(cve, osFamily))
|
||||
// }
|
||||
return
|
||||
}
|
||||
|
||||
// func formatPlainTextUnknownCve(cveInfo models.CveInfo, osFamily string) string {
|
||||
// cveID := cveInfo.VulnInfo.CveID
|
||||
// dtable := uitable.New()
|
||||
// dtable.MaxColWidth = maxColWidth
|
||||
// dtable.Wrap = true
|
||||
// dtable.AddRow(cveID)
|
||||
// dtable.AddRow("-------------")
|
||||
// dtable.AddRow("Score", "?")
|
||||
// dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID))
|
||||
// dlinks := distroLinks(cveInfo, osFamily)
|
||||
// for _, link := range dlinks {
|
||||
// dtable.AddRow(link.title, link.url)
|
||||
// }
|
||||
// dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))
|
||||
// dtable = addPackageInfos(dtable, cveInfo.Packages)
|
||||
// dtable = addCpeNames(dtable, cveInfo.CpeNames)
|
||||
// dtable.AddRow("Confidence", cveInfo.VulnInfo.Confidence)
|
||||
|
||||
// return fmt.Sprintf("%s", dtable)
|
||||
// }
|
||||
|
||||
//TODO
|
||||
// func formatPlainTextDetailsLangJa(cveInfo models.CveInfo, osFamily string) string {
|
||||
// return "TODO"
|
||||
// cveDetail := cveInfo.CveDetail
|
||||
// cveID := cveDetail.CveID
|
||||
// jvn := cveDetail.Jvn
|
||||
|
||||
// dtable := uitable.New()
|
||||
// dtable.MaxColWidth = maxColWidth
|
||||
// dtable.Wrap = true
|
||||
// dtable.AddRow(cveID)
|
||||
// dtable.AddRow("-------------")
|
||||
// if score := cveDetail.Jvn.CvssScore(); 0 < score {
|
||||
// dtable.AddRow("Score",
|
||||
// fmt.Sprintf("%4.1f (%s)",
|
||||
// cveDetail.Jvn.CvssScore(),
|
||||
// jvn.CvssSeverity(),
|
||||
// ))
|
||||
// } else {
|
||||
// dtable.AddRow("Score", "?")
|
||||
// }
|
||||
// dtable.AddRow("Vector", jvn.CvssVector())
|
||||
// dtable.AddRow("Title", jvn.CveTitle())
|
||||
// dtable.AddRow("Description", jvn.CveSummary())
|
||||
// dtable.AddRow(cveDetail.CweID(), cweURL(cveDetail.CweID()))
|
||||
// dtable.AddRow(cveDetail.CweID()+"(JVN)", cweJvnURL(cveDetail.CweID()))
|
||||
|
||||
// dtable.AddRow("JVN", jvn.Link())
|
||||
// dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID))
|
||||
// dtable.AddRow("MITRE", fmt.Sprintf("%s%s", mitreBaseURL, cveID))
|
||||
// dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))
|
||||
// dtable.AddRow("CVSSv2 Clac", fmt.Sprintf(cvssV2CalcBaseURL, cveID))
|
||||
// dtable.AddRow("CVSSv3 Clac", fmt.Sprintf(cvssV3CalcBaseURL, cveID))
|
||||
|
||||
// dlinks := distroLinks(cveInfo, osFamily)
|
||||
// for _, link := range dlinks {
|
||||
// dtable.AddRow(link.title, link.url)
|
||||
// }
|
||||
|
||||
// dtable = addPackageInfos(dtable, cveInfo.Packages)
|
||||
// dtable = addCpeNames(dtable, cveInfo.CpeNames)
|
||||
// dtable.AddRow("Confidence", cveInfo.VulnInfo.Confidence)
|
||||
|
||||
// return fmt.Sprintf("%s", dtable)
|
||||
// }
|
||||
|
||||
//TODO
|
||||
// func formatPlainTextDetailsLangEn(d models.CveInfo, osFamily string) string {
|
||||
// return ""
|
||||
// cveDetail := d.CveDetail
|
||||
// cveID := cveDetail.CveID
|
||||
// nvd := cveDetail.Nvd
|
||||
|
||||
// dtable := uitable.New()
|
||||
// dtable.MaxColWidth = maxColWidth
|
||||
// dtable.Wrap = true
|
||||
// dtable.AddRow(cveID)
|
||||
// dtable.AddRow("-------------")
|
||||
|
||||
// if score := cveDetail.Nvd.CvssScore(); 0 < score {
|
||||
// dtable.AddRow("Score",
|
||||
// fmt.Sprintf("%4.1f (%s)",
|
||||
// cveDetail.Nvd.CvssScore(),
|
||||
// nvd.CvssSeverity(),
|
||||
// ))
|
||||
// } else {
|
||||
// dtable.AddRow("Score", "?")
|
||||
// }
|
||||
|
||||
// dtable.AddRow("Vector", nvd.CvssVector())
|
||||
// dtable.AddRow("Summary", nvd.CveSummary())
|
||||
// dtable.AddRow("CWE", cweURL(cveDetail.CweID()))
|
||||
|
||||
// dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID))
|
||||
// dtable.AddRow("MITRE", fmt.Sprintf("%s%s", mitreBaseURL, cveID))
|
||||
// dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))
|
||||
// dtable.AddRow("CVSSv2 Clac", fmt.Sprintf(cvssV2CalcBaseURL, cveID))
|
||||
// dtable.AddRow("CVSSv3 Clac", fmt.Sprintf(cvssV3CalcBaseURL, cveID))
|
||||
|
||||
// links := distroLinks(d, osFamily)
|
||||
// for _, link := range links {
|
||||
// dtable.AddRow(link.title, link.url)
|
||||
// }
|
||||
// dtable = addPackageInfos(dtable, d.Packages)
|
||||
// dtable = addCpeNames(dtable, d.CpeNames)
|
||||
// dtable.AddRow("Confidence", d.VulnInfo.Confidence)
|
||||
|
||||
// return fmt.Sprintf("%s\n", dtable)
|
||||
// }
|
||||
|
||||
// type distroLink struct {
|
||||
// title string
|
||||
// url string
|
||||
@@ -481,40 +337,12 @@ func formatChangelogs(r models.ScanResult) string {
|
||||
if p.NewVersion == "" {
|
||||
continue
|
||||
}
|
||||
clog := formatOneChangelog(p)
|
||||
clog := p.FormatChangelog()
|
||||
buf = append(buf, clog, "\n\n")
|
||||
}
|
||||
return strings.Join(buf, "\n")
|
||||
}
|
||||
|
||||
func formatOneChangelog(p models.Package) string {
|
||||
buf := []string{}
|
||||
if p.NewVersion == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
packVer := fmt.Sprintf("%s-%s -> %s",
|
||||
p.Name, p.FormatVer(), p.FormatNewVer())
|
||||
var delim bytes.Buffer
|
||||
for i := 0; i < len(packVer); i++ {
|
||||
delim.WriteString("-")
|
||||
}
|
||||
|
||||
clog := p.Changelog.Contents
|
||||
if lines := strings.Split(clog, "\n"); len(lines) != 0 {
|
||||
clog = strings.Join(lines[0:len(lines)-1], "\n")
|
||||
}
|
||||
|
||||
switch p.Changelog.Method {
|
||||
case models.FailedToGetChangelog:
|
||||
clog = "No changelogs"
|
||||
case models.FailedToFindVersionInChangelog:
|
||||
clog = "Failed to parse changelogs. For detials, check yourself"
|
||||
}
|
||||
buf = append(buf, packVer, delim.String(), clog)
|
||||
return strings.Join(buf, "\n")
|
||||
}
|
||||
|
||||
func needToRefreshCve(r models.ScanResult) bool {
|
||||
if r.Lang != config.Conf.Lang {
|
||||
return true
|
||||
|
||||
12
util/util.go
12
util/util.go
@@ -136,6 +136,18 @@ func Truncate(str string, length int) string {
|
||||
return str
|
||||
}
|
||||
|
||||
// Distinct a slice
|
||||
func Distinct(ss []string) (distincted []string) {
|
||||
m := map[string]bool{}
|
||||
for _, s := range ss {
|
||||
if _, found := m[s]; !found {
|
||||
m[s] = true
|
||||
distincted = append(distincted, s)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// VendorLink returns a URL of the given OS family and CVEID
|
||||
//TODO
|
||||
// func VendorLink(family, cveID string) string {
|
||||
|
||||
Reference in New Issue
Block a user