2023-01-24 18:03:10 -05:00
|
|
|
package cveinfo
|
|
|
|
|
|
|
|
import (
|
2023-03-14 05:02:19 -05:00
|
|
|
"fmt"
|
2023-01-24 18:03:10 -05:00
|
|
|
"sort"
|
|
|
|
|
|
|
|
zerr "zotregistry.io/zot/errors"
|
|
|
|
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
|
|
|
|
)
|
|
|
|
|
|
|
|
type SortCriteria string
|
|
|
|
|
|
|
|
const (
|
|
|
|
AlphabeticAsc = SortCriteria("ALPHABETIC_ASC")
|
|
|
|
AlphabeticDsc = SortCriteria("ALPHABETIC_DSC")
|
|
|
|
SeverityDsc = SortCriteria("SEVERITY")
|
|
|
|
)
|
|
|
|
|
|
|
|
func SortFunctions() map[SortCriteria]func(pageBuffer []cvemodel.CVE, cveInfo CveInfo) func(i, j int) bool {
|
|
|
|
return map[SortCriteria]func(pageBuffer []cvemodel.CVE, cveInfo CveInfo) func(i, j int) bool{
|
|
|
|
AlphabeticAsc: SortByAlphabeticAsc,
|
|
|
|
AlphabeticDsc: SortByAlphabeticDsc,
|
|
|
|
SeverityDsc: SortBySeverity,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func SortByAlphabeticAsc(pageBuffer []cvemodel.CVE, cveInfo CveInfo) func(i, j int) bool {
|
|
|
|
return func(i, j int) bool {
|
|
|
|
return pageBuffer[i].ID < pageBuffer[j].ID
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func SortByAlphabeticDsc(pageBuffer []cvemodel.CVE, cveInfo CveInfo) func(i, j int) bool {
|
|
|
|
return func(i, j int) bool {
|
|
|
|
return pageBuffer[i].ID > pageBuffer[j].ID
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func SortBySeverity(pageBuffer []cvemodel.CVE, cveInfo CveInfo) func(i, j int) bool {
|
|
|
|
return func(i, j int) bool {
|
|
|
|
return cveInfo.CompareSeverities(pageBuffer[i].Severity, pageBuffer[j].Severity) < 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PageFinder permits keeping a pool of objects using Add
|
|
|
|
// and returning a specific page.
|
|
|
|
type PageFinder interface {
|
|
|
|
Add(cve cvemodel.CVE)
|
|
|
|
Page() ([]cvemodel.CVE, PageInfo)
|
|
|
|
Reset()
|
|
|
|
}
|
|
|
|
|
|
|
|
// CvePageFinder implements PageFinder. It manages Cve objects and calculates the page
|
|
|
|
// using the given limit, offset and sortBy option.
|
|
|
|
type CvePageFinder struct {
|
|
|
|
limit int
|
|
|
|
offset int
|
|
|
|
sortBy SortCriteria
|
|
|
|
pageBuffer []cvemodel.CVE
|
|
|
|
cveInfo CveInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewCvePageFinder(limit, offset int, sortBy SortCriteria, cveInfo CveInfo) (*CvePageFinder, error) {
|
|
|
|
if sortBy == "" {
|
|
|
|
sortBy = SeverityDsc
|
|
|
|
}
|
|
|
|
|
|
|
|
if limit < 0 {
|
|
|
|
return nil, zerr.ErrLimitIsNegative
|
|
|
|
}
|
|
|
|
|
|
|
|
if offset < 0 {
|
|
|
|
return nil, zerr.ErrOffsetIsNegative
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, found := SortFunctions()[sortBy]; !found {
|
2023-03-14 05:02:19 -05:00
|
|
|
return nil, fmt.Errorf("sorting CVEs by '%s' is not supported %w", sortBy, zerr.ErrSortCriteriaNotSupported)
|
2023-01-24 18:03:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return &CvePageFinder{
|
|
|
|
limit: limit,
|
|
|
|
offset: offset,
|
|
|
|
sortBy: sortBy,
|
|
|
|
pageBuffer: make([]cvemodel.CVE, 0, limit),
|
|
|
|
cveInfo: cveInfo,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bpt *CvePageFinder) Reset() {
|
|
|
|
bpt.pageBuffer = []cvemodel.CVE{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bpt *CvePageFinder) Add(cve cvemodel.CVE) {
|
|
|
|
bpt.pageBuffer = append(bpt.pageBuffer, cve)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bpt *CvePageFinder) Page() ([]cvemodel.CVE, PageInfo) {
|
|
|
|
if len(bpt.pageBuffer) == 0 {
|
|
|
|
return []cvemodel.CVE{}, PageInfo{}
|
|
|
|
}
|
|
|
|
|
|
|
|
pageInfo := &PageInfo{}
|
|
|
|
|
|
|
|
sort.Slice(bpt.pageBuffer, SortFunctions()[bpt.sortBy](bpt.pageBuffer, bpt.cveInfo))
|
|
|
|
|
|
|
|
// the offset and limit are calculated in terms of CVEs counted
|
|
|
|
start := bpt.offset
|
|
|
|
end := bpt.offset + bpt.limit
|
|
|
|
|
|
|
|
// we'll return an empty array when the offset is greater than the number of elements
|
|
|
|
if start >= len(bpt.pageBuffer) {
|
|
|
|
start = len(bpt.pageBuffer)
|
|
|
|
end = start
|
|
|
|
}
|
|
|
|
|
|
|
|
if end >= len(bpt.pageBuffer) {
|
|
|
|
end = len(bpt.pageBuffer)
|
|
|
|
}
|
|
|
|
|
|
|
|
cves := bpt.pageBuffer[start:end]
|
|
|
|
|
|
|
|
pageInfo.ItemCount = len(cves)
|
|
|
|
|
|
|
|
if start == 0 && end == 0 {
|
|
|
|
cves = bpt.pageBuffer
|
|
|
|
pageInfo.ItemCount = len(cves)
|
|
|
|
}
|
|
|
|
|
|
|
|
pageInfo.TotalCount = len(bpt.pageBuffer)
|
|
|
|
|
|
|
|
return cves, *pageInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
type PageInfo struct {
|
|
|
|
TotalCount int
|
|
|
|
ItemCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
type PageInput struct {
|
|
|
|
Limit int
|
|
|
|
Offset int
|
|
|
|
SortBy SortCriteria
|
|
|
|
}
|