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