devise 3.0.0 → 3.1.0

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.

Potentially problematic release.


This version of devise might be problematic. Click here for more details.

Files changed (68) hide show
  1. data/{CHANGELOG.rdoc → CHANGELOG.md} +67 -25
  2. data/Gemfile.lock +13 -12
  3. data/README.md +19 -17
  4. data/app/controllers/devise/confirmations_controller.rb +11 -3
  5. data/app/controllers/devise/registrations_controller.rb +9 -3
  6. data/app/controllers/devise/sessions_controller.rb +1 -1
  7. data/app/mailers/devise/mailer.rb +6 -3
  8. data/app/views/devise/mailer/confirmation_instructions.html.erb +1 -1
  9. data/app/views/devise/mailer/reset_password_instructions.html.erb +1 -1
  10. data/app/views/devise/mailer/unlock_instructions.html.erb +1 -1
  11. data/app/views/devise/shared/_links.erb +2 -2
  12. data/config/locales/en.yml +4 -3
  13. data/devise.gemspec +1 -0
  14. data/gemfiles/Gemfile.rails-3.2.x.lock +47 -44
  15. data/lib/devise/controllers/helpers.rb +1 -0
  16. data/lib/devise/controllers/rememberable.rb +1 -0
  17. data/lib/devise/hooks/csrf_cleaner.rb +5 -0
  18. data/lib/devise/hooks/lockable.rb +1 -1
  19. data/lib/devise/hooks/rememberable.rb +2 -1
  20. data/lib/devise/mailers/helpers.rb +0 -6
  21. data/lib/devise/models/authenticatable.rb +9 -16
  22. data/lib/devise/models/confirmable.rb +34 -43
  23. data/lib/devise/models/lockable.rb +15 -17
  24. data/lib/devise/models/recoverable.rb +21 -27
  25. data/lib/devise/models/rememberable.rb +6 -2
  26. data/lib/devise/models/timeoutable.rb +1 -1
  27. data/lib/devise/models/token_authenticatable.rb +4 -1
  28. data/lib/devise/models.rb +8 -12
  29. data/lib/devise/parameter_sanitizer.rb +49 -19
  30. data/lib/devise/rails/routes.rb +12 -9
  31. data/lib/devise/rails/warden_compat.rb +10 -2
  32. data/lib/devise/rails.rb +7 -11
  33. data/lib/devise/strategies/authenticatable.rb +0 -12
  34. data/lib/devise/token_generator.rb +70 -0
  35. data/lib/devise/version.rb +1 -1
  36. data/lib/devise.rb +23 -12
  37. data/lib/generators/active_record/devise_generator.rb +2 -5
  38. data/lib/generators/active_record/templates/migration.rb +0 -1
  39. data/lib/generators/active_record/templates/migration_existing.rb +0 -1
  40. data/lib/generators/devise/orm_helpers.rb +25 -6
  41. data/lib/generators/mongoid/devise_generator.rb +2 -2
  42. data/lib/generators/templates/devise.rb +21 -9
  43. data/test/controllers/helpers_test.rb +1 -1
  44. data/test/controllers/passwords_controller_test.rb +4 -5
  45. data/test/failure_app_test.rb +1 -1
  46. data/test/generators/active_record_generator_test.rb +31 -1
  47. data/test/integration/authenticatable_test.rb +15 -1
  48. data/test/integration/confirmable_test.rb +29 -42
  49. data/test/integration/http_authenticatable_test.rb +1 -1
  50. data/test/integration/lockable_test.rb +11 -14
  51. data/test/integration/recoverable_test.rb +23 -24
  52. data/test/integration/rememberable_test.rb +15 -13
  53. data/test/mailers/confirmation_instructions_test.rb +6 -2
  54. data/test/mailers/reset_password_instructions_test.rb +6 -2
  55. data/test/mailers/unlock_instructions_test.rb +6 -2
  56. data/test/models/confirmable_test.rb +38 -27
  57. data/test/models/lockable_test.rb +15 -5
  58. data/test/models/recoverable_test.rb +20 -48
  59. data/test/models/rememberable_test.rb +8 -0
  60. data/test/models/timeoutable_test.rb +5 -0
  61. data/test/models_test.rb +0 -19
  62. data/test/parameter_sanitizer_test.rb +23 -9
  63. data/test/rails_app/config/initializers/devise.rb +3 -0
  64. data/test/rails_app/lib/shared_admin.rb +3 -0
  65. data/test/rails_app/lib/shared_user.rb +4 -0
  66. data/test/support/helpers.rb +0 -21
  67. metadata +42 -26
  68. data/app/views/devise/_links.erb +0 -3
