app/models/model_mixin.rb in quo_vadis-1.0.2 vs app/models/model_mixin.rb in quo_vadis-1.0.3
- old
+ new
@@ -5,10 +5,13 @@
def self.included(base)
base.send :extend, ClassMethods
end
module ClassMethods
+ # Adds methods to set and authenticate against a password stored encrypted by BCrypt.
+ # Also adds methods to generate and clear a token, used to retrieve the record of a
+ # user who has forgotten their password.
def authenticates
send :include, InstanceMethodsOnActivation
attr_reader :password
attr_protected :password_digest
@@ -18,46 +21,73 @@
validates :password_digest, :presence => true
scope :valid_token, lambda { |token| where("token = ? AND token_created_at > ?", token, 3.hours.ago) }
instance_eval <<-END
+ # Returns the user with the given <tt>username</tt> if the given password is
+ # correct, and <tt>nil</tt> otherwise.
def authenticate(username, plain_text_password)
user = where(:username => username).first
if user && user.has_matching_password?(plain_text_password)
user
else
nil
end
end
+
+ def find_by_salt(id, salt) # :nodoc:
+ user = User.find_by_id id
+ if user && user.has_matching_salt?(salt)
+ user
+ else
+ nil
+ end
+ end
END
end
end
module InstanceMethodsOnActivation
- def password=(plain_text_password)
+ def password=(plain_text_password) # :nodoc:
@password = plain_text_password
self.password_digest = BCrypt::Password.create plain_text_password
end
- def generate_token
+ # Generates a unique, timestamped token which can be used in URLs, and
+ # saves the record. This is part of the forgotten-password workflow.
+ def generate_token # :nodoc:
begin
self.token = url_friendly_token
end while self.class.exists?(:token => token)
self.token_created_at = Time.now.utc
save
end
- def clear_token
+ # Clears the user's timestamped token and saves the record.
+ # This is part of the forgotten-password workflow.
+ def clear_token # :nodoc:
update_attributes :token => nil, :token_created_at => nil
end
- def has_matching_password?(plain_text_password)
+ # Returns true if the given <tt>plain_text_password</tt> is the user's
+ # password, and false otherwise.
+ def has_matching_password?(plain_text_password) # :nodoc:
BCrypt::Password.new(password_digest) == plain_text_password
end
+ # Returns true if the given <tt>salt</tt> is the user's salt,
+ # and false otherwise.
+ def has_matching_salt?(salt) # :nodoc:
+ password_salt == salt
+ end
+
+ def password_salt # :nodoc:
+ BCrypt::Password.new(password_digest).salt
+ end
+
private
- def url_friendly_token
+ def url_friendly_token # :nodoc:
ActiveSupport::SecureRandom.base64(10).tr('+/=', 'xyz')
end
end
end