activesupport 5.0.7.2 → 5.1.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 activesupport might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +215 -820
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_support.rb +8 -4
- data/lib/active_support/all.rb +3 -3
- data/lib/active_support/array_inquirer.rb +7 -5
- data/lib/active_support/backtrace_cleaner.rb +4 -4
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache.rb +42 -49
- data/lib/active_support/cache/file_store.rb +12 -21
- data/lib/active_support/cache/mem_cache_store.rb +30 -40
- data/lib/active_support/cache/memory_store.rb +11 -13
- data/lib/active_support/cache/null_store.rb +4 -4
- data/lib/active_support/cache/strategy/local_cache.rb +16 -25
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +8 -9
- data/lib/active_support/callbacks.rb +647 -584
- data/lib/active_support/concurrency/share_lock.rb +20 -21
- data/lib/active_support/configurable.rb +5 -5
- data/lib/active_support/core_ext.rb +1 -2
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/array/access.rb +1 -1
- data/lib/active_support/core_ext/array/conversions.rb +15 -15
- data/lib/active_support/core_ext/array/grouping.rb +1 -1
- data/lib/active_support/core_ext/array/inquiry.rb +1 -1
- data/lib/active_support/core_ext/array/prepend_and_append.rb +1 -1
- data/lib/active_support/core_ext/benchmark.rb +1 -1
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +4 -6
- data/lib/active_support/core_ext/class.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +5 -5
- data/lib/active_support/core_ext/class/attribute_accessors.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +18 -4
- data/lib/active_support/core_ext/date.rb +5 -5
- data/lib/active_support/core_ext/date/acts_like.rb +1 -1
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +8 -8
- data/lib/active_support/core_ext/date/conversions.rb +12 -12
- data/lib/active_support/core_ext/date/zones.rb +2 -2
- data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -22
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +9 -1
- data/lib/active_support/core_ext/date_and_time/zones.rb +7 -8
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/date_time/acts_like.rb +2 -2
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +9 -9
- data/lib/active_support/core_ext/date_time/compatibility.rb +2 -13
- data/lib/active_support/core_ext/date_time/conversions.rb +12 -12
- data/lib/active_support/core_ext/digest/uuid.rb +4 -4
- data/lib/active_support/core_ext/enumerable.rb +46 -57
- data/lib/active_support/core_ext/file.rb +1 -1
- data/lib/active_support/core_ext/file/atomic.rb +4 -4
- data/lib/active_support/core_ext/hash.rb +9 -9
- data/lib/active_support/core_ext/hash/compact.rb +12 -9
- data/lib/active_support/core_ext/hash/conversions.rb +36 -37
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -2
- data/lib/active_support/core_ext/hash/keys.rb +8 -8
- data/lib/active_support/core_ext/hash/reverse_merge.rb +1 -1
- data/lib/active_support/core_ext/hash/slice.rb +4 -4
- data/lib/active_support/core_ext/hash/transform_values.rb +1 -0
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/integer/inflections.rb +1 -1
- data/lib/active_support/core_ext/integer/time.rb +2 -2
- data/lib/active_support/core_ext/kernel.rb +4 -4
- data/lib/active_support/core_ext/kernel/concern.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -18
- data/lib/active_support/core_ext/marshal.rb +2 -2
- data/lib/active_support/core_ext/module.rb +11 -12
- data/lib/active_support/core_ext/module/aliasing.rb +3 -48
- data/lib/active_support/core_ext/module/attr_internal.rb +4 -4
- data/lib/active_support/core_ext/module/attribute_accessors.rb +11 -5
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +20 -13
- data/lib/active_support/core_ext/module/concerning.rb +1 -1
- data/lib/active_support/core_ext/module/delegation.rb +82 -16
- data/lib/active_support/core_ext/module/introspection.rb +3 -11
- data/lib/active_support/core_ext/module/reachable.rb +2 -2
- data/lib/active_support/core_ext/numeric.rb +4 -4
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -9
- data/lib/active_support/core_ext/numeric/inquiry.rb +21 -21
- data/lib/active_support/core_ext/numeric/time.rb +5 -5
- data/lib/active_support/core_ext/object.rb +12 -12
- data/lib/active_support/core_ext/object/blank.rb +3 -1
- data/lib/active_support/core_ext/object/conversions.rb +4 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +24 -4
- data/lib/active_support/core_ext/object/inclusion.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +26 -12
- data/lib/active_support/core_ext/object/to_param.rb +1 -1
- data/lib/active_support/core_ext/object/to_query.rb +4 -4
- data/lib/active_support/core_ext/object/try.rb +1 -1
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range.rb +4 -4
- data/lib/active_support/core_ext/range/conversions.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +4 -0
- data/lib/active_support/core_ext/securerandom.rb +3 -3
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/string/access.rb +6 -6
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +3 -3
- data/lib/active_support/core_ext/string/indent.rb +4 -4
- data/lib/active_support/core_ext/string/inflections.rb +10 -14
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +19 -20
- data/lib/active_support/core_ext/string/strip.rb +1 -1
- data/lib/active_support/core_ext/string/zones.rb +2 -2
- data/lib/active_support/core_ext/time.rb +5 -5
- data/lib/active_support/core_ext/time/acts_like.rb +1 -1
- data/lib/active_support/core_ext/time/calculations.rb +23 -29
- data/lib/active_support/core_ext/time/compatibility.rb +1 -10
- data/lib/active_support/core_ext/time/conversions.rb +12 -12
- data/lib/active_support/core_ext/time/zones.rb +3 -3
- data/lib/active_support/core_ext/uri.rb +2 -2
- data/lib/active_support/dependencies.rb +45 -47
- data/lib/active_support/dependencies/interlock.rb +1 -1
- data/lib/active_support/deprecation.rb +8 -8
- data/lib/active_support/deprecation/behaviors.rb +3 -3
- data/lib/active_support/deprecation/instance_delegator.rb +2 -2
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +6 -4
- data/lib/active_support/deprecation/reporting.rb +7 -7
- data/lib/active_support/duration.rb +30 -26
- data/lib/active_support/duration/iso8601_parser.rb +66 -65
- data/lib/active_support/duration/iso8601_serializer.rb +11 -9
- data/lib/active_support/evented_file_update_checker.rb +59 -60
- data/lib/active_support/execution_wrapper.rb +3 -3
- data/lib/active_support/executor.rb +1 -1
- data/lib/active_support/file_update_checker.rb +54 -50
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/gzip.rb +5 -5
- data/lib/active_support/hash_with_indifferent_access.rb +10 -20
- data/lib/active_support/i18n.rb +5 -5
- data/lib/active_support/i18n_railtie.rb +11 -10
- data/lib/active_support/inflections.rb +11 -11
- data/lib/active_support/inflector.rb +5 -5
- data/lib/active_support/inflector/inflections.rb +11 -9
- data/lib/active_support/inflector/methods.rb +51 -50
- data/lib/active_support/inflector/transliterate.rb +8 -11
- data/lib/active_support/json.rb +2 -2
- data/lib/active_support/json/decoding.rb +3 -3
- data/lib/active_support/json/encoding.rb +8 -7
- data/lib/active_support/key_generator.rb +17 -17
- data/lib/active_support/lazy_load_hooks.rb +12 -30
- data/lib/active_support/log_subscriber.rb +5 -5
- data/lib/active_support/log_subscriber/test_helper.rb +9 -9
- data/lib/active_support/logger.rb +3 -3
- data/lib/active_support/logger_silence.rb +3 -3
- data/lib/active_support/logger_thread_safe_level.rb +1 -1
- data/lib/active_support/message_encryptor.rb +72 -35
- data/lib/active_support/message_verifier.rb +7 -7
- data/lib/active_support/multibyte.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +23 -21
- data/lib/active_support/multibyte/unicode.rb +68 -89
- data/lib/active_support/notifications.rb +5 -5
- data/lib/active_support/notifications/fanout.rb +3 -3
- data/lib/active_support/notifications/instrumenter.rb +5 -5
- data/lib/active_support/number_helper.rb +4 -4
- data/lib/active_support/number_helper/number_converter.rb +11 -11
- data/lib/active_support/number_helper/number_to_currency_converter.rb +3 -3
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +6 -6
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -11
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -3
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +6 -6
- data/lib/active_support/option_merger.rb +1 -1
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +6 -4
- data/lib/active_support/per_thread_registry.rb +5 -5
- data/lib/active_support/rails.rb +12 -6
- data/lib/active_support/railtie.rb +3 -3
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +8 -14
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/string_inquirer.rb +8 -2
- data/lib/active_support/subscriber.rb +9 -5
- data/lib/active_support/tagged_logging.rb +4 -4
- data/lib/active_support/test_case.rb +12 -29
- data/lib/active_support/testing/assertions.rb +100 -2
- data/lib/active_support/testing/autorun.rb +6 -2
- data/lib/active_support/testing/constant_lookup.rb +0 -1
- data/lib/active_support/testing/declarative.rb +1 -1
- data/lib/active_support/testing/deprecation.rb +3 -2
- data/lib/active_support/testing/isolation.rb +13 -22
- data/lib/active_support/testing/method_call_assertions.rb +1 -1
- data/lib/active_support/testing/setup_and_teardown.rb +2 -2
- data/lib/active_support/testing/stream.rb +28 -28
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +45 -12
- data/lib/active_support/time.rb +12 -12
- data/lib/active_support/time_with_zone.rb +16 -26
- data/lib/active_support/values/time_zone.rb +40 -46
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini.rb +34 -36
- data/lib/active_support/xml_mini/jdom.rb +112 -112
- data/lib/active_support/xml_mini/libxml.rb +15 -12
- data/lib/active_support/xml_mini/libxmlsax.rb +17 -15
- data/lib/active_support/xml_mini/nokogiri.rb +13 -11
- data/lib/active_support/xml_mini/nokogirisax.rb +15 -14
- data/lib/active_support/xml_mini/rexml.rb +9 -9
- metadata +8 -19
- data/lib/active_support/concurrency/latch.rb +0 -26
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
- data/lib/active_support/core_ext/struct.rb +0 -3
- data/lib/active_support/core_ext/time/marshal.rb +0 -3
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "concurrent/map"
|
2
|
+
require "openssl"
|
3
3
|
|
4
4
|
module ActiveSupport
|
5
5
|
# KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2.
|
@@ -17,7 +17,7 @@ module ActiveSupport
|
|
17
17
|
# Returns a derived key suitable for use. The default key_size is chosen
|
18
18
|
# to be compatible with the default settings of ActiveSupport::MessageVerifier.
|
19
19
|
# i.e. OpenSSL::Digest::SHA1#block_length
|
20
|
-
def generate_key(salt, key_size=64)
|
20
|
+
def generate_key(salt, key_size = 64)
|
21
21
|
OpenSSL::PKCS5.pbkdf2_hmac_sha1(@secret, salt, @iterations, key_size)
|
22
22
|
end
|
23
23
|
end
|
@@ -51,21 +51,21 @@ module ActiveSupport
|
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
54
|
+
# To prevent users from using something insecure like "Password" we make sure that the
|
55
|
+
# secret they've provided is at least 30 characters in length.
|
56
|
+
def ensure_secret_secure(secret)
|
57
|
+
if secret.blank?
|
58
|
+
raise ArgumentError, "A secret is required to generate an integrity hash " \
|
59
|
+
"for cookie session data. Set a secret_key_base of at least " \
|
60
|
+
"#{SECRET_MIN_LENGTH} characters in config/secrets.yml."
|
61
|
+
end
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
63
|
+
if secret.length < SECRET_MIN_LENGTH
|
64
|
+
raise ArgumentError, "Secret should be something secure, " \
|
65
|
+
"like \"#{SecureRandom.hex(16)}\". The value you " \
|
66
|
+
"provided, \"#{secret}\", is shorter than the minimum length " \
|
67
|
+
"of #{SECRET_MIN_LENGTH} characters."
|
68
|
+
end
|
68
69
|
end
|
69
|
-
end
|
70
70
|
end
|
71
71
|
end
|
@@ -15,9 +15,9 @@ module ActiveSupport
|
|
15
15
|
# end
|
16
16
|
# end
|
17
17
|
#
|
18
|
-
# When the entirety of +
|
18
|
+
# When the entirety of +ActiveRecord::Base+ has been
|
19
19
|
# evaluated then +run_load_hooks+ is invoked. The very last line of
|
20
|
-
# +
|
20
|
+
# +ActiveRecord::Base+ is:
|
21
21
|
#
|
22
22
|
# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
|
23
23
|
module LazyLoadHooks
|
@@ -25,51 +25,33 @@ module ActiveSupport
|
|
25
25
|
base.class_eval do
|
26
26
|
@load_hooks = Hash.new { |h, k| h[k] = [] }
|
27
27
|
@loaded = Hash.new { |h, k| h[k] = [] }
|
28
|
-
@run_once = Hash.new { |h, k| h[k] = [] }
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
32
31
|
# Declares a block that will be executed when a Rails component is fully
|
33
32
|
# loaded.
|
34
|
-
#
|
35
|
-
# Options:
|
36
|
-
#
|
37
|
-
# * <tt>:yield</tt> - Yields the object that run_load_hooks to +block+.
|
38
|
-
# * <tt>:run_once</tt> - Given +block+ will run only once.
|
39
33
|
def on_load(name, options = {}, &block)
|
40
34
|
@loaded[name].each do |base|
|
41
|
-
execute_hook(
|
35
|
+
execute_hook(base, options, block)
|
42
36
|
end
|
43
37
|
|
44
38
|
@load_hooks[name] << [block, options]
|
45
39
|
end
|
46
40
|
|
41
|
+
def execute_hook(base, options, block)
|
42
|
+
if options[:yield]
|
43
|
+
block.call(base)
|
44
|
+
else
|
45
|
+
base.instance_eval(&block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
47
49
|
def run_load_hooks(name, base = Object)
|
48
50
|
@loaded[name] << base
|
49
51
|
@load_hooks[name].each do |hook, options|
|
50
|
-
execute_hook(
|
52
|
+
execute_hook(base, options, hook)
|
51
53
|
end
|
52
54
|
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def with_execution_control(name, block, once)
|
57
|
-
unless @run_once[name].include?(block)
|
58
|
-
@run_once[name] << block if once
|
59
|
-
|
60
|
-
yield
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def execute_hook(name, base, options, block)
|
65
|
-
with_execution_control(name, block, options[:run_once]) do
|
66
|
-
if options[:yield]
|
67
|
-
block.call(base)
|
68
|
-
else
|
69
|
-
base.instance_eval(&block)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
55
|
end
|
74
56
|
|
75
57
|
extend LazyLoadHooks
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "active_support/core_ext/module/attribute_accessors"
|
2
|
+
require "active_support/core_ext/class/attribute"
|
3
|
+
require "active_support/subscriber"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
# ActiveSupport::LogSubscriber is an object set to consume
|
@@ -85,7 +85,7 @@ module ActiveSupport
|
|
85
85
|
logger.error "Could not log #{name.inspect} event. #{e.class}: #{e.message} #{e.backtrace}"
|
86
86
|
end
|
87
87
|
|
88
|
-
|
88
|
+
private
|
89
89
|
|
90
90
|
%w(info debug warn error fatal unknown).each do |level|
|
91
91
|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
@@ -99,7 +99,7 @@ module ActiveSupport
|
|
99
99
|
# option is set to +true+, it also adds bold to the string. This is based
|
100
100
|
# on the Highline implementation and will automatically append CLEAR to the
|
101
101
|
# end of the returned String.
|
102
|
-
def color(text, color, bold=false)
|
102
|
+
def color(text, color, bold = false) # :doc:
|
103
103
|
return text unless colorize_logging
|
104
104
|
color = self.class.const_get(color.upcase) if color.is_a?(Symbol)
|
105
105
|
bold = bold ? BOLD : ""
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "active_support/log_subscriber"
|
2
|
+
require "active_support/logger"
|
3
|
+
require "active_support/notifications"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
class LogSubscriber
|
@@ -58,15 +58,15 @@ module ActiveSupport
|
|
58
58
|
def initialize(level = DEBUG)
|
59
59
|
@flush_count = 0
|
60
60
|
@level = level
|
61
|
-
@logged = Hash.new { |h,k| h[k] = [] }
|
61
|
+
@logged = Hash.new { |h, k| h[k] = [] }
|
62
62
|
end
|
63
63
|
|
64
64
|
def method_missing(level, message = nil)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
if block_given?
|
66
|
+
@logged[level] << yield
|
67
|
+
else
|
68
|
+
@logged[level] << message
|
69
|
+
end
|
70
70
|
end
|
71
71
|
|
72
72
|
def logged(level)
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "active_support/logger_silence"
|
2
|
+
require "active_support/logger_thread_safe_level"
|
3
|
+
require "logger"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
class Logger < ::Logger
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "active_support/concern"
|
2
|
+
require "active_support/core_ext/module/attribute_accessors"
|
3
|
+
require "concurrent"
|
4
4
|
|
5
5
|
module LoggerSilence
|
6
6
|
extend ActiveSupport::Concern
|
@@ -1,6 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "openssl"
|
2
|
+
require "base64"
|
3
|
+
require "active_support/core_ext/array/extract_options"
|
4
|
+
require "active_support/message_verifier"
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
7
|
# MessageEncryptor is a simple way to encrypt values which get stored
|
@@ -30,6 +31,16 @@ module ActiveSupport
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
34
|
+
module NullVerifier #:nodoc:
|
35
|
+
def self.verify(value)
|
36
|
+
value
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.generate(value)
|
40
|
+
value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
33
44
|
class InvalidMessage < StandardError; end
|
34
45
|
OpenSSLCipherError = OpenSSL::Cipher::CipherError
|
35
46
|
|
@@ -42,15 +53,17 @@ module ActiveSupport
|
|
42
53
|
# Options:
|
43
54
|
# * <tt>:cipher</tt> - Cipher to use. Can be any cipher returned by
|
44
55
|
# <tt>OpenSSL::Cipher.ciphers</tt>. Default is 'aes-256-cbc'.
|
45
|
-
# * <tt>:digest</tt> - String of digest to use for signing. Default is
|
56
|
+
# * <tt>:digest</tt> - String of digest to use for signing. Default is
|
57
|
+
# +SHA1+. Ignored when using an AEAD cipher like 'aes-256-gcm'.
|
46
58
|
# * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+.
|
47
59
|
def initialize(secret, *signature_key_or_options)
|
48
60
|
options = signature_key_or_options.extract_options!
|
49
61
|
sign_secret = signature_key_or_options.first
|
50
62
|
@secret = secret
|
51
63
|
@sign_secret = sign_secret
|
52
|
-
@cipher = options[:cipher] ||
|
53
|
-
@
|
64
|
+
@cipher = options[:cipher] || "aes-256-cbc"
|
65
|
+
@digest = options[:digest] || "SHA1" unless aead_mode?
|
66
|
+
@verifier = resolve_verifier
|
54
67
|
@serializer = options[:serializer] || Marshal
|
55
68
|
end
|
56
69
|
|
@@ -73,42 +86,66 @@ module ActiveSupport
|
|
73
86
|
|
74
87
|
private
|
75
88
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
89
|
+
def _encrypt(value)
|
90
|
+
cipher = new_cipher
|
91
|
+
cipher.encrypt
|
92
|
+
cipher.key = @secret
|
80
93
|
|
81
|
-
|
82
|
-
|
94
|
+
# Rely on OpenSSL for the initialization vector
|
95
|
+
iv = cipher.random_iv
|
96
|
+
cipher.auth_data = "" if aead_mode?
|
83
97
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
"#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
|
88
|
-
end
|
98
|
+
encrypted_data = cipher.update(@serializer.dump(value))
|
99
|
+
encrypted_data << cipher.final
|
89
100
|
|
90
|
-
|
91
|
-
|
92
|
-
|
101
|
+
blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
|
102
|
+
blob << "--#{::Base64.strict_encode64 cipher.auth_tag}" if aead_mode?
|
103
|
+
blob
|
104
|
+
end
|
93
105
|
|
94
|
-
|
95
|
-
|
96
|
-
|
106
|
+
def _decrypt(encrypted_message)
|
107
|
+
cipher = new_cipher
|
108
|
+
encrypted_data, iv, auth_tag = encrypted_message.split("--".freeze).map { |v| ::Base64.strict_decode64(v) }
|
109
|
+
|
110
|
+
# Currently the OpenSSL bindings do not raise an error if auth_tag is
|
111
|
+
# truncated, which would allow an attacker to easily forge it. See
|
112
|
+
# https://github.com/ruby/openssl/issues/63
|
113
|
+
raise InvalidMessage if aead_mode? && auth_tag.bytes.length != 16
|
114
|
+
|
115
|
+
cipher.decrypt
|
116
|
+
cipher.key = @secret
|
117
|
+
cipher.iv = iv
|
118
|
+
if aead_mode?
|
119
|
+
cipher.auth_tag = auth_tag
|
120
|
+
cipher.auth_data = ""
|
121
|
+
end
|
122
|
+
|
123
|
+
decrypted_data = cipher.update(encrypted_data)
|
124
|
+
decrypted_data << cipher.final
|
125
|
+
|
126
|
+
@serializer.load(decrypted_data)
|
127
|
+
rescue OpenSSLCipherError, TypeError, ArgumentError
|
128
|
+
raise InvalidMessage
|
129
|
+
end
|
97
130
|
|
98
|
-
|
99
|
-
|
131
|
+
def new_cipher
|
132
|
+
OpenSSL::Cipher.new(@cipher)
|
133
|
+
end
|
100
134
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
135
|
+
def verifier
|
136
|
+
@verifier
|
137
|
+
end
|
105
138
|
|
106
|
-
|
107
|
-
|
108
|
-
|
139
|
+
def aead_mode?
|
140
|
+
@aead_mode ||= new_cipher.authenticated?
|
141
|
+
end
|
109
142
|
|
110
|
-
|
111
|
-
|
112
|
-
|
143
|
+
def resolve_verifier
|
144
|
+
if aead_mode?
|
145
|
+
NullVerifier
|
146
|
+
else
|
147
|
+
MessageVerifier.new(@sign_secret || @secret, digest: @digest, serializer: NullSerializer)
|
148
|
+
end
|
149
|
+
end
|
113
150
|
end
|
114
151
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "base64"
|
2
|
+
require "active_support/core_ext/object/blank"
|
3
|
+
require "active_support/security_utils"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
# +MessageVerifier+ makes it easy to generate and verify messages which are
|
@@ -34,9 +34,9 @@ module ActiveSupport
|
|
34
34
|
class InvalidSignature < StandardError; end
|
35
35
|
|
36
36
|
def initialize(secret, options = {})
|
37
|
-
raise ArgumentError,
|
37
|
+
raise ArgumentError, "Secret should not be nil." unless secret
|
38
38
|
@secret = secret
|
39
|
-
@digest = options[:digest] ||
|
39
|
+
@digest = options[:digest] || "SHA1"
|
40
40
|
@serializer = options[:serializer] || Marshal
|
41
41
|
end
|
42
42
|
|
@@ -83,7 +83,7 @@ module ActiveSupport
|
|
83
83
|
data = signed_message.split("--".freeze)[0]
|
84
84
|
@serializer.load(decode(data))
|
85
85
|
rescue ArgumentError => argument_error
|
86
|
-
return if argument_error.message
|
86
|
+
return if argument_error.message.include?("invalid base64")
|
87
87
|
raise
|
88
88
|
end
|
89
89
|
end
|
@@ -127,7 +127,7 @@ module ActiveSupport
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def generate_digest(data)
|
130
|
-
require
|
130
|
+
require "openssl" unless defined?(OpenSSL)
|
131
131
|
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data)
|
132
132
|
end
|
133
133
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveSupport #:nodoc:
|
2
2
|
module Multibyte
|
3
|
-
autoload :Chars,
|
4
|
-
autoload :Unicode,
|
3
|
+
autoload :Chars, "active_support/multibyte/chars"
|
4
|
+
autoload :Unicode, "active_support/multibyte/unicode"
|
5
5
|
|
6
6
|
# The proxy class returned when calling mb_chars. You can use this accessor
|
7
7
|
# to configure your own proxy class so you can support other encodings. See
|
@@ -1,7 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require "active_support/json"
|
2
|
+
require "active_support/core_ext/string/access"
|
3
|
+
require "active_support/core_ext/string/behavior"
|
4
|
+
require "active_support/core_ext/module/delegation"
|
5
|
+
require "active_support/core_ext/regexp"
|
5
6
|
|
6
7
|
module ActiveSupport #:nodoc:
|
7
8
|
module Multibyte #:nodoc:
|
@@ -15,7 +16,8 @@ module ActiveSupport #:nodoc:
|
|
15
16
|
# through the +mb_chars+ method. Methods which would normally return a
|
16
17
|
# String object now return a Chars object so methods can be chained.
|
17
18
|
#
|
18
|
-
# 'The Perfect String '.mb_chars.downcase.strip.normalize
|
19
|
+
# 'The Perfect String '.mb_chars.downcase.strip.normalize
|
20
|
+
# # => #<ActiveSupport::Multibyte::Chars:0x007fdc434ccc10 @wrapped_string="the perfect string">
|
19
21
|
#
|
20
22
|
# Chars objects are perfectly interchangeable with String objects as long as
|
21
23
|
# no explicit class checks are made. If certain methods do explicitly check
|
@@ -45,7 +47,7 @@ module ActiveSupport #:nodoc:
|
|
45
47
|
alias to_s wrapped_string
|
46
48
|
alias to_str wrapped_string
|
47
49
|
|
48
|
-
delegate :<=>, :=~, :acts_like_string?, :
|
50
|
+
delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
|
49
51
|
|
50
52
|
# Creates a new Chars instance by wrapping _string_.
|
51
53
|
def initialize(string)
|
@@ -56,7 +58,7 @@ module ActiveSupport #:nodoc:
|
|
56
58
|
# Forward all undefined methods to the wrapped string.
|
57
59
|
def method_missing(method, *args, &block)
|
58
60
|
result = @wrapped_string.__send__(method, *args, &block)
|
59
|
-
if method
|
61
|
+
if /!$/.match?(method)
|
60
62
|
self if result
|
61
63
|
else
|
62
64
|
result.kind_of?(String) ? chars(result) : result
|
@@ -86,7 +88,7 @@ module ActiveSupport #:nodoc:
|
|
86
88
|
end
|
87
89
|
|
88
90
|
# Works like <tt>String#slice!</tt>, but returns an instance of
|
89
|
-
# Chars, or nil if the string was not modified. The string will not be
|
91
|
+
# Chars, or +nil+ if the string was not modified. The string will not be
|
90
92
|
# modified if the range given is out of bounds
|
91
93
|
#
|
92
94
|
# string = 'Welcome'
|
@@ -105,7 +107,7 @@ module ActiveSupport #:nodoc:
|
|
105
107
|
#
|
106
108
|
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
|
107
109
|
def reverse
|
108
|
-
chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack(
|
110
|
+
chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack("U*"))
|
109
111
|
end
|
110
112
|
|
111
113
|
# Limits the byte size of the string to a number of bytes without breaking
|
@@ -133,7 +135,7 @@ module ActiveSupport #:nodoc:
|
|
133
135
|
|
134
136
|
# Converts characters in the string to the opposite case.
|
135
137
|
#
|
136
|
-
# 'El Cañón
|
138
|
+
# 'El Cañón'.mb_chars.swapcase.to_s # => "eL cAÑÓN"
|
137
139
|
def swapcase
|
138
140
|
chars Unicode.swapcase(@wrapped_string)
|
139
141
|
end
|
@@ -142,15 +144,15 @@ module ActiveSupport #:nodoc:
|
|
142
144
|
#
|
143
145
|
# 'über'.mb_chars.capitalize.to_s # => "Über"
|
144
146
|
def capitalize
|
145
|
-
(slice(0) || chars(
|
147
|
+
(slice(0) || chars("")).upcase + (slice(1..-1) || chars("")).downcase
|
146
148
|
end
|
147
149
|
|
148
150
|
# Capitalizes the first letter of every word, when possible.
|
149
151
|
#
|
150
|
-
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
|
151
|
-
# "日本語".mb_chars.titleize
|
152
|
+
# "ÉL QUE SE ENTERÓ".mb_chars.titleize.to_s # => "Él Que Se Enteró"
|
153
|
+
# "日本語".mb_chars.titleize.to_s # => "日本語"
|
152
154
|
def titleize
|
153
|
-
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1)})
|
155
|
+
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1) })
|
154
156
|
end
|
155
157
|
alias_method :titlecase, :titleize
|
156
158
|
|
@@ -170,7 +172,7 @@ module ActiveSupport #:nodoc:
|
|
170
172
|
# 'é'.length # => 2
|
171
173
|
# 'é'.mb_chars.decompose.to_s.length # => 3
|
172
174
|
def decompose
|
173
|
-
chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack(
|
175
|
+
chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*"))
|
174
176
|
end
|
175
177
|
|
176
178
|
# Performs composition on all the characters.
|
@@ -178,7 +180,7 @@ module ActiveSupport #:nodoc:
|
|
178
180
|
# 'é'.length # => 3
|
179
181
|
# 'é'.mb_chars.compose.to_s.length # => 2
|
180
182
|
def compose
|
181
|
-
chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack(
|
183
|
+
chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*"))
|
182
184
|
end
|
183
185
|
|
184
186
|
# Returns the number of grapheme clusters in the string.
|
@@ -209,21 +211,21 @@ module ActiveSupport #:nodoc:
|
|
209
211
|
end
|
210
212
|
end
|
211
213
|
|
212
|
-
|
214
|
+
private
|
213
215
|
|
214
|
-
def translate_offset(byte_offset)
|
216
|
+
def translate_offset(byte_offset)
|
215
217
|
return nil if byte_offset.nil?
|
216
|
-
return 0 if @wrapped_string ==
|
218
|
+
return 0 if @wrapped_string == ""
|
217
219
|
|
218
220
|
begin
|
219
|
-
@wrapped_string.byteslice(0...byte_offset).unpack(
|
221
|
+
@wrapped_string.byteslice(0...byte_offset).unpack("U*").length
|
220
222
|
rescue ArgumentError
|
221
223
|
byte_offset -= 1
|
222
224
|
retry
|
223
225
|
end
|
224
226
|
end
|
225
227
|
|
226
|
-
def chars(string)
|
228
|
+
def chars(string)
|
227
229
|
self.class.new(string)
|
228
230
|
end
|
229
231
|
end
|