diff --git a/lib/active_model/password_reset.rb b/lib/active_model/password_reset.rb index 5fb9bcd..b1a5f68 100644 --- a/lib/active_model/password_reset.rb +++ b/lib/active_model/password_reset.rb @@ -25,12 +25,10 @@ def token email = user.email digest = Digest::MD5.digest(user.password_digest) expires_at = Time.now.to_i + EXPIRATION_TIME - token = MessageVerifier.generate([email, digest, expires_at]) - CGI.escape(token) + MessageVerifier.generate([email, digest, expires_at]) end - def self.find(escaped_token) - token = CGI.unescape(escaped_token) + def self.find(token) email, digest, expires_at = MessageVerifier.verify(token) raise TokenExpired if Time.now.to_i > expires_at.to_i new(email: email).tap do |password_reset| diff --git a/lib/active_model/password_reset/message_verifier.rb b/lib/active_model/password_reset/message_verifier.rb index 4c49c98..802c448 100644 --- a/lib/active_model/password_reset/message_verifier.rb +++ b/lib/active_model/password_reset/message_verifier.rb @@ -9,12 +9,14 @@ class MessageVerifier class << self def generate(object) - instance.message_verifier.generate(object) + token = instance.message_verifier.generate(object) + Base64.urlsafe_encode64(token) end def verify(string) - instance.message_verifier.verify(string) - rescue ActiveSupport::MessageVerifier::InvalidSignature + token = Base64.urlsafe_decode64(string) + instance.message_verifier.verify(token) + rescue ActiveSupport::MessageVerifier::InvalidSignature, ArgumentError raise TokenInvalid end end diff --git a/lib/active_model/password_reset/version.rb b/lib/active_model/password_reset/version.rb index b1f8f51..3fff052 100644 --- a/lib/active_model/password_reset/version.rb +++ b/lib/active_model/password_reset/version.rb @@ -1,5 +1,5 @@ module ActiveModel class PasswordReset - VERSION = "1.0.2" + VERSION = "1.0.3" end end diff --git a/test/password_reset_test.rb b/test/password_reset_test.rb index 1e96f6f..197d73c 100644 --- a/test/password_reset_test.rb +++ b/test/password_reset_test.rb @@ -51,20 +51,24 @@ def test_is_invalid_without_email def test_find_raises_exception_with_invalid_email token = ActiveModel::PasswordReset::MessageVerifier.generate(["invalid@example.com", Digest::MD5.digest("alicedigest"), Time.now.to_i + 3600]) - assert_raises(ActiveModel::PasswordReset::EmailInvalid) { ActiveModel::PasswordReset.find(CGI.escape(token)) } + assert_raises(ActiveModel::PasswordReset::EmailInvalid) { ActiveModel::PasswordReset.find(token) } end def test_find_raises_exception_with_invalid_token assert_raises(ActiveModel::PasswordReset::TokenInvalid) { ActiveModel::PasswordReset.find("invalidtoken") } end + def test_find_raises_exception_with_non_base64_token + assert_raises(ActiveModel::PasswordReset::TokenInvalid) { ActiveModel::PasswordReset.find("%%%%%%%%%") } + end + def test_find_raises_exception_with_expired_token token = ActiveModel::PasswordReset::MessageVerifier.generate(["alice@example.com", Digest::MD5.digest("alicedigest"), Time.now.to_i - 3600]) - assert_raises(ActiveModel::PasswordReset::TokenExpired) { ActiveModel::PasswordReset.find(CGI.escape(token)) } + assert_raises(ActiveModel::PasswordReset::TokenExpired) { ActiveModel::PasswordReset.find(token) } end def test_find_raises_exception_with_changed_password token = ActiveModel::PasswordReset::MessageVerifier.generate(["alice@example.com", Digest::MD5.digest("anotheralicedigest"), Time.now.to_i + 3600]) - assert_raises(ActiveModel::PasswordReset::PasswordChanged) { ActiveModel::PasswordReset.find(CGI.escape(token)) } + assert_raises(ActiveModel::PasswordReset::PasswordChanged) { ActiveModel::PasswordReset.find(token) } end end