actionpack 6.0.2.1 → 6.0.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +0 -1
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/collector.rb +0 -1
- data/lib/abstract_controller/helpers.rb +5 -4
- data/lib/abstract_controller/translation.rb +4 -5
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/metal.rb +7 -5
- data/lib/action_controller/metal/content_security_policy.rb +0 -1
- data/lib/action_controller/metal/instrumentation.rb +0 -1
- data/lib/action_controller/metal/live.rb +0 -4
- data/lib/action_controller/metal/params_wrapper.rb +0 -1
- data/lib/action_controller/metal/rendering.rb +0 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +27 -9
- data/lib/action_controller/metal/streaming.rb +0 -1
- data/lib/action_controller/metal/strong_parameters.rb +4 -0
- data/lib/action_controller/test_case.rb +7 -5
- data/lib/action_dispatch.rb +3 -0
- data/lib/action_dispatch/http/cache.rb +0 -1
- data/lib/action_dispatch/http/content_security_policy.rb +0 -2
- data/lib/action_dispatch/http/filter_parameters.rb +0 -1
- data/lib/action_dispatch/http/filter_redirect.rb +0 -1
- data/lib/action_dispatch/http/headers.rb +0 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +0 -1
- data/lib/action_dispatch/http/mime_type.rb +1 -3
- data/lib/action_dispatch/http/parameters.rb +1 -2
- data/lib/action_dispatch/http/request.rb +9 -1
- data/lib/action_dispatch/http/response.rb +0 -1
- data/lib/action_dispatch/http/url.rb +0 -1
- data/lib/action_dispatch/journey/formatter.rb +0 -1
- data/lib/action_dispatch/journey/gtg/builder.rb +0 -1
- data/lib/action_dispatch/journey/gtg/transition_table.rb +0 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -1
- data/lib/action_dispatch/journey/path/pattern.rb +0 -1
- data/lib/action_dispatch/journey/router.rb +0 -1
- data/lib/action_dispatch/journey/routes.rb +0 -1
- data/lib/action_dispatch/journey/scanner.rb +0 -1
- data/lib/action_dispatch/journey/visitors.rb +0 -3
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +6 -6
- data/lib/action_dispatch/middleware/debug_exceptions.rb +7 -3
- data/lib/action_dispatch/middleware/debug_view.rb +3 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +0 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +0 -2
- data/lib/action_dispatch/middleware/public_exceptions.rb +0 -1
- data/lib/action_dispatch/middleware/remote_ip.rb +0 -1
- data/lib/action_dispatch/middleware/session/abstract_store.rb +0 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +0 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +0 -1
- data/lib/action_dispatch/middleware/stack.rb +5 -1
- data/lib/action_dispatch/middleware/static.rb +1 -1
- data/lib/action_dispatch/request/session.rb +0 -1
- data/lib/action_dispatch/routing/inspector.rb +0 -2
- data/lib/action_dispatch/routing/mapper.rb +2 -3
- data/lib/action_dispatch/routing/polymorphic_routes.rb +0 -2
- data/lib/action_dispatch/routing/route_set.rb +1 -4
- data/lib/action_dispatch/routing/url_for.rb +0 -2
- data/lib/action_dispatch/system_test_case.rb +2 -3
- data/lib/action_dispatch/system_testing/driver.rb +2 -2
- data/lib/action_dispatch/testing/assertion_response.rb +0 -1
- data/lib/action_dispatch/testing/integration.rb +22 -7
- data/lib/action_pack/gem_version.rb +2 -2
- metadata +16 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b64b66c90800df2c6d807903bf40f902efb79bc47ca5b83dbd1b247e1bdffcf
|
4
|
+
data.tar.gz: 93e1f48c69ef9d057a40d0b838eea0535bf66d1b683ee5971f7c6c181467a98c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15c8497c65a02f8b1d25c441ba2df08f9a815b96d503ebdfb5bffd396094b6dd8383adafaf8c1c72dffd8c52d1544418b6051e12b22d41d335e222b1e45751cd
|
7
|
+
data.tar.gz: d7de3f0b1c8e0a1d8ca347786a348cbee449cad8583b2255aa33d79d65de8f182e9a105bc750ee8e498ffc2a8899770f5f9cab1cc2a40c7ceb939fcbdb327a73
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,34 @@
|
|
1
|
+
## Rails 6.0.3.2 (June 17, 2020) ##
|
2
|
+
|
3
|
+
* [CVE-2020-8185] Only allow ActionableErrors if show_detailed_exceptions is enabled
|
4
|
+
|
5
|
+
## Rails 6.0.3.1 (May 18, 2020) ##
|
6
|
+
|
7
|
+
* [CVE-2020-8166] HMAC raw CSRF token before masking it, so it cannot be used to reconstruct a per-form token
|
8
|
+
|
9
|
+
* [CVE-2020-8164] Return self when calling #each, #each_pair, and #each_value instead of the raw @parameters hash
|
10
|
+
|
11
|
+
## Rails 6.0.3 (May 06, 2020) ##
|
12
|
+
|
13
|
+
* Include child session assertion count in ActionDispatch::IntegrationTest
|
14
|
+
|
15
|
+
`IntegrationTest#open_session` uses `dup` to create the new session, which
|
16
|
+
meant it had its own copy of `@assertions`. This prevented the assertions
|
17
|
+
from being correctly counted and reported.
|
18
|
+
|
19
|
+
Child sessions now have their `attr_accessor` overriden to delegate to the
|
20
|
+
root session.
|
21
|
+
|
22
|
+
Fixes #32142
|
23
|
+
|
24
|
+
*Sam Bostock*
|
25
|
+
|
26
|
+
|
27
|
+
## Rails 6.0.2.2 (March 19, 2020) ##
|
28
|
+
|
29
|
+
* No changes.
|
30
|
+
|
31
|
+
|
1
32
|
## Rails 6.0.2.1 (December 18, 2019) ##
|
2
33
|
|
3
34
|
* Fix possible information leak / session hijacking vulnerability.
|
data/README.rdoc
CHANGED
@@ -55,4 +55,4 @@ Bug reports for the Ruby on Rails project can be filed here:
|
|
55
55
|
|
56
56
|
Feature requests should be discussed on the rails-core mailing list here:
|
57
57
|
|
58
|
-
* https://
|
58
|
+
* https://discuss.rubyonrails.org/c/rubyonrails-core
|
@@ -61,11 +61,12 @@ module AbstractController
|
|
61
61
|
meths.flatten!
|
62
62
|
self._helper_methods += meths
|
63
63
|
|
64
|
-
meths.each do |
|
64
|
+
meths.each do |method|
|
65
65
|
_helpers.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
|
66
|
-
def #{
|
67
|
-
controller.send(%(#{
|
68
|
-
end
|
66
|
+
def #{method}(*args, &blk) # def current_user(*args, &blk)
|
67
|
+
controller.send(%(#{method}), *args, &blk) # controller.send(:current_user, *args, &blk)
|
68
|
+
end # end
|
69
|
+
ruby2_keywords(%(#{method})) if respond_to?(:ruby2_keywords, true)
|
69
70
|
ruby_eval
|
70
71
|
end
|
71
72
|
end
|
@@ -10,8 +10,7 @@ module AbstractController
|
|
10
10
|
# <tt>I18n.translate("people.index.foo")</tt>. This makes it less repetitive
|
11
11
|
# to translate many keys within the same controller / action and gives you a
|
12
12
|
# simple framework for scoping them consistently.
|
13
|
-
def translate(key, options
|
14
|
-
options = options.dup
|
13
|
+
def translate(key, **options)
|
15
14
|
if key.to_s.first == "."
|
16
15
|
path = controller_path.tr("/", ".")
|
17
16
|
defaults = [:"#{path}#{key}"]
|
@@ -19,13 +18,13 @@ module AbstractController
|
|
19
18
|
options[:default] = defaults.flatten
|
20
19
|
key = "#{path}.#{action_name}#{key}"
|
21
20
|
end
|
22
|
-
I18n.translate(key, options)
|
21
|
+
I18n.translate(key, **options)
|
23
22
|
end
|
24
23
|
alias :t :translate
|
25
24
|
|
26
25
|
# Delegates to <tt>I18n.localize</tt>. Also aliased as <tt>l</tt>.
|
27
|
-
def localize(
|
28
|
-
I18n.localize(
|
26
|
+
def localize(object, **options)
|
27
|
+
I18n.localize(object, **options)
|
29
28
|
end
|
30
29
|
alias :l :localize
|
31
30
|
end
|
@@ -35,7 +35,6 @@ module ActionController
|
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
38
|
-
|
39
38
|
INCLUDE = ->(list, action) { list.include? action }
|
40
39
|
EXCLUDE = ->(list, action) { !list.include? action }
|
41
40
|
NULL = ->(list, action) { true }
|
@@ -217,10 +216,13 @@ module ActionController
|
|
217
216
|
super
|
218
217
|
end
|
219
218
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
219
|
+
class << self
|
220
|
+
# Pushes the given Rack middleware and its arguments to the bottom of the
|
221
|
+
# middleware stack.
|
222
|
+
def use(*args, &block)
|
223
|
+
middleware_stack.use(*args, &block)
|
224
|
+
end
|
225
|
+
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
224
226
|
end
|
225
227
|
|
226
228
|
# Alias for +middleware_stack+.
|
@@ -107,7 +107,6 @@ module ActionController
|
|
107
107
|
end
|
108
108
|
|
109
109
|
private
|
110
|
-
|
111
110
|
def perform_write(json, options)
|
112
111
|
current_options = @options.merge(options).stringify_keys
|
113
112
|
|
@@ -205,7 +204,6 @@ module ActionController
|
|
205
204
|
end
|
206
205
|
|
207
206
|
private
|
208
|
-
|
209
207
|
def each_chunk(&block)
|
210
208
|
loop do
|
211
209
|
str = nil
|
@@ -220,7 +218,6 @@ module ActionController
|
|
220
218
|
|
221
219
|
class Response < ActionDispatch::Response #:nodoc: all
|
222
220
|
private
|
223
|
-
|
224
221
|
def before_committed
|
225
222
|
super
|
226
223
|
jar = request.cookie_jar
|
@@ -286,7 +283,6 @@ module ActionController
|
|
286
283
|
end
|
287
284
|
|
288
285
|
private
|
289
|
-
|
290
286
|
# Spawn a new thread to serve up the controller in. This is to get
|
291
287
|
# around the fact that Rack isn't based around IOs and we need to use
|
292
288
|
# a thread to stream data from the response bodies. Nobody should call
|
@@ -151,7 +151,6 @@ module ActionController #:nodoc:
|
|
151
151
|
end
|
152
152
|
|
153
153
|
private
|
154
|
-
|
155
154
|
def protection_method_class(name)
|
156
155
|
ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify)
|
157
156
|
rescue NameError
|
@@ -175,7 +174,6 @@ module ActionController #:nodoc:
|
|
175
174
|
end
|
176
175
|
|
177
176
|
private
|
178
|
-
|
179
177
|
class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc:
|
180
178
|
def initialize(req)
|
181
179
|
super(nil, req)
|
@@ -324,13 +322,10 @@ module ActionController #:nodoc:
|
|
324
322
|
action_path = normalize_action_path(action)
|
325
323
|
per_form_csrf_token(session, action_path, method)
|
326
324
|
else
|
327
|
-
|
325
|
+
global_csrf_token(session)
|
328
326
|
end
|
329
327
|
|
330
|
-
|
331
|
-
encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token)
|
332
|
-
masked_token = one_time_pad + encrypted_csrf_token
|
333
|
-
Base64.strict_encode64(masked_token)
|
328
|
+
mask_token(raw_token)
|
334
329
|
end
|
335
330
|
|
336
331
|
# Checks the client's masked token to see if it matches the
|
@@ -360,7 +355,8 @@ module ActionController #:nodoc:
|
|
360
355
|
elsif masked_token.length == AUTHENTICITY_TOKEN_LENGTH * 2
|
361
356
|
csrf_token = unmask_token(masked_token)
|
362
357
|
|
363
|
-
|
358
|
+
compare_with_global_token(csrf_token, session) ||
|
359
|
+
compare_with_real_token(csrf_token, session) ||
|
364
360
|
valid_per_form_csrf_token?(csrf_token, session)
|
365
361
|
else
|
366
362
|
false # Token is malformed.
|
@@ -375,10 +371,21 @@ module ActionController #:nodoc:
|
|
375
371
|
xor_byte_strings(one_time_pad, encrypted_csrf_token)
|
376
372
|
end
|
377
373
|
|
374
|
+
def mask_token(raw_token) # :doc:
|
375
|
+
one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
|
376
|
+
encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token)
|
377
|
+
masked_token = one_time_pad + encrypted_csrf_token
|
378
|
+
Base64.strict_encode64(masked_token)
|
379
|
+
end
|
380
|
+
|
378
381
|
def compare_with_real_token(token, session) # :doc:
|
379
382
|
ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, real_csrf_token(session))
|
380
383
|
end
|
381
384
|
|
385
|
+
def compare_with_global_token(token, session) # :doc:
|
386
|
+
ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, global_csrf_token(session))
|
387
|
+
end
|
388
|
+
|
382
389
|
def valid_per_form_csrf_token?(token, session) # :doc:
|
383
390
|
if per_form_csrf_tokens
|
384
391
|
correct_token = per_form_csrf_token(
|
@@ -399,10 +406,21 @@ module ActionController #:nodoc:
|
|
399
406
|
end
|
400
407
|
|
401
408
|
def per_form_csrf_token(session, action_path, method) # :doc:
|
409
|
+
csrf_token_hmac(session, [action_path, method.downcase].join("#"))
|
410
|
+
end
|
411
|
+
|
412
|
+
GLOBAL_CSRF_TOKEN_IDENTIFIER = "!real_csrf_token"
|
413
|
+
private_constant :GLOBAL_CSRF_TOKEN_IDENTIFIER
|
414
|
+
|
415
|
+
def global_csrf_token(session) # :doc:
|
416
|
+
csrf_token_hmac(session, GLOBAL_CSRF_TOKEN_IDENTIFIER)
|
417
|
+
end
|
418
|
+
|
419
|
+
def csrf_token_hmac(session, identifier) # :doc:
|
402
420
|
OpenSSL::HMAC.digest(
|
403
421
|
OpenSSL::Digest::SHA256.new,
|
404
422
|
real_csrf_token(session),
|
405
|
-
|
423
|
+
identifier
|
406
424
|
)
|
407
425
|
end
|
408
426
|
|
@@ -344,6 +344,8 @@ module ActionController
|
|
344
344
|
@parameters.each_pair do |key, value|
|
345
345
|
yield [key, convert_hashes_to_parameters(key, value)]
|
346
346
|
end
|
347
|
+
|
348
|
+
self
|
347
349
|
end
|
348
350
|
alias_method :each, :each_pair
|
349
351
|
|
@@ -353,6 +355,8 @@ module ActionController
|
|
353
355
|
@parameters.each_pair do |key, value|
|
354
356
|
yield convert_hashes_to_parameters(key, value)
|
355
357
|
end
|
358
|
+
|
359
|
+
self
|
356
360
|
end
|
357
361
|
|
358
362
|
# Attribute that keeps track of converted arrays, if any, to avoid double
|
@@ -158,7 +158,6 @@ module ActionController
|
|
158
158
|
end.new
|
159
159
|
|
160
160
|
private
|
161
|
-
|
162
161
|
def params_parsers
|
163
162
|
super.merge @custom_param_parsers
|
164
163
|
end
|
@@ -177,12 +176,12 @@ module ActionController
|
|
177
176
|
|
178
177
|
# Methods #destroy and #load! are overridden to avoid calling methods on the
|
179
178
|
# @store object, which does not exist for the TestSession class.
|
180
|
-
class TestSession < Rack::Session::Abstract::
|
179
|
+
class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash #:nodoc:
|
181
180
|
DEFAULT_OPTIONS = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS
|
182
181
|
|
183
182
|
def initialize(session = {})
|
184
183
|
super(nil, nil)
|
185
|
-
@id = SecureRandom.hex(16)
|
184
|
+
@id = Rack::Session::SessionId.new(SecureRandom.hex(16))
|
186
185
|
@data = stringify_keys(session)
|
187
186
|
@loaded = true
|
188
187
|
end
|
@@ -203,12 +202,16 @@ module ActionController
|
|
203
202
|
clear
|
204
203
|
end
|
205
204
|
|
205
|
+
def dig(*keys)
|
206
|
+
keys = keys.map.with_index { |key, i| i.zero? ? key.to_s : key }
|
207
|
+
@data.dig(*keys)
|
208
|
+
end
|
209
|
+
|
206
210
|
def fetch(key, *args, &block)
|
207
211
|
@data.fetch(key.to_s, *args, &block)
|
208
212
|
end
|
209
213
|
|
210
214
|
private
|
211
|
-
|
212
215
|
def load!
|
213
216
|
@id
|
214
217
|
end
|
@@ -595,7 +598,6 @@ module ActionController
|
|
595
598
|
end
|
596
599
|
|
597
600
|
private
|
598
|
-
|
599
601
|
def scrub_env!(env)
|
600
602
|
env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
|
601
603
|
env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
|
data/lib/action_dispatch.rb
CHANGED
@@ -31,7 +31,6 @@ module ActionDispatch #:nodoc:
|
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
|
-
|
35
34
|
def html_response?(headers)
|
36
35
|
if content_type = headers[CONTENT_TYPE]
|
37
36
|
content_type =~ /html/
|
@@ -101,7 +100,6 @@ module ActionDispatch #:nodoc:
|
|
101
100
|
end
|
102
101
|
|
103
102
|
private
|
104
|
-
|
105
103
|
def generate_content_security_policy_nonce
|
106
104
|
content_security_policy_nonce_generator.call(self)
|
107
105
|
end
|