yavdb 0.1.0.pre.alpha.2
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.
- checksums.yaml +7 -0
- data/.circleci/config.yml +48 -0
- data/.gitignore +115 -0
- data/.rspec +3 -0
- data/.rubocop.yml +339 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +85 -0
- data/LICENSE +661 -0
- data/README.md +87 -0
- data/Rakefile +6 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/bin/vulndb +3 -0
- data/bin/vulnerabilitydb +3 -0
- data/bin/yavdb +5 -0
- data/lib/yavdb.rb +68 -0
- data/lib/yavdb/cli.rb +60 -0
- data/lib/yavdb/constants.rb +34 -0
- data/lib/yavdb/crawler.rb +52 -0
- data/lib/yavdb/database.rb +95 -0
- data/lib/yavdb/dtos/advisory.rb +102 -0
- data/lib/yavdb/source_types/git_repo.rb +35 -0
- data/lib/yavdb/sources/friends_of_php.rb +87 -0
- data/lib/yavdb/sources/nodesecurity_io.rb +120 -0
- data/lib/yavdb/sources/ossindex.rb +137 -0
- data/lib/yavdb/sources/ruby_advisory.rb +117 -0
- data/lib/yavdb/sources/snyk_io.rb +311 -0
- data/lib/yavdb/sources/victims.rb +105 -0
- data/lib/yavdb/utils/cache.rb +96 -0
- data/lib/yavdb/utils/exec.rb +36 -0
- data/lib/yavdb/utils/git.rb +61 -0
- data/lib/yavdb/utils/http.rb +56 -0
- data/lib/yavdb/utils/semver.rb +79 -0
- data/lib/yavdb/utils/zip.rb +64 -0
- data/lib/yavdb/version.rb +21 -0
- data/yavdb.gemspec +44 -0
- metadata +267 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
# yavdb - The Free and Open Source vulnerability database
|
2
|
+
# Copyright (C) 2017-present Rodrigo Fernandes
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'date'
|
18
|
+
require 'yaml'
|
19
|
+
|
20
|
+
require_relative '../dtos/advisory'
|
21
|
+
require_relative '../source_types/git_repo'
|
22
|
+
|
23
|
+
module YAVDB
|
24
|
+
module Sources
|
25
|
+
module RubyAdvisory
|
26
|
+
class Client
|
27
|
+
|
28
|
+
REPOSITORY_URL = 'https://github.com/rubysec/ruby-advisory-db'.freeze
|
29
|
+
PACKAGE_MANAGER = 'rubygems'.freeze
|
30
|
+
|
31
|
+
def self.advisories
|
32
|
+
YAVDB::SourceTypes::GitRepo.search('gems/**/*.yml', REPOSITORY_URL).map do |repo_path, file_paths|
|
33
|
+
Dir.chdir(repo_path) do
|
34
|
+
file_paths.map do |file_path|
|
35
|
+
advisory_hash = YAML.load_file(file_path)
|
36
|
+
create(advisory_hash)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end.flatten
|
40
|
+
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def create(advisory_hash)
|
47
|
+
date = Date.strptime(advisory_hash['date'].to_s, '%Y-%m-%d')
|
48
|
+
severity = severity(advisory_hash['cvss_v2'], advisory_hash['cvss_v3'])
|
49
|
+
cve = ["CVE-#{advisory_hash['cve']}"]
|
50
|
+
references = references(advisory_hash)
|
51
|
+
vulnerable_versions = if advisory_hash['unaffected_versions'] || advisory_hash['patched_versions']
|
52
|
+
nil
|
53
|
+
else
|
54
|
+
['*']
|
55
|
+
end
|
56
|
+
|
57
|
+
YAVDB::Advisory.new(
|
58
|
+
"rubyadvisory:rubygems:#{advisory_hash['gem']}:#{date}",
|
59
|
+
advisory_hash['title'],
|
60
|
+
advisory_hash['description'],
|
61
|
+
advisory_hash['gem'],
|
62
|
+
vulnerable_versions,
|
63
|
+
advisory_hash['unaffected_versions'],
|
64
|
+
advisory_hash['patched_versions'],
|
65
|
+
severity,
|
66
|
+
PACKAGE_MANAGER,
|
67
|
+
cve,
|
68
|
+
nil, #:cwe
|
69
|
+
advisory_hash['osvdb'],
|
70
|
+
nil, #:cvss_v2_vector
|
71
|
+
advisory_hash['cvss_v2'],
|
72
|
+
nil, #:cvss_v3_vector
|
73
|
+
advisory_hash['cvss_v3'],
|
74
|
+
date,
|
75
|
+
date,
|
76
|
+
date,
|
77
|
+
['Rubysec'],
|
78
|
+
references,
|
79
|
+
advisory_hash['url']
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def references(advisory_hash)
|
84
|
+
references = [REPOSITORY_URL]
|
85
|
+
|
86
|
+
if advisory_hash['related'] && advisory_hash['related']['url']
|
87
|
+
references.concat(advisory_hash['related']['url'])
|
88
|
+
else
|
89
|
+
references
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def severity(cvss_v2_score, cvss_v3_score)
|
94
|
+
if cvss_v3_score
|
95
|
+
severity_level(cvss_v3_score)
|
96
|
+
elsif cvss_v2_score
|
97
|
+
severity_level(cvss_v2_score)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def severity_level(cvss_score)
|
102
|
+
case cvss_score
|
103
|
+
when 0.0..3.3 then
|
104
|
+
'low'
|
105
|
+
when 3.3..6.6 then
|
106
|
+
'medium'
|
107
|
+
else
|
108
|
+
'high'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
# yavdb - The Free and Open Source vulnerability database
|
2
|
+
# Copyright (C) 2017-present Rodrigo Fernandes
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'oga'
|
18
|
+
require 'oga/xml/entities'
|
19
|
+
require 'kramdown'
|
20
|
+
|
21
|
+
require_relative '../dtos/advisory'
|
22
|
+
require_relative '../utils/http'
|
23
|
+
|
24
|
+
module YAVDB
|
25
|
+
module Sources
|
26
|
+
module SnykIO
|
27
|
+
class Client
|
28
|
+
|
29
|
+
BASE_URL = 'https://snyk.io'
|
30
|
+
BASE_VULN_URL = "#{BASE_URL}/vuln"
|
31
|
+
INFO_SEP = '#=#'
|
32
|
+
|
33
|
+
PACKAGE_MANAGERS_RSS_FEED = ['composer', 'golang', 'maven', 'npm', 'nuget', 'pip', 'rubygems'].freeze
|
34
|
+
|
35
|
+
PACKAGE_MANAGER_ALIAS = Hash[
|
36
|
+
'composer' => 'packagist',
|
37
|
+
'go' => 'go',
|
38
|
+
'maven' => 'maven',
|
39
|
+
'npm' => 'npm',
|
40
|
+
'nuget' => 'nuget',
|
41
|
+
'pip' => 'pypi',
|
42
|
+
'rubygems' => 'rubygems'
|
43
|
+
].freeze
|
44
|
+
|
45
|
+
def self.advisories
|
46
|
+
urls = fetch_advisory_urls
|
47
|
+
urls.map do |advisory_url|
|
48
|
+
advisory_page = get_page_html(advisory_url, true, 'snyk.io/advisories')
|
49
|
+
create(advisory_url, advisory_page)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class << self
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def fetch_advisory_urls
|
58
|
+
PACKAGE_MANAGERS_RSS_FEED.map do |pm|
|
59
|
+
fetch_advisory_recursive("#{BASE_VULN_URL}?type=#{pm}")
|
60
|
+
end.flatten
|
61
|
+
end
|
62
|
+
|
63
|
+
def fetch_advisory_recursive(page_url)
|
64
|
+
snykio = get_page_html(page_url, true, 'snyk.io/feed')
|
65
|
+
|
66
|
+
page_vuln_urls = snykio
|
67
|
+
.css('table tbody tr td span a')
|
68
|
+
.map { |anchor| anchor.get('href') }
|
69
|
+
.map { |link| link if link =~ %r{\/vuln\/.+} }.compact
|
70
|
+
|
71
|
+
next_urls = if page_vuln_urls.any?
|
72
|
+
next_url = snykio.css('a.pagination__next')
|
73
|
+
if next_url
|
74
|
+
fetch_advisory_recursive(next_url.first.get('href'))
|
75
|
+
else
|
76
|
+
[]
|
77
|
+
end
|
78
|
+
else
|
79
|
+
[]
|
80
|
+
end
|
81
|
+
|
82
|
+
page_vuln_urls
|
83
|
+
.concat(next_urls)
|
84
|
+
.map do |url|
|
85
|
+
full_url = url
|
86
|
+
full_url = "#{BASE_URL}#{url}" unless url.start_with?('http')
|
87
|
+
full_url
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def create(advisory_url, advisory_page)
|
92
|
+
severity = advisory_page.css('span.label__text').text.gsub(%r{(.*?) severity}, '\1')
|
93
|
+
|
94
|
+
package_manager = advisory_page.css('.breadcrumbs__list-item')[1].text.gsub(%r{\s+}, '').downcase
|
95
|
+
package_manager = PACKAGE_MANAGER_ALIAS[package_manager] || raise("Could not find alias for package manager #{package_manager}")
|
96
|
+
|
97
|
+
title = utf8(advisory_page.css('h1.header__title span.header__title__text').text)
|
98
|
+
|
99
|
+
affected_package = advisory_page.css('.custom-package-name').text
|
100
|
+
affected_package = advisory_page.css('.header__lede .breadcrumbs__list-item__link').text if affected_package.empty?
|
101
|
+
|
102
|
+
vulnerable_versions = advisory_page.css('.custom-affected-versions').text.strip
|
103
|
+
vulnerable_versions = if vulnerable_versions.empty? || vulnerable_versions == 'ALL'
|
104
|
+
['*']
|
105
|
+
else
|
106
|
+
[vulnerable_versions]
|
107
|
+
end
|
108
|
+
|
109
|
+
sidebar_data = parse_side_bar(advisory_page)
|
110
|
+
body_data = parse_body(advisory_page)
|
111
|
+
|
112
|
+
published_date = parse_date(sidebar_data[:published_date].to_s)
|
113
|
+
disclosed_date = parse_date(sidebar_data[:disclosed_date].to_s) || published_date
|
114
|
+
last_modified_date = if sidebar_data[:last_modified_date]
|
115
|
+
parse_date(sidebar_data[:last_modified_date].to_s)
|
116
|
+
else
|
117
|
+
published_date
|
118
|
+
end
|
119
|
+
|
120
|
+
YAVDB::Advisory.new(
|
121
|
+
"snykio:#{package_manager}:#{affected_package}:#{disclosed_date}",
|
122
|
+
title,
|
123
|
+
body_data[:description],
|
124
|
+
affected_package,
|
125
|
+
vulnerable_versions,
|
126
|
+
nil, #:unaffected_versions
|
127
|
+
nil, #:patched_versions
|
128
|
+
severity,
|
129
|
+
package_manager,
|
130
|
+
sidebar_data[:cve],
|
131
|
+
sidebar_data[:cwe],
|
132
|
+
nil, #:osvdb
|
133
|
+
nil, #:cvss_v2_vector
|
134
|
+
nil, #:cvss_v2_score
|
135
|
+
nil, #:cvss_v3_vector
|
136
|
+
nil, #:cvss_v3_score
|
137
|
+
disclosed_date,
|
138
|
+
published_date,
|
139
|
+
last_modified_date,
|
140
|
+
[sidebar_data[:credit]].flatten,
|
141
|
+
body_data[:references],
|
142
|
+
advisory_url
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
def parse_body(advisory_page)
|
147
|
+
data = {}
|
148
|
+
|
149
|
+
description_sections = []
|
150
|
+
overview_fields = advisory_page.css('.card.card--markdown .card__content > *')
|
151
|
+
overview_fields.each do |field|
|
152
|
+
if field.name == 'h2'
|
153
|
+
description_sections.push(:header => field, :body => [])
|
154
|
+
elsif description_sections.any?
|
155
|
+
last_elem = description_sections.last
|
156
|
+
new_body = last_elem[:body].push(field)
|
157
|
+
last_elem[:body] = new_body
|
158
|
+
description_sections.push(last_elem)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
description_sections.map do |section|
|
163
|
+
header = section[:header]
|
164
|
+
body = section[:body]
|
165
|
+
|
166
|
+
case header.text
|
167
|
+
when 'Overview' then
|
168
|
+
overview_str = body
|
169
|
+
.map(&:to_xml)
|
170
|
+
.join("\n")
|
171
|
+
.force_encoding('UTF-8')
|
172
|
+
begin
|
173
|
+
data[:description] += '\n' if data[:description]
|
174
|
+
data[:description] = '' unless data[:description]
|
175
|
+
data[:description] += utf8(Kramdown::Document.new(overview_str, :html_to_native => true).to_kramdown)
|
176
|
+
rescue StandardError
|
177
|
+
# ignore
|
178
|
+
end
|
179
|
+
when 'Details' then
|
180
|
+
details_str = body
|
181
|
+
.map(&:to_xml)
|
182
|
+
.join("\n")
|
183
|
+
.force_encoding('UTF-8')
|
184
|
+
begin
|
185
|
+
data[:description] += '\n' if data[:description]
|
186
|
+
data[:description] = '' unless data[:description]
|
187
|
+
data[:description] += utf8(Kramdown::Document.new(details_str, :html_to_native => true).to_kramdown)
|
188
|
+
rescue StandardError
|
189
|
+
# ignore
|
190
|
+
end
|
191
|
+
when 'References' then
|
192
|
+
references = []
|
193
|
+
if body.any?
|
194
|
+
body.first.css('li a').map do |elem|
|
195
|
+
references.push(elem.get('href'))
|
196
|
+
end
|
197
|
+
end
|
198
|
+
data[:references] = references.flatten
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
data
|
203
|
+
end
|
204
|
+
|
205
|
+
def parse_side_bar(advisory_page)
|
206
|
+
data = {}
|
207
|
+
|
208
|
+
advisory_page.css('.l-col .card .card__content dl > *').each_slice(2).to_a.map do |key, value|
|
209
|
+
case key.text
|
210
|
+
when 'Credit' then
|
211
|
+
data[:credit] = utf8(value.text.split(',').map { |str| str.strip.sub(%r{-\s*}, '') }.reject(&:empty?))
|
212
|
+
when 'CVE' then
|
213
|
+
data[:cve] = value.css('a').map { |a| a.text.strip.split(',') }.flatten.map(&:strip).reject(&:empty?)
|
214
|
+
when 'CWE' then
|
215
|
+
data[:cwe] = value.css('a').map { |a| a.text.strip.split(',') }.flatten.map(&:strip).reject(&:empty?)
|
216
|
+
when 'Snyk ID' then
|
217
|
+
data[:id] = value.text.strip
|
218
|
+
when 'Disclosed' then
|
219
|
+
data[:disclosed_date] = value.text.strip
|
220
|
+
when 'Published' then
|
221
|
+
data[:published_date] = value.text.strip
|
222
|
+
when 'Last modified' then
|
223
|
+
data[:last_modified_date] = value.text.strip
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
data
|
228
|
+
end
|
229
|
+
|
230
|
+
def get_page_html(source_url, with_cache, group_cache_key)
|
231
|
+
source_url = "#{BASE_URL}#{source_url}" unless source_url.start_with?('http')
|
232
|
+
body_lines = YAVDB::Utils::HTTP.get_page_contents(source_url, with_cache, group_cache_key)
|
233
|
+
body_lines = escape_vulnerable_versions(body_lines)
|
234
|
+
Oga.parse_html(body_lines, :strict => true)
|
235
|
+
end
|
236
|
+
|
237
|
+
def clean_references(references)
|
238
|
+
references.map do |reference|
|
239
|
+
reference
|
240
|
+
.gsub(%r{\s*-\s*(.*)}, '\1')
|
241
|
+
.gsub(%r{\[.+?\]\((.*)\).*}, '\1')
|
242
|
+
.strip
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def parse_date(date_str)
|
247
|
+
Date.strptime(date_str, '%d %b, %Y')
|
248
|
+
rescue ArgumentError
|
249
|
+
# ignore
|
250
|
+
end
|
251
|
+
|
252
|
+
# HACK: Page contains non UTF-8 characters and we need to fix it to be able to convert to json
|
253
|
+
def utf8(value)
|
254
|
+
if value.is_a?(Array)
|
255
|
+
value.map { |sub_value| utf8(sub_value) }
|
256
|
+
elsif value.is_a?(String)
|
257
|
+
value.force_encoding('UTF-8')
|
258
|
+
else
|
259
|
+
value
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# HACK: Page contains invalid HTML and we need to fix it to get the affected version
|
264
|
+
def escape_vulnerable_versions(body_lines)
|
265
|
+
cleaning = false
|
266
|
+
body_lines.map do |line|
|
267
|
+
if line.include?('<h2 id="overview">Overview</h2>')
|
268
|
+
cleaning = true
|
269
|
+
elsif line.include?('<h2 id=')
|
270
|
+
cleaning = false
|
271
|
+
end
|
272
|
+
|
273
|
+
if cleaning
|
274
|
+
key = '<script>'
|
275
|
+
line = line.gsub(key, Oga::XML::Entities.encode(key))
|
276
|
+
end
|
277
|
+
|
278
|
+
if line.include?(', versions')
|
279
|
+
extracted = line.gsub(%r{\s*<strong\s*>(.*)<\/strong>\s*}, '\1')
|
280
|
+
.gsub(%r{\s*<a.*>(.*)<\/a><\/strong>\s*}, '\1 ')
|
281
|
+
.gsub(%r{\s*<\/p>\s*}, '')
|
282
|
+
.gsub(%r{\s*<\/strong>\s*}, ' ')
|
283
|
+
.gsub(%r{\s*(.*)\s*}, '\1')
|
284
|
+
.gsub(%r{(\S*)(?:\s+.*)?,\s*versions\s*(.*)\s*}, "\\1#{INFO_SEP}\\2")
|
285
|
+
.tr("\n", ' ')
|
286
|
+
.gsub(' ', ' ')
|
287
|
+
.split(INFO_SEP)
|
288
|
+
fixed_version = Oga::XML::Entities.encode(extracted[1])
|
289
|
+
"</strong><span class=\"custom-package-name\">#{extracted[0]}</span><span class=\"custom-affected-versions\">#{fixed_version}</span>"
|
290
|
+
elsif line.include?(', <strong >ALL</strong> versions')
|
291
|
+
extracted = line.gsub(%r{\s*<strong\s*>(.*)<\/strong>\s*}, '\1')
|
292
|
+
.gsub(%r{\s*<a.*>(.*)<\/a><\/strong>\s*}, '\1 ')
|
293
|
+
.gsub(%r{\s*<\/p>\s*}, '')
|
294
|
+
.gsub(%r{\s*<\/strong>\s*}, ' ')
|
295
|
+
.gsub(%r{\s*(.*)\s*}, '\1')
|
296
|
+
.gsub(%r{(\S*)(?:\s+.*)?,\s*.*\s*versions\s*}, '\1')
|
297
|
+
.tr("\n", ' ')
|
298
|
+
.split(INFO_SEP)
|
299
|
+
"</strong><span class=\"custom-package-name\">#{extracted[0]}</span><span class=\"custom-affected-versions\">*</span>"
|
300
|
+
else
|
301
|
+
line
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# yavdb - The Free and Open Source vulnerability database
|
2
|
+
# Copyright (C) 2017-present Rodrigo Fernandes
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'date'
|
18
|
+
require 'yaml'
|
19
|
+
|
20
|
+
require_relative '../dtos/advisory'
|
21
|
+
require_relative '../utils/git'
|
22
|
+
|
23
|
+
module YAVDB
|
24
|
+
module Sources
|
25
|
+
module Victims
|
26
|
+
class Client
|
27
|
+
|
28
|
+
Language = Struct.new(:name, :package_manager, :name_parser)
|
29
|
+
|
30
|
+
REPOSITORY_URL = 'https://github.com/victims/victims-cve-db'.freeze
|
31
|
+
|
32
|
+
LANGUAGES = [
|
33
|
+
Language.new('java', 'maven', lambda { |affected_package| "#{affected_package['groupId']}:#{affected_package['artifactId']}" }),
|
34
|
+
Language.new('python', 'pypi', lambda { |affected_package| affected_package['name'] })
|
35
|
+
]
|
36
|
+
|
37
|
+
def self.advisories
|
38
|
+
LANGUAGES.map do |language|
|
39
|
+
glob = language_glob(language.name)
|
40
|
+
YAVDB::SourceTypes::GitRepo.search(glob, REPOSITORY_URL).map do |repo_path, file_paths|
|
41
|
+
Dir.chdir(repo_path) do
|
42
|
+
file_paths.map do |file_path|
|
43
|
+
advisory_hash = YAML.load_file(file_path)
|
44
|
+
url = "#{REPOSITORY_URL}/blob/master/#{file_path}"
|
45
|
+
create(advisory_hash, language, url)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end.flatten
|
50
|
+
end
|
51
|
+
|
52
|
+
class << self
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def language_glob(language)
|
57
|
+
"database/#{language}/*/*.*"
|
58
|
+
end
|
59
|
+
|
60
|
+
def create(advisory_hash, language, url)
|
61
|
+
advisory_hash['affected'].map do |affected_package|
|
62
|
+
YAVDB::Advisory.new(
|
63
|
+
"victims:#{language.package_manager}:#{language.name_parser[affected_package]}:date",
|
64
|
+
advisory_hash['title'],
|
65
|
+
advisory_hash['description'],
|
66
|
+
language.name_parser[affected_package],
|
67
|
+
affected_package['version'],
|
68
|
+
affected_package['unaffected'],
|
69
|
+
affected_package['fixedin'],
|
70
|
+
severity(advisory_hash['cvss_v2']),
|
71
|
+
language.package_manager,
|
72
|
+
[advisory_hash['cve']],
|
73
|
+
nil, #:cwe
|
74
|
+
nil, #:osvdb
|
75
|
+
nil, #:cvss_v2_vector
|
76
|
+
advisory_hash['cvss_v2'],
|
77
|
+
nil, #:cvss_v3_vector
|
78
|
+
nil, #:cvss_v3
|
79
|
+
nil,
|
80
|
+
nil,
|
81
|
+
nil,
|
82
|
+
['Victims CVE Database'],
|
83
|
+
advisory_hash['references'],
|
84
|
+
url
|
85
|
+
)
|
86
|
+
end.flatten
|
87
|
+
end
|
88
|
+
|
89
|
+
def severity(cvss_score)
|
90
|
+
case cvss_score
|
91
|
+
when 0.0..3.3 then
|
92
|
+
'low'
|
93
|
+
when 3.3..6.6 then
|
94
|
+
'medium'
|
95
|
+
else
|
96
|
+
'high'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|