@@ -1,21 +1,22 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- devise (3.0.0.rc)
4
+ devise (3.1.0)
5
5
  bcrypt-ruby (~> 3.0)
6
6
  orm_adapter (~> 0.1)
7
7
  railties (>= 3.2.6, < 5)
8
- warden (~> 1.2.1)
8
+ thread_safe (~> 0.1)
9
+ warden (~> 1.2.3)
9
10
 
10
11
  GEM
11
12
  remote: https://rubygems.org/
12
13
  specs:
13
- actionmailer (3.2.13)
14
- actionpack (= 3.2.13)
15
- mail (~> 2.5.3)
16
- actionpack (3.2.13)
17
- activemodel (= 3.2.13)
18
- activesupport (= 3.2.13)
14
+ actionmailer (3.2.14)
15
+ actionpack (= 3.2.14)
16
+ mail (~> 2.5.4)
17
+ actionpack (3.2.14)
18
+ activemodel (= 3.2.14)
19
+ activesupport (= 3.2.14)
19
20
  builder (~> 3.0.0)
20
21
  erubis (~> 2.7.0)
21
22
  journey (~> 1.0.4)
@@ -23,49 +24,49 @@ GEM
23
24
  rack-cache (~> 1.2)
24
25
  rack-test (~> 0.6.1)
25
26
  sprockets (~> 2.2.1)
26
- activemodel (3.2.13)
27
- activesupport (= 3.2.13)
27
+ activemodel (3.2.14)
28
+ activesupport (= 3.2.14)
28
29
  builder (~> 3.0.0)
29
- activerecord (3.2.13)
30
- activemodel (= 3.2.13)
31
- activesupport (= 3.2.13)
30
+ activerecord (3.2.14)
31
+ activemodel (= 3.2.14)
32
+ activesupport (= 3.2.14)
32
33
  arel (~> 3.0.2)
33
34
  tzinfo (~> 0.3.29)
34
- activeresource (3.2.13)
35
- activemodel (= 3.2.13)
36
- activesupport (= 3.2.13)
37
- activesupport (3.2.13)
38
- i18n (= 0.6.1)
35
+ activeresource (3.2.14)
36
+ activemodel (= 3.2.14)
37
+ activesupport (= 3.2.14)
38
+ activesupport (3.2.14)
39
+ i18n (~> 0.6, >= 0.6.4)
39
40
  multi_json (~> 1.0)
40
41
  arel (3.0.2)
41
- bcrypt-ruby (3.0.1)
42
+ atomic (1.1.13)
43
+ bcrypt-ruby (3.1.1)
42
44
  builder (3.0.4)
43
45
  erubis (2.7.0)
44
- faraday (0.8.7)
45
- multipart-post (~> 1.1)
46
+ faraday (0.8.8)
47
+ multipart-post (~> 1.2.0)
46
48
  hashie (1.2.0)
47
- hike (1.2.2)
49
+ hike (1.2.3)
48
50
  httpauth (0.2.0)
49
- i18n (0.6.1)
51
+ i18n (0.6.5)
50
52
  journey (1.0.4)
51
- json (1.7.7)
53
+ json (1.8.0)
52
54
  jwt (0.1.8)
53
55
  multi_json (>= 1.5)
54
- mail (2.5.3)
55
- i18n (>= 0.4.0)
56
+ mail (2.5.4)
56
57
  mime-types (~> 1.16)
57
58
  treetop (~> 1.4.8)
58
59
  metaclass (0.0.1)
59
60
  mime-types (1.23)
60
61
  mocha (0.13.3)
61
62
  metaclass (~> 0.0.1)
62
- mongoid (3.1.3)
63
+ mongoid (3.1.4)
63
64
  activemodel (~> 3.2)
64
- moped (~> 1.4.2)
65
+ moped (~> 1.4)
65
66
  origin (~> 1.0)
66
67
  tzinfo (~> 0.3.22)
67
- moped (1.4.5)
68
- multi_json (1.7.3)
68
+ moped (1.5.1)
69
+ multi_json (1.7.9)
69
70
  multipart-post (1.2.0)
