nvd-json_feeds 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.github/workflows/ruby.yml +29 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +25 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.md +136 -0
- data/Rakefile +31 -0
- data/gemspec.yml +22 -0
- data/lib/nvd/json_feeds.rb +25 -0
- data/lib/nvd/json_feeds/exceptions.rb +15 -0
- data/lib/nvd/json_feeds/feed.rb +50 -0
- data/lib/nvd/json_feeds/feed_file.rb +95 -0
- data/lib/nvd/json_feeds/feed_uri.rb +131 -0
- data/lib/nvd/json_feeds/gz_feed_file.rb +60 -0
- data/lib/nvd/json_feeds/gz_feed_uri.rb +25 -0
- data/lib/nvd/json_feeds/json_feed_file.rb +21 -0
- data/lib/nvd/json_feeds/meta.rb +122 -0
- data/lib/nvd/json_feeds/meta_feed_uri.rb +22 -0
- data/lib/nvd/json_feeds/schema/configurations.rb +61 -0
- data/lib/nvd/json_feeds/schema/configurations/node.rb +98 -0
- data/lib/nvd/json_feeds/schema/cpe/has_uri.rb +66 -0
- data/lib/nvd/json_feeds/schema/cpe/match.rb +117 -0
- data/lib/nvd/json_feeds/schema/cpe/name.rb +67 -0
- data/lib/nvd/json_feeds/schema/cve_feed.rb +142 -0
- data/lib/nvd/json_feeds/schema/cve_item.rb +94 -0
- data/lib/nvd/json_feeds/schema/cvss_v2.rb +298 -0
- data/lib/nvd/json_feeds/schema/cvss_v3.rb +332 -0
- data/lib/nvd/json_feeds/schema/has_data_version.rb +54 -0
- data/lib/nvd/json_feeds/schema/impact.rb +73 -0
- data/lib/nvd/json_feeds/schema/impact/base_metric_v2.rb +132 -0
- data/lib/nvd/json_feeds/schema/impact/base_metric_v3.rb +79 -0
- data/lib/nvd/json_feeds/schema/timestamp.rb +9 -0
- data/lib/nvd/json_feeds/version.rb +6 -0
- data/lib/nvd/json_feeds/zip_feed_file.rb +64 -0
- data/lib/nvd/json_feeds/zip_feed_uri.rb +25 -0
- data/nvd-json_feeds.gemspec +61 -0
- data/spec/feed_file_examples.rb +27 -0
- data/spec/feed_file_spec.rb +42 -0
- data/spec/feed_spec.rb +56 -0
- data/spec/feed_uri_spec.rb +81 -0
- data/spec/fixtures/gz_feed_file/nvdcve-1.1-recent.json.gz +0 -0
- data/spec/fixtures/nvdcve-1.1-recent.json +180 -0
- data/spec/fixtures/zip_feed_file/nvdcve-1.1-recent.json.zip +0 -0
- data/spec/gz_feed_file_spec.rb +66 -0
- data/spec/gz_feed_uri_spec.rb +35 -0
- data/spec/json_feed_file_spec.rb +18 -0
- data/spec/json_feeds_spec.rb +8 -0
- data/spec/meta_spec.rb +141 -0
- data/spec/schema/configurations/node_spec.rb +87 -0
- data/spec/schema/configurations_spec.rb +57 -0
- data/spec/schema/cpe/match_spec.rb +188 -0
- data/spec/schema/cpe/name_spec.rb +54 -0
- data/spec/schema/cve_feed_spec.rb +162 -0
- data/spec/schema/cve_item_spec.rb +116 -0
- data/spec/schema/impact/base_metric_v2_spec.rb +183 -0
- data/spec/schema/impact/base_metric_v3_spec.rb +80 -0
- data/spec/schema/impact_spec.rb +53 -0
- data/spec/schema/shared_examples.rb +136 -0
- data/spec/schema/timestamp_spec.rb +8 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/zip_feed_file_spec.rb +66 -0
- data/spec/zip_feed_uri_spec.rb +35 -0
- metadata +156 -0
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'nvd/json_feeds/schema/cpe/match'
|
2
|
+
|
3
|
+
module NVD
|
4
|
+
module JSONFeeds
|
5
|
+
module Schema
|
6
|
+
class Configurations
|
7
|
+
#
|
8
|
+
# Represents a value within `"nodes"`.
|
9
|
+
#
|
10
|
+
class Node
|
11
|
+
|
12
|
+
OPERATORS = {
|
13
|
+
'OR' => :OR,
|
14
|
+
'AND' => :AND
|
15
|
+
}
|
16
|
+
|
17
|
+
# @return [:OR, :AND, String]
|
18
|
+
attr_reader :operator
|
19
|
+
|
20
|
+
# @return [Boolean, nil]
|
21
|
+
attr_reader :negate
|
22
|
+
|
23
|
+
# @return [Array<Node>]
|
24
|
+
attr_reader :children
|
25
|
+
|
26
|
+
# @return [Array<CPE::Match>]
|
27
|
+
attr_reader :cpe_match
|
28
|
+
|
29
|
+
#
|
30
|
+
# Initializes the node.
|
31
|
+
#
|
32
|
+
# @param [:OR, :AND, String] operator
|
33
|
+
#
|
34
|
+
# @param [Boolean, nil] negate
|
35
|
+
#
|
36
|
+
# @param [Array<Node>] children
|
37
|
+
#
|
38
|
+
# @param [Array<CPE::Match>] cpe_match
|
39
|
+
#
|
40
|
+
def initialize(operator: nil, negate: nil, children: [], cpe_match: [])
|
41
|
+
@operator = operator
|
42
|
+
@negate = negate
|
43
|
+
|
44
|
+
@children = children
|
45
|
+
@cpe_match = cpe_match
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Determines if {#negate} is `true`.
|
50
|
+
#
|
51
|
+
# @return [Boolean]
|
52
|
+
#
|
53
|
+
def negate?
|
54
|
+
@negate == true
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
59
|
+
#
|
60
|
+
# @param [Hash{String => Object}] json
|
61
|
+
# The parsed JSON.
|
62
|
+
#
|
63
|
+
# @return [Hash{Symbol => Object}]
|
64
|
+
# The Symbol Hash.
|
65
|
+
#
|
66
|
+
# @see https://csrc.nist.gov/schema/nvd/feed/1.1-Beta/cvss-v2.0_beta.json
|
67
|
+
#
|
68
|
+
def self.from_json(json)
|
69
|
+
{
|
70
|
+
operator: if (operator = json['operator'])
|
71
|
+
OPERATORS.fetch(operator,operator)
|
72
|
+
end,
|
73
|
+
negate: json['negate'],
|
74
|
+
|
75
|
+
children: Array(json['children']).map(&method(:load)),
|
76
|
+
cpe_match: Array(json['cpe_match']).map(&CPE::Match.method(:load))
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Loads the node object from the parsed JSON.
|
82
|
+
#
|
83
|
+
# @param [Hash{String => Object}] json
|
84
|
+
# The parsed JSON.
|
85
|
+
#
|
86
|
+
# @return [Node]
|
87
|
+
# The node object.
|
88
|
+
#
|
89
|
+
def self.load(json)
|
90
|
+
new(**from_json(json))
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module NVD
|
2
|
+
module JSONFeeds
|
3
|
+
module Schema
|
4
|
+
module CPE
|
5
|
+
#
|
6
|
+
# Adds the {#cpe23uri} and {#cpe22uri} attributes.
|
7
|
+
#
|
8
|
+
module HasURI
|
9
|
+
#
|
10
|
+
# Extends {ClassMethods}.
|
11
|
+
#
|
12
|
+
def self.included(base)
|
13
|
+
base.extend ClassMethods
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Class methods.
|
18
|
+
#
|
19
|
+
module ClassMethods
|
20
|
+
#
|
21
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
22
|
+
#
|
23
|
+
# @param [Hash{String => Object}] json
|
24
|
+
# The parsed JSON.
|
25
|
+
#
|
26
|
+
# @return [Hash{Symbol => Object}]
|
27
|
+
# The Symbol Hash.
|
28
|
+
#
|
29
|
+
def from_json(json)
|
30
|
+
{
|
31
|
+
cpe23uri: json.fetch('cpe23Uri'),
|
32
|
+
cpe22uri: json['cpe22Uri']
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Initializes the CPE URIs.
|
39
|
+
#
|
40
|
+
# @param [String] cpe23uri
|
41
|
+
# The CPE 2.3 URI.
|
42
|
+
#
|
43
|
+
# @param [String] cpe22uri
|
44
|
+
# The CPE 2.2 URI.
|
45
|
+
#
|
46
|
+
def initialize(cpe23uri: , cpe22uri: nil)
|
47
|
+
@cpe23uri = cpe23uri
|
48
|
+
@cpe22uri = cpe22uri
|
49
|
+
end
|
50
|
+
|
51
|
+
# The CPE 2.3 URI.
|
52
|
+
#
|
53
|
+
# @return [String]
|
54
|
+
attr_reader :cpe23uri
|
55
|
+
|
56
|
+
alias cpe_uri cpe23uri
|
57
|
+
|
58
|
+
# The CPE 2.2 URI.
|
59
|
+
#
|
60
|
+
# @return [String, nil]
|
61
|
+
attr_reader :cpe22uri
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'nvd/json_feeds/schema/cpe/name'
|
2
|
+
|
3
|
+
module NVD
|
4
|
+
module JSONFeeds
|
5
|
+
module Schema
|
6
|
+
module CPE
|
7
|
+
#
|
8
|
+
# Represents the `"cpe_match"` value.
|
9
|
+
#
|
10
|
+
class Match
|
11
|
+
|
12
|
+
include HasURI
|
13
|
+
|
14
|
+
# @return [Boolean]
|
15
|
+
attr_reader :vulnerable
|
16
|
+
|
17
|
+
# @return [String, nil]
|
18
|
+
attr_reader :version_start_excluding
|
19
|
+
|
20
|
+
# @return [String, nil]
|
21
|
+
attr_reader :version_start_including
|
22
|
+
|
23
|
+
# @return [String, nil]
|
24
|
+
attr_reader :version_end_excluding
|
25
|
+
|
26
|
+
# @return [String, nil]
|
27
|
+
attr_reader :version_end_including
|
28
|
+
|
29
|
+
# @return [Array<Name>]
|
30
|
+
attr_reader :cpe_name
|
31
|
+
|
32
|
+
#
|
33
|
+
# Initializes the CPE match object.
|
34
|
+
#
|
35
|
+
# @param [Boolean] vulnerable
|
36
|
+
#
|
37
|
+
# @param [String, nil] version_start_excluding
|
38
|
+
#
|
39
|
+
# @param [String, nil] version_start_including
|
40
|
+
#
|
41
|
+
# @param [String, nil] version_end_excluding
|
42
|
+
#
|
43
|
+
# @param [String, nil] version_end_including
|
44
|
+
#
|
45
|
+
# @param [Array<Name>] cpe_name
|
46
|
+
#
|
47
|
+
def initialize(vulnerable: , version_start_excluding: nil,
|
48
|
+
version_start_including: nil,
|
49
|
+
version_end_excluding: nil,
|
50
|
+
version_end_including: nil,
|
51
|
+
cpe_name: [],
|
52
|
+
**kwargs)
|
53
|
+
super(**kwargs)
|
54
|
+
|
55
|
+
@vulnerable = vulnerable
|
56
|
+
|
57
|
+
@version_start_excluding = version_start_excluding
|
58
|
+
@version_start_including = version_start_including
|
59
|
+
|
60
|
+
@version_end_excluding = version_end_excluding
|
61
|
+
@version_end_including = version_end_including
|
62
|
+
|
63
|
+
@cpe_name = cpe_name
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Determines if the CPE match indicates whether it's vulnerable.
|
68
|
+
#
|
69
|
+
# @return [Boolean]
|
70
|
+
#
|
71
|
+
def vulnerable?
|
72
|
+
@vulnerable == true
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Maps the CPE match JSON to a Symbol Hash for {#initialize}.
|
77
|
+
#
|
78
|
+
# @param [Hash{String => Object}] json
|
79
|
+
# The parsed JSON.
|
80
|
+
#
|
81
|
+
# @return [Hash{Symbol => Object}]
|
82
|
+
# The mapped Symbol Hash.
|
83
|
+
#
|
84
|
+
def self.from_json(json)
|
85
|
+
{
|
86
|
+
vulnerable: json.fetch('vulnerable'),
|
87
|
+
|
88
|
+
**super(json),
|
89
|
+
|
90
|
+
version_start_excluding: json['versionStartExcluding'],
|
91
|
+
version_start_including: json['versionStartIncluding'],
|
92
|
+
|
93
|
+
version_end_excluding: json['versionEndExcluding'],
|
94
|
+
version_end_including: json['versionEndIncluding'],
|
95
|
+
|
96
|
+
cpe_name: Array(json['cpe_name']).map(&Name.method(:load))
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Loads the CPE match object from the parsed JSON.
|
102
|
+
#
|
103
|
+
# @param [Hash{String => Object}] json
|
104
|
+
# The parsed JSON.
|
105
|
+
#
|
106
|
+
# @return [Match]
|
107
|
+
# The loaded CPE match object.
|
108
|
+
#
|
109
|
+
def self.load(json)
|
110
|
+
new(**from_json(json))
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'nvd/json_feeds/schema/cpe/has_uri'
|
2
|
+
require 'nvd/json_feeds/schema/timestamp'
|
3
|
+
|
4
|
+
module NVD
|
5
|
+
module JSONFeeds
|
6
|
+
module Schema
|
7
|
+
module CPE
|
8
|
+
#
|
9
|
+
# Represents the `"cpe_name"` value.
|
10
|
+
#
|
11
|
+
class Name
|
12
|
+
|
13
|
+
include HasURI
|
14
|
+
|
15
|
+
# Last modified date.
|
16
|
+
#
|
17
|
+
# @return [DateTime, nil]
|
18
|
+
attr_reader :last_modified_date
|
19
|
+
|
20
|
+
#
|
21
|
+
# Initializes the CPE name.
|
22
|
+
#
|
23
|
+
# @param [DateTime, nil] last_modified_date
|
24
|
+
#
|
25
|
+
def initialize(last_modified_date: nil, **kwargs)
|
26
|
+
super(**kwargs)
|
27
|
+
|
28
|
+
@last_modified_date = last_modified_date
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
33
|
+
#
|
34
|
+
# @param [Hash{String => Object}] json
|
35
|
+
# The parsed JSON Hash.
|
36
|
+
#
|
37
|
+
# @return [Hash{Symbol => Object}]
|
38
|
+
# The mapped Symbol Hash.
|
39
|
+
#
|
40
|
+
def self.from_json(json)
|
41
|
+
{
|
42
|
+
**super(json),
|
43
|
+
|
44
|
+
last_modified_date: if (last_modified_date = json['lastModifiedDate'])
|
45
|
+
Timestamp.parse(last_modified_date)
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Loads the CPE name object from the parsed JSON.
|
52
|
+
#
|
53
|
+
# @param [Hash{String => Object}] json
|
54
|
+
# The parsed JSON Hash.
|
55
|
+
#
|
56
|
+
# @return [Name]
|
57
|
+
# The loaded CPE name object.
|
58
|
+
#
|
59
|
+
def self.load(json)
|
60
|
+
new(**from_json(json))
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'nvd/json_feeds/schema/has_data_version'
|
2
|
+
require 'nvd/json_feeds/schema/timestamp'
|
3
|
+
require 'nvd/json_feeds/schema/cve_item'
|
4
|
+
|
5
|
+
module NVD
|
6
|
+
module JSONFeeds
|
7
|
+
module Schema
|
8
|
+
#
|
9
|
+
# Represents the parsed contents of a JSON CVE feed.
|
10
|
+
#
|
11
|
+
class CVEFeed
|
12
|
+
|
13
|
+
include HasDataVersion
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
DATA_TYPES = {
|
17
|
+
'CVE' => :CVE
|
18
|
+
}
|
19
|
+
|
20
|
+
DATA_FORMATS = {
|
21
|
+
'MITRE' => :MITRE
|
22
|
+
}
|
23
|
+
|
24
|
+
# The feed format.
|
25
|
+
#
|
26
|
+
# @return [:MITRE]
|
27
|
+
attr_reader :data_format
|
28
|
+
|
29
|
+
alias format data_format
|
30
|
+
|
31
|
+
# The feed type.
|
32
|
+
#
|
33
|
+
# @return [:CVE]
|
34
|
+
attr_reader :data_type
|
35
|
+
|
36
|
+
alias type data_type
|
37
|
+
|
38
|
+
# The number of CVEs.
|
39
|
+
#
|
40
|
+
# @return [Integer, nil]
|
41
|
+
attr_reader :data_number_of_cves
|
42
|
+
|
43
|
+
alias number_of_cves data_number_of_cves
|
44
|
+
|
45
|
+
# The feed timestamp.
|
46
|
+
#
|
47
|
+
# @return [DateTime, nil]
|
48
|
+
attr_reader :data_timestamp
|
49
|
+
|
50
|
+
alias timestamp data_timestamp
|
51
|
+
|
52
|
+
# The CVE items.
|
53
|
+
#
|
54
|
+
# @return [Array<CVEItem>]
|
55
|
+
attr_reader :cve_items
|
56
|
+
|
57
|
+
#
|
58
|
+
# Initializes the JSON feed.
|
59
|
+
#
|
60
|
+
# @param [:MITRE] data_format
|
61
|
+
#
|
62
|
+
# @param [:CVE] data_type
|
63
|
+
#
|
64
|
+
# @param [Integer, nil] data_number_of_cves
|
65
|
+
#
|
66
|
+
# @param [DateTime, nil] data_timestamp
|
67
|
+
#
|
68
|
+
# @param [Array<CVEItem>] cve_items
|
69
|
+
#
|
70
|
+
def initialize(data_format: , data_type: , data_number_of_cves: nil,
|
71
|
+
data_timestamp: nil,
|
72
|
+
cve_items: ,
|
73
|
+
**kwargs)
|
74
|
+
super(**kwargs)
|
75
|
+
|
76
|
+
@data_format = data_format
|
77
|
+
@data_type = data_type
|
78
|
+
|
79
|
+
@data_number_of_cves = data_number_of_cves
|
80
|
+
@data_timestamp = data_timestamp
|
81
|
+
|
82
|
+
@cve_items = cve_items
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
87
|
+
#
|
88
|
+
# @param [Hash{String => Object}] json
|
89
|
+
# The parsed JSON.
|
90
|
+
#
|
91
|
+
# @return [Hash{Symbol => Object}]
|
92
|
+
# The mapped Symbol Hash.
|
93
|
+
#
|
94
|
+
def self.from_json(json)
|
95
|
+
{
|
96
|
+
data_type: DATA_TYPES.fetch(json.fetch('CVE_data_type')),
|
97
|
+
data_format: DATA_FORMATS.fetch(json.fetch('CVE_data_format')),
|
98
|
+
**super(json),
|
99
|
+
|
100
|
+
data_number_of_cves: json.fetch('CVE_data_numberOfCVEs').to_i,
|
101
|
+
|
102
|
+
data_timestamp: if (timestamp = json['CVE_data_timestamp'])
|
103
|
+
Timestamp.parse(timestamp)
|
104
|
+
end,
|
105
|
+
|
106
|
+
cve_items: json.fetch('CVE_Items').map(&CVEItem.method(:load))
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Loads the JSON feed data from the parsed JSON.
|
112
|
+
#
|
113
|
+
# @param [Hash{String => Object}] json
|
114
|
+
# The parsed JSON.
|
115
|
+
#
|
116
|
+
# @return [JSONFeed]
|
117
|
+
# The loaded JSON data.
|
118
|
+
#
|
119
|
+
def self.load(json)
|
120
|
+
new(**from_json(json))
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Enumerates over each CVE item in the feed.
|
125
|
+
#
|
126
|
+
# @yield [cve_itme]
|
127
|
+
# The given block will be passed each CVE Item.
|
128
|
+
#
|
129
|
+
# @yieldparam [CVEItem] cve_item
|
130
|
+
# A CVE Item in the feed.
|
131
|
+
#
|
132
|
+
# @return [Enumerator]
|
133
|
+
# If no block is given, an enumerator will be returned.
|
134
|
+
#
|
135
|
+
def each(&block)
|
136
|
+
@cve_items.each(&block)
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|