actionpack 5.2.4.rc1 → 6.0.0.rc2

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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +179 -335
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -2
  5. data/lib/abstract_controller/base.rb +4 -2
  6. data/lib/abstract_controller/caching/fragments.rb +6 -22
  7. data/lib/abstract_controller/callbacks.rb +12 -0
  8. data/lib/abstract_controller/collector.rb +1 -1
  9. data/lib/abstract_controller/helpers.rb +2 -2
  10. data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
  11. data/lib/abstract_controller/translation.rb +1 -0
  12. data/lib/action_controller.rb +1 -0
  13. data/lib/action_controller/api.rb +2 -1
  14. data/lib/action_controller/base.rb +2 -7
  15. data/lib/action_controller/caching.rb +1 -1
  16. data/lib/action_controller/log_subscriber.rb +8 -5
  17. data/lib/action_controller/metal.rb +1 -1
  18. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  19. data/lib/action_controller/metal/conditional_get.rb +9 -3
  20. data/lib/action_controller/metal/data_streaming.rb +5 -6
  21. data/lib/action_controller/metal/default_headers.rb +17 -0
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
  23. data/lib/action_controller/metal/exceptions.rb +22 -1
  24. data/lib/action_controller/metal/flash.rb +5 -5
  25. data/lib/action_controller/metal/force_ssl.rb +15 -56
  26. data/lib/action_controller/metal/head.rb +1 -1
  27. data/lib/action_controller/metal/helpers.rb +3 -4
  28. data/lib/action_controller/metal/http_authentication.rb +20 -21
  29. data/lib/action_controller/metal/implicit_render.rb +4 -14
  30. data/lib/action_controller/metal/instrumentation.rb +3 -5
  31. data/lib/action_controller/metal/live.rb +29 -27
  32. data/lib/action_controller/metal/mime_responds.rb +13 -2
  33. data/lib/action_controller/metal/params_wrapper.rb +17 -13
  34. data/lib/action_controller/metal/redirecting.rb +5 -5
  35. data/lib/action_controller/metal/renderers.rb +1 -1
  36. data/lib/action_controller/metal/rendering.rb +2 -2
  37. data/lib/action_controller/metal/request_forgery_protection.rb +23 -12
  38. data/lib/action_controller/metal/strong_parameters.rb +63 -44
  39. data/lib/action_controller/metal/url_for.rb +1 -1
  40. data/lib/action_controller/railties/helpers.rb +1 -1
  41. data/lib/action_controller/renderer.rb +16 -3
  42. data/lib/action_controller/template_assertions.rb +1 -1
  43. data/lib/action_controller/test_case.rb +3 -7
  44. data/lib/action_dispatch.rb +4 -1
  45. data/lib/action_dispatch/http/cache.rb +14 -10
  46. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  47. data/lib/action_dispatch/http/content_security_policy.rb +28 -16
  48. data/lib/action_dispatch/http/filter_parameters.rb +8 -6
  49. data/lib/action_dispatch/http/filter_redirect.rb +1 -1
  50. data/lib/action_dispatch/http/headers.rb +1 -1
  51. data/lib/action_dispatch/http/mime_negotiation.rb +7 -5
  52. data/lib/action_dispatch/http/mime_type.rb +14 -6
  53. data/lib/action_dispatch/http/parameter_filter.rb +5 -79
  54. data/lib/action_dispatch/http/parameters.rb +13 -3
  55. data/lib/action_dispatch/http/request.rb +10 -13
  56. data/lib/action_dispatch/http/response.rb +33 -19
  57. data/lib/action_dispatch/http/upload.rb +9 -1
  58. data/lib/action_dispatch/http/url.rb +81 -81
  59. data/lib/action_dispatch/journey/formatter.rb +2 -2
  60. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
  61. data/lib/action_dispatch/journey/nodes/node.rb +9 -8
  62. data/lib/action_dispatch/journey/path/pattern.rb +6 -2
  63. data/lib/action_dispatch/journey/route.rb +5 -4
  64. data/lib/action_dispatch/journey/router.rb +0 -3
  65. data/lib/action_dispatch/journey/router/utils.rb +10 -10
  66. data/lib/action_dispatch/journey/routes.rb +0 -1
  67. data/lib/action_dispatch/journey/scanner.rb +11 -4
  68. data/lib/action_dispatch/journey/visitors.rb +1 -1
  69. data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
  70. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  71. data/lib/action_dispatch/middleware/cookies.rb +46 -72
  72. data/lib/action_dispatch/middleware/debug_exceptions.rb +39 -59
  73. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  74. data/lib/action_dispatch/middleware/debug_view.rb +68 -0
  75. data/lib/action_dispatch/middleware/exception_wrapper.rb +49 -15
  76. data/lib/action_dispatch/middleware/flash.rb +1 -1
  77. data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
  78. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -2
  79. data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
  80. data/lib/action_dispatch/middleware/request_id.rb +2 -2
  81. data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -6
  82. data/lib/action_dispatch/middleware/show_exceptions.rb +1 -1
  83. data/lib/action_dispatch/middleware/ssl.rb +8 -8
  84. data/lib/action_dispatch/middleware/stack.rb +33 -1
  85. data/lib/action_dispatch/middleware/static.rb +5 -6
  86. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  89. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  90. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  91. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  92. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -4
  95. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  96. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +7 -4
  97. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -2
  98. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
  99. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  102. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  103. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  104. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
  105. data/lib/action_dispatch/railtie.rb +3 -0
  106. data/lib/action_dispatch/request/session.rb +8 -0
  107. data/lib/action_dispatch/routing.rb +21 -20
  108. data/lib/action_dispatch/routing/inspector.rb +99 -50
  109. data/lib/action_dispatch/routing/mapper.rb +60 -38
  110. data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
  111. data/lib/action_dispatch/routing/route_set.rb +24 -27
  112. data/lib/action_dispatch/routing/url_for.rb +1 -0
  113. data/lib/action_dispatch/system_test_case.rb +23 -2
  114. data/lib/action_dispatch/system_testing/browser.rb +38 -7
  115. data/lib/action_dispatch/system_testing/driver.rb +10 -1
  116. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +6 -5
  117. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -5
  118. data/lib/action_dispatch/testing/assertions.rb +1 -1
  119. data/lib/action_dispatch/testing/assertions/response.rb +2 -3
  120. data/lib/action_dispatch/testing/assertions/routing.rb +15 -3
  121. data/lib/action_dispatch/testing/integration.rb +12 -5
  122. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  123. data/lib/action_dispatch/testing/test_process.rb +2 -2
  124. data/lib/action_dispatch/testing/test_response.rb +4 -32
  125. data/lib/action_pack.rb +1 -1
  126. data/lib/action_pack/gem_version.rb +4 -4
  127. metadata +24 -13