70
71
  nokogiri (1.5.9)
71
72
  oauth2 (0.8.1)
@@ -98,22 +99,22 @@ GEM
98
99
  rack
99
100
  rack-test (0.6.2)
100
101
  rack (>= 1.0)
101
- rails (3.2.13)
102
- actionmailer (= 3.2.13)
103
- actionpack (= 3.2.13)
104
- activerecord (= 3.2.13)
105
- activeresource (= 3.2.13)
106
- activesupport (= 3.2.13)
102
+ rails (3.2.14)
103
+ actionmailer (= 3.2.14)
104
+ actionpack (= 3.2.14)
105
+ activerecord (= 3.2.14)
106
+ activeresource (= 3.2.14)
107
+ activesupport (= 3.2.14)
107
108
  bundler (~> 1.0)
108
- railties (= 3.2.13)
109
- railties (3.2.13)
110
- actionpack (= 3.2.13)
111
- activesupport (= 3.2.13)
109
+ railties (= 3.2.14)
110
+ railties (3.2.14)
111
+ actionpack (= 3.2.14)
112
+ activesupport (= 3.2.14)
112
113
  rack-ssl (~> 1.3.2)
113
114
  rake (>= 0.8.7)
114
115
  rdoc (~> 3.4)
115
116
  thor (>= 0.14.6, < 2.0)
116
- rake (10.0.4)
117
+ rake (10.1.0)
117
118
  rdoc (3.12.2)
118
119
  json (~> 1.4)
119
120
  ruby-openid (2.2.3)
@@ -124,12 +125,14 @@ GEM
124
125
  tilt (~> 1.1, != 1.3.0)
125
126
  sqlite3 (1.3.7)
126
127
  thor (0.18.1)
127
- tilt (1.4.0)
128
- treetop (1.4.12)
128
+ thread_safe (0.1.2)
129
+ atomic
130
+ tilt (1.4.1)
131
+ treetop (1.4.14)
129
132
  polyglot
130
133
  polyglot (>= 0.3.1)
131
134
  tzinfo (0.3.37)
132
- warden (1.2.1)
135
+ warden (1.2.3)
133
136
  rack (>= 1.0)
134
137
  webrat (0.7.3)
135
138
  nokogiri (>= 1.2.0)
@@ -117,6 +117,7 @@ module Devise
117
117
  # sign_in :user, @user # sign_in(scope, resource)
118
118
  # sign_in @user # sign_in(resource)
119
119
  # sign_in @user, :event => :authentication # sign_in(resource, options)
120
+ # sign_in @user, :store => false # sign_in(resource, options)
120
121
  # sign_in @user, :bypass => true # sign_in(resource, options)
121
122
  #
122
123
  def sign_in(resource_or_scope, *args)
@@ -21,6 +21,7 @@ module Devise
21
21
 
22
22
  # Remembers the given resource by setting up a cookie
23
23
  def remember_me(resource)
24
+ return if env["devise.skip_storage"]
24
25
  scope = Devise::Mapping.find_scope!(resource)
25
26
  resource.remember_me!(resource.extend_remember_period)
26
27
  cookies.signed[remember_key(resource, scope)] = remember_cookie_values(resource)
@@ -0,0 +1,5 @@
1
+ Warden::Manager.after_authentication do |record, warden, options|
2
+ if Devise.clean_up_csrf_token_on_authentication
3
+ warden.request.session.try(:delete, :_csrf_token)
4
+ end
5
+ end
@@ -2,6 +2,6 @@
2
2
  # This is only triggered when the user is explicitly set (with set_user)
3
3
  Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
4
4
  if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
5
- record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.zero?
5
+ record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.to_i.zero?
6
6
  end
7
7
  end
@@ -1,6 +1,7 @@
1
1
  Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
2
2
  scope = options[:scope]
3
- if record.respond_to?(:remember_me) && record.remember_me && warden.authenticated?(scope)
3
+ if record.respond_to?(:remember_me) && options[:store] != false &&
4
+ record.remember_me && warden.authenticated?(scope)
4
5
  Devise::Controllers::Rememberable::Proxy.new(warden).remember_me(record)
5
6
  end
6
7
  end
@@ -35,12 +35,6 @@ module Devise
35
35
  :template_name => action
36
36
  }.merge(opts)
37
37
 
