actionpack 5.2.4.5 → 6.0.0.beta1
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 +111 -384
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -21
- 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/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 +2 -2
- 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/exceptions.rb +22 -1
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +17 -57
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +1 -2
- data/lib/action_controller/metal/http_authentication.rb +20 -21
- data/lib/action_controller/metal/implicit_render.rb +2 -12
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +28 -26
- data/lib/action_controller/metal/mime_responds.rb +13 -2
- data/lib/action_controller/metal/params_wrapper.rb +18 -14
- data/lib/action_controller/metal/redirecting.rb +32 -11
- data/lib/action_controller/metal/rendering.rb +1 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +26 -40
- data/lib/action_controller/metal/strong_parameters.rb +57 -34
- 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 +15 -2
- data/lib/action_controller/test_case.rb +3 -7
- data/lib/action_dispatch.rb +7 -6
- 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 +9 -8
- 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 -10
- data/lib/action_dispatch/http/mime_type.rb +1 -5
- 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 +14 -14
- data/lib/action_dispatch/http/upload.rb +5 -0
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +1 -1
- 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 +3 -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/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +49 -70
- data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -58
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +50 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +36 -7
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- 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/abstract_store.rb +0 -14
- data/lib/action_dispatch/middleware/session/cache_store.rb +6 -11
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -27
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +2 -2
- data/lib/action_dispatch/middleware/static.rb +5 -6
- 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 +20 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- 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 +1 -0
- data/lib/action_dispatch/request/session.rb +8 -6
- data/lib/action_dispatch/routing.rb +3 -2
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +36 -29
- data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
- data/lib/action_dispatch/routing/route_set.rb +11 -12
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +7 -2
- data/lib/action_dispatch/testing/integration.rb +11 -4
- 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 +22 -20
@@ -32,7 +32,7 @@ module ActionDispatch
|
|
32
32
|
req = ActionDispatch::Request.new env
|
33
33
|
|
34
34
|
if req.get?
|
35
|
-
path = req.path_info.chomp("/"
|
35
|
+
path = req.path_info.chomp("/")
|
36
36
|
if path == @path
|
37
37
|
return render_details(req)
|
38
38
|
end
|
@@ -63,19 +63,19 @@ module ActionDispatch
|
|
63
63
|
|
64
64
|
str = threads.map do |thread, info|
|
65
65
|
if info[:exclusive]
|
66
|
-
lock_state = "Exclusive"
|
66
|
+
lock_state = +"Exclusive"
|
67
67
|
elsif info[:sharing] > 0
|
68
|
-
lock_state = "Sharing"
|
68
|
+
lock_state = +"Sharing"
|
69
69
|
lock_state << " x#{info[:sharing]}" if info[:sharing] > 1
|
70
70
|
else
|
71
|
-
lock_state = "No lock"
|
71
|
+
lock_state = +"No lock"
|
72
72
|
end
|
73
73
|
|
74
74
|
if info[:waiting]
|
75
75
|
lock_state << " (yielded share)"
|
76
76
|
end
|
77
77
|
|
78
|
-
msg = "Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n"
|
78
|
+
msg = +"Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n"
|
79
79
|
|
80
80
|
if info[:sleeper]
|
81
81
|
msg << " Waiting in #{info[:sleeper]}"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pp"
|
4
|
+
|
5
|
+
require "action_view"
|
6
|
+
require "action_view/base"
|
7
|
+
|
8
|
+
module ActionDispatch
|
9
|
+
class DebugView < ActionView::Base # :nodoc:
|
10
|
+
RESCUES_TEMPLATE_PATH = File.expand_path("templates", __dir__)
|
11
|
+
|
12
|
+
def initialize(assigns)
|
13
|
+
super([RESCUES_TEMPLATE_PATH], assigns)
|
14
|
+
end
|
15
|
+
|
16
|
+
def debug_params(params)
|
17
|
+
clean_params = params.clone
|
18
|
+
clean_params.delete("action")
|
19
|
+
clean_params.delete("controller")
|
20
|
+
|
21
|
+
if clean_params.empty?
|
22
|
+
"None"
|
23
|
+
else
|
24
|
+
PP.pp(clean_params, +"", 200)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def debug_headers(headers)
|
29
|
+
if headers.present?
|
30
|
+
headers.inspect.gsub(",", ",\n")
|
31
|
+
else
|
32
|
+
"None"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def debug_hash(object)
|
37
|
+
object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
def render(*)
|
41
|
+
logger = ActionView::Base.logger
|
42
|
+
|
43
|
+
if logger && logger.respond_to?(:silence)
|
44
|
+
logger.silence { super }
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -12,6 +12,7 @@ module ActionDispatch
|
|
12
12
|
"ActionController::UnknownHttpMethod" => :method_not_allowed,
|
13
13
|
"ActionController::NotImplemented" => :not_implemented,
|
14
14
|
"ActionController::UnknownFormat" => :not_acceptable,
|
15
|
+
"ActionController::MissingExactTemplate" => :not_acceptable,
|
15
16
|
"ActionController::InvalidAuthenticityToken" => :unprocessable_entity,
|
16
17
|
"ActionController::InvalidCrossOriginRequest" => :unprocessable_entity,
|
17
18
|
"ActionDispatch::Http::Parameters::ParseError" => :bad_request,
|
@@ -22,18 +23,20 @@ module ActionDispatch
|
|
22
23
|
)
|
23
24
|
|
24
25
|
cattr_accessor :rescue_templates, default: Hash.new("diagnostics").merge!(
|
25
|
-
"ActionView::MissingTemplate"
|
26
|
-
"ActionController::RoutingError"
|
27
|
-
"AbstractController::ActionNotFound"
|
28
|
-
"ActiveRecord::StatementInvalid"
|
29
|
-
"ActionView::Template::Error"
|
26
|
+
"ActionView::MissingTemplate" => "missing_template",
|
27
|
+
"ActionController::RoutingError" => "routing_error",
|
28
|
+
"AbstractController::ActionNotFound" => "unknown_action",
|
29
|
+
"ActiveRecord::StatementInvalid" => "invalid_statement",
|
30
|
+
"ActionView::Template::Error" => "template_error",
|
31
|
+
"ActionController::MissingExactTemplate" => "missing_exact_template",
|
30
32
|
)
|
31
33
|
|
32
|
-
attr_reader :backtrace_cleaner, :exception, :line_number, :file
|
34
|
+
attr_reader :backtrace_cleaner, :exception, :wrapped_causes, :line_number, :file
|
33
35
|
|
34
36
|
def initialize(backtrace_cleaner, exception)
|
35
37
|
@backtrace_cleaner = backtrace_cleaner
|
36
38
|
@exception = original_exception(exception)
|
39
|
+
@wrapped_causes = wrapped_causes_for(exception, backtrace_cleaner)
|
37
40
|
|
38
41
|
expand_backtrace if exception.is_a?(SyntaxError) || exception.cause.is_a?(SyntaxError)
|
39
42
|
end
|
@@ -64,7 +67,11 @@ module ActionDispatch
|
|
64
67
|
full_trace_with_ids = []
|
65
68
|
|
66
69
|
full_trace.each_with_index do |trace, idx|
|
67
|
-
trace_with_id = {
|
70
|
+
trace_with_id = {
|
71
|
+
exception_object_id: @exception.object_id,
|
72
|
+
id: idx,
|
73
|
+
trace: trace
|
74
|
+
}
|
68
75
|
|
69
76
|
if application_trace.include?(trace)
|
70
77
|
application_trace_with_ids << trace_with_id
|
@@ -97,6 +104,18 @@ module ActionDispatch
|
|
97
104
|
end
|
98
105
|
end
|
99
106
|
|
107
|
+
def trace_to_show
|
108
|
+
if traces["Application Trace"].empty? && rescue_template != "routing_error"
|
109
|
+
"Full Trace"
|
110
|
+
else
|
111
|
+
"Application Trace"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def source_to_show_id
|
116
|
+
(traces[trace_to_show].first || {})[:id]
|
117
|
+
end
|
118
|
+
|
100
119
|
private
|
101
120
|
|
102
121
|
def backtrace
|
@@ -111,6 +130,16 @@ module ActionDispatch
|
|
111
130
|
end
|
112
131
|
end
|
113
132
|
|
133
|
+
def causes_for(exception)
|
134
|
+
return enum_for(__method__, exception) unless block_given?
|
135
|
+
|
136
|
+
yield exception while exception = exception.cause
|
137
|
+
end
|
138
|
+
|
139
|
+
def wrapped_causes_for(exception, backtrace_cleaner)
|
140
|
+
causes_for(exception).map { |cause| self.class.new(backtrace_cleaner, cause) }
|
141
|
+
end
|
142
|
+
|
114
143
|
def clean_backtrace(*args)
|
115
144
|
if backtrace_cleaner
|
116
145
|
backtrace_cleaner.clean(backtrace, *args)
|
@@ -38,7 +38,7 @@ module ActionDispatch
|
|
38
38
|
#
|
39
39
|
# See docs on the FlashHash class for more details about the flash.
|
40
40
|
class Flash
|
41
|
-
KEY = "action_dispatch.request.flash_hash"
|
41
|
+
KEY = "action_dispatch.request.flash_hash"
|
42
42
|
|
43
43
|
module RequestMethods
|
44
44
|
# Access the contents of the flash. Use <tt>flash["notice"]</tt> to
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_dispatch/http/request"
|
4
|
+
|
5
|
+
module ActionDispatch
|
6
|
+
# This middleware guards from DNS rebinding attacks by white-listing the
|
7
|
+
# hosts a request can be sent to.
|
8
|
+
#
|
9
|
+
# When a request comes to an unauthorized host, the +response_app+
|
10
|
+
# application will be executed and rendered. If no +response_app+ is given, a
|
11
|
+
# default one will run, which responds with +403 Forbidden+.
|
12
|
+
class HostAuthorization
|
13
|
+
class Permissions # :nodoc:
|
14
|
+
def initialize(hosts)
|
15
|
+
@hosts = sanitize_hosts(hosts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def empty?
|
19
|
+
@hosts.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def allows?(host)
|
23
|
+
@hosts.any? do |allowed|
|
24
|
+
allowed === host
|
25
|
+
rescue
|
26
|
+
# IPAddr#=== raises an error if you give it a hostname instead of
|
27
|
+
# IP. Treat similar errors as blocked access.
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def sanitize_hosts(hosts)
|
35
|
+
Array(hosts).map do |host|
|
36
|
+
case host
|
37
|
+
when Regexp then sanitize_regexp(host)
|
38
|
+
when String then sanitize_string(host)
|
39
|
+
else host
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def sanitize_regexp(host)
|
45
|
+
/\A#{host}\z/
|
46
|
+
end
|
47
|
+
|
48
|
+
def sanitize_string(host)
|
49
|
+
if host.start_with?(".")
|
50
|
+
/\A(.+\.)?#{Regexp.escape(host[1..-1])}\z/
|
51
|
+
else
|
52
|
+
host
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
DEFAULT_RESPONSE_APP = -> env do
|
58
|
+
request = Request.new(env)
|
59
|
+
|
60
|
+
format = request.xhr? ? "text/plain" : "text/html"
|
61
|
+
template = DebugView.new(host: request.host)
|
62
|
+
body = template.render(template: "rescues/blocked_host", layout: "rescues/layout")
|
63
|
+
|
64
|
+
[403, {
|
65
|
+
"Content-Type" => "#{format}; charset=#{Response.default_charset}",
|
66
|
+
"Content-Length" => body.bytesize.to_s,
|
67
|
+
}, [body]]
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize(app, hosts, response_app = nil)
|
71
|
+
@app = app
|
72
|
+
@permissions = Permissions.new(hosts)
|
73
|
+
@response_app = response_app || DEFAULT_RESPONSE_APP
|
74
|
+
end
|
75
|
+
|
76
|
+
def call(env)
|
77
|
+
return @app.call(env) if @permissions.empty?
|
78
|
+
|
79
|
+
request = Request.new(env)
|
80
|
+
|
81
|
+
if authorized?(request)
|
82
|
+
mark_as_authorized(request)
|
83
|
+
@app.call(env)
|
84
|
+
else
|
85
|
+
@response_app.call(env)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def authorized?(request)
|
92
|
+
origin_host = request.get_header("HTTP_HOST").to_s.sub(/:\d+\z/, "")
|
93
|
+
forwarded_host = request.x_forwarded_host.to_s.split(/,\s?/).last.to_s.sub(/:\d+\z/, "")
|
94
|
+
|
95
|
+
@permissions.allows?(origin_host) &&
|
96
|
+
(forwarded_host.blank? || @permissions.allows?(forwarded_host))
|
97
|
+
end
|
98
|
+
|
99
|
+
def mark_as_authorized(request)
|
100
|
+
request.set_header("action_dispatch.authorized_host", request.host)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -162,14 +162,12 @@ module ActionDispatch
|
|
162
162
|
# Split the comma-separated list into an array of strings.
|
163
163
|
ips = header.strip.split(/[,\s]+/)
|
164
164
|
ips.select do |ip|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
nil
|
172
|
-
end
|
165
|
+
# Only return IPs that are valid according to the IPAddr#new method.
|
166
|
+
range = IPAddr.new(ip).to_range
|
167
|
+
# We want to make sure nobody is sneaking a netmask in.
|
168
|
+
range.begin == range.end
|
169
|
+
rescue ArgumentError
|
170
|
+
nil
|
173
171
|
end
|
174
172
|
end
|
175
173
|
|
@@ -15,7 +15,7 @@ module ActionDispatch
|
|
15
15
|
# The unique request id can be used to trace a request end-to-end and would typically end up being part of log files
|
16
16
|
# from multiple pieces of the stack.
|
17
17
|
class RequestId
|
18
|
-
X_REQUEST_ID = "X-Request-Id"
|
18
|
+
X_REQUEST_ID = "X-Request-Id" #:nodoc:
|
19
19
|
|
20
20
|
def initialize(app)
|
21
21
|
@app = app
|
@@ -30,7 +30,7 @@ module ActionDispatch
|
|
30
30
|
private
|
31
31
|
def make_request_id(request_id)
|
32
32
|
if request_id.presence
|
33
|
-
request_id.gsub(/[^\w\-@]/, ""
|
33
|
+
request_id.gsub(/[^\w\-@]/, "").first(255)
|
34
34
|
else
|
35
35
|
internal_request_id
|
36
36
|
end
|
@@ -83,21 +83,7 @@ module ActionDispatch
|
|
83
83
|
include SessionObject
|
84
84
|
|
85
85
|
private
|
86
|
-
def set_cookie(request, session_id, cookie)
|
87
|
-
request.cookie_jar[key] = cookie
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class AbstractSecureStore < Rack::Session::Abstract::PersistedSecure
|
92
|
-
include Compatibility
|
93
|
-
include StaleSessionCheck
|
94
|
-
include SessionObject
|
95
|
-
|
96
|
-
def generate_sid
|
97
|
-
Rack::Session::SessionId.new(super)
|
98
|
-
end
|
99
86
|
|
100
|
-
private
|
101
87
|
def set_cookie(request, session_id, cookie)
|
102
88
|
request.cookie_jar[key] = cookie
|
103
89
|
end
|
@@ -12,7 +12,7 @@ module ActionDispatch
|
|
12
12
|
# * <tt>cache</tt> - The cache to use. If it is not specified, <tt>Rails.cache</tt> will be used.
|
13
13
|
# * <tt>expire_after</tt> - The length of time a session will be stored before automatically expiring.
|
14
14
|
# By default, the <tt>:expires_in</tt> option of the cache is used.
|
15
|
-
class CacheStore <
|
15
|
+
class CacheStore < AbstractStore
|
16
16
|
def initialize(app, options = {})
|
17
17
|
@cache = options[:cache] || Rails.cache
|
18
18
|
options[:expire_after] ||= @cache.options[:expires_in]
|
@@ -21,7 +21,7 @@ module ActionDispatch
|
|
21
21
|
|
22
22
|
# Get a session from the cache.
|
23
23
|
def find_session(env, sid)
|
24
|
-
unless sid && (session =
|
24
|
+
unless sid && (session = @cache.read(cache_key(sid)))
|
25
25
|
sid, session = generate_sid, {}
|
26
26
|
end
|
27
27
|
[sid, session]
|
@@ -29,7 +29,7 @@ module ActionDispatch
|
|
29
29
|
|
30
30
|
# Set a session in the cache.
|
31
31
|
def write_session(env, sid, session, options)
|
32
|
-
key = cache_key(sid
|
32
|
+
key = cache_key(sid)
|
33
33
|
if session
|
34
34
|
@cache.write(key, session, expires_in: options[:expire_after])
|
35
35
|
else
|
@@ -40,19 +40,14 @@ module ActionDispatch
|
|
40
40
|
|
41
41
|
# Remove a session from the cache.
|
42
42
|
def delete_session(env, sid, options)
|
43
|
-
@cache.delete(cache_key(sid
|
44
|
-
@cache.delete(cache_key(sid.public_id))
|
43
|
+
@cache.delete(cache_key(sid))
|
45
44
|
generate_sid
|
46
45
|
end
|
47
46
|
|
48
47
|
private
|
49
48
|
# Turn the session id into a cache key.
|
50
|
-
def cache_key(
|
51
|
-
"_session_id:#{
|
52
|
-
end
|
53
|
-
|
54
|
-
def get_session_with_fallback(sid)
|
55
|
-
@cache.read(cache_key(sid.private_id)) || @cache.read(cache_key(sid.public_id))
|
49
|
+
def cache_key(sid)
|
50
|
+
"_session_id:#{sid}"
|
56
51
|
end
|
57
52
|
end
|
58
53
|
end
|
@@ -16,23 +16,17 @@ module ActionDispatch
|
|
16
16
|
# The cookie jar used for storage is automatically configured to be the
|
17
17
|
# best possible option given your application's configuration.
|
18
18
|
#
|
19
|
-
# If you only have secret_token set, your cookies will be signed, but
|
20
|
-
# not encrypted. This means a user cannot alter their +user_id+ without
|
21
|
-
# knowing your app's secret key, but can easily read their +user_id+. This
|
22
|
-
# was the default for Rails 3 apps.
|
23
|
-
#
|
24
19
|
# Your cookies will be encrypted using your apps secret_key_base. This
|
25
20
|
# goes a step further than signed cookies in that encrypted cookies cannot
|
26
21
|
# be altered or read by users. This is the default starting in Rails 4.
|
27
22
|
#
|
28
|
-
# Configure your session store in
|
23
|
+
# Configure your session store in an initializer:
|
29
24
|
#
|
30
25
|
# Rails.application.config.session_store :cookie_store, key: '_your_app_session'
|
31
26
|
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# <tt>config/credentials.yml.enc</tt> file.
|
27
|
+
# By default, your secret key base is derived from your application name in
|
28
|
+
# the test and development environments. In all other environments, it is stored
|
29
|
+
# encrypted in the <tt>config/credentials.yml.enc</tt> file.
|
36
30
|
#
|
37
31
|
# If your application was not updated to Rails 5.2 defaults, the secret_key_base
|
38
32
|
# will be found in the old <tt>config/secrets.yml</tt> file.
|
@@ -51,16 +45,7 @@ module ActionDispatch
|
|
51
45
|
# would set the session cookie to expire automatically 14 days after creation.
|
52
46
|
# Other useful options include <tt>:key</tt>, <tt>:secure</tt> and
|
53
47
|
# <tt>:httponly</tt>.
|
54
|
-
class CookieStore <
|
55
|
-
class SessionId < DelegateClass(Rack::Session::SessionId)
|
56
|
-
attr_reader :cookie_value
|
57
|
-
|
58
|
-
def initialize(session_id, cookie_value = {})
|
59
|
-
super(session_id)
|
60
|
-
@cookie_value = cookie_value
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
48
|
+
class CookieStore < AbstractStore
|
64
49
|
def initialize(app, options = {})
|
65
50
|
super(app, options.merge!(cookie_only: true))
|
66
51
|
end
|
@@ -68,7 +53,7 @@ module ActionDispatch
|
|
68
53
|
def delete_session(req, session_id, options)
|
69
54
|
new_sid = generate_sid unless options[:drop]
|
70
55
|
# Reset hash and Assign the new session id
|
71
|
-
req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid
|
56
|
+
req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid } : {})
|
72
57
|
new_sid
|
73
58
|
end
|
74
59
|
|
@@ -76,7 +61,7 @@ module ActionDispatch
|
|
76
61
|
stale_session_check! do
|
77
62
|
data = unpacked_cookie_data(req)
|
78
63
|
data = persistent_session_id!(data)
|
79
|
-
[
|
64
|
+
[data["session_id"], data]
|
80
65
|
end
|
81
66
|
end
|
82
67
|
|
@@ -84,8 +69,7 @@ module ActionDispatch
|
|
84
69
|
|
85
70
|
def extract_session_id(req)
|
86
71
|
stale_session_check! do
|
87
|
-
|
88
|
-
sid && Rack::Session::SessionId.new(sid)
|
72
|
+
unpacked_cookie_data(req)["session_id"]
|
89
73
|
end
|
90
74
|
end
|
91
75
|
|
@@ -103,13 +87,13 @@ module ActionDispatch
|
|
103
87
|
|
104
88
|
def persistent_session_id!(data, sid = nil)
|
105
89
|
data ||= {}
|
106
|
-
data["session_id"] ||= sid || generate_sid
|
90
|
+
data["session_id"] ||= sid || generate_sid
|
107
91
|
data
|
108
92
|
end
|
109
93
|
|
110
94
|
def write_session(req, sid, session_data, options)
|
111
|
-
session_data["session_id"] = sid
|
112
|
-
|
95
|
+
session_data["session_id"] = sid
|
96
|
+
session_data
|
113
97
|
end
|
114
98
|
|
115
99
|
def set_cookie(request, session_id, cookie)
|