@@ -25,8 +25,6 @@ module ActionDispatch
25
25
  state = tt.eclosure(0)
26
26
  until input.eos?
27
27
  sym = input.scan(%r([/.?]|[^/.?]+))
28
-
29
- # FIXME: tt.eclosure is not needed for the GTG
30
28
  state = tt.eclosure(tt.move(state, sym))
31
29
  end
32
30
 
@@ -32,7 +32,7 @@ module ActionDispatch
32
32
  end
33
33
 
34
34
  def name
35
- left.tr "*:".freeze, "".freeze
35
+ -left.tr("*:", "")
36
36
  end
37
37
 
38
38
  def type
@@ -65,12 +65,12 @@ module ActionDispatch
65
65
  def literal?; false; end
66
66
  end
67
67
 
68
- %w{ Symbol Slash Dot }.each do |t|
69
- class_eval <<-eoruby, __FILE__, __LINE__ + 1
70
- class #{t} < Terminal;
71
- def type; :#{t.upcase}; end
72
- end
73
- eoruby
68
+ class Slash < Terminal # :nodoc:
69
+ def type; :SLASH; end
70
+ end
71
+
72
+ class Dot < Terminal # :nodoc:
73
+ def type; :DOT; end
74
74
  end
75
75
 
76
76
  class Symbol < Terminal # :nodoc:
@@ -82,13 +82,14 @@ module ActionDispatch
82
82
  def initialize(left)
83
83
  super
84
84
  @regexp = DEFAULT_EXP
85
- @name = left.tr "*:".freeze, "".freeze
85
+ @name = -left.tr("*:", "")
86
86
  end
87
87
 
88
88
  def default_regexp?
89
89
  regexp == DEFAULT_EXP
90
90
  end
91
91
 
92
+ def type; :SYMBOL; end
92
93
  def symbol?; true; end
93
94
  end
94
95
 
@@ -90,7 +90,7 @@ module ActionDispatch
90
90
  return @separator_re unless @matchers.key?(node)
91
91
 
92
92
  re = @matchers[node]
93
- "(#{re})"
93
+ "(#{Regexp.union(re)})"
94
94
  end
95
95
 
96
96
  def visit_GROUP(node)
@@ -137,6 +137,10 @@ module ActionDispatch
137
137
  Array.new(length - 1) { |i| self[i + 1] }
138
138
  end
139
139
 
140
+ def named_captures
141
+ @names.zip(captures).to_h
142
+ end
143
+
140
144
  def [](x)
141
145
  idx = @offsets[x - 1] + x
142
146
  @match[idx]
@@ -184,7 +188,7 @@ module ActionDispatch
184
188
  node = node.to_sym
185
189
 
186
190
  if @requirements.key?(node)
187
- re = /#{@requirements[node]}|/
191
+ re = /#{Regexp.union(@requirements[node])}|/
188
192
  @offsets.push((re.match("").length - 1) + @offsets.last)
189
193
  else
190
194
  @offsets << @offsets.last
@@ -4,9 +4,9 @@ module ActionDispatch
4
4
  # :stopdoc:
5
5
  module Journey
6
6
  class Route
7
- attr_reader :app, :path, :defaults, :name, :precedence
7
+ attr_reader :app, :path, :defaults, :name, :precedence, :constraints,
8
+ :internal, :scope_options
8
9
 
9
- attr_reader :constraints, :internal
10
10
  alias :conditions :constraints
11
11
 
12
12
  module VerbMatchers
@@ -51,13 +51,13 @@ module ActionDispatch
51
51
 
52
52
  def self.build(name, app, path, constraints, required_defaults, defaults)
53
53
  request_method_match = verb_matcher(constraints.delete(:request_method))
54
- new name, app, path, constraints, required_defaults, defaults, request_method_match, 0
54
+ new name, app, path, constraints, required_defaults, defaults, request_method_match, 0, {}
55
55
  end
56
56
 
57
57
  ##
58
58
  # +path+ is a path constraint.
59
59
  # +constraints+ is a hash of constraints to be applied to this route.
60
- def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, internal = false)
60
+ def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, scope_options, internal = false)
61
61
  @name = name
62
62
  @app = app
63
63
  @path = path
@@ -72,6 +72,7 @@ module ActionDispatch
72
72
  @decorated_ast = nil
73
73
  @precedence = precedence
74
74
  @path_formatter = @path.build_formatter
75
+ @scope_options = scope_options
75
76
  @internal = internal
76
77
  end
77
78
 
@@ -15,9 +15,6 @@ require "action_dispatch/journey/path/pattern"
15
15
  module ActionDispatch
16
16
  module Journey # :nodoc:
17
17
  class Router # :nodoc:
18
- class RoutingError < ::StandardError # :nodoc:
19
- end
20
-
21
18
  attr_accessor :routes
22
19
 
23
20
  def initialize(routes)
@@ -17,11 +17,11 @@ module ActionDispatch
17
17
  def self.normalize_path(path)
18
18
  path ||= ""
19
19
  encoding = path.encoding
20
- path = "/#{path}".dup
21
- path.squeeze!("/".freeze)
22
- path.sub!(%r{/+\Z}, "".freeze)
20
+ path = +"/#{path}"
21
+ path.squeeze!("/")
22
+ path.sub!(%r{/+\Z}, "")
23
23
  path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
24
- path = "/".dup if path == "".freeze
24
+ path = +"/" if path == ""
25
25
  path.force_encoding(encoding)