38
- if resource.respond_to?(:headers_for)
39
- ActiveSupport::Deprecation.warn "Calling headers_for in the model is no longer supported. " <<
40
- "Please customize your mailer instead."
41
- headers.merge!(resource.headers_for(action))
42
- end
43
-
44
38
  @email = headers[:to]
45
39
  headers
46
40
  end
@@ -1,4 +1,5 @@
1
1
  require 'devise/hooks/activatable'
2
+ require 'devise/hooks/csrf_cleaner'
2
3
 
3
4
  module Devise
4
5
  module Models
@@ -143,20 +144,20 @@ module Devise
143
144
  #
144
145
  # protected
145
146
  #
146
- # def send_devise_notification(notification, opts = {})
147
- # # if the record is new or changed then delay the
147
+ # def send_devise_notification(notification, *args)
148
+ # # If the record is new or changed then delay the
148
149
  # # delivery until the after_commit callback otherwise
149
150
  # # send now because after_commit will not be called.
150
151
  # if new_record? || changed?
151
- # pending_notifications << [notification, opts]
152
+ # pending_notifications << [notification, args]
152
153
  # else
153
- # devise_mailer.send(notification, self, opts).deliver
154
+ # devise_mailer.send(notification, self, *args).deliver
154
155
  # end
155
156
  # end
156
157
  #
157
158
  # def send_pending_notifications
158
- # pending_notifications.each do |n, opts|
159
- # devise_mailer.send(n, self, opts).deliver
159
+ # pending_notifications.each do |notification, args|
160
+ # devise_mailer.send(notification, self, *args).deliver
160
161
  # end
161
162
  #
162
163
  # # Empty the pending notifications array because the
@@ -170,8 +171,8 @@ module Devise
170
171
  # end
171
172
  # end
172
173
  #
173
- def send_devise_notification(notification, opts={})
174
- devise_mailer.send(notification, self, opts).deliver
174
+ def send_devise_notification(notification, *args)
175
+ devise_mailer.send(notification, self, *args).deliver
175
176
  end
176
177
 
177
178
  def downcase_keys
@@ -278,14 +279,6 @@ module Devise
278
279
  def devise_parameter_filter
279
280
  @devise_parameter_filter ||= Devise::ParameterFilter.new(case_insensitive_keys, strip_whitespace_keys)
280
281
  end
281
-
282
- # Generate a token by looping and ensuring does not already exist.
283
- def generate_token(column)
284
- loop do
285
- token = Devise.friendly_token
286
- break token unless to_adapter.find_first({ column => token })
287
- end
288
- end
289
282
  end
290
283
  end
291
284
  end
@@ -7,7 +7,7 @@ module Devise
7
7
  #
8
8
  # == Options
9
9
  #
10
- # Confirmable adds the following options to devise_for:
10
+ # Confirmable adds the following options to +devise+:
11
11
  #
12
12
  # * +allow_unconfirmed_access_for+: the time you want to allow the user to access his account
13
13
  # before confirming it. After this period, the user access is denied. You can
@@ -40,9 +40,10 @@ module Devise
40
40
  end
41
41
 
42
42
  def initialize(*args, &block)
43
- @bypass_postpone = false
43
+ @bypass_confirmation_postpone = false
44
44
  @reconfirmation_required = false
45
45
  @skip_confirmation_notification = false
46
+ @raw_confirmation_token = nil
46
47
  super
47
48
  end
48
49
 
@@ -66,7 +67,7 @@ module Devise
66
67
  self.confirmation_token = nil
67
68
  self.confirmed_at = Time.now.utc
68
69
 
69
- if self.class.reconfirmable && unconfirmed_email.present?
70
+ saved = if self.class.reconfirmable && unconfirmed_email.present?
70
71
  skip_reconfirmation!
71
72
  self.email = unconfirmed_email
72
73
  self.unconfirmed_email = nil
@@ -76,6 +77,9 @@ module Devise
76
77
  else
77
78
  save(:validate => false)
78
79
  end
80
+
81
+ after_confirmation if saved
82
+ saved
79
83
  end
80
84
  end
81
85
 
@@ -90,10 +94,12 @@ module Devise
90
94
 
91
95
  # Send confirmation instructions by email
92
96
  def send_confirmation_instructions
93
- ensure_confirmation_token!
97
+ unless @raw_confirmation_token
98
+ generate_confirmation_token!
99
+ end
94
100
 
95
101
  opts = pending_reconfirmation? ? { :to => unconfirmed_email } : { }
