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