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.
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