96
- send_devise_notification(:confirmation_instructions, opts)
102
+ send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
97
103
  end
98
104
 
99
105
  def send_reconfirmation_instructions
@@ -106,17 +112,11 @@ module Devise
106
112
 
107
113
  # Resend confirmation token.
108
114
  # Regenerates the token if the period is expired.
109
- def resend_confirmation_token
115
+ def resend_confirmation_instructions
110
116
  pending_any_confirmation do
111
- regenerate_confirmation_token! if confirmation_period_expired?
112
117
  send_confirmation_instructions
113
118
  end
114
119
  end
115
-
116
- # Generate a confirmation token unless already exists and save the record.
117
- def ensure_confirmation_token!
118
- generate_confirmation_token! if should_generate_confirmation_token?
119
- end
120
120
 
121
121
  # Overwrites active_for_authentication? for confirmation
122
122
  # by verifying whether a user is active to sign in or not. If the user
@@ -146,19 +146,16 @@ module Devise
146
146
  # If you don't want reconfirmation to be sent, neither a code
147
147
  # to be generated, call skip_reconfirmation!
148
148
  def skip_reconfirmation!
149
- @bypass_postpone = true
149
+ @bypass_confirmation_postpone = true
150
150
  end
151
151
 
152
152
  protected
153
- def should_generate_confirmation_token?
154
- confirmation_token.nil? || confirmation_period_expired?
155
- end
156
153
 
157
154
  # A callback method used to deliver confirmation
158
155
  # instructions on creation. This can be overriden
159
156
  # in models to map to a nice sign up e-mail.
160
157
  def send_on_create_confirmation_instructions
161
- send_devise_notification(:confirmation_instructions)
158
+ send_confirmation_instructions
162
159
  end
163
160
 
164
161
  # Callback to overwrite if confirmation is required or not.
@@ -218,10 +215,12 @@ module Devise
218
215
  end
219
216
  end
220
217
 
221
- # Generates a new random token for confirmation, and stores the time
222
- # this token is being generated
218
+ # Generates a new random token for confirmation, and stores
219
+ # the time this token is being generated
223
220
  def generate_confirmation_token
224
- self.confirmation_token = self.class.confirmation_token
221
+ raw, enc = Devise.token_generator.generate(self.class, :confirmation_token)
222
+ @raw_confirmation_token = raw
223
+ self.confirmation_token = enc
225
224
  self.confirmation_sent_at = Time.now.utc
226
225
  end
227
226
 
@@ -229,30 +228,16 @@ module Devise
229
228
  generate_confirmation_token && save(:validate => false)
230
229
  end
231
230
 
232
- # Regenerates a new token.
233
- def regenerate_confirmation_token
234
- generate_confirmation_token
235
- end
236
-
237
- def regenerate_confirmation_token!
238
- regenerate_confirmation_token && save(:validate => false)
239
- end
240
-
241
- def after_password_reset
242
- super
243
- confirm! unless confirmed?
244
- end
245
-
246
231
  def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
247
232
  @reconfirmation_required = true
248
233
  self.unconfirmed_email = self.email
249
234
  self.email = self.email_was
250
- regenerate_confirmation_token
235
+ generate_confirmation_token
251
236
  end
252
237
 
253
238
  def postpone_email_change?
254
- postpone = self.class.reconfirmable && email_changed? && !@bypass_postpone && !self.email.blank?
255
- @bypass_postpone = false
239
+ postpone = self.class.reconfirmable && email_changed? && !@bypass_confirmation_postpone && !self.email.blank?
240
+ @bypass_confirmation_postpone = false
256
241
  postpone
257
242
  end
258
243
 
@@ -264,6 +249,9 @@ module Devise
264
249
  confirmation_required? && !@skip_confirmation_notification && !self.email.blank?
265
250
  end
266
251
 
252
+ def after_confirmation
253
+ end
254
+
267
255
  module ClassMethods
268
256
  # Attempt to find a user by its email. If a record is found, send new
269
257
  # confirmation instructions to it. If not, try searching for a user by unconfirmed_email
@@ -274,7 +262,7 @@ module Devise
274
262
  unless confirmable.try(:persisted?)
275
263
  confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
276
264
  end
277
- confirmable.resend_confirmation_token if confirmable.persisted?
265
+ confirmable.resend_confirmation_instructions if confirmable.persisted?
278
266
  confirmable
