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,61 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'nvd/json_feeds/version'
14
+ NVD::JSONFeeds::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+ gem.metadata = gemspec['metadata'] if gemspec['metadata']
24
+
25
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
26
+
27
+ gem.files = `git ls-files`.split($/)
28
+ gem.files = glob[gemspec['files']] if gemspec['files']
29
+
30
+ gem.executables = gemspec.fetch('executables') do
31
+ glob['bin/*'].map { |path| File.basename(path) }
32
+ end
33
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
34
+
35
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
36
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
37
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
38
+
39
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
40
+ %w[ext lib].select { |dir| File.directory?(dir) }
41
+ })
42
+
43
+ gem.requirements = Array(gemspec['requirements'])
44
+ gem.required_ruby_version = gemspec['required_ruby_version']
45
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
46
+ gem.post_install_message = gemspec['post_install_message']
47
+
48
+ split = lambda { |string| string.split(/,\s*/) }
49
+
50
+ if gemspec['dependencies']
51
+ gemspec['dependencies'].each do |name,versions|
52
+ gem.add_dependency(name,split[versions])
53
+ end
54
+ end
55
+
56
+ if gemspec['development_dependencies']
57
+ gemspec['development_dependencies'].each do |name,versions|
58
+ gem.add_development_dependency(name,split[versions])
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.shared_examples_for "FeedFile" do
4
+ describe "#read" do
5
+ subject { super().read }
6
+
7
+ it "must return a String" do
8
+ expect(subject).to be_kind_of(String)
9
+ expect(subject).to_not be_empty
10
+ end
11
+ end
12
+
13
+ describe "#json" do
14
+ subject { super().json }
15
+
16
+ it "must return a parsed JSON Hash" do
17
+ expect(subject).to be_kind_of(Hash)
18
+ expect(subject).to_not be_empty
19
+ end
20
+ end
21
+
22
+ describe "#parse" do
23
+ it "must return a CVEFeed object" do
24
+ expect(subject.parse).to be_kind_of(Schema::CVEFeed)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'nvd/json_feeds/feed_file'
3
+
4
+ describe FeedFile do
5
+ let(:fixtures_dir) { File.expand_path('../fixtures',__FILE__) }
6
+ let(:filename) { 'nvdcve-1.1-recent.json' }
7
+ let(:path) { File.join(fixtures_dir,filename) }
8
+
9
+ subject { described_class.new(path) }
10
+
11
+ describe "#initialize" do
12
+ it "must set #path" do
13
+ expect(subject.path).to eq(path)
14
+ end
15
+
16
+ context "when given a relative path" do
17
+ let(:path) { File.join('../fixtures',filename) }
18
+
19
+ it "must expand the relative path" do
20
+ expect(subject.path).to eq(File.expand_path(path))
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "#read" do
26
+ it do
27
+ expect { subject.read }.to raise_error(NotImplementedError)
28
+ end
29
+ end
30
+
31
+ describe "#to_s" do
32
+ it "must the #path" do
33
+ expect(subject.to_s).to eq(subject.path)
34
+ end
35
+ end
36
+
37
+ describe "#inspect" do
38
+ it "must include the class name and path" do
39
+ expect(subject.inspect).to eq("#<#{described_class}: #{subject.path}>")
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'nvd/json_feeds/feed'
3
+
4
+ describe Feed do
5
+ let(:name) { :recent }
6
+
7
+ subject { described_class.new(name) }
8
+
9
+ describe "#initialize" do
10
+ it "must set #name" do
11
+ expect(subject.name).to eq(name)
12
+ end
13
+
14
+ describe "#meta" do
15
+ subject { super().meta }
16
+
17
+ it { expect(subject).to be_kind_of(MetaFeedURI) }
18
+
19
+ it "must have the same name" do
20
+ expect(subject.name).to eq(name)
21
+ end
22
+
23
+ it "must use '.meta' for the extension" do
24
+ expect(subject.ext).to eq('.meta')
25
+ end
26
+ end
27
+
28
+ describe "#gz" do
29
+ subject { super().gz }
30
+
31
+ it { expect(subject).to be_kind_of(GzFeedURI) }
32
+
33
+ it "must have the same name" do
34
+ expect(subject.name).to eq(name)
35
+ end
36
+
37
+ it "must use '.json.gz' for the extension" do
38
+ expect(subject.ext).to eq('.json.gz')
39
+ end
40
+ end
41
+
42
+ describe "#zip" do
43
+ subject { super().zip }
44
+
45
+ it { expect(subject).to be_kind_of(ZipFeedURI) }
46
+
47
+ it "must have the same name" do
48
+ expect(subject.name).to eq(name)
49
+ end
50
+
51
+ it "must use '.json.zip' for the extension" do
52
+ expect(subject.ext).to eq('.json.zip')
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+ require 'nvd/json_feeds/feed_uri'
3
+
4
+ describe FeedURI do
5
+ let(:name) { :recent }
6
+ let(:ext) { '.json.gz' }
7
+
8
+ subject { described_class.new(name,ext) }
9
+
10
+ describe "#initialize" do
11
+ it "must set #name" do
12
+ expect(subject.name).to eq(name)
13
+ end
14
+
15
+ it "must set #ext" do
16
+ expect(subject.ext).to eq(ext)
17
+ end
18
+
19
+ it "must set #filename" do
20
+ expect(subject.filename).to eq("nvdcve-1.1-#{name}#{ext}")
21
+ end
22
+ end
23
+
24
+ describe "#get", :integration do
25
+ let(:contents) { Net::HTTP.get(subject.uri) }
26
+
27
+ context "when not given a block" do
28
+ it "must return the full String of the file" do
29
+ expect(subject.get).to eq(contents)
30
+ end
31
+ end
32
+
33
+ context "when given a block" do
34
+ it "must yield each chunk of the file" do
35
+ chunks = []
36
+
37
+ subject.get { |chunk| chunks << chunk }
38
+
39
+ expect(chunks.join).to eq(contents)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#download", :integration do
45
+ context "when given a file" do
46
+ it "must return the path to the newly downloaded file" do
47
+ end
48
+ end
49
+
50
+ context "when given a directory" do
51
+ it "must return the path to the newly downloaded file in the directory" do
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "#uri" do
57
+ subject { super().uri }
58
+
59
+ it { expect(subject).to be_kind_of(URI::HTTPS) }
60
+
61
+ describe "host" do
62
+ it { expect(subject.host).to eq('nvd.nist.gov') }
63
+ end
64
+
65
+ describe "path" do
66
+ it { expect(subject.path).to start_with('/feeds/json/cve/1.1/') }
67
+ end
68
+ end
69
+
70
+ describe "#to_s" do
71
+ it "must the String version of the URI" do
72
+ expect(subject.to_s).to eq(subject.uri.to_s)
73
+ end
74
+ end
75
+
76
+ describe "#inspect" do
77
+ it "must include the class name and URI" do
78
+ expect(subject.inspect).to eq("#<#{described_class}: #{subject.uri}>")
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,180 @@
1
+ {
2
+ "CVE_data_type" : "CVE",
3
+ "CVE_data_format" : "MITRE",
4
+ "CVE_data_version" : "4.0",
5
+ "CVE_data_numberOfCVEs" : "343",
6
+ "CVE_data_timestamp" : "2020-12-30T11:00Z",
7
+ "CVE_Items" : [ {
8
+ "cve" : {
9
+ "data_type" : "CVE",
10
+ "data_format" : "MITRE",
11
+ "data_version" : "4.0",
12
+ "CVE_data_meta" : {
13
+ "ID" : "CVE-2018-1000891",
14
+ "ASSIGNER" : "cve@mitre.org"
15
+ },
16
+ "problemtype" : {
17
+ "problemtype_data" : [ {
18
+ "description" : [ {
19
+ "lang" : "en",
20
+ "value" : "CWE-400"
21
+ } ]
22
+ } ]
23
+ },
24
+ "references" : {
25
+ "reference_data" : [ {
26
+ "url" : "https://bitcoinsv.io/2019/03/01/denial-of-service-vulnerabilities-repaired-in-bitcoin-sv-version-0-1-1/",
27
+ "name" : "https://bitcoinsv.io/2019/03/01/denial-of-service-vulnerabilities-repaired-in-bitcoin-sv-version-0-1-1/",
28
+ "refsource" : "MISC",
29
+ "tags" : [ "Vendor Advisory" ]
30
+ } ]
31
+ },
32
+ "description" : {
33
+ "description_data" : [ {
34
+ "lang" : "en",
35
+ "value" : "Bitcoin SV before 0.1.1 allows uncontrolled resource consumption when receiving messages with invalid checksums."
36
+ } ]
37
+ }
38
+ },
39
+ "configurations" : {
40
+ "CVE_data_version" : "4.0",
41
+ "nodes" : [ {
42
+ "operator" : "OR",
43
+ "cpe_match" : [ {
44
+ "vulnerable" : true,
45
+ "cpe23Uri" : "cpe:2.3:a:bitcoinsv:bitcoin_sv:*:*:*:*:*:*:*:*",
46
+ "versionEndExcluding" : "0.1.1"
47
+ } ]
48
+ } ]
49
+ },
50
+ "impact" : {
51
+ "baseMetricV3" : {
52
+ "cvssV3" : {
53
+ "version" : "3.1",
54
+ "vectorString" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
55
+ "attackVector" : "NETWORK",
56
+ "attackComplexity" : "LOW",
57
+ "privilegesRequired" : "NONE",
58
+ "userInteraction" : "NONE",
59
+ "scope" : "UNCHANGED",
60
+ "confidentialityImpact" : "NONE",
61
+ "integrityImpact" : "NONE",
62
+ "availabilityImpact" : "HIGH",
63
+ "baseScore" : 7.5,
64
+ "baseSeverity" : "HIGH"
65
+ },
66
+ "exploitabilityScore" : 3.9,
67
+ "impactScore" : 3.6
68
+ },
69
+ "baseMetricV2" : {
70
+ "cvssV2" : {
71
+ "version" : "2.0",
72
+ "vectorString" : "AV:N/AC:L/Au:N/C:N/I:N/A:P",
73
+ "accessVector" : "NETWORK",
74
+ "accessComplexity" : "LOW",
75
+ "authentication" : "NONE",
76
+ "confidentialityImpact" : "NONE",
77
+ "integrityImpact" : "NONE",
78
+ "availabilityImpact" : "PARTIAL",
79
+ "baseScore" : 5.0
80
+ },
81
+ "severity" : "MEDIUM",
82
+ "exploitabilityScore" : 10.0,
83
+ "impactScore" : 2.9,
84
+ "acInsufInfo" : false,
85
+ "obtainAllPrivilege" : false,
86
+ "obtainUserPrivilege" : false,
87
+ "obtainOtherPrivilege" : false,
88
+ "userInteractionRequired" : false
89
+ }
90
+ },
91
+ "publishedDate" : "2020-12-23T17:15Z",
92
+ "lastModifiedDate" : "2020-12-23T20:10Z"
93
+ }, {
94
+ "cve" : {
95
+ "data_type" : "CVE",
96
+ "data_format" : "MITRE",
97
+ "data_version" : "4.0",
98
+ "CVE_data_meta" : {
99
+ "ID" : "CVE-2018-1000892",
100
+ "ASSIGNER" : "cve@mitre.org"
101
+ },
102
+ "problemtype" : {
103
+ "problemtype_data" : [ {
104
+ "description" : [ {
105
+ "lang" : "en",
106
+ "value" : "CWE-400"
107
+ } ]
108
+ } ]
109
+ },
110
+ "references" : {
111
+ "reference_data" : [ {
112
+ "url" : "https://bitcoinsv.io/2019/03/01/denial-of-service-vulnerabilities-repaired-in-bitcoin-sv-version-0-1-1/",
113
+ "name" : "https://bitcoinsv.io/2019/03/01/denial-of-service-vulnerabilities-repaired-in-bitcoin-sv-version-0-1-1/",
114
+ "refsource" : "MISC",
115
+ "tags" : [ "Vendor Advisory" ]
116
+ } ]
117
+ },
118
+ "description" : {
119
+ "description_data" : [ {
120
+ "lang" : "en",
121
+ "value" : "Bitcoin SV before 0.1.1 allows uncontrolled resource consumption when receiving sendheaders messages."
122
+ } ]
123
+ }
124
+ },
125
+ "configurations" : {
126
+ "CVE_data_version" : "4.0",
127
+ "nodes" : [ {
128
+ "operator" : "OR",
129
+ "cpe_match" : [ {
130
+ "vulnerable" : true,
131
+ "cpe23Uri" : "cpe:2.3:a:bitcoinsv:bitcoin_sv:*:*:*:*:*:*:*:*",
132
+ "versionEndExcluding" : "0.1.1"
133
+ } ]
134
+ } ]
135
+ },
136
+ "impact" : {
137
+ "baseMetricV3" : {
138
+ "cvssV3" : {
139
+ "version" : "3.1",
140
+ "vectorString" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
141
+ "attackVector" : "NETWORK",
142
+ "attackComplexity" : "LOW",
143
+ "privilegesRequired" : "NONE",
144
+ "userInteraction" : "NONE",
145
+ "scope" : "UNCHANGED",
146
+ "confidentialityImpact" : "NONE",
147
+ "integrityImpact" : "NONE",
148
+ "availabilityImpact" : "HIGH",
149
+ "baseScore" : 7.5,
150
+ "baseSeverity" : "HIGH"
151
+ },
152
+ "exploitabilityScore" : 3.9,
153
+ "impactScore" : 3.6
154
+ },
155
+ "baseMetricV2" : {
156
+ "cvssV2" : {
157
+ "version" : "2.0",
158
+ "vectorString" : "AV:N/AC:L/Au:N/C:N/I:N/A:P",
159
+ "accessVector" : "NETWORK",
160
+ "accessComplexity" : "LOW",
161
+ "authentication" : "NONE",
162
+ "confidentialityImpact" : "NONE",
163
+ "integrityImpact" : "NONE",
164
+ "availabilityImpact" : "PARTIAL",
165
+ "baseScore" : 5.0
166
+ },
167
+ "severity" : "MEDIUM",
168
+ "exploitabilityScore" : 10.0,
169
+ "impactScore" : 2.9,
170
+ "acInsufInfo" : false,
171
+ "obtainAllPrivilege" : false,
172
+ "obtainUserPrivilege" : false,
173
+ "obtainOtherPrivilege" : false,
174
+ "userInteractionRequired" : false
175
+ }
176
+ },
177
+ "publishedDate" : "2020-12-23T17:15Z",
178
+ "lastModifiedDate" : "2020-12-23T20:10Z"
179
+ } ]
180
+ }