1package models
2
3import (
4	"fmt"
5	"strings"
6	"time"
7
8	"github.com/fatih/color"
9	"github.com/jinzhu/gorm"
10)
11
12// FeedMeta has meta information about fetched feeds
13type FeedMeta struct {
14	gorm.Model `json:"-"`
15
16	URL              string
17	Hash             string
18	LastModifiedDate string
19
20	LatestHash             string `json:"-" gorm:"-"`
21	LatestLastModifiedDate string `json:"-" gorm:"-"`
22}
23
24// UpToDate checks whether last fetched feed is up to date
25func (f FeedMeta) UpToDate() bool {
26	return !f.Newly() && f.Hash == f.LatestHash
27}
28
29// OutDated checks whether last fetched feed is out dated
30func (f FeedMeta) OutDated() bool {
31	return !f.Newly() && f.Hash != f.LatestHash
32}
33
34// Newly checks whether not fetched yet
35func (f FeedMeta) Newly() bool {
36	return f.Hash == ""
37}
38
39// StatusForStdout returns a status of fetched feed
40func (f FeedMeta) StatusForStdout() string {
41	if f.Newly() {
42		return "Newly"
43	} else if f.OutDated() {
44		red := color.New(color.FgRed, color.Bold).SprintFunc()
45		return red("Out-Dated")
46	} else if f.UpToDate() {
47		return color.GreenString("Up-to-Date")
48	}
49	return "Unknown"
50}
51
52const (
53	nvdjson = "NVD(JSON)"
54	jvn     = "JVN"
55)
56
57func (f FeedMeta) color(str string) string {
58	if f.OutDated() {
59		return color.WhiteString(str)
60	} else if f.UpToDate() {
61		return color.HiBlackString(str)
62	}
63	return str
64}
65
66func (f FeedMeta) source() string {
67	if strings.Contains(f.URL, "nvdcve-1.1-") {
68		return nvdjson
69	} else if strings.Contains(f.URL, "jvndb") {
70		return jvn
71	}
72	return "Unknown"
73}
74
75// FetchOption returns a option of fetch subcommand for list subcommand
76func (f FeedMeta) FetchOption() string {
77	switch f.source() {
78	case nvdjson:
79		return "fetchnvd"
80	case jvn:
81		return "fetchjvn"
82	default:
83		return ""
84	}
85}
86
87// Year returns year, whether xml or not of the feed
88func (f FeedMeta) Year() (year string, xml bool, err error) {
89	switch f.source() {
90	case nvdjson:
91		return strings.TrimSuffix(
92			strings.Split(f.URL, "nvdcve-1.1-")[1], ".json.gz"), false, nil
93	case jvn:
94		if strings.HasSuffix(f.URL, "jvndb.rdf") {
95			return "modified", true, nil
96		} else if strings.HasSuffix(f.URL, "jvndb_new.rdf") {
97			return "recent", true, nil
98		} else {
99			return strings.TrimSuffix(
100				strings.Split(f.URL, "jvndb_")[1], ".rdf"), true, nil
101		}
102	default:
103		return "", false, fmt.Errorf("Failed to parse URL: %s", f.URL)
104	}
105}
106
107func (f FeedMeta) modifiedTimesToStrs() (fetched, latest string) {
108	switch f.source() {
109	case nvdjson:
110		layout := "2006-01-02T15:04:05-07:00"
111		last, _ := time.Parse(layout, f.LastModifiedDate)
112		latest, _ := time.Parse(layout, f.LatestLastModifiedDate)
113		return last.Format("2006/1/2-15:04"),
114			latest.Format("2006/1/2-15:04")
115	case jvn:
116		layout := "2006/01/02 15:04:05"
117		last, _ := time.Parse(layout, f.LastModifiedDate)
118		latest, _ := time.Parse(layout, f.LatestLastModifiedDate)
119		return last.Format("2006/1/2-15:04"),
120			latest.Format("2006/1/2-15:04")
121	default:
122		return "Unknown", "Unknown"
123	}
124}
125
126// ToTableWriterRow generate data for table writer
127func (f FeedMeta) ToTableWriterRow() []string {
128	y, _, _ := f.Year()
129	fetched, latest := f.modifiedTimesToStrs()
130	return []string{
131		f.color(f.source()),
132		f.color(y),
133		f.StatusForStdout(),
134		f.color(fetched),
135		f.color(latest),
136	}
137}
138
139// CveDetail is a parent of Jnv/Nvd model
140type CveDetail struct {
141	gorm.Model `json:"-" xml:"-"`
142
143	CveID   string
144	NvdJSON *NvdJSON `json:",omitempty"`
145	Jvn     *Jvn     `json:",omitempty"`
146}
147
148// NvdJSON is a struct of NVD JSON
149// https://scap.nist.gov/schema/nvd/feed/0.1/nvd_cve_feed_json_0.1_beta.schema
150type NvdJSON struct {
151	gorm.Model  `json:"-" xml:"-"`
152	CveDetailID uint `json:"-" xml:"-"`
153
154	// DataType    string
155	// DataFormat  string
156	// DataVersion string
157
158	CveID        string
159	Descriptions []Description
160
161	Cvss2      Cvss2Extra
162	Cvss3      Cvss3
163	Cwes       []Cwe
164	Cpes       []Cpe
165	Affects    []Affect
166	References []Reference
167
168	// Assigner         string
169	Certs            []Cert
170	PublishedDate    time.Time
171	LastModifiedDate time.Time
172}
173
174// Jvn is a model of JVN
175type Jvn struct {
176	gorm.Model  `json:"-" xml:"-"`
177	CveDetailID uint `json:"-" xml:"-"`
178
179	CveID   string
180	Title   string
181	Summary string `sql:"type:text"`
182	JvnLink string
183	JvnID   string
184
185	Cvss2      Cvss2
186	Cvss3      Cvss3
187	Cpes       []Cpe `json:",omitempty"`
188	References []Reference
189
190	Certs            []Cert
191	PublishedDate    time.Time
192	LastModifiedDate time.Time
193}
194
195// Cwe has CweID
196type Cwe struct {
197	gorm.Model `json:"-" xml:"-"`
198	NvdJSONID  uint `json:"-" xml:"-"`
199	JvnID      uint `json:"-" xml:"-"`
200
201	CweID string
202}
203
204// Cpe is Child model of Jvn/Nvd.
205// see https://www.ipa.go.jp/security/vuln/CPE.html
206// In NVD JSON,
207// configurations>nodes>cpe>valunerable: true
208type Cpe struct {
209	gorm.Model `json:"-" xml:"-"`
210	JvnID      uint `json:"-" xml:"-"`
211	NvdJSONID  uint `json:"-" xml:"-"`
212
213	CpeBase
214	EnvCpes []EnvCpe
215}
216
217// EnvCpe is a Environmental CPE
218// Only NVD JSON has this information.
219// configurations>nodes>cpe>valunerable: false
220type EnvCpe struct {
221	gorm.Model `json:"-" xml:"-"`
222	CpeID      uint `json:"-" xml:"-"`
223
224	CpeBase
225}
226
227// CpeBase has common args of Cpe and EnvCpe
228type CpeBase struct {
229	URI             string
230	FormattedString string
231	WellFormedName  string `sql:"type:text"`
232	CpeWFN
233
234	VersionStartExcluding string
235	VersionStartIncluding string
236	VersionEndExcluding   string
237	VersionEndIncluding   string
238}
239
240// CpeWFN has CPE Well Formed name informaiton
241type CpeWFN struct {
242	Part            string
243	Vendor          string
244	Product         string
245	Version         string
246	Update          string
247	Edition         string
248	Language        string
249	SoftwareEdition string
250	TargetSW        string
251	TargetHW        string
252	Other           string
253}
254
255// Reference is Child model of Jvn/Nvd.
256// It holds reference information about the CVE.
257type Reference struct {
258	gorm.Model `json:"-" xml:"-"`
259	NvdJSONID  uint `json:"-" xml:"-"`
260	JvnID      uint `json:"-" xml:"-"`
261
262	Source string
263	Tags   string
264	Link   string `sql:"type:text"`
265}
266
267// Cert is Child model of Jvn/Nvd.
268// It holds CERT alerts.
269type Cert struct {
270	gorm.Model `json:"-" xml:"-"`
271	JvnID      uint `json:"-" xml:"-"`
272	NvdJSONID  uint `json:"-" xml:"-"`
273
274	Title string `sql:"type:text"`
275	Link  string `sql:"type:text"`
276}
277
278// Affect has vendor/product/version info in NVD JSON
279type Affect struct {
280	gorm.Model `json:"-" xml:"-"`
281	NvdJSONID  uint `json:"-" xml:"-"`
282
283	Vendor  string
284	Product string
285	Version string
286}
287
288// Cvss3 has CVSS Version 3 info
289// NVD JSON and JVN has CVSS3 info
290type Cvss3 struct {
291	gorm.Model `json:"-" xml:"-"`
292	NvdJSONID  uint `json:"-" xml:"-"`
293	JVNID      uint `json:"-" xml:"-"`
294
295	VectorString string
296
297	AttackVector          string
298	AttackComplexity      string
299	PrivilegesRequired    string
300	UserInteraction       string
301	Scope                 string
302	ConfidentialityImpact string
303	IntegrityImpact       string
304	AvailabilityImpact    string
305
306	BaseScore           float64
307	BaseSeverity        string
308	ExploitabilityScore float64
309	ImpactScore         float64
310}
311
312// Cvss2 has CVSS Version 2 info
313type Cvss2 struct {
314	gorm.Model `json:"-" xml:"-"`
315	JvnID      uint `json:"-" xml:"-"`
316
317	VectorString          string
318	AccessVector          string
319	AccessComplexity      string
320	Authentication        string
321	ConfidentialityImpact string
322	IntegrityImpact       string
323	AvailabilityImpact    string
324	BaseScore             float64
325
326	// NVD JSON and JVN has severity (Not in NVD XML)
327	Severity string
328}
329
330// Cvss2Extra has extra CVSS V2 info
331type Cvss2Extra struct {
332	NvdJSONID uint `json:"-" xml:"-"`
333
334	Cvss2
335	ExploitabilityScore     float64
336	ImpactScore             float64
337	ObtainAllPrivilege      bool
338	ObtainUserPrivilege     bool
339	ObtainOtherPrivilege    bool
340	UserInteractionRequired bool
341}
342
343// Description has description of the CVE
344type Description struct {
345	gorm.Model `json:"-" xml:"-"`
346	NvdJSONID  uint `json:"-" xml:"-"`
347
348	Lang  string
349	Value string `sql:"type:text"`
350}
351