yavdb 0.6.0 → 0.7.0

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