yavdb 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bd83226987ff17616cf7fc728a9804295402491da0254c04f09e83b162070fd
4
- data.tar.gz: '0629122cc39f6740a833aa61cb3da32acfcd9205ad1ed0658ac17380d2373874'
3
+ metadata.gz: e1e5f9733916e6d5f5d5be22dc13f15879d2d27c4d67f3a1da2354108de7c693
4
+ data.tar.gz: 8748dccfdbc49a566c1bc46d692b96d8dff6bbf17aa77b876fc20fd92066ae61
5
5
  SHA512:
6
- metadata.gz: 14f2363effd7b653ad4eb9ca71a54236304d7b5e42d224ff3dfbc554dcef8fa8c76d0a19f8a7c5fed5b795199fde239cee6b7296e716494055f504ab0edb2520
7
- data.tar.gz: 1a0ba50cbdf9c1b4fff512465886924458de19195e5e6fc03b1dbc5620c4e9ce2728bc7864d2830473748c68cc1225ef5669358a0c21da78f17e0ff12993071b
6
+ metadata.gz: 7be1bd86bf8f7c066cc4ee6e5cbc005d226bc70e0d1a8a0f849ac447c4c64032608cfef4a25abe46bdc297e985a1050450b355014113c25efd9bfc1afe4bccf2
7
+ data.tar.gz: 5e44694faa7f72af21f2cb2548e3059e7ab993872e0f1ad0b08d6f60f1f2bcef28cd7af02f9fb61a9ef20ae9ca18b6bd0172afe175cb8d77e78f1450bd2b2b47
@@ -163,8 +163,6 @@ Lint/UselessAssignment:
163
163
 
164
164
  Lint/SuppressedException:
165
165
  Enabled: true
166
- Exclude:
167
- - "lib/yavdb/sources/snyk_io.rb"
168
166
 
169
167
  Metrics/AbcSize:
170
168
  Enabled: true
@@ -1 +1 @@
1
- 2.5.5
1
+ 2.5.7
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yavdb (0.6.0)
4
+ yavdb (0.7.0)
5
5
  execjs (~> 2.7)
6
6
  json (~> 2.2)
7
7
  kramdown (~> 2.3)
@@ -133,4 +133,4 @@ DEPENDENCIES
133
133
  yavdb!
134
134
 
135
135
  BUNDLED WITH
136
- 2.1.2
136
+ 2.2.5
data/README.md CHANGED
@@ -11,7 +11,7 @@ developers identify and fix know vulnerabilities in their apps.
11
11
 
12
12
  The sources for this database include
