1package models
2
3import (
4	"time"
5
6	"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
7)
8
9// CveContents has CveContent
10type CveContents map[CveContentType]CveContent
11
12// NewCveContents create CveContents
13func NewCveContents(conts ...CveContent) CveContents {
14	m := CveContents{}
15	for _, cont := range conts {
16		m[cont.Type] = cont
17	}
18	return m
19}
20
21// CveContentStr has CveContentType and Value
22type CveContentStr struct {
23	Type  CveContentType
24	Value string
25}
26
27// Except returns CveContents except given keys for enumeration
28func (v CveContents) Except(exceptCtypes ...CveContentType) (values CveContents) {
29	values = CveContents{}
30	for ctype, content := range v {
31		found := false
32		for _, exceptCtype := range exceptCtypes {
33			if ctype == exceptCtype {
34				found = true
35				break
36			}
37		}
38		if !found {
39			values[ctype] = content
40		}
41	}
42	return
43}
44
45// SourceLinks returns link of source
46func (v CveContents) SourceLinks(lang, myFamily, cveID string) (values []CveContentStr) {
47	if lang == "ja" {
48		if cont, found := v[Jvn]; found && 0 < len(cont.SourceLink) {
49			values = append(values, CveContentStr{Jvn, cont.SourceLink})
50		}
51	}
52
53	order := CveContentTypes{Nvd, NvdXML, NewCveContentType(myFamily)}
54	for _, ctype := range order {
55		if cont, found := v[ctype]; found {
56			if cont.SourceLink == "" {
57				continue
58			}
59			values = append(values, CveContentStr{ctype, cont.SourceLink})
60		}
61	}
62
63	if len(values) == 0 {
64		return []CveContentStr{{
65			Type:  Nvd,
66			Value: "https://nvd.nist.gov/vuln/detail/" + cveID,
67		}}
68	}
69	return values
70}
71
72/*
73// Severities returns Severities
74func (v CveContents) Severities(myFamily string) (values []CveContentStr) {
75	order := CveContentTypes{NVD, NewCveContentType(myFamily)}
76	order = append(order, AllCveContetTypes.Except(append(order)...)...)
77
78	for _, ctype := range order {
79		if cont, found := v[ctype]; found && 0 < len(cont.Severity) {
80			values = append(values, CveContentStr{
81				Type:  ctype,
82				Value: cont.Severity,
83			})
84		}
85	}
86	return
87}
88*/
89
90// CveContentCpes has CveContentType and Value
91type CveContentCpes struct {
92	Type  CveContentType
93	Value []Cpe
94}
95
96// Cpes returns affected CPEs of this Vulnerability
97func (v CveContents) Cpes(myFamily string) (values []CveContentCpes) {
98	order := CveContentTypes{NewCveContentType(myFamily)}
99	order = append(order, AllCveContetTypes.Except(order...)...)
100
101	for _, ctype := range order {
102		if cont, found := v[ctype]; found && 0 < len(cont.Cpes) {
103			values = append(values, CveContentCpes{
104				Type:  ctype,
105				Value: cont.Cpes,
106			})
107		}
108	}
109	return
110}
111
112// CveContentRefs has CveContentType and Cpes
113type CveContentRefs struct {
114	Type  CveContentType
115	Value []Reference
116}
117
118// References returns References
119func (v CveContents) References(myFamily string) (values []CveContentRefs) {
120	order := CveContentTypes{NewCveContentType(myFamily)}
121	order = append(order, AllCveContetTypes.Except(order...)...)
122
123	for _, ctype := range order {
124		if cont, found := v[ctype]; found && 0 < len(cont.References) {
125			values = append(values, CveContentRefs{
126				Type:  ctype,
127				Value: cont.References,
128			})
129		}
130	}
131
132	return
133}
134
135// CweIDs returns related CweIDs of the vulnerability
136func (v CveContents) CweIDs(myFamily string) (values []CveContentStr) {
137	order := CveContentTypes{NewCveContentType(myFamily)}
138	order = append(order, AllCveContetTypes.Except(order...)...)
139	for _, ctype := range order {
140		if cont, found := v[ctype]; found && 0 < len(cont.CweIDs) {
141			for _, cweID := range cont.CweIDs {
142				for _, val := range values {
143					if val.Value == cweID {
144						continue
145					}
146				}
147				values = append(values, CveContentStr{
148					Type:  ctype,
149					Value: cweID,
150				})
151			}
152		}
153	}
154	return
155}
156
157// UniqCweIDs returns Uniq CweIDs
158func (v CveContents) UniqCweIDs(myFamily string) (values []CveContentStr) {
159	uniq := map[string]CveContentStr{}
160	for _, cwes := range v.CweIDs(myFamily) {
161		uniq[cwes.Value] = cwes
162	}
163	for _, cwe := range uniq {
164		values = append(values, cwe)
165	}
166	return values
167}
168
169// CveContent has abstraction of various vulnerability information
170type CveContent struct {
171	Type          CveContentType    `json:"type"`
172	CveID         string            `json:"cveID"`
173	Title         string            `json:"title"`
174	Summary       string            `json:"summary"`
175	Cvss2Score    float64           `json:"cvss2Score"`
176	Cvss2Vector   string            `json:"cvss2Vector"`
177	Cvss2Severity string            `json:"cvss2Severity"`
178	Cvss3Score    float64           `json:"cvss3Score"`
179	Cvss3Vector   string            `json:"cvss3Vector"`
180	Cvss3Severity string            `json:"cvss3Severity"`
181	SourceLink    string            `json:"sourceLink"`
182	Cpes          []Cpe             `json:"cpes,omitempty"`
183	References    References        `json:"references,omitempty"`
184	CweIDs        []string          `json:"cweIDs,omitempty"`
185	Published     time.Time         `json:"published"`
186	LastModified  time.Time         `json:"lastModified"`
187	Mitigation    string            `json:"mitigation"` // RedHat API
188	Optional      map[string]string `json:"optional,omitempty"`
189}
190
191// Empty checks the content is empty
192func (c CveContent) Empty() bool {
193	return c.Summary == ""
194}
195
196// CveContentType is a source of CVE information
197type CveContentType string
198
199// NewCveContentType create CveContentType
200func NewCveContentType(name string) CveContentType {
201	switch name {
202	case "nvdxml":
203		return NvdXML
204	case "nvd":
205		return Nvd
206	case "jvn":
207		return Jvn
208	case "redhat", "centos":
209		return RedHat
210	case "oracle":
211		return Oracle
212	case "ubuntu":
213		return Ubuntu
214	case "debian", vulnerability.DebianOVAL:
215		return Debian
216	case "redhat_api":
217		return RedHatAPI
218	case "debian_security_tracker":
219		return DebianSecurityTracker
220	case "microsoft":
221		return Microsoft
222	case "wordpress":
223		return WPVulnDB
224	case "amazon":
225		return Amazon
226	case "trivy":
227		return Trivy
228	// case vulnerability.NodejsSecurityWg:
229	// 	return NodeSec
230	// case vulnerability.PythonSafetyDB:
231	// 	return PythonSec
232	// case vulnerability.RustSec:
233	// 	return RustSec
234	// case vulnerability.PhpSecurityAdvisories:
235	// 	return PhpSec
236	// case vulnerability.RubySec:
237	// 	return RubySec
238	default:
239		return Unknown
240	}
241}
242
243const (
244	// NvdXML is NvdXML
245	NvdXML CveContentType = "nvdxml"
246
247	// Nvd is Nvd
248	Nvd CveContentType = "nvd"
249
250	// Jvn is Jvn
251	Jvn CveContentType = "jvn"
252
253	// RedHat is RedHat
254	RedHat CveContentType = "redhat"
255
256	// RedHatAPI is RedHat
257	RedHatAPI CveContentType = "redhat_api"
258
259	// DebianSecurityTracker is Debian Security tracker
260	DebianSecurityTracker CveContentType = "debian_security_tracker"
261
262	// Debian is Debian
263	Debian CveContentType = "debian"
264
265	// Ubuntu is Ubuntu
266	Ubuntu CveContentType = "ubuntu"
267
268	// Oracle is Oracle Linux
269	Oracle CveContentType = "oracle"
270
271	// Amazon is Amazon Linux
272	Amazon CveContentType = "amazon"
273
274	// SUSE is SUSE Linux
275	SUSE CveContentType = "suse"
276
277	// Microsoft is Microsoft
278	Microsoft CveContentType = "microsoft"
279
280	// WPVulnDB is WordPress
281	WPVulnDB CveContentType = "wpvulndb"
282
283	// Trivy is Trivy
284	Trivy CveContentType = "trivy"
285
286	// NodeSec : for JS
287	// NodeSec CveContentType = "node"
288
289	// // PythonSec : for PHP
290	// PythonSec CveContentType = "python"
291
292	// // PhpSec : for PHP
293	// PhpSec CveContentType = "php"
294
295	// // RubySec : for Ruby
296	// RubySec CveContentType = "ruby"
297
298	// // RustSec : for Rust
299	// RustSec CveContentType = "rust"
300
301	// Unknown is Unknown
302	Unknown CveContentType = "unknown"
303)
304
305// CveContentTypes has slide of CveContentType
306type CveContentTypes []CveContentType
307
308// AllCveContetTypes has all of CveContentTypes
309var AllCveContetTypes = CveContentTypes{
310	Nvd,
311	NvdXML,
312	Jvn,
313	RedHat,
314	RedHatAPI,
315	Debian,
316	Ubuntu,
317	Amazon,
318	SUSE,
319	DebianSecurityTracker,
320	WPVulnDB,
321	Trivy,
322	// NodeSec,
323	// PythonSec,
324	// PhpSec,
325	// RubySec,
326	// RustSec,
327}
328
329// Except returns CveContentTypes except for given args
330func (c CveContentTypes) Except(excepts ...CveContentType) (excepted CveContentTypes) {
331	for _, ctype := range c {
332		found := false
333		for _, except := range excepts {
334			if ctype == except {
335				found = true
336				break
337			}
338		}
339		if !found {
340			excepted = append(excepted, ctype)
341		}
342	}
343	return
344}
345
346// Cpe is Common Platform Enumeration
347type Cpe struct {
348	URI             string `json:"uri"`
349	FormattedString string `json:"formattedString"`
350}
351
352// References is a slice of Reference
353type References []Reference
354
355// Reference has a related link of the CVE
356type Reference struct {
357	Source string `json:"source"`
358	Link   string `json:"link"`
359	RefID  string `json:"refID"`
360}
361