279
267
  end
280
268
 
@@ -283,16 +271,19 @@ module Devise
283
271
  # If the user is already confirmed, create an error for the user
284
272
  # Options must have the confirmation_token
285
273
  def confirm_by_token(confirmation_token)
274
+ original_token = confirmation_token
275
+ confirmation_token = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
276
+
286
277
  confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
278
+ if !confirmable.persisted? && Devise.allow_insecure_token_lookup
279
+ confirmable = find_or_initialize_with_error_by(:confirmation_token, original_token)
280
+ end
281
+
287
282
  confirmable.confirm! if confirmable.persisted?
283
+ confirmable.confirmation_token = original_token
288
284
  confirmable
289
285
  end
290
286
 
291
- # Generate a token checking if one does not already exist in the database.
292
- def confirmation_token
293
- generate_token(:confirmation_token)
294
- end
295
-
296
287
  # Find a record for confirmation by unconfirmed email field
297
288
  def find_by_unconfirmed_email_with_errors(attributes = {})
298
289
  unconfirmed_required_attributes = confirmation_keys.map { |k| k == :email ? :unconfirmed_email : k }
@@ -38,7 +38,6 @@ module Devise
38
38
  self.locked_at = Time.now.utc
39
39
 
40
40
  if unlock_strategy_enabled?(:email)
41
- generate_unlock_token!
42
41
  send_unlock_instructions
43
42
  else
44
43
  save(:validate => false)
@@ -60,11 +59,15 @@ module Devise
60
59
 
61
60
  # Send unlock instructions by email
62
61
  def send_unlock_instructions
63
- send_devise_notification(:unlock_instructions)
62
+ raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
63
+ self.unlock_token = enc
64
+ self.save(:validate => false)
65
+ send_devise_notification(:unlock_instructions, raw, {})
66
+ raw
64
67
  end
65
68
 
66
69
  # Resend the unlock instructions if the user is locked.
67
- def resend_unlock_token
70
+ def resend_unlock_instructions
68
71
  if_access_locked { send_unlock_instructions }
69
72
  end
70
73
 
@@ -122,15 +125,6 @@ module Devise
122
125
  self.failed_attempts > self.class.maximum_attempts
123
126
  end
124
127
 
125
- # Generates unlock token
126
- def generate_unlock_token
127
- self.unlock_token = self.class.unlock_token
128
- end
129
-
130
- def generate_unlock_token!
131
- generate_unlock_token && save(:validate => false)
132
- end
133
-
134
128
  # Tells if the lock is expired if :time unlock strategy is active
135
129
  def lock_expired?
136
130
  if unlock_strategy_enabled?(:time)
@@ -158,7 +152,7 @@ module Devise
158
152
  # Options must contain the user's unlock keys
159
153
  def send_unlock_instructions(attributes={})
160
154
  lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
161
- lockable.resend_unlock_token if lockable.persisted?
155
+ lockable.resend_unlock_instructions if lockable.persisted?
162
156
  lockable
163
157
  end
164
158
 
@@ -167,8 +161,16 @@ module Devise
167
161
  # If the user is not locked, creates an error for the user
168
162
  # Options must have the unlock_token
169
163
  def unlock_access_by_token(unlock_token)
164
+ original_token = unlock_token
165
+ unlock_token = Devise.token_generator.digest(self, :unlock_token, unlock_token)
166
+
170
167
  lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
168
+ if !lockable.persisted? && Devise.allow_insecure_token_lookup
169
+ lockable = find_or_initialize_with_error_by(:unlock_token, original_token)
170
+ end
171
+
171
172
  lockable.unlock_access! if lockable.persisted?
173
+ lockable.unlock_token = original_token
172
174
  lockable
173
175
  end
174
176
 
@@ -182,10 +184,6 @@ module Devise
182
184
  self.lock_strategy == strategy
183
185
  end
184
186
 
185
- def unlock_token
186
- Devise.friendly_token
187
- end
188
-
189
187
  Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in, :unlock_keys)
190
188
  end
191
189
  end
@@ -42,17 +42,19 @@ module Devise
42
42
  save
43
43
  end
44
44
 
45
- # Resets reset password token and send reset password instructions by email
45
+ # Resets reset password token and send reset password instructions by email.
46
+ # Returns the token sent in the e-mail.
46
47
  def send_reset_password_instructions
