actionpack 7.0.3.1 → 7.0.4.1
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 +28 -0
- data/lib/abstract_controller/helpers.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +7 -2
- data/lib/action_controller/metal/rendering.rb +2 -2
- data/lib/action_controller/metal/strong_parameters.rb +7 -2
- data/lib/action_dispatch/http/cache.rb +1 -1
- data/lib/action_dispatch/http/response.rb +2 -3
- data/lib/action_dispatch/middleware/cookies.rb +30 -23
- data/lib/action_dispatch/middleware/server_timing.rb +53 -10
- data/lib/action_dispatch/middleware/session/cookie_store.rb +7 -7
- data/lib/action_dispatch/routing/mapper.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +20 -2
- data/lib/action_pack/gem_version.rb +1 -1
- metadata +12 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f31d845cb672a69a48bf5a99d24da4cc0a1911dd90592b7f569954a08040d32
|
4
|
+
data.tar.gz: 4f82a27ee5dba8c642621ab247ef345b7daff0e9e4fe25c3ba81163a2a31b8d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7094329330497de30fa9dbae232a2563a3699129681dbba34092db10f3e07d97b9905abe2d4339f50c39b8f45c6e9765a77523c379dbe53f3ff96cb544586483
|
7
|
+
data.tar.gz: db8c045d237562750468b511cd54990c2fe0069fe7942e663f013f6cdfa30e7211b8f9874cdc7187dc0b16f1238cb331dde86bbd38f796688935e541b0fcac25
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
## Rails 7.0.4.1 (January 17, 2023) ##
|
2
|
+
|
3
|
+
* Fix sec issue with _url_host_allowed?
|
4
|
+
|
5
|
+
Disallow certain strings from `_url_host_allowed?` to avoid a redirect
|
6
|
+
to malicious sites.
|
7
|
+
|
8
|
+
[CVE-2023-22797]
|
9
|
+
|
10
|
+
* Avoid regex backtracking on If-None-Match header
|
11
|
+
|
12
|
+
[CVE-2023-22795]
|
13
|
+
|
14
|
+
* Use string#split instead of regex for domain parts
|
15
|
+
|
16
|
+
[CVE-2023-22792]
|
17
|
+
|
18
|
+
|
19
|
+
## Rails 7.0.4 (September 09, 2022) ##
|
20
|
+
|
21
|
+
* Prevent `ActionDispatch::ServerTiming` from overwriting existing values in `Server-Timing`.
|
22
|
+
|
23
|
+
Previously, if another middleware down the chain set `Server-Timing` header,
|
24
|
+
it would overwritten by `ActionDispatch::ServerTiming`.
|
25
|
+
|
26
|
+
*Jakub Malinowski*
|
27
|
+
|
28
|
+
|
1
29
|
## Rails 7.0.3.1 (July 12, 2022) ##
|
2
30
|
|
3
31
|
* No changes.
|
@@ -110,7 +110,7 @@ module AbstractController
|
|
110
110
|
# The last two assume that <tt>"foo".camelize</tt> returns "Foo".
|
111
111
|
#
|
112
112
|
# When strings or symbols are passed, the method finds the actual module
|
113
|
-
# object using
|
113
|
+
# object using String#constantize. Therefore, if the module has not been
|
114
114
|
# yet loaded, it has to be autoloadable, which is normally the case.
|
115
115
|
#
|
116
116
|
# Namespaces are supported. The following calls include +Foo::BarHelper+:
|
@@ -117,7 +117,7 @@ module ActionController
|
|
117
117
|
# * <tt>:allow_other_host</tt> - Allow or disallow redirection to the host that is different to the current host, defaults to true.
|
118
118
|
#
|
119
119
|
# All other options that can be passed to #redirect_to are accepted as
|
120
|
-
# options and the behavior is identical.
|
120
|
+
# options, and the behavior is identical.
|
121
121
|
def redirect_back_or_to(fallback_location, allow_other_host: _allow_other_host, **options)
|
122
122
|
if request.referer && (allow_other_host || _url_host_allowed?(request.referer))
|
123
123
|
redirect_to request.referer, allow_other_host: allow_other_host, **options
|
@@ -195,7 +195,12 @@ module ActionController
|
|
195
195
|
end
|
196
196
|
|
197
197
|
def _url_host_allowed?(url)
|
198
|
-
|
198
|
+
host = URI(url.to_s).host
|
199
|
+
|
200
|
+
return true if host == request.host
|
201
|
+
return false unless host.nil?
|
202
|
+
return false unless url.to_s.start_with?("/")
|
203
|
+
return !url.to_s.start_with?("//")
|
199
204
|
rescue ArgumentError, URI::Error
|
200
205
|
false
|
201
206
|
end
|
@@ -78,8 +78,8 @@ module ActionController
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def _set_vary_header
|
81
|
-
if
|
82
|
-
|
81
|
+
if response.headers["Vary"].blank? && request.should_apply_vary_header?
|
82
|
+
response.headers["Vary"] = "Accept"
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -279,10 +279,15 @@ module ActionController
|
|
279
279
|
@parameters == other
|
280
280
|
end
|
281
281
|
end
|
282
|
-
|
282
|
+
|
283
|
+
def eql?(other)
|
284
|
+
self.class == other.class &&
|
285
|
+
permitted? == other.permitted? &&
|
286
|
+
parameters.eql?(other.parameters)
|
287
|
+
end
|
283
288
|
|
284
289
|
def hash
|
285
|
-
[@parameters
|
290
|
+
[self.class, @parameters, @permitted].hash
|
286
291
|
end
|
287
292
|
|
288
293
|
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
|
@@ -21,9 +21,8 @@ module ActionDispatch # :nodoc:
|
|
21
21
|
# Nevertheless, integration tests may want to inspect controller responses in
|
22
22
|
# more detail, and that's when \Response can be useful for application
|
23
23
|
# developers. Integration test methods such as
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# TestResponse (which are of course also of type \Response).
|
24
|
+
# Integration::RequestHelpers#get and Integration::RequestHelpers#post return
|
25
|
+
# objects of type TestResponse (which are of course also of type \Response).
|
27
26
|
#
|
28
27
|
# For example, the following demo integration test prints the body of the
|
29
28
|
# controller response to the console:
|
@@ -92,7 +92,7 @@ module ActionDispatch
|
|
92
92
|
include RequestCookieMethods
|
93
93
|
end
|
94
94
|
|
95
|
-
# Read and write data to cookies through ActionController#cookies.
|
95
|
+
# Read and write data to cookies through ActionController::Base#cookies.
|
96
96
|
#
|
97
97
|
# When reading cookie data, the data is read from the HTTP request header, Cookie.
|
98
98
|
# When writing cookie data, the data is sent out in the HTTP response header, Set-Cookie.
|
@@ -178,8 +178,7 @@ module ActionDispatch
|
|
178
178
|
# only HTTP. Defaults to +false+.
|
179
179
|
# * <tt>:same_site</tt> - The value of the +SameSite+ cookie attribute, which
|
180
180
|
# determines how this cookie should be restricted in cross-site contexts.
|
181
|
-
# Possible values are
|
182
|
-
# +:lax+.
|
181
|
+
# Possible values are +:none+, +:lax+, and +:strict+. Defaults to +:lax+.
|
183
182
|
class Cookies
|
184
183
|
HTTP_HEADER = "Set-Cookie"
|
185
184
|
GENERATOR_KEY = "action_dispatch.key_generator"
|
@@ -291,20 +290,6 @@ module ActionDispatch
|
|
291
290
|
class CookieJar # :nodoc:
|
292
291
|
include Enumerable, ChainedCookieJars
|
293
292
|
|
294
|
-
# This regular expression is used to split the levels of a domain.
|
295
|
-
# The top level domain can be any string without a period or
|
296
|
-
# **.**, ***.** style TLDs like co.uk or com.au
|
297
|
-
#
|
298
|
-
# www.example.co.uk gives:
|
299
|
-
# $& => example.co.uk
|
300
|
-
#
|
301
|
-
# example.com gives:
|
302
|
-
# $& => example.com
|
303
|
-
#
|
304
|
-
# lots.of.subdomains.example.local gives:
|
305
|
-
# $& => example.local
|
306
|
-
DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
|
307
|
-
|
308
293
|
def self.build(req, cookies)
|
309
294
|
jar = new(req)
|
310
295
|
jar.update(cookies)
|
@@ -457,13 +442,35 @@ module ActionDispatch
|
|
457
442
|
options[:same_site] ||= cookies_same_site_protection.call(request)
|
458
443
|
|
459
444
|
if options[:domain] == :all || options[:domain] == "all"
|
460
|
-
|
461
|
-
|
445
|
+
cookie_domain = ""
|
446
|
+
dot_splitted_host = request.host.split('.', -1)
|
447
|
+
|
448
|
+
# Case where request.host is not an IP address or it's an invalid domain
|
449
|
+
# (ip confirms to the domain structure we expect so we explicitly check for ip)
|
450
|
+
if request.host.match?(/^[\d.]+$/) || dot_splitted_host.include?("") || dot_splitted_host.length == 1
|
451
|
+
options[:domain] = nil
|
452
|
+
return
|
453
|
+
end
|
454
|
+
|
455
|
+
# If there is a provided tld length then we use it otherwise default domain.
|
456
|
+
if options[:tld_length].present?
|
457
|
+
# Case where the tld_length provided is valid
|
458
|
+
if dot_splitted_host.length >= options[:tld_length]
|
459
|
+
cookie_domain = dot_splitted_host.last(options[:tld_length]).join('.')
|
460
|
+
end
|
461
|
+
# Case where tld_length is not provided
|
462
|
+
else
|
463
|
+
# Regular TLDs
|
464
|
+
if !(/([^.]{2,3}\.[^.]{2})$/.match?(request.host))
|
465
|
+
cookie_domain = dot_splitted_host.last(2).join('.')
|
466
|
+
# **.**, ***.** style TLDs like co.uk and com.au
|
467
|
+
else
|
468
|
+
cookie_domain = dot_splitted_host.last(3).join('.')
|
469
|
+
end
|
470
|
+
end
|
462
471
|
|
463
|
-
|
464
|
-
|
465
|
-
options[:domain] = if !request.host.match?(/^[\d.]+$/) && (request.host =~ domain_regexp)
|
466
|
-
".#{$&}"
|
472
|
+
options[:domain] = if cookie_domain.present?
|
473
|
+
".#{cookie_domain}"
|
467
474
|
end
|
468
475
|
elsif options[:domain].is_a? Array
|
469
476
|
# If host matches one of the supplied domains.
|
@@ -6,28 +6,71 @@ module ActionDispatch
|
|
6
6
|
class ServerTiming
|
7
7
|
SERVER_TIMING_HEADER = "Server-Timing"
|
8
8
|
|
9
|
+
class Subscriber # :nodoc:
|
10
|
+
include Singleton
|
11
|
+
KEY = :action_dispatch_server_timing_events
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@mutex = Mutex.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(event)
|
18
|
+
if events = ActiveSupport::IsolatedExecutionState[KEY]
|
19
|
+
events << event
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def collect_events
|
24
|
+
events = []
|
25
|
+
ActiveSupport::IsolatedExecutionState[KEY] = events
|
26
|
+
yield
|
27
|
+
events
|
28
|
+
ensure
|
29
|
+
ActiveSupport::IsolatedExecutionState.delete(KEY)
|
30
|
+
end
|
31
|
+
|
32
|
+
def ensure_subscribed
|
33
|
+
@mutex.synchronize do
|
34
|
+
# Subscribe to all events, except those beginning with "!"
|
35
|
+
# Ideally we would be more selective of what is being measured
|
36
|
+
@subscriber ||= ActiveSupport::Notifications.subscribe(/\A[^!]/, self)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def unsubscribe
|
41
|
+
@mutex.synchronize do
|
42
|
+
ActiveSupport::Notifications.unsubscribe @subscriber
|
43
|
+
@subscriber = nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.unsubscribe # :nodoc:
|
49
|
+
Subscriber.instance.unsubscribe
|
50
|
+
end
|
51
|
+
|
9
52
|
def initialize(app)
|
10
53
|
@app = app
|
54
|
+
@subscriber = Subscriber.instance
|
55
|
+
@subscriber.ensure_subscribed
|
11
56
|
end
|
12
57
|
|
13
58
|
def call(env)
|
14
|
-
|
15
|
-
|
16
|
-
|
59
|
+
response = nil
|
60
|
+
events = @subscriber.collect_events do
|
61
|
+
response = @app.call(env)
|
17
62
|
end
|
18
63
|
|
19
|
-
|
20
|
-
@app.call(env)
|
21
|
-
ensure
|
22
|
-
ActiveSupport::Notifications.unsubscribe(subscriber)
|
23
|
-
end
|
64
|
+
headers = response[1]
|
24
65
|
|
25
66
|
header_info = events.group_by(&:name).map do |event_name, events_collection|
|
26
|
-
"
|
67
|
+
"%s;dur=%.2f" % [event_name, events_collection.sum(&:duration)]
|
27
68
|
end
|
69
|
+
|
70
|
+
header_info.prepend(headers[SERVER_TIMING_HEADER]) if headers[SERVER_TIMING_HEADER].present?
|
28
71
|
headers[SERVER_TIMING_HEADER] = header_info.join(", ")
|
29
72
|
|
30
|
-
|
73
|
+
response
|
31
74
|
end
|
32
75
|
end
|
33
76
|
end
|
@@ -9,14 +9,14 @@ module ActionDispatch
|
|
9
9
|
# This cookie-based session store is the Rails default. It is
|
10
10
|
# dramatically faster than the alternatives.
|
11
11
|
#
|
12
|
-
# Sessions typically contain at most a
|
13
|
-
# within the 4096 bytes cookie size limit. A CookieOverflow exception is raised if
|
12
|
+
# Sessions typically contain at most a user ID and flash message; both fit
|
13
|
+
# within the 4096 bytes cookie size limit. A +CookieOverflow+ exception is raised if
|
14
14
|
# you attempt to store more than 4096 bytes of data.
|
15
15
|
#
|
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
|
-
# Your cookies will be encrypted using your
|
19
|
+
# Your cookies will be encrypted using your application's +secret_key_base+. This
|
20
20
|
# goes a step further than signed cookies in that encrypted cookies cannot
|
21
21
|
# be altered or read by users. This is the default starting in Rails 4.
|
22
22
|
#
|
@@ -24,20 +24,20 @@ module ActionDispatch
|
|
24
24
|
#
|
25
25
|
# Rails.application.config.session_store :cookie_store, key: '_your_app_session'
|
26
26
|
#
|
27
|
-
# In the development and test environments your application's
|
27
|
+
# In the development and test environments your application's +secret_key_base+ is
|
28
28
|
# generated by Rails and stored in a temporary file in <tt>tmp/development_secret.txt</tt>.
|
29
29
|
# In all other environments, it is stored encrypted in the
|
30
30
|
# <tt>config/credentials.yml.enc</tt> file.
|
31
31
|
#
|
32
|
-
# If your application was not updated to Rails 5.2 defaults, the secret_key_base
|
32
|
+
# If your application was not updated to Rails 5.2 defaults, the +secret_key_base+
|
33
33
|
# will be found in the old <tt>config/secrets.yml</tt> file.
|
34
34
|
#
|
35
|
-
# Note that changing your secret_key_base will invalidate all existing session.
|
35
|
+
# Note that changing your +secret_key_base+ will invalidate all existing session.
|
36
36
|
# Additionally, you should take care to make sure you are not relying on the
|
37
37
|
# ability to decode signed cookies generated by your app in external
|
38
38
|
# applications or JavaScript before changing it.
|
39
39
|
#
|
40
|
-
# Because CookieStore extends Rack::Session::Abstract::Persisted
|
40
|
+
# Because CookieStore extends +Rack::Session::Abstract::Persisted+, many of the
|
41
41
|
# options described there can be used to customize the session cookie that
|
42
42
|
# is generated. For example:
|
43
43
|
#
|
@@ -609,7 +609,7 @@ module ActionDispatch
|
|
609
609
|
target_as = name_for_action(options[:as], path)
|
610
610
|
options[:via] ||= :all
|
611
611
|
|
612
|
-
match(path,
|
612
|
+
match(path, { to: app, anchor: false, format: false }.merge(options))
|
613
613
|
|
614
614
|
define_generate_prefix(app, target_as) if rails_app
|
615
615
|
self
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require "action_dispatch/testing/request_encoder"
|
4
4
|
|
5
5
|
module ActionDispatch
|
6
|
-
# Integration test methods such as
|
7
|
-
# and
|
6
|
+
# Integration test methods such as Integration::RequestHelpers#get
|
7
|
+
# and Integration::RequestHelpers#post return objects of class
|
8
8
|
# TestResponse, which represent the HTTP response results of the requested
|
9
9
|
# controller actions.
|
10
10
|
#
|
@@ -14,6 +14,24 @@ module ActionDispatch
|
|
14
14
|
new response.status, response.headers, response.body
|
15
15
|
end
|
16
16
|
|
17
|
+
# Returns a parsed body depending on the response MIME type. When a parser
|
18
|
+
# corresponding to the MIME type is not found, it returns the raw body.
|
19
|
+
#
|
20
|
+
# ==== Examples
|
21
|
+
# get "/posts"
|
22
|
+
# response.content_type # => "text/html; charset=utf-8"
|
23
|
+
# response.parsed_body.class # => String
|
24
|
+
# response.parsed_body # => "<!DOCTYPE html>\n<html>\n..."
|
25
|
+
#
|
26
|
+
# get "/posts.json"
|
27
|
+
# response.content_type # => "application/json; charset=utf-8"
|
28
|
+
# response.parsed_body.class # => Array
|
29
|
+
# response.parsed_body # => [{"id"=>42, "title"=>"Title"},...
|
30
|
+
#
|
31
|
+
# get "/posts/42.json"
|
32
|
+
# response.content_type # => "application/json; charset=utf-8"
|
33
|
+
# response.parsed_body.class # => Hash
|
34
|
+
# response.parsed_body # => {"id"=>42, "title"=>"Title"}
|
17
35
|
def parsed_body
|
18
36
|
@parsed_body ||= response_parser.call(body)
|
19
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionpack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.
|
4
|
+
version: 7.0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 7.0.
|
19
|
+
version: 7.0.4.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.0.
|
26
|
+
version: 7.0.4.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,28 +98,28 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - '='
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: 7.0.
|
101
|
+
version: 7.0.4.1
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - '='
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version: 7.0.
|
108
|
+
version: 7.0.4.1
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
110
|
name: activemodel
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
113
|
- - '='
|
114
114
|
- !ruby/object:Gem::Version
|
115
|
-
version: 7.0.
|
115
|
+
version: 7.0.4.1
|
116
116
|
type: :development
|
117
117
|
prerelease: false
|
118
118
|
version_requirements: !ruby/object:Gem::Requirement
|
119
119
|
requirements:
|
120
120
|
- - '='
|
121
121
|
- !ruby/object:Gem::Version
|
122
|
-
version: 7.0.
|
122
|
+
version: 7.0.4.1
|
123
123
|
description: Web apps on Rails. Simple, battle-tested conventions for building and
|
124
124
|
testing MVC web applications. Works with any Rack-compatible server.
|
125
125
|
email: david@loudthinking.com
|
@@ -310,10 +310,10 @@ licenses:
|
|
310
310
|
- MIT
|
311
311
|
metadata:
|
312
312
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
313
|
-
changelog_uri: https://github.com/rails/rails/blob/v7.0.
|
314
|
-
documentation_uri: https://api.rubyonrails.org/v7.0.
|
313
|
+
changelog_uri: https://github.com/rails/rails/blob/v7.0.4.1/actionpack/CHANGELOG.md
|
314
|
+
documentation_uri: https://api.rubyonrails.org/v7.0.4.1/
|
315
315
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
316
|
-
source_code_uri: https://github.com/rails/rails/tree/v7.0.
|
316
|
+
source_code_uri: https://github.com/rails/rails/tree/v7.0.4.1/actionpack
|
317
317
|
rubygems_mfa_required: 'true'
|
318
318
|
post_install_message:
|
319
319
|
rdoc_options: []
|
@@ -331,7 +331,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
331
331
|
version: '0'
|
332
332
|
requirements:
|
333
333
|
- none
|
334
|
-
rubygems_version: 3.
|
334
|
+
rubygems_version: 3.4.3
|
335
335
|
signing_key:
|
336
336
|
specification_version: 4
|
337
337
|
summary: Web-flow and rendering framework putting the VC in MVC (part of Rails).
|