github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/cpe/by_specificity.go (about) 1 package cpe 2 3 import ( 4 "sort" 5 6 "github.com/facebookincubator/nvdtools/wfn" 7 ) 8 9 var _ sort.Interface = (*BySpecificity)(nil) 10 11 type BySpecificity []wfn.Attributes 12 13 func (c BySpecificity) Len() int { return len(c) } 14 15 func (c BySpecificity) Swap(i, j int) { c[i], c[j] = c[j], c[i] } 16 17 func (c BySpecificity) Less(i, j int) bool { 18 iScore := weightedCountForSpecifiedFields(c[i]) 19 jScore := weightedCountForSpecifiedFields(c[j]) 20 21 // check weighted sort first 22 if iScore != jScore { 23 return iScore > jScore 24 } 25 26 // sort longer fields to top 27 if countFieldLength(c[i]) != countFieldLength(c[j]) { 28 return countFieldLength(c[i]) > countFieldLength(c[j]) 29 } 30 31 // if score and length are equal then text sort 32 // note that we are not using String from the gosbom pkg 33 // as we are not encoding/decoding this CPE string so we don't 34 // need the proper quoted version of the CPE. 35 return c[i].BindToFmtString() < c[j].BindToFmtString() 36 } 37 38 func countFieldLength(cpe wfn.Attributes) int { 39 return len(cpe.Part + cpe.Vendor + cpe.Product + cpe.Version + cpe.TargetSW) 40 } 41 42 func weightedCountForSpecifiedFields(cpe wfn.Attributes) int { 43 checksForSpecifiedField := []func(cpe wfn.Attributes) (bool, int){ 44 func(cpe wfn.Attributes) (bool, int) { return cpe.Part != "", 2 }, 45 func(cpe wfn.Attributes) (bool, int) { return cpe.Vendor != "", 3 }, 46 func(cpe wfn.Attributes) (bool, int) { return cpe.Product != "", 4 }, 47 func(cpe wfn.Attributes) (bool, int) { return cpe.Version != "", 1 }, 48 func(cpe wfn.Attributes) (bool, int) { return cpe.TargetSW != "", 1 }, 49 } 50 51 weightedCount := 0 52 for _, fieldIsSpecified := range checksForSpecifiedField { 53 isSpecified, weight := fieldIsSpecified(cpe) 54 if isSpecified { 55 weightedCount += weight 56 } 57 } 58 59 return weightedCount 60 }