47
- ensure_reset_password_token!
48
- send_devise_notification(:reset_password_instructions)
48
+ raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
49
+
50
+ self.reset_password_token = enc
51
+ self.reset_password_sent_at = Time.now.utc
52
+ self.save(:validate => false)
53
+
54
+ send_devise_notification(:reset_password_instructions, raw, {})
55
+ raw
49
56
  end
50
-
51
- # Generate reset password token unless already exists and save the record.
52
- def ensure_reset_password_token!
53
- generate_reset_password_token! if should_generate_reset_token?
54
- end
55
-
57
+
56
58
  # Checks if the reset password token sent is within the limit time.
57
59
  # We do this by calculating if the difference between today and the
58
60
  # sending date does not exceed the confirm in time configured.
@@ -79,23 +81,6 @@ module Devise
79
81
 
80
82
  protected
81
83
 
82
- def should_generate_reset_token?
83
- reset_password_token.nil? || !reset_password_period_valid?
84
- end
85
-
86
- # Generates a new random token for reset password
87
- def generate_reset_password_token
88
- self.reset_password_token = self.class.reset_password_token
89
- self.reset_password_sent_at = Time.now.utc
90
- self.reset_password_token
91
- end
92
-
93
- # Resets the reset password token with and save the record without
94
- # validating
95
- def generate_reset_password_token!
96
- generate_reset_password_token && save(:validate => false)
97
- end
98
-
99
84
  # Removes reset_password token
100
85
  def clear_reset_password_token
101
86
  self.reset_password_token = nil
@@ -127,7 +112,14 @@ module Devise
127
112
  # containing an error in reset_password_token attribute.
128
113
  # Attributes must contain reset_password_token, password and confirmation
129
114
  def reset_password_by_token(attributes={})
130
- recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
115
+ original_token = attributes[:reset_password_token]
116
+ reset_password_token = Devise.token_generator.digest(self, :reset_password_token, original_token)
117
+
118
+ recoverable = find_or_initialize_with_error_by(:reset_password_token, reset_password_token)
119
+ if !recoverable.persisted? && Devise.allow_insecure_token_lookup
120
+ recoverable = find_or_initialize_with_error_by(:reset_password_token, original_token)
121
+ end
122
+
131
123
  if recoverable.persisted?
132
124
  if recoverable.reset_password_period_valid?
133
125
  recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
@@ -135,6 +127,8 @@ module Devise
135
127
  recoverable.errors.add(:reset_password_token, :expired)
136
128
  end
137
129
  end
130
+
131
+ recoverable.reset_password_token = original_token
138
132
  recoverable
139
133
  end
140
134
 
@@ -110,12 +110,16 @@ module Devise
110
110
  # Recreate the user based on the stored cookie
111
111
  def serialize_from_cookie(id, remember_token)
112
112
  record = to_adapter.get(id)
113
- record if record && record.rememberable_value == remember_token && !record.remember_expired?
113
+ record if record && !record.remember_expired? &&
114
+ Devise.secure_compare(record.rememberable_value, remember_token)
114
115
  end
115
116
 
116
117
  # Generate a token checking if one does not already exist in the database.
117
118
  def remember_token #:nodoc:
118
- generate_token(:remember_token)
119
+ loop do
120
+ token = Devise.friendly_token
121
+ break token unless to_adapter.find_first({ :remember_token => token })
122
+ end
119
123
  end
120
124
 
121
125
  Devise::Models.config(self, :remember_for, :extend_remember_period, :rememberable_options)
@@ -37,7 +37,7 @@ module Devise
37
37
  private
38
38
 
39
39
  def remember_exists_and_not_expired?
40
- return false unless respond_to?(:remember_created_at)
40
+ return false unless respond_to?(:remember_created_at) && respond_to?(:remember_expired?)
41
41
  remember_created_at && !remember_expired?
42
42
  end
43
43
 
@@ -79,7 +79,10 @@ module Devise
79
79
 
80
80
  # Generate a token checking if one does not already exist in the database.
81
81
  def authentication_token
82
- generate_token(:authentication_token)
82
+ loop do
83
+ token = Devise.friendly_token
84
+ break token unless to_adapter.find_first({ :authentication_token => token })
85
+ end
83
86
  end
84
87
 
85
88
  Devise::Models.config(self, :token_authentication_key, :expire_auth_token_on_timeout)