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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +179 -335
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -2
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/callbacks.rb +12 -0
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/abstract_controller/translation.rb +1 -0
- data/lib/action_controller.rb +1 -0
- data/lib/action_controller/api.rb +2 -1
- data/lib/action_controller/base.rb +2 -7
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -5
- data/lib/action_controller/metal.rb +1 -1
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +9 -3
- data/lib/action_controller/metal/data_streaming.rb +5 -6
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
- data/lib/action_controller/metal/exceptions.rb +22 -1
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +15 -56
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +3 -4
- data/lib/action_controller/metal/http_authentication.rb +20 -21
- data/lib/action_controller/metal/implicit_render.rb +4 -14
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +29 -27
- data/lib/action_controller/metal/mime_responds.rb +13 -2
- data/lib/action_controller/metal/params_wrapper.rb +17 -13
- data/lib/action_controller/metal/redirecting.rb +5 -5
- data/lib/action_controller/metal/renderers.rb +1 -1
- data/lib/action_controller/metal/rendering.rb +2 -2
- data/lib/action_controller/metal/request_forgery_protection.rb +23 -12
- data/lib/action_controller/metal/strong_parameters.rb +63 -44
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +16 -3
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +3 -7
- data/lib/action_dispatch.rb +4 -1
- data/lib/action_dispatch/http/cache.rb +14 -10
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +28 -16
- data/lib/action_dispatch/http/filter_parameters.rb +8 -6
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +7 -5
- data/lib/action_dispatch/http/mime_type.rb +14 -6
- data/lib/action_dispatch/http/parameter_filter.rb +5 -79
- data/lib/action_dispatch/http/parameters.rb +13 -3
- data/lib/action_dispatch/http/request.rb +10 -13
- data/lib/action_dispatch/http/response.rb +33 -19
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
- data/lib/action_dispatch/journey/nodes/node.rb +9 -8
- data/lib/action_dispatch/journey/path/pattern.rb +6 -2
- data/lib/action_dispatch/journey/route.rb +5 -4
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- data/lib/action_dispatch/journey/routes.rb +0 -1
- data/lib/action_dispatch/journey/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +46 -72
- data/lib/action_dispatch/middleware/debug_exceptions.rb +39 -59
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +68 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +49 -15
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -2
- data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -6
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +33 -1
- data/lib/action_dispatch/middleware/static.rb +5 -6
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
- data/lib/action_dispatch/railtie.rb +3 -0
- data/lib/action_dispatch/request/session.rb +8 -0
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +60 -38
- data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
- data/lib/action_dispatch/routing/route_set.rb +24 -27
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_test_case.rb +23 -2
- data/lib/action_dispatch/system_testing/browser.rb +38 -7
- data/lib/action_dispatch/system_testing/driver.rb +10 -1
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +6 -5
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -5
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -3
- data/lib/action_dispatch/testing/integration.rb +12 -5
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +24 -13
@@ -32,7 +32,7 @@ module ActionDispatch
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def name
|
35
|
-
left.tr
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
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
|
|
@@ -17,11 +17,11 @@ module ActionDispatch
|
|
17
17
|
def self.normalize_path(path)
|
18
18
|
path ||= ""
|
19
19
|
encoding = path.encoding
|
20
|
-
path = "/#{path}"
|
21
|
-
path.squeeze!("/"
|
22
|
-
path.sub!(%r{/+\Z}, ""
|
20
|
+
path = +"/#{path}"
|
21
|
+
path.squeeze!("/")
|
22
|
+
path.sub!(%r{/+\Z}, "")
|
23
23
|
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
|
24
|
-
path = "/"
|
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"
|
32
|
+
ENCODE = "%%%02X"
|
33
33
|
US_ASCII = Encoding::US_ASCII
|
34
34
|
UTF_8 = Encoding::UTF_8
|
35
|
-
EMPTY = "".
|
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"
|
39
|
-
DIGIT = "0-9"
|
40
|
-
UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
|
41
|
-
SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
|
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
|
|
@@ -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 =
|
57
|
+
when text = dedup_scan(/:\w+/)
|
51
58
|
[:SYMBOL, text]
|
52
|
-
when text =
|
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 =
|
65
|
+
when text = dedup_scan(/./)
|
59
66
|
[:LITERAL, text]
|
60
67
|
end
|
61
68
|
end
|
@@ -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
|
@@ -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"
|
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"
|
25
|
+
has_header? "action_dispatch.cookies"
|
26
26
|
end
|
27
27
|
|
28
28
|
def cookie_jar=(jar)
|
29
|
-
set_header "action_dispatch.cookies"
|
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"
|
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
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
494
|
-
|
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"
|
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]),
|
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
|
-
|
627
|
+
nil
|
644
628
|
end
|
645
629
|
|
646
|
-
def commit(options)
|
647
|
-
options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]),
|
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)
|