aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib')
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/digest/uuid.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/deep_merge.rb18
-rw-r--r--activesupport/lib/active_support/core_ext/module/delegation.rb12
-rw-r--r--activesupport/lib/active_support/duration.rb2
-rw-r--r--activesupport/lib/active_support/duration/iso8601_parser.rb2
-rw-r--r--activesupport/lib/active_support/lazy_load_hooks.rb38
-rw-r--r--activesupport/lib/active_support/message_encryptor.rb18
-rw-r--r--activesupport/lib/active_support/message_verifier.rb5
-rw-r--r--activesupport/lib/active_support/messages/metadata.rb49
-rw-r--r--activesupport/lib/active_support/xml_mini/jdom.rb2
11 files changed, 92 insertions, 58 deletions
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index 73924aaaf9..d7bd914722 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -14,7 +14,7 @@ require_relative "../core_ext/array/extract_options"
module ActiveSupport
module Cache
# A cache store implementation which stores data in Memcached:
- # http://memcached.org/
+ # https://memcached.org
#
# This is currently the most popular cache store for production websites.
#
diff --git a/activesupport/lib/active_support/core_ext/digest/uuid.rb b/activesupport/lib/active_support/core_ext/digest/uuid.rb
index 992e1081e4..6e949a2d72 100644
--- a/activesupport/lib/active_support/core_ext/digest/uuid.rb
+++ b/activesupport/lib/active_support/core_ext/digest/uuid.rb
@@ -14,7 +14,7 @@ module Digest
# Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs.
# uuid_from_hash always generates the same UUID for a given name and namespace combination.
#
- # See RFC 4122 for details of UUID at: http://www.ietf.org/rfc/rfc4122.txt
+ # See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
def self.uuid_from_hash(hash_class, uuid_namespace, name)
if hash_class == Digest::MD5
version = 3
diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
index f92a2f1c2a..9bc50b7bc6 100644
--- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
+++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
@@ -21,20 +21,14 @@ class Hash
# Same as +deep_merge+, but modifies +self+.
def deep_merge!(other_hash, &block)
- other_hash.each_pair do |current_key, other_value|
- this_value = self[current_key]
-
- self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
- this_value.deep_merge(other_value, &block)
+ merge!(other_hash) do |key, this_val, other_val|
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
+ this_val.deep_merge(other_val, &block)
+ elsif block_given?
+ block.call(key, this_val, other_val)
else
- if block_given? && key?(current_key)
- block.call(current_key, this_value, other_value)
- else
- other_value
- end
+ other_val
end
end
-
- self
end
end
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index c979af9de3..1840dc942f 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -273,10 +273,16 @@ class Module
def method_missing(method, *args, &block)
if #{target}.respond_to?(method)
#{target}.public_send(method, *args, &block)
- elsif #{target}.nil?
- raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
else
- super
+ begin
+ super
+ rescue NoMethodError
+ if #{target}.nil?
+ raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
+ else
+ raise
+ end
+ end
end
end
RUBY
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index f411bb81df..34024fa8c6 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -133,7 +133,7 @@ module ActiveSupport
class << self
# Creates a new Duration from string formatted according to ISO 8601 Duration.
#
- # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
+ # See {ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
# This method allows negative parts to be present in pattern.
# If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+.
def parse(iso8601duration)
diff --git a/activesupport/lib/active_support/duration/iso8601_parser.rb b/activesupport/lib/active_support/duration/iso8601_parser.rb
index 14b2c27d82..a002424cd9 100644
--- a/activesupport/lib/active_support/duration/iso8601_parser.rb
+++ b/activesupport/lib/active_support/duration/iso8601_parser.rb
@@ -7,7 +7,7 @@ module ActiveSupport
class Duration
# Parses a string formatted according to ISO 8601 Duration into the hash.
#
- # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
+ # See {ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
#
# This parser allows negative parts to be present in pattern.
class ISO8601Parser # :nodoc:
diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb
index c23b319046..dc8080c469 100644
--- a/activesupport/lib/active_support/lazy_load_hooks.rb
+++ b/activesupport/lib/active_support/lazy_load_hooks.rb
@@ -27,33 +27,51 @@ module ActiveSupport
base.class_eval do
@load_hooks = Hash.new { |h, k| h[k] = [] }
@loaded = Hash.new { |h, k| h[k] = [] }
+ @run_once = Hash.new { |h, k| h[k] = [] }
end
end
# Declares a block that will be executed when a Rails component is fully
# loaded.
+ #
+ # Options:
+ #
+ # * <tt>:yield</tt> - Yields the object that run_load_hooks to +block+.
+ # * <tt>:run_once</tt> - Given +block+ will run only once.
def on_load(name, options = {}, &block)
@loaded[name].each do |base|
- execute_hook(base, options, block)
+ execute_hook(name, base, options, block)
end
@load_hooks[name] << [block, options]
end
- def execute_hook(base, options, block)
- if options[:yield]
- block.call(base)
- else
- base.instance_eval(&block)
- end
- end
-
def run_load_hooks(name, base = Object)
@loaded[name] << base
@load_hooks[name].each do |hook, options|
- execute_hook(base, options, hook)
+ execute_hook(name, base, options, hook)
end
end
+
+ private
+
+ def with_execution_control(name, block, once)
+ unless @run_once[name].include?(block)
+ @run_once[name] << block if once
+
+ yield
+ end
+ end
+
+ def execute_hook(name, base, options, block)
+ with_execution_control(name, block, options[:run_once]) do
+ if options[:yield]
+ block.call(base)
+ else
+ base.instance_eval(&block)
+ end
+ end
+ end
end
extend LazyLoadHooks
diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb
index 090d51933a..27620f56be 100644
--- a/activesupport/lib/active_support/message_encryptor.rb
+++ b/activesupport/lib/active_support/message_encryptor.rb
@@ -119,16 +119,15 @@ module ActiveSupport
end
# Encrypt and sign a message. We need to sign the message in order to avoid
- # padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks.
+ # padding attacks. Reference: https://www.limited-entropy.com/padding-oracle-attacks/.
def encrypt_and_sign(value, expires_at: nil, expires_in: nil, purpose: nil)
- data = Messages::Metadata.wrap(value, expires_at: expires_at, expires_in: expires_in, purpose: purpose)
- verifier.generate(_encrypt(data))
+ verifier.generate(_encrypt(value, expires_at: expires_at, expires_in: expires_in, purpose: purpose))
end
# Decrypt and verify a message. We need to verify the message in order to
- # avoid padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks.
+ # avoid padding attacks. Reference: https://www.limited-entropy.com/padding-oracle-attacks/.
def decrypt_and_verify(data, purpose: nil)
- Messages::Metadata.verify(_decrypt(verifier.verify(data)), purpose)
+ _decrypt(verifier.verify(data), purpose)
end
# Given a cipher, returns the key length of the cipher to help generate the key of desired size
@@ -137,7 +136,7 @@ module ActiveSupport
end
private
- def _encrypt(value)
+ def _encrypt(value, **metadata_options)
cipher = new_cipher
cipher.encrypt
cipher.key = @secret
@@ -146,7 +145,7 @@ module ActiveSupport
iv = cipher.random_iv
cipher.auth_data = "" if aead_mode?
- encrypted_data = cipher.update(@serializer.dump(value))
+ encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), metadata_options))
encrypted_data << cipher.final
blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
@@ -154,7 +153,7 @@ module ActiveSupport
blob
end
- def _decrypt(encrypted_message)
+ def _decrypt(encrypted_message, purpose)
cipher = new_cipher
encrypted_data, iv, auth_tag = encrypted_message.split("--".freeze).map { |v| ::Base64.strict_decode64(v) }
@@ -174,7 +173,8 @@ module ActiveSupport
decrypted_data = cipher.update(encrypted_data)
decrypted_data << cipher.final
- @serializer.load(decrypted_data)
+ message = Messages::Metadata.verify(decrypted_data, purpose)
+ @serializer.load(message) if message
rescue OpenSSLCipherError, TypeError, ArgumentError
raise InvalidMessage
end
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index fdd2185f7f..7110d6d2c9 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -124,7 +124,8 @@ module ActiveSupport
if valid_message?(signed_message)
begin
data = signed_message.split("--".freeze)[0]
- Messages::Metadata.verify(@serializer.load(decode(data)), purpose)
+ message = Messages::Metadata.verify(decode(data), purpose)
+ @serializer.load(message) if message
rescue ArgumentError => argument_error
return if argument_error.message.include?("invalid base64")
raise
@@ -156,7 +157,7 @@ module ActiveSupport
# verifier = ActiveSupport::MessageVerifier.new 's3Krit'
# verifier.generate 'a private message' # => "BAhJIhRwcml2YXRlLW1lc3NhZ2UGOgZFVA==--e2d724331ebdee96a10fb99b089508d1c72bd772"
def generate(value, expires_at: nil, expires_in: nil, purpose: nil)
- data = encode(@serializer.dump(Messages::Metadata.wrap(value, expires_at: expires_at, expires_in: expires_in, purpose: purpose)))
+ data = encode(Messages::Metadata.wrap(@serializer.dump(value), expires_at: expires_at, expires_in: expires_in, purpose: purpose))
"#{data}--#{generate_digest(data)}"
end
diff --git a/activesupport/lib/active_support/messages/metadata.rb b/activesupport/lib/active_support/messages/metadata.rb
index a45aecfcd0..e97caac766 100644
--- a/activesupport/lib/active_support/messages/metadata.rb
+++ b/activesupport/lib/active_support/messages/metadata.rb
@@ -5,27 +5,25 @@ require "time"
module ActiveSupport
module Messages #:nodoc:
class Metadata #:nodoc:
- def initialize(expires_at, purpose)
- @expires_at, @purpose = expires_at, purpose.to_s
+ def initialize(message, expires_at = nil, purpose = nil)
+ @message, @expires_at, @purpose = message, expires_at, purpose
+ end
+
+ def as_json(options = {})
+ { _rails: { message: @message, exp: @expires_at, pur: @purpose } }
end
class << self
def wrap(message, expires_at: nil, expires_in: nil, purpose: nil)
if expires_at || expires_in || purpose
- { "value" => message, "_rails" => { "exp" => pick_expiry(expires_at, expires_in), "pur" => purpose } }
+ JSON.encode new(encode(message), pick_expiry(expires_at, expires_in), purpose)
else
message
end
end
def verify(message, purpose)
- metadata = extract_metadata(message)
-
- if metadata.nil?
- message if purpose.nil?
- elsif metadata.match?(purpose) && metadata.fresh?
- message["value"]
- end
+ extract_metadata(message).verify(purpose)
end
private
@@ -38,19 +36,36 @@ module ActiveSupport
end
def extract_metadata(message)
- if message.is_a?(Hash) && message.key?("_rails")
- new(message["_rails"]["exp"], message["_rails"]["pur"])
+ data = JSON.decode(message) rescue nil
+
+ if data.is_a?(Hash) && data.key?("_rails")
+ new(decode(data["_rails"]["message"]), data["_rails"]["exp"], data["_rails"]["pur"])
+ else
+ new(message)
end
end
- end
- def match?(purpose)
- @purpose == purpose.to_s
+ def encode(message)
+ ::Base64.strict_encode64(message)
+ end
+
+ def decode(message)
+ ::Base64.strict_decode64(message)
+ end
end
- def fresh?
- @expires_at.nil? || Time.now.utc < Time.iso8601(@expires_at)
+ def verify(purpose)
+ @message if match?(purpose) && fresh?
end
+
+ private
+ def match?(purpose)
+ @purpose.to_s == purpose.to_s
+ end
+
+ def fresh?
+ @expires_at.nil? || Time.now.utc < Time.iso8601(@expires_at)
+ end
end
end
end
diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb
index 60c7277028..ebed376c7a 100644
--- a/activesupport/lib/active_support/xml_mini/jdom.rb
+++ b/activesupport/lib/active_support/xml_mini/jdom.rb
@@ -40,7 +40,7 @@ module ActiveSupport
else
@dbf = DocumentBuilderFactory.new_instance
# secure processing of java xml
- # http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html
+ # https://archive.is/9xcQQ
@dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
@dbf.setFeature("http://xml.org/sax/features/external-general-entities", false)
@dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false)