mechanize 2.7.6 → 2.7.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of mechanize might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.github/workflows/ci-test.yml +25 -0
- data/CHANGELOG.rdoc +27 -0
- data/EXAMPLES.rdoc +1 -24
- data/Gemfile +4 -2
- data/README.rdoc +1 -1
- data/examples/rubygems.rb +2 -2
- data/lib/mechanize.rb +2 -2
- data/lib/mechanize/cookie_jar.rb +2 -2
- data/lib/mechanize/download.rb +1 -1
- data/lib/mechanize/file.rb +1 -1
- data/lib/mechanize/file_response.rb +1 -1
- data/lib/mechanize/form.rb +1 -1
- data/lib/mechanize/test_case.rb +2 -2
- data/lib/mechanize/test_case/gzip_servlet.rb +3 -3
- data/lib/mechanize/test_case/verb_servlet.rb +4 -6
- data/lib/mechanize/version.rb +1 -1
- data/mechanize.gemspec +2 -6
- data/test/htdocs/tc_links.html +1 -1
- data/test/test_mechanize.rb +14 -3
- data/test/test_mechanize_cookie.rb +19 -19
- data/test/test_mechanize_cookie_jar.rb +83 -53
- data/test/test_mechanize_download.rb +12 -1
- data/test/test_mechanize_file.rb +9 -0
- data/test/test_mechanize_file_response.rb +20 -2
- data/test/test_mechanize_form.rb +12 -0
- data/test/test_mechanize_form_keygen.rb +1 -0
- data/test/test_mechanize_http_agent.rb +6 -1
- metadata +11 -54
- data/.travis.yml +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: feff4acdf05edc4c615ab91f9ab0b7abfd1987dbd998ed07a36489189594edf2
|
4
|
+
data.tar.gz: efce735d57a4b2259f30a630829f432f270e3aa353fb9d4f5ad032df06387e84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f83a08c469e67045f58f3f3685cb17618db889dd85d1b7f2e56da1c9ae7744f36815a1f811f09bd99614c529b42f2038100a64fb06cdee1569d43bb831ea3fae
|
7
|
+
data.tar.gz: c01289d967e87c40e0936c2f973847da696bc92d9255a5c5f20099ff795ce57430f45a631a02a9395cfe7066e27731ec040a879fd255468b43cf9a1b5149c3eb
|
@@ -0,0 +1,25 @@
|
|
1
|
+
name: "ci"
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ "*" ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
fail-fast: false
|
14
|
+
matrix:
|
15
|
+
ruby-version: ["2.3", "2.4", "2.5", "2.6", "2.7", "3.0", "jruby"]
|
16
|
+
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- name: Set up Ruby
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: ${{ matrix.ruby-version }}
|
23
|
+
bundler-cache: true
|
24
|
+
- name: Run tests
|
25
|
+
run: bundle exec rake
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
= Mechanize CHANGELOG
|
2
2
|
|
3
|
+
=== 2.7.7 / 2021-02-01
|
4
|
+
|
5
|
+
* Security fixes for CVE-2021-21289
|
6
|
+
|
7
|
+
Mechanize `>= v2.0`, `< v2.7.7` allows for OS commands to be injected into several classes'
|
8
|
+
methods via implicit use of Ruby's `Kernel.open` method. Exploitation is possible only if
|
9
|
+
untrusted input is used as a local filename and passed to any of these calls:
|
10
|
+
|
11
|
+
- `Mechanize::CookieJar#load`: since v2.0 (see 208e3ed)
|
12
|
+
- `Mechanize::CookieJar#save_as`: since v2.0 (see 5b776a4)
|
13
|
+
- `Mechanize#download`: since v2.2 (see dc91667)
|
14
|
+
- `Mechanize::Download#save` and `#save!` since v2.1 (see 98b2f51, bd62ff0)
|
15
|
+
- `Mechanize::File#save` and `#save_as`: since v2.1 (see 2bf7519)
|
16
|
+
- `Mechanize::FileResponse#read_body`: since v2.0 (see 01039f5)
|
17
|
+
|
18
|
+
See https://github.com/sparklemotion/mechanize/security/advisories/GHSA-qrqm-fpv6-6r8g for more
|
19
|
+
information.
|
20
|
+
|
21
|
+
Also see #547, #548. Thank you, @kyoshidajp!
|
22
|
+
|
23
|
+
* New Features
|
24
|
+
* Support for Ruby 3.0 by adding `webrick` as a runtime dependency. (#557) @pvalena
|
25
|
+
|
26
|
+
* Bug fix
|
27
|
+
* Ignore input fields with blank names (#542, #536)
|
28
|
+
|
29
|
+
|
3
30
|
=== 2.7.6
|
4
31
|
|
5
32
|
* New Features
|
data/EXAMPLES.rdoc
CHANGED
@@ -24,29 +24,6 @@ example, <code>do ... end.submit</code> is the same as <code>{ ...
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
== Rubyforge
|
28
|
-
|
29
|
-
require 'rubygems'
|
30
|
-
require 'mechanize'
|
31
|
-
|
32
|
-
a = Mechanize.new
|
33
|
-
a.get('http://rubyforge.org/') do |page|
|
34
|
-
# Click the login link
|
35
|
-
login_page = a.click(page.link_with(:text => /Log In/))
|
36
|
-
|
37
|
-
# Submit the login form
|
38
|
-
my_page = login_page.form_with(:action => '/account/login.php') do |f|
|
39
|
-
f.form_loginname = ARGV[0]
|
40
|
-
f.form_pw = ARGV[1]
|
41
|
-
end.click_button
|
42
|
-
|
43
|
-
my_page.links.each do |link|
|
44
|
-
text = link.text.strip
|
45
|
-
next unless text.length > 0
|
46
|
-
puts text
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
27
|
== File Upload
|
51
28
|
|
52
29
|
Upload a file to flickr.
|
@@ -129,7 +106,7 @@ This example also demonstrates subclassing Mechanize.
|
|
129
106
|
|
130
107
|
class TestMech < Mechanize
|
131
108
|
def process
|
132
|
-
get 'http://
|
109
|
+
get 'http://rubygems.org/'
|
133
110
|
search_form = page.forms.first
|
134
111
|
search_form.words = 'WWW'
|
135
112
|
submit search_form
|
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -48,7 +48,7 @@ Copyright (c) 2005 by Michael Neumann (mneumann@ntecs.de)
|
|
48
48
|
|
49
49
|
Copyright (c) 2006-2011:
|
50
50
|
|
51
|
-
* {Aaron Patterson}[http://tenderlovemaking.com] (
|
51
|
+
* {Aaron Patterson}[http://tenderlovemaking.com] (aaron.patterson@gmail.com)
|
52
52
|
* {Mike Dalessio}[http://mike.daless.io] (mike@csa.net)
|
53
53
|
|
54
54
|
Copyright (c) 2011-2015:
|
data/examples/rubygems.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# This example logs a user in to
|
1
|
+
# This example logs a user in to rubygems and prints out the body of the
|
2
2
|
# page after logging the user in.
|
3
3
|
require 'rubygems'
|
4
4
|
require 'mechanize'
|
@@ -9,7 +9,7 @@ mech = Mechanize.new
|
|
9
9
|
mech.log = Logger.new $stderr
|
10
10
|
mech.agent.http.debug_output = $stderr
|
11
11
|
|
12
|
-
# Load the
|
12
|
+
# Load the rubygems website
|
13
13
|
page = mech.get('https://rubygems.org/')
|
14
14
|
page = mech.click page.link_with(:text => /Sign in/) # Click the login link
|
15
15
|
form = page.forms[1] # Select the first form
|
data/lib/mechanize.rb
CHANGED
@@ -175,7 +175,7 @@ class Mechanize
|
|
175
175
|
# as SSL parameters or proxies:
|
176
176
|
#
|
177
177
|
# agent = Mechanize.new do |a|
|
178
|
-
# a.
|
178
|
+
# a.proxy_addr = 'proxy.example'
|
179
179
|
# a.proxy_port = 8080
|
180
180
|
# end
|
181
181
|
#
|
@@ -396,7 +396,7 @@ class Mechanize
|
|
396
396
|
io = if io_or_filename.respond_to? :write then
|
397
397
|
io_or_filename
|
398
398
|
else
|
399
|
-
open
|
399
|
+
::File.open(io_or_filename, 'wb')
|
400
400
|
end
|
401
401
|
|
402
402
|
case page
|
data/lib/mechanize/cookie_jar.rb
CHANGED
@@ -65,7 +65,7 @@ class Mechanize
|
|
65
65
|
class CookieJar < ::HTTP::CookieJar
|
66
66
|
def save(output, *options)
|
67
67
|
output.respond_to?(:write) or
|
68
|
-
return open(output, 'w') { |io| save(io, *options) }
|
68
|
+
return ::File.open(output, 'w') { |io| save(io, *options) }
|
69
69
|
|
70
70
|
opthash = {
|
71
71
|
:format => :yaml,
|
@@ -119,7 +119,7 @@ class Mechanize
|
|
119
119
|
|
120
120
|
def load(input, *options)
|
121
121
|
input.respond_to?(:write) or
|
122
|
-
return open(input, 'r') { |io| load(io, *options) }
|
122
|
+
return ::File.open(input, 'r') { |io| load(io, *options) }
|
123
123
|
|
124
124
|
opthash = {
|
125
125
|
:format => :yaml,
|
data/lib/mechanize/download.rb
CHANGED
data/lib/mechanize/file.rb
CHANGED
data/lib/mechanize/form.rb
CHANGED
data/lib/mechanize/test_case.rb
CHANGED
@@ -230,9 +230,9 @@ class Net::HTTP # :nodoc:
|
|
230
230
|
else
|
231
231
|
filename = "htdocs#{path.gsub(/[^\/\\.\w\s]/, '_')}"
|
232
232
|
unless PAGE_CACHE[filename]
|
233
|
-
open("#{Mechanize::TestCase::TEST_DIR}/#{filename}", 'rb')
|
233
|
+
::File.open("#{Mechanize::TestCase::TEST_DIR}/#{filename}", 'rb') do |io|
|
234
234
|
PAGE_CACHE[filename] = io.read
|
235
|
-
|
235
|
+
end
|
236
236
|
end
|
237
237
|
|
238
238
|
res.body = PAGE_CACHE[filename]
|
@@ -13,8 +13,8 @@ class GzipServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
13
13
|
end
|
14
14
|
|
15
15
|
if name = req.query['file'] then
|
16
|
-
open
|
17
|
-
string =
|
16
|
+
::File.open("#{TEST_DIR}/htdocs/#{name}") do |io|
|
17
|
+
string = String.new
|
18
18
|
zipped = StringIO.new string, 'w'
|
19
19
|
Zlib::GzipWriter.wrap zipped do |gz|
|
20
20
|
gz.write io.read
|
@@ -22,7 +22,7 @@ class GzipServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
22
22
|
res.body = string
|
23
23
|
end
|
24
24
|
else
|
25
|
-
res.body =
|
25
|
+
res.body = String.new
|
26
26
|
end
|
27
27
|
|
28
28
|
res['Content-Encoding'] = req['X-ResponseContentEncoding'] || 'gzip'
|
@@ -1,11 +1,9 @@
|
|
1
1
|
class VerbServlet < WEBrick::HTTPServlet::AbstractServlet
|
2
2
|
%w[HEAD GET POST PUT DELETE].each do |verb|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
-
METHOD
|
3
|
+
define_method "do_#{verb}" do |req, res|
|
4
|
+
res.header['X-Request-Method'] = verb
|
5
|
+
res.body = verb
|
6
|
+
end
|
9
7
|
end
|
10
8
|
end
|
11
9
|
|
data/lib/mechanize/version.rb
CHANGED
data/mechanize.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.email =
|
29
29
|
[
|
30
30
|
'drbrain@segment7.net',
|
31
|
-
'
|
31
|
+
'aaron.patterson@gmail.com',
|
32
32
|
'mike.dalessio@gmail.com',
|
33
33
|
'knu@idaemons.org',
|
34
34
|
'ljjarvis@gmail.com'
|
@@ -58,9 +58,5 @@ Gem::Specification.new do |spec|
|
|
58
58
|
spec.add_runtime_dependency "ntlm-http", [ ">= 0.1.1", "~> 0.1" ]
|
59
59
|
spec.add_runtime_dependency "webrobots", [ "< 0.2", ">= 0.0.9" ]
|
60
60
|
spec.add_runtime_dependency "domain_name", [ ">= 0.5.1", "~> 0.5" ]
|
61
|
-
|
62
|
-
spec.add_development_dependency "rake"
|
63
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
64
|
-
spec.add_development_dependency "rdoc", "~> 4.0"
|
65
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
61
|
+
spec.add_runtime_dependency 'webrick', "~> 1.7"
|
66
62
|
end
|
data/test/htdocs/tc_links.html
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
<a href="thing.html" class="thing_link">Thing!</a>
|
8
8
|
<a href="thing.html">Ruby <b>Rocks!</b></a>
|
9
9
|
<!-- Testing a bug with escaped stuff in links:
|
10
|
-
http://
|
10
|
+
http://rubygems.org/pipermail/mechanize-users/2006-September/000002.html
|
11
11
|
-->
|
12
12
|
<a href="link%20with%20space.html">encoded space</a>
|
13
13
|
<a href="link with space.html">not encoded space</a>
|
data/test/test_mechanize.rb
CHANGED
@@ -345,6 +345,14 @@ but not <a href="/" rel="me nofollow">this</a>!
|
|
345
345
|
end
|
346
346
|
end
|
347
347
|
|
348
|
+
def test_download_does_not_allow_command_injection
|
349
|
+
in_tmpdir do
|
350
|
+
@mech.download('http://example', '| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
|
351
|
+
|
352
|
+
refute_operator(File, :exist?, "vul.txt")
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
348
356
|
def test_get
|
349
357
|
uri = URI 'http://localhost'
|
350
358
|
|
@@ -689,9 +697,7 @@ but not <a href="/" rel="me nofollow">this</a>!
|
|
689
697
|
end
|
690
698
|
|
691
699
|
def test_get_space
|
692
|
-
|
693
|
-
|
694
|
-
page = @mech.get("http://localhost/tc_bad_links.html ")
|
700
|
+
@mech.get("http://localhost/tc_bad_links.html ")
|
695
701
|
|
696
702
|
assert_match(/tc_bad_links.html$/, @mech.history.last.uri.to_s)
|
697
703
|
|
@@ -1056,6 +1062,11 @@ but not <a href="/" rel="me nofollow">this</a>!
|
|
1056
1062
|
end
|
1057
1063
|
|
1058
1064
|
def test_retry_change_requests_equals
|
1065
|
+
unless Gem::Requirement.new("< 4.0.0").satisfied_by?(Gem::Version.new(Net::HTTP::Persistent::VERSION))
|
1066
|
+
# see https://github.com/drbrain/net-http-persistent/pull/100
|
1067
|
+
skip("net-http-persistent 4.0.0 and later does not support retry_change_requests")
|
1068
|
+
end
|
1069
|
+
|
1059
1070
|
refute @mech.retry_change_requests
|
1060
1071
|
|
1061
1072
|
@mech.retry_change_requests = true
|
@@ -141,7 +141,7 @@ class TestMechanizeCookie < Mechanize::TestCase
|
|
141
141
|
def test_parse_date_fail
|
142
142
|
url = URI.parse('http://localhost/')
|
143
143
|
|
144
|
-
dates = [
|
144
|
+
dates = [
|
145
145
|
"20/06/95 21:07",
|
146
146
|
]
|
147
147
|
|
@@ -290,16 +290,16 @@ class TestMechanizeCookie < Mechanize::TestCase
|
|
290
290
|
end
|
291
291
|
|
292
292
|
def test_parse_valid_cookie
|
293
|
-
url = URI.parse('http://
|
293
|
+
url = URI.parse('http://rubygems.org/')
|
294
294
|
cookie_params = {}
|
295
295
|
cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
|
296
296
|
cookie_params['path'] = 'path=/'
|
297
|
-
cookie_params['domain'] = 'domain=.
|
297
|
+
cookie_params['domain'] = 'domain=.rubygems.org'
|
298
298
|
cookie_params['httponly'] = 'HttpOnly'
|
299
299
|
cookie_value = '12345%7D=ASDFWEE345%3DASda'
|
300
300
|
|
301
301
|
expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
|
302
|
-
|
302
|
+
|
303
303
|
cookie_params.keys.combine.each do |c|
|
304
304
|
cookie_text = "#{cookie_value}; "
|
305
305
|
c.each_with_index do |key, idx|
|
@@ -325,16 +325,16 @@ class TestMechanizeCookie < Mechanize::TestCase
|
|
325
325
|
end
|
326
326
|
|
327
327
|
def test_parse_valid_cookie_empty_value
|
328
|
-
url = URI.parse('http://
|
328
|
+
url = URI.parse('http://rubygems.org/')
|
329
329
|
cookie_params = {}
|
330
330
|
cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
|
331
331
|
cookie_params['path'] = 'path=/'
|
332
|
-
cookie_params['domain'] = 'domain=.
|
332
|
+
cookie_params['domain'] = 'domain=.rubygems.org'
|
333
333
|
cookie_params['httponly'] = 'HttpOnly'
|
334
334
|
cookie_value = '12345%7D='
|
335
335
|
|
336
336
|
expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
|
337
|
-
|
337
|
+
|
338
338
|
cookie_params.keys.combine.each do |c|
|
339
339
|
cookie_text = "#{cookie_value}; "
|
340
340
|
c.each_with_index do |key, idx|
|
@@ -361,16 +361,16 @@ class TestMechanizeCookie < Mechanize::TestCase
|
|
361
361
|
|
362
362
|
# If no path was given, use the one from the URL
|
363
363
|
def test_cookie_using_url_path
|
364
|
-
url = URI.parse('http://
|
364
|
+
url = URI.parse('http://rubygems.org/login.php')
|
365
365
|
cookie_params = {}
|
366
366
|
cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
|
367
367
|
cookie_params['path'] = 'path=/'
|
368
|
-
cookie_params['domain'] = 'domain=.
|
368
|
+
cookie_params['domain'] = 'domain=.rubygems.org'
|
369
369
|
cookie_params['httponly'] = 'HttpOnly'
|
370
370
|
cookie_value = '12345%7D=ASDFWEE345%3DASda'
|
371
371
|
|
372
372
|
expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
|
373
|
-
|
373
|
+
|
374
374
|
cookie_params.keys.combine.each do |c|
|
375
375
|
next if c.find { |k| k == 'path' }
|
376
376
|
cookie_text = "#{cookie_value}; "
|
@@ -398,16 +398,16 @@ class TestMechanizeCookie < Mechanize::TestCase
|
|
398
398
|
|
399
399
|
# Test using secure cookies
|
400
400
|
def test_cookie_with_secure
|
401
|
-
url = URI.parse('http://
|
401
|
+
url = URI.parse('http://rubygems.org/')
|
402
402
|
cookie_params = {}
|
403
403
|
cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
|
404
404
|
cookie_params['path'] = 'path=/'
|
405
|
-
cookie_params['domain'] = 'domain=.
|
405
|
+
cookie_params['domain'] = 'domain=.rubygems.org'
|
406
406
|
cookie_params['secure'] = 'secure'
|
407
407
|
cookie_value = '12345%7D=ASDFWEE345%3DASda'
|
408
408
|
|
409
409
|
expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
|
410
|
-
|
410
|
+
|
411
411
|
cookie_params.keys.combine.each do |c|
|
412
412
|
next unless c.find { |k| k == 'secure' }
|
413
413
|
cookie_text = "#{cookie_value}; "
|
@@ -435,16 +435,16 @@ class TestMechanizeCookie < Mechanize::TestCase
|
|
435
435
|
end
|
436
436
|
|
437
437
|
def test_parse_cookie_no_spaces
|
438
|
-
url = URI.parse('http://
|
438
|
+
url = URI.parse('http://rubygems.org/')
|
439
439
|
cookie_params = {}
|
440
440
|
cookie_params['expires'] = 'expires=Sun, 27-Sep-2037 00:00:00 GMT'
|
441
441
|
cookie_params['path'] = 'path=/'
|
442
|
-
cookie_params['domain'] = 'domain=.
|
442
|
+
cookie_params['domain'] = 'domain=.rubygems.org'
|
443
443
|
cookie_params['httponly'] = 'HttpOnly'
|
444
444
|
cookie_value = '12345%7D=ASDFWEE345%3DASda'
|
445
445
|
|
446
446
|
expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
|
447
|
-
|
447
|
+
|
448
448
|
cookie_params.keys.combine.each do |c|
|
449
449
|
cookie_text = "#{cookie_value};"
|
450
450
|
c.each_with_index do |key, idx|
|
@@ -511,13 +511,13 @@ class TestMechanizeCookie < Mechanize::TestCase
|
|
511
511
|
end
|
512
512
|
|
513
513
|
def test_cookie_httponly
|
514
|
-
url = URI.parse('http://
|
514
|
+
url = URI.parse('http://rubygems.org/')
|
515
515
|
cookie_params = {}
|
516
516
|
cookie_params['httponly'] = 'HttpOnly'
|
517
517
|
cookie_value = '12345%7D=ASDFWEE345%3DASda'
|
518
518
|
|
519
519
|
expires = Time.parse('Sun, 27-Sep-2037 00:00:00 GMT')
|
520
|
-
|
520
|
+
|
521
521
|
cookie_params.keys.combine.each do |c|
|
522
522
|
cookie_text = "#{cookie_value}; "
|
523
523
|
c.each_with_index do |key, idx|
|
@@ -532,7 +532,7 @@ class TestMechanizeCookie < Mechanize::TestCase
|
|
532
532
|
|
533
533
|
assert_equal(true, cookie.httponly)
|
534
534
|
|
535
|
-
|
535
|
+
|
536
536
|
# if expires was set, make sure we parsed it
|
537
537
|
if c.find { |k| k == 'expires' }
|
538
538
|
assert_equal(expires, cookie.expires)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'mechanize/test_case'
|
2
|
+
require 'fileutils'
|
2
3
|
|
3
4
|
class TestMechanizeCookieJar < Mechanize::TestCase
|
4
5
|
|
@@ -39,23 +40,23 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
39
40
|
:path => '/',
|
40
41
|
:expires => Time.now + (10 * 86400),
|
41
42
|
:for_domain => true,
|
42
|
-
:domain => '
|
43
|
+
:domain => 'rubygems.org'
|
43
44
|
}.merge(options)
|
44
45
|
end
|
45
46
|
|
46
47
|
def test_two_cookies_same_domain_and_name_different_paths
|
47
|
-
url = URI 'http://
|
48
|
+
url = URI 'http://rubygems.org/'
|
48
49
|
|
49
50
|
cookie = Mechanize::Cookie.new(cookie_values)
|
50
51
|
@jar.add(url, cookie)
|
51
52
|
@jar.add(url, Mechanize::Cookie.new(cookie_values(:path => '/onetwo')))
|
52
53
|
|
53
54
|
assert_equal(1, @jar.cookies(url).length)
|
54
|
-
assert_equal 2, @jar.cookies(URI('http://
|
55
|
+
assert_equal 2, @jar.cookies(URI('http://rubygems.org/onetwo')).length
|
55
56
|
end
|
56
57
|
|
57
58
|
def test_domain_case
|
58
|
-
url = URI 'http://
|
59
|
+
url = URI 'http://rubygems.org/'
|
59
60
|
|
60
61
|
# Add one cookie with an expiration date in the future
|
61
62
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -63,49 +64,49 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
63
64
|
assert_equal(1, @jar.cookies(url).length)
|
64
65
|
|
65
66
|
@jar.add(url, Mechanize::Cookie.new(
|
66
|
-
cookie_values(:domain => '
|
67
|
+
cookie_values(:domain => 'rubygems.Org', :name => 'aaron')))
|
67
68
|
|
68
69
|
assert_equal(2, @jar.cookies(url).length)
|
69
70
|
|
70
|
-
url2 = URI 'http://
|
71
|
+
url2 = URI 'http://rubygems.oRg/'
|
71
72
|
assert_equal(2, @jar.cookies(url2).length)
|
72
73
|
end
|
73
74
|
|
74
75
|
def test_host_only
|
75
|
-
url = URI.parse('http://
|
76
|
+
url = URI.parse('http://rubygems.org/')
|
76
77
|
|
77
78
|
@jar.add(url, Mechanize::Cookie.new(
|
78
|
-
cookie_values(:domain => '
|
79
|
+
cookie_values(:domain => 'rubygems.org', :for_domain => false)))
|
79
80
|
|
80
81
|
assert_equal(1, @jar.cookies(url).length)
|
81
82
|
|
82
|
-
assert_equal(1, @jar.cookies(URI('http://
|
83
|
+
assert_equal(1, @jar.cookies(URI('http://rubygems.org/')).length)
|
83
84
|
|
84
|
-
assert_equal(1, @jar.cookies(URI('https://
|
85
|
+
assert_equal(1, @jar.cookies(URI('https://rubygems.org/')).length)
|
85
86
|
|
86
|
-
assert_equal(0, @jar.cookies(URI('http://www.
|
87
|
+
assert_equal(0, @jar.cookies(URI('http://www.rubygems.org/')).length)
|
87
88
|
end
|
88
89
|
|
89
90
|
def test_empty_value
|
90
91
|
values = cookie_values(:value => "")
|
91
|
-
url = URI 'http://
|
92
|
+
url = URI 'http://rubygems.org/'
|
92
93
|
|
93
94
|
# Add one cookie with an expiration date in the future
|
94
95
|
cookie = Mechanize::Cookie.new(values)
|
95
96
|
@jar.add(url, cookie)
|
96
97
|
assert_equal(1, @jar.cookies(url).length)
|
97
98
|
|
98
|
-
@jar.add url, Mechanize::Cookie.new(values.merge(:domain => '
|
99
|
+
@jar.add url, Mechanize::Cookie.new(values.merge(:domain => 'rubygems.Org',
|
99
100
|
:name => 'aaron'))
|
100
101
|
|
101
102
|
assert_equal(2, @jar.cookies(url).length)
|
102
103
|
|
103
|
-
url2 = URI 'http://
|
104
|
+
url2 = URI 'http://rubygems.oRg/'
|
104
105
|
assert_equal(2, @jar.cookies(url2).length)
|
105
106
|
end
|
106
107
|
|
107
108
|
def test_add_future_cookies
|
108
|
-
url = URI 'http://
|
109
|
+
url = URI 'http://rubygems.org/'
|
109
110
|
|
110
111
|
# Add one cookie with an expiration date in the future
|
111
112
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -117,14 +118,14 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
117
118
|
assert_equal(1, @jar.cookies(url).length)
|
118
119
|
|
119
120
|
# Make sure we can get the cookie from different paths
|
120
|
-
assert_equal(1, @jar.cookies(URI('http://
|
121
|
+
assert_equal(1, @jar.cookies(URI('http://rubygems.org/login')).length)
|
121
122
|
|
122
123
|
# Make sure we can't get the cookie from different domains
|
123
124
|
assert_equal(0, @jar.cookies(URI('http://google.com/')).length)
|
124
125
|
end
|
125
126
|
|
126
127
|
def test_add_multiple_cookies
|
127
|
-
url = URI 'http://
|
128
|
+
url = URI 'http://rubygems.org/'
|
128
129
|
|
129
130
|
# Add one cookie with an expiration date in the future
|
130
131
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -136,14 +137,14 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
136
137
|
assert_equal(2, @jar.cookies(url).length)
|
137
138
|
|
138
139
|
# Make sure we can get the cookie from different paths
|
139
|
-
assert_equal(2, @jar.cookies(URI('http://
|
140
|
+
assert_equal(2, @jar.cookies(URI('http://rubygems.org/login')).length)
|
140
141
|
|
141
142
|
# Make sure we can't get the cookie from different domains
|
142
143
|
assert_equal(0, @jar.cookies(URI('http://google.com/')).length)
|
143
144
|
end
|
144
145
|
|
145
146
|
def test_add_rejects_cookies_that_do_not_contain_an_embedded_dot
|
146
|
-
url = URI 'http://
|
147
|
+
url = URI 'http://rubygems.org/'
|
147
148
|
|
148
149
|
tld_cookie = Mechanize::Cookie.new(cookie_values(:domain => '.org'))
|
149
150
|
@jar.add(url, tld_cookie)
|
@@ -196,43 +197,43 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
196
197
|
end
|
197
198
|
|
198
199
|
def test_cookie_without_leading_dot_does_not_cause_substring_match
|
199
|
-
url = URI 'http://
|
200
|
+
url = URI 'http://arubygems.org/'
|
200
201
|
|
201
|
-
cookie = Mechanize::Cookie.new(cookie_values(:domain => '
|
202
|
+
cookie = Mechanize::Cookie.new(cookie_values(:domain => 'rubygems.org'))
|
202
203
|
@jar.add(url, cookie)
|
203
204
|
|
204
205
|
assert_equal(0, @jar.cookies(url).length)
|
205
206
|
end
|
206
207
|
|
207
208
|
def test_cookie_without_leading_dot_matches_subdomains
|
208
|
-
url = URI 'http://admin.
|
209
|
+
url = URI 'http://admin.rubygems.org/'
|
209
210
|
|
210
|
-
cookie = Mechanize::Cookie.new(cookie_values(:domain => '
|
211
|
+
cookie = Mechanize::Cookie.new(cookie_values(:domain => 'rubygems.org'))
|
211
212
|
@jar.add(url, cookie)
|
212
213
|
|
213
214
|
assert_equal(1, @jar.cookies(url).length)
|
214
215
|
end
|
215
216
|
|
216
217
|
def test_cookies_with_leading_dot_match_subdomains
|
217
|
-
url = URI 'http://admin.
|
218
|
+
url = URI 'http://admin.rubygems.org/'
|
218
219
|
|
219
|
-
@jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.
|
220
|
+
@jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubygems.org')))
|
220
221
|
|
221
222
|
assert_equal(1, @jar.cookies(url).length)
|
222
223
|
end
|
223
224
|
|
224
225
|
def test_cookies_with_leading_dot_match_parent_domains
|
225
|
-
url = URI 'http://
|
226
|
+
url = URI 'http://rubygems.org/'
|
226
227
|
|
227
|
-
@jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.
|
228
|
+
@jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubygems.org')))
|
228
229
|
|
229
230
|
assert_equal(1, @jar.cookies(url).length)
|
230
231
|
end
|
231
232
|
|
232
233
|
def test_cookies_with_leading_dot_match_parent_domains_exactly
|
233
|
-
url = URI 'http://
|
234
|
+
url = URI 'http://arubygems.org/'
|
234
235
|
|
235
|
-
@jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.
|
236
|
+
@jar.add(url, Mechanize::Cookie.new(cookie_values(:domain => '.rubygems.org')))
|
236
237
|
|
237
238
|
assert_equal(0, @jar.cookies(url).length)
|
238
239
|
end
|
@@ -275,7 +276,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
275
276
|
end
|
276
277
|
|
277
278
|
def test_clear_bang
|
278
|
-
url = URI 'http://
|
279
|
+
url = URI 'http://rubygems.org/'
|
279
280
|
|
280
281
|
# Add one cookie with an expiration date in the future
|
281
282
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -289,7 +290,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
289
290
|
end
|
290
291
|
|
291
292
|
def test_save_cookies_yaml
|
292
|
-
url = URI 'http://
|
293
|
+
url = URI 'http://rubygems.org/'
|
293
294
|
|
294
295
|
# Add one cookie with an expiration date in the future
|
295
296
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -315,7 +316,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
315
316
|
end
|
316
317
|
|
317
318
|
def test_save_session_cookies_yaml
|
318
|
-
url = URI 'http://
|
319
|
+
url = URI 'http://rubygems.org/'
|
319
320
|
|
320
321
|
# Add one cookie with an expiration date in the future
|
321
322
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -341,7 +342,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
341
342
|
|
342
343
|
|
343
344
|
def test_save_cookies_cookiestxt
|
344
|
-
url = URI 'http://
|
345
|
+
url = URI 'http://rubygems.org/'
|
345
346
|
|
346
347
|
# Add one cookie with an expiration date in the future
|
347
348
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -378,7 +379,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
378
379
|
end
|
379
380
|
|
380
381
|
def test_expire_cookies
|
381
|
-
url = URI 'http://
|
382
|
+
url = URI 'http://rubygems.org/'
|
382
383
|
|
383
384
|
# Add one cookie with an expiration date in the future
|
384
385
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -390,7 +391,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
390
391
|
assert_equal(2, @jar.cookies(url).length)
|
391
392
|
|
392
393
|
# Make sure we can get the cookie from different paths
|
393
|
-
assert_equal(2, @jar.cookies(URI('http://
|
394
|
+
assert_equal(2, @jar.cookies(URI('http://rubygems.org/login')).length)
|
394
395
|
|
395
396
|
# Expire the first cookie
|
396
397
|
@jar.add(url, Mechanize::Cookie.new(
|
@@ -405,7 +406,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
405
406
|
|
406
407
|
def test_session_cookies
|
407
408
|
values = cookie_values(:expires => nil)
|
408
|
-
url = URI 'http://
|
409
|
+
url = URI 'http://rubygems.org/'
|
409
410
|
|
410
411
|
# Add one cookie with an expiration date in the future
|
411
412
|
cookie = Mechanize::Cookie.new(values)
|
@@ -417,7 +418,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
417
418
|
assert_equal(2, @jar.cookies(url).length)
|
418
419
|
|
419
420
|
# Make sure we can get the cookie from different paths
|
420
|
-
assert_equal(2, @jar.cookies(URI('http://
|
421
|
+
assert_equal(2, @jar.cookies(URI('http://rubygems.org/login')).length)
|
421
422
|
|
422
423
|
# Expire the first cookie
|
423
424
|
@jar.add(url, Mechanize::Cookie.new(values.merge(:expires => Time.now - (10 * 86400))))
|
@@ -430,7 +431,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
430
431
|
|
431
432
|
# When given a URI with a blank path, CookieJar#cookies should return
|
432
433
|
# cookies with the path '/':
|
433
|
-
url = URI 'http://
|
434
|
+
url = URI 'http://rubygems.org'
|
434
435
|
assert_equal '', url.path
|
435
436
|
assert_equal(0, @jar.cookies(url).length)
|
436
437
|
# Now add a cookie with the path set to '/':
|
@@ -441,7 +442,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
441
442
|
|
442
443
|
def test_paths
|
443
444
|
values = cookie_values(:path => "/login", :expires => nil)
|
444
|
-
url = URI 'http://
|
445
|
+
url = URI 'http://rubygems.org/login'
|
445
446
|
|
446
447
|
# Add one cookie with an expiration date in the future
|
447
448
|
cookie = Mechanize::Cookie.new(values)
|
@@ -453,8 +454,8 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
453
454
|
assert_equal(2, @jar.cookies(url).length)
|
454
455
|
|
455
456
|
# Make sure we don't get the cookie in a different path
|
456
|
-
assert_equal(0, @jar.cookies(URI('http://
|
457
|
-
assert_equal(0, @jar.cookies(URI('http://
|
457
|
+
assert_equal(0, @jar.cookies(URI('http://rubygems.org/hello')).length)
|
458
|
+
assert_equal(0, @jar.cookies(URI('http://rubygems.org/')).length)
|
458
459
|
|
459
460
|
# Expire the first cookie
|
460
461
|
@jar.add(url, Mechanize::Cookie.new(values.merge( :expires => Time.now - (10 * 86400))))
|
@@ -467,7 +468,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
467
468
|
end
|
468
469
|
|
469
470
|
def test_save_and_read_cookiestxt
|
470
|
-
url = URI 'http://
|
471
|
+
url = URI 'http://rubygems.org/'
|
471
472
|
|
472
473
|
# Add one cookie with an expiration date in the future
|
473
474
|
cookie = Mechanize::Cookie.new(cookie_values)
|
@@ -486,7 +487,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
486
487
|
end
|
487
488
|
|
488
489
|
def test_save_and_read_cookiestxt_with_session_cookies
|
489
|
-
url = URI 'http://
|
490
|
+
url = URI 'http://rubygems.org/'
|
490
491
|
|
491
492
|
@jar.add(url, Mechanize::Cookie.new(cookie_values(:expires => nil)))
|
492
493
|
|
@@ -500,10 +501,39 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
500
501
|
assert_equal(0, @jar.cookies(url).length)
|
501
502
|
end
|
502
503
|
|
504
|
+
def test_prevent_command_injection_when_saving
|
505
|
+
url = URI 'http://rubygems.org/'
|
506
|
+
path = '| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\''
|
507
|
+
|
508
|
+
@jar.add(url, Mechanize::Cookie.new(cookie_values))
|
509
|
+
|
510
|
+
in_tmpdir do
|
511
|
+
@jar.save_as(path, :cookiestxt)
|
512
|
+
assert_equal(false, File.exist?('vul.txt'))
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
def test_prevent_command_injection_when_loading
|
517
|
+
url = URI 'http://rubygems.org/'
|
518
|
+
path = '| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\''
|
519
|
+
|
520
|
+
@jar.add(url, Mechanize::Cookie.new(cookie_values))
|
521
|
+
|
522
|
+
in_tmpdir do
|
523
|
+
@jar.save_as("cookies.txt", :cookiestxt)
|
524
|
+
@jar.clear!
|
525
|
+
|
526
|
+
assert_raises Errno::ENOENT do
|
527
|
+
@jar.load(path, :cookiestxt)
|
528
|
+
end
|
529
|
+
assert_equal(false, File.exist?('vul.txt'))
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
503
533
|
def test_save_and_read_expired_cookies
|
504
|
-
url = URI 'http://
|
534
|
+
url = URI 'http://rubygems.org/'
|
505
535
|
|
506
|
-
@jar.jar['
|
536
|
+
@jar.jar['rubygems.org'] = {}
|
507
537
|
|
508
538
|
|
509
539
|
@jar.add url, Mechanize::Cookie.new(cookie_values)
|
@@ -515,7 +545,7 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
515
545
|
# thanks to michal "ocher" ochman for reporting the bug responsible for this test.
|
516
546
|
values = cookie_values(:expires => nil)
|
517
547
|
values_ssl = values.merge(:name => 'Baz', :domain => "#{values[:domain]}:443")
|
518
|
-
url = URI 'https://
|
548
|
+
url = URI 'https://rubygems.org/login'
|
519
549
|
|
520
550
|
cookie = Mechanize::Cookie.new(values)
|
521
551
|
@jar.add(url, cookie)
|
@@ -527,8 +557,8 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
527
557
|
end
|
528
558
|
|
529
559
|
def test_secure_cookie
|
530
|
-
nurl = URI 'http://
|
531
|
-
surl = URI 'https://
|
560
|
+
nurl = URI 'http://rubygems.org/login'
|
561
|
+
surl = URI 'https://rubygems.org/login'
|
532
562
|
|
533
563
|
ncookie = Mechanize::Cookie.new(cookie_values(:name => 'Foo1'))
|
534
564
|
scookie = Mechanize::Cookie.new(cookie_values(:name => 'Foo2', :secure => true))
|
@@ -543,10 +573,10 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
543
573
|
end
|
544
574
|
|
545
575
|
def test_save_cookies_cookiestxt_subdomain
|
546
|
-
top_url = URI 'http://
|
547
|
-
subdomain_url = URI 'http://admin.
|
576
|
+
top_url = URI 'http://rubygems.org/'
|
577
|
+
subdomain_url = URI 'http://admin.rubygems.org/'
|
548
578
|
|
549
|
-
# cookie1 is for *.
|
579
|
+
# cookie1 is for *.rubygems.org; cookie2 is only for rubygems.org, no subdomains
|
550
580
|
cookie1 = Mechanize::Cookie.new(cookie_values)
|
551
581
|
cookie2 = Mechanize::Cookie.new(cookie_values(:name => 'Boo', :for_domain => false))
|
552
582
|
|
@@ -572,8 +602,8 @@ class TestMechanizeCookieJar < Mechanize::TestCase
|
|
572
602
|
# * Cookies that match subdomains may have a leading dot, and must have
|
573
603
|
# TRUE as the second field.
|
574
604
|
cookies_txt = File.readlines("cookies.txt")
|
575
|
-
assert_equal(1, cookies_txt.grep( /^
|
576
|
-
assert_equal(1, cookies_txt.grep( /^\.
|
605
|
+
assert_equal(1, cookies_txt.grep( /^rubygems\.org\tFALSE/ ).length)
|
606
|
+
assert_equal(1, cookies_txt.grep( /^\.rubygems\.org\tTRUE/ ).length)
|
577
607
|
end
|
578
608
|
|
579
609
|
assert_equal(2, @jar.cookies(top_url).length)
|
@@ -46,6 +46,18 @@ class TestMechanizeDownload < Mechanize::TestCase
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
def test_save_bang_does_not_allow_command_injection
|
50
|
+
uri = URI.parse 'http://example/foo.html'
|
51
|
+
body_io = StringIO.new '0123456789'
|
52
|
+
|
53
|
+
download = @parser.new uri, nil, body_io
|
54
|
+
|
55
|
+
in_tmpdir do
|
56
|
+
download.save!('| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
|
57
|
+
refute_operator(File, :exist?, "vul.txt")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
49
61
|
def test_save_tempfile
|
50
62
|
uri = URI.parse 'http://example/foo.html'
|
51
63
|
Tempfile.open @NAME do |body_io|
|
@@ -84,6 +96,5 @@ class TestMechanizeDownload < Mechanize::TestCase
|
|
84
96
|
|
85
97
|
assert_equal "foo.html", download.filename
|
86
98
|
end
|
87
|
-
|
88
99
|
end
|
89
100
|
|
data/test/test_mechanize_file.rb
CHANGED
@@ -103,5 +103,14 @@ class TestMechanizeFile < Mechanize::TestCase
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
+
def test_save_bang_does_not_allow_command_injection
|
107
|
+
uri = URI 'http://example/test.html'
|
108
|
+
page = Mechanize::File.new uri, nil, ''
|
109
|
+
|
110
|
+
in_tmpdir do
|
111
|
+
page.save!('| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
|
112
|
+
refute_operator(File, :exist?, "vul.txt")
|
113
|
+
end
|
114
|
+
end
|
106
115
|
end
|
107
116
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'mechanize/test_case'
|
2
2
|
|
3
3
|
class TestMechanizeFileResponse < Mechanize::TestCase
|
4
|
-
|
5
4
|
def test_content_type
|
6
5
|
Tempfile.open %w[pi .nothtml] do |tempfile|
|
7
6
|
res = Mechanize::FileResponse.new tempfile.path
|
@@ -19,5 +18,24 @@ class TestMechanizeFileResponse < Mechanize::TestCase
|
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
|
-
|
21
|
+
def test_read_body
|
22
|
+
Tempfile.open %w[pi .html] do |tempfile|
|
23
|
+
tempfile.write("asdfasdfasdf")
|
24
|
+
tempfile.close
|
23
25
|
|
26
|
+
res = Mechanize::FileResponse.new(tempfile.path)
|
27
|
+
res.read_body do |input|
|
28
|
+
assert_equal("asdfasdfasdf", input)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_read_body_does_not_allow_command_injection
|
34
|
+
in_tmpdir do
|
35
|
+
FileUtils.touch('| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
|
36
|
+
res = Mechanize::FileResponse.new('| ruby -rfileutils -e \'FileUtils.touch("vul.txt")\'')
|
37
|
+
res.read_body { |_| }
|
38
|
+
refute_operator(File, :exist?, "vul.txt")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/test/test_mechanize_form.rb
CHANGED
@@ -65,6 +65,18 @@ class TestMechanizeForm < Mechanize::TestCase
|
|
65
65
|
assert query.all? { |x| x[1] == '' }
|
66
66
|
end
|
67
67
|
|
68
|
+
def test_build_query_blank_input_name
|
69
|
+
html = Nokogiri::HTML <<-HTML
|
70
|
+
<form>
|
71
|
+
<input type="text" name="" value="foo" />
|
72
|
+
</form>
|
73
|
+
HTML
|
74
|
+
|
75
|
+
form = Mechanize::Form.new html.at('form'), @mech, @page
|
76
|
+
|
77
|
+
assert_equal [], form.build_query
|
78
|
+
end
|
79
|
+
|
68
80
|
def test_build_query_radio_button_duplicate
|
69
81
|
html = Nokogiri::HTML <<-HTML
|
70
82
|
<form>
|
@@ -22,6 +22,7 @@ class TestMechanizeFormKeygen < Mechanize::TestCase
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_spki_signature
|
25
|
+
skip("JRuby PKI doesn't handle this for reasons I've been unable to understand") if RUBY_ENGINE=~/jruby/
|
25
26
|
spki = OpenSSL::Netscape::SPKI.new @keygen.value
|
26
27
|
assert_equal @keygen.challenge, spki.challenge
|
27
28
|
assert_equal @keygen.key.public_key.to_pem, spki.public_key.to_pem
|
@@ -935,7 +935,7 @@ class TestMechanizeHttpAgent < Mechanize::TestCase
|
|
935
935
|
body_io = StringIO.new \
|
936
936
|
"\037\213\b\0002\002\225M\000\003+H,*\001"
|
937
937
|
|
938
|
-
|
938
|
+
skip if jruby_zlib?
|
939
939
|
|
940
940
|
e = assert_raises Mechanize::Error do
|
941
941
|
@agent.response_content_encoding @res, body_io
|
@@ -1590,6 +1590,11 @@ class TestMechanizeHttpAgent < Mechanize::TestCase
|
|
1590
1590
|
end
|
1591
1591
|
|
1592
1592
|
def test_retry_change_request_equals
|
1593
|
+
unless Gem::Requirement.new("< 4.0.0").satisfied_by?(Gem::Version.new(Net::HTTP::Persistent::VERSION))
|
1594
|
+
# see https://github.com/drbrain/net-http-persistent/pull/100
|
1595
|
+
skip("net-http-persistent 4.0.0 and later does not support retry_change_requests")
|
1596
|
+
end
|
1597
|
+
|
1593
1598
|
refute @agent.http.retry_change_requests
|
1594
1599
|
|
1595
1600
|
@agent.retry_change_requests = true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mechanize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.7.
|
4
|
+
version: 2.7.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Hodel
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date:
|
15
|
+
date: 2021-02-01 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: net-http-digest_auth
|
@@ -151,61 +151,19 @@ dependencies:
|
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0.5'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - ">="
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - ">="
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: bundler
|
154
|
+
name: webrick
|
169
155
|
requirement: !ruby/object:Gem::Requirement
|
170
156
|
requirements:
|
171
157
|
- - "~>"
|
172
158
|
- !ruby/object:Gem::Version
|
173
|
-
version: '1.
|
174
|
-
type: :
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - "~>"
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '1.3'
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: rdoc
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - "~>"
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '4.0'
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - "~>"
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: '4.0'
|
195
|
-
- !ruby/object:Gem::Dependency
|
196
|
-
name: minitest
|
197
|
-
requirement: !ruby/object:Gem::Requirement
|
198
|
-
requirements:
|
199
|
-
- - "~>"
|
200
|
-
- !ruby/object:Gem::Version
|
201
|
-
version: '5.0'
|
202
|
-
type: :development
|
159
|
+
version: '1.7'
|
160
|
+
type: :runtime
|
203
161
|
prerelease: false
|
204
162
|
version_requirements: !ruby/object:Gem::Requirement
|
205
163
|
requirements:
|
206
164
|
- - "~>"
|
207
165
|
- !ruby/object:Gem::Version
|
208
|
-
version: '
|
166
|
+
version: '1.7'
|
209
167
|
description: |-
|
210
168
|
The Mechanize library is used for automating interaction with websites.
|
211
169
|
Mechanize automatically stores and sends cookies, follows redirects,
|
@@ -214,22 +172,22 @@ description: |-
|
|
214
172
|
a history.
|
215
173
|
email:
|
216
174
|
- drbrain@segment7.net
|
217
|
-
-
|
175
|
+
- aaron.patterson@gmail.com
|
218
176
|
- mike.dalessio@gmail.com
|
219
177
|
- knu@idaemons.org
|
220
178
|
- ljjarvis@gmail.com
|
221
179
|
executables: []
|
222
180
|
extensions: []
|
223
181
|
extra_rdoc_files:
|
224
|
-
- EXAMPLES.rdoc
|
225
|
-
- CHANGELOG.rdoc
|
226
182
|
- GUIDE.rdoc
|
183
|
+
- EXAMPLES.rdoc
|
227
184
|
- LICENSE.rdoc
|
185
|
+
- CHANGELOG.rdoc
|
228
186
|
- README.rdoc
|
229
187
|
files:
|
230
188
|
- ".autotest"
|
189
|
+
- ".github/workflows/ci-test.yml"
|
231
190
|
- ".gitignore"
|
232
|
-
- ".travis.yml"
|
233
191
|
- CHANGELOG.rdoc
|
234
192
|
- EXAMPLES.rdoc
|
235
193
|
- GUIDE.rdoc
|
@@ -455,8 +413,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
455
413
|
- !ruby/object:Gem::Version
|
456
414
|
version: '0'
|
457
415
|
requirements: []
|
458
|
-
|
459
|
-
rubygems_version: 2.6.14.1
|
416
|
+
rubygems_version: 3.1.4
|
460
417
|
signing_key:
|
461
418
|
specification_version: 4
|
462
419
|
summary: The Mechanize library is used for automating interaction with websites
|
data/.travis.yml
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
---
|
2
|
-
language: ruby
|
3
|
-
notifications:
|
4
|
-
email:
|
5
|
-
- drbrain@segment7.net
|
6
|
-
- ljjarvis@gmail.com
|
7
|
-
- knu@idaemons.org
|
8
|
-
|
9
|
-
sudo: false
|
10
|
-
|
11
|
-
# bundler is missing for jruby-head in travis-ci
|
12
|
-
# https://github.com/travis-ci/travis-ci/issues/5861
|
13
|
-
before_install:
|
14
|
-
- gem install --conservative bundler -v'1.13.7'
|
15
|
-
|
16
|
-
script: rake test
|
17
|
-
|
18
|
-
matrix:
|
19
|
-
include:
|
20
|
-
- rvm: 1.9.3
|
21
|
-
- rvm: 2.0.0
|
22
|
-
- rvm: 2.1
|
23
|
-
- rvm: 2.2
|
24
|
-
- rvm: 2.3.3
|
25
|
-
- rvm: 2.4.0
|
26
|
-
- rvm: ruby-head
|
27
|
-
- rvm: jruby-1.7.27
|
28
|
-
- rvm: jruby-9.1.14.0
|
29
|
-
- rvm: jruby-head
|
30
|
-
allow_failures:
|
31
|
-
- rvm: jruby-9.1.14.0
|
32
|
-
- rvm: jruby-head
|
33
|
-
|
34
|
-
env:
|
35
|
-
global:
|
36
|
-
- JRUBY_OPTS="--debug"
|