namxam-devise 1.1.0.win
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +455 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +118 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +311 -0
- data/Rakefile +55 -0
- data/TODO +3 -0
- data/app/controllers/devise/confirmations_controller.rb +33 -0
- data/app/controllers/devise/passwords_controller.rb +41 -0
- data/app/controllers/devise/registrations_controller.rb +57 -0
- data/app/controllers/devise/sessions_controller.rb +23 -0
- data/app/controllers/devise/unlocks_controller.rb +34 -0
- data/app/helpers/devise_helper.rb +17 -0
- data/app/mailers/devise/mailer.rb +71 -0
- data/app/views/devise/confirmations/new.html.erb +12 -0
- data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/devise/passwords/edit.html.erb +16 -0
- data/app/views/devise/passwords/new.html.erb +12 -0
- data/app/views/devise/registrations/edit.html.erb +25 -0
- data/app/views/devise/registrations/new.html.erb +18 -0
- data/app/views/devise/sessions/new.html.erb +17 -0
- data/app/views/devise/shared/_links.erb +19 -0
- data/app/views/devise/unlocks/new.html.erb +12 -0
- data/config/locales/en.yml +39 -0
- data/lib/devise.rb +290 -0
- data/lib/devise/controllers/helpers.rb +231 -0
- data/lib/devise/controllers/internal_helpers.rb +98 -0
- data/lib/devise/controllers/scoped_views.rb +35 -0
- data/lib/devise/controllers/url_helpers.rb +41 -0
- data/lib/devise/encryptors/authlogic_sha512.rb +19 -0
- data/lib/devise/encryptors/base.rb +20 -0
- data/lib/devise/encryptors/bcrypt.rb +19 -0
- data/lib/devise/encryptors/clearance_sha1.rb +17 -0
- data/lib/devise/encryptors/restful_authentication_sha1.rb +22 -0
- data/lib/devise/encryptors/sha1.rb +25 -0
- data/lib/devise/encryptors/sha512.rb +25 -0
- data/lib/devise/failure_app.rb +107 -0
- data/lib/devise/hooks/activatable.rb +11 -0
- data/lib/devise/hooks/forgetable.rb +11 -0
- data/lib/devise/hooks/rememberable.rb +35 -0
- data/lib/devise/hooks/timeoutable.rb +22 -0
- data/lib/devise/hooks/trackable.rb +9 -0
- data/lib/devise/mapping.rb +103 -0
- data/lib/devise/models.rb +80 -0
- data/lib/devise/models/authenticatable.rb +126 -0
- data/lib/devise/models/confirmable.rb +164 -0
- data/lib/devise/models/database_authenticatable.rb +110 -0
- data/lib/devise/models/lockable.rb +165 -0
- data/lib/devise/models/recoverable.rb +81 -0
- data/lib/devise/models/registerable.rb +8 -0
- data/lib/devise/models/rememberable.rb +104 -0
- data/lib/devise/models/timeoutable.rb +26 -0
- data/lib/devise/models/token_authenticatable.rb +60 -0
- data/lib/devise/models/trackable.rb +30 -0
- data/lib/devise/models/validatable.rb +53 -0
- data/lib/devise/modules.rb +23 -0
- data/lib/devise/orm/active_record.rb +36 -0
- data/lib/devise/orm/mongoid.rb +29 -0
- data/lib/devise/path_checker.rb +18 -0
- data/lib/devise/rails.rb +69 -0
- data/lib/devise/rails/routes.rb +248 -0
- data/lib/devise/rails/warden_compat.rb +39 -0
- data/lib/devise/schema.rb +97 -0
- data/lib/devise/strategies/authenticatable.rb +111 -0
- data/lib/devise/strategies/base.rb +33 -0
- data/lib/devise/strategies/database_authenticatable.rb +21 -0
- data/lib/devise/strategies/rememberable.rb +43 -0
- data/lib/devise/strategies/token_authenticatable.rb +49 -0
- data/lib/devise/test_helpers.rb +90 -0
- data/lib/devise/version.rb +3 -0
- data/lib/generators/active_record/devise_generator.rb +28 -0
- data/lib/generators/active_record/templates/migration.rb +29 -0
- data/lib/generators/devise/devise_generator.rb +17 -0
- data/lib/generators/devise/install_generator.rb +24 -0
- data/lib/generators/devise/orm_helpers.rb +23 -0
- data/lib/generators/devise/templates/README +25 -0
- data/lib/generators/devise/templates/devise.rb +139 -0
- data/lib/generators/devise/views_generator.rb +63 -0
- data/lib/generators/devise_install_generator.rb +4 -0
- data/lib/generators/devise_views_generator.rb +4 -0
- data/lib/generators/mongoid/devise_generator.rb +17 -0
- data/test/controllers/helpers_test.rb +213 -0
- data/test/controllers/internal_helpers_test.rb +51 -0
- data/test/controllers/url_helpers_test.rb +58 -0
- data/test/devise_test.rb +65 -0
- data/test/encryptors_test.rb +30 -0
- data/test/failure_app_test.rb +123 -0
- data/test/integration/authenticatable_test.rb +344 -0
- data/test/integration/confirmable_test.rb +104 -0
- data/test/integration/database_authenticatable_test.rb +38 -0
- data/test/integration/http_authenticatable_test.rb +49 -0
- data/test/integration/lockable_test.rb +109 -0
- data/test/integration/recoverable_test.rb +141 -0
- data/test/integration/registerable_test.rb +153 -0
- data/test/integration/rememberable_test.rb +91 -0
- data/test/integration/timeoutable_test.rb +80 -0
- data/test/integration/token_authenticatable_test.rb +88 -0
- data/test/integration/trackable_test.rb +64 -0
- data/test/mailers/confirmation_instructions_test.rb +80 -0
- data/test/mailers/reset_password_instructions_test.rb +68 -0
- data/test/mailers/unlock_instructions_test.rb +62 -0
- data/test/mapping_test.rb +85 -0
- data/test/models/confirmable_test.rb +221 -0
- data/test/models/database_authenticatable_test.rb +148 -0
- data/test/models/lockable_test.rb +188 -0
- data/test/models/recoverable_test.rb +138 -0
- data/test/models/rememberable_test.rb +176 -0
- data/test/models/timeoutable_test.rb +28 -0
- data/test/models/token_authenticatable_test.rb +37 -0
- data/test/models/trackable_test.rb +5 -0
- data/test/models/validatable_test.rb +99 -0
- data/test/models_test.rb +77 -0
- data/test/orm/active_record.rb +9 -0
- data/test/orm/mongoid.rb +10 -0
- data/test/rails_app/app/active_record/admin.rb +3 -0
- data/test/rails_app/app/active_record/shim.rb +2 -0
- data/test/rails_app/app/active_record/user.rb +7 -0
- data/test/rails_app/app/controllers/admins_controller.rb +6 -0
- data/test/rails_app/app/controllers/application_controller.rb +9 -0
- data/test/rails_app/app/controllers/home_controller.rb +7 -0
- data/test/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
- data/test/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
- data/test/rails_app/app/controllers/sessions_controller.rb +6 -0
- data/test/rails_app/app/controllers/users_controller.rb +18 -0
- data/test/rails_app/app/helpers/application_helper.rb +3 -0
- data/test/rails_app/app/mongoid/admin.rb +6 -0
- data/test/rails_app/app/mongoid/shim.rb +16 -0
- data/test/rails_app/app/mongoid/user.rb +10 -0
- data/test/rails_app/config/application.rb +35 -0
- data/test/rails_app/config/boot.rb +13 -0
- data/test/rails_app/config/environment.rb +5 -0
- data/test/rails_app/config/environments/development.rb +19 -0
- data/test/rails_app/config/environments/production.rb +33 -0
- data/test/rails_app/config/environments/test.rb +33 -0
- data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_app/config/initializers/devise.rb +136 -0
- data/test/rails_app/config/initializers/inflections.rb +2 -0
- data/test/rails_app/config/initializers/secret_token.rb +2 -0
- data/test/rails_app/config/routes.rb +47 -0
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +27 -0
- data/test/rails_app/db/schema.rb +86 -0
- data/test/routes_test.rb +146 -0
- data/test/support/assertions.rb +24 -0
- data/test/support/helpers.rb +54 -0
- data/test/support/integration.rb +88 -0
- data/test/support/test_silencer.rb +5 -0
- data/test/support/webrat/integrations/rails.rb +32 -0
- data/test/test_helper.rb +21 -0
- data/test/test_helpers_test.rb +72 -0
- metadata +230 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'devise/strategies/database_authenticatable'
|
|
2
|
+
|
|
3
|
+
module Devise
|
|
4
|
+
module Models
|
|
5
|
+
# Authenticable Module, responsible for encrypting password and validating
|
|
6
|
+
# authenticity of a user while signing in.
|
|
7
|
+
#
|
|
8
|
+
# Configuration:
|
|
9
|
+
#
|
|
10
|
+
# You can overwrite configuration values by setting in globally in Devise,
|
|
11
|
+
# using devise method or overwriting the respective instance method.
|
|
12
|
+
#
|
|
13
|
+
# pepper: encryption key used for creating encrypted password. Each time
|
|
14
|
+
# password changes, it's gonna be encrypted again, and this key
|
|
15
|
+
# is added to the password and salt to create a secure hash.
|
|
16
|
+
# Always use `rake secret' to generate a new key.
|
|
17
|
+
#
|
|
18
|
+
# stretches: defines how many times the password will be encrypted.
|
|
19
|
+
#
|
|
20
|
+
# encryptor: the encryptor going to be used. By default :sha1.
|
|
21
|
+
#
|
|
22
|
+
# Examples:
|
|
23
|
+
#
|
|
24
|
+
# User.find(1).valid_password?('password123') # returns true/false
|
|
25
|
+
#
|
|
26
|
+
module DatabaseAuthenticatable
|
|
27
|
+
extend ActiveSupport::Concern
|
|
28
|
+
|
|
29
|
+
included do
|
|
30
|
+
attr_reader :password, :current_password
|
|
31
|
+
attr_accessor :password_confirmation
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Regenerates password salt and encrypted password each time password is set,
|
|
35
|
+
# and then trigger any "after_changed_password"-callbacks.
|
|
36
|
+
def password=(new_password)
|
|
37
|
+
@password = new_password
|
|
38
|
+
|
|
39
|
+
if @password.present?
|
|
40
|
+
self.password_salt = self.class.password_salt
|
|
41
|
+
self.encrypted_password = password_digest(@password)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
|
46
|
+
def valid_password?(incoming_password)
|
|
47
|
+
password_digest(incoming_password) == self.encrypted_password
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Set password and password confirmation to nil
|
|
51
|
+
def clean_up_passwords
|
|
52
|
+
self.password = self.password_confirmation = nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Update record attributes when :current_password matches, otherwise returns
|
|
56
|
+
# error on :current_password. It also automatically rejects :password and
|
|
57
|
+
# :password_confirmation if they are blank.
|
|
58
|
+
def update_with_password(params={})
|
|
59
|
+
current_password = params.delete(:current_password)
|
|
60
|
+
|
|
61
|
+
if params[:password].blank?
|
|
62
|
+
params.delete(:password)
|
|
63
|
+
params.delete(:password_confirmation) if params[:password_confirmation].blank?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
result = if valid_password?(current_password)
|
|
67
|
+
update_attributes(params)
|
|
68
|
+
else
|
|
69
|
+
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
|
70
|
+
self.attributes = params
|
|
71
|
+
false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
clean_up_passwords
|
|
75
|
+
result
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def after_database_authentication
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
protected
|
|
82
|
+
|
|
83
|
+
# Digests the password using the configured encryptor.
|
|
84
|
+
def password_digest(password)
|
|
85
|
+
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
module ClassMethods
|
|
89
|
+
Devise::Models.config(self, :pepper, :stretches, :encryptor)
|
|
90
|
+
|
|
91
|
+
# Returns the class for the configured encryptor.
|
|
92
|
+
def encryptor_class
|
|
93
|
+
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def password_salt
|
|
97
|
+
self.encryptor_class.salt(self.stretches)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# We assume this method already gets the sanitized values from the
|
|
101
|
+
# DatabaseAuthenticatable strategy. If you are using this method on
|
|
102
|
+
# your own, be sure to sanitize the conditions hash to only include
|
|
103
|
+
# the proper fields.
|
|
104
|
+
def find_for_database_authentication(conditions)
|
|
105
|
+
find_for_authentication(conditions)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
module Devise
|
|
2
|
+
module Models
|
|
3
|
+
# Handles blocking a user access after a certain number of attempts.
|
|
4
|
+
# Lockable accepts two different strategies to unlock a user after it's
|
|
5
|
+
# blocked: email and time. The former will send an email to the user when
|
|
6
|
+
# the lock happens, containing a link to unlock it's account. The second
|
|
7
|
+
# will unlock the user automatically after some configured time (ie 2.hours).
|
|
8
|
+
# It's also possible to setup lockable to use both email and time strategies.
|
|
9
|
+
#
|
|
10
|
+
# Configuration:
|
|
11
|
+
#
|
|
12
|
+
# maximum_attempts: how many attempts should be accepted before blocking the user.
|
|
13
|
+
# lock_strategy: lock the user account by :failed_attempts or :none.
|
|
14
|
+
# unlock_strategy: unlock the user account by :time, :email, :both or :none.
|
|
15
|
+
# unlock_in: the time you want to lock the user after to lock happens. Only
|
|
16
|
+
# available when unlock_strategy is :time or :both.
|
|
17
|
+
#
|
|
18
|
+
module Lockable
|
|
19
|
+
extend ActiveSupport::Concern
|
|
20
|
+
|
|
21
|
+
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
|
|
22
|
+
|
|
23
|
+
# Lock an user setting it's locked_at to actual time.
|
|
24
|
+
def lock_access!
|
|
25
|
+
self.locked_at = Time.now
|
|
26
|
+
|
|
27
|
+
if unlock_strategy_enabled?(:email)
|
|
28
|
+
generate_unlock_token
|
|
29
|
+
send_unlock_instructions
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
save(:validate => false)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Unlock an user by cleaning locket_at and failed_attempts.
|
|
36
|
+
def unlock_access!
|
|
37
|
+
if_access_locked do
|
|
38
|
+
self.locked_at = nil
|
|
39
|
+
self.failed_attempts = 0 if respond_to?(:failed_attempts=)
|
|
40
|
+
self.unlock_token = nil if respond_to?(:unlock_token=)
|
|
41
|
+
save(:validate => false)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Verifies whether a user is locked or not.
|
|
46
|
+
def access_locked?
|
|
47
|
+
locked_at && !lock_expired?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Send unlock instructions by email
|
|
51
|
+
def send_unlock_instructions
|
|
52
|
+
::Devise.mailer.unlock_instructions(self).deliver
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Resend the unlock instructions if the user is locked.
|
|
56
|
+
def resend_unlock_token
|
|
57
|
+
if_access_locked { send_unlock_instructions }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Overwrites active? from Devise::Models::Activatable for locking purposes
|
|
61
|
+
# by verifying whether an user is active to sign in or not based on locked?
|
|
62
|
+
def active?
|
|
63
|
+
super && !access_locked?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Overwrites invalid_message from Devise::Models::Authenticatable to define
|
|
67
|
+
# the correct reason for blocking the sign in.
|
|
68
|
+
def inactive_message
|
|
69
|
+
access_locked? ? :locked : super
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Overwrites valid_for_authentication? from Devise::Models::Authenticatable
|
|
73
|
+
# for verifying whether an user is allowed to sign in or not. If the user
|
|
74
|
+
# is locked, it should never be allowed.
|
|
75
|
+
def valid_for_authentication?
|
|
76
|
+
return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
|
|
77
|
+
|
|
78
|
+
case (result = super)
|
|
79
|
+
when Symbol
|
|
80
|
+
return result
|
|
81
|
+
when TrueClass
|
|
82
|
+
self.failed_attempts = 0
|
|
83
|
+
when FalseClass
|
|
84
|
+
self.failed_attempts += 1
|
|
85
|
+
if attempts_exceeded?
|
|
86
|
+
lock_access!
|
|
87
|
+
return :locked
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
save(:validate => false) if changed?
|
|
92
|
+
result
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
protected
|
|
96
|
+
|
|
97
|
+
def attempts_exceeded?
|
|
98
|
+
self.failed_attempts > self.class.maximum_attempts
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Generates unlock token
|
|
102
|
+
def generate_unlock_token
|
|
103
|
+
self.unlock_token = self.class.unlock_token
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Tells if the lock is expired if :time unlock strategy is active
|
|
107
|
+
def lock_expired?
|
|
108
|
+
if unlock_strategy_enabled?(:time)
|
|
109
|
+
locked_at && locked_at < self.class.unlock_in.ago
|
|
110
|
+
else
|
|
111
|
+
false
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Checks whether the record is locked or not, yielding to the block
|
|
116
|
+
# if it's locked, otherwise adds an error to email.
|
|
117
|
+
def if_access_locked
|
|
118
|
+
if access_locked?
|
|
119
|
+
yield
|
|
120
|
+
else
|
|
121
|
+
self.errors.add(:email, :not_locked)
|
|
122
|
+
false
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
module ClassMethods
|
|
127
|
+
# Attempt to find a user by it's email. If a record is found, send new
|
|
128
|
+
# unlock instructions to it. If not user is found, returns a new user
|
|
129
|
+
# with an email not found error.
|
|
130
|
+
# Options must contain the user email
|
|
131
|
+
def send_unlock_instructions(attributes={})
|
|
132
|
+
lockable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
|
133
|
+
lockable.resend_unlock_token if lockable.persisted?
|
|
134
|
+
lockable
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Find a user by it's unlock token and try to unlock it.
|
|
138
|
+
# If no user is found, returns a new user with an error.
|
|
139
|
+
# If the user is not locked, creates an error for the user
|
|
140
|
+
# Options must have the unlock_token
|
|
141
|
+
def unlock_access_by_token(unlock_token)
|
|
142
|
+
lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
|
|
143
|
+
lockable.unlock_access! if lockable.persisted?
|
|
144
|
+
lockable
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Is the unlock enabled for the given unlock strategy?
|
|
148
|
+
def unlock_strategy_enabled?(strategy)
|
|
149
|
+
[:both, strategy].include?(self.unlock_strategy)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Is the lock enabled for the given lock strategy?
|
|
153
|
+
def lock_strategy_enabled?(strategy)
|
|
154
|
+
self.lock_strategy == strategy
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def unlock_token
|
|
158
|
+
Devise.friendly_token
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module Devise
|
|
2
|
+
module Models
|
|
3
|
+
|
|
4
|
+
# Recoverable takes care of reseting the user password and send reset instructions
|
|
5
|
+
# Examples:
|
|
6
|
+
#
|
|
7
|
+
# # resets the user password and save the record, true if valid passwords are given, otherwise false
|
|
8
|
+
# User.find(1).reset_password!('password123', 'password123')
|
|
9
|
+
#
|
|
10
|
+
# # only resets the user password, without saving the record
|
|
11
|
+
# user = User.find(1)
|
|
12
|
+
# user.reset_password('password123', 'password123')
|
|
13
|
+
#
|
|
14
|
+
# # creates a new token and send it with instructions about how to reset the password
|
|
15
|
+
# User.find(1).send_reset_password_instructions
|
|
16
|
+
module Recoverable
|
|
17
|
+
extend ActiveSupport::Concern
|
|
18
|
+
|
|
19
|
+
# Update password saving the record and clearing token. Returns true if
|
|
20
|
+
# the passwords are valid and the record was saved, false otherwise.
|
|
21
|
+
def reset_password!(new_password, new_password_confirmation)
|
|
22
|
+
self.password = new_password
|
|
23
|
+
self.password_confirmation = new_password_confirmation
|
|
24
|
+
clear_reset_password_token if valid?
|
|
25
|
+
save
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Resets reset password token and send reset password instructions by email
|
|
29
|
+
def send_reset_password_instructions
|
|
30
|
+
generate_reset_password_token!
|
|
31
|
+
::Devise.mailer.reset_password_instructions(self).deliver
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
# Generates a new random token for reset password
|
|
37
|
+
def generate_reset_password_token
|
|
38
|
+
self.reset_password_token = self.class.reset_password_token
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Resets the reset password token with and save the record without
|
|
42
|
+
# validating
|
|
43
|
+
def generate_reset_password_token!
|
|
44
|
+
generate_reset_password_token && save(:validate => false)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Removes reset_password token
|
|
48
|
+
def clear_reset_password_token
|
|
49
|
+
self.reset_password_token = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
module ClassMethods
|
|
53
|
+
# Attempt to find a user by it's email. If a record is found, send new
|
|
54
|
+
# password instructions to it. If not user is found, returns a new user
|
|
55
|
+
# with an email not found error.
|
|
56
|
+
# Attributes must contain the user email
|
|
57
|
+
def send_reset_password_instructions(attributes={})
|
|
58
|
+
recoverable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
|
59
|
+
recoverable.send_reset_password_instructions if recoverable.persisted?
|
|
60
|
+
recoverable
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Generate a token checking if one does not already exist in the database.
|
|
64
|
+
def reset_password_token
|
|
65
|
+
generate_token(:reset_password_token)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Attempt to find a user by it's reset_password_token to reset it's
|
|
69
|
+
# password. If a user is found, reset it's password and automatically
|
|
70
|
+
# try saving the record. If not user is found, returns a new user
|
|
71
|
+
# containing an error in reset_password_token attribute.
|
|
72
|
+
# Attributes must contain reset_password_token, password and confirmation
|
|
73
|
+
def reset_password_by_token(attributes={})
|
|
74
|
+
recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
|
|
75
|
+
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) if recoverable.persisted?
|
|
76
|
+
recoverable
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'devise/strategies/rememberable'
|
|
2
|
+
require 'devise/hooks/rememberable'
|
|
3
|
+
require 'devise/hooks/forgetable'
|
|
4
|
+
|
|
5
|
+
module Devise
|
|
6
|
+
module Models
|
|
7
|
+
# Rememberable manages generating and clearing token for remember the user
|
|
8
|
+
# from a saved cookie. Rememberable also has utility methods for dealing
|
|
9
|
+
# with serializing the user into the cookie and back from the cookie, trying
|
|
10
|
+
# to lookup the record based on the saved information.
|
|
11
|
+
# You probably wouldn't use rememberable methods directly, they are used
|
|
12
|
+
# mostly internally for handling the remember token.
|
|
13
|
+
#
|
|
14
|
+
# Configuration:
|
|
15
|
+
#
|
|
16
|
+
# remember_for: the time you want the user will be remembered without
|
|
17
|
+
# asking for credentials. After this time the user will be
|
|
18
|
+
# blocked and will have to enter his credentials again.
|
|
19
|
+
# This configuration is also used to calculate the expires
|
|
20
|
+
# time for the cookie created to remember the user.
|
|
21
|
+
# By default remember_for is 2.weeks.
|
|
22
|
+
#
|
|
23
|
+
# remember_across_browsers: if a valid remember token can be re-used
|
|
24
|
+
# between multiple browsers.
|
|
25
|
+
# By default remember_across_browsers is true.
|
|
26
|
+
#
|
|
27
|
+
# Examples:
|
|
28
|
+
#
|
|
29
|
+
# User.find(1).remember_me! # regenerating the token
|
|
30
|
+
# User.find(1).forget_me! # clearing the token
|
|
31
|
+
#
|
|
32
|
+
# # generating info to put into cookies
|
|
33
|
+
# User.serialize_into_cookie(user)
|
|
34
|
+
#
|
|
35
|
+
# # lookup the user based on the incoming cookie information
|
|
36
|
+
# User.serialize_from_cookie(cookie_string)
|
|
37
|
+
module Rememberable
|
|
38
|
+
extend ActiveSupport::Concern
|
|
39
|
+
|
|
40
|
+
included do
|
|
41
|
+
# Remember me option available in after_authentication hook.
|
|
42
|
+
attr_accessor :remember_me
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Generate a new remember token and save the record without validations
|
|
46
|
+
# unless remember_across_browsers is true and the user already has a valid token.
|
|
47
|
+
def remember_me!
|
|
48
|
+
return if self.class.remember_across_browsers && self.remember_created_at && !self.remember_expired?
|
|
49
|
+
self.remember_token = self.class.remember_token
|
|
50
|
+
self.remember_created_at = Time.now.utc
|
|
51
|
+
save(:validate => false)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Removes the remember token only if it exists, and save the record
|
|
55
|
+
# without validations.
|
|
56
|
+
def forget_me!
|
|
57
|
+
if remember_token
|
|
58
|
+
self.remember_token = nil
|
|
59
|
+
self.remember_created_at = nil
|
|
60
|
+
save(:validate => false)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Remember token should be expired if expiration time not overpass now.
|
|
65
|
+
def remember_expired?
|
|
66
|
+
remember_expires_at <= Time.now.utc
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Remember token expires at created time + remember_for configuration
|
|
70
|
+
def remember_expires_at
|
|
71
|
+
remember_created_at + self.class.remember_for
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def cookie_domain
|
|
75
|
+
self.class.cookie_domain
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def cookie_domain?
|
|
79
|
+
self.class.cookie_domain != false
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
module ClassMethods
|
|
83
|
+
# Create the cookie key using the record id and remember_token
|
|
84
|
+
def serialize_into_cookie(record)
|
|
85
|
+
[record.id, record.remember_token]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Recreate the user based on the stored cookie
|
|
89
|
+
def serialize_from_cookie(id, remember_token)
|
|
90
|
+
conditions = { :id => id, :remember_token => remember_token }
|
|
91
|
+
record = find(:first, :conditions => conditions)
|
|
92
|
+
record if record && !record.remember_expired?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Generate a token checking if one does not already exist in the database.
|
|
96
|
+
def remember_token
|
|
97
|
+
generate_token(:remember_token)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
Devise::Models.config(self, :remember_for, :remember_across_browsers, :cookie_domain)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|