-
-
Notifications
You must be signed in to change notification settings - Fork 457
/
user.rb
190 lines (166 loc) · 5.39 KB
/
user.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
require 'digest/sha1'
module Clearance
module User
# Hook for all Clearance::User modules.
#
# If you need to override parts of Clearance::User,
# extend and include à la carte.
#
# @example
# extend ClassMethods
# include InstanceMethods
# include AttrAccessor
# include Callbacks
#
# @see ClassMethods
# @see InstanceMethods
# @see AttrAccessor
# @see Validations
# @see Callbacks
def self.included(model)
model.extend(ClassMethods)
model.send(:include, InstanceMethods)
model.send(:include, AttrAccessor)
model.send(:include, Validations)
model.send(:include, Callbacks)
end
module AttrAccessor
# Hook for attr_accessor virtual attributes.
#
# :password, :password_confirmation
def self.included(model)
model.class_eval do
attr_accessor :password, :password_confirmation
end
end
end
module Validations
# Hook for validations.
#
# :email must be present, unique, formatted
#
# If password is required,
# :password must be present, confirmed
def self.included(model)
model.class_eval do
validates_presence_of :email, :unless => :email_optional?
validates_uniqueness_of :email, :case_sensitive => false, :allow_blank => true
validates_format_of :email, :with => %r{^[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$}i, :allow_blank => true
validates_presence_of :password, :unless => :password_optional?
validates_confirmation_of :password
end
end
end
module Callbacks
# Hook for callbacks.
#
# salt, token, password encryption are handled before_save.
def self.included(model)
model.class_eval do
before_save :initialize_salt,
:encrypt_password
before_create :generate_remember_token
end
end
end
module InstanceMethods
# Am I authenticated with given password?
#
# @param [String] plain-text password
# @return [true, false]
# @example
# user.authenticated?('password')
def authenticated?(password)
encrypted_password == encrypt(password)
end
# Set the remember token.
#
# @deprecated Use {#reset_remember_token!} instead
def remember_me!
warn "[DEPRECATION] remember_me!: use reset_remember_token! instead"
reset_remember_token!
end
# Reset the remember token.
#
# @example
# user.reset_remember_token!
def reset_remember_token!
generate_remember_token
save(:validate => false)
end
# Mark my account as forgotten password.
#
# @example
# user.forgot_password!
def forgot_password!
generate_confirmation_token
save(:validate => false)
end
# Update my password.
#
# @param [String, String] password and password confirmation
# @return [true, false] password was updated or not
# @example
# user.update_password('new-password', 'new-password')
def update_password(new_password, new_password_confirmation)
self.password = new_password
self.password_confirmation = new_password_confirmation
if valid?
self.confirmation_token = nil
end
save
end
protected
def generate_hash(string)
Digest::SHA1.hexdigest(string)
end
def initialize_salt
if new_record?
self.salt = generate_hash("--#{Time.now.utc}--#{password}--#{rand}--")
end
end
def encrypt_password
return if password.blank?
self.encrypted_password = encrypt(password)
end
def encrypt(string)
generate_hash("--#{salt}--#{string}--")
end
def generate_confirmation_token
self.confirmation_token = encrypt("--#{Time.now.utc}--#{password}--#{rand}--")
end
def generate_remember_token
self.remember_token = encrypt("--#{Time.now.utc}--#{encrypted_password}--#{id}--#{rand}--")
end
# Always false. Override to allow other forms of authentication
# (username, facebook, etc).
# @return [Boolean] true if the email field be left blank for this user
def email_optional?
false
end
# True if the password has been set and the password is not being
# updated. Override to allow other forms of # authentication (username,
# facebook, etc).
# @return [Boolean] true if the password field can be left blank for this user
def password_optional?
encrypted_password.present? && password.blank?
end
def password_required?
# warn "[DEPRECATION] password_required?: use !password_optional? instead"
!password_optional?
end
end
module ClassMethods
# Authenticate with email and password.
#
# @param [String, String] email and password
# @return [User, nil] authenticated user or nil
# @example
# User.authenticate("email@example.com", "password")
def authenticate(email, password)
return nil unless user = find_by_email(email)
return user if user.authenticated?(password)
end
end
end
end