26
26
  path
27
27
  end
@@ -29,16 +29,16 @@ module ActionDispatch
29
29
  # URI path and fragment escaping
30
30
  # https://tools.ietf.org/html/rfc3986
31
31
  class UriEncoder # :nodoc:
32
- ENCODE = "%%%02X".freeze
32
+ ENCODE = "%%%02X"
33
33
  US_ASCII = Encoding::US_ASCII
34
34
  UTF_8 = Encoding::UTF_8
35
- EMPTY = "".dup.force_encoding(US_ASCII).freeze
35
+ EMPTY = (+"").force_encoding(US_ASCII).freeze
36
36
  DEC2HEX = (0..255).to_a.map { |i| ENCODE % i }.map { |s| s.force_encoding(US_ASCII) }
37
37
 
38
- ALPHA = "a-zA-Z".freeze
39
- DIGIT = "0-9".freeze
40
- UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~".freeze
41
- SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;=".freeze
38
+ ALPHA = "a-zA-Z"
39
+ DIGIT = "0-9"
40
+ UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
41
+ SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
42
42
 
43
43
  ESCAPED = /%[a-zA-Z0-9]{2}/.freeze
44
44
 
@@ -56,7 +56,6 @@ module ActionDispatch
56
56
  end
57
57
 
58
58
  def simulator
59
- return if ast.nil?
60
59
  @simulator ||= begin
61
60
  gtg = GTG::Builder.new(ast).transition_table
62
61
  GTG::Simulator.new(gtg)
@@ -34,6 +34,13 @@ module ActionDispatch
34
34
 
35
35
  private
36
36
 
37
+ # takes advantage of String @- deduping capabilities in Ruby 2.5 upwards
38
+ # see: https://bugs.ruby-lang.org/issues/13077
39
+ def dedup_scan(regex)
40
+ r = @ss.scan(regex)
41
+ r ? -r : nil
42
+ end
43
+
37
44
  def scan
38
45
  case
39
46
  # /
@@ -47,15 +54,15 @@ module ActionDispatch
47
54
  [:OR, "|"]
48
55
  when @ss.skip(/\./)
49
56
  [:DOT, "."]
50
- when text = @ss.scan(/:\w+/)
57
+ when text = dedup_scan(/:\w+/)
51
58
  [:SYMBOL, text]
52
- when text = @ss.scan(/\*\w+/)
59
+ when text = dedup_scan(/\*\w+/)
53
60
  [:STAR, text]
54
61
  when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/)
55
62
  text.tr! "\\", ""
56
- [:LITERAL, text]
63
+ [:LITERAL, -text]
57
64
  # any char
58
- when text = @ss.scan(/./)
65
+ when text = dedup_scan(/./)
59
66
  [:LITERAL, text]
60
67
  end
61
68
  end
@@ -40,7 +40,7 @@ module ActionDispatch
40
40
  @parameters.each do |index|
41
41
  param = parts[index]
42
42
  value = hash[param.name]
43
- return "".freeze unless value
43
+ return "" unless value
44
44
  parts[index] = param.escape value
45
45
  end
46
46
 
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "action_dispatch/http/request"
5
+ require "active_support/actionable_error"
6
+
7
+ module ActionDispatch
8
+ class ActionableExceptions # :nodoc:
9
+ cattr_accessor :endpoint, default: "/rails/actions"
10
+
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ request = ActionDispatch::Request.new(env)
17
+ return @app.call(env) unless actionable_request?(request)
18
+
19
+ ActiveSupport::ActionableError.dispatch(request.params[:error].to_s.safe_constantize, request.params[:action])
20
+
21
+ redirect_to request.params[:location]
22
+ end
23
+
24
+ private
25
+ def actionable_request?(request)
26
+ request.show_exceptions? && request.post? && request.path == endpoint
27
+ end
28
+
29
+ def redirect_to(location)
30
+ body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
31
+
32
+ [302, {
33
+ "Content-Type" => "text/html; charset=#{Response.default_charset}",
34
+ "Content-Length" => body.bytesize.to_s,
35
+ "Location" => location,
36
+ }, [body]]
37
+ end
38
+ end
39
+ end
@@ -24,10 +24,8 @@ module ActionDispatch
24
24
  def call(env)
25
25
  error = nil
26
26
  result = run_callbacks :call do
27
- begin
28
- @app.call(env)
29
- rescue => error
30
- end
27
+ @app.call(env)
28
+ rescue => error
31
29
  end
32
30
  raise error if error
33
31
  result
@@ -9,7 +9,7 @@ require "rack/utils"
9
9
  module ActionDispatch
10
10
  class Request
11
11
  def cookie_jar
12
- fetch_header("action_dispatch.cookies".freeze) do
12
+ fetch_header("action_dispatch.cookies") do
13
13
  self.cookie_jar = Cookies::CookieJar.build(self, cookies)
14
14
  end
15
15
  end
@@ -22,11 +22,11 @@ module ActionDispatch
22
22
  }
23
23
 
24
24
  def have_cookie_jar?
25
- has_header? "action_dispatch.cookies".freeze
25
+ has_header? "action_dispatch.cookies"
26
26
  end
27
27
 
28
28
  def cookie_jar=(jar)
29
- set_header "action_dispatch.cookies".freeze, jar
29
+ set_header "action_dispatch.cookies", jar
30
30
  end
31
31
 
32
32
  def key_generator
@@ -61,10 +61,6 @@ module ActionDispatch
61
61
  get_header Cookies::SIGNED_COOKIE_DIGEST
62
62
  end
63
63
 
64
- def secret_token
65
- get_header Cookies::SECRET_TOKEN
66
- end
67
-
68
64
  def secret_key_base
69
65
  get_header Cookies::SECRET_KEY_BASE
70
66
  end
@@ -81,6 +77,10 @@ module ActionDispatch
81
77
  get_header Cookies::COOKIES_ROTATIONS
82
78
  end
83
79
 
80
+ def use_cookies_with_metadata
81
+ get_header Cookies::USE_COOKIES_WITH_METADATA
82
+ end
83
+
84
84
  # :startdoc:
85
85
  end
86
86
 
@@ -168,20 +168,20 @@ module ActionDispatch
168
168
  # * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
169
169
  # only HTTP. Defaults to +false+.
170
170
  class Cookies
171
- HTTP_HEADER = "Set-Cookie".freeze
172
- GENERATOR_KEY = "action_dispatch.key_generator".freeze
173
- SIGNED_COOKIE_SALT = "action_dispatch.signed_cookie_salt".freeze
174
- ENCRYPTED_COOKIE_SALT = "action_dispatch.encrypted_cookie_salt".freeze
175
- ENCRYPTED_SIGNED_COOKIE_SALT = "action_dispatch.encrypted_signed_cookie_salt".freeze
176
- AUTHENTICATED_ENCRYPTED_COOKIE_SALT = "action_dispatch.authenticated_encrypted_cookie_salt".freeze
177
- USE_AUTHENTICATED_COOKIE_ENCRYPTION = "action_dispatch.use_authenticated_cookie_encryption".freeze
178
- ENCRYPTED_COOKIE_CIPHER = "action_dispatch.encrypted_cookie_cipher".freeze
179
- SIGNED_COOKIE_DIGEST = "action_dispatch.signed_cookie_digest".freeze
180
- SECRET_TOKEN = "action_dispatch.secret_token".freeze
181
- SECRET_KEY_BASE = "action_dispatch.secret_key_base".freeze
182
- COOKIES_SERIALIZER = "action_dispatch.cookies_serializer".freeze
183
- COOKIES_DIGEST = "action_dispatch.cookies_digest".freeze
184
- COOKIES_ROTATIONS = "action_dispatch.cookies_rotations".freeze
171
+ HTTP_HEADER = "Set-Cookie"
172
+ GENERATOR_KEY = "action_dispatch.key_generator"
173
+ SIGNED_COOKIE_SALT = "action_dispatch.signed_cookie_salt"
174
+ ENCRYPTED_COOKIE_SALT = "action_dispatch.encrypted_cookie_salt"
175
+ ENCRYPTED_SIGNED_COOKIE_SALT = "action_dispatch.encrypted_signed_cookie_salt"
176
+ AUTHENTICATED_ENCRYPTED_COOKIE_SALT = "action_dispatch.authenticated_encrypted_cookie_salt"
177
+ USE_AUTHENTICATED_COOKIE_ENCRYPTION = "action_dispatch.use_authenticated_cookie_encryption"
178
+ ENCRYPTED_COOKIE_CIPHER = "action_dispatch.encrypted_cookie_cipher"
179
+ SIGNED_COOKIE_DIGEST = "action_dispatch.signed_cookie_digest"
180
+ SECRET_KEY_BASE = "action_dispatch.secret_key_base"
181
+ COOKIES_SERIALIZER = "action_dispatch.cookies_serializer"
182
+ COOKIES_DIGEST = "action_dispatch.cookies_digest"
183
+ COOKIES_ROTATIONS = "action_dispatch.cookies_rotations"
184
+ USE_COOKIES_WITH_METADATA = "action_dispatch.use_cookies_with_metadata"
185
185
 
186
186
  # Cookies can typically store 4096 bytes.
187
187
  MAX_COOKIE_SIZE = 4096
@@ -210,9 +210,6 @@ module ActionDispatch
210
210
  # the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
211
211
  # cookie was tampered with by the user (or a 3rd party), +nil+ will be returned.
212
212
  #
213
- # If +secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
214
- # legacy cookies signed with the old key generator will be transparently upgraded.
215
- #
216
213
  # This jar requires that you set a suitable secret for the verification on your app's +secret_key_base+.
217
214
  #
218
215
  # Example:
@@ -228,9 +225,6 @@ module ActionDispatch
228
225
  # Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
229
226
  # If the cookie was tampered with by the user (or a 3rd party), +nil+ will be returned.
230
227
  #
231
- # If +secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
232
- # legacy cookies signed with the old key generator will be transparently upgraded.
233
- #
234
228
  # If +config.action_dispatch.encrypted_cookie_salt+ and +config.action_dispatch.encrypted_signed_cookie_salt+
235
229
  # are both set, legacy cookies encrypted with HMAC AES-256-CBC will be transparently upgraded.
236
230
  #
@@ -259,10 +253,6 @@ module ActionDispatch
259
253
 
260
254
  private
261
255
 
262
- def upgrade_legacy_signed_cookies?
263
- request.secret_token.present? && request.secret_key_base.present?
264
- end
265
-
266
256
  def upgrade_legacy_hmac_aes_cbc_cookies?
267
257
  request.secret_key_base.present? &&
268
258
  request.encrypted_signed_cookie_salt.present? &&
@@ -348,7 +338,7 @@ module ActionDispatch
348
338
 
349
339
  def update_cookies_from_jar
350
340
  request_jar = @request.cookie_jar.instance_variable_get(:@cookies)
351
- set_cookies = request_jar.reject { |k, _| @delete_cookies.key?(k) }
341
+ set_cookies = request_jar.reject { |k, _| @delete_cookies.key?(k) || @set_cookies.key?(k) }
352
342
 
353
343
  @cookies.update set_cookies if set_cookies
354
344
  end
@@ -470,7 +460,7 @@ module ActionDispatch
470
460
 
471
461
  def [](name)
472
462
  if data = @parent_jar[name.to_s]
473
- parse name, data
463
+ parse(name, data, purpose: "cookie.#{name}") || parse(name, data)
474
464
  end
475
465
  end
476
466
 
@@ -481,7 +471,7 @@ module ActionDispatch
481
471
  options = { value: options }
482
472
  end
483
473
 
484
- commit(options)
474
+ commit(name, options)
485
475
  @parent_jar[name] = options
486
476
  end
487
477
 
@@ -490,24 +480,26 @@ module ActionDispatch
490
480
 
491
481
  private
492
482
  def expiry_options(options)
