nvd_feed_api 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +3 -0
- data/.gitignore +1 -1
- data/.gitlab-ci.yml +17 -10
- data/.rubocop.yml +15 -5
- data/.tool-versions +1 -0
- data/.yardopts +2 -0
- data/Gemfile +24 -1
- data/Gemfile.lock +64 -0
- data/README.md +2 -1
- data/lib/nvd_feed_api/feed.rb +27 -17
- data/lib/nvd_feed_api/meta.rb +6 -6
- data/lib/nvd_feed_api/version.rb +1 -1
- data/lib/nvd_feed_api.rb +47 -20
- data/nvd_feed_api.gemspec +13 -24
- data/pages/CHANGELOG.md +40 -0
- data/pages/INSTALL.md +2 -9
- data/renovate.json +15 -0
- data/test/test_nvd_feed_api.rb +10 -10
- metadata +29 -128
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d03fa81fd296a62aba7a9356b3c41135851febb254af4db13758c5b76475739f
|
4
|
+
data.tar.gz: c0d716121dccaeaee6944ccd3e0d85cf59854084ae68d0f7347fb678dc4760bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5bef50a5709e8bd53a138110e80f6a5ee34d02f5849e1a3d9add0c9573e963926adbdf6eeb610b75d04d25d285b4450b8e99aa724582d382ed072ef46c89a8a
|
7
|
+
data.tar.gz: 7be0a9191d6efb0e7a80e7a868d8d019186268008473e3e731fe9e4e3e1d21b85b7cc6189c912d5315495dbb12dbaaa688ca077823ba844a01d91b11696ae954
|
data/.github/FUNDING.yml
ADDED
data/.gitignore
CHANGED
data/.gitlab-ci.yml
CHANGED
@@ -1,36 +1,43 @@
|
|
1
1
|
# Official language image. Look for the different tagged releases at:
|
2
2
|
# https://hub.docker.com/r/library/ruby/tags/
|
3
|
-
image: ruby:2.4-alpine
|
4
3
|
|
4
|
+
# Caching: https://docs.gitlab.com/ee/ci/caching/#caching-ruby-dependencies
|
5
5
|
cache:
|
6
|
+
key: ${CI_COMMIT_REF_SLUG}
|
6
7
|
paths:
|
7
8
|
- vendor/ruby # cache gems in between builds
|
8
9
|
|
9
10
|
before_script:
|
10
11
|
- ruby -v # Print out ruby version for debugging
|
11
|
-
- gem install bundler
|
12
|
+
- gem install bundler --no-document # Bundler is not installed with the image
|
12
13
|
# install nproc (coreutils) for bundle -j
|
13
14
|
# install git for building the gemspec
|
14
15
|
# install make, gcc for building gem native extension (commonmarker)
|
15
16
|
# libc-dev for musl-dev dependency (stdlib.h) needed by gcc
|
16
17
|
- apk --no-cache add coreutils git make gcc libc-dev
|
17
18
|
- bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby
|
18
|
-
- rake install # install the gem
|
19
|
+
- bundle exec rake install # install the gem
|
19
20
|
|
20
|
-
|
21
|
+
# Anchors: https://docs.gitlab.com/ee/ci/yaml/README.html#anchors
|
22
|
+
.test_template: &job_definition
|
21
23
|
stage: test
|
22
24
|
script:
|
23
|
-
|
25
|
+
- bundle exec rubocop
|
26
|
+
- bundle exec rake test
|
24
27
|
|
25
|
-
test:
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
#test:2.4:
|
29
|
+
# <<: *job_definition
|
30
|
+
# image: ruby:2.4-alpine
|
31
|
+
|
32
|
+
test:3.1:
|
33
|
+
<<: *job_definition
|
34
|
+
image: ruby:3.1-alpine
|
29
35
|
|
30
36
|
pages:
|
31
37
|
stage: deploy
|
38
|
+
image: ruby:3.1-alpine
|
32
39
|
script:
|
33
|
-
- yard doc
|
40
|
+
- bundle exec yard doc
|
34
41
|
- mkdir public
|
35
42
|
- mv doc/* public/
|
36
43
|
artifacts:
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
2
|
+
TargetRubyVersion: 2.7
|
3
|
+
NewCops: enable
|
4
|
+
|
5
|
+
Layout/HashAlignment:
|
6
|
+
EnforcedHashRocketStyle: table
|
7
|
+
|
8
|
+
Layout/LineLength:
|
9
|
+
Enabled: false
|
3
10
|
|
4
11
|
# Rubocop is too stupid too see that the variable is used
|
5
12
|
Lint/UselessAssignment:
|
@@ -18,10 +25,7 @@ Metrics/ClassLength:
|
|
18
25
|
Enabled: false
|
19
26
|
|
20
27
|
Metrics/CyclomaticComplexity:
|
21
|
-
Max:
|
22
|
-
|
23
|
-
Metrics/LineLength:
|
24
|
-
Enabled: false
|
28
|
+
Max: 25
|
25
29
|
|
26
30
|
Metrics/MethodLength:
|
27
31
|
Max: 100
|
@@ -35,6 +39,9 @@ Naming/VariableName:
|
|
35
39
|
Security/JSONLoad:
|
36
40
|
Enabled: false
|
37
41
|
|
42
|
+
Style/CaseLikeIf:
|
43
|
+
Enabled: true
|
44
|
+
|
38
45
|
Style/FrozenStringLiteralComment:
|
39
46
|
EnforcedStyle: never
|
40
47
|
|
@@ -44,3 +51,6 @@ Style/PerlBackrefs:
|
|
44
51
|
# Allow explicit return
|
45
52
|
Style/RedundantReturn:
|
46
53
|
Enabled: false
|
54
|
+
|
55
|
+
Style/WordArray:
|
56
|
+
EnforcedStyle: brackets
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 3.1.0
|
data/.yardopts
CHANGED
data/Gemfile
CHANGED
@@ -1,4 +1,27 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
# Specify your gem's dependencies in .gemspec
|
4
3
|
gemspec
|
4
|
+
|
5
|
+
group :runtime, :cli do
|
6
|
+
gem 'archive-zip', '~> 0.11'
|
7
|
+
gem 'nokogiri', '~> 1.11'
|
8
|
+
gem 'oj', '>= 3.7.8', '<4'
|
9
|
+
end
|
10
|
+
|
11
|
+
group :development, :install do
|
12
|
+
gem 'bundler', '~> 2.1'
|
13
|
+
end
|
14
|
+
|
15
|
+
group :development, :test do
|
16
|
+
gem 'minitest', '~> 5.12'
|
17
|
+
gem 'rake', '~> 13.0'
|
18
|
+
end
|
19
|
+
|
20
|
+
group :development, :lint do
|
21
|
+
gem 'rubocop', '~> 1.23'
|
22
|
+
end
|
23
|
+
|
24
|
+
group :development, :docs do
|
25
|
+
gem 'commonmarker', '~> 0.21' # for markdown support in YARD
|
26
|
+
gem 'yard', ['>= 0.9.27', '< 0.10']
|
27
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
nvd_feed_api (0.4.0)
|
5
|
+
archive-zip (~> 0.11)
|
6
|
+
nokogiri (~> 1.11)
|
7
|
+
oj (>= 3.7.8, < 4)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
archive-zip (0.12.0)
|
13
|
+
io-like (~> 0.3.0)
|
14
|
+
ast (2.4.2)
|
15
|
+
commonmarker (0.23.2)
|
16
|
+
io-like (0.3.1)
|
17
|
+
mini_portile2 (2.7.1)
|
18
|
+
minitest (5.15.0)
|
19
|
+
nokogiri (1.13.1)
|
20
|
+
mini_portile2 (~> 2.7.0)
|
21
|
+
racc (~> 1.4)
|
22
|
+
oj (3.13.10)
|
23
|
+
parallel (1.21.0)
|
24
|
+
parser (3.0.3.2)
|
25
|
+
ast (~> 2.4.1)
|
26
|
+
racc (1.6.0)
|
27
|
+
rainbow (3.0.0)
|
28
|
+
rake (13.0.6)
|
29
|
+
regexp_parser (2.2.0)
|
30
|
+
rexml (3.2.5)
|
31
|
+
rubocop (1.24.1)
|
32
|
+
parallel (~> 1.10)
|
33
|
+
parser (>= 3.0.0.0)
|
34
|
+
rainbow (>= 2.2.2, < 4.0)
|
35
|
+
regexp_parser (>= 1.8, < 3.0)
|
36
|
+
rexml
|
37
|
+
rubocop-ast (>= 1.15.1, < 2.0)
|
38
|
+
ruby-progressbar (~> 1.7)
|
39
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
40
|
+
rubocop-ast (1.15.1)
|
41
|
+
parser (>= 3.0.1.1)
|
42
|
+
ruby-progressbar (1.11.0)
|
43
|
+
unicode-display_width (2.1.0)
|
44
|
+
webrick (1.7.0)
|
45
|
+
yard (0.9.27)
|
46
|
+
webrick (~> 1.7.0)
|
47
|
+
|
48
|
+
PLATFORMS
|
49
|
+
ruby
|
50
|
+
|
51
|
+
DEPENDENCIES
|
52
|
+
archive-zip (~> 0.11)
|
53
|
+
bundler (~> 2.1)
|
54
|
+
commonmarker (~> 0.21)
|
55
|
+
minitest (~> 5.12)
|
56
|
+
nokogiri (~> 1.11)
|
57
|
+
nvd_feed_api!
|
58
|
+
oj (>= 3.7.8, < 4)
|
59
|
+
rake (~> 13.0)
|
60
|
+
rubocop (~> 1.23)
|
61
|
+
yard (>= 0.9.27, < 0.10)
|
62
|
+
|
63
|
+
BUNDLED WITH
|
64
|
+
2.3.6
|
data/README.md
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
[![Gem stable](https://img.shields.io/gem/dv/nvd_feed_api/stable.svg)][rubygems]
|
6
6
|
[![Gem latest](https://img.shields.io/gem/dtv/nvd_feed_api.svg)][rubygems]
|
7
7
|
[![Gem total download](https://img.shields.io/gem/dt/nvd_feed_api.svg)][rubygems]
|
8
|
+
[![Rawsec's CyberSecurity Inventory](https://inventory.rawsec.ml/img/badges/Rawsec-inventoried-FF5050_flat.svg)](https://inventory.rawsec.ml/tools.html#nvd_feed_api)
|
8
9
|
|
9
10
|
[rubygems]:https://rubygems.org/gems/nvd_feed_api/
|
10
11
|
|
@@ -12,7 +13,7 @@
|
|
12
13
|
|
13
14
|
**nvd_feed_api** is a simple ruby API for NVD CVE feeds.
|
14
15
|
|
15
|
-
The API will help you to download and manage NVD Data Feeds, search for CVEs, build your
|
16
|
+
The API will help you to download and manage NVD Data Feeds, search for CVEs, build your vulnerability assessment platform or vulnerability database.
|
16
17
|
|
17
18
|
Name | Link
|
18
19
|
--- | ---
|
data/lib/nvd_feed_api/feed.rb
CHANGED
@@ -13,7 +13,7 @@ class NVDFeedScraper
|
|
13
13
|
class Feed
|
14
14
|
class << self
|
15
15
|
# Get / set default feed storage location, where will be stored JSON feeds and archives by default.
|
16
|
-
# @return [String] default feed storage location. Default to
|
16
|
+
# @return [String] default feed storage location. Default to `/tmp/`.
|
17
17
|
# @example
|
18
18
|
# NVDFeedScraper::Feed.default_storage_location = '/srv/downloads/'
|
19
19
|
attr_accessor :default_storage_location
|
@@ -69,11 +69,11 @@ class NVDFeedScraper
|
|
69
69
|
# f.json_file # => "/tmp/nvdcve-1.0-2014.json"
|
70
70
|
attr_reader :json_file
|
71
71
|
|
72
|
-
# @return [String] the type of the feed, should always be
|
72
|
+
# @return [String] the type of the feed, should always be `CVE`.
|
73
73
|
# @note Return nil if not previously loaded by {#json_pull}.
|
74
74
|
attr_reader :data_type
|
75
75
|
|
76
|
-
# @return [String] the format of the feed, should always be
|
76
|
+
# @return [String] the format of the feed, should always be `MITRE`.
|
77
77
|
# @note Return nil if not previously loaded by {#json_pull}.
|
78
78
|
attr_reader :data_format
|
79
79
|
|
@@ -96,7 +96,7 @@ class NVDFeedScraper
|
|
96
96
|
# @param gz_url [String] see {#gz_url}.
|
97
97
|
# @param zip_url [String] see {#zip_url}.
|
98
98
|
def initialize(name, updated, meta_url, gz_url, zip_url)
|
99
|
-
#
|
99
|
+
# From meta file
|
100
100
|
@name = name
|
101
101
|
@updated = updated
|
102
102
|
@meta_url = meta_url
|
@@ -146,7 +146,7 @@ class NVDFeedScraper
|
|
146
146
|
# Download the JSON feed and fill the attribute.
|
147
147
|
# @param opts [Hash] see {#download_file}.
|
148
148
|
# @return [String] the path of the saved JSON file. Default use {Feed#default_storage_location}.
|
149
|
-
# @note Will
|
149
|
+
# @note Will download and save the zip of the JSON file, unzip and save it. This massively consume time.
|
150
150
|
# @see #json_file
|
151
151
|
def json_pull(opts = {})
|
152
152
|
opts[:destination_path] ||= Feed.default_storage_location
|
@@ -184,6 +184,7 @@ class NVDFeedScraper
|
|
184
184
|
# Verify hash integrity
|
185
185
|
computed_h = Digest::SHA256.file(@json_file)
|
186
186
|
raise "File corruption: #{@json_file}" unless meta.sha256.casecmp(computed_h.hexdigest).zero?
|
187
|
+
|
187
188
|
# update data
|
188
189
|
doc = Oj::Doc.open(File.read(@json_file))
|
189
190
|
@data_type = doc.fetch('/CVE_data_type')
|
@@ -223,11 +224,15 @@ class NVDFeedScraper
|
|
223
224
|
def cve(*arg_cve)
|
224
225
|
raise 'json_file is nil, it needs to be populated with json_pull' if @json_file.nil?
|
225
226
|
raise "json_file (#{@json_file}) doesn't exist" unless File.file?(@json_file)
|
227
|
+
|
226
228
|
return_value = nil
|
227
229
|
raise 'no argument provided, 1 or more expected' if arg_cve.empty?
|
230
|
+
|
228
231
|
if arg_cve.length == 1
|
229
|
-
|
232
|
+
case arg_cve[0]
|
233
|
+
when String
|
230
234
|
raise "bad CVE name (#{arg_cve[0]})" unless /^CVE-[0-9]{4}-[0-9]{4,}$/i.match?(arg_cve[0])
|
235
|
+
|
231
236
|
doc = Oj::Doc.open(File.read(@json_file))
|
232
237
|
# Quicker than doc.fetch('/CVE_Items').size
|
233
238
|
(1..@data_number_of_cves).each do |i|
|
@@ -237,13 +242,14 @@ class NVDFeedScraper
|
|
237
242
|
end
|
238
243
|
end
|
239
244
|
doc.close
|
240
|
-
|
245
|
+
when Array
|
241
246
|
return_value = []
|
242
247
|
# Sorting CVE can allow us to parse quicker
|
243
248
|
# Upcase to be sure include? works
|
244
249
|
cves_to_find = arg_cve[0].map(&:upcase).sort
|
245
250
|
raise 'one of the provided arguments is not a String' unless cves_to_find.all? { |x| x.is_a?(String) }
|
246
251
|
raise 'bad CVE name' unless cves_to_find.all? { |x| /^CVE-[0-9]{4}-[0-9]{4,}$/i.match?(x) }
|
252
|
+
|
247
253
|
doc = Oj::Doc.open(File.read(@json_file))
|
248
254
|
# Quicker than doc.fetch('/CVE_Items').size
|
249
255
|
(1..@data_number_of_cves).each do |i|
|
@@ -273,6 +279,7 @@ class NVDFeedScraper
|
|
273
279
|
def available_cves
|
274
280
|
raise 'json_file is nil, it needs to be populated with json_pull' if @json_file.nil?
|
275
281
|
raise "json_file (#{@json_file}) doesn't exist" unless File.file?(@json_file)
|
282
|
+
|
276
283
|
doc = Oj::Doc.open(File.read(@json_file))
|
277
284
|
# Quicker than doc.fetch('/CVE_Items').size
|
278
285
|
cve_names = []
|
@@ -290,6 +297,7 @@ class NVDFeedScraper
|
|
290
297
|
# 'CVE-2007'
|
291
298
|
def name=(arg_name)
|
292
299
|
raise "name (#{arg_name}) is not a string" unless arg_name.is_a?(String)
|
300
|
+
|
293
301
|
@name = arg_name
|
294
302
|
end
|
295
303
|
|
@@ -299,6 +307,7 @@ class NVDFeedScraper
|
|
299
307
|
# '10/19/2017 3:27:02 AM -04:00'
|
300
308
|
def updated=(arg_updated)
|
301
309
|
raise "updated date (#{arg_updated}) is not a string" unless arg_updated.is_a?(String)
|
310
|
+
|
302
311
|
@updated = arg_updated
|
303
312
|
end
|
304
313
|
|
@@ -308,6 +317,7 @@ class NVDFeedScraper
|
|
308
317
|
# 'https://static.nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-2007.meta'
|
309
318
|
def meta_url=(arg_meta_url)
|
310
319
|
raise "meta_url (#{arg_meta_url}) is not a string" unless arg_meta_url.is_a?(String)
|
320
|
+
|
311
321
|
@meta_url = arg_meta_url
|
312
322
|
end
|
313
323
|
|
@@ -317,6 +327,7 @@ class NVDFeedScraper
|
|
317
327
|
# 'https://static.nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-2007.json.gz'
|
318
328
|
def gz_url=(arg_gz_url)
|
319
329
|
raise "gz_url (#{arg_gz_url}) is not a string" unless arg_gz_url.is_a?(String)
|
330
|
+
|
320
331
|
@gz_url = arg_gz_url
|
321
332
|
end
|
322
333
|
|
@@ -326,6 +337,7 @@ class NVDFeedScraper
|
|
326
337
|
# 'https://static.nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-2007.json.zip'
|
327
338
|
def zip_url=(arg_zip_url)
|
328
339
|
raise "zip_url (#{arg_zip_url}) is not a string" unless arg_zip_url.is_a?(String)
|
340
|
+
|
329
341
|
@zip_url = arg_zip_url
|
330
342
|
end
|
331
343
|
|
@@ -352,30 +364,28 @@ class NVDFeedScraper
|
|
352
364
|
uri = URI(file_url)
|
353
365
|
filename = uri.path.split('/').last
|
354
366
|
destination_file = destination_path + filename
|
355
|
-
|
356
|
-
if
|
357
|
-
|
358
|
-
|
359
|
-
skip_download = true if opts[:sha256].casecmp(computed_h.hexdigest).zero?
|
360
|
-
end
|
367
|
+
if !opts[:sha256].nil? && File.file?(destination_file)
|
368
|
+
# Verify hash to see if it is the latest
|
369
|
+
computed_h = Digest::SHA256.file(destination_file)
|
370
|
+
skip_download = true if opts[:sha256].casecmp(computed_h.hexdigest).zero?
|
361
371
|
end
|
362
372
|
unless skip_download
|
363
373
|
res = Net::HTTP.get_response(uri)
|
364
374
|
raise "#{file_url} ended with #{res.code} #{res.message}" unless res.is_a?(Net::HTTPSuccess)
|
365
|
-
|
366
|
-
|
367
|
-
end
|
375
|
+
|
376
|
+
File.binwrite(destination_file, res.body)
|
368
377
|
end
|
369
378
|
return destination_file
|
370
379
|
end
|
371
380
|
|
372
381
|
# Update the feed
|
373
382
|
# @param fresh_feed [Feed] the fresh feed from which the feed will be updated.
|
374
|
-
# @return [Boolean]
|
383
|
+
# @return [Boolean] `true` if the feed was updated, `false` if it wasn't.
|
375
384
|
# @note Is not intended to be used directly, use {NVDFeedScraper#update_feeds} instead.
|
376
385
|
def update!(fresh_feed)
|
377
386
|
return_value = false
|
378
387
|
raise "#{fresh_feed} is not a Feed" unless fresh_feed.is_a?(Feed)
|
388
|
+
|
379
389
|
# update attributes
|
380
390
|
if updated != fresh_feed.updated
|
381
391
|
self.name = fresh_feed.name
|
data/lib/nvd_feed_api/meta.rb
CHANGED
@@ -76,26 +76,26 @@ class NVDFeedScraper
|
|
76
76
|
# Parse the meta file from the URL and set the attributes.
|
77
77
|
# @overload parse
|
78
78
|
# Parse the meta file from the URL and set the attributes.
|
79
|
-
# @return [Integer] Returns
|
79
|
+
# @return [Integer] Returns `0` when there is no error.
|
80
80
|
# @overload parse(url)
|
81
81
|
# Set the URL of the meta file of the feed and
|
82
82
|
# parse the meta file from the URL and set the attributes.
|
83
83
|
# @param url [String] see {Feed.meta_url}
|
84
|
-
# @return [Integer] Returns
|
84
|
+
# @return [Integer] Returns `0` when there is no error.
|
85
85
|
def parse(*arg)
|
86
|
-
if arg.
|
87
|
-
elsif arg.length == 1 # arg = url
|
86
|
+
if arg.length == 1 # arg = url
|
88
87
|
self.url = arg[0]
|
89
|
-
|
88
|
+
elsif arg.length > 1
|
90
89
|
raise 'Too much arguments'
|
91
90
|
end
|
92
91
|
|
93
92
|
raise "Can't parse if the URL is empty" if @url.nil?
|
93
|
+
|
94
94
|
uri = URI(@url)
|
95
95
|
|
96
96
|
meta = Net::HTTP.get(uri)
|
97
97
|
|
98
|
-
meta =
|
98
|
+
meta = meta.split.to_h { |x| x.split(':', 2) }
|
99
99
|
|
100
100
|
raise 'no lastModifiedDate attribute found' unless meta['lastModifiedDate']
|
101
101
|
raise 'no valid size attribute found' unless /[0-9]+/.match?(meta['size'])
|
data/lib/nvd_feed_api/version.rb
CHANGED
data/lib/nvd_feed_api.rb
CHANGED
@@ -18,8 +18,9 @@ require 'nvd_feed_api/feed'
|
|
18
18
|
# scraper.feeds("CVE-2007")
|
19
19
|
# cve2007, cve2015 = scraper.feeds("CVE-2007", "CVE-2015")
|
20
20
|
class NVDFeedScraper
|
21
|
+
BASE = 'https://nvd.nist.gov'.freeze
|
21
22
|
# The NVD url where is located the data feeds.
|
22
|
-
URL =
|
23
|
+
URL = "#{BASE}/vuln/data-feeds".freeze
|
23
24
|
# Load constants
|
24
25
|
include NvdFeedApi
|
25
26
|
|
@@ -31,21 +32,34 @@ class NVDFeedScraper
|
|
31
32
|
|
32
33
|
# Scrap / parse the website to get the feeds and fill the {#feeds} attribute.
|
33
34
|
# @note {#scrap} need to be called only once but can be called again to update if the NVD feed page changed.
|
34
|
-
# @return [Integer]
|
35
|
+
# @return [Integer] Number of scrapped feeds.
|
35
36
|
def scrap
|
36
37
|
uri = URI(@url)
|
37
38
|
html = Net::HTTP.get(uri)
|
38
39
|
|
39
40
|
doc = Nokogiri::HTML(html)
|
40
41
|
@feeds = []
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
tmp_feeds = {}
|
43
|
+
doc.css('#vuln-feed-table table.xml-feed-table tr[data-testid]').each do |tr|
|
44
|
+
num, type = tr.attr('data-testid')[13..].split('-')
|
45
|
+
case type
|
46
|
+
when 'meta'
|
47
|
+
tmp_feeds[num] = {}
|
48
|
+
tmp_feeds[num][:name] = tr.css('td')[0].text
|
49
|
+
tmp_feeds[num][:updated] = tr.css('td')[1].text
|
50
|
+
tmp_feeds[num][:meta] = BASE + tr.css('td')[2].css('> a').attr('href').value
|
51
|
+
when 'gz'
|
52
|
+
tmp_feeds[num][:gz] = BASE + tr.css('td > a').attr('href').value
|
53
|
+
when 'zip'
|
54
|
+
tmp_feeds[num][:zip] = BASE + tr.css('td > a').attr('href').value
|
55
|
+
@feeds.push(Feed.new(tmp_feeds[num][:name],
|
56
|
+
tmp_feeds[num][:updated],
|
57
|
+
tmp_feeds[num][:meta],
|
58
|
+
tmp_feeds[num][:gz],
|
59
|
+
tmp_feeds[num][:zip]))
|
60
|
+
end
|
48
61
|
end
|
62
|
+
return @feeds.size
|
49
63
|
end
|
50
64
|
|
51
65
|
# Return feeds. Can only be called after {#scrap}.
|
@@ -72,17 +86,20 @@ class NVDFeedScraper
|
|
72
86
|
# @see https://nvd.nist.gov/vuln/data-feeds
|
73
87
|
def feeds(*arg_feeds)
|
74
88
|
raise 'call scrap method before using feeds method' if @feeds.nil?
|
89
|
+
|
75
90
|
return_value = nil
|
76
91
|
if arg_feeds.empty?
|
77
92
|
return_value = @feeds
|
78
93
|
elsif arg_feeds.length == 1
|
79
|
-
|
94
|
+
case arg_feeds[0]
|
95
|
+
when String
|
80
96
|
@feeds.each do |feed| # feed is an object
|
81
97
|
return_value = feed if arg_feeds.include?(feed.name)
|
82
98
|
end
|
83
99
|
# if nothing found return nil
|
84
|
-
|
100
|
+
when Array
|
85
101
|
raise 'one of the provided arguments is not a String' unless arg_feeds[0].all? { |x| x.is_a?(String) }
|
102
|
+
|
86
103
|
# Sorting CVE can allow us to parse quicker
|
87
104
|
# Upcase to be sure include? works
|
88
105
|
# Does not use map(&:upcase) to preserve CVE-Recent and CVE-Modified
|
@@ -114,6 +131,7 @@ class NVDFeedScraper
|
|
114
131
|
# scraper.available_feeds => ["CVE-Modified", "CVE-Recent", "CVE-2017", "CVE-2016", "CVE-2015", "CVE-2014", "CVE-2013", "CVE-2012", "CVE-2011", "CVE-2010", "CVE-2009", "CVE-2008", "CVE-2007", "CVE-2006", "CVE-2005", "CVE-2004", "CVE-2003", "CVE-2002"]
|
115
132
|
def available_feeds
|
116
133
|
raise 'call scrap method before using available_feeds method' if @feeds.nil?
|
134
|
+
|
117
135
|
feed_names = []
|
118
136
|
@feeds.each do |feed| # feed is an objet
|
119
137
|
feed_names.push(feed.name)
|
@@ -146,9 +164,12 @@ class NVDFeedScraper
|
|
146
164
|
def cve(*arg_cve)
|
147
165
|
return_value = nil
|
148
166
|
raise 'no argument provided, 1 or more expected' if arg_cve.empty?
|
167
|
+
|
149
168
|
if arg_cve.length == 1
|
150
|
-
|
169
|
+
case arg_cve[0]
|
170
|
+
when String
|
151
171
|
raise 'bad CVE name' unless /^CVE-[0-9]{4}-[0-9]{4,}$/i.match?(arg_cve[0])
|
172
|
+
|
152
173
|
year = /^CVE-([0-9]{4})-[0-9]{4,}$/i.match(arg_cve[0]).captures[0]
|
153
174
|
matched_feed = nil
|
154
175
|
feed_names = available_feeds
|
@@ -163,12 +184,14 @@ class NVDFeedScraper
|
|
163
184
|
# CVE-2002 feed (the 1st one) contains CVE from 1999 to 2002
|
164
185
|
matched_feed = 'CVE-2002' if matched_feed.nil? && ('1999'..'2001').to_a.include?(year)
|
165
186
|
raise "bad CVE year in #{arg_cve}" if matched_feed.nil?
|
187
|
+
|
166
188
|
f = feeds(matched_feed)
|
167
189
|
f.json_pull
|
168
190
|
return_value = f.cve(arg_cve[0])
|
169
|
-
|
191
|
+
when Array
|
170
192
|
raise 'one of the provided arguments is not a String' unless arg_cve[0].all? { |x| x.is_a?(String) }
|
171
193
|
raise 'bad CVE name' unless arg_cve[0].all? { |x| /^CVE-[0-9]{4}-[0-9]{4,}$/i.match?(x) }
|
194
|
+
|
172
195
|
return_value = []
|
173
196
|
# Sorting CVE can allow us to parse quicker
|
174
197
|
# Upcase to be sure include? works
|
@@ -185,6 +208,7 @@ class NVDFeedScraper
|
|
185
208
|
# So virtually add those feed...
|
186
209
|
feed_names.merge(virtual_feeds)
|
187
210
|
raise 'unexisting CVE year was provided in some CVE' unless feeds_to_match.subset?(feed_names)
|
211
|
+
|
188
212
|
matched_feeds = feeds_to_match.intersection(feed_names)
|
189
213
|
# and now that the intersection is done remove those virtual feeds and add CVE-2002 instead if needed
|
190
214
|
unless matched_feeds.intersection(virtual_feeds.to_set).empty?
|
@@ -195,9 +219,10 @@ class NVDFeedScraper
|
|
195
219
|
feeds_arr.each do |feed|
|
196
220
|
feed.json_pull
|
197
221
|
cves_obj = feed.cve(cves_to_find.select { |cve| cve.include?(feed.name) })
|
198
|
-
|
222
|
+
case cves_obj
|
223
|
+
when Hash
|
199
224
|
return_value.push(cves_obj)
|
200
|
-
|
225
|
+
when Array
|
201
226
|
return_value.push(*cves_obj)
|
202
227
|
else
|
203
228
|
raise 'cve() method of the feed instance returns wrong value'
|
@@ -217,16 +242,16 @@ class NVDFeedScraper
|
|
217
242
|
# @overload update_feeds(feed)
|
218
243
|
# One feed.
|
219
244
|
# @param feed [Feed] feed object to update.
|
220
|
-
# @return [Boolean]
|
245
|
+
# @return [Boolean] `true` if the feed was updated, `false` if it wasn't.
|
221
246
|
# @overload update_feeds(feed_arr)
|
222
247
|
# An array of feed.
|
223
248
|
# @param feed_arr [Array<Feed>] array of feed objects to update.
|
224
|
-
# @return [Array<Boolean>]
|
249
|
+
# @return [Array<Boolean>] `true` if the feed was updated, `false` if it wasn't.
|
225
250
|
# @overload update_feeds(feed, *)
|
226
251
|
# Multiple feeds.
|
227
252
|
# @param feed [Feed] feed object to update.
|
228
253
|
# @param * [Feed] As many feed objects as you want.
|
229
|
-
# @return [Array<Boolean>]
|
254
|
+
# @return [Array<Boolean>] `true` if the feed was updated, `false` if it wasn't.
|
230
255
|
# @example
|
231
256
|
# s = NVDFeedScraper.new
|
232
257
|
# s.scrap
|
@@ -235,13 +260,15 @@ class NVDFeedScraper
|
|
235
260
|
def update_feeds(*arg_feed)
|
236
261
|
return_value = false
|
237
262
|
raise 'no argument provided, 1 or more expected' if arg_feed.empty?
|
263
|
+
|
238
264
|
scrap
|
239
265
|
if arg_feed.length == 1
|
240
|
-
|
266
|
+
case arg_feed[0]
|
267
|
+
when Feed
|
241
268
|
new_feed = feeds(arg_feed[0].name)
|
242
269
|
# update attributes
|
243
270
|
return_value = arg_feed[0].update!(new_feed)
|
244
|
-
|
271
|
+
when Array
|
245
272
|
return_value = []
|
246
273
|
arg_feed[0].each do |f|
|
247
274
|
res = update_feeds(f)
|
data/nvd_feed_api.gemspec
CHANGED
@@ -1,12 +1,9 @@
|
|
1
|
-
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require 'nvd_feed_api/version'
|
1
|
+
require_relative 'lib/nvd_feed_api/version'
|
4
2
|
|
5
3
|
Gem::Specification.new do |s|
|
6
4
|
s.name = 'nvd_feed_api'
|
7
5
|
s.version = NvdFeedApi::VERSION
|
8
6
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.date = '2018-01-06'
|
10
7
|
s.summary = 'API for NVD CVE feeds'
|
11
8
|
s.description = 'A simple API for NVD CVE feeds'
|
12
9
|
s.authors = ['Alexandre ZANNI']
|
@@ -20,27 +17,19 @@ Gem::Specification.new do |s|
|
|
20
17
|
s.require_paths = ['lib']
|
21
18
|
|
22
19
|
s.metadata = {
|
23
|
-
'yard.run'
|
24
|
-
'bug_tracker_uri'
|
25
|
-
'changelog_uri'
|
26
|
-
'documentation_uri'
|
27
|
-
'homepage_uri'
|
28
|
-
'source_code_uri'
|
29
|
-
'wiki_uri'
|
20
|
+
'yard.run' => 'yard',
|
21
|
+
'bug_tracker_uri' => 'https://gitlab.com/noraj/nvd_api/issues',
|
22
|
+
'changelog_uri' => 'https://noraj.gitlab.io/nvd_api/file.CHANGELOG.html',
|
23
|
+
'documentation_uri' => 'https://noraj.gitlab.io/nvd_api/',
|
24
|
+
'homepage_uri' => 'https://noraj.gitlab.io/nvd_api/',
|
25
|
+
'source_code_uri' => 'https://gitlab.com/noraj/nvd_api/tree/master',
|
26
|
+
'wiki_uri' => 'https://gitlab.com/noraj/nvd_api/wikis/home',
|
27
|
+
'rubygems_mfa_required' => 'true'
|
30
28
|
}
|
31
29
|
|
32
|
-
s.required_ruby_version = '
|
30
|
+
s.required_ruby_version = ['>= 2.7.0', '< 3.2']
|
33
31
|
|
34
|
-
s.add_dependency('archive-zip', '~> 0.
|
35
|
-
s.add_dependency('nokogiri', '~> 1.
|
36
|
-
s.add_dependency('oj', '
|
37
|
-
|
38
|
-
s.add_development_dependency('bundler', '~> 1.15')
|
39
|
-
s.add_development_dependency('commonmarker', '~> 0.17') # for GMF support in YARD
|
40
|
-
s.add_development_dependency('github-markup', '~> 1.6') # for GMF support in YARD
|
41
|
-
s.add_development_dependency('minitest', '~> 5.10')
|
42
|
-
s.add_development_dependency('rake', '~> 12.3')
|
43
|
-
s.add_development_dependency('redcarpet', '~> 3.4') # for GMF support in YARD
|
44
|
-
s.add_development_dependency('rubocop', '~> 0.51')
|
45
|
-
s.add_development_dependency('yard', '~> 0.9')
|
32
|
+
s.add_dependency('archive-zip', '~> 0.11')
|
33
|
+
s.add_dependency('nokogiri', '~> 1.11')
|
34
|
+
s.add_dependency('oj', '>= 3.7.8', '<4')
|
46
35
|
end
|
data/pages/CHANGELOG.md
CHANGED
@@ -1,3 +1,43 @@
|
|
1
|
+
# [unreleased]
|
2
|
+
|
3
|
+
# [0.4.0] - 31 January 2021
|
4
|
+
|
5
|
+
- Dependencies:
|
6
|
+
- Update to yard [v0.9.27](https://github.com/lsegal/yard/releases/tag/v0.9.27)
|
7
|
+
- Move from Redcarpet to CommonMarker markdown provider
|
8
|
+
- Move doc syntax from Rdoc to markdown
|
9
|
+
- Move dev dependencies from gemspec to gemfile
|
10
|
+
- Chore:
|
11
|
+
- Add support for Ruby 3.1
|
12
|
+
- Update rubocop rules
|
13
|
+
|
14
|
+
# [0.3.1] - 13 October 2020
|
15
|
+
|
16
|
+
[0.3.1]: https://gitlab.com/noraj/nvd_api/tags/v0.3.1
|
17
|
+
|
18
|
+
- fix scrap method to reflect NVD feeds page changes
|
19
|
+
- update dependencies
|
20
|
+
- update rubocop rules
|
21
|
+
|
22
|
+
# [0.3.0] - 22 January 2019
|
23
|
+
|
24
|
+
[0.3.0]: https://gitlab.com/noraj/nvd_api/tags/v0.3.0
|
25
|
+
|
26
|
+
- update dependencies: updated gemspec, ruby 2.6 support, fix gem doc flag, fix oj crash (seg fault)
|
27
|
+
- Gemfile.lock: now Gemfile.lock is not ignored anymore
|
28
|
+
- gitlab-ci: add ruby 2.6 test, add caching key, and anchors for better reuse, always use bundle
|
29
|
+
- NVDFeedScraper `scrap` method: change return value
|
30
|
+
- rubocop: fix lint
|
31
|
+
|
32
|
+
# [0.2.1] - 2 May 2018
|
33
|
+
|
34
|
+
[0.2.1]: https://gitlab.com/noraj/nvd_api/tags/v0.2.1
|
35
|
+
|
36
|
+
- Gitlab-CI: test with ruby 2.4.x and 2.5.x
|
37
|
+
- style: fix Style/ExpandPathArguments cop
|
38
|
+
- security: fix Security/Open cop, protect from pipe command injection
|
39
|
+
- test: fix NVD URL after NVD changed it
|
40
|
+
|
1
41
|
# [0.2.0] - 20 January 2018
|
2
42
|
|
3
43
|
[0.2.0]: https://gitlab.com/noraj/nvd_api/tags/v0.2.0
|
data/pages/INSTALL.md
CHANGED
@@ -10,14 +10,7 @@ $ gem install nvd_feed_api
|
|
10
10
|
|
11
11
|
## Development
|
12
12
|
|
13
|
-
It's better to use [
|
14
|
-
|
15
|
-
To keep clean gem dependencies create a gemset with rvm:
|
16
|
-
|
17
|
-
```
|
18
|
-
$ rvm gemset create nvd_feed_api
|
19
|
-
$ rvm gemset use nvd_feed_api
|
20
|
-
```
|
13
|
+
It's better to use [rbenv](https://github.com/rbenv/rbenv) to have latests version of ruby and to avoid trashing your system ruby.
|
21
14
|
|
22
15
|
### Install from rubygems.org
|
23
16
|
|
@@ -53,7 +46,7 @@ Note: if an automatic install is needed you can get the version with `$ gem buil
|
|
53
46
|
|
54
47
|
### Run the API in irb without installing the gem
|
55
48
|
|
56
|
-
|
49
|
+
Useful when you want to try your changes without building the gem and re-installing it each time.
|
57
50
|
|
58
51
|
```
|
59
52
|
$ git clone https://gitlab.com/noraj/nvd_api.git nvd_feed_api
|
data/renovate.json
ADDED
data/test/test_nvd_feed_api.rb
CHANGED
@@ -9,7 +9,7 @@ class NVDAPITest < Minitest::Test
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def test_scraper_scrap
|
12
|
-
|
12
|
+
assert_operator(0, :<, @s.scrap, 'scrap method returns nothing')
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_scraper_feeds_noarg
|
@@ -78,7 +78,7 @@ class NVDAPITest < Minitest::Test
|
|
78
78
|
f2017, f2016, f_modified = @s.feeds('CVE-2017', 'CVE-2016', 'CVE-Modified')
|
79
79
|
# one arg
|
80
80
|
# can't use assert_instance_of because there is no boolean class
|
81
|
-
assert(
|
81
|
+
assert(['TrueClass', 'FalseClass'].include?(@s.update_feeds(f2017).class.to_s), "update_feeds doesn't return a boolean")
|
82
82
|
# two args
|
83
83
|
assert_instance_of(Array, @s.update_feeds(f2017, f2016), "update_feeds doesn't return an array")
|
84
84
|
refute_empty(@s.update_feeds(f2017, f2016), 'update_feeds returns an empty array')
|
@@ -109,9 +109,9 @@ class NVDAPITest < Minitest::Test
|
|
109
109
|
|
110
110
|
def test_feed_attributes
|
111
111
|
name = 'CVE-2010'
|
112
|
-
meta_url = 'https://
|
113
|
-
gz_url = 'https://
|
114
|
-
zip_url = 'https://
|
112
|
+
meta_url = 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-2010.meta'
|
113
|
+
gz_url = 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-2010.json.gz'
|
114
|
+
zip_url = 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-2010.json.zip'
|
115
115
|
f = @s.feeds('CVE-2010')
|
116
116
|
# Test name
|
117
117
|
assert_instance_of(String, f.name, "name doesn't return a string")
|
@@ -231,7 +231,7 @@ class NVDAPITest < Minitest::Test
|
|
231
231
|
f_new = @s.feeds('CVE-2006')
|
232
232
|
# Right arg
|
233
233
|
# can't use assert_instance_of because there is no boolean class
|
234
|
-
assert(
|
234
|
+
assert(['TrueClass', 'FalseClass'].include?(f.update!(f_new).class.to_s), "update! doesn't return a boolean")
|
235
235
|
# Bad arg
|
236
236
|
err = assert_raises(RuntimeError) do
|
237
237
|
f.update!('bad_arg')
|
@@ -240,25 +240,25 @@ class NVDAPITest < Minitest::Test
|
|
240
240
|
end
|
241
241
|
|
242
242
|
def test_meta_parse_noarg
|
243
|
-
m = NVDFeedScraper::Meta.new('https://
|
243
|
+
m = NVDFeedScraper::Meta.new('https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-2015.meta')
|
244
244
|
assert_equal(0, m.parse, 'parse method return nothing')
|
245
245
|
end
|
246
246
|
|
247
247
|
def test_meta_parse_witharg
|
248
248
|
m = NVDFeedScraper::Meta.new
|
249
|
-
meta_url = 'https://
|
249
|
+
meta_url = 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-2015.meta'
|
250
250
|
assert_equal(0, m.parse(meta_url), 'parse method return nothing')
|
251
251
|
end
|
252
252
|
|
253
253
|
def test_meta_url_setter
|
254
254
|
m = NVDFeedScraper::Meta.new
|
255
|
-
meta_url = 'https://
|
255
|
+
meta_url = 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-2015.meta'
|
256
256
|
assert_equal(meta_url, m.url = meta_url, 'the meta URL is not set correctly')
|
257
257
|
end
|
258
258
|
|
259
259
|
def test_meta_attributes
|
260
260
|
m = NVDFeedScraper::Meta.new
|
261
|
-
meta_url = 'https://
|
261
|
+
meta_url = 'https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-2015.meta'
|
262
262
|
m.url = meta_url
|
263
263
|
m.parse
|
264
264
|
# Test gz_size
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nvd_feed_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexandre ZANNI
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: archive-zip
|
@@ -16,154 +16,48 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.11'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.11'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: nokogiri
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.11'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.11'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: oj
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '3.3'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '3.3'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: bundler
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.15'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.15'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: commonmarker
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0.17'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0.17'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: github-markup
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '1.6'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '1.6'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: minitest
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
45
|
+
- - ">="
|
102
46
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
104
|
-
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '5.10'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rake
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '12.3'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '12.3'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: redcarpet
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - "~>"
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '3.4'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - "~>"
|
47
|
+
version: 3.7.8
|
48
|
+
- - "<"
|
137
49
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
139
|
-
|
140
|
-
name: rubocop
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - "~>"
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0.51'
|
146
|
-
type: :development
|
50
|
+
version: '4'
|
51
|
+
type: :runtime
|
147
52
|
prerelease: false
|
148
53
|
version_requirements: !ruby/object:Gem::Requirement
|
149
54
|
requirements:
|
150
|
-
- - "
|
55
|
+
- - ">="
|
151
56
|
- !ruby/object:Gem::Version
|
152
|
-
version:
|
153
|
-
-
|
154
|
-
name: yard
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - "~>"
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: '0.9'
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - "~>"
|
57
|
+
version: 3.7.8
|
58
|
+
- - "<"
|
165
59
|
- !ruby/object:Gem::Version
|
166
|
-
version: '
|
60
|
+
version: '4'
|
167
61
|
description: A simple API for NVD CVE feeds
|
168
62
|
email: alexandre.zanni@europe.com
|
169
63
|
executables:
|
@@ -173,6 +67,7 @@ executables:
|
|
173
67
|
extensions: []
|
174
68
|
extra_rdoc_files: []
|
175
69
|
files:
|
70
|
+
- ".github/FUNDING.yml"
|
176
71
|
- ".gitignore"
|
177
72
|
- ".gitlab-ci.yml"
|
178
73
|
- ".gitlab/CONTRIBUTING.md"
|
@@ -180,8 +75,10 @@ files:
|
|
180
75
|
- ".gitlab/issue_templates/Feature_proposal.md"
|
181
76
|
- ".gitlab/merge_request_templates/MR.md"
|
182
77
|
- ".rubocop.yml"
|
78
|
+
- ".tool-versions"
|
183
79
|
- ".yardopts"
|
184
80
|
- Gemfile
|
81
|
+
- Gemfile.lock
|
185
82
|
- LICENSE.txt
|
186
83
|
- README.md
|
187
84
|
- Rakefile
|
@@ -197,6 +94,7 @@ files:
|
|
197
94
|
- pages/EXAMPLES.md
|
198
95
|
- pages/FEATURES.md
|
199
96
|
- pages/INSTALL.md
|
97
|
+
- renovate.json
|
200
98
|
- test/test_nvd_feed_api.rb
|
201
99
|
homepage: https://noraj.gitlab.io/nvd_api/
|
202
100
|
licenses:
|
@@ -209,24 +107,27 @@ metadata:
|
|
209
107
|
homepage_uri: https://noraj.gitlab.io/nvd_api/
|
210
108
|
source_code_uri: https://gitlab.com/noraj/nvd_api/tree/master
|
211
109
|
wiki_uri: https://gitlab.com/noraj/nvd_api/wikis/home
|
212
|
-
|
110
|
+
rubygems_mfa_required: 'true'
|
111
|
+
post_install_message:
|
213
112
|
rdoc_options: []
|
214
113
|
require_paths:
|
215
114
|
- lib
|
216
115
|
required_ruby_version: !ruby/object:Gem::Requirement
|
217
116
|
requirements:
|
218
|
-
- - "
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: 2.7.0
|
120
|
+
- - "<"
|
219
121
|
- !ruby/object:Gem::Version
|
220
|
-
version: '2
|
122
|
+
version: '3.2'
|
221
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
222
124
|
requirements:
|
223
125
|
- - ">="
|
224
126
|
- !ruby/object:Gem::Version
|
225
127
|
version: '0'
|
226
128
|
requirements: []
|
227
|
-
|
228
|
-
|
229
|
-
signing_key:
|
129
|
+
rubygems_version: 3.3.3
|
130
|
+
signing_key:
|
230
131
|
specification_version: 4
|
231
132
|
summary: API for NVD CVE feeds
|
232
133
|
test_files:
|