loyal_devise 2.1.2

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.
Files changed (208) hide show
  1. data/.gitignore +10 -0
  2. data/.travis.yml +15 -0
  3. data/CHANGELOG.rdoc +881 -0
  4. data/CONTRIBUTING.md +12 -0
  5. data/Gemfile +31 -0
  6. data/Gemfile.lock +154 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +388 -0
  9. data/Rakefile +34 -0
  10. data/app/controllers/devise/confirmations_controller.rb +44 -0
  11. data/app/controllers/devise/omniauth_callbacks_controller.rb +31 -0
  12. data/app/controllers/devise/passwords_controller.rb +57 -0
  13. data/app/controllers/devise/registrations_controller.rb +120 -0
  14. data/app/controllers/devise/sessions_controller.rb +51 -0
  15. data/app/controllers/devise/unlocks_controller.rb +45 -0
  16. data/app/controllers/devise_controller.rb +193 -0
  17. data/app/helpers/devise_helper.rb +26 -0
  18. data/app/mailers/devise/mailer.rb +16 -0
  19. data/app/views/devise/_links.erb +3 -0
  20. data/app/views/devise/confirmations/new.html.erb +12 -0
  21. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  22. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  23. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  24. data/app/views/devise/passwords/edit.html.erb +16 -0
  25. data/app/views/devise/passwords/new.html.erb +12 -0
  26. data/app/views/devise/registrations/edit.html.erb +25 -0
  27. data/app/views/devise/registrations/new.html.erb +18 -0
  28. data/app/views/devise/sessions/new.html.erb +17 -0
  29. data/app/views/devise/shared/_links.erb +25 -0
  30. data/app/views/devise/unlocks/new.html.erb +12 -0
  31. data/config/locales/en.yml +59 -0
  32. data/devise.gemspec +26 -0
  33. data/gemfiles/Gemfile.rails-3.1.x +35 -0
  34. data/gemfiles/Gemfile.rails-3.1.x.lock +167 -0
  35. data/lib/devise/controllers/helpers.rb +273 -0
  36. data/lib/devise/controllers/rememberable.rb +53 -0
  37. data/lib/devise/controllers/scoped_views.rb +18 -0
  38. data/lib/devise/controllers/url_helpers.rb +68 -0
  39. data/lib/devise/delegator.rb +17 -0
  40. data/lib/devise/failure_app.rb +188 -0
  41. data/lib/devise/hooks/activatable.rb +12 -0
  42. data/lib/devise/hooks/forgetable.rb +10 -0
  43. data/lib/devise/hooks/lockable.rb +8 -0
  44. data/lib/devise/hooks/rememberable.rb +7 -0
  45. data/lib/devise/hooks/timeoutable.rb +26 -0
  46. data/lib/devise/hooks/trackable.rb +10 -0
  47. data/lib/devise/mailers/helpers.rb +92 -0
  48. data/lib/devise/mapping.rb +173 -0
  49. data/lib/devise/models/authenticatable.rb +269 -0
  50. data/lib/devise/models/confirmable.rb +271 -0
  51. data/lib/devise/models/database_authenticatable.rb +127 -0
  52. data/lib/devise/models/lockable.rb +194 -0
  53. data/lib/devise/models/omniauthable.rb +28 -0
  54. data/lib/devise/models/recoverable.rb +141 -0
  55. data/lib/devise/models/registerable.rb +26 -0
  56. data/lib/devise/models/rememberable.rb +126 -0
  57. data/lib/devise/models/timeoutable.rb +50 -0
  58. data/lib/devise/models/token_authenticatable.rb +90 -0
  59. data/lib/devise/models/trackable.rb +36 -0
  60. data/lib/devise/models/validatable.rb +67 -0
  61. data/lib/devise/models.rb +129 -0
  62. data/lib/devise/modules.rb +30 -0
  63. data/lib/devise/omniauth/config.rb +46 -0
  64. data/lib/devise/omniauth/url_helpers.rb +19 -0
  65. data/lib/devise/omniauth.rb +29 -0
  66. data/lib/devise/orm/active_record.rb +4 -0
  67. data/lib/devise/orm/mongoid.rb +4 -0
  68. data/lib/devise/param_filter.rb +42 -0
  69. data/lib/devise/rails/routes.rb +447 -0
  70. data/lib/devise/rails/warden_compat.rb +44 -0
  71. data/lib/devise/rails.rb +55 -0
  72. data/lib/devise/strategies/authenticatable.rb +177 -0
  73. data/lib/devise/strategies/base.rb +21 -0
  74. data/lib/devise/strategies/database_authenticatable.rb +21 -0
  75. data/lib/devise/strategies/rememberable.rb +56 -0
  76. data/lib/devise/strategies/token_authenticatable.rb +57 -0
  77. data/lib/devise/test_helpers.rb +132 -0
  78. data/lib/devise/time_inflector.rb +15 -0
  79. data/lib/devise/version.rb +4 -0
  80. data/lib/devise.rb +445 -0
  81. data/lib/generators/active_record/devise_generator.rb +80 -0
  82. data/lib/generators/active_record/templates/migration.rb +20 -0
  83. data/lib/generators/active_record/templates/migration_existing.rb +27 -0
  84. data/lib/generators/devise/devise_generator.rb +25 -0
  85. data/lib/generators/devise/install_generator.rb +25 -0
  86. data/lib/generators/devise/orm_helpers.rb +33 -0
  87. data/lib/generators/devise/views_generator.rb +117 -0
  88. data/lib/generators/mongoid/devise_generator.rb +58 -0
  89. data/lib/generators/templates/README +35 -0
  90. data/lib/generators/templates/devise.rb +241 -0
  91. data/lib/generators/templates/markerb/confirmation_instructions.markerb +5 -0
  92. data/lib/generators/templates/markerb/reset_password_instructions.markerb +8 -0
  93. data/lib/generators/templates/markerb/unlock_instructions.markerb +7 -0
  94. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +15 -0
  95. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +19 -0
  96. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +15 -0
  97. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +22 -0
  98. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +17 -0
  99. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +15 -0
  100. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +15 -0
  101. data/test/controllers/custom_strategy_test.rb +63 -0
  102. data/test/controllers/helpers_test.rb +254 -0
  103. data/test/controllers/internal_helpers_test.rb +111 -0
  104. data/test/controllers/sessions_controller_test.rb +58 -0
  105. data/test/controllers/url_helpers_test.rb +60 -0
  106. data/test/delegator_test.rb +20 -0
  107. data/test/devise_test.rb +73 -0
  108. data/test/failure_app_test.rb +222 -0
  109. data/test/generators/active_record_generator_test.rb +76 -0
  110. data/test/generators/devise_generator_test.rb +40 -0
  111. data/test/generators/install_generator_test.rb +14 -0
  112. data/test/generators/mongoid_generator_test.rb +24 -0
  113. data/test/generators/views_generator_test.rb +53 -0
  114. data/test/helpers/devise_helper_test.rb +52 -0
  115. data/test/indifferent_hash.rb +34 -0
  116. data/test/integration/authenticatable_test.rb +634 -0
  117. data/test/integration/confirmable_test.rb +299 -0
  118. data/test/integration/database_authenticatable_test.rb +83 -0
  119. data/test/integration/http_authenticatable_test.rb +98 -0
  120. data/test/integration/lockable_test.rb +243 -0
  121. data/test/integration/omniauthable_test.rb +134 -0
  122. data/test/integration/recoverable_test.rb +307 -0
  123. data/test/integration/registerable_test.rb +346 -0
  124. data/test/integration/rememberable_test.rb +159 -0
  125. data/test/integration/timeoutable_test.rb +141 -0
  126. data/test/integration/token_authenticatable_test.rb +162 -0
  127. data/test/integration/trackable_test.rb +93 -0
  128. data/test/mailers/confirmation_instructions_test.rb +103 -0
  129. data/test/mailers/reset_password_instructions_test.rb +84 -0
  130. data/test/mailers/unlock_instructions_test.rb +78 -0
  131. data/test/mapping_test.rb +128 -0
  132. data/test/models/authenticatable_test.rb +8 -0
  133. data/test/models/confirmable_test.rb +392 -0
  134. data/test/models/database_authenticatable_test.rb +190 -0
  135. data/test/models/lockable_test.rb +274 -0
  136. data/test/models/omniauthable_test.rb +8 -0
  137. data/test/models/recoverable_test.rb +206 -0
  138. data/test/models/registerable_test.rb +8 -0
  139. data/test/models/rememberable_test.rb +175 -0
  140. data/test/models/serializable_test.rb +49 -0
  141. data/test/models/timeoutable_test.rb +47 -0
  142. data/test/models/token_authenticatable_test.rb +56 -0
  143. data/test/models/trackable_test.rb +14 -0
  144. data/test/models/validatable_test.rb +117 -0
  145. data/test/models_test.rb +180 -0
  146. data/test/omniauth/config_test.rb +58 -0
  147. data/test/omniauth/url_helpers_test.rb +52 -0
  148. data/test/orm/active_record.rb +10 -0
  149. data/test/orm/mongoid.rb +15 -0
  150. data/test/rails_app/Rakefile +10 -0
  151. data/test/rails_app/app/active_record/admin.rb +7 -0
  152. data/test/rails_app/app/active_record/shim.rb +3 -0
  153. data/test/rails_app/app/active_record/user.rb +7 -0
  154. data/test/rails_app/app/controllers/admins/sessions_controller.rb +7 -0
  155. data/test/rails_app/app/controllers/admins_controller.rb +12 -0
  156. data/test/rails_app/app/controllers/application_controller.rb +9 -0
  157. data/test/rails_app/app/controllers/home_controller.rb +26 -0
  158. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +3 -0
  159. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +3 -0
  160. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +15 -0
  161. data/test/rails_app/app/controllers/users_controller.rb +24 -0
  162. data/test/rails_app/app/helpers/application_helper.rb +4 -0
  163. data/test/rails_app/app/mailers/users/mailer.rb +9 -0
  164. data/test/rails_app/app/mongoid/admin.rb +28 -0
  165. data/test/rails_app/app/mongoid/shim.rb +25 -0
  166. data/test/rails_app/app/mongoid/user.rb +43 -0
  167. data/test/rails_app/app/views/admins/index.html.erb +1 -0
  168. data/test/rails_app/app/views/admins/sessions/new.html.erb +2 -0
  169. data/test/rails_app/app/views/home/admin_dashboard.html.erb +1 -0
  170. data/test/rails_app/app/views/home/index.html.erb +1 -0
  171. data/test/rails_app/app/views/home/join.html.erb +1 -0
  172. data/test/rails_app/app/views/home/private.html.erb +1 -0
  173. data/test/rails_app/app/views/home/user_dashboard.html.erb +1 -0
  174. data/test/rails_app/app/views/layouts/application.html.erb +24 -0
  175. data/test/rails_app/app/views/users/index.html.erb +1 -0
  176. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +1 -0
  177. data/test/rails_app/app/views/users/sessions/new.html.erb +1 -0
  178. data/test/rails_app/config/application.rb +42 -0
  179. data/test/rails_app/config/boot.rb +9 -0
  180. data/test/rails_app/config/database.yml +18 -0
  181. data/test/rails_app/config/environment.rb +6 -0
  182. data/test/rails_app/config/environments/development.rb +19 -0
  183. data/test/rails_app/config/environments/production.rb +34 -0
  184. data/test/rails_app/config/environments/test.rb +34 -0
  185. data/test/rails_app/config/initializers/backtrace_silencers.rb +8 -0
  186. data/test/rails_app/config/initializers/devise.rb +179 -0
  187. data/test/rails_app/config/initializers/inflections.rb +3 -0
  188. data/test/rails_app/config/initializers/secret_token.rb +3 -0
  189. data/test/rails_app/config/routes.rb +101 -0
  190. data/test/rails_app/config.ru +4 -0
  191. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +75 -0
  192. data/test/rails_app/db/schema.rb +53 -0
  193. data/test/rails_app/lib/shared_admin.rb +15 -0
  194. data/test/rails_app/lib/shared_user.rb +27 -0
  195. data/test/rails_app/public/404.html +26 -0
  196. data/test/rails_app/public/422.html +26 -0
  197. data/test/rails_app/public/500.html +26 -0
  198. data/test/rails_app/public/favicon.ico +0 -0
  199. data/test/rails_app/script/rails +10 -0
  200. data/test/routes_test.rb +249 -0
  201. data/test/support/assertions.rb +41 -0
  202. data/test/support/helpers.rb +92 -0
  203. data/test/support/integration.rb +93 -0
  204. data/test/support/locale/en.yml +4 -0
  205. data/test/support/webrat/integrations/rails.rb +25 -0
  206. data/test/test_helper.rb +28 -0
  207. data/test/test_helpers_test.rb +152 -0
  208. metadata +407 -0
