nvd-json_feeds 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.github/workflows/ruby.yml +29 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/ChangeLog.md +25 -0
  8. data/Gemfile +13 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +136 -0
  11. data/Rakefile +31 -0
  12. data/gemspec.yml +22 -0
  13. data/lib/nvd/json_feeds.rb +25 -0
  14. data/lib/nvd/json_feeds/exceptions.rb +15 -0
  15. data/lib/nvd/json_feeds/feed.rb +50 -0
  16. data/lib/nvd/json_feeds/feed_file.rb +95 -0
  17. data/lib/nvd/json_feeds/feed_uri.rb +131 -0
  18. data/lib/nvd/json_feeds/gz_feed_file.rb +60 -0
  19. data/lib/nvd/json_feeds/gz_feed_uri.rb +25 -0
  20. data/lib/nvd/json_feeds/json_feed_file.rb +21 -0
  21. data/lib/nvd/json_feeds/meta.rb +122 -0
  22. data/lib/nvd/json_feeds/meta_feed_uri.rb +22 -0
  23. data/lib/nvd/json_feeds/schema/configurations.rb +61 -0
  24. data/lib/nvd/json_feeds/schema/configurations/node.rb +98 -0
  25. data/lib/nvd/json_feeds/schema/cpe/has_uri.rb +66 -0
  26. data/lib/nvd/json_feeds/schema/cpe/match.rb +117 -0
  27. data/lib/nvd/json_feeds/schema/cpe/name.rb +67 -0
  28. data/lib/nvd/json_feeds/schema/cve_feed.rb +142 -0
  29. data/lib/nvd/json_feeds/schema/cve_item.rb +94 -0
  30. data/lib/nvd/json_feeds/schema/cvss_v2.rb +298 -0
  31. data/lib/nvd/json_feeds/schema/cvss_v3.rb +332 -0
  32. data/lib/nvd/json_feeds/schema/has_data_version.rb +54 -0
  33. data/lib/nvd/json_feeds/schema/impact.rb +73 -0
  34. data/lib/nvd/json_feeds/schema/impact/base_metric_v2.rb +132 -0
  35. data/lib/nvd/json_feeds/schema/impact/base_metric_v3.rb +79 -0
  36. data/lib/nvd/json_feeds/schema/timestamp.rb +9 -0
  37. data/lib/nvd/json_feeds/version.rb +6 -0
  38. data/lib/nvd/json_feeds/zip_feed_file.rb +64 -0
  39. data/lib/nvd/json_feeds/zip_feed_uri.rb +25 -0
  40. data/nvd-json_feeds.gemspec +61 -0
  41. data/spec/feed_file_examples.rb +27 -0
  42. data/spec/feed_file_spec.rb +42 -0
  43. data/spec/feed_spec.rb +56 -0
  44. data/spec/feed_uri_spec.rb +81 -0
  45. data/spec/fixtures/gz_feed_file/nvdcve-1.1-recent.json.gz +0 -0
  46. data/spec/fixtures/nvdcve-1.1-recent.json +180 -0
  47. data/spec/fixtures/zip_feed_file/nvdcve-1.1-recent.json.zip +0 -0
  48. data/spec/gz_feed_file_spec.rb +66 -0
  49. data/spec/gz_feed_uri_spec.rb +35 -0
  50. data/spec/json_feed_file_spec.rb +18 -0
  51. data/spec/json_feeds_spec.rb +8 -0
  52. data/spec/meta_spec.rb +141 -0
  53. data/spec/schema/configurations/node_spec.rb +87 -0
  54. data/spec/schema/configurations_spec.rb +57 -0
  55. data/spec/schema/cpe/match_spec.rb +188 -0
  56. data/spec/schema/cpe/name_spec.rb +54 -0
  57. data/spec/schema/cve_feed_spec.rb +162 -0
  58. data/spec/schema/cve_item_spec.rb +116 -0
  59. data/spec/schema/impact/base_metric_v2_spec.rb +183 -0
  60. data/spec/schema/impact/base_metric_v3_spec.rb +80 -0
  61. data/spec/schema/impact_spec.rb +53 -0
  62. data/spec/schema/shared_examples.rb +136 -0
  63. data/spec/schema/timestamp_spec.rb +8 -0
  64. data/spec/spec_helper.rb +8 -0
  65. data/spec/zip_feed_file_spec.rb +66 -0
  66. data/spec/zip_feed_uri_spec.rb +35 -0
  67. 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,9 @@
1
+ require 'cve_schema/cve/timestamp'
2
+
3
+ module NVD
4
+ module JSONFeeds
5
+ module Schema
6
+ Timestamp = CVESchema::CVE::Timestamp
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module NVD
2
+ module JSONFeeds
3
+ # nvd-json_feeds version
4
+ VERSION = "0.1.0"
5
+ end
6
+ 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