aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support
diff options
context:
space:
mode:
authorKasper Timm Hansen <kaspth@gmail.com>2017-07-19 15:17:09 +0200
committerGitHub <noreply@github.com>2017-07-19 15:17:09 +0200
commit1f7f872ac6c8b57af6e0117bde5f6c38d0bae923 (patch)
treecfc630ba1060eab5e566d7e9be6acabb9b5477da /activesupport/lib/active_support
parentd1281cdc2c11ebf26a4e040b02ac1da21f2010a0 (diff)
parent3b506ee0d8ccc8fa69da19aeb38915115a8aa44d (diff)
downloadrails-1f7f872ac6c8b57af6e0117bde5f6c38d0bae923.tar.gz
rails-1f7f872ac6c8b57af6e0117bde5f6c38d0bae923.tar.bz2
rails-1f7f872ac6c8b57af6e0117bde5f6c38d0bae923.zip
Merge pull request #29599 from assain/add_meta_data_to_message_encryptor
Add purpose and expiry to messages encrypted using Message Encryptor
Diffstat (limited to 'activesupport/lib/active_support')
-rw-r--r--activesupport/lib/active_support/message_encryptor.rb11
-rw-r--r--activesupport/lib/active_support/messages/metadata.rb55
2 files changed, 61 insertions, 5 deletions
diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb
index d5db2920b9..9ceb3a3a7f 100644
--- a/activesupport/lib/active_support/message_encryptor.rb
+++ b/activesupport/lib/active_support/message_encryptor.rb
@@ -4,6 +4,7 @@ require "openssl"
require "base64"
require_relative "core_ext/array/extract_options"
require_relative "message_verifier"
+require_relative "messages/metadata"
module ActiveSupport
# MessageEncryptor is a simple way to encrypt values which get stored
@@ -87,14 +88,15 @@ module ActiveSupport
# 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.
- def encrypt_and_sign(value)
- verifier.generate(_encrypt(value))
+ 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))
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.
- def decrypt_and_verify(value)
- _decrypt(verifier.verify(value))
+ def decrypt_and_verify(data, purpose: nil)
+ Messages::Metadata.verify(_decrypt(verifier.verify(data)), purpose)
end
# Given a cipher, returns the key length of the cipher to help generate the key of desired size
@@ -103,7 +105,6 @@ module ActiveSupport
end
private
-
def _encrypt(value)
cipher = new_cipher
cipher.encrypt
diff --git a/activesupport/lib/active_support/messages/metadata.rb b/activesupport/lib/active_support/messages/metadata.rb
new file mode 100644
index 0000000000..e35086fb77
--- /dev/null
+++ b/activesupport/lib/active_support/messages/metadata.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+require "time"
+
+module ActiveSupport
+ module Messages #:nodoc:
+ class Metadata #:nodoc:
+ def initialize(expires_at, purpose)
+ @expires_at, @purpose = expires_at, 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.to_s } }
+ else
+ message
+ end
+ end
+
+ def verify(message, purpose)
+ metadata = extract_metadata(message)
+
+ if metadata.nil?
+ message if purpose.nil?
+ elsif metadata.match?(purpose.to_s) && metadata.fresh?
+ message["value"]
+ end
+ end
+
+ private
+ def pick_expiry(expires_at, expires_in)
+ if expires_at
+ expires_at.utc.iso8601(3)
+ elsif expires_in
+ expires_in.from_now.utc.iso8601(3)
+ end
+ end
+
+ def extract_metadata(message)
+ if message.is_a?(Hash) && message.key?("_rails")
+ new(message["_rails"]["exp"], message["_rails"]["pur"])
+ end
+ end
+ end
+
+ def match?(purpose)
+ @purpose == purpose
+ end
+
+ def fresh?
+ @expires_at.nil? || Time.now.utc < Time.iso8601(@expires_at)
+ end
+ end
+ end
+end