mirror of https://github.com/rails/rails
Refactor `has_secure_password` to extract dedicated attribute module
Follow up of #26764 and #35700. And add test case for #35700.
This commit is contained in:
parent
dc45130c44
commit
50fba828d5
|
@ -69,42 +69,7 @@ module ActiveModel
|
|||
raise
|
||||
end
|
||||
|
||||
mod = Module.new do
|
||||
attr_reader attribute
|
||||
|
||||
define_method("#{attribute}=") do |unencrypted_password|
|
||||
if unencrypted_password.nil?
|
||||
self.send("#{attribute}_digest=", nil)
|
||||
elsif !unencrypted_password.empty?
|
||||
instance_variable_set("@#{attribute}", unencrypted_password)
|
||||
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
|
||||
self.send("#{attribute}_digest=", BCrypt::Password.create(unencrypted_password, cost: cost))
|
||||
end
|
||||
end
|
||||
|
||||
define_method("#{attribute}_confirmation=") do |unencrypted_password|
|
||||
instance_variable_set("@#{attribute}_confirmation", unencrypted_password)
|
||||
end
|
||||
|
||||
# Returns +self+ if the password is correct, otherwise +false+.
|
||||
#
|
||||
# class User < ActiveRecord::Base
|
||||
# has_secure_password validations: false
|
||||
# end
|
||||
#
|
||||
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
|
||||
# user.save
|
||||
# user.authenticate_password('notright') # => false
|
||||
# user.authenticate_password('mUc3m00RsqyRe') # => user
|
||||
define_method("authenticate_#{attribute}") do |unencrypted_password|
|
||||
attribute_digest = send("#{attribute}_digest")
|
||||
BCrypt::Password.new(attribute_digest).is_password?(unencrypted_password) && self
|
||||
end
|
||||
|
||||
alias_method :authenticate, :authenticate_password if attribute == :password
|
||||
end
|
||||
|
||||
include mod
|
||||
include InstanceMethodsOnActivation.new(attribute)
|
||||
|
||||
if validations
|
||||
include ActiveModel::Validations
|
||||
|
@ -122,5 +87,42 @@ module ActiveModel
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
class InstanceMethodsOnActivation < Module
|
||||
def initialize(attribute)
|
||||
attr_reader attribute
|
||||
|
||||
define_method("#{attribute}=") do |unencrypted_password|
|
||||
if unencrypted_password.nil?
|
||||
self.send("#{attribute}_digest=", nil)
|
||||
elsif !unencrypted_password.empty?
|
||||
instance_variable_set("@#{attribute}", unencrypted_password)
|
||||
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
|
||||
self.send("#{attribute}_digest=", BCrypt::Password.create(unencrypted_password, cost: cost))
|
||||
end
|
||||
end
|
||||
|
||||
define_method("#{attribute}_confirmation=") do |unencrypted_password|
|
||||
instance_variable_set("@#{attribute}_confirmation", unencrypted_password)
|
||||
end
|
||||
|
||||
# Returns +self+ if the password is correct, otherwise +false+.
|
||||
#
|
||||
# class User < ActiveRecord::Base
|
||||
# has_secure_password validations: false
|
||||
# end
|
||||
#
|
||||
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
|
||||
# user.save
|
||||
# user.authenticate_password('notright') # => false
|
||||
# user.authenticate_password('mUc3m00RsqyRe') # => user
|
||||
define_method("authenticate_#{attribute}") do |unencrypted_password|
|
||||
attribute_digest = send("#{attribute}_digest")
|
||||
BCrypt::Password.new(attribute_digest).is_password?(unencrypted_password) && self
|
||||
end
|
||||
|
||||
alias_method :authenticate, :authenticate_password if attribute == :password
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -184,6 +184,20 @@ class SecurePasswordTest < ActiveModel::TestCase
|
|||
assert_nil @existing_user.password_digest
|
||||
end
|
||||
|
||||
test "override secure password attribute" do
|
||||
assert_nil @user.password_called
|
||||
|
||||
@user.password = "secret"
|
||||
|
||||
assert_equal "secret", @user.password
|
||||
assert_equal 1, @user.password_called
|
||||
|
||||
@user.password = "terces"
|
||||
|
||||
assert_equal "terces", @user.password
|
||||
assert_equal 2, @user.password_called
|
||||
end
|
||||
|
||||
test "authenticate" do
|
||||
@user.password = "secret"
|
||||
@user.recovery_password = "42password"
|
||||
|
|
|
@ -10,4 +10,11 @@ class User
|
|||
has_secure_password :recovery_password, validations: false
|
||||
|
||||
attr_accessor :password_digest, :recovery_password_digest
|
||||
attr_accessor :password_called
|
||||
|
||||
def password=(unencrypted_password)
|
||||
self.password_called ||= 0
|
||||
self.password_called += 1
|
||||
super
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue