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.

Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.rdoc +1 -1
  4. data/lib/abstract_controller/base.rb +0 -1
  5. data/lib/abstract_controller/caching.rb +1 -1
  6. data/lib/abstract_controller/collector.rb +0 -1
  7. data/lib/abstract_controller/helpers.rb +5 -4
  8. data/lib/abstract_controller/translation.rb +4 -5
  9. data/lib/action_controller/caching.rb +0 -1
  10. data/lib/action_controller/metal.rb +7 -5
  11. data/lib/action_controller/metal/content_security_policy.rb +0 -1
  12. data/lib/action_controller/metal/instrumentation.rb +0 -1
  13. data/lib/action_controller/metal/live.rb +0 -4
  14. data/lib/action_controller/metal/params_wrapper.rb +0 -1
  15. data/lib/action_controller/metal/rendering.rb +0 -1
  16. data/lib/action_controller/metal/request_forgery_protection.rb +27 -9
  17. data/lib/action_controller/metal/streaming.rb +0 -1
  18. data/lib/action_controller/metal/strong_parameters.rb +4 -0
  19. data/lib/action_controller/test_case.rb +7 -5
  20. data/lib/action_dispatch.rb +3 -0
  21. data/lib/action_dispatch/http/cache.rb +0 -1
  22. data/lib/action_dispatch/http/content_security_policy.rb +0 -2
  23. data/lib/action_dispatch/http/filter_parameters.rb +0 -1
  24. data/lib/action_dispatch/http/filter_redirect.rb +0 -1
  25. data/lib/action_dispatch/http/headers.rb +0 -1
  26. data/lib/action_dispatch/http/mime_negotiation.rb +0 -1
  27. data/lib/action_dispatch/http/mime_type.rb +1 -3
  28. data/lib/action_dispatch/http/parameters.rb +1 -2
  29. data/lib/action_dispatch/http/request.rb +9 -1
  30. data/lib/action_dispatch/http/response.rb +0 -1
  31. data/lib/action_dispatch/http/url.rb +0 -1
  32. data/lib/action_dispatch/journey/formatter.rb +0 -1
  33. data/lib/action_dispatch/journey/gtg/builder.rb +0 -1
  34. data/lib/action_dispatch/journey/gtg/transition_table.rb +0 -1
  35. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -1
  36. data/lib/action_dispatch/journey/path/pattern.rb +0 -1
  37. data/lib/action_dispatch/journey/router.rb +0 -1
  38. data/lib/action_dispatch/journey/routes.rb +0 -1
  39. data/lib/action_dispatch/journey/scanner.rb +0 -1
  40. data/lib/action_dispatch/journey/visitors.rb +0 -3
  41. data/lib/action_dispatch/middleware/actionable_exceptions.rb +1 -1
  42. data/lib/action_dispatch/middleware/cookies.rb +6 -6
  43. data/lib/action_dispatch/middleware/debug_exceptions.rb +7 -3
  44. data/lib/action_dispatch/middleware/debug_view.rb +3 -5
  45. data/lib/action_dispatch/middleware/exception_wrapper.rb +0 -1
  46. data/lib/action_dispatch/middleware/host_authorization.rb +0 -2
  47. data/lib/action_dispatch/middleware/public_exceptions.rb +0 -1
  48. data/lib/action_dispatch/middleware/remote_ip.rb +0 -1
  49. data/lib/action_dispatch/middleware/session/abstract_store.rb +0 -1
  50. data/lib/action_dispatch/middleware/session/cookie_store.rb +0 -1
  51. data/lib/action_dispatch/middleware/show_exceptions.rb +0 -1
  52. data/lib/action_dispatch/middleware/stack.rb +5 -1
  53. data/lib/action_dispatch/middleware/static.rb +1 -1
  54. data/lib/action_dispatch/request/session.rb +0 -1
  55. data/lib/action_dispatch/routing/inspector.rb +0 -2
  56. data/lib/action_dispatch/routing/mapper.rb +2 -3
  57. data/lib/action_dispatch/routing/polymorphic_routes.rb +0 -2
  58. data/lib/action_dispatch/routing/route_set.rb +1 -4
  59. data/lib/action_dispatch/routing/url_for.rb +0 -2
  60. data/lib/action_dispatch/system_test_case.rb +2 -3
  61. data/lib/action_dispatch/system_testing/driver.rb +2 -2
  62. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  63. data/lib/action_dispatch/testing/integration.rb +22 -7
  64. data/lib/action_pack/gem_version.rb +2 -2
  65. metadata +16 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb4d2886c2ddd45b39d89f4adb1d70764435a236d046d4db4d703ad93318e464
4
- data.tar.gz: 776bd2d00abd923d4a80437fb99fd77741d90ca0269b16ca2e03b3de99e966aa
3
+ metadata.gz: 8b64b66c90800df2c6d807903bf40f902efb79bc47ca5b83dbd1b247e1bdffcf
4
+ data.tar.gz: 93e1f48c69ef9d057a40d0b838eea0535bf66d1b683ee5971f7c6c181467a98c
5
5
  SHA512:
6
- metadata.gz: 9858771c2bcabdc985dcd72927c56ec47fc4e54d3c1a1e0e116111fcf70046f8add6a4cde9448611552fae7131b6e87e68eec389212ff989174ebd7e997bb675
7
- data.tar.gz: 3761566fbc2835aa652aee777633857b29e3dfab4556c3fc0a1f16ffa53f28cb3f7166fb42f04917bdf3df79e75320e0eea865f12ad4762deb6c5e0d47a969c8
6
+ metadata.gz: 15c8497c65a02f8b1d25c441ba2df08f9a815b96d503ebdfb5bffd396094b6dd8383adafaf8c1c72dffd8c52d1544418b6051e12b22d41d335e222b1e45751cd
7
+ data.tar.gz: d7de3f0b1c8e0a1d8ca347786a348cbee449cad8583b2255aa33d79d65de8f182e9a105bc750ee8e498ffc2a8899770f5f9cab1cc2a40c7ceb939fcbdb327a73
@@ -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.
@@ -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://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
58
+ * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -176,7 +176,6 @@ module AbstractController
176
176
  end
177
177
 
178
178
  private
179
-
180
179
  # Returns true if the name can be considered an action because
181
180
  # it has a method defined in the controller.
182
181
  #
@@ -15,7 +15,7 @@ module AbstractController
15
15
  end
16
16
 
17
17
  def cache_store=(store)
18
- config.cache_store = ActiveSupport::Cache.lookup_store(store)
18
+ config.cache_store = ActiveSupport::Cache.lookup_store(*store)
19
19
  end
20
20
 
21
21
  private
@@ -22,7 +22,6 @@ module AbstractController
22
22
  end
23
23
 
24
24
  private
25
-
26
25
  def method_missing(symbol, &block)
27
26
  unless mime_constant = Mime[symbol]
28
27
  raise NoMethodError, "To respond to a custom format, register it as a MIME type first: " \
@@ -61,11 +61,12 @@ module AbstractController
61
61
  meths.flatten!
62
62
  self._helper_methods += meths
63
63
 
64
- meths.each do |meth|
64
+ meths.each do |method|
65
65
  _helpers.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
66
- def #{meth}(*args, &blk) # def current_user(*args, &blk)
67
- controller.send(%(#{meth}), *args, &blk) # controller.send(:current_user, *args, &blk)
68
- end # 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(*args)
28
- I18n.localize(*args)
26
+ def localize(object, **options)
27
+ I18n.localize(object, **options)
29
28
  end
30
29
  alias :l :localize
31
30
  end
@@ -30,7 +30,6 @@ module ActionController
30
30
  end
31
31
 
32
32
  private
33
-
34
33
  def instrument_payload(key)
35
34
  {
36
35
  controller: controller_name,
@@ -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
- # Pushes the given Rack middleware and its arguments to the bottom of the
221
- # middleware stack.
222
- def self.use(*args, &block)
223
- middleware_stack.use(*args, &block)
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+.
@@ -36,7 +36,6 @@ module ActionController #:nodoc:
36
36
  end
37
37
 
38
38
  private
39
-
40
39
  def content_security_policy?
41
40
  request.content_security_policy
42
41
  end
@@ -69,7 +69,6 @@ module ActionController
69
69
  end
70
70
 
71
71
  private
72
-
73
72
  # A hook invoked every time a before callback is halted.
74
73
  def halted_callback_hook(filter)
75
74
  ActiveSupport::Notifications.instrument("halted_callback.action_controller", filter: filter)
@@ -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
@@ -246,7 +246,6 @@ module ActionController
246
246
  end
247
247
 
248
248
  private
249
-
250
249
  # Returns the wrapper key which will be used to store wrapped parameters.
251
250
  def _wrapper_key
252
251
  _wrapper_options.name
@@ -53,7 +53,6 @@ module ActionController
53
53
  end
54
54
 
55
55
  private
56
-
57
56
  def _process_variant(options)
58
57
  if defined?(request) && !request.nil? && request.variant.present?
59
58
  options[:variant] = request.variant
@@ -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
- real_csrf_token(session)
325
+ global_csrf_token(session)
328
326
  end
329
327
 
330
- one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
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
- compare_with_real_token(csrf_token, session) ||
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
- [action_path, method.downcase].join("#")
423
+ identifier
406
424
  )
407
425
  end
408
426
 
@@ -196,7 +196,6 @@ module ActionController #:nodoc:
196
196
  extend ActiveSupport::Concern
197
197
 
198
198
  private
199
-
200
199
  # Set proper cache control and transfer encoding when streaming
201
200
  def _process_options(options)
202
201
  super
@@ -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::SessionHash #:nodoc:
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/ }
@@ -40,6 +40,9 @@ module ActionDispatch
40
40
  class IllegalStateError < StandardError
41
41
  end
42
42
 
43
+ class MissingController < NameError
44
+ end
45
+
43
46
  eager_autoload do
44
47
  autoload_under "http" do
45
48
  autoload :ContentSecurityPolicy
@@ -123,7 +123,6 @@ module ActionDispatch
123
123
  end
124
124
 
125
125
  private
126
-
127
126
  DATE = "Date"
128
127
  LAST_MODIFIED = "Last-Modified"
129
128
  SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public private must-revalidate])
@@ -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
@@ -56,7 +56,6 @@ module ActionDispatch
56
56
  end
57
57
 
58
58
  private
59
-
60
59
  def parameter_filter # :doc:
61
60
  parameter_filter_for fetch_header("action_dispatch.parameter_filter") {
62
61
  return NULL_PARAM_FILTER
@@ -14,7 +14,6 @@ module ActionDispatch
14
14
  end
15
15
 
16
16
  private
17
-
18
17
  def location_filters
19
18
  if request
20
19
  request.get_header("action_dispatch.redirect_filter") || []
@@ -116,7 +116,6 @@ module ActionDispatch
116
116
  def env; @req.env.dup; end
117
117
 
118
118
  private
119
-
120
119
  # Converts an HTTP header name to an environment variable name if it is
121
120
  # not contained within the headers hash.
122
121
  def env_name(key)