493
- if request.use_authenticated_cookie_encryption
494
- if options[:expires].respond_to?(:from_now)
495
- { expires_in: options[:expires] }
496
- else
497
- { expires_at: options[:expires] }
498
- end
483
+ if options[:expires].respond_to?(:from_now)
484
+ { expires_in: options[:expires] }
499
485
  else
500
- {}
486
+ { expires_at: options[:expires] }
487
+ end
488
+ end
489
+
490
+ def cookie_metadata(name, options)
491
+ expiry_options(options).tap do |metadata|
492
+ metadata[:purpose] = "cookie.#{name}" if request.use_cookies_with_metadata
501
493
  end
502
494
  end
503
495
 
504
- def parse(name, data); data; end
505
- def commit(options); end
496
+ def parse(name, data, purpose: nil); data; end
497
+ def commit(name, options); end
506
498
  end
507
499
 
508
500
  class PermanentCookieJar < AbstractCookieJar # :nodoc:
509
501
  private
510
- def commit(options)
502
+ def commit(name, options)
511
503
  options[:expires] = 20.years.from_now
512
504
  end
513
505
  end
@@ -523,7 +515,7 @@ module ActionDispatch
523
515
  end
524
516
 
525
517
  module SerializedCookieJars # :nodoc:
526
- MARSHAL_SIGNATURE = "\x04\x08".freeze
518
+ MARSHAL_SIGNATURE = "\x04\x08"
527
519
  SERIALIZER = ActiveSupport::MessageEncryptor::NullSerializer
528
520
 
529
521
  protected
@@ -580,21 +572,17 @@ module ActionDispatch
580
572
  request.cookies_rotations.signed.each do |*secrets, **options|
581
573
  @verifier.rotate(*secrets, serializer: SERIALIZER, **options)
582
574
  end
583
-
584
- if upgrade_legacy_signed_cookies?
585
- @verifier.rotate request.secret_token, serializer: SERIALIZER
586
- end
587
575
  end
588
576
 
589
577
  private
590
- def parse(name, signed_message)
578
+ def parse(name, signed_message, purpose: nil)
591
579
  deserialize(name) do |rotate|
592
- @verifier.verified(signed_message, on_rotation: rotate)
580
+ @verifier.verified(signed_message, on_rotation: rotate, purpose: purpose)
593
581
  end
594
582
  end
595
583
 
596
- def commit(options)
597
- options[:value] = @verifier.generate(serialize(options[:value]), expiry_options(options))
584
+ def commit(name, options)
585
+ options[:value] = @verifier.generate(serialize(options[:value]), cookie_metadata(name, options))
598
586
 
599
587
  raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
600
588
  end
@@ -628,36 +616,22 @@ module ActionDispatch
628
616
 
629
617
  @encryptor.rotate(secret, sign_secret, cipher: legacy_cipher, digest: digest, serializer: SERIALIZER)
630
618
  end
631
-
632
- if upgrade_legacy_signed_cookies?
633
- @legacy_verifier = ActiveSupport::MessageVerifier.new(request.secret_token, digest: digest, serializer: SERIALIZER)
634
- end
635
619
  end
636
620
 
637
621
  private
638
- def parse(name, encrypted_message)
622
+ def parse(name, encrypted_message, purpose: nil)
639
623
  deserialize(name) do |rotate|
640
- @encryptor.decrypt_and_verify(encrypted_message, on_rotation: rotate)
624
+ @encryptor.decrypt_and_verify(encrypted_message, on_rotation: rotate, purpose: purpose)
641
625
  end
642
626
  rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature
643
- parse_legacy_signed_message(name, encrypted_message)
627
+ nil
644
628
  end
645
629
 
646
- def commit(options)
647
- options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]), expiry_options(options))
630
+ def commit(name, options)
631
+ options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]), cookie_metadata(name, options))
648
632
 
649
633
  raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
650
634
  end
651
-
652
- def parse_legacy_signed_message(name, legacy_signed_message)
653
- if defined?(@legacy_verifier)
654
- deserialize(name) do |rotate|
655
- rotate.call
656
-
657
- @legacy_verifier.verified(legacy_signed_message)
658
- end
659
- end
660
- end
661
635
  end
662
636
 
663
637
  def initialize(app)