activesupport 5.2.7.1 → 6.1.4.6
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 +399 -434
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +29 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +34 -34
- data/lib/active_support/cache/mem_cache_store.rb +39 -24
- data/lib/active_support/cache/memory_store.rb +59 -33
- data/lib/active_support/cache/null_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +72 -45
- data/lib/active_support/cache/strategy/local_cache.rb +41 -26
- data/lib/active_support/cache.rb +148 -78
- data/lib/active_support/callbacks.rb +81 -64
- data/lib/active_support/concern.rb +70 -3
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configurable.rb +10 -14
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/array/conversions.rb +5 -5
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array.rb +1 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +32 -47
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/calculations.rb +6 -5
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
- data/lib/active_support/core_ext/enumerable.rb +171 -75
- data/lib/active_support/core_ext/hash/conversions.rb +3 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +2 -2
- data/lib/active_support/core_ext/hash/keys.rb +1 -30
- data/lib/active_support/core_ext/hash/slice.rb +6 -27
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +76 -33
- data/lib/active_support/core_ext/module/introspection.rb +16 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +1 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +7 -114
- data/lib/active_support/core_ext/object/json.rb +14 -2
- data/lib/active_support/core_ext/object/try.rb +17 -7
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range/compare_range.rb +34 -13
- data/lib/active_support/core_ext/range/conversions.rb +31 -29
- data/lib/active_support/core_ext/range/each.rb +0 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -5
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +5 -16
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +45 -6
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +6 -5
- data/lib/active_support/core_ext/string/output_safety.rb +70 -41
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +51 -3
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +6 -1
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +16 -2
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +109 -34
- data/lib/active_support/deprecation/behaviors.rb +16 -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 +18 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +59 -9
- data/lib/active_support/duration/iso8601_parser.rb +2 -4
- data/lib/active_support/duration/iso8601_serializer.rb +18 -14
- data/lib/active_support/duration.rb +78 -30
- data/lib/active_support/encrypted_configuration.rb +0 -4
- data/lib/active_support/encrypted_file.rb +22 -4
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +82 -117
- data/lib/active_support/execution_wrapper.rb +2 -1
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +64 -0
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +70 -42
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +15 -8
- data/lib/active_support/inflector/inflections.rb +2 -7
- data/lib/active_support/inflector/methods.rb +49 -58
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/json/decoding.rb +25 -26
- data/lib/active_support/json/encoding.rb +11 -3
- data/lib/active_support/key_generator.rb +1 -33
- data/lib/active_support/lazy_load_hooks.rb +5 -2
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +39 -9
- data/lib/active_support/logger.rb +2 -17
- data/lib/active_support/logger_silence.rb +11 -19
- data/lib/active_support/logger_thread_safe_level.rb +50 -6
- data/lib/active_support/message_encryptor.rb +8 -13
- data/lib/active_support/message_verifier.rb +10 -10
- data/lib/active_support/messages/metadata.rb +11 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +10 -9
- data/lib/active_support/multibyte/chars.rb +10 -68
- data/lib/active_support/multibyte/unicode.rb +15 -327
- data/lib/active_support/notifications/fanout.rb +116 -16
- data/lib/active_support/notifications/instrumenter.rb +71 -9
- data/lib/active_support/notifications.rb +72 -8
- data/lib/active_support/number_helper/number_converter.rb +5 -6
- data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/number_helper.rb +38 -12
- data/lib/active_support/option_merger.rb +22 -3
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +13 -3
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -10
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/reloader.rb +4 -5
- data/lib/active_support/rescuable.rb +4 -4
- 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 +4 -3
- data/lib/active_support/subscriber.rb +72 -28
- data/lib/active_support/tagged_logging.rb +42 -8
- data/lib/active_support/test_case.rb +91 -0
- data/lib/active_support/testing/assertions.rb +30 -9
- data/lib/active_support/testing/deprecation.rb +0 -1
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +28 -1
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/stream.rb +1 -2
- data/lib/active_support/testing/time_helpers.rb +47 -12
- data/lib/active_support/time_with_zone.rb +81 -47
- data/lib/active_support/values/time_zone.rb +32 -17
- data/lib/active_support/xml_mini/jdom.rb +2 -3
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
- data/lib/active_support/xml_mini/rexml.rb +10 -3
- data/lib/active_support/xml_mini.rb +2 -10
- data/lib/active_support.rb +14 -1
- metadata +55 -29
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
- data/lib/active_support/core_ext/hash/compact.rb +0 -29
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/core_ext/module/reachable.rb +0 -11
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
- data/lib/active_support/core_ext/range/include_range.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -6,7 +6,6 @@ require "logger"
|
|
6
6
|
|
7
7
|
module ActiveSupport
|
8
8
|
class Logger < ::Logger
|
9
|
-
include ActiveSupport::LoggerThreadSafeLevel
|
10
9
|
include LoggerSilence
|
11
10
|
|
12
11
|
# Returns true if the logger destination matches one of the sources
|
@@ -15,7 +14,7 @@ module ActiveSupport
|
|
15
14
|
# ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
|
16
15
|
# # => true
|
17
16
|
def self.logger_outputs_to?(logger, *sources)
|
18
|
-
logdev = logger.instance_variable_get(
|
17
|
+
logdev = logger.instance_variable_get(:@logdev)
|
19
18
|
logger_source = logdev.dev if logdev.respond_to?(:dev)
|
20
19
|
sources.any? { |source| source == logger_source }
|
21
20
|
end
|
@@ -78,23 +77,9 @@ module ActiveSupport
|
|
78
77
|
end
|
79
78
|
end
|
80
79
|
|
81
|
-
def initialize(*args)
|
80
|
+
def initialize(*args, **kwargs)
|
82
81
|
super
|
83
82
|
@formatter = SimpleFormatter.new
|
84
|
-
after_initialize if respond_to? :after_initialize
|
85
|
-
end
|
86
|
-
|
87
|
-
def add(severity, message = nil, progname = nil, &block)
|
88
|
-
return true if @logdev.nil? || (severity || UNKNOWN) < level
|
89
|
-
super
|
90
|
-
end
|
91
|
-
|
92
|
-
Logger::Severity.constants.each do |severity|
|
93
|
-
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
|
94
|
-
def #{severity.downcase}? # def debug?
|
95
|
-
Logger::#{severity} >= level # DEBUG >= level
|
96
|
-
end # end
|
97
|
-
EOT
|
98
83
|
end
|
99
84
|
|
100
85
|
# Simple formatter which only displays the message.
|
@@ -2,28 +2,20 @@
|
|
2
2
|
|
3
3
|
require "active_support/concern"
|
4
4
|
require "active_support/core_ext/module/attribute_accessors"
|
5
|
-
require "
|
5
|
+
require "active_support/logger_thread_safe_level"
|
6
6
|
|
7
|
-
module
|
8
|
-
|
7
|
+
module ActiveSupport
|
8
|
+
module LoggerSilence
|
9
|
+
extend ActiveSupport::Concern
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# Silences the logger for the duration of the block.
|
15
|
-
def silence(temporary_level = Logger::ERROR)
|
16
|
-
if silencer
|
17
|
-
begin
|
18
|
-
old_local_level = local_level
|
19
|
-
self.local_level = temporary_level
|
11
|
+
included do
|
12
|
+
cattr_accessor :silencer, default: true
|
13
|
+
include ActiveSupport::LoggerThreadSafeLevel
|
14
|
+
end
|
20
15
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
else
|
26
|
-
yield self
|
16
|
+
# Silences the logger for the duration of the block.
|
17
|
+
def silence(severity = Logger::ERROR)
|
18
|
+
silencer ? log_at(severity) { yield self } : yield(self)
|
27
19
|
end
|
28
20
|
end
|
29
21
|
end
|
@@ -1,14 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/concern"
|
4
|
+
require "active_support/core_ext/module/attribute_accessors"
|
5
|
+
require "concurrent"
|
4
6
|
require "fiber"
|
5
7
|
|
6
8
|
module ActiveSupport
|
7
9
|
module LoggerThreadSafeLevel # :nodoc:
|
8
10
|
extend ActiveSupport::Concern
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
included do
|
13
|
+
cattr_accessor :local_levels, default: Concurrent::Map.new(initial_capacity: 2), instance_accessor: false
|
14
|
+
end
|
15
|
+
|
16
|
+
Logger::Severity.constants.each do |severity|
|
17
|
+
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
|
18
|
+
def #{severity.downcase}? # def debug?
|
19
|
+
Logger::#{severity} >= level # DEBUG >= level
|
20
|
+
end # end
|
21
|
+
EOT
|
12
22
|
end
|
13
23
|
|
14
24
|
def local_log_id
|
@@ -16,19 +26,53 @@ module ActiveSupport
|
|
16
26
|
end
|
17
27
|
|
18
28
|
def local_level
|
19
|
-
|
29
|
+
self.class.local_levels[local_log_id]
|
20
30
|
end
|
21
31
|
|
22
32
|
def local_level=(level)
|
23
|
-
|
24
|
-
|
33
|
+
case level
|
34
|
+
when Integer
|
35
|
+
self.class.local_levels[local_log_id] = level
|
36
|
+
when Symbol
|
37
|
+
self.class.local_levels[local_log_id] = Logger::Severity.const_get(level.to_s.upcase)
|
38
|
+
when nil
|
39
|
+
self.class.local_levels.delete(local_log_id)
|
25
40
|
else
|
26
|
-
|
41
|
+
raise ArgumentError, "Invalid log level: #{level.inspect}"
|
27
42
|
end
|
28
43
|
end
|
29
44
|
|
30
45
|
def level
|
31
46
|
local_level || super
|
32
47
|
end
|
48
|
+
|
49
|
+
# Change the thread-local level for the duration of the given block.
|
50
|
+
def log_at(level)
|
51
|
+
old_local_level, self.local_level = local_level, level
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
self.local_level = old_local_level
|
55
|
+
end
|
56
|
+
|
57
|
+
# Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
|
58
|
+
# FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
|
59
|
+
def add(severity, message = nil, progname = nil, &block) #:nodoc:
|
60
|
+
severity ||= UNKNOWN
|
61
|
+
progname ||= @progname
|
62
|
+
|
63
|
+
return true if @logdev.nil? || severity < level
|
64
|
+
|
65
|
+
if message.nil?
|
66
|
+
if block_given?
|
67
|
+
message = yield
|
68
|
+
else
|
69
|
+
message = progname
|
70
|
+
progname = @progname
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
@logdev.write \
|
75
|
+
format_message(format_severity(severity), Time.now, progname, message)
|
76
|
+
end
|
33
77
|
end
|
34
78
|
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"
|
@@ -53,7 +52,7 @@ module ActiveSupport
|
|
53
52
|
# crypt.encrypt_and_sign(parcel, expires_in: 1.month)
|
54
53
|
# crypt.encrypt_and_sign(doowad, expires_at: Time.now.end_of_year)
|
55
54
|
#
|
56
|
-
# Then the messages can be verified and returned
|
55
|
+
# Then the messages can be verified and returned up to the expire time.
|
57
56
|
# Thereafter, verifying returns +nil+.
|
58
57
|
#
|
59
58
|
# === Rotating keys
|
@@ -134,15 +133,13 @@ module ActiveSupport
|
|
134
133
|
# * <tt>:digest</tt> - String of digest to use for signing. Default is
|
135
134
|
# +SHA1+. Ignored when using an AEAD cipher like 'aes-256-gcm'.
|
136
135
|
# * <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
|
136
|
+
def initialize(secret, sign_secret = nil, cipher: nil, digest: nil, serializer: nil)
|
140
137
|
@secret = secret
|
141
138
|
@sign_secret = sign_secret
|
142
|
-
@cipher =
|
143
|
-
@digest =
|
139
|
+
@cipher = cipher || self.class.default_cipher
|
140
|
+
@digest = digest || "SHA1" unless aead_mode?
|
144
141
|
@verifier = resolve_verifier
|
145
|
-
@serializer =
|
142
|
+
@serializer = serializer || Marshal
|
146
143
|
end
|
147
144
|
|
148
145
|
# Encrypt and sign a message. We need to sign the message in order to avoid
|
@@ -172,7 +169,7 @@ module ActiveSupport
|
|
172
169
|
iv = cipher.random_iv
|
173
170
|
cipher.auth_data = "" if aead_mode?
|
174
171
|
|
175
|
-
encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), metadata_options))
|
172
|
+
encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), **metadata_options))
|
176
173
|
encrypted_data << cipher.final
|
177
174
|
|
178
175
|
blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
|
@@ -182,7 +179,7 @@ module ActiveSupport
|
|
182
179
|
|
183
180
|
def _decrypt(encrypted_message, purpose)
|
184
181
|
cipher = new_cipher
|
185
|
-
encrypted_data, iv, auth_tag = encrypted_message.split("--"
|
182
|
+
encrypted_data, iv, auth_tag = encrypted_message.split("--").map { |v| ::Base64.strict_decode64(v) }
|
186
183
|
|
187
184
|
# Currently the OpenSSL bindings do not raise an error if auth_tag is
|
188
185
|
# truncated, which would allow an attacker to easily forge it. See
|
@@ -210,9 +207,7 @@ module ActiveSupport
|
|
210
207
|
OpenSSL::Cipher.new(@cipher)
|
211
208
|
end
|
212
209
|
|
213
|
-
|
214
|
-
@verifier
|
215
|
-
end
|
210
|
+
attr_reader :verifier
|
216
211
|
|
217
212
|
def aead_mode?
|
218
213
|
@aead_mode ||= new_cipher.authenticated?
|
@@ -71,7 +71,7 @@ module ActiveSupport
|
|
71
71
|
# @verifier.generate(parcel, expires_in: 1.month)
|
72
72
|
# @verifier.generate(doowad, expires_at: Time.now.end_of_year)
|
73
73
|
#
|
74
|
-
# Then the messages can be verified and returned
|
74
|
+
# Then the messages can be verified and returned up to the expire time.
|
75
75
|
# Thereafter, the +verified+ method returns +nil+ while +verify+ raises
|
76
76
|
# <tt>ActiveSupport::MessageVerifier::InvalidSignature</tt>.
|
77
77
|
#
|
@@ -103,11 +103,11 @@ module ActiveSupport
|
|
103
103
|
|
104
104
|
class InvalidSignature < StandardError; end
|
105
105
|
|
106
|
-
def initialize(secret,
|
106
|
+
def initialize(secret, digest: nil, serializer: nil)
|
107
107
|
raise ArgumentError, "Secret should not be nil." unless secret
|
108
108
|
@secret = secret
|
109
|
-
@digest =
|
110
|
-
@serializer =
|
109
|
+
@digest = digest || "SHA1"
|
110
|
+
@serializer = serializer || Marshal
|
111
111
|
end
|
112
112
|
|
113
113
|
# Checks if a signed message could have been generated by signing an object
|
@@ -122,7 +122,7 @@ module ActiveSupport
|
|
122
122
|
def valid_message?(signed_message)
|
123
123
|
return if signed_message.nil? || !signed_message.valid_encoding? || signed_message.blank?
|
124
124
|
|
125
|
-
data, digest = signed_message.split("--"
|
125
|
+
data, digest = signed_message.split("--")
|
126
126
|
data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
|
127
127
|
end
|
128
128
|
|
@@ -150,7 +150,7 @@ module ActiveSupport
|
|
150
150
|
def verified(signed_message, purpose: nil, **)
|
151
151
|
if valid_message?(signed_message)
|
152
152
|
begin
|
153
|
-
data = signed_message.split("--"
|
153
|
+
data = signed_message.split("--")[0]
|
154
154
|
message = Messages::Metadata.verify(decode(data), purpose)
|
155
155
|
@serializer.load(message) if message
|
156
156
|
rescue ArgumentError => argument_error
|
@@ -172,14 +172,14 @@ module ActiveSupport
|
|
172
172
|
#
|
173
173
|
# other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
|
174
174
|
# other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
|
175
|
-
def verify(*args)
|
176
|
-
verified(*args) || raise(InvalidSignature)
|
175
|
+
def verify(*args, **options)
|
176
|
+
verified(*args, **options) || raise(InvalidSignature)
|
177
177
|
end
|
178
178
|
|
179
179
|
# Generates a signed message for the provided value.
|
180
180
|
#
|
181
|
-
# The message is signed with the +MessageVerifier+'s secret.
|
182
|
-
#
|
181
|
+
# The message is signed with the +MessageVerifier+'s secret.
|
182
|
+
# Returns Base64-encoded message joined with the generated signature.
|
183
183
|
#
|
184
184
|
# verifier = ActiveSupport::MessageVerifier.new 's3Krit'
|
185
185
|
# verifier.generate 'a private message' # => "BAhJIhRwcml2YXRlLW1lc3NhZ2UGOgZFVA==--e2d724331ebdee96a10fb99b089508d1c72bd772"
|
@@ -6,7 +6,8 @@ module ActiveSupport
|
|
6
6
|
module Messages #:nodoc:
|
7
7
|
class Metadata #:nodoc:
|
8
8
|
def initialize(message, expires_at = nil, purpose = nil)
|
9
|
-
@message, @
|
9
|
+
@message, @purpose = message, purpose
|
10
|
+
@expires_at = expires_at.is_a?(String) ? parse_expires_at(expires_at) : expires_at
|
10
11
|
end
|
11
12
|
|
12
13
|
def as_json(options = {})
|
@@ -64,7 +65,15 @@ module ActiveSupport
|
|
64
65
|
end
|
65
66
|
|
66
67
|
def fresh?
|
67
|
-
@expires_at.nil? || Time.now.utc <
|
68
|
+
@expires_at.nil? || Time.now.utc < @expires_at
|
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
|
68
77
|
end
|
69
78
|
end
|
70
79
|
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,28 +18,28 @@ 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
|
-
run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, options) } || raise
|
24
|
+
run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
|
24
25
|
end
|
25
26
|
|
26
27
|
private
|
27
28
|
def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
|
28
|
-
self.class.new(secret, sign_secret, options)
|
29
|
+
self.class.new(secret, sign_secret, **options)
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
33
|
module Verifier
|
33
34
|
include Rotator
|
34
35
|
|
35
|
-
def verified(*args, on_rotation:
|
36
|
-
super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, options) }
|
36
|
+
def verified(*args, on_rotation: @on_rotation, **options)
|
37
|
+
super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
|
37
38
|
end
|
38
39
|
|
39
40
|
private
|
40
41
|
def build_rotation(secret = @secret, options)
|
41
|
-
self.class.new(secret, options)
|
42
|
+
self.class.new(secret, **options)
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
@@ -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
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require "active_support/json"
|
4
4
|
require "active_support/core_ext/string/access"
|
5
5
|
require "active_support/core_ext/string/behavior"
|
6
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
6
7
|
require "active_support/core_ext/module/delegation"
|
7
|
-
require "active_support/core_ext/regexp"
|
8
8
|
|
9
9
|
module ActiveSupport #:nodoc:
|
10
10
|
module Multibyte #:nodoc:
|
@@ -18,7 +18,7 @@ module ActiveSupport #:nodoc:
|
|
18
18
|
# through the +mb_chars+ method. Methods which would normally return a
|
19
19
|
# String object now return a Chars object so methods can be chained.
|
20
20
|
#
|
21
|
-
# 'The Perfect String '.mb_chars.downcase.strip
|
21
|
+
# 'The Perfect String '.mb_chars.downcase.strip
|
22
22
|
# # => #<ActiveSupport::Multibyte::Chars:0x007fdc434ccc10 @wrapped_string="the perfect string">
|
23
23
|
#
|
24
24
|
# Chars objects are perfectly interchangeable with String objects as long as
|
@@ -49,7 +49,7 @@ module ActiveSupport #:nodoc:
|
|
49
49
|
alias to_s wrapped_string
|
50
50
|
alias to_str wrapped_string
|
51
51
|
|
52
|
-
delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
|
52
|
+
delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
|
53
53
|
|
54
54
|
# Creates a new Chars instance by wrapping _string_.
|
55
55
|
def initialize(string)
|
@@ -60,7 +60,7 @@ module ActiveSupport #:nodoc:
|
|
60
60
|
# Forward all undefined methods to the wrapped string.
|
61
61
|
def method_missing(method, *args, &block)
|
62
62
|
result = @wrapped_string.__send__(method, *args, &block)
|
63
|
-
if
|
63
|
+
if method.end_with?("!")
|
64
64
|
self if result
|
65
65
|
else
|
66
66
|
result.kind_of?(String) ? chars(result) : result
|
@@ -74,12 +74,6 @@ module ActiveSupport #:nodoc:
|
|
74
74
|
@wrapped_string.respond_to?(method, include_private)
|
75
75
|
end
|
76
76
|
|
77
|
-
# Returns +true+ when the proxy class can handle the string. Returns
|
78
|
-
# +false+ otherwise.
|
79
|
-
def self.consumes?(string)
|
80
|
-
string.encoding == Encoding::UTF_8
|
81
|
-
end
|
82
|
-
|
83
77
|
# Works just like <tt>String#split</tt>, with the exception that the items
|
84
78
|
# in the resulting list are Chars instances instead of String. This makes
|
85
79
|
# chaining methods easier.
|
@@ -109,7 +103,7 @@ module ActiveSupport #:nodoc:
|
|
109
103
|
#
|
110
104
|
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
|
111
105
|
def reverse
|
112
|
-
chars(
|
106
|
+
chars(@wrapped_string.scan(/\X/).reverse.join)
|
113
107
|
end
|
114
108
|
|
115
109
|
# Limits the byte size of the string to a number of bytes without breaking
|
@@ -118,35 +112,7 @@ module ActiveSupport #:nodoc:
|
|
118
112
|
#
|
119
113
|
# 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
|
120
114
|
def limit(limit)
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
# Converts characters in the string to uppercase.
|
125
|
-
#
|
126
|
-
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
|
127
|
-
def upcase
|
128
|
-
chars Unicode.upcase(@wrapped_string)
|
129
|
-
end
|
130
|
-
|
131
|
-
# Converts characters in the string to lowercase.
|
132
|
-
#
|
133
|
-
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
|
134
|
-
def downcase
|
135
|
-
chars Unicode.downcase(@wrapped_string)
|
136
|
-
end
|
137
|
-
|
138
|
-
# Converts characters in the string to the opposite case.
|
139
|
-
#
|
140
|
-
# 'El Cañón'.mb_chars.swapcase.to_s # => "eL cAÑÓN"
|
141
|
-
def swapcase
|
142
|
-
chars Unicode.swapcase(@wrapped_string)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Converts the first character to uppercase and the remainder to lowercase.
|
146
|
-
#
|
147
|
-
# 'über'.mb_chars.capitalize.to_s # => "Über"
|
148
|
-
def capitalize
|
149
|
-
(slice(0) || chars("")).upcase + (slice(1..-1) || chars("")).downcase
|
115
|
+
chars(@wrapped_string.truncate_bytes(limit, omission: nil))
|
150
116
|
end
|
151
117
|
|
152
118
|
# Capitalizes the first letter of every word, when possible.
|
@@ -154,21 +120,10 @@ module ActiveSupport #:nodoc:
|
|
154
120
|
# "ÉL QUE SE ENTERÓ".mb_chars.titleize.to_s # => "Él Que Se Enteró"
|
155
121
|
# "日本語".mb_chars.titleize.to_s # => "日本語"
|
156
122
|
def titleize
|
157
|
-
chars(downcase.to_s.gsub(/\b('?\S)/u) {
|
123
|
+
chars(downcase.to_s.gsub(/\b('?\S)/u) { $1.upcase })
|
158
124
|
end
|
159
125
|
alias_method :titlecase, :titleize
|
160
126
|
|
161
|
-
# Returns the KC normalization of the string by default. NFKC is
|
162
|
-
# considered the best normalization form for passing strings to databases
|
163
|
-
# and validations.
|
164
|
-
#
|
165
|
-
# * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
|
166
|
-
# <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
|
167
|
-
# ActiveSupport::Multibyte::Unicode.default_normalization_form
|
168
|
-
def normalize(form = nil)
|
169
|
-
chars(Unicode.normalize(@wrapped_string, form))
|
170
|
-
end
|
171
|
-
|
172
127
|
# Performs canonical decomposition on all the characters.
|
173
128
|
#
|
174
129
|
# 'é'.length # => 2
|
@@ -190,7 +145,7 @@ module ActiveSupport #:nodoc:
|
|
190
145
|
# 'क्षि'.mb_chars.length # => 4
|
191
146
|
# 'क्षि'.mb_chars.grapheme_length # => 3
|
192
147
|
def grapheme_length
|
193
|
-
|
148
|
+
@wrapped_string.scan(/\X/).length
|
194
149
|
end
|
195
150
|
|
196
151
|
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
@@ -206,27 +161,14 @@ module ActiveSupport #:nodoc:
|
|
206
161
|
to_s.as_json(options)
|
207
162
|
end
|
208
163
|
|
209
|
-
%w(
|
164
|
+
%w(reverse tidy_bytes).each do |method|
|
210
165
|
define_method("#{method}!") do |*args|
|
211
|
-
@wrapped_string =
|
166
|
+
@wrapped_string = public_send(method, *args).to_s
|
212
167
|
self
|
213
168
|
end
|
214
169
|
end
|
215
170
|
|
216
171
|
private
|
217
|
-
|
218
|
-
def translate_offset(byte_offset)
|
219
|
-
return nil if byte_offset.nil?
|
220
|
-
return 0 if @wrapped_string == ""
|
221
|
-
|
222
|
-
begin
|
223
|
-
@wrapped_string.byteslice(0...byte_offset).unpack("U*").length
|
224
|
-
rescue ArgumentError
|
225
|
-
byte_offset -= 1
|
226
|
-
retry
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
172
|
def chars(string)
|
231
173
|
self.class.new(string)
|
232
174
|
end
|