@@ -0,0 +1,194 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require "devise/hooks/lockable"
3
+
4
+ module Devise
5
+ module Models
6
+ # Handles blocking a user access after a certain number of attempts.
7
+ # Lockable accepts two different strategies to unlock a user after it's
8
+ # blocked: email and time. The former will send an email to the user when
9
+ # the lock happens, containing a link to unlock its account. The second
10
+ # will unlock the user automatically after some configured time (ie 2.hours).
11
+ # It's also possible to setup lockable to use both email and time strategies.
12
+ #
13
+ # == Options
14
+ #
15
+ # Lockable adds the following options to +devise+:
16
+ #
17
+ # * +maximum_attempts+: how many attempts should be accepted before blocking the user.
18
+ # * +lock_strategy+: lock the user account by :failed_attempts or :none.
19
+ # * +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
20
+ # * +unlock_in+: the time you want to lock the user after to lock happens. Only available when unlock_strategy is :time or :both.
21
+ # * +unlock_keys+: the keys you want to use when locking and unlocking an account
22
+ #
23
+ module Lockable
24
+ extend ActiveSupport::Concern
25
+
26
+ delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
27
+
28
+ def self.required_fields(klass)
29
+ attributes = []
30
+ attributes << :failed_attempts if klass.lock_strategy_enabled?(:failed_attempts)
31
+ attributes << :locked_at if klass.unlock_strategy_enabled?(:time)
32
+ attributes << :unlock_token if klass.unlock_strategy_enabled?(:email)
33
+
34
+ attributes
35
+ end
36
+
37
+ # Lock a user setting its locked_at to actual time.
38
+ def lock_access!
39
+ self.locked_at = Time.now.utc
40
+
41
+ if unlock_strategy_enabled?(:email)
42
+ generate_unlock_token!
43
+ send_unlock_instructions
44
+ else
45
+ save(:validate => false)
46
+ end
47
+ end
48
+
49
+ # Unlock a user by cleaning locked_at and failed_attempts.
50
+ def unlock_access!
51
+ self.locked_at = nil
52
+ self.failed_attempts = 0 if respond_to?(:failed_attempts=)
53
+ self.unlock_token = nil if respond_to?(:unlock_token=)
54
+ save(:validate => false)
55
+ end
56
+
57
+ # Verifies whether a user is locked or not.
58
+ def access_locked?
59
+ locked_at && !lock_expired?
60
+ end
61
+
62
+ # Send unlock instructions by email
63
+ def send_unlock_instructions
64
+ send_devise_notification(:unlock_instructions)
65
+ end
66
+
67
+ # Resend the unlock instructions if the user is locked.
68
+ def resend_unlock_token
69
+ if_access_locked { send_unlock_instructions }
70
+ end
71
+
72
+ # Overwrites active_for_authentication? from Devise::Models::Activatable for locking purposes
73
+ # by verifying whether a user is active to sign in or not based on locked?
74
+ def active_for_authentication?
75
+ super && !access_locked?
76
+ end
77
+
78
+ # Overwrites invalid_message from Devise::Models::Authenticatable to define
79
+ # the correct reason for blocking the sign in.
80
+ def inactive_message
81
+ access_locked? ? :locked : super
82
+ end
83
+
84
+ # Overwrites valid_for_authentication? from Devise::Models::Authenticatable
85
+ # for verifying whether a user is allowed to sign in or not. If the user
86
+ # is locked, it should never be allowed.
87
+ def valid_for_authentication?
88
+ return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
89
+
90
+ # Unlock the user if the lock is expired, no matter
91
+ # if the user can login or not (wrong password, etc)
92
+ unlock_access! if lock_expired?
93
+
94
+ if super && !access_locked?
95
+ true
96
+ else
97
+ self.failed_attempts ||= 0
98
+ self.failed_attempts += 1
99
+ if attempts_exceeded?
100
+ lock_access! unless access_locked?
101
+ else
102
+ save(:validate => false)
103
+ end
104
+ false
105
+ end
106
+ end
107
+
108
+ def unauthenticated_message
109
+ # If set to paranoid mode, do not show the locked message because it
110
+ # leaks the existence of an account.
111
+ if Devise.paranoid
112
+ super
113
+ elsif lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?
114
+ :locked
115
+ else
116
+ super
117
+ end
118
+ end
119
+
120
+ protected
121
+
122
+ def attempts_exceeded?
123
+ self.failed_attempts > self.class.maximum_attempts
124
+ end
125
+
126
+ # Generates unlock token
127
+ def generate_unlock_token
128
+ self.unlock_token = self.class.unlock_token
129
+ end
130
+
131
+ def generate_unlock_token!
132
+ generate_unlock_token && save(:validate => false)
133
+ end
134
+
135
+ # Tells if the lock is expired if :time unlock strategy is active
136
+ def lock_expired?
137
+ if unlock_strategy_enabled?(:time)
138
+ locked_at && locked_at < self.class.unlock_in.ago
139
+ else
140
+ false
141
+ end
142
+ end
143
+
144
+ # Checks whether the record is locked or not, yielding to the block
145
+ # if it's locked, otherwise adds an error to email.
146
+ def if_access_locked
147
+ if access_locked?
148
+ yield
149
+ else
150
+ self.errors.add(:email, :not_locked)
151
+ false
152
+ end
153
+ end
154
+
155
+ module ClassMethods
156
+ # Attempt to find a user by its email. If a record is found, send new
157
+ # unlock instructions to it. If not user is found, returns a new user
158
+ # with an email not found error.
159
+ # Options must contain the user email
160
+ def send_unlock_instructions(attributes={})
161
+ lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
162
+ lockable.resend_unlock_token if lockable.persisted?
163
+ lockable
164
+ end
165
+
166
+ # Find a user by its unlock token and try to unlock it.
167
+ # If no user is found, returns a new user with an error.
168
+ # If the user is not locked, creates an error for the user
169
+ # Options must have the unlock_token
170
+ def unlock_access_by_token(unlock_token)
171
+ lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
172
+ lockable.unlock_access! if lockable.persisted?
173
+ lockable
174
+ end
175
+
176
+ # Is the unlock enabled for the given unlock strategy?
177
+ def unlock_strategy_enabled?(strategy)
178
+ [:both, strategy].include?(self.unlock_strategy)
179
+ end
180
+
181
+ # Is the lock enabled for the given lock strategy?
182
+ def lock_strategy_enabled?(strategy)
183
+ self.lock_strategy == strategy
184
+ end
185
+
186
+ def unlock_token
187
+ Devise.friendly_token
188
+ end
189
+
190
+ Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in, :unlock_keys)
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'devise/omniauth'
3
+
4
+ module Devise
5
+ module Models
6
+ # Adds OmniAuth support to your model.
7
+ #
8
+ # == Options
9
+ #
10
+ # Oauthable adds the following options to devise_for:
11
+ #
12
+ # * +omniauth_providers+: Which providers are avaialble to this model. It expects an array:
13
+ #
14
+ # devise_for :database_authenticatable, :omniauthable, :omniauth_providers => [:twitter]
15
+ #
16
+ module Omniauthable
17
+ extend ActiveSupport::Concern
18
+
19
+ def self.required_fields(klass)
20
+ []
21
+ end
22
+
23
+ module ClassMethods
24
+ Devise::Models.config(self, :omniauth_providers)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,141 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Devise
3
+ module Models
4
+
5
+ # Recoverable takes care of reseting the user password and send reset instructions.
6
+ #
7
+ # ==Options
8
+ #
9
+ # Recoverable adds the following options to devise_for:
10
+ #
11
+ # * +reset_password_keys+: the keys you want to use when recovering the password for an account
12
+ #
13
+ # == Examples
14
+ #
15
+ # # resets the user password and save the record, true if valid passwords are given, otherwise false
16
+ # User.find(1).reset_password!('password123', 'password123')
17
+ #
18
+ # # only resets the user password, without saving the record
19
+ # user = User.find(1)
20
+ # user.reset_password('password123', 'password123')
21
+ #
22
+ # # creates a new token and send it with instructions about how to reset the password
23
+ # User.find(1).send_reset_password_instructions
24
+ #
25
+ module Recoverable
26
+ extend ActiveSupport::Concern
27
+
28
+ def self.required_fields(klass)
29
+ [:reset_password_sent_at, :reset_password_token]
30
+ end
31
+
32
+ # Update password saving the record and clearing token. Returns true if
33
+ # the passwords are valid and the record was saved, false otherwise.
34
+ def reset_password!(new_password, new_password_confirmation)
35
+ self.password = new_password
36
+ self.password_confirmation = new_password_confirmation
37
+
38
+ if valid?
39
+ clear_reset_password_token
40
+ after_password_reset
41
+ end
42
+
43
+ save
44
+ end
45
+
46
+ # Resets reset password token and send reset password instructions by email
47
+ def send_reset_password_instructions
48
+ generate_reset_password_token! if should_generate_reset_token?
49
+ send_devise_notification(:reset_password_instructions)
50
+ end
51
+
52
+ # Checks if the reset password token sent is within the limit time.
53
+ # We do this by calculating if the difference between today and the
54
+ # sending date does not exceed the confirm in time configured.
55
+ # Returns true if the resource is not responding to reset_password_sent_at at all.
56
+ # reset_password_within is a model configuration, must always be an integer value.
57
+ #
58
+ # Example:
59
+ #
60
+ # # reset_password_within = 1.day and reset_password_sent_at = today
61
+ # reset_password_period_valid? # returns true
62
+ #
63
+ # # reset_password_within = 5.days and reset_password_sent_at = 4.days.ago
64
+ # reset_password_period_valid? # returns true
65
+ #
66
+ # # reset_password_within = 5.days and reset_password_sent_at = 5.days.ago
67
+ # reset_password_period_valid? # returns false
68
+ #
69
+ # # reset_password_within = 0.days
70
+ # reset_password_period_valid? # will always return false
71
+ #
72
+ def reset_password_period_valid?
73
+ reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago
74
+ end
75
+
76
+ protected
77
+
78
+ def should_generate_reset_token?
79
+ reset_password_token.nil? || !reset_password_period_valid?
80
+ end
81
+
82
+ # Generates a new random token for reset password
83
+ def generate_reset_password_token
84
+ self.reset_password_token = self.class.reset_password_token
85
+ self.reset_password_sent_at = Time.now.utc
86
+ self.reset_password_token
87
+ end
88
+
89
+ # Resets the reset password token with and save the record without
90
+ # validating
91
+ def generate_reset_password_token!
92
+ generate_reset_password_token && save(:validate => false)
93
+ end
94
+
95
+ # Removes reset_password token
96
+ def clear_reset_password_token
97
+ self.reset_password_token = nil
98
+ self.reset_password_sent_at = nil
99
+ end
100
+
101
+ def after_password_reset
102
+ end
103
+
104
+ module ClassMethods
105
+ # Attempt to find a user by its email. If a record is found, send new
106
+ # password instructions to it. If not user is found, returns a new user
107
+ # with an email not found error.
108
+ # Attributes must contain the user email
109
+ def send_reset_password_instructions(attributes={})
110
+ recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
111
+ recoverable.send_reset_password_instructions if recoverable.persisted?
112
+ recoverable
113
+ end
114
+
115
+ # Generate a token checking if one does not already exist in the database.
116
+ def reset_password_token
117
+ generate_token(:reset_password_token)
118
+ end
119
+
120
+ # Attempt to find a user by its reset_password_token to reset its
121
+ # password. If a user is found and token is still valid, reset its password and automatically
122
+ # try saving the record. If not user is found, returns a new user
123
+ # containing an error in reset_password_token attribute.
124
+ # Attributes must contain reset_password_token, password and confirmation
125
+ def reset_password_by_token(attributes={})
126
+ recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
127
+ if recoverable.persisted?
128
+ if recoverable.reset_password_period_valid?
129
+ recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
130
+ else
131
+ recoverable.errors.add(:reset_password_token, :expired)
132
+ end
133
+ end
134
+ recoverable
135
+ end
136
+
137
+ Devise::Models.config(self, :reset_password_keys, :reset_password_within)
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Devise
3
+ module Models
4
+ # Registerable is responsible for everything related to registering a new
5
+ # resource (ie user sign up).
6
+ module Registerable
7
+ extend ActiveSupport::Concern
8
+
9
+ def self.required_fields(klass)
10
+ []
11
+ end
12
+
13
+ module ClassMethods
14
+ # A convenience method that receives both parameters and session to
15
+ # initialize a user. This can be used by OAuth, for example, to send
16
+ # in the user token and be stored on initialization.
17
+ #
18
+ # By default discards all information sent by the session by calling
19
+ # new with params.
20
+ def new_with_session(params, session)
21
+ new(params)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,126 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'devise/strategies/rememberable'
3
+ require 'devise/hooks/rememberable'
4
+ require 'devise/hooks/forgetable'
5
+
6
+ module Devise
7
+ module Models
8
+ # Rememberable manages generating and clearing token for remember the user
9
+ # from a saved cookie. Rememberable also has utility methods for dealing
10
+ # with serializing the user into the cookie and back from the cookie, trying
11
+ # to lookup the record based on the saved information.
12
+ # You probably wouldn't use rememberable methods directly, they are used
13
+ # mostly internally for handling the remember token.
14
+ #
15
+ # == Options
16
+ #
17
+ # Rememberable adds the following options in devise_for:
18
+ #
19
+ # * +remember_for+: the time you want the user will be remembered without
20
+ # asking for credentials. After this time the user will be blocked and
21
+ # will have to enter his credentials again. This configuration is also
22
+ # used to calculate the expires time for the cookie created to remember
23
+ # the user. By default remember_for is 2.weeks.
24
+ #
25
+ # * +extend_remember_period+: if true, extends the user's remember period
26
+ # when remembered via cookie. False by default.
27
+ #
28
+ # * +rememberable_options+: configuration options passed to the created cookie.
29
+ #
30
+ # == Examples
31
+ #
32
+ # User.find(1).remember_me! # regenerating the token
33
+ # User.find(1).forget_me! # clearing the token
34
+ #
35
+ # # generating info to put into cookies
36
+ # User.serialize_into_cookie(user)
37
+ #
38
+ # # lookup the user based on the incoming cookie information
39
+ # User.serialize_from_cookie(cookie_string)
40
+ module Rememberable
41
+ extend ActiveSupport::Concern
42
+
43
+ attr_accessor :remember_me, :extend_remember_period
44
+
45
+ def self.required_fields(klass)
46
+ [:remember_created_at]
47
+ end
48
+
49
+ # Generate a new remember token and save the record without validations
50
+ # unless remember_across_browsers is true and the user already has a valid token.
51
+ def remember_me!(extend_period=false)
52
+ self.remember_token = self.class.remember_token if generate_remember_token?
53
+ self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
54
+ save(:validate => false)
55
+ end
56
+
57
+ # If the record is persisted, remove the remember token (but only if
58
+ # it exists), and save the record without validations.
59
+ def forget_me!
60
+ return unless persisted?
61
+ self.remember_token = nil if respond_to?(:remember_token=)
62
+ self.remember_created_at = nil
63
+ save(:validate => false)
64
+ end
65
+
66
+ # Remember token should be expired if expiration time not overpass now.
67
+ def remember_expired?
68
+ remember_created_at.nil? || (remember_expires_at <= Time.now.utc)
69
+ end
70
+
71
+ # Remember token expires at created time + remember_for configuration
72
+ def remember_expires_at
73
+ remember_created_at + self.class.remember_for
74
+ end
75
+
76
+ def rememberable_value
77
+ if respond_to?(:remember_token)
78
+ remember_token
79
+ elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
80
+ salt
81
+ else
82
+ raise "authenticable_salt returned nil for the #{self.class.name} model. " \
83
+ "In order to use rememberable, you must ensure a password is always set " \
84
+ "or have a remember_token column in your model or implement your own " \
85
+ "rememberable_value in the model with custom logic."
86
+ end
87
+ end
88
+
89
+ def rememberable_options
90
+ self.class.rememberable_options
91
+ end
92
+
93
+ protected
94
+
95
+ def generate_remember_token? #:nodoc:
96
+ respond_to?(:remember_token) && remember_expired?
97
+ end
98
+
99
+ # Generate a timestamp if extend_remember_period is true, if no remember_token
100
+ # exists, or if an existing remember token has expired.
101
+ def generate_remember_timestamp?(extend_period) #:nodoc:
102
+ extend_period || remember_created_at.nil? || remember_expired?
103
+ end
104
+
105
+ module ClassMethods
106
+ # Create the cookie key using the record id and remember_token
107
+ def serialize_into_cookie(record)
108
+ [record.to_key, record.rememberable_value]
109
+ end
110
+
111
+ # Recreate the user based on the stored cookie
112
+ def serialize_from_cookie(id, remember_token)
113
+ record = to_adapter.get(id)
114
+ record if record && record.rememberable_value == remember_token && !record.remember_expired?
115
+ end
116
+
117
+ # Generate a token checking if one does not already exist in the database.
118
+ def remember_token #:nodoc:
119
+ generate_token(:remember_token)
120
+ end
121
+
122
+ Devise::Models.config(self, :remember_for, :extend_remember_period, :rememberable_options)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,50 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'devise/hooks/timeoutable'
3
+
4
+ module Devise
5
+ module Models
6
+ # Timeoutable takes care of veryfing whether a user session has already
7
+ # expired or not. When a session expires after the configured time, the user
8
+ # will be asked for credentials again, it means, he/she will be redirected
9
+ # to the sign in page.
10
+ #
11
+ # == Options
12
+ #
13
+ # Timeoutable adds the following options to devise_for:
14
+ #
15
+ # * +timeout_in+: the interval to timeout the user session without activity.
16
+ #
17
+ # == Examples
18
+ #
19
+ # user.timedout?(30.minutes.ago)
20
+ #
21
+ module Timeoutable
22
+ extend ActiveSupport::Concern
23
+
24
+ def self.required_fields(klass)
25
+ []
26
+ end
27
+
28
+ # Checks whether the user session has expired based on configured time.
29
+ def timedout?(last_access)
30
+ return false if remember_exists_and_not_expired?
31
+ !timeout_in.nil? && last_access && last_access <= timeout_in.ago
32
+ end
33
+
34
+ def timeout_in
35
+ self.class.timeout_in
36
+ end
37
+
38
+ private
39
+
40
+ def remember_exists_and_not_expired?
41
+ return false unless respond_to?(:remember_created_at)
42
+ remember_created_at && !remember_expired?
43
+ end
44
+
45
+ module ClassMethods
46
+ Devise::Models.config(self, :timeout_in)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,90 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'devise/strategies/token_authenticatable'
3
+
4
+ module Devise
5
+ module Models
6
+ # The TokenAuthenticatable module is responsible for generating an authentication token and
7
+ # validating the authenticity of the same while signing in.
8
+ #
9
+ # This module only provides a few helpers to help you manage the token, but it is up to you
10
+ # to choose how to use it. For example, if you want to have a new token every time the user
11
+ # saves his account, you can do the following:
12
+ #
13
+ # before_save :reset_authentication_token
14
+ #
15
+ # On the other hand, if you want to generate token unless one exists, you should use instead:
16
+ #
17
+ # before_save :ensure_authentication_token
18
+ #
19
+ # If you want to delete the token after it is used, you can do so in the
20
+ # after_token_authentication callback.
21
+ #
22
+ # == APIs
23
+ #
24
+ # If you are using token authentication with APIs and using trackable. Every
25
+ # request will be considered as a new sign in (since there is no session in
26
+ # APIs). You can disable this by creating a before filter as follow:
27
+ #
28
+ # before_filter :skip_trackable
29
+ #
30
+ # def skip_trackable
31
+ # request.env['devise.skip_trackable'] = true
32
+ # end
33
+ #
34
+ # == Options
35
+ #
36
+ # TokenAuthenticatable adds the following options to devise_for:
37
+ #
38
+ # * +token_authentication_key+: Defines name of the authentication token params key. E.g. /users/sign_in?some_key=...
39
+ #
40
+ module TokenAuthenticatable
41
+ extend ActiveSupport::Concern
42
+
43
+ def self.required_fields(klass)
44
+ [:authentication_token]
45
+ end
46
+
47
+ # Generate new authentication token (a.k.a. "single access token").
48
+ def reset_authentication_token
49
+ self.authentication_token = self.class.authentication_token
50
+ end
51
+
52
+ # Generate new authentication token and save the record.
53
+ def reset_authentication_token!
54
+ reset_authentication_token
55
+ save(:validate => false)
56
+ end
57
+
58
+ # Generate authentication token unless already exists.
59
+ def ensure_authentication_token
60
+ reset_authentication_token if authentication_token.blank?
61
+ end
62
+
63
+ # Generate authentication token unless already exists and save the record.
64
+ def ensure_authentication_token!
65
+ reset_authentication_token! if authentication_token.blank?
66
+ end
67
+
68
+ # Hook called after token authentication.
69
+ def after_token_authentication
70
+ end
71
+
72
+ def expire_auth_token_on_timeout
73
+ self.class.expire_auth_token_on_timeout
74
+ end
75
+
76
+ module ClassMethods
77
+ def find_for_token_authentication(conditions)
78
+ find_for_authentication(:authentication_token => conditions[token_authentication_key])
79
+ end
80
+
81
+ # Generate a token checking if one does not already exist in the database.
82
+ def authentication_token
83
+ generate_token(:authentication_token)
84
+ end
85
+
86
+ Devise::Models.config(self, :token_authentication_key, :expire_auth_token_on_timeout)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'devise/hooks/trackable'
3
+
4
+ module Devise
5
+ module Models
6
+ # Track information about your user sign in. It tracks the following columns:
7
+ #
8
+ # * sign_in_count - Increased every time a sign in is made (by form, openid, oauth)
9
+ # * current_sign_in_at - A timestamp updated when the user signs in
10
+ # * last_sign_in_at - Holds the timestamp of the previous sign in
11
+ # * current_sign_in_ip - The remote ip updated when the user sign in
12
+ # * last_sign_in_ip - Holds the remote ip of the previous sign in
13
+ #
14
+ module Trackable
15
+ def self.required_fields(klass)
16
+ [:current_sign_in_at, :current_sign_in_ip, :last_sign_in_at, :last_sign_in_ip, :sign_in_count]
17
+ end
18
+
19
+ def update_tracked_fields!(request)
20
+ old_current, new_current = self.current_sign_in_at, Time.now.utc
21
+ self.last_sign_in_at = old_current || new_current
22
+ self.current_sign_in_at = new_current
23
+
24
+ old_current, new_current = self.current_sign_in_ip, request.remote_ip
25
+ self.last_sign_in_ip = old_current || new_current
26
+ self.current_sign_in_ip = new_current
27
+
28
+ self.sign_in_count ||= 0
29
+ self.sign_in_count += 1
30
+
31
+ save(:validate => false) or raise "Devise trackable could not save #{inspect}." \
32
+ "Please make sure a model using trackable can be saved at sign in."
33
+ end
34
+ end
35
+ end
36
+ end