activesupport 6.0.3.7 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +220 -533
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +18 -11
- data/lib/active_support/cache/mem_cache_store.rb +143 -37
- data/lib/active_support/cache/memory_store.rb +56 -28
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +63 -88
- data/lib/active_support/cache/strategy/local_cache.rb +46 -57
- data/lib/active_support/cache.rb +273 -82
- data/lib/active_support/callbacks.rb +226 -118
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +49 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +9 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +9 -7
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +21 -40
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +4 -4
- data/lib/active_support/core_ext/date/conversions.rb +5 -4
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +5 -5
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +139 -15
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/except.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +2 -2
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +40 -36
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +79 -72
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +42 -26
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +39 -5
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +69 -45
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +26 -6
- data/lib/active_support/core_ext/time/conversions.rb +6 -3
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +4 -19
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -23
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +39 -16
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -764
- data/lib/active_support/deprecation/behaviors.rb +19 -3
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +6 -5
- data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +177 -64
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -10
- data/lib/active_support/duration.rb +134 -55
- data/lib/active_support/encrypted_configuration.rb +11 -1
- data/lib/active_support/encrypted_file.rb +20 -3
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +70 -134
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +30 -4
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +51 -25
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +24 -9
- data/lib/active_support/inflector/methods.rb +29 -49
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/isolated_execution_state.rb +56 -0
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +8 -4
- data/lib/active_support/key_generator.rb +19 -2
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber.rb +21 -3
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -21
- data/lib/active_support/message_encryptor.rb +12 -10
- data/lib/active_support/message_verifier.rb +50 -18
- data/lib/active_support/messages/metadata.rb +11 -3
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +13 -52
- data/lib/active_support/multibyte/unicode.rb +1 -87
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +110 -69
- data/lib/active_support/notifications/instrumenter.rb +37 -29
- data/lib/active_support/notifications.rb +47 -26
- data/lib/active_support/number_helper/number_converter.rb +2 -4
- data/lib/active_support/number_helper/number_to_currency_converter.rb +10 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +29 -16
- data/lib/active_support/option_merger.rb +9 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +21 -11
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/rescuable.rb +6 -6
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +2 -2
- data/lib/active_support/subscriber.rb +19 -25
- data/lib/active_support/tagged_logging.rb +31 -6
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +49 -12
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +53 -5
- data/lib/active_support/time_with_zone.rb +120 -55
- data/lib/active_support/values/time_zone.rb +49 -18
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +29 -1
- metadata +46 -45
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -4,19 +4,6 @@ require "active_support/concern"
|
|
4
4
|
require "active_support/core_ext/module/attribute_accessors"
|
5
5
|
require "active_support/logger_thread_safe_level"
|
6
6
|
|
7
|
-
module LoggerSilence
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
|
10
|
-
included do
|
11
|
-
ActiveSupport::Deprecation.warn(
|
12
|
-
"Including LoggerSilence is deprecated and will be removed in Rails 6.1. " \
|
13
|
-
"Please use `ActiveSupport::LoggerSilence` instead"
|
14
|
-
)
|
15
|
-
|
16
|
-
include ActiveSupport::LoggerSilence
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
7
|
module ActiveSupport
|
21
8
|
module LoggerSilence
|
22
9
|
extend ActiveSupport::Concern
|
@@ -27,19 +14,8 @@ module ActiveSupport
|
|
27
14
|
end
|
28
15
|
|
29
16
|
# Silences the logger for the duration of the block.
|
30
|
-
def silence(
|
31
|
-
|
32
|
-
begin
|
33
|
-
old_local_level = local_level
|
34
|
-
self.local_level = temporary_level
|
35
|
-
|
36
|
-
yield self
|
37
|
-
ensure
|
38
|
-
self.local_level = old_local_level
|
39
|
-
end
|
40
|
-
else
|
41
|
-
yield self
|
42
|
-
end
|
17
|
+
def silence(severity = Logger::ERROR)
|
18
|
+
silencer ? log_at(severity) { yield self } : yield(self)
|
43
19
|
end
|
44
20
|
end
|
45
21
|
end
|
@@ -9,10 +9,6 @@ module ActiveSupport
|
|
9
9
|
module LoggerThreadSafeLevel # :nodoc:
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
|
-
included do
|
13
|
-
cattr_accessor :local_levels, default: Concurrent::Map.new(initial_capacity: 2), instance_accessor: false
|
14
|
-
end
|
15
|
-
|
16
12
|
Logger::Severity.constants.each do |severity|
|
17
13
|
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
|
18
14
|
def #{severity.downcase}? # def debug?
|
@@ -21,36 +17,53 @@ module ActiveSupport
|
|
21
17
|
EOT
|
22
18
|
end
|
23
19
|
|
24
|
-
def after_initialize
|
25
|
-
ActiveSupport::Deprecation.warn(
|
26
|
-
"Logger don't need to call #after_initialize directly anymore. It will be deprecated without replacement in " \
|
27
|
-
"Rails 6.1."
|
28
|
-
)
|
29
|
-
end
|
30
|
-
|
31
|
-
def local_log_id
|
32
|
-
Fiber.current.__id__
|
33
|
-
end
|
34
|
-
|
35
20
|
def local_level
|
36
|
-
|
21
|
+
IsolatedExecutionState[:logger_thread_safe_level]
|
37
22
|
end
|
38
23
|
|
39
24
|
def local_level=(level)
|
40
|
-
|
41
|
-
|
25
|
+
case level
|
26
|
+
when Integer
|
27
|
+
when Symbol
|
28
|
+
level = Logger::Severity.const_get(level.to_s.upcase)
|
29
|
+
when nil
|
42
30
|
else
|
43
|
-
|
31
|
+
raise ArgumentError, "Invalid log level: #{level.inspect}"
|
44
32
|
end
|
33
|
+
IsolatedExecutionState[:logger_thread_safe_level] = level
|
45
34
|
end
|
46
35
|
|
47
36
|
def level
|
48
37
|
local_level || super
|
49
38
|
end
|
50
39
|
|
40
|
+
# Change the thread-local level for the duration of the given block.
|
41
|
+
def log_at(level)
|
42
|
+
old_local_level, self.local_level = local_level, level
|
43
|
+
yield
|
44
|
+
ensure
|
45
|
+
self.local_level = old_local_level
|
46
|
+
end
|
47
|
+
|
48
|
+
# Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
|
49
|
+
# FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
|
51
50
|
def add(severity, message = nil, progname = nil, &block) # :nodoc:
|
52
|
-
|
53
|
-
|
51
|
+
severity ||= UNKNOWN
|
52
|
+
progname ||= @progname
|
53
|
+
|
54
|
+
return true if @logdev.nil? || severity < level
|
55
|
+
|
56
|
+
if message.nil?
|
57
|
+
if block_given?
|
58
|
+
message = yield
|
59
|
+
else
|
60
|
+
message = progname
|
61
|
+
progname = @progname
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
@logdev.write \
|
66
|
+
format_message(format_severity(severity), Time.now, progname, message)
|
54
67
|
end
|
55
68
|
end
|
56
69
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "openssl"
|
4
4
|
require "base64"
|
5
|
-
require "active_support/core_ext/array/extract_options"
|
6
5
|
require "active_support/core_ext/module/attribute_accessors"
|
7
6
|
require "active_support/message_verifier"
|
8
7
|
require "active_support/messages/metadata"
|
@@ -23,6 +22,11 @@ module ActiveSupport
|
|
23
22
|
# crypt = ActiveSupport::MessageEncryptor.new(key) # => #<ActiveSupport::MessageEncryptor ...>
|
24
23
|
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
|
25
24
|
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
|
25
|
+
# The +decrypt_and_verify+ method will raise an
|
26
|
+
# <tt>ActiveSupport::MessageEncryptor::InvalidMessage</tt> exception if the data
|
27
|
+
# provided cannot be decrypted or verified.
|
28
|
+
#
|
29
|
+
# crypt.decrypt_and_verify('not encrypted data') # => ActiveSupport::MessageEncryptor::InvalidMessage
|
26
30
|
#
|
27
31
|
# === Confining messages to a specific purpose
|
28
32
|
#
|
@@ -85,7 +89,7 @@ module ActiveSupport
|
|
85
89
|
cattr_accessor :use_authenticated_message_encryption, instance_accessor: false, default: false
|
86
90
|
|
87
91
|
class << self
|
88
|
-
def default_cipher
|
92
|
+
def default_cipher # :nodoc:
|
89
93
|
if use_authenticated_message_encryption
|
90
94
|
"aes-256-gcm"
|
91
95
|
else
|
@@ -94,7 +98,7 @@ module ActiveSupport
|
|
94
98
|
end
|
95
99
|
end
|
96
100
|
|
97
|
-
module NullSerializer
|
101
|
+
module NullSerializer # :nodoc:
|
98
102
|
def self.load(value)
|
99
103
|
value
|
100
104
|
end
|
@@ -104,7 +108,7 @@ module ActiveSupport
|
|
104
108
|
end
|
105
109
|
end
|
106
110
|
|
107
|
-
module NullVerifier
|
111
|
+
module NullVerifier # :nodoc:
|
108
112
|
def self.verify(value)
|
109
113
|
value
|
110
114
|
end
|
@@ -134,15 +138,13 @@ module ActiveSupport
|
|
134
138
|
# * <tt>:digest</tt> - String of digest to use for signing. Default is
|
135
139
|
# +SHA1+. Ignored when using an AEAD cipher like 'aes-256-gcm'.
|
136
140
|
# * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+.
|
137
|
-
def initialize(secret,
|
138
|
-
options = signature_key_or_options.extract_options!
|
139
|
-
sign_secret = signature_key_or_options.first
|
141
|
+
def initialize(secret, sign_secret = nil, cipher: nil, digest: nil, serializer: nil)
|
140
142
|
@secret = secret
|
141
143
|
@sign_secret = sign_secret
|
142
|
-
@cipher =
|
143
|
-
@digest =
|
144
|
+
@cipher = cipher || self.class.default_cipher
|
145
|
+
@digest = digest || "SHA1" unless aead_mode?
|
144
146
|
@verifier = resolve_verifier
|
145
|
-
@serializer =
|
147
|
+
@serializer = serializer || Marshal
|
146
148
|
end
|
147
149
|
|
148
150
|
# Encrypt and sign a message. We need to sign the message in order to avoid
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "openssl"
|
3
4
|
require "base64"
|
4
5
|
require "active_support/core_ext/object/blank"
|
5
6
|
require "active_support/security_utils"
|
@@ -68,8 +69,8 @@ module ActiveSupport
|
|
68
69
|
# return the original value. But messages can be set to expire at a given
|
69
70
|
# time with +:expires_in+ or +:expires_at+.
|
70
71
|
#
|
71
|
-
# @verifier.generate(parcel, expires_in: 1.month)
|
72
|
-
# @verifier.generate(doowad, expires_at: Time.now.end_of_year)
|
72
|
+
# @verifier.generate("parcel", expires_in: 1.month)
|
73
|
+
# @verifier.generate("doowad", expires_at: Time.now.end_of_year)
|
73
74
|
#
|
74
75
|
# Then the messages can be verified and returned up to the expire time.
|
75
76
|
# Thereafter, the +verified+ method returns +nil+ while +verify+ raises
|
@@ -78,8 +79,8 @@ module ActiveSupport
|
|
78
79
|
# === Rotating keys
|
79
80
|
#
|
80
81
|
# MessageVerifier also supports rotating out old configurations by falling
|
81
|
-
# back to a stack of verifiers. Call +rotate+ to build and add a verifier
|
82
|
-
#
|
82
|
+
# back to a stack of verifiers. Call +rotate+ to build and add a verifier so
|
83
|
+
# either +verified+ or +verify+ will also try verifying with the fallback.
|
83
84
|
#
|
84
85
|
# By default any rotated verifiers use the values of the primary
|
85
86
|
# verifier unless specified otherwise.
|
@@ -103,11 +104,14 @@ module ActiveSupport
|
|
103
104
|
|
104
105
|
class InvalidSignature < StandardError; end
|
105
106
|
|
106
|
-
|
107
|
+
SEPARATOR = "--" # :nodoc:
|
108
|
+
SEPARATOR_LENGTH = SEPARATOR.length # :nodoc:
|
109
|
+
|
110
|
+
def initialize(secret, digest: nil, serializer: nil)
|
107
111
|
raise ArgumentError, "Secret should not be nil." unless secret
|
108
112
|
@secret = secret
|
109
|
-
@digest =
|
110
|
-
@serializer =
|
113
|
+
@digest = digest&.to_s || "SHA1"
|
114
|
+
@serializer = serializer || Marshal
|
111
115
|
end
|
112
116
|
|
113
117
|
# Checks if a signed message could have been generated by signing an object
|
@@ -120,10 +124,8 @@ module ActiveSupport
|
|
120
124
|
# tampered_message = signed_message.chop # editing the message invalidates the signature
|
121
125
|
# verifier.valid_message?(tampered_message) # => false
|
122
126
|
def valid_message?(signed_message)
|
123
|
-
|
124
|
-
|
125
|
-
data, digest = signed_message.split("--")
|
126
|
-
data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
|
127
|
+
data, digest = get_data_and_digest_from(signed_message)
|
128
|
+
digest_matches_data?(digest, data)
|
127
129
|
end
|
128
130
|
|
129
131
|
# Decodes the signed message using the +MessageVerifier+'s secret.
|
@@ -148,9 +150,9 @@ module ActiveSupport
|
|
148
150
|
# incompatible_message = "test--dad7b06c94abba8d46a15fafaef56c327665d5ff"
|
149
151
|
# verifier.verified(incompatible_message) # => TypeError: incompatible marshal file format
|
150
152
|
def verified(signed_message, purpose: nil, **)
|
151
|
-
|
153
|
+
data, digest = get_data_and_digest_from(signed_message)
|
154
|
+
if digest_matches_data?(digest, data)
|
152
155
|
begin
|
153
|
-
data = signed_message.split("--")[0]
|
154
156
|
message = Messages::Metadata.verify(decode(data), purpose)
|
155
157
|
@serializer.load(message) if message
|
156
158
|
rescue ArgumentError => argument_error
|
@@ -178,14 +180,14 @@ module ActiveSupport
|
|
178
180
|
|
179
181
|
# Generates a signed message for the provided value.
|
180
182
|
#
|
181
|
-
# The message is signed with the +MessageVerifier+'s secret.
|
182
|
-
#
|
183
|
+
# The message is signed with the +MessageVerifier+'s secret.
|
184
|
+
# Returns Base64-encoded message joined with the generated signature.
|
183
185
|
#
|
184
186
|
# verifier = ActiveSupport::MessageVerifier.new 's3Krit'
|
185
187
|
# verifier.generate 'a private message' # => "BAhJIhRwcml2YXRlLW1lc3NhZ2UGOgZFVA==--e2d724331ebdee96a10fb99b089508d1c72bd772"
|
186
188
|
def generate(value, expires_at: nil, expires_in: nil, purpose: nil)
|
187
189
|
data = encode(Messages::Metadata.wrap(@serializer.dump(value), expires_at: expires_at, expires_in: expires_in, purpose: purpose))
|
188
|
-
"#{data}
|
190
|
+
"#{data}#{SEPARATOR}#{generate_digest(data)}"
|
189
191
|
end
|
190
192
|
|
191
193
|
private
|
@@ -198,8 +200,38 @@ module ActiveSupport
|
|
198
200
|
end
|
199
201
|
|
200
202
|
def generate_digest(data)
|
201
|
-
|
202
|
-
|
203
|
+
OpenSSL::HMAC.hexdigest(@digest, @secret, data)
|
204
|
+
end
|
205
|
+
|
206
|
+
def digest_length_in_hex
|
207
|
+
# In hexadecimal (AKA base16) it takes 4 bits to represent a character,
|
208
|
+
# hence we multiply the digest's length (in bytes) by 8 to get it in
|
209
|
+
# bits and divide by 4 to get its number of characters it hex. Well, 8
|
210
|
+
# divided by 4 is 2.
|
211
|
+
@digest_length_in_hex ||= OpenSSL::Digest.new(@digest).digest_length * 2
|
212
|
+
end
|
213
|
+
|
214
|
+
def separator_index_for(signed_message)
|
215
|
+
index = signed_message.length - digest_length_in_hex - SEPARATOR_LENGTH
|
216
|
+
return if index.negative? || signed_message[index, SEPARATOR_LENGTH] != SEPARATOR
|
217
|
+
|
218
|
+
index
|
219
|
+
end
|
220
|
+
|
221
|
+
def get_data_and_digest_from(signed_message)
|
222
|
+
return if signed_message.nil? || !signed_message.valid_encoding? || signed_message.empty?
|
223
|
+
|
224
|
+
separator_index = separator_index_for(signed_message)
|
225
|
+
return if separator_index.nil?
|
226
|
+
|
227
|
+
data = signed_message[0...separator_index]
|
228
|
+
digest = signed_message[separator_index + SEPARATOR_LENGTH..-1]
|
229
|
+
|
230
|
+
[data, digest]
|
231
|
+
end
|
232
|
+
|
233
|
+
def digest_matches_data?(digest, data)
|
234
|
+
data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
|
203
235
|
end
|
204
236
|
end
|
205
237
|
end
|
@@ -3,11 +3,11 @@
|
|
3
3
|
require "time"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
module Messages
|
7
|
-
class Metadata
|
6
|
+
module Messages # :nodoc:
|
7
|
+
class Metadata # :nodoc:
|
8
8
|
def initialize(message, expires_at = nil, purpose = nil)
|
9
9
|
@message, @purpose = message, purpose
|
10
|
-
@expires_at = expires_at.is_a?(String) ?
|
10
|
+
@expires_at = expires_at.is_a?(String) ? parse_expires_at(expires_at) : expires_at
|
11
11
|
end
|
12
12
|
|
13
13
|
def as_json(options = {})
|
@@ -67,6 +67,14 @@ module ActiveSupport
|
|
67
67
|
def fresh?
|
68
68
|
@expires_at.nil? || Time.now.utc < @expires_at
|
69
69
|
end
|
70
|
+
|
71
|
+
def parse_expires_at(expires_at)
|
72
|
+
if ActiveSupport.use_standard_json_time_format
|
73
|
+
Time.iso8601(expires_at)
|
74
|
+
else
|
75
|
+
Time.parse(expires_at)
|
76
|
+
end
|
77
|
+
end
|
70
78
|
end
|
71
79
|
end
|
72
80
|
end
|
@@ -3,11 +3,12 @@
|
|
3
3
|
module ActiveSupport
|
4
4
|
module Messages
|
5
5
|
module Rotator # :nodoc:
|
6
|
-
def initialize(
|
7
|
-
super
|
6
|
+
def initialize(*secrets, on_rotation: nil, **options)
|
7
|
+
super(*secrets, **options)
|
8
8
|
|
9
9
|
@options = options
|
10
10
|
@rotations = []
|
11
|
+
@on_rotation = on_rotation
|
11
12
|
end
|
12
13
|
|
13
14
|
def rotate(*secrets, **options)
|
@@ -17,7 +18,7 @@ module ActiveSupport
|
|
17
18
|
module Encryptor
|
18
19
|
include Rotator
|
19
20
|
|
20
|
-
def decrypt_and_verify(*args, on_rotation:
|
21
|
+
def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
|
21
22
|
super
|
22
23
|
rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
|
23
24
|
run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
|
@@ -32,7 +33,7 @@ module ActiveSupport
|
|
32
33
|
module Verifier
|
33
34
|
include Rotator
|
34
35
|
|
35
|
-
def verified(*args, on_rotation:
|
36
|
+
def verified(*args, on_rotation: @on_rotation, **options)
|
36
37
|
super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
|
37
38
|
end
|
38
39
|
|
@@ -46,7 +47,7 @@ module ActiveSupport
|
|
46
47
|
def run_rotations(on_rotation)
|
47
48
|
@rotations.find do |rotation|
|
48
49
|
if message = yield(rotation) rescue next
|
49
|
-
on_rotation
|
50
|
+
on_rotation&.call
|
50
51
|
return message
|
51
52
|
end
|
52
53
|
end
|
@@ -5,8 +5,8 @@ require "active_support/core_ext/string/access"
|
|
5
5
|
require "active_support/core_ext/string/behavior"
|
6
6
|
require "active_support/core_ext/module/delegation"
|
7
7
|
|
8
|
-
module ActiveSupport
|
9
|
-
module Multibyte
|
8
|
+
module ActiveSupport # :nodoc:
|
9
|
+
module Multibyte # :nodoc:
|
10
10
|
# Chars enables you to work transparently with UTF-8 encoding in the Ruby
|
11
11
|
# String class without having extensive knowledge about the encoding. A
|
12
12
|
# Chars object accepts a string upon initialization and proxies String
|
@@ -48,7 +48,7 @@ module ActiveSupport #:nodoc:
|
|
48
48
|
alias to_s wrapped_string
|
49
49
|
alias to_str wrapped_string
|
50
50
|
|
51
|
-
delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
|
51
|
+
delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
|
52
52
|
|
53
53
|
# Creates a new Chars instance by wrapping _string_.
|
54
54
|
def initialize(string)
|
@@ -59,7 +59,7 @@ module ActiveSupport #:nodoc:
|
|
59
59
|
# Forward all undefined methods to the wrapped string.
|
60
60
|
def method_missing(method, *args, &block)
|
61
61
|
result = @wrapped_string.__send__(method, *args, &block)
|
62
|
-
if
|
62
|
+
if method.end_with?("!")
|
63
63
|
self if result
|
64
64
|
else
|
65
65
|
result.kind_of?(String) ? chars(result) : result
|
@@ -73,17 +73,6 @@ module ActiveSupport #:nodoc:
|
|
73
73
|
@wrapped_string.respond_to?(method, include_private)
|
74
74
|
end
|
75
75
|
|
76
|
-
# Returns +true+ when the proxy class can handle the string. Returns
|
77
|
-
# +false+ otherwise.
|
78
|
-
def self.consumes?(string)
|
79
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
80
|
-
ActiveSupport::Multibyte::Chars.consumes? is deprecated and will be
|
81
|
-
removed from Rails 6.1. Use string.is_utf8? instead.
|
82
|
-
MSG
|
83
|
-
|
84
|
-
string.encoding == Encoding::UTF_8
|
85
|
-
end
|
86
|
-
|
87
76
|
# Works just like <tt>String#split</tt>, with the exception that the items
|
88
77
|
# in the resulting list are Chars instances instead of String. This makes
|
89
78
|
# chaining methods easier.
|
@@ -113,7 +102,7 @@ module ActiveSupport #:nodoc:
|
|
113
102
|
#
|
114
103
|
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
|
115
104
|
def reverse
|
116
|
-
chars(@wrapped_string.
|
105
|
+
chars(@wrapped_string.grapheme_clusters.reverse.join)
|
117
106
|
end
|
118
107
|
|
119
108
|
# Limits the byte size of the string to a number of bytes without breaking
|
@@ -134,46 +123,18 @@ module ActiveSupport #:nodoc:
|
|
134
123
|
end
|
135
124
|
alias_method :titlecase, :titleize
|
136
125
|
|
137
|
-
# Returns the KC normalization of the string by default. NFKC is
|
138
|
-
# considered the best normalization form for passing strings to databases
|
139
|
-
# and validations.
|
140
|
-
#
|
141
|
-
# * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
|
142
|
-
# <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
|
143
|
-
# ActiveSupport::Multibyte::Unicode.default_normalization_form
|
144
|
-
def normalize(form = nil)
|
145
|
-
form ||= Unicode.default_normalization_form
|
146
|
-
|
147
|
-
# See https://www.unicode.org/reports/tr15, Table 1
|
148
|
-
if alias_form = Unicode::NORMALIZATION_FORM_ALIASES[form]
|
149
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
150
|
-
ActiveSupport::Multibyte::Chars#normalize is deprecated and will be
|
151
|
-
removed from Rails 6.1. Use #unicode_normalize(:#{alias_form}) instead.
|
152
|
-
MSG
|
153
|
-
|
154
|
-
send(:unicode_normalize, alias_form)
|
155
|
-
else
|
156
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
157
|
-
ActiveSupport::Multibyte::Chars#normalize is deprecated and will be
|
158
|
-
removed from Rails 6.1. Use #unicode_normalize instead.
|
159
|
-
MSG
|
160
|
-
|
161
|
-
raise ArgumentError, "#{form} is not a valid normalization variant", caller
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
126
|
# Performs canonical decomposition on all the characters.
|
166
127
|
#
|
167
|
-
# 'é'.length # =>
|
168
|
-
# 'é'.mb_chars.decompose.to_s.length # =>
|
128
|
+
# 'é'.length # => 1
|
129
|
+
# 'é'.mb_chars.decompose.to_s.length # => 2
|
169
130
|
def decompose
|
170
131
|
chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*"))
|
171
132
|
end
|
172
133
|
|
173
134
|
# Performs composition on all the characters.
|
174
135
|
#
|
175
|
-
# 'é'.length # =>
|
176
|
-
# 'é'.mb_chars.compose.to_s.length # =>
|
136
|
+
# 'é'.length # => 1
|
137
|
+
# 'é'.mb_chars.compose.to_s.length # => 1
|
177
138
|
def compose
|
178
139
|
chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*"))
|
179
140
|
end
|
@@ -181,9 +142,9 @@ module ActiveSupport #:nodoc:
|
|
181
142
|
# Returns the number of grapheme clusters in the string.
|
182
143
|
#
|
183
144
|
# 'क्षि'.mb_chars.length # => 4
|
184
|
-
# 'क्षि'.mb_chars.grapheme_length # =>
|
145
|
+
# 'क्षि'.mb_chars.grapheme_length # => 2
|
185
146
|
def grapheme_length
|
186
|
-
@wrapped_string.
|
147
|
+
@wrapped_string.grapheme_clusters.length
|
187
148
|
end
|
188
149
|
|
189
150
|
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
@@ -195,13 +156,13 @@ module ActiveSupport #:nodoc:
|
|
195
156
|
chars(Unicode.tidy_bytes(@wrapped_string, force))
|
196
157
|
end
|
197
158
|
|
198
|
-
def as_json(options = nil)
|
159
|
+
def as_json(options = nil) # :nodoc:
|
199
160
|
to_s.as_json(options)
|
200
161
|
end
|
201
162
|
|
202
163
|
%w(reverse tidy_bytes).each do |method|
|
203
164
|
define_method("#{method}!") do |*args|
|
204
|
-
@wrapped_string =
|
165
|
+
@wrapped_string = public_send(method, *args).to_s
|
205
166
|
self
|
206
167
|
end
|
207
168
|
end
|
@@ -5,55 +5,9 @@ module ActiveSupport
|
|
5
5
|
module Unicode
|
6
6
|
extend self
|
7
7
|
|
8
|
-
# A list of all available normalization forms.
|
9
|
-
# See https://www.unicode.org/reports/tr15/tr15-29.html for more
|
10
|
-
# information about normalization.
|
11
|
-
NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
|
12
|
-
|
13
|
-
NORMALIZATION_FORM_ALIASES = { # :nodoc:
|
14
|
-
c: :nfc,
|
15
|
-
d: :nfd,
|
16
|
-
kc: :nfkc,
|
17
|
-
kd: :nfkd
|
18
|
-
}
|
19
|
-
|
20
8
|
# The Unicode version that is supported by the implementation
|
21
9
|
UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
|
22
10
|
|
23
|
-
# The default normalization used for operations that require
|
24
|
-
# normalization. It can be set to any of the normalizations
|
25
|
-
# in NORMALIZATION_FORMS.
|
26
|
-
#
|
27
|
-
# ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
|
28
|
-
attr_accessor :default_normalization_form
|
29
|
-
@default_normalization_form = :kc
|
30
|
-
|
31
|
-
# Unpack the string at grapheme boundaries. Returns a list of character
|
32
|
-
# lists.
|
33
|
-
#
|
34
|
-
# Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
|
35
|
-
# Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
|
36
|
-
def unpack_graphemes(string)
|
37
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
38
|
-
ActiveSupport::Multibyte::Unicode#unpack_graphemes is deprecated and will be
|
39
|
-
removed from Rails 6.1. Use string.scan(/\X/).map(&:codepoints) instead.
|
40
|
-
MSG
|
41
|
-
|
42
|
-
string.scan(/\X/).map(&:codepoints)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Reverse operation of unpack_graphemes.
|
46
|
-
#
|
47
|
-
# Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
|
48
|
-
def pack_graphemes(unpacked)
|
49
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
50
|
-
ActiveSupport::Multibyte::Unicode#pack_graphemes is deprecated and will be
|
51
|
-
removed from Rails 6.1. Use array.flatten.pack("U*") instead.
|
52
|
-
MSG
|
53
|
-
|
54
|
-
unpacked.flatten.pack("U*")
|
55
|
-
end
|
56
|
-
|
57
11
|
# Decompose composed characters to the decomposed form.
|
58
12
|
def decompose(type, codepoints)
|
59
13
|
if type == :compatibility
|
@@ -76,7 +30,7 @@ module ActiveSupport
|
|
76
30
|
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
77
31
|
# encoding is entirely CP1252 or ISO-8859-1.
|
78
32
|
def tidy_bytes(string, force = false)
|
79
|
-
return string if string.empty?
|
33
|
+
return string if string.empty? || string.ascii_only?
|
80
34
|
return recode_windows1252_chars(string) if force
|
81
35
|
string.scrub { |bad| recode_windows1252_chars(bad) }
|
82
36
|
end
|
@@ -107,46 +61,6 @@ module ActiveSupport
|
|
107
61
|
end
|
108
62
|
end
|
109
63
|
|
110
|
-
# Returns the KC normalization of the string by default. NFKC is
|
111
|
-
# considered the best normalization form for passing strings to databases
|
112
|
-
# and validations.
|
113
|
-
#
|
114
|
-
# * <tt>string</tt> - The string to perform normalization on.
|
115
|
-
# * <tt>form</tt> - The form you want to normalize in. Should be one of
|
116
|
-
# the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
|
117
|
-
# Default is ActiveSupport::Multibyte::Unicode.default_normalization_form.
|
118
|
-
def normalize(string, form = nil)
|
119
|
-
form ||= @default_normalization_form
|
120
|
-
|
121
|
-
# See https://www.unicode.org/reports/tr15, Table 1
|
122
|
-
if alias_form = NORMALIZATION_FORM_ALIASES[form]
|
123
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
124
|
-
ActiveSupport::Multibyte::Unicode#normalize is deprecated and will be
|
125
|
-
removed from Rails 6.1. Use String#unicode_normalize(:#{alias_form}) instead.
|
126
|
-
MSG
|
127
|
-
|
128
|
-
string.unicode_normalize(alias_form)
|
129
|
-
else
|
130
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
131
|
-
ActiveSupport::Multibyte::Unicode#normalize is deprecated and will be
|
132
|
-
removed from Rails 6.1. Use String#unicode_normalize instead.
|
133
|
-
MSG
|
134
|
-
|
135
|
-
raise ArgumentError, "#{form} is not a valid normalization variant", caller
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
%w(downcase upcase swapcase).each do |method|
|
140
|
-
define_method(method) do |string|
|
141
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
142
|
-
ActiveSupport::Multibyte::Unicode##{method} is deprecated and
|
143
|
-
will be removed from Rails 6.1. Use String methods directly.
|
144
|
-
MSG
|
145
|
-
|
146
|
-
string.send(method)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
64
|
private
|
151
65
|
def recode_windows1252_chars(string)
|
152
66
|
string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
|