13
13
  [Rubysec](https://rubysec.com/),
14
- [snyk](https://snyk.io/),
14
+ ~~[snyk](https://snyk.io/),~~ (removed)
15
15
  [Friends of PHP](https://github.com/FriendsOfPHP/security-advisories),
16
16
  [Magento Related Security Advisories](https://github.com/victims/victims-cve-db),
17
17
  [Victims CVE Database](https://github.com/victims/victims-cve-db),
@@ -33,7 +33,6 @@ gem install yavdb
33
33
 
34
34
  * Sources
35
35
  - [ ] [Rubysec](lib/yavdb/sources/ruby_advisory.rb)
36
- - [X] [snyk](lib/yavdb/sources/snyk_io.rb)
37
36
  - [ ] [OSSIndex](lib/yavdb/sources/ossindex.rb)
38
37
  - [ ] [Friends of PHP and Magento Related Security Advisories](lib/yavdb/sources/friends_of_php.rb)
39
38
  - [ ] [Victims CVE Database](lib/yavdb/sources/victims.rb)
@@ -16,6 +16,6 @@
16
16
 
17
17
  module YAVDB
18
18
 
19
- VERSION = '0.6.0'
19
+ VERSION = '0.7.0'
20
20
 
21
21
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yavdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Fernandes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-17 00:00:00.000000000 Z
11
+ date: 2021-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: codacy-coverage
@@ -296,7 +296,6 @@ files:
296
296
  - lib/yavdb/sources/npmjs.rb
297
297
  - lib/yavdb/sources/ruby_advisory.rb
298
298
  - lib/yavdb/sources/rustsec.rb
299
- - lib/yavdb/sources/snyk_io.rb
300
299
  - lib/yavdb/sources/victims.rb
301
300
  - lib/yavdb/utils/cache.rb
302
301
  - lib/yavdb/utils/exec.rb
@@ -1,309 +0,0 @@
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 = ['composer', 'golang', 'maven', 'npm', 'nuget', 'pip', 'rubygems', 'cocoapods'].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
- 'cocoapods' => 'cocoapods'
44
- ].freeze
45
-
46
- def self.advisories
47
- urls = fetch_advisory_urls
48
- urls.map do |advisory_url|
49
- advisory_page = get_page_html(advisory_url, true, 'snyk.io/advisories')
50
- create(advisory_url, advisory_page)
51
- end.reject(&:nil?)
52
- end
53
-
54
- class << self
55
-
56
- private
57
-
58
- def fetch_advisory_urls
59
- PACKAGE_MANAGERS.map do |pm|
60
- fetch_advisory_recursive("#{BASE_VULN_URL}?type=#{pm}")
61
- end.flatten
62
- end
63
-
64
- def fetch_advisory_recursive(page_url)
65
- snykio = get_page_html(page_url, false, 'snyk.io/feed')
66
-
67
- page_vuln_urls = snykio
68
- .css('table tbody tr td span a')
69
- .map { |anchor| anchor.get('href') }
70
- .map { |link| link if %r{\/vuln\/.+}.match?(link) }.compact
71
-
72
- next_urls = if page_vuln_urls.any?
73
- next_url = snykio.css('a.pagination__next')
74
- if next_url&.first
75
- fetch_advisory_recursive(next_url.first.get('href'))
76
- else
77
- []
78
- end
79
- else
80
- []
81
- end
82
-
83
- page_vuln_urls
84
- .concat(next_urls)
85
- .map do |url|
86
- full_url = url
87
- full_url = "#{BASE_URL}#{url}" unless url.start_with?('http')
88
- full_url
89
- end
90
- end
91
-
92
- def create(advisory_url, advisory_page)
93
- severity = advisory_page.css('span.label__text').text.gsub(%r{(.*?) severity}, '\1')
94
-
95
- package_manager = advisory_page.css('.breadcrumbs__list-item')[1].text.gsub(%r{\s+}, '').downcase
96
- package_manager = PACKAGE_MANAGER_ALIAS[package_manager] || return
97
-
98
- title = utf8(advisory_page.css('h1.header__title span.header__title__text').text)
99
-
100
- affected_package = advisory_page.css('.custom-package-name').text
101
- affected_package = advisory_page.css('.header__lede .breadcrumbs__list-item__link').text if affected_package.empty?
102
-
103
- vulnerable_versions = (advisory_page.css('.custom-affected-versions') ||
104
- advisory_page.css('.header__lede strong').drop(1).first).text.strip
105
- vulnerable_versions = if vulnerable_versions.empty? || vulnerable_versions == 'ALL' || vulnerable_versions == '(,)'
106
- ['*']
107
- elsif ['maven', 'nuget', 'pypi'].include?(package_manager)
108
- [vulnerable_versions]
109
- else
110
- [vulnerable_versions.tr(',', ' ')]
111
- end
112
-
113
- sidebar_data = parse_side_bar(advisory_page)
114
- body_data = parse_body(advisory_page)
115
-
116
- published_date = parse_date(sidebar_data[:published_date].to_s)
117
- disclosed_date = parse_date(sidebar_data[:disclosed_date].to_s) || published_date
118
- last_modified_date = if sidebar_data[:last_modified_date]
119
- parse_date(sidebar_data[:last_modified_date].to_s)
120
- else
121
- published_date
122
- end
123
-
124
- vuln_id_stamp = sidebar_data[:id].split(%r{-|:}).last || disclosed_date
125
- vuln_id = "snykio:#{package_manager}:#{affected_package}:#{vuln_id_stamp}"
126
-
127
- YAVDB::Advisory.new(
128
- vuln_id,
129
- title,
130
- body_data[:description],
131
- affected_package,
132
- vulnerable_versions,
133
- nil, #:unaffected_versions
134
- nil, #:patched_versions
135
- severity,
136
- package_manager,
137
- sidebar_data[:cve],
138
- sidebar_data[:cwe],
139
- nil, #:osvdb
140
- nil, #:cvss_v2_vector
141
- nil, #:cvss_v2_score
142
- nil, #:cvss_v3_vector
143
- nil, #:cvss_v3_score
144
- disclosed_date,
145
- published_date,
146
- last_modified_date,
147
- [sidebar_data[:credit]].flatten,
148
- body_data[:references],
149
- advisory_url
150
- )
151
- end
152
-
153
- def parse_body(advisory_page)
154
- data = {}
155
-
156
- description_sections = []
157
- overview_fields = advisory_page.css('.card.card--markdown .card__content > *')
158
- overview_fields.each do |field|
159
- if field.name == 'h2'
160
- description_sections.push(:header => field, :body => [])
161
- elsif description_sections.any?
162
- last_elem = description_sections.last
163
- new_body = last_elem[:body].push(field)
164
- last_elem[:body] = new_body
165
- end
166
- end
167
-
168
- description_sections.map do |section|
169
- header = section[:header]
170
- body = section[:body]
171
-
172
- case header.text
173
- when %r{^(Overview|Details)$} then
174
- overview_str = body
175
- .map(&:to_xml)
176
- .map { |e| e.force_encoding('UTF-8') }
177
- .join("\n")
178
- begin
179
- if data[:description]
180
- data[:description] += '\n'
181
- else
182
- data[:description] = ''
183
- end
184
-
185
- data[:description] += utf8(Kramdown::Document.new(overview_str, :html_to_native => true).to_kramdown)
186
- rescue StandardError
187
- # ignore
188
- end
189
- when 'References' then
190
- references = []
191
- if body.any?
192
- body.first.css('li a').map do |elem|
193
- references.push(elem.get('href'))
194
- end
195
- end
196
- data[:references] = references.flatten
197
- end
198
- end
199
-
200
- data
201
- end
202
-
203
- def parse_side_bar(advisory_page)
204
- data = {}
205
-
206
- advisory_page.css('.l-col .card .card__content dl > *').each_slice(2).to_a.map do |key, value|
207
- case key.text
208
- when 'Credit'
209
- data[:credit] = utf8(value.text.split(',').map { |str| str.strip.sub(%r{-\s*}, '') }.reject(&:empty?))
210
- when 'CVE'
211
- data[:cve] = value.css('a').map { |a| a.text.strip.split(',') }.flatten.map(&:strip).reject(&:empty?)
212
- when 'CWE'
213
- data[:cwe] = value.css('a').map { |a| a.text.strip.split(',') }.flatten.map(&:strip).reject(&:empty?)
214
- when 'Snyk ID'
215
- data[:id] = value.text.strip
216
- when 'Disclosed'
217
- data[:disclosed_date] = value.text.strip
218
- when 'Published'
219
- data[:published_date] = value.text.strip
220
- when 'Last modified'
221
- data[:last_modified_date] = value.text.strip
222
- end
223
- end
224
-
225
- data
226
- end
227
-
228
- def get_page_html(source_url, with_cache, group_cache_key)
229
- source_url = "#{BASE_URL}#{source_url}" unless source_url.start_with?('http')
230
- body_lines = YAVDB::Utils::HTTP.get_page_contents(source_url, with_cache, group_cache_key)
231
- body_lines = escape_vulnerable_versions(body_lines)
232
- Oga.parse_html(body_lines, :strict => true)
233
- end
234
-
235
- def clean_references(references)
236
- references.map do |reference|
237
- reference
238
- .gsub(%r{\s*-\s*(.*)}, '\1')
239
- .gsub(%r{\[.+?\]\((.*)\).*}, '\1')
240
- .strip
241
- end
242
- end
243
-
244
- def parse_date(date_str)
245
- Date.strptime(date_str, '%d %b, %Y')
246
- rescue ArgumentError
247
- # ignore
248
- end
249
-
250
- # HACK: Page contains non UTF-8 characters and we need to fix it to be able to convert to json
251
- def utf8(value)
252
- if value.is_a?(Array)
253
- value.map { |sub_value| utf8(sub_value) }
254
- elsif value.is_a?(String)
255
- value.force_encoding('UTF-8')
256
- else
257
- value
258
- end
259
- end
260
-
261
- # HACK: Page contains invalid HTML and we need to fix it to get the affected version
262
- def escape_vulnerable_versions(body_lines)
263
- cleaning = false
264
- body_lines.map do |line|
265
- if line.include?('<h2 id="overview">Overview</h2>')
266
- cleaning = true
267
- elsif line.include?('<h2 id=')
268
- cleaning = false
269
- end
270
-
271
- if cleaning
272
- key = '<script>'
273
- line = line.gsub(key, Oga::XML::Entities.encode(key))
274
- end
275
-
276
- if line.include?(', versions')
277
- extracted = line.gsub(%r{\s*<strong\s*>(.*)<\/strong>\s*}, '\1')
278
- .gsub(%r{\s*<a.*>(.*)<\/a><\/strong>\s*}, '\1 ')
279
- .gsub(%r{\s*<\/p>\s*}, '')
280
- .gsub(%r{\s*<\/strong>\s*}, ' ')
281
- .gsub(%r{\s*(.*)\s*}, '\1')
282
- .gsub(%r{(\S*)(?:\s+.*)?,\s*versions\s*(.*)\s*}, "\\1#{INFO_SEP}\\2")
283
- .tr("\n", ' ')
284
- .gsub('&nbsp;', ' ')
285
- .split(INFO_SEP)
286
- fixed_version = Oga::XML::Entities.encode(extracted[1])
287
- "</strong><span class=\"custom-package-name\">#{extracted[0]}</span><span class=\"custom-affected-versions\">#{fixed_version}</span>"
288
- elsif line.include?(', <strong >ALL</strong> versions')
289
- extracted = line.gsub(%r{\s*<strong\s*>(.*)<\/strong>\s*}, '\1')
290
- .gsub(%r{\s*<a.*>(.*)<\/a><\/strong>\s*}, '\1 ')
291
- .gsub(%r{\s*<\/p>\s*}, '')
292
- .gsub(%r{\s*<\/strong>\s*}, ' ')
293
- .gsub(%r{\s*(.*)\s*}, '\1')
294
- .gsub(%r{(\S*)(?:\s+.*)?,\s*.*\s*versions\s*}, '\1')
295
- .tr("\n", ' ')
296
- .split(INFO_SEP)
297
- "</strong><span class=\"custom-package-name\">#{extracted[0]}</span><span class=\"custom-affected-versions\">*</span>"
298
- else
299
- line
300
- end
301
- end
302
- end
303
-
304
- end
305
-
306
- end
307
- end
308
- end
309
- end