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,54 @@
|
|
1
|
+
module NVD
|
2
|
+
module JSONFeeds
|
3
|
+
module Schema
|
4
|
+
#
|
5
|
+
# Adds the {#data_version} attribute.
|
6
|
+
#
|
7
|
+
module HasDataVersion
|
8
|
+
DATA_VERSIONS = {'4.0' => :"4.0"}
|
9
|
+
|
10
|
+
#
|
11
|
+
# Extends {ClassMethods}.
|
12
|
+
#
|
13
|
+
def self.included(base)
|
14
|
+
base.extend ClassMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# The class methods.
|
19
|
+
#
|
20
|
+
module ClassMethods
|
21
|
+
#
|
22
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
23
|
+
#
|
24
|
+
# @param [Hash{String => Object}] json
|
25
|
+
# The parsed JSON.
|
26
|
+
#
|
27
|
+
# @return [Hash{Symbol => Object}]
|
28
|
+
# The Symbol Hash.
|
29
|
+
#
|
30
|
+
def from_json(json)
|
31
|
+
{
|
32
|
+
data_version: DATA_VERSIONS.fetch(json.fetch('CVE_data_version'))
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# The data version.
|
38
|
+
#
|
39
|
+
# @return [:"4.0", String]
|
40
|
+
attr_reader :data_version
|
41
|
+
|
42
|
+
#
|
43
|
+
# Initializes the data version.
|
44
|
+
#
|
45
|
+
# @param [:"4.0", String] data_version
|
46
|
+
# The data version.
|
47
|
+
#
|
48
|
+
def initialize(data_version: )
|
49
|
+
@data_version = data_version
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'nvd/json_feeds/schema/impact/base_metric_v2'
|
2
|
+
require 'nvd/json_feeds/schema/impact/base_metric_v3'
|
3
|
+
|
4
|
+
module NVD
|
5
|
+
module JSONFeeds
|
6
|
+
module Schema
|
7
|
+
#
|
8
|
+
# Represents the `"impact"` value.
|
9
|
+
#
|
10
|
+
class Impact
|
11
|
+
|
12
|
+
# The base metric V3.
|
13
|
+
#
|
14
|
+
# @return [BaseMetricV3, nil]
|
15
|
+
attr_reader :base_metric_v3
|
16
|
+
|
17
|
+
# The base metric V2.
|
18
|
+
#
|
19
|
+
# @return [BaseMetricV2, nil]
|
20
|
+
attr_reader :base_metric_v2
|
21
|
+
|
22
|
+
#
|
23
|
+
# Initializes the impact object.
|
24
|
+
#
|
25
|
+
# @param [BaseMetricV3, nil] base_metric_v3
|
26
|
+
# The parsed `"baseMetricV3"` object.
|
27
|
+
#
|
28
|
+
# @param [BaseMetricV2, nil] base_metric_v2
|
29
|
+
# The parsed `"baseMetricV3"` object.
|
30
|
+
#
|
31
|
+
def initialize(base_metric_v3: nil, base_metric_v2: nil)
|
32
|
+
@base_metric_v3 = base_metric_v3
|
33
|
+
@base_metric_v2 = base_metric_v2
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
38
|
+
#
|
39
|
+
# @param [Hash{String => Object}] json
|
40
|
+
# The parsed JSON.
|
41
|
+
#
|
42
|
+
# @return [Hash{Symbol => Object}]
|
43
|
+
# The Symbol Hash.
|
44
|
+
#
|
45
|
+
def self.from_json(json)
|
46
|
+
{
|
47
|
+
base_metric_v3: if (base_metric_v3 = json['baseMetricV3'])
|
48
|
+
BaseMetricV3.load(base_metric_v3)
|
49
|
+
end,
|
50
|
+
|
51
|
+
base_metric_v2: if (base_metric_v2 = json['baseMetricV2'])
|
52
|
+
BaseMetricV2.load(base_metric_v2)
|
53
|
+
end
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Loads the impact object from the parsed JSON.
|
59
|
+
#
|
60
|
+
# @param [Hash{String => Object}] json
|
61
|
+
# The parsed JSON.
|
62
|
+
#
|
63
|
+
# @return [Impact]
|
64
|
+
# The loaded impact object.
|
65
|
+
#
|
66
|
+
def self.load(json)
|
67
|
+
new(**from_json(json))
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'nvd/json_feeds/schema/cvss_v2'
|
2
|
+
|
3
|
+
module NVD
|
4
|
+
module JSONFeeds
|
5
|
+
module Schema
|
6
|
+
class Impact
|
7
|
+
#
|
8
|
+
# Represents the `"baseMetricV2"` value.
|
9
|
+
#
|
10
|
+
class BaseMetricV2
|
11
|
+
|
12
|
+
# The CVSSv2 data.
|
13
|
+
#
|
14
|
+
# @return [CVSSv2, nil]
|
15
|
+
attr_reader :cvss_v2
|
16
|
+
|
17
|
+
# The severity.
|
18
|
+
#
|
19
|
+
# @return [String, nil]
|
20
|
+
attr_reader :severity
|
21
|
+
|
22
|
+
# The exploitability score.
|
23
|
+
#
|
24
|
+
# @return [Float, nil]
|
25
|
+
attr_reader :exploitability_score
|
26
|
+
|
27
|
+
# The impact score.
|
28
|
+
#
|
29
|
+
# @return [Float, nil]
|
30
|
+
attr_reader :impact_score
|
31
|
+
|
32
|
+
# @return [Boolean, nil]
|
33
|
+
attr_reader :ac_insuf_info
|
34
|
+
|
35
|
+
# @return [Boolean, nil]
|
36
|
+
attr_reader :obtain_all_privilege
|
37
|
+
|
38
|
+
# @return [Boolean, nil]
|
39
|
+
attr_reader :obtain_user_privilege
|
40
|
+
|
41
|
+
# @return [Boolean, nil]
|
42
|
+
attr_reader :obtain_other_privilege
|
43
|
+
|
44
|
+
# @return [Boolean, nil]
|
45
|
+
attr_reader :user_interaction_required
|
46
|
+
|
47
|
+
#
|
48
|
+
# Initializes the base metric V2 object.
|
49
|
+
#
|
50
|
+
# @param [CVSSv2, nil] cvss_v2
|
51
|
+
#
|
52
|
+
# @param [String, nil] severity
|
53
|
+
#
|
54
|
+
# @param [Float, nil] exploitability_score
|
55
|
+
#
|
56
|
+
# @param [Float, nil] impact_score
|
57
|
+
#
|
58
|
+
# @param [Boolean, nil] ac_insuf_info
|
59
|
+
#
|
60
|
+
# @param [Boolean, nil] obtain_all_privilege
|
61
|
+
#
|
62
|
+
# @param [Boolean, nil] obtain_user_privilege
|
63
|
+
#
|
64
|
+
# @param [Boolean, nil] obtain_other_privilege
|
65
|
+
#
|
66
|
+
# @param [Boolean, nil] user_interaction_required
|
67
|
+
#
|
68
|
+
def initialize(cvss_v2: nil,
|
69
|
+
severity: nil,
|
70
|
+
exploitability_score: nil,
|
71
|
+
impact_score: nil,
|
72
|
+
ac_insuf_info: nil,
|
73
|
+
obtain_all_privilege: nil,
|
74
|
+
obtain_user_privilege: nil,
|
75
|
+
obtain_other_privilege: nil,
|
76
|
+
user_interaction_required: nil)
|
77
|
+
@cvss_v2 = cvss_v2
|
78
|
+
@severity = severity
|
79
|
+
@exploitability_score = exploitability_score
|
80
|
+
@impact_score = impact_score
|
81
|
+
@ac_insuf_info = ac_insuf_info
|
82
|
+
@obtain_all_privilege = obtain_all_privilege
|
83
|
+
@obtain_user_privilege = obtain_user_privilege
|
84
|
+
@obtain_other_privilege = obtain_other_privilege
|
85
|
+
@user_interaction_required = user_interaction_required
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
90
|
+
#
|
91
|
+
# @param [Hash{String => Object}] json
|
92
|
+
# The parsed JSON.
|
93
|
+
#
|
94
|
+
# @return [Hash{Symbol => Object}]
|
95
|
+
# The Symbol Hash.
|
96
|
+
#
|
97
|
+
def self.from_json(json)
|
98
|
+
{
|
99
|
+
cvss_v2: if (value = json['cvssV2'])
|
100
|
+
CVSSv2.load(value)
|
101
|
+
end,
|
102
|
+
|
103
|
+
severity: json['severity'],
|
104
|
+
exploitability_score: json['exploitabilityScore'],
|
105
|
+
impact_score: json['impactScore'],
|
106
|
+
ac_insuf_info: json['acInsufInfo'],
|
107
|
+
obtain_all_privilege: json['obtainAllPrivilege'],
|
108
|
+
obtain_user_privilege: json['obtainUserPrivilege'],
|
109
|
+
obtain_other_privilege: json['obtainOtherPrivilege'],
|
110
|
+
user_interaction_required: json['userInteractionRequired']
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Loads the base metrics V2 object from the parsed JSON.
|
116
|
+
#
|
117
|
+
# @param [Hash{String => Object}] json
|
118
|
+
# The parsed JSON.
|
119
|
+
#
|
120
|
+
# @return [BaseMetricV2]
|
121
|
+
# The loaded base metric V3 object.
|
122
|
+
#
|
123
|
+
def self.load(json)
|
124
|
+
new(**from_json(json))
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'nvd/json_feeds/schema/cvss_v3'
|
2
|
+
|
3
|
+
module NVD
|
4
|
+
module JSONFeeds
|
5
|
+
module Schema
|
6
|
+
class Impact
|
7
|
+
#
|
8
|
+
# Represents the `"baseMetricV3"` value.
|
9
|
+
#
|
10
|
+
class BaseMetricV3
|
11
|
+
|
12
|
+
# The CVSSv3 data.
|
13
|
+
#
|
14
|
+
# @return [CVSSv3]
|
15
|
+
attr_reader :cvss_v3
|
16
|
+
|
17
|
+
# The exploitability score.
|
18
|
+
#
|
19
|
+
# @return [Float, nil]
|
20
|
+
attr_reader :exploitability_score
|
21
|
+
|
22
|
+
# The impact score.
|
23
|
+
#
|
24
|
+
# @return [Float, nil]
|
25
|
+
attr_reader :impact_score
|
26
|
+
|
27
|
+
#
|
28
|
+
# Initializes the base metric v3 object.
|
29
|
+
#
|
30
|
+
# @param [CVSSv3] cvss_v3
|
31
|
+
#
|
32
|
+
# @param [Float, nil] exploitability_score
|
33
|
+
#
|
34
|
+
# @param [Float, nil] impact_score
|
35
|
+
#
|
36
|
+
def initialize(cvss_v3: , exploitability_score: nil,
|
37
|
+
impact_score: nil)
|
38
|
+
@cvss_v3 = cvss_v3
|
39
|
+
|
40
|
+
@exploitability_score = exploitability_score
|
41
|
+
@impact_score = impact_score
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Maps the parsed JSON to a Symbol Hash for {#initialize}.
|
46
|
+
#
|
47
|
+
# @param [Hash{String => Object}] json
|
48
|
+
# The parsed JSON.
|
49
|
+
#
|
50
|
+
# @return [Hash{Symbol => Object}]
|
51
|
+
# The Symbol Hash.
|
52
|
+
#
|
53
|
+
def self.from_json(json)
|
54
|
+
{
|
55
|
+
cvss_v3: CVSSv3.load(json.fetch('cvssV3')),
|
56
|
+
|
57
|
+
exploitability_score: json['exploitabilityScore'],
|
58
|
+
impact_score: json['impactScore']
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Loads the base metrics V3 object from the parsed JSON.
|
64
|
+
#
|
65
|
+
# @param [Hash{String => Object}] json
|
66
|
+
# The parsed JSON.
|
67
|
+
#
|
68
|
+
# @return [BaseMetricV3]
|
69
|
+
# The loaded base metric V3 object.
|
70
|
+
#
|
71
|
+
def self.load(json)
|
72
|
+
new(**from_json(json))
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nvd/json_feeds/feed_file'
|
4
|
+
require 'nvd/json_feeds/json_feed_file'
|
5
|
+
require 'nvd/json_feeds/exceptions'
|
6
|
+
|
7
|
+
require 'shellwords'
|
8
|
+
|
9
|
+
module NVD
|
10
|
+
module JSONFeeds
|
11
|
+
#
|
12
|
+
# Represents a `.json.zip` feed file.
|
13
|
+
#
|
14
|
+
class ZipFeedFile < FeedFile
|
15
|
+
|
16
|
+
#
|
17
|
+
# The filename of the `.json` file within the `.zip` archive.
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
#
|
21
|
+
def json_filename
|
22
|
+
File.basename(@path,'.zip')
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Reads the compressed feed file.
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
#
|
30
|
+
# @raise [ReadFailed]
|
31
|
+
# The `unzip` command is not installed.
|
32
|
+
#
|
33
|
+
def read
|
34
|
+
`unzip -qq -p #{Shellwords.escape(@path)} #{Shellwords.escape(json_filename)}`
|
35
|
+
rescue Errno::ENOENT
|
36
|
+
raise(ReadFailed,"unzip command is not installed")
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Extracts the feed file.
|
41
|
+
#
|
42
|
+
# @return [JSONFeedFile]
|
43
|
+
#
|
44
|
+
# @raise [ExtractFailed]
|
45
|
+
# The `unzip` command failed or the `.json` file was not extracted.
|
46
|
+
#
|
47
|
+
def extract
|
48
|
+
extracted_dir = File.dirname(@path)
|
49
|
+
|
50
|
+
unless system('unzip', '-qq', '-d', extracted_dir, @path, json_filename)
|
51
|
+
raise(ExtractFailed,"unzip command failed")
|
52
|
+
end
|
53
|
+
|
54
|
+
extracted_path = File.join(extracted_dir,json_filename)
|
55
|
+
|
56
|
+
unless File.file?(extracted_path)
|
57
|
+
raise(ExtractFailed,"extraction failed: #{@path.inspect}")
|
58
|
+
end
|
59
|
+
|
60
|
+
return JSONFeedFile.new(extracted_path)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'nvd/json_feeds/feed_uri'
|
2
|
+
require 'nvd/json_feeds/zip_feed_file'
|
3
|
+
|
4
|
+
module NVD
|
5
|
+
module JSONFeeds
|
6
|
+
#
|
7
|
+
# Represents a URI to a `.json.zip` feed file.
|
8
|
+
#
|
9
|
+
class ZipFeedURI < FeedURI
|
10
|
+
|
11
|
+
#
|
12
|
+
# Downloads the compressed feed file.
|
13
|
+
#
|
14
|
+
# @param [String] dest
|
15
|
+
# The destination file or directory.
|
16
|
+
#
|
17
|
+
# @return [ZipFeedFile]
|
18
|
+
#
|
19
|
+
def download(dest)
|
20
|
+
ZipFeedFile.new(super(dest))
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|