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  }