Unify the models of NVD, JVN, OVAL
This commit is contained in:
		@@ -30,6 +30,7 @@ import (
 | 
			
		||||
	"github.com/future-architect/vuls/report"
 | 
			
		||||
	"github.com/future-architect/vuls/util"
 | 
			
		||||
	"github.com/google/subcommands"
 | 
			
		||||
	"github.com/k0kubun/pp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ReportCmd is subcommand for reporting
 | 
			
		||||
@@ -421,6 +422,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
 | 
			
		||||
				util.Log.Errorf("Failed to fill OVAL information: %s", err)
 | 
			
		||||
				return subcommands.ExitFailure
 | 
			
		||||
			}
 | 
			
		||||
			pp.Println(filled)
 | 
			
		||||
 | 
			
		||||
			filled, err = fillCveInfoFromCveDB(*filled)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -246,15 +246,15 @@ func diff(current, previous models.ScanResults) (diff models.ScanResults, err er
 | 
			
		||||
	return diff, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getNewCves(previousResult, currentResult models.ScanResult) (newVulninfos []models.VulnInfo) {
 | 
			
		||||
func getNewCves(previous, current models.ScanResult) (newVulninfos []models.VulnInfo) {
 | 
			
		||||
	previousCveIDsSet := map[string]bool{}
 | 
			
		||||
	for _, previousVulnInfo := range previousResult.ScannedCves {
 | 
			
		||||
	for _, previousVulnInfo := range previous.ScannedCves {
 | 
			
		||||
		previousCveIDsSet[previousVulnInfo.CveID] = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, v := range currentResult.ScannedCves {
 | 
			
		||||
	for _, v := range current.ScannedCves {
 | 
			
		||||
		if previousCveIDsSet[v.CveID] {
 | 
			
		||||
			if isCveInfoUpdated(currentResult, previousResult, v.CveID) {
 | 
			
		||||
			if isCveInfoUpdated(current, previous, v.CveID) {
 | 
			
		||||
				newVulninfos = append(newVulninfos, v)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
@@ -264,25 +264,35 @@ func getNewCves(previousResult, currentResult models.ScanResult) (newVulninfos [
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isCveInfoUpdated(currentResult, previousResult models.ScanResult, CveID string) bool {
 | 
			
		||||
func isCveInfoUpdated(current, previous models.ScanResult, CveID string) bool {
 | 
			
		||||
	type lastModified struct {
 | 
			
		||||
		Nvd time.Time
 | 
			
		||||
		Jvn time.Time
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	previousModifies := lastModified{}
 | 
			
		||||
	for _, c := range previousResult.KnownCves {
 | 
			
		||||
	for _, c := range previous.KnownCves {
 | 
			
		||||
		if CveID == c.CveID {
 | 
			
		||||
			previousModifies.Nvd = c.CveDetail.Nvd.LastModifiedDate
 | 
			
		||||
			previousModifies.Jvn = c.CveDetail.Jvn.LastModifiedDate
 | 
			
		||||
			//TODO
 | 
			
		||||
			if nvd, found := c.Get(models.NVD); found {
 | 
			
		||||
				previousModifies.Nvd = nvd.LastModified
 | 
			
		||||
			}
 | 
			
		||||
			if jvn, found := c.Get(models.JVN); found {
 | 
			
		||||
				previousModifies.Jvn = jvn.LastModified
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	currentModifies := lastModified{}
 | 
			
		||||
	for _, c := range currentResult.KnownCves {
 | 
			
		||||
		if CveID == c.CveDetail.CveID {
 | 
			
		||||
			currentModifies.Nvd = c.CveDetail.Nvd.LastModifiedDate
 | 
			
		||||
			currentModifies.Jvn = c.CveDetail.Jvn.LastModifiedDate
 | 
			
		||||
	for _, c := range current.KnownCves {
 | 
			
		||||
		if CveID == c.VulnInfo.CveID {
 | 
			
		||||
			//TODO
 | 
			
		||||
			if nvd, found := c.Get(models.NVD); found {
 | 
			
		||||
				previousModifies.Nvd = nvd.LastModified
 | 
			
		||||
			}
 | 
			
		||||
			if jvn, found := c.Get(models.JVN); found {
 | 
			
		||||
				previousModifies.Jvn = jvn.LastModified
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return !currentModifies.Nvd.Equal(previousModifies.Nvd) ||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,6 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	"github.com/k0kubun/pp"
 | 
			
		||||
	cve "github.com/kotakanbe/go-cve-dictionary/models"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestDiff(t *testing.T) {
 | 
			
		||||
@@ -174,10 +173,11 @@ func TestDiff(t *testing.T) {
 | 
			
		||||
					},
 | 
			
		||||
					KnownCves: []models.CveInfo{
 | 
			
		||||
						{
 | 
			
		||||
							CveDetail: cve.CveDetail{
 | 
			
		||||
								CveID: "CVE-2016-6662",
 | 
			
		||||
								Nvd: cve.Nvd{
 | 
			
		||||
									LastModifiedDate: time.Date(2016, 1, 1, 0, 0, 0, 0, time.Local),
 | 
			
		||||
							CveContents: []models.CveContent{
 | 
			
		||||
								{
 | 
			
		||||
									Type:         models.NVD,
 | 
			
		||||
									CveID:        "CVE-2016-6662",
 | 
			
		||||
									LastModified: time.Date(2016, 1, 1, 0, 0, 0, 0, time.Local),
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
							VulnInfo: models.VulnInfo{
 | 
			
		||||
@@ -214,10 +214,11 @@ func TestDiff(t *testing.T) {
 | 
			
		||||
					},
 | 
			
		||||
					KnownCves: []models.CveInfo{
 | 
			
		||||
						{
 | 
			
		||||
							CveDetail: cve.CveDetail{
 | 
			
		||||
								CveID: "CVE-2016-6662",
 | 
			
		||||
								Nvd: cve.Nvd{
 | 
			
		||||
									LastModifiedDate: time.Date(2017, 3, 15, 13, 40, 57, 0, time.Local),
 | 
			
		||||
							CveContents: []models.CveContent{
 | 
			
		||||
								{
 | 
			
		||||
									Type:         models.NVD,
 | 
			
		||||
									CveID:        "CVE-2016-6662",
 | 
			
		||||
									LastModified: time.Date(2017, 3, 15, 13, 40, 57, 0, time.Local),
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
							VulnInfo: models.VulnInfo{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										267
									
								
								models/models.go
									
									
									
									
									
								
							
							
						
						
									
										267
									
								
								models/models.go
									
									
									
									
									
								
							@@ -20,12 +20,12 @@ package models
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
	"github.com/future-architect/vuls/cveapi"
 | 
			
		||||
	cve "github.com/kotakanbe/go-cve-dictionary/models"
 | 
			
		||||
	goval "github.com/kotakanbe/goval-dictionary/models"
 | 
			
		||||
	cvedict "github.com/kotakanbe/go-cve-dictionary/models"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ScanResults is slice of ScanResult.
 | 
			
		||||
@@ -73,8 +73,7 @@ type ScanResult struct {
 | 
			
		||||
	Optional [][]interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FillCveDetail fetches CVE detailed information from
 | 
			
		||||
// CVE Database, and then set to fields.
 | 
			
		||||
// FillCveDetail fetches NVD, JVN from CVE Database, and then set to fields.
 | 
			
		||||
func (r ScanResult) FillCveDetail() (*ScanResult, error) {
 | 
			
		||||
	set := map[string]VulnInfo{}
 | 
			
		||||
	var cveIDs []string
 | 
			
		||||
@@ -90,35 +89,45 @@ func (r ScanResult) FillCveDetail() (*ScanResult, error) {
 | 
			
		||||
 | 
			
		||||
	r.IgnoredCves = CveInfos{}
 | 
			
		||||
	for _, d := range ds {
 | 
			
		||||
		nvd := *r.convertNvdToModel(d.CveID, d.Nvd)
 | 
			
		||||
		jvn := *r.convertJvnToModel(d.CveID, d.Jvn)
 | 
			
		||||
		cinfo := CveInfo{
 | 
			
		||||
			CveDetail: d,
 | 
			
		||||
			VulnInfo:  set[d.CveID],
 | 
			
		||||
			CveContents: []CveContent{nvd, jvn},
 | 
			
		||||
			VulnInfo:    set[d.CveID],
 | 
			
		||||
		}
 | 
			
		||||
		cinfo.NilSliceToEmpty()
 | 
			
		||||
 | 
			
		||||
		// ignored
 | 
			
		||||
		found := false
 | 
			
		||||
		ignore := false
 | 
			
		||||
		for _, icve := range config.Conf.Servers[r.ServerName].IgnoreCves {
 | 
			
		||||
			if icve == d.CveID {
 | 
			
		||||
				r.IgnoredCves.Insert(cinfo)
 | 
			
		||||
				found = true
 | 
			
		||||
				ignore = true
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if found {
 | 
			
		||||
		if ignore {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Update known if KnownCves already have cinfo
 | 
			
		||||
		if c, ok := r.KnownCves.Get(cinfo.CveID); ok {
 | 
			
		||||
			c.CveDetail = d
 | 
			
		||||
			for _, con := range []CveContent{nvd, jvn} {
 | 
			
		||||
				if !c.Update(con) {
 | 
			
		||||
					c.Insert(con)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			r.KnownCves.Update(c)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Update unknown if UnknownCves already have cinfo
 | 
			
		||||
		if c, ok := r.UnknownCves.Get(cinfo.CveID); ok {
 | 
			
		||||
			c.CveDetail = d
 | 
			
		||||
			for _, con := range []CveContent{nvd, jvn} {
 | 
			
		||||
				if !c.Update(con) {
 | 
			
		||||
					c.Insert(con)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			r.UnknownCves.Update(c)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
@@ -138,6 +147,93 @@ func (r ScanResult) FillCveDetail() (*ScanResult, error) {
 | 
			
		||||
	return &r, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r ScanResult) convertNvdToModel(cveID string, nvd cvedict.Nvd) *CveContent {
 | 
			
		||||
	var cpes []Cpe
 | 
			
		||||
	for _, c := range nvd.Cpes {
 | 
			
		||||
		cpes = append(cpes, Cpe{CpeName: c.CpeName})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var refs []Reference
 | 
			
		||||
	for _, r := range nvd.References {
 | 
			
		||||
		refs = append(refs, Reference{
 | 
			
		||||
			Link:   r.Link,
 | 
			
		||||
			Source: r.Source,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	validVec := true
 | 
			
		||||
	for _, v := range []string{
 | 
			
		||||
		nvd.AccessVector,
 | 
			
		||||
		nvd.AccessComplexity,
 | 
			
		||||
		nvd.Authentication,
 | 
			
		||||
		nvd.ConfidentialityImpact,
 | 
			
		||||
		nvd.IntegrityImpact,
 | 
			
		||||
		nvd.AvailabilityImpact,
 | 
			
		||||
	} {
 | 
			
		||||
		if len(v) == 0 {
 | 
			
		||||
			validVec = false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vector := ""
 | 
			
		||||
	if validVec {
 | 
			
		||||
		vector = fmt.Sprintf("AV:%s/AC:%s/Au:%s/C:%s/I:%s/A:%s",
 | 
			
		||||
			string(nvd.AccessVector[0]),
 | 
			
		||||
			string(nvd.AccessComplexity[0]),
 | 
			
		||||
			string(nvd.Authentication[0]),
 | 
			
		||||
			string(nvd.ConfidentialityImpact[0]),
 | 
			
		||||
			string(nvd.IntegrityImpact[0]),
 | 
			
		||||
			string(nvd.AvailabilityImpact[0]))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//TODO CVSSv3
 | 
			
		||||
	return &CveContent{
 | 
			
		||||
		Type:         NVD,
 | 
			
		||||
		CveID:        cveID,
 | 
			
		||||
		Summary:      nvd.Summary,
 | 
			
		||||
		Cvss2Score:   nvd.Score,
 | 
			
		||||
		Cvss2Vector:  vector,
 | 
			
		||||
		Cpes:         cpes,
 | 
			
		||||
		CweID:        nvd.CweID,
 | 
			
		||||
		References:   refs,
 | 
			
		||||
		Published:    nvd.PublishedDate,
 | 
			
		||||
		LastModified: nvd.LastModifiedDate,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r ScanResult) convertJvnToModel(cveID string, jvn cvedict.Jvn) *CveContent {
 | 
			
		||||
	var cpes []Cpe
 | 
			
		||||
	for _, c := range jvn.Cpes {
 | 
			
		||||
		cpes = append(cpes, Cpe{CpeName: c.CpeName})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	refs := []Reference{{
 | 
			
		||||
		Link:   jvn.JvnLink,
 | 
			
		||||
		Source: string(JVN),
 | 
			
		||||
	}}
 | 
			
		||||
	for _, r := range jvn.References {
 | 
			
		||||
		refs = append(refs, Reference{
 | 
			
		||||
			Link:   r.Link,
 | 
			
		||||
			Source: r.Source,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vector := strings.TrimSuffix(strings.TrimPrefix(jvn.Vector, "("), ")")
 | 
			
		||||
	return &CveContent{
 | 
			
		||||
		Type:         JVN,
 | 
			
		||||
		CveID:        cveID,
 | 
			
		||||
		Title:        jvn.Title,
 | 
			
		||||
		Summary:      jvn.Summary,
 | 
			
		||||
		Severity:     jvn.Severity,
 | 
			
		||||
		Cvss2Score:   jvn.Score,
 | 
			
		||||
		Cvss2Vector:  vector,
 | 
			
		||||
		Cpes:         cpes,
 | 
			
		||||
		References:   refs,
 | 
			
		||||
		Published:    jvn.PublishedDate,
 | 
			
		||||
		LastModified: jvn.LastModifiedDate,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FilterByCvssOver is filter function.
 | 
			
		||||
func (r ScanResult) FilterByCvssOver() ScanResult {
 | 
			
		||||
	cveInfos := []CveInfo{}
 | 
			
		||||
@@ -147,7 +243,7 @@ func (r ScanResult) FilterByCvssOver() ScanResult {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, cveInfo := range r.KnownCves {
 | 
			
		||||
		if config.Conf.CvssScoreOver <= cveInfo.CveDetail.CvssScore(config.Conf.Lang) {
 | 
			
		||||
		if config.Conf.CvssScoreOver <= cveInfo.CvssV2Score() {
 | 
			
		||||
			cveInfos = append(cveInfos, cveInfo)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -217,7 +313,7 @@ func (r ScanResult) CveSummary() string {
 | 
			
		||||
	var high, medium, low, unknown int
 | 
			
		||||
	cves := append(r.KnownCves, r.UnknownCves...)
 | 
			
		||||
	for _, cveInfo := range cves {
 | 
			
		||||
		score := cveInfo.CveDetail.CvssScore(config.Conf.Lang)
 | 
			
		||||
		score := cveInfo.CvssV2Score()
 | 
			
		||||
		switch {
 | 
			
		||||
		case 7.0 <= score:
 | 
			
		||||
			high++
 | 
			
		||||
@@ -379,11 +475,10 @@ func (c CveInfos) Swap(i, j int) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c CveInfos) Less(i, j int) bool {
 | 
			
		||||
	lang := config.Conf.Lang
 | 
			
		||||
	if c[i].CveDetail.CvssScore(lang) == c[j].CveDetail.CvssScore(lang) {
 | 
			
		||||
		return c[i].CveDetail.CveID < c[j].CveDetail.CveID
 | 
			
		||||
	if c[i].CvssV2Score() == c[j].CvssV2Score() {
 | 
			
		||||
		return c[i].CveID < c[j].CveID
 | 
			
		||||
	}
 | 
			
		||||
	return c[j].CveDetail.CvssScore(lang) < c[i].CveDetail.CvssScore(lang)
 | 
			
		||||
	return c[j].CvssV2Score() < c[i].CvssV2Score()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get cveInfo by cveID
 | 
			
		||||
@@ -431,27 +526,120 @@ func (c *CveInfos) Upsert(cveInfo CveInfo) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CveInfo has Cve Information.
 | 
			
		||||
// CveInfo has CVE detailed Information.
 | 
			
		||||
type CveInfo struct {
 | 
			
		||||
	CveDetail  cve.CveDetail
 | 
			
		||||
	OvalDetail goval.Definition
 | 
			
		||||
	VulnInfo
 | 
			
		||||
	CveContents []CveContent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get a CveContent specified by arg
 | 
			
		||||
func (c *CveInfo) Get(typestr CveContentType) (*CveContent, bool) {
 | 
			
		||||
	for _, cont := range c.CveContents {
 | 
			
		||||
		if cont.Type == typestr {
 | 
			
		||||
			return &cont, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &CveContent{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Insert a CveContent to specified by arg
 | 
			
		||||
func (c *CveInfo) Insert(con CveContent) {
 | 
			
		||||
	c.CveContents = append(c.CveContents, con)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update a CveContent to specified by arg
 | 
			
		||||
func (c *CveInfo) Update(to CveContent) bool {
 | 
			
		||||
	for i, cont := range c.CveContents {
 | 
			
		||||
		if cont.Type == to.Type {
 | 
			
		||||
			c.CveContents[i] = to
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CvssV2Score returns CVSS V2 Score
 | 
			
		||||
func (c *CveInfo) CvssV2Score() float64 {
 | 
			
		||||
	//TODO
 | 
			
		||||
	if cont, found := c.Get(NVD); found {
 | 
			
		||||
		return cont.Cvss2Score
 | 
			
		||||
	} else if cont, found := c.Get(JVN); found {
 | 
			
		||||
		return cont.Cvss2Score
 | 
			
		||||
	} else if cont, found := c.Get(RedHat); found {
 | 
			
		||||
		return cont.Cvss2Score
 | 
			
		||||
	}
 | 
			
		||||
	return -1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NilSliceToEmpty set nil slice fields to empty slice to avoid null in JSON
 | 
			
		||||
func (c *CveInfo) NilSliceToEmpty() {
 | 
			
		||||
	if c.CveDetail.Nvd.Cpes == nil {
 | 
			
		||||
		c.CveDetail.Nvd.Cpes = []cve.Cpe{}
 | 
			
		||||
	}
 | 
			
		||||
	if c.CveDetail.Jvn.Cpes == nil {
 | 
			
		||||
		c.CveDetail.Jvn.Cpes = []cve.Cpe{}
 | 
			
		||||
	}
 | 
			
		||||
	if c.CveDetail.Nvd.References == nil {
 | 
			
		||||
		c.CveDetail.Nvd.References = []cve.Reference{}
 | 
			
		||||
	}
 | 
			
		||||
	if c.CveDetail.Jvn.References == nil {
 | 
			
		||||
		c.CveDetail.Jvn.References = []cve.Reference{}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
	// TODO
 | 
			
		||||
	//  if c.CveDetail.Nvd.Cpes == nil {
 | 
			
		||||
	//      c.CveDetail.Nvd.Cpes = []cve.Cpe{}
 | 
			
		||||
	//  }
 | 
			
		||||
	//  if c.CveDetail.Jvn.Cpes == nil {
 | 
			
		||||
	//      c.CveDetail.Jvn.Cpes = []cve.Cpe{}
 | 
			
		||||
	//  }
 | 
			
		||||
	//  if c.CveDetail.Nvd.References == nil {
 | 
			
		||||
	//      c.CveDetail.Nvd.References = []cve.Reference{}
 | 
			
		||||
	//  }
 | 
			
		||||
	//  if c.CveDetail.Jvn.References == nil {
 | 
			
		||||
	//      c.CveDetail.Jvn.References = []cve.Reference{}
 | 
			
		||||
	//  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CveContentType is a source of CVE information
 | 
			
		||||
type CveContentType string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// NVD is NVD
 | 
			
		||||
	NVD CveContentType = "nvd"
 | 
			
		||||
 | 
			
		||||
	// JVN is JVN
 | 
			
		||||
	JVN CveContentType = "jvn"
 | 
			
		||||
 | 
			
		||||
	// RedHat is RedHat
 | 
			
		||||
	RedHat CveContentType = "redhat"
 | 
			
		||||
 | 
			
		||||
	// CentOS is CentOS
 | 
			
		||||
	CentOS CveContentType = "centos"
 | 
			
		||||
 | 
			
		||||
	// Debian is Debian
 | 
			
		||||
	Debian CveContentType = "debian"
 | 
			
		||||
 | 
			
		||||
	// Ubuntu is Ubuntu
 | 
			
		||||
	Ubuntu CveContentType = "ubuntu"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CveContent has abstraction of various vulnerability information
 | 
			
		||||
type CveContent struct {
 | 
			
		||||
	Type         CveContentType
 | 
			
		||||
	CveID        string
 | 
			
		||||
	Title        string
 | 
			
		||||
	Summary      string
 | 
			
		||||
	Severity     string
 | 
			
		||||
	Cvss2Score   float64
 | 
			
		||||
	Cvss2Vector  string
 | 
			
		||||
	Cvss3Score   float64
 | 
			
		||||
	Cvss3Vector  string
 | 
			
		||||
	Cpes         []Cpe
 | 
			
		||||
	References   []Reference
 | 
			
		||||
	CweID        string
 | 
			
		||||
	Published    time.Time
 | 
			
		||||
	LastModified time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Cpe is Common Platform Enumeration
 | 
			
		||||
type Cpe struct {
 | 
			
		||||
	CpeName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reference has a related link of the CVE
 | 
			
		||||
type Reference struct {
 | 
			
		||||
	RefID  string
 | 
			
		||||
	Source string
 | 
			
		||||
	Link   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PackageInfoList is slice of PackageInfo
 | 
			
		||||
@@ -552,13 +740,14 @@ func (a PackageInfosByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
 | 
			
		||||
 | 
			
		||||
// PackageInfo has installed packages.
 | 
			
		||||
type PackageInfo struct {
 | 
			
		||||
	Name       string
 | 
			
		||||
	Version    string
 | 
			
		||||
	Release    string
 | 
			
		||||
	NewVersion string
 | 
			
		||||
	NewRelease string
 | 
			
		||||
	Repository string
 | 
			
		||||
	Changelog  Changelog
 | 
			
		||||
	Name        string
 | 
			
		||||
	Version     string
 | 
			
		||||
	Release     string
 | 
			
		||||
	NewVersion  string
 | 
			
		||||
	NewRelease  string
 | 
			
		||||
	Repository  string
 | 
			
		||||
	Changelog   Changelog
 | 
			
		||||
	NotFixedYet bool // Ubuntu OVAL Only
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Changelog has contents of changelog and how to get it.
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import (
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	"github.com/future-architect/vuls/util"
 | 
			
		||||
	ver "github.com/knqyf263/go-deb-version"
 | 
			
		||||
	cve "github.com/kotakanbe/go-cve-dictionary/models"
 | 
			
		||||
	ovalconf "github.com/kotakanbe/goval-dictionary/config"
 | 
			
		||||
	db "github.com/kotakanbe/goval-dictionary/db"
 | 
			
		||||
	ovalmodels "github.com/kotakanbe/goval-dictionary/models"
 | 
			
		||||
@@ -62,54 +61,78 @@ func (o Debian) FillCveInfoFromOvalDB(r *models.ScanResult) (*models.ScanResult,
 | 
			
		||||
func (o Debian) fillOvalInfo(r *models.ScanResult, definition *ovalmodels.Definition) *models.ScanResult {
 | 
			
		||||
	// Update ScannedCves by OVAL info
 | 
			
		||||
	found := false
 | 
			
		||||
	cves := []models.VulnInfo{}
 | 
			
		||||
	for _, cve := range r.ScannedCves {
 | 
			
		||||
		if cve.CveID == definition.Debian.CveID {
 | 
			
		||||
	updatedCves := []models.VulnInfo{}
 | 
			
		||||
 | 
			
		||||
	// Update scanned confidence to ovalmatch
 | 
			
		||||
	for _, scanned := range r.ScannedCves {
 | 
			
		||||
		if scanned.CveID == definition.Debian.CveID {
 | 
			
		||||
			found = true
 | 
			
		||||
			if cve.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
				cve.Confidence = models.OvalMatch
 | 
			
		||||
			if scanned.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
				scanned.Confidence = models.OvalMatch
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		cves = append(cves, cve)
 | 
			
		||||
		updatedCves = append(updatedCves, scanned)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	packageInfoList := getPackageInfoList(r, definition)
 | 
			
		||||
	vuln := models.VulnInfo{
 | 
			
		||||
		CveID:      definition.Debian.CveID,
 | 
			
		||||
		Confidence: models.OvalMatch,
 | 
			
		||||
		Packages:   packageInfoList,
 | 
			
		||||
		Packages:   getPackageInfoList(r, definition),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !found {
 | 
			
		||||
		cves = append(cves, vuln)
 | 
			
		||||
		util.Log.Debugf("%s is newly detected by OVAL", vuln.CveID)
 | 
			
		||||
		updatedCves = append(updatedCves, vuln)
 | 
			
		||||
	}
 | 
			
		||||
	r.ScannedCves = cves
 | 
			
		||||
	r.ScannedCves = updatedCves
 | 
			
		||||
 | 
			
		||||
	// Update KnownCves by OVAL info
 | 
			
		||||
	cveInfo, ok := r.KnownCves.Get(definition.Debian.CveID)
 | 
			
		||||
	ovalContent := *o.convertToModel(definition)
 | 
			
		||||
	ovalContent.Type = models.CveContentType(r.Family)
 | 
			
		||||
	cInfo, ok := r.KnownCves.Get(definition.Debian.CveID)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		cveInfo.CveDetail = cve.CveDetail{
 | 
			
		||||
			CveID: definition.Debian.CveID,
 | 
			
		||||
		}
 | 
			
		||||
		cveInfo.VulnInfo = vuln
 | 
			
		||||
		cInfo.VulnInfo = vuln
 | 
			
		||||
		cInfo.CveContents = []models.CveContent{ovalContent}
 | 
			
		||||
	}
 | 
			
		||||
	cveInfo.OvalDetail = *definition
 | 
			
		||||
	if cveInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
		cveInfo.Confidence = models.OvalMatch
 | 
			
		||||
	if !cInfo.Update(ovalContent) {
 | 
			
		||||
		cInfo.Insert(ovalContent)
 | 
			
		||||
	}
 | 
			
		||||
	r.KnownCves.Upsert(cveInfo)
 | 
			
		||||
	if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
		cInfo.Confidence = models.OvalMatch
 | 
			
		||||
	}
 | 
			
		||||
	r.KnownCves.Upsert(cInfo)
 | 
			
		||||
 | 
			
		||||
	// Update UnknownCves by OVAL info
 | 
			
		||||
	cveInfo, ok = r.UnknownCves.Get(definition.Debian.CveID)
 | 
			
		||||
	cInfo, ok = r.UnknownCves.Get(definition.Debian.CveID)
 | 
			
		||||
	if ok {
 | 
			
		||||
		cveInfo.OvalDetail = *definition
 | 
			
		||||
		if cveInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
			cveInfo.Confidence = models.OvalMatch
 | 
			
		||||
		}
 | 
			
		||||
		r.UnknownCves.Delete(definition.Debian.CveID)
 | 
			
		||||
		r.KnownCves.Upsert(cveInfo)
 | 
			
		||||
 | 
			
		||||
		// Insert new CveInfo
 | 
			
		||||
		if !cInfo.Update(ovalContent) {
 | 
			
		||||
			cInfo.Insert(ovalContent)
 | 
			
		||||
		}
 | 
			
		||||
		if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
			cInfo.Confidence = models.OvalMatch
 | 
			
		||||
		}
 | 
			
		||||
		r.KnownCves.Upsert(cInfo)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o Debian) convertToModel(def *ovalmodels.Definition) *models.CveContent {
 | 
			
		||||
	var refs []models.Reference
 | 
			
		||||
	for _, r := range def.References {
 | 
			
		||||
		refs = append(refs, models.Reference{
 | 
			
		||||
			Link:   r.RefURL,
 | 
			
		||||
			Source: r.Source,
 | 
			
		||||
			RefID:  r.RefID,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return &models.CveContent{
 | 
			
		||||
		CveID:      def.Debian.CveID,
 | 
			
		||||
		Title:      def.Title,
 | 
			
		||||
		Summary:    def.Description,
 | 
			
		||||
		References: refs,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ func getPackageInfoList(r *models.ScanResult, d *ovalmodels.Definition) models.P
 | 
			
		||||
	for _, pack := range d.AffectedPacks {
 | 
			
		||||
		for _, p := range r.Packages {
 | 
			
		||||
			if pack.Name == p.Name {
 | 
			
		||||
				p.Changelog = models.Changelog{}
 | 
			
		||||
				packageInfoList = append(packageInfoList, p)
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								oval/redhat.go
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								oval/redhat.go
									
									
									
									
									
								
							@@ -7,7 +7,6 @@ import (
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	"github.com/future-architect/vuls/util"
 | 
			
		||||
	ver "github.com/knqyf263/go-deb-version"
 | 
			
		||||
	cve "github.com/kotakanbe/go-cve-dictionary/models"
 | 
			
		||||
	ovalconf "github.com/kotakanbe/goval-dictionary/config"
 | 
			
		||||
	db "github.com/kotakanbe/goval-dictionary/db"
 | 
			
		||||
	ovalmodels "github.com/kotakanbe/goval-dictionary/models"
 | 
			
		||||
@@ -56,69 +55,108 @@ func (o Redhat) FillCveInfoFromOvalDB(r *models.ScanResult) (*models.ScanResult,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o Redhat) fillOvalInfo(r *models.ScanResult, definition *ovalmodels.Definition) *models.ScanResult {
 | 
			
		||||
	found := make(map[string]bool)
 | 
			
		||||
	vulnInfos := make(map[string]models.VulnInfo)
 | 
			
		||||
	packageInfoList := getPackageInfoList(r, definition)
 | 
			
		||||
	cveIDSet := make(map[string]bool)
 | 
			
		||||
	cveID2VulnInfo := make(map[string]models.VulnInfo)
 | 
			
		||||
	for _, cve := range definition.Advisory.Cves {
 | 
			
		||||
		found[cve.CveID] = false
 | 
			
		||||
		vulnInfos[cve.CveID] = models.VulnInfo{
 | 
			
		||||
		cveIDSet[cve.CveID] = false
 | 
			
		||||
		cveID2VulnInfo[cve.CveID] = models.VulnInfo{
 | 
			
		||||
			CveID:      cve.CveID,
 | 
			
		||||
			Confidence: models.OvalMatch,
 | 
			
		||||
			Packages:   packageInfoList,
 | 
			
		||||
			Packages:   getPackageInfoList(r, definition),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Update ScannedCves by OVAL info
 | 
			
		||||
	cves := []models.VulnInfo{}
 | 
			
		||||
	for _, scannedCve := range r.ScannedCves {
 | 
			
		||||
	updatedCves := []models.VulnInfo{}
 | 
			
		||||
	for _, scanned := range r.ScannedCves {
 | 
			
		||||
		// Update scanned confidence to ovalmatch
 | 
			
		||||
		for _, c := range definition.Advisory.Cves {
 | 
			
		||||
			if scannedCve.CveID == c.CveID {
 | 
			
		||||
				found[c.CveID] = true
 | 
			
		||||
				if scannedCve.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
					scannedCve.Confidence = models.OvalMatch
 | 
			
		||||
			if scanned.CveID == c.CveID {
 | 
			
		||||
				cveIDSet[c.CveID] = true
 | 
			
		||||
				if scanned.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
					scanned.Confidence = models.OvalMatch
 | 
			
		||||
				}
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		cves = append(cves, scannedCve)
 | 
			
		||||
		updatedCves = append(updatedCves, scanned)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for cveID, found := range found {
 | 
			
		||||
	for cveID, found := range cveIDSet {
 | 
			
		||||
		if !found {
 | 
			
		||||
			cves = append(cves, vulnInfos[cveID])
 | 
			
		||||
			util.Log.Debugf("%s is newly detected by OVAL", cveID)
 | 
			
		||||
			updatedCves = append(updatedCves, cveID2VulnInfo[cveID])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	r.ScannedCves = cves
 | 
			
		||||
	r.ScannedCves = updatedCves
 | 
			
		||||
 | 
			
		||||
	// Update KnownCves by OVAL info
 | 
			
		||||
	for _, c := range definition.Advisory.Cves {
 | 
			
		||||
		cveInfo, ok := r.KnownCves.Get(c.CveID)
 | 
			
		||||
		ovalContent := *o.convertToModel(c.CveID, definition)
 | 
			
		||||
		cInfo, ok := r.KnownCves.Get(c.CveID)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			cveInfo.CveDetail = cve.CveDetail{
 | 
			
		||||
				CveID: c.CveID,
 | 
			
		||||
			}
 | 
			
		||||
			cveInfo.VulnInfo = vulnInfos[c.CveID]
 | 
			
		||||
			cInfo.VulnInfo = cveID2VulnInfo[c.CveID]
 | 
			
		||||
			cInfo.CveContents = []models.CveContent{ovalContent}
 | 
			
		||||
		}
 | 
			
		||||
		cveInfo.OvalDetail = *definition
 | 
			
		||||
		if cveInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
			cveInfo.Confidence = models.OvalMatch
 | 
			
		||||
		if !cInfo.Update(ovalContent) {
 | 
			
		||||
			cInfo.Insert(ovalContent)
 | 
			
		||||
		}
 | 
			
		||||
		r.KnownCves.Upsert(cveInfo)
 | 
			
		||||
		if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
			cInfo.Confidence = models.OvalMatch
 | 
			
		||||
		}
 | 
			
		||||
		r.KnownCves.Upsert(cInfo)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Update UnknownCves by OVAL info
 | 
			
		||||
	for _, c := range definition.Advisory.Cves {
 | 
			
		||||
		cveInfo, ok := r.UnknownCves.Get(c.CveID)
 | 
			
		||||
		cInfo, ok := r.UnknownCves.Get(c.CveID)
 | 
			
		||||
		if ok {
 | 
			
		||||
			cveInfo.OvalDetail = *definition
 | 
			
		||||
			if cveInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
				cveInfo.Confidence = models.OvalMatch
 | 
			
		||||
			}
 | 
			
		||||
			r.UnknownCves.Delete(c.CveID)
 | 
			
		||||
			r.KnownCves.Upsert(cveInfo)
 | 
			
		||||
 | 
			
		||||
			// Insert new CveInfo
 | 
			
		||||
			ovalContent := *o.convertToModel(c.CveID, definition)
 | 
			
		||||
			if !cInfo.Update(ovalContent) {
 | 
			
		||||
				cInfo.Insert(ovalContent)
 | 
			
		||||
			}
 | 
			
		||||
			if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
 | 
			
		||||
				cInfo.Confidence = models.OvalMatch
 | 
			
		||||
			}
 | 
			
		||||
			r.KnownCves.Upsert(cInfo)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o Redhat) convertToModel(cveID string, def *ovalmodels.Definition) *models.CveContent {
 | 
			
		||||
	for _, cve := range def.Advisory.Cves {
 | 
			
		||||
		if cve.CveID != cveID {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		var refs []models.Reference
 | 
			
		||||
		//TODO RHSAのリンクを入れる
 | 
			
		||||
		for _, r := range def.References {
 | 
			
		||||
			refs = append(refs, models.Reference{
 | 
			
		||||
				Link:   r.RefURL,
 | 
			
		||||
				Source: r.Source,
 | 
			
		||||
				RefID:  r.RefID,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//  util.ParseCvss2()
 | 
			
		||||
 | 
			
		||||
		return &models.CveContent{
 | 
			
		||||
			Type:     models.RedHat,
 | 
			
		||||
			CveID:    cve.CveID,
 | 
			
		||||
			Title:    def.Title,
 | 
			
		||||
			Summary:  def.Description,
 | 
			
		||||
			Severity: def.Advisory.Severity,
 | 
			
		||||
			//  V2Score:    v2Score,   // TODO divide into score and vector
 | 
			
		||||
			Cvss2Vector: cve.Cvss2, // TODO divide into score and vector
 | 
			
		||||
			Cvss3Vector: cve.Cvss3, // TODO divide into score and vector
 | 
			
		||||
			References:  refs,
 | 
			
		||||
			CweID:       cve.Cwe,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -166,7 +166,7 @@ func toSlackAttachments(scanResult models.ScanResult) (attaches []*attachment) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, cveInfo := range cves {
 | 
			
		||||
		cveID := cveInfo.CveDetail.CveID
 | 
			
		||||
		cveID := cveInfo.VulnInfo.CveID
 | 
			
		||||
 | 
			
		||||
		curentPackages := []string{}
 | 
			
		||||
		for _, p := range cveInfo.Packages {
 | 
			
		||||
@@ -199,7 +199,7 @@ func toSlackAttachments(scanResult models.ScanResult) (attaches []*attachment) {
 | 
			
		||||
					Short: true,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			Color: color(cveInfo.CveDetail.CvssScore(config.Conf.Lang)),
 | 
			
		||||
			Color: color(cveInfo.CvssV2Score()),
 | 
			
		||||
		}
 | 
			
		||||
		attaches = append(attaches, &a)
 | 
			
		||||
	}
 | 
			
		||||
@@ -221,57 +221,61 @@ func color(cvssScore float64) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func attachmentText(cveInfo models.CveInfo, osFamily string) string {
 | 
			
		||||
	linkText := links(cveInfo, osFamily)
 | 
			
		||||
	switch {
 | 
			
		||||
	case config.Conf.Lang == "ja" &&
 | 
			
		||||
		0 < cveInfo.CveDetail.Jvn.CvssScore():
 | 
			
		||||
	//  linkText := links(cveInfo, osFamily)
 | 
			
		||||
	//TODO
 | 
			
		||||
	return ""
 | 
			
		||||
	//  switch {
 | 
			
		||||
	//  case config.Conf.Lang == "ja" &&
 | 
			
		||||
	//      0 < cveInfo.CveDetail.Jvn.CvssScore():
 | 
			
		||||
 | 
			
		||||
		jvn := cveInfo.CveDetail.Jvn
 | 
			
		||||
		return fmt.Sprintf("*%4.1f (%s)* <%s|%s>\n%s\n%s\n*Confidence:* %v",
 | 
			
		||||
			cveInfo.CveDetail.CvssScore(config.Conf.Lang),
 | 
			
		||||
			jvn.CvssSeverity(),
 | 
			
		||||
			fmt.Sprintf(cvssV2CalcBaseURL, cveInfo.CveDetail.CveID),
 | 
			
		||||
			jvn.CvssVector(),
 | 
			
		||||
			jvn.CveTitle(),
 | 
			
		||||
			linkText,
 | 
			
		||||
			cveInfo.VulnInfo.Confidence,
 | 
			
		||||
		)
 | 
			
		||||
	case 0 < cveInfo.CveDetail.CvssScore("en"):
 | 
			
		||||
		nvd := cveInfo.CveDetail.Nvd
 | 
			
		||||
		return fmt.Sprintf("*%4.1f (%s)* <%s|%s>\n%s\n%s\n*Confidence:* %v",
 | 
			
		||||
			cveInfo.CveDetail.CvssScore(config.Conf.Lang),
 | 
			
		||||
			nvd.CvssSeverity(),
 | 
			
		||||
			fmt.Sprintf(cvssV2CalcBaseURL, cveInfo.CveDetail.CveID),
 | 
			
		||||
			nvd.CvssVector(),
 | 
			
		||||
			nvd.CveSummary(),
 | 
			
		||||
			linkText,
 | 
			
		||||
			cveInfo.VulnInfo.Confidence,
 | 
			
		||||
		)
 | 
			
		||||
	default:
 | 
			
		||||
		nvd := cveInfo.CveDetail.Nvd
 | 
			
		||||
		return fmt.Sprintf("?\n%s\n%s\n*Confidence:* %v",
 | 
			
		||||
			nvd.CveSummary(), linkText, cveInfo.VulnInfo.Confidence)
 | 
			
		||||
	}
 | 
			
		||||
	//      jvn := cveInfo.CveDetail.Jvn
 | 
			
		||||
	//      return fmt.Sprintf("*%4.1f (%s)* <%s|%s>\n%s\n%s\n*Confidence:* %v",
 | 
			
		||||
	//          cveInfo.CveDetail.CvssScore(config.Conf.Lang),
 | 
			
		||||
	//          jvn.CvssSeverity(),
 | 
			
		||||
	//          fmt.Sprintf(cvssV2CalcBaseURL, cveInfo.CveDetail.CveID),
 | 
			
		||||
	//          jvn.CvssVector(),
 | 
			
		||||
	//          jvn.CveTitle(),
 | 
			
		||||
	//          linkText,
 | 
			
		||||
	//          cveInfo.VulnInfo.Confidence,
 | 
			
		||||
	//      )
 | 
			
		||||
	//  case 0 < cveInfo.CveDetail.CvssScore("en"):
 | 
			
		||||
	//      nvd := cveInfo.CveDetail.Nvd
 | 
			
		||||
	//      return fmt.Sprintf("*%4.1f (%s)* <%s|%s>\n%s\n%s\n*Confidence:* %v",
 | 
			
		||||
	//          cveInfo.CveDetail.CvssScore(config.Conf.Lang),
 | 
			
		||||
	//          nvd.CvssSeverity(),
 | 
			
		||||
	//          fmt.Sprintf(cvssV2CalcBaseURL, cveInfo.CveDetail.CveID),
 | 
			
		||||
	//          nvd.CvssVector(),
 | 
			
		||||
	//          nvd.CveSummary(),
 | 
			
		||||
	//          linkText,
 | 
			
		||||
	//          cveInfo.VulnInfo.Confidence,
 | 
			
		||||
	//      )
 | 
			
		||||
	//  default:
 | 
			
		||||
	//      nvd := cveInfo.CveDetail.Nvd
 | 
			
		||||
	//      return fmt.Sprintf("?\n%s\n%s\n*Confidence:* %v",
 | 
			
		||||
	//          nvd.CveSummary(), linkText, cveInfo.VulnInfo.Confidence)
 | 
			
		||||
	//  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func links(cveInfo models.CveInfo, osFamily string) string {
 | 
			
		||||
	links := []string{}
 | 
			
		||||
 | 
			
		||||
	cweID := cveInfo.CveDetail.CweID()
 | 
			
		||||
	if 0 < len(cweID) {
 | 
			
		||||
		links = append(links, fmt.Sprintf("<%s|%s>",
 | 
			
		||||
			cweURL(cweID), cweID))
 | 
			
		||||
		if config.Conf.Lang == "ja" {
 | 
			
		||||
			links = append(links, fmt.Sprintf("<%s|%s(JVN)>",
 | 
			
		||||
				cweJvnURL(cweID), cweID))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	//TODO
 | 
			
		||||
	//  cweID := cveInfo.CveDetail.CweID()
 | 
			
		||||
	//  if 0 < len(cweID) {
 | 
			
		||||
	//      links = append(links, fmt.Sprintf("<%s|%s>",
 | 
			
		||||
	//          cweURL(cweID), cweID))
 | 
			
		||||
	//      if config.Conf.Lang == "ja" {
 | 
			
		||||
	//          links = append(links, fmt.Sprintf("<%s|%s(JVN)>",
 | 
			
		||||
	//              cweJvnURL(cweID), cweID))
 | 
			
		||||
	//      }
 | 
			
		||||
	//  }
 | 
			
		||||
 | 
			
		||||
	cveID := cveInfo.CveDetail.CveID
 | 
			
		||||
	if config.Conf.Lang == "ja" && 0 < len(cveInfo.CveDetail.Jvn.Link()) {
 | 
			
		||||
		jvn := fmt.Sprintf("<%s|JVN>", cveInfo.CveDetail.Jvn.Link())
 | 
			
		||||
		links = append(links, jvn)
 | 
			
		||||
	}
 | 
			
		||||
	cveID := cveInfo.VulnInfo.CveID
 | 
			
		||||
	//TODO
 | 
			
		||||
	//  if config.Conf.Lang == "ja" && 0 < len(cveInfo.CveDetail.Jvn.Link()) {
 | 
			
		||||
	//      jvn := fmt.Sprintf("<%s|JVN>", cveInfo.CveDetail.Jvn.Link())
 | 
			
		||||
	//      links = append(links, jvn)
 | 
			
		||||
	//  }
 | 
			
		||||
	dlinks := distroLinks(cveInfo, osFamily)
 | 
			
		||||
	for _, link := range dlinks {
 | 
			
		||||
		links = append(links,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										134
									
								
								report/tui.go
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								report/tui.go
									
									
									
									
									
								
							@@ -26,7 +26,6 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	log "github.com/Sirupsen/logrus"
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	"github.com/google/subcommands"
 | 
			
		||||
	"github.com/gosuri/uitable"
 | 
			
		||||
@@ -613,39 +612,53 @@ func summaryLines() string {
 | 
			
		||||
 | 
			
		||||
	for i, d := range currentScanResult.AllCves() {
 | 
			
		||||
		var cols []string
 | 
			
		||||
		//  packs := []string{}
 | 
			
		||||
		//  for _, pack := range d.Packages {
 | 
			
		||||
		//      packs = append(packs, pack.Name)
 | 
			
		||||
		//  }
 | 
			
		||||
		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()
 | 
			
		||||
 | 
			
		||||
			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,
 | 
			
		||||
			}
 | 
			
		||||
		//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()
 | 
			
		||||
 | 
			
		||||
		//      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 {
 | 
			
		||||
@@ -748,7 +761,7 @@ func detailLines() (string, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cveInfo := currentScanResult.AllCves()[currentCveInfo]
 | 
			
		||||
	cveID := cveInfo.CveDetail.CveID
 | 
			
		||||
	cveID := cveInfo.VulnInfo.CveID
 | 
			
		||||
 | 
			
		||||
	tmpl, err := template.New("detail").Parse(detailTemplate())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -758,22 +771,27 @@ func detailLines() (string, error) {
 | 
			
		||||
	var cvssSeverity, cvssVector, summary string
 | 
			
		||||
	var refs []cve.Reference
 | 
			
		||||
	switch {
 | 
			
		||||
	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()
 | 
			
		||||
	//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:
 | 
			
		||||
		nvd := cveInfo.CveDetail.Nvd
 | 
			
		||||
		cvssSeverity = nvd.CvssSeverity()
 | 
			
		||||
		cvssVector = nvd.CvssVector()
 | 
			
		||||
		summary = nvd.CveSummary()
 | 
			
		||||
		refs = nvd.VulnSiteReferences()
 | 
			
		||||
		var nvd *models.CveContent
 | 
			
		||||
		if cont, found := cveInfo.Get(models.NVD); found {
 | 
			
		||||
			nvd = cont
 | 
			
		||||
		}
 | 
			
		||||
		//  cvssSeverity = nvd.CvssSeverity()
 | 
			
		||||
		//  cvssVector = nvd.CvssVector()
 | 
			
		||||
		summary = nvd.Summary
 | 
			
		||||
		//  refs = nvd.VulnSiteReferences()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cweURL := cweURL(cveInfo.CveDetail.CweID())
 | 
			
		||||
	//TODO
 | 
			
		||||
	//  cweURL := cweURL(cveInfo.CveDetail.CweID())
 | 
			
		||||
 | 
			
		||||
	links := []string{
 | 
			
		||||
		fmt.Sprintf("[NVD]( %s )", fmt.Sprintf("%s/%s", nvdBaseURL, cveID)),
 | 
			
		||||
@@ -787,11 +805,12 @@ func detailLines() (string, error) {
 | 
			
		||||
		links = append(links, fmt.Sprintf("[%s]( %s )", link.title, link.url))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//TODO
 | 
			
		||||
	var cvssScore string
 | 
			
		||||
	if cveInfo.CveDetail.CvssScore(config.Conf.Lang) == -1 {
 | 
			
		||||
	if cveInfo.CvssV2Score() == -1 {
 | 
			
		||||
		cvssScore = "?"
 | 
			
		||||
	} else {
 | 
			
		||||
		cvssScore = fmt.Sprintf("%4.1f", cveInfo.CveDetail.CvssScore(config.Conf.Lang))
 | 
			
		||||
		//  } else {
 | 
			
		||||
		//      cvssScore = fmt.Sprintf("%4.1f", cveInfo.CveDetail.CvssScore(config.Conf.Lang))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	packages := []string{}
 | 
			
		||||
@@ -804,13 +823,14 @@ func detailLines() (string, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data := dataForTmpl{
 | 
			
		||||
		CveID:         cveID,
 | 
			
		||||
		CvssScore:     cvssScore,
 | 
			
		||||
		CvssSeverity:  cvssSeverity,
 | 
			
		||||
		CvssVector:    cvssVector,
 | 
			
		||||
		Summary:       summary,
 | 
			
		||||
		Confidence:    cveInfo.VulnInfo.Confidence,
 | 
			
		||||
		CweURL:        cweURL,
 | 
			
		||||
		CveID:        cveID,
 | 
			
		||||
		CvssScore:    cvssScore,
 | 
			
		||||
		CvssSeverity: cvssSeverity,
 | 
			
		||||
		CvssVector:   cvssVector,
 | 
			
		||||
		Summary:      summary,
 | 
			
		||||
		Confidence:   cveInfo.VulnInfo.Confidence,
 | 
			
		||||
		//TODO
 | 
			
		||||
		//  CweURL:        cweURL,
 | 
			
		||||
		VulnSiteLinks: links,
 | 
			
		||||
		References:    refs,
 | 
			
		||||
		Packages:      packages,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										254
									
								
								report/util.go
									
									
									
									
									
								
							
							
						
						
									
										254
									
								
								report/util.go
									
									
									
									
									
								
							@@ -126,38 +126,43 @@ No CVE-IDs are found in updatable packages.
 | 
			
		||||
 | 
			
		||||
		var scols []string
 | 
			
		||||
		switch {
 | 
			
		||||
		case config.Conf.Lang == "ja" &&
 | 
			
		||||
			0 < d.CveDetail.Jvn.CvssScore():
 | 
			
		||||
			summary := fmt.Sprintf("%s\n%s\n%s\n%sConfidence: %v",
 | 
			
		||||
				d.CveDetail.Jvn.CveTitle(),
 | 
			
		||||
				d.CveDetail.Jvn.Link(),
 | 
			
		||||
				distroLinks(d, r.Family)[0].url,
 | 
			
		||||
				packsVer,
 | 
			
		||||
				d.VulnInfo.Confidence,
 | 
			
		||||
			)
 | 
			
		||||
			scols = []string{
 | 
			
		||||
				d.CveDetail.CveID,
 | 
			
		||||
				fmt.Sprintf("%-4.1f (%s)",
 | 
			
		||||
					d.CveDetail.CvssScore(config.Conf.Lang),
 | 
			
		||||
					d.CveDetail.Jvn.CvssSeverity(),
 | 
			
		||||
				),
 | 
			
		||||
				summary,
 | 
			
		||||
			}
 | 
			
		||||
		//  case config.Conf.Lang == "ja" &&
 | 
			
		||||
		//TODO
 | 
			
		||||
		//  0 < d.CveDetail.Jvn.CvssScore():
 | 
			
		||||
		//  summary := fmt.Sprintf("%s\n%s\n%s\n%sConfidence: %v",
 | 
			
		||||
		//      d.CveDetail.Jvn.CveTitle(),
 | 
			
		||||
		//      d.CveDetail.Jvn.Link(),
 | 
			
		||||
		//      distroLinks(d, r.Family)[0].url,
 | 
			
		||||
		//      packsVer,
 | 
			
		||||
		//      d.VulnInfo.Confidence,
 | 
			
		||||
		//  )
 | 
			
		||||
		//  scols = []string{
 | 
			
		||||
		//      d.CveDetail.CveID,
 | 
			
		||||
		//      fmt.Sprintf("%-4.1f (%s)",
 | 
			
		||||
		//          d.CveDetail.CvssScore(config.Conf.Lang),
 | 
			
		||||
		//          d.CveDetail.Jvn.CvssSeverity(),
 | 
			
		||||
		//      ),
 | 
			
		||||
		//      summary,
 | 
			
		||||
		//  }
 | 
			
		||||
 | 
			
		||||
		case 0 < d.CveDetail.CvssScore("en"):
 | 
			
		||||
		case 0 < d.CvssV2Score():
 | 
			
		||||
			var nvd *models.CveContent
 | 
			
		||||
			if cont, found := d.Get(models.NVD); found {
 | 
			
		||||
				nvd = cont
 | 
			
		||||
			}
 | 
			
		||||
			summary := fmt.Sprintf("%s\n%s/%s\n%s\n%sConfidence: %v",
 | 
			
		||||
				d.CveDetail.Nvd.CveSummary(),
 | 
			
		||||
				nvd.Summary,
 | 
			
		||||
				cveDetailsBaseURL,
 | 
			
		||||
				d.CveDetail.CveID,
 | 
			
		||||
				d.VulnInfo.CveID,
 | 
			
		||||
				distroLinks(d, r.Family)[0].url,
 | 
			
		||||
				packsVer,
 | 
			
		||||
				d.VulnInfo.Confidence,
 | 
			
		||||
			)
 | 
			
		||||
			scols = []string{
 | 
			
		||||
				d.CveDetail.CveID,
 | 
			
		||||
				d.VulnInfo.CveID,
 | 
			
		||||
				fmt.Sprintf("%-4.1f (%s)",
 | 
			
		||||
					d.CveDetail.CvssScore(config.Conf.Lang),
 | 
			
		||||
					d.CveDetail.Nvd.CvssSeverity(),
 | 
			
		||||
					d.CvssV2Score(),
 | 
			
		||||
					"TODO",
 | 
			
		||||
				),
 | 
			
		||||
				summary,
 | 
			
		||||
			}
 | 
			
		||||
@@ -165,7 +170,7 @@ No CVE-IDs are found in updatable packages.
 | 
			
		||||
			summary := fmt.Sprintf("%s\n%sConfidence: %v",
 | 
			
		||||
				distroLinks(d, r.Family)[0].url, packsVer, d.VulnInfo.Confidence)
 | 
			
		||||
			scols = []string{
 | 
			
		||||
				d.CveDetail.CveID,
 | 
			
		||||
				d.VulnInfo.CveID,
 | 
			
		||||
				"?",
 | 
			
		||||
				summary,
 | 
			
		||||
			}
 | 
			
		||||
@@ -229,39 +234,40 @@ No CVE-IDs are found in updatable packages.
 | 
			
		||||
	return fmt.Sprintf("%s\n%s\n%s", header, detail, formatChangelogs(r))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//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))
 | 
			
		||||
	}
 | 
			
		||||
	//  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.CveDetail.CveID
 | 
			
		||||
	cveID := cveInfo.VulnInfo.CveID
 | 
			
		||||
	dtable := uitable.New()
 | 
			
		||||
	dtable.MaxColWidth = maxColWidth
 | 
			
		||||
	dtable.Wrap = true
 | 
			
		||||
@@ -281,90 +287,94 @@ func formatPlainTextUnknownCve(cveInfo models.CveInfo, osFamily string) string {
 | 
			
		||||
	return fmt.Sprintf("%s", dtable)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//TODO
 | 
			
		||||
func formatPlainTextDetailsLangJa(cveInfo models.CveInfo, osFamily string) string {
 | 
			
		||||
	cveDetail := cveInfo.CveDetail
 | 
			
		||||
	cveID := cveDetail.CveID
 | 
			
		||||
	jvn := cveDetail.Jvn
 | 
			
		||||
	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 := 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))
 | 
			
		||||
	//  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)
 | 
			
		||||
	}
 | 
			
		||||
	//  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)
 | 
			
		||||
	//  dtable = addPackageInfos(dtable, cveInfo.Packages)
 | 
			
		||||
	//  dtable = addCpeNames(dtable, cveInfo.CpeNames)
 | 
			
		||||
	//  dtable.AddRow("Confidence", cveInfo.VulnInfo.Confidence)
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("%s", dtable)
 | 
			
		||||
	//  return fmt.Sprintf("%s", dtable)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//TODO
 | 
			
		||||
func formatPlainTextDetailsLangEn(d models.CveInfo, osFamily string) string {
 | 
			
		||||
	cveDetail := d.CveDetail
 | 
			
		||||
	cveID := cveDetail.CveID
 | 
			
		||||
	nvd := cveDetail.Nvd
 | 
			
		||||
	return ""
 | 
			
		||||
	//  cveDetail := d.CveDetail
 | 
			
		||||
	//  cveID := cveDetail.CveID
 | 
			
		||||
	//  nvd := cveDetail.Nvd
 | 
			
		||||
 | 
			
		||||
	dtable := uitable.New()
 | 
			
		||||
	dtable.MaxColWidth = maxColWidth
 | 
			
		||||
	dtable.Wrap = true
 | 
			
		||||
	dtable.AddRow(cveID)
 | 
			
		||||
	dtable.AddRow("-------------")
 | 
			
		||||
	//  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", "?")
 | 
			
		||||
	}
 | 
			
		||||
	//  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("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))
 | 
			
		||||
	//  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)
 | 
			
		||||
	//  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)
 | 
			
		||||
	//  return fmt.Sprintf("%s\n", dtable)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type distroLink struct {
 | 
			
		||||
@@ -374,7 +384,7 @@ type distroLink struct {
 | 
			
		||||
 | 
			
		||||
// distroLinks add Vendor URL of the CVE to table
 | 
			
		||||
func distroLinks(cveInfo models.CveInfo, osFamily string) []distroLink {
 | 
			
		||||
	cveID := cveInfo.CveDetail.CveID
 | 
			
		||||
	cveID := cveInfo.VulnInfo.CveID
 | 
			
		||||
	switch osFamily {
 | 
			
		||||
	case "rhel", "centos":
 | 
			
		||||
		links := []distroLink{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								util/util.go
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								util/util.go
									
									
									
									
									
								
							@@ -20,6 +20,7 @@ package util
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
@@ -135,3 +136,31 @@ func Truncate(str string, length int) string {
 | 
			
		||||
	}
 | 
			
		||||
	return str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCvss2 divide CVSSv2 string into score and vector
 | 
			
		||||
// 5/AV:N/AC:L/Au:N/C:N/I:N/A:P
 | 
			
		||||
func ParseCvss2(scoreVector string) (score float64, vector string) {
 | 
			
		||||
	var err error
 | 
			
		||||
	ss := strings.Split(scoreVector, "/")
 | 
			
		||||
	if 1 < len(ss) {
 | 
			
		||||
		if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
 | 
			
		||||
			return 0, ""
 | 
			
		||||
		}
 | 
			
		||||
		return score, strings.Join(ss[1:len(ss)], "/")
 | 
			
		||||
	}
 | 
			
		||||
	return 0, ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCvss3 divide CVSSv3 string into score and vector
 | 
			
		||||
// 5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
 | 
			
		||||
func ParseCvss3(scoreVector string) (score float64, vector string) {
 | 
			
		||||
	var err error
 | 
			
		||||
	ss := strings.Split(scoreVector, "/CVSS:3.0/")
 | 
			
		||||
	if 1 < len(ss) {
 | 
			
		||||
		if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
 | 
			
		||||
			return 0, ""
 | 
			
		||||
		}
 | 
			
		||||
		return score, strings.Join(ss[1:len(ss)], "/")
 | 
			
		||||
	}
 | 
			
		||||
	return 0, ""
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -171,3 +171,69 @@ func TestTruncate(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseCvss2(t *testing.T) {
 | 
			
		||||
	type out struct {
 | 
			
		||||
		score  float64
 | 
			
		||||
		vector string
 | 
			
		||||
	}
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  string
 | 
			
		||||
		out out
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: "5/AV:N/AC:L/Au:N/C:N/I:N/A:P",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  5.0,
 | 
			
		||||
				vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  0,
 | 
			
		||||
				vector: "",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		s, v := ParseCvss2(tt.in)
 | 
			
		||||
		if s != tt.out.score || v != tt.out.vector {
 | 
			
		||||
			t.Errorf("\nexpected: %f, %s\n  actual: %f, %s",
 | 
			
		||||
				tt.out.score, tt.out.vector, s, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseCvss3(t *testing.T) {
 | 
			
		||||
	type out struct {
 | 
			
		||||
		score  float64
 | 
			
		||||
		vector string
 | 
			
		||||
	}
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  string
 | 
			
		||||
		out out
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: "5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  5.6,
 | 
			
		||||
				vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  0,
 | 
			
		||||
				vector: "",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		s, v := ParseCvss3(tt.in)
 | 
			
		||||
		if s != tt.out.score || v != tt.out.vector {
 | 
			
		||||
			t.Errorf("\nexpected: %f, %s\n  actual: %f, %s",
 | 
			
		||||
				tt.out.score, tt.out.vector, s, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user