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