devise 3.5.10 → 4.7.1
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +256 -1135
- data/MIT-LICENSE +1 -1
- data/README.md +254 -67
- data/app/controllers/devise/confirmations_controller.rb +3 -1
- data/app/controllers/devise/omniauth_callbacks_controller.rb +8 -6
- data/app/controllers/devise/passwords_controller.rb +7 -4
- data/app/controllers/devise/registrations_controller.rb +39 -18
- data/app/controllers/devise/sessions_controller.rb +9 -7
- data/app/controllers/devise/unlocks_controller.rb +4 -2
- data/app/controllers/devise_controller.rb +23 -10
- data/app/helpers/devise_helper.rb +12 -19
- data/app/mailers/devise/mailer.rb +6 -0
- data/app/views/devise/confirmations/new.html.erb +2 -2
- data/app/views/devise/mailer/email_changed.html.erb +7 -0
- data/app/views/devise/passwords/edit.html.erb +3 -3
- data/app/views/devise/passwords/new.html.erb +2 -2
- data/app/views/devise/registrations/edit.html.erb +9 -5
- data/app/views/devise/registrations/new.html.erb +4 -4
- data/app/views/devise/sessions/new.html.erb +4 -4
- data/app/views/devise/shared/_error_messages.html.erb +15 -0
- data/app/views/devise/shared/_links.html.erb +7 -7
- data/app/views/devise/unlocks/new.html.erb +2 -2
- data/config/locales/en.yml +4 -1
- data/lib/devise/controllers/helpers.rb +23 -20
- data/lib/devise/controllers/rememberable.rb +3 -1
- data/lib/devise/controllers/scoped_views.rb +2 -0
- data/lib/devise/controllers/sign_in_out.rb +34 -11
- data/lib/devise/controllers/store_location.rb +25 -7
- data/lib/devise/controllers/url_helpers.rb +2 -0
- data/lib/devise/delegator.rb +2 -0
- data/lib/devise/encryptor.rb +6 -4
- data/lib/devise/failure_app.rb +75 -37
- data/lib/devise/hooks/activatable.rb +2 -0
- data/lib/devise/hooks/csrf_cleaner.rb +2 -0
- data/lib/devise/hooks/forgetable.rb +2 -0
- data/lib/devise/hooks/lockable.rb +6 -1
- data/lib/devise/hooks/proxy.rb +3 -1
- data/lib/devise/hooks/rememberable.rb +2 -0
- data/lib/devise/hooks/timeoutable.rb +2 -0
- data/lib/devise/hooks/trackable.rb +2 -0
- data/lib/devise/mailers/helpers.rb +7 -4
- data/lib/devise/mapping.rb +2 -0
- data/lib/devise/models/authenticatable.rb +51 -26
- data/lib/devise/models/confirmable.rb +88 -27
- data/lib/devise/models/database_authenticatable.rb +88 -21
- data/lib/devise/models/lockable.rb +10 -4
- data/lib/devise/models/omniauthable.rb +2 -0
- data/lib/devise/models/recoverable.rb +31 -19
- data/lib/devise/models/registerable.rb +4 -0
- data/lib/devise/models/rememberable.rb +5 -10
- data/lib/devise/models/timeoutable.rb +2 -0
- data/lib/devise/models/trackable.rb +15 -1
- data/lib/devise/models/validatable.rb +10 -3
- data/lib/devise/models.rb +3 -1
- data/lib/devise/modules.rb +2 -0
- data/lib/devise/omniauth/config.rb +2 -0
- data/lib/devise/omniauth/url_helpers.rb +14 -5
- data/lib/devise/omniauth.rb +2 -0
- data/lib/devise/orm/active_record.rb +5 -1
- data/lib/devise/orm/mongoid.rb +6 -2
- data/lib/devise/parameter_filter.rb +4 -0
- data/lib/devise/parameter_sanitizer.rb +139 -65
- data/lib/devise/rails/routes.rb +44 -33
- data/lib/devise/rails/warden_compat.rb +3 -10
- data/lib/devise/rails.rb +7 -16
- data/lib/devise/secret_key_finder.rb +27 -0
- data/lib/devise/strategies/authenticatable.rb +3 -1
- data/lib/devise/strategies/base.rb +2 -0
- data/lib/devise/strategies/database_authenticatable.rb +11 -4
- data/lib/devise/strategies/rememberable.rb +2 -0
- data/lib/devise/test/controller_helpers.rb +165 -0
- data/lib/devise/test/integration_helpers.rb +63 -0
- data/lib/devise/test_helpers.rb +7 -124
- data/lib/devise/time_inflector.rb +2 -0
- data/lib/devise/token_generator.rb +3 -41
- data/lib/devise/version.rb +3 -1
- data/lib/devise.rb +61 -40
- data/lib/generators/active_record/devise_generator.rb +29 -10
- data/lib/generators/active_record/templates/migration.rb +4 -2
- data/lib/generators/active_record/templates/migration_existing.rb +4 -2
- data/lib/generators/devise/controllers_generator.rb +3 -1
- data/lib/generators/devise/devise_generator.rb +4 -2
- data/lib/generators/devise/install_generator.rb +17 -0
- data/lib/generators/devise/orm_helpers.rb +10 -21
- data/lib/generators/devise/views_generator.rb +7 -8
- data/lib/generators/mongoid/devise_generator.rb +7 -5
- data/lib/generators/templates/README +1 -8
- data/lib/generators/templates/controllers/confirmations_controller.rb +2 -0
- data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +2 -0
- data/lib/generators/templates/controllers/passwords_controller.rb +2 -0
- data/lib/generators/templates/controllers/registrations_controller.rb +6 -4
- data/lib/generators/templates/controllers/sessions_controller.rb +4 -2
- data/lib/generators/templates/controllers/unlocks_controller.rb +2 -0
- data/lib/generators/templates/devise.rb +50 -20
- data/lib/generators/templates/markerb/email_changed.markerb +7 -0
- data/lib/generators/templates/markerb/password_change.markerb +2 -2
- data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +5 -1
- data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +10 -2
- data/lib/generators/templates/simple_form_for/passwords/new.html.erb +4 -1
- data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +11 -3
- data/lib/generators/templates/simple_form_for/registrations/new.html.erb +11 -3
- data/lib/generators/templates/simple_form_for/sessions/new.html.erb +7 -2
- data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +4 -1
- metadata +13 -312
- data/.gitignore +0 -10
- data/.travis.yml +0 -44
- data/.yardopts +0 -9
- data/CODE_OF_CONDUCT.md +0 -22
- data/CONTRIBUTING.md +0 -16
- data/Gemfile +0 -30
- data/Gemfile.lock +0 -187
- data/Rakefile +0 -36
- data/devise.gemspec +0 -27
- data/devise.png +0 -0
- data/gemfiles/Gemfile.rails-3.2-stable +0 -29
- data/gemfiles/Gemfile.rails-3.2-stable.lock +0 -172
- data/gemfiles/Gemfile.rails-4.0-stable +0 -30
- data/gemfiles/Gemfile.rails-4.0-stable.lock +0 -166
- data/gemfiles/Gemfile.rails-4.1-stable +0 -30
- data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
- data/gemfiles/Gemfile.rails-4.2-stable +0 -30
- data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -193
- data/script/cached-bundle +0 -49
- data/script/s3-put +0 -71
- data/test/controllers/custom_registrations_controller_test.rb +0 -40
- data/test/controllers/custom_strategy_test.rb +0 -62
- data/test/controllers/helper_methods_test.rb +0 -21
- data/test/controllers/helpers_test.rb +0 -316
- data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -51
- data/test/controllers/internal_helpers_test.rb +0 -129
- data/test/controllers/load_hooks_controller_test.rb +0 -19
- data/test/controllers/passwords_controller_test.rb +0 -31
- data/test/controllers/sessions_controller_test.rb +0 -103
- data/test/controllers/url_helpers_test.rb +0 -65
- data/test/delegator_test.rb +0 -19
- data/test/devise_test.rb +0 -107
- data/test/failure_app_test.rb +0 -315
- data/test/generators/active_record_generator_test.rb +0 -109
- data/test/generators/controllers_generator_test.rb +0 -48
- data/test/generators/devise_generator_test.rb +0 -39
- data/test/generators/install_generator_test.rb +0 -13
- data/test/generators/mongoid_generator_test.rb +0 -23
- data/test/generators/views_generator_test.rb +0 -103
- data/test/helpers/devise_helper_test.rb +0 -49
- data/test/integration/authenticatable_test.rb +0 -729
- data/test/integration/confirmable_test.rb +0 -324
- data/test/integration/database_authenticatable_test.rb +0 -95
- data/test/integration/http_authenticatable_test.rb +0 -105
- data/test/integration/lockable_test.rb +0 -239
- data/test/integration/omniauthable_test.rb +0 -135
- data/test/integration/recoverable_test.rb +0 -347
- data/test/integration/registerable_test.rb +0 -359
- data/test/integration/rememberable_test.rb +0 -214
- data/test/integration/timeoutable_test.rb +0 -184
- data/test/integration/trackable_test.rb +0 -92
- data/test/mailers/confirmation_instructions_test.rb +0 -115
- data/test/mailers/reset_password_instructions_test.rb +0 -96
- data/test/mailers/unlock_instructions_test.rb +0 -91
- data/test/mapping_test.rb +0 -134
- data/test/models/authenticatable_test.rb +0 -23
- data/test/models/confirmable_test.rb +0 -511
- data/test/models/database_authenticatable_test.rb +0 -269
- data/test/models/lockable_test.rb +0 -350
- data/test/models/omniauthable_test.rb +0 -7
- data/test/models/recoverable_test.rb +0 -251
- data/test/models/registerable_test.rb +0 -7
- data/test/models/rememberable_test.rb +0 -169
- data/test/models/serializable_test.rb +0 -49
- data/test/models/timeoutable_test.rb +0 -51
- data/test/models/trackable_test.rb +0 -41
- data/test/models/validatable_test.rb +0 -127
- data/test/models_test.rb +0 -153
- data/test/omniauth/config_test.rb +0 -57
- data/test/omniauth/url_helpers_test.rb +0 -54
- data/test/orm/active_record.rb +0 -10
- data/test/orm/mongoid.rb +0 -13
- data/test/parameter_sanitizer_test.rb +0 -81
- data/test/rails_app/Rakefile +0 -6
- data/test/rails_app/app/active_record/admin.rb +0 -6
- data/test/rails_app/app/active_record/shim.rb +0 -2
- data/test/rails_app/app/active_record/user.rb +0 -6
- data/test/rails_app/app/active_record/user_on_engine.rb +0 -7
- data/test/rails_app/app/active_record/user_on_main_app.rb +0 -7
- data/test/rails_app/app/active_record/user_without_email.rb +0 -8
- data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
- data/test/rails_app/app/controllers/admins_controller.rb +0 -6
- data/test/rails_app/app/controllers/application_controller.rb +0 -12
- data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -30
- data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -31
- data/test/rails_app/app/controllers/home_controller.rb +0 -25
- data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
- data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
- data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
- data/test/rails_app/app/controllers/users_controller.rb +0 -31
- data/test/rails_app/app/helpers/application_helper.rb +0 -3
- data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -3
- data/test/rails_app/app/mailers/users/mailer.rb +0 -3
- data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -4
- data/test/rails_app/app/mongoid/admin.rb +0 -29
- data/test/rails_app/app/mongoid/shim.rb +0 -23
- data/test/rails_app/app/mongoid/user.rb +0 -39
- data/test/rails_app/app/mongoid/user_on_engine.rb +0 -39
- data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -39
- data/test/rails_app/app/mongoid/user_without_email.rb +0 -33
- data/test/rails_app/app/views/admins/index.html.erb +0 -1
- data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
- data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
- data/test/rails_app/app/views/home/index.html.erb +0 -1
- data/test/rails_app/app/views/home/join.html.erb +0 -1
- data/test/rails_app/app/views/home/private.html.erb +0 -1
- data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
- data/test/rails_app/app/views/layouts/application.html.erb +0 -24
- data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
- data/test/rails_app/app/views/users/index.html.erb +0 -1
- data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
- data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
- data/test/rails_app/bin/bundle +0 -3
- data/test/rails_app/bin/rails +0 -4
- data/test/rails_app/bin/rake +0 -4
- data/test/rails_app/config/application.rb +0 -40
- data/test/rails_app/config/boot.rb +0 -14
- data/test/rails_app/config/database.yml +0 -18
- data/test/rails_app/config/environment.rb +0 -5
- data/test/rails_app/config/environments/development.rb +0 -30
- data/test/rails_app/config/environments/production.rb +0 -84
- data/test/rails_app/config/environments/test.rb +0 -41
- data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
- data/test/rails_app/config/initializers/devise.rb +0 -180
- data/test/rails_app/config/initializers/inflections.rb +0 -2
- data/test/rails_app/config/initializers/secret_token.rb +0 -8
- data/test/rails_app/config/initializers/session_store.rb +0 -1
- data/test/rails_app/config/routes.rb +0 -125
- data/test/rails_app/config.ru +0 -4
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -71
- data/test/rails_app/db/schema.rb +0 -55
- data/test/rails_app/lib/shared_admin.rb +0 -17
- data/test/rails_app/lib/shared_user.rb +0 -29
- data/test/rails_app/lib/shared_user_without_email.rb +0 -26
- data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -13
- data/test/rails_app/public/404.html +0 -26
- data/test/rails_app/public/422.html +0 -26
- data/test/rails_app/public/500.html +0 -26
- data/test/rails_app/public/favicon.ico +0 -0
- data/test/rails_test.rb +0 -9
- data/test/routes_test.rb +0 -264
- data/test/support/action_controller/record_identifier.rb +0 -10
- data/test/support/assertions.rb +0 -39
- data/test/support/helpers.rb +0 -77
- data/test/support/integration.rb +0 -92
- data/test/support/locale/en.yml +0 -8
- data/test/support/mongoid.yml +0 -6
- data/test/support/webrat/integrations/rails.rb +0 -24
- data/test/test_helper.rb +0 -34
- data/test/test_helpers_test.rb +0 -178
- data/test/test_models.rb +0 -33
- data/test/time_helpers.rb +0 -137
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Devise
|
2
4
|
module Models
|
3
5
|
# Confirmable is responsible to verify if an account is already confirmed to
|
@@ -24,9 +26,11 @@ module Devise
|
|
24
26
|
# By default allow_unconfirmed_access_for is zero, it means users always have to confirm to sign in.
|
25
27
|
# * +reconfirmable+: requires any email changes to be confirmed (exactly the same way as
|
26
28
|
# initial account confirmation) to be applied. Requires additional unconfirmed_email
|
27
|
-
# db field to be
|
29
|
+
# db field to be set up (t.reconfirmable in migrations). Until confirmed, new email is
|
28
30
|
# stored in unconfirmed email column, and copied to email column on successful
|
29
|
-
# confirmation.
|
31
|
+
# confirmation. Also, when used in conjunction with `send_email_changed_notification`,
|
32
|
+
# the notification is sent to the original email when the change is requested,
|
33
|
+
# not when the unconfirmed email is confirmed.
|
30
34
|
# * +confirm_within+: the time before a sent confirmation token becomes invalid.
|
31
35
|
# You can use this to force the user to confirm within a set period of time.
|
32
36
|
# Confirmable will not generate a new token if a repeat confirmation is requested
|
@@ -40,17 +44,23 @@ module Devise
|
|
40
44
|
#
|
41
45
|
module Confirmable
|
42
46
|
extend ActiveSupport::Concern
|
43
|
-
include ActionView::Helpers::DateHelper
|
44
47
|
|
45
48
|
included do
|
46
49
|
before_create :generate_confirmation_token, if: :confirmation_required?
|
47
|
-
after_create
|
50
|
+
after_create :skip_reconfirmation_in_callback!, if: :send_confirmation_notification?
|
51
|
+
if defined?(ActiveRecord) && self < ActiveRecord::Base # ActiveRecord
|
52
|
+
after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
|
53
|
+
after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
|
54
|
+
else # Mongoid
|
55
|
+
after_create :send_on_create_confirmation_instructions, if: :send_confirmation_notification?
|
56
|
+
after_update :send_reconfirmation_instructions, if: :reconfirmation_required?
|
57
|
+
end
|
48
58
|
before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, if: :postpone_email_change?
|
49
|
-
after_update :send_reconfirmation_instructions, if: :reconfirmation_required?
|
50
59
|
end
|
51
60
|
|
52
61
|
def initialize(*args, &block)
|
53
62
|
@bypass_confirmation_postpone = false
|
63
|
+
@skip_reconfirmation_in_callback = false
|
54
64
|
@reconfirmation_required = false
|
55
65
|
@skip_confirmation_notification = false
|
56
66
|
@raw_confirmation_token = nil
|
@@ -76,7 +86,7 @@ module Devise
|
|
76
86
|
|
77
87
|
self.confirmed_at = Time.now.utc
|
78
88
|
|
79
|
-
saved = if
|
89
|
+
saved = if pending_reconfirmation?
|
80
90
|
skip_reconfirmation!
|
81
91
|
self.email = unconfirmed_email
|
82
92
|
self.unconfirmed_email = nil
|
@@ -92,11 +102,6 @@ module Devise
|
|
92
102
|
end
|
93
103
|
end
|
94
104
|
|
95
|
-
def confirm!(args={})
|
96
|
-
ActiveSupport::Deprecation.warn "confirm! is deprecated in favor of confirm"
|
97
|
-
confirm(args)
|
98
|
-
end
|
99
|
-
|
100
105
|
# Verifies whether a user is confirmed or not
|
101
106
|
def confirmed?
|
102
107
|
!!confirmed_at
|
@@ -165,12 +170,17 @@ module Devise
|
|
165
170
|
|
166
171
|
protected
|
167
172
|
|
173
|
+
# To not require reconfirmation after creating with #save called in a
|
174
|
+
# callback call skip_create_confirmation!
|
175
|
+
def skip_reconfirmation_in_callback!
|
176
|
+
@skip_reconfirmation_in_callback = true
|
177
|
+
end
|
178
|
+
|
168
179
|
# A callback method used to deliver confirmation
|
169
180
|
# instructions on creation. This can be overridden
|
170
181
|
# in models to map to a nice sign up e-mail.
|
171
182
|
def send_on_create_confirmation_instructions
|
172
183
|
send_confirmation_instructions
|
173
|
-
skip_reconfirmation!
|
174
184
|
end
|
175
185
|
|
176
186
|
# Callback to overwrite if confirmation is required or not.
|
@@ -181,7 +191,7 @@ module Devise
|
|
181
191
|
# Checks if the confirmation for the user is within the limit time.
|
182
192
|
# We do this by calculating if the difference between today and the
|
183
193
|
# confirmation sent date does not exceed the confirm in time configured.
|
184
|
-
#
|
194
|
+
# allow_unconfirmed_access_for is a model configuration, must always be an integer value.
|
185
195
|
#
|
186
196
|
# Example:
|
187
197
|
#
|
@@ -201,7 +211,10 @@ module Devise
|
|
201
211
|
# confirmation_period_valid? # will always return true
|
202
212
|
#
|
203
213
|
def confirmation_period_valid?
|
204
|
-
|
214
|
+
return true if self.class.allow_unconfirmed_access_for.nil?
|
215
|
+
return false if self.class.allow_unconfirmed_access_for == 0.days
|
216
|
+
|
217
|
+
confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago
|
205
218
|
end
|
206
219
|
|
207
220
|
# Checks if the user confirmation happens before the token becomes invalid
|
@@ -217,7 +230,7 @@ module Devise
|
|
217
230
|
# confirmation_period_expired? # will always return false
|
218
231
|
#
|
219
232
|
def confirmation_period_expired?
|
220
|
-
self.class.confirm_within && self.confirmation_sent_at && (Time.now > self.confirmation_sent_at + self.class.confirm_within)
|
233
|
+
self.class.confirm_within && self.confirmation_sent_at && (Time.now.utc > self.confirmation_sent_at.utc + self.class.confirm_within)
|
221
234
|
end
|
222
235
|
|
223
236
|
# Checks whether the record requires any confirmation.
|
@@ -236,8 +249,7 @@ module Devise
|
|
236
249
|
if self.confirmation_token && !confirmation_period_expired?
|
237
250
|
@raw_confirmation_token = self.confirmation_token
|
238
251
|
else
|
239
|
-
|
240
|
-
self.confirmation_token = @raw_confirmation_token = raw
|
252
|
+
self.confirmation_token = @raw_confirmation_token = Devise.friendly_token
|
241
253
|
self.confirmation_sent_at = Time.now.utc
|
242
254
|
end
|
243
255
|
end
|
@@ -246,18 +258,44 @@ module Devise
|
|
246
258
|
generate_confirmation_token && save(validate: false)
|
247
259
|
end
|
248
260
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
261
|
+
if Devise.activerecord51?
|
262
|
+
def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
|
263
|
+
@reconfirmation_required = true
|
264
|
+
self.unconfirmed_email = self.email
|
265
|
+
self.email = self.email_in_database
|
266
|
+
self.confirmation_token = nil
|
267
|
+
generate_confirmation_token
|
268
|
+
end
|
269
|
+
else
|
270
|
+
def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
|
271
|
+
@reconfirmation_required = true
|
272
|
+
self.unconfirmed_email = self.email
|
273
|
+
self.email = self.email_was
|
274
|
+
self.confirmation_token = nil
|
275
|
+
generate_confirmation_token
|
276
|
+
end
|
255
277
|
end
|
256
278
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
279
|
+
if Devise.activerecord51?
|
280
|
+
def postpone_email_change?
|
281
|
+
postpone = self.class.reconfirmable &&
|
282
|
+
will_save_change_to_email? &&
|
283
|
+
!@bypass_confirmation_postpone &&
|
284
|
+
self.email.present? &&
|
285
|
+
(!@skip_reconfirmation_in_callback || !self.email_in_database.nil?)
|
286
|
+
@bypass_confirmation_postpone = false
|
287
|
+
postpone
|
288
|
+
end
|
289
|
+
else
|
290
|
+
def postpone_email_change?
|
291
|
+
postpone = self.class.reconfirmable &&
|
292
|
+
email_changed? &&
|
293
|
+
!@bypass_confirmation_postpone &&
|
294
|
+
self.email.present? &&
|
295
|
+
(!@skip_reconfirmation_in_callback || !self.email_was.nil?)
|
296
|
+
@bypass_confirmation_postpone = false
|
297
|
+
postpone
|
298
|
+
end
|
261
299
|
end
|
262
300
|
|
263
301
|
def reconfirmation_required?
|
@@ -268,6 +306,16 @@ module Devise
|
|
268
306
|
confirmation_required? && !@skip_confirmation_notification && self.email.present?
|
269
307
|
end
|
270
308
|
|
309
|
+
# With reconfirmable, notify the original email when the user first
|
310
|
+
# requests the email change, instead of when the change is confirmed.
|
311
|
+
def send_email_changed_notification?
|
312
|
+
if self.class.reconfirmable
|
313
|
+
self.class.send_email_changed_notification && reconfirmation_required?
|
314
|
+
else
|
315
|
+
super
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
271
319
|
# A callback initiated after successfully confirming. This can be
|
272
320
|
# used to insert your own logic that is only run after the user successfully
|
273
321
|
# confirms.
|
@@ -300,7 +348,19 @@ module Devise
|
|
300
348
|
# If the user is already confirmed, create an error for the user
|
301
349
|
# Options must have the confirmation_token
|
302
350
|
def confirm_by_token(confirmation_token)
|
351
|
+
# When the `confirmation_token` parameter is blank, if there are any users with a blank
|
352
|
+
# `confirmation_token` in the database, the first one would be confirmed here.
|
353
|
+
# The error is being manually added here to ensure no users are confirmed by mistake.
|
354
|
+
# This was done in the model for convenience, since validation errors are automatically
|
355
|
+
# displayed in the view.
|
356
|
+
if confirmation_token.blank?
|
357
|
+
confirmable = new
|
358
|
+
confirmable.errors.add(:confirmation_token, :blank)
|
359
|
+
return confirmable
|
360
|
+
end
|
361
|
+
|
303
362
|
confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
|
363
|
+
|
304
364
|
unless confirmable
|
305
365
|
confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
|
306
366
|
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
|
@@ -316,6 +376,7 @@ module Devise
|
|
316
376
|
|
317
377
|
# Find a record for confirmation by unconfirmed email field
|
318
378
|
def find_by_unconfirmed_email_with_errors(attributes = {})
|
379
|
+
attributes = attributes.slice(*confirmation_keys).permit!.to_h if attributes.respond_to? :permit
|
319
380
|
unconfirmed_required_attributes = confirmation_keys.map { |k| k == :email ? :unconfirmed_email : k }
|
320
381
|
unconfirmed_attributes = attributes.symbolize_keys
|
321
382
|
unconfirmed_attributes[:unconfirmed_email] = unconfirmed_attributes.delete(:email)
|
@@ -1,24 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'devise/strategies/database_authenticatable'
|
2
4
|
|
3
5
|
module Devise
|
4
|
-
def self.bcrypt(klass, password)
|
5
|
-
ActiveSupport::Deprecation.warn "Devise.bcrypt is deprecated; use Devise::Encryptor.digest instead"
|
6
|
-
Devise::Encryptor.digest(klass, password)
|
7
|
-
end
|
8
|
-
|
9
6
|
module Models
|
10
|
-
# Authenticatable Module, responsible for
|
11
|
-
# authenticity of a user while signing in.
|
7
|
+
# Authenticatable Module, responsible for hashing the password and
|
8
|
+
# validating the authenticity of a user while signing in.
|
12
9
|
#
|
13
10
|
# == Options
|
14
11
|
#
|
15
12
|
# DatabaseAuthenticatable adds the following options to devise_for:
|
16
13
|
#
|
17
14
|
# * +pepper+: a random string used to provide a more secure hash. Use
|
18
|
-
# `
|
15
|
+
# `rails secret` to generate new keys.
|
19
16
|
#
|
20
17
|
# * +stretches+: the cost given to bcrypt.
|
21
18
|
#
|
19
|
+
# * +send_email_changed_notification+: notify original email when it changes.
|
20
|
+
#
|
21
|
+
# * +send_password_change_notification+: notify email when password changes.
|
22
|
+
#
|
22
23
|
# == Examples
|
23
24
|
#
|
24
25
|
# User.find(1).valid_password?('password123') # returns true/false
|
@@ -27,17 +28,36 @@ module Devise
|
|
27
28
|
extend ActiveSupport::Concern
|
28
29
|
|
29
30
|
included do
|
31
|
+
after_update :send_email_changed_notification, if: :send_email_changed_notification?
|
30
32
|
after_update :send_password_change_notification, if: :send_password_change_notification?
|
31
33
|
|
32
34
|
attr_reader :password, :current_password
|
33
35
|
attr_accessor :password_confirmation
|
34
36
|
end
|
35
37
|
|
38
|
+
def initialize(*args, &block)
|
39
|
+
@skip_email_changed_notification = false
|
40
|
+
@skip_password_change_notification = false
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
# Skips sending the email changed notification after_update
|
45
|
+
def skip_email_changed_notification!
|
46
|
+
@skip_email_changed_notification = true
|
47
|
+
end
|
48
|
+
|
49
|
+
# Skips sending the password change notification after_update
|
50
|
+
def skip_password_change_notification!
|
51
|
+
@skip_password_change_notification = true
|
52
|
+
end
|
53
|
+
|
36
54
|
def self.required_fields(klass)
|
37
55
|
[:encrypted_password] + klass.authentication_keys
|
38
56
|
end
|
39
57
|
|
40
|
-
# Generates password
|
58
|
+
# Generates a hashed password based on the given value.
|
59
|
+
# For legacy reasons, we use `encrypted_password` to store
|
60
|
+
# the hashed password.
|
41
61
|
def password=(new_password)
|
42
62
|
@password = new_password
|
43
63
|
self.encrypted_password = password_digest(@password) if @password.present?
|
@@ -61,6 +81,15 @@ module Devise
|
|
61
81
|
# their password). In case the password field is rejected, the confirmation
|
62
82
|
# is also rejected as long as it is also blank.
|
63
83
|
def update_with_password(params, *options)
|
84
|
+
if options.present?
|
85
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
|
86
|
+
[Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
|
87
|
+
(`options`) is deprecated and it will be removed in the next major version.
|
88
|
+
It was added to support a feature deprecated in Rails 4, so you can safely remove it
|
89
|
+
from your code.
|
90
|
+
DEPRECATION
|
91
|
+
end
|
92
|
+
|
64
93
|
current_password = params.delete(:current_password)
|
65
94
|
|
66
95
|
if params[:password].blank?
|
@@ -69,11 +98,11 @@ module Devise
|
|
69
98
|
end
|
70
99
|
|
71
100
|
result = if valid_password?(current_password)
|
72
|
-
|
101
|
+
update(params, *options)
|
73
102
|
else
|
74
|
-
|
75
|
-
|
76
|
-
|
103
|
+
assign_attributes(params, *options)
|
104
|
+
valid?
|
105
|
+
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
77
106
|
false
|
78
107
|
end
|
79
108
|
|
@@ -94,10 +123,19 @@ module Devise
|
|
94
123
|
# end
|
95
124
|
#
|
96
125
|
def update_without_password(params, *options)
|
126
|
+
if options.present?
|
127
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
|
128
|
+
[Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
|
129
|
+
(`options`) is deprecated and it will be removed in the next major version.
|
130
|
+
It was added to support a feature deprecated in Rails 4, so you can safely remove it
|
131
|
+
from your code.
|
132
|
+
DEPRECATION
|
133
|
+
end
|
134
|
+
|
97
135
|
params.delete(:password)
|
98
136
|
params.delete(:password_confirmation)
|
99
137
|
|
100
|
-
result =
|
138
|
+
result = update(params, *options)
|
101
139
|
clean_up_passwords
|
102
140
|
result
|
103
141
|
end
|
@@ -109,8 +147,8 @@ module Devise
|
|
109
147
|
result = if valid_password?(current_password)
|
110
148
|
destroy
|
111
149
|
else
|
112
|
-
|
113
|
-
|
150
|
+
valid?
|
151
|
+
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
114
152
|
false
|
115
153
|
end
|
116
154
|
|
@@ -135,27 +173,56 @@ module Devise
|
|
135
173
|
encrypted_password[0,29] if encrypted_password
|
136
174
|
end
|
137
175
|
|
176
|
+
if Devise.activerecord51?
|
177
|
+
# Send notification to user when email changes.
|
178
|
+
def send_email_changed_notification
|
179
|
+
send_devise_notification(:email_changed, to: email_before_last_save)
|
180
|
+
end
|
181
|
+
else
|
182
|
+
# Send notification to user when email changes.
|
183
|
+
def send_email_changed_notification
|
184
|
+
send_devise_notification(:email_changed, to: email_was)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Send notification to user when password changes.
|
138
189
|
def send_password_change_notification
|
139
190
|
send_devise_notification(:password_change)
|
140
191
|
end
|
141
192
|
|
142
193
|
protected
|
143
194
|
|
144
|
-
#
|
195
|
+
# Hashes the password using bcrypt. Custom hash functions should override
|
145
196
|
# this method to apply their own algorithm.
|
146
197
|
#
|
147
198
|
# See https://github.com/plataformatec/devise-encryptable for examples
|
148
|
-
# of other
|
199
|
+
# of other hashing engines.
|
149
200
|
def password_digest(password)
|
150
201
|
Devise::Encryptor.digest(self.class, password)
|
151
202
|
end
|
152
203
|
|
153
|
-
|
154
|
-
|
204
|
+
if Devise.activerecord51?
|
205
|
+
def send_email_changed_notification?
|
206
|
+
self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
|
207
|
+
end
|
208
|
+
else
|
209
|
+
def send_email_changed_notification?
|
210
|
+
self.class.send_email_changed_notification && email_changed? && !@skip_email_changed_notification
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
if Devise.activerecord51?
|
215
|
+
def send_password_change_notification?
|
216
|
+
self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
|
217
|
+
end
|
218
|
+
else
|
219
|
+
def send_password_change_notification?
|
220
|
+
self.class.send_password_change_notification && encrypted_password_changed? && !@skip_password_change_notification
|
221
|
+
end
|
155
222
|
end
|
156
223
|
|
157
224
|
module ClassMethods
|
158
|
-
Devise::Models.config(self, :pepper, :stretches, :send_password_change_notification)
|
225
|
+
Devise::Models.config(self, :pepper, :stretches, :send_email_changed_notification, :send_password_change_notification)
|
159
226
|
|
160
227
|
# We assume this method already gets the sanitized values from the
|
161
228
|
# DatabaseAuthenticatable strategy. If you are using this method on
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "devise/hooks/lockable"
|
2
4
|
|
3
5
|
module Devise
|
@@ -7,7 +9,7 @@ module Devise
|
|
7
9
|
# blocked: email and time. The former will send an email to the user when
|
8
10
|
# the lock happens, containing a link to unlock its account. The second
|
9
11
|
# will unlock the user automatically after some configured time (ie 2.hours).
|
10
|
-
# It's also possible to
|
12
|
+
# It's also possible to set up lockable to use both email and time strategies.
|
11
13
|
#
|
12
14
|
# == Options
|
13
15
|
#
|
@@ -64,7 +66,7 @@ module Devise
|
|
64
66
|
def send_unlock_instructions
|
65
67
|
raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
|
66
68
|
self.unlock_token = enc
|
67
|
-
|
69
|
+
save(validate: false)
|
68
70
|
send_devise_notification(:unlock_instructions, raw, {})
|
69
71
|
raw
|
70
72
|
end
|
@@ -99,8 +101,7 @@ module Devise
|
|
99
101
|
if super && !access_locked?
|
100
102
|
true
|
101
103
|
else
|
102
|
-
|
103
|
-
self.failed_attempts += 1
|
104
|
+
increment_failed_attempts
|
104
105
|
if attempts_exceeded?
|
105
106
|
lock_access! unless access_locked?
|
106
107
|
else
|
@@ -109,6 +110,11 @@ module Devise
|
|
109
110
|
false
|
110
111
|
end
|
111
112
|
end
|
113
|
+
|
114
|
+
def increment_failed_attempts
|
115
|
+
self.class.increment_counter(:failed_attempts, id)
|
116
|
+
reload
|
117
|
+
end
|
112
118
|
|
113
119
|
def unauthenticated_message
|
114
120
|
# If set to paranoid mode, do not show the locked message because it
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Devise
|
2
4
|
module Models
|
3
5
|
|
@@ -27,30 +29,20 @@ module Devise
|
|
27
29
|
end
|
28
30
|
|
29
31
|
included do
|
30
|
-
before_update
|
31
|
-
if (respond_to?(:email_changed?) && email_changed?) || encrypted_password_changed?
|
32
|
-
clear_reset_password_token
|
33
|
-
end
|
34
|
-
end
|
32
|
+
before_update :clear_reset_password_token, if: :clear_reset_password_token?
|
35
33
|
end
|
36
34
|
|
37
35
|
# Update password saving the record and clearing token. Returns true if
|
38
36
|
# the passwords are valid and the record was saved, false otherwise.
|
39
37
|
def reset_password(new_password, new_password_confirmation)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
if new_password.present?
|
39
|
+
self.password = new_password
|
40
|
+
self.password_confirmation = new_password_confirmation
|
41
|
+
save
|
42
|
+
else
|
43
|
+
errors.add(:password, :blank)
|
44
|
+
false
|
46
45
|
end
|
47
|
-
|
48
|
-
save
|
49
|
-
end
|
50
|
-
|
51
|
-
def reset_password!(new_password, new_password_confirmation)
|
52
|
-
ActiveSupport::Deprecation.warn "reset_password! is deprecated in favor of reset_password"
|
53
|
-
reset_password(new_password, new_password_confirmation)
|
54
46
|
end
|
55
47
|
|
56
48
|
# Resets reset password token and send reset password instructions by email.
|
@@ -99,7 +91,7 @@ module Devise
|
|
99
91
|
|
100
92
|
self.reset_password_token = enc
|
101
93
|
self.reset_password_sent_at = Time.now.utc
|
102
|
-
|
94
|
+
save(validate: false)
|
103
95
|
raw
|
104
96
|
end
|
105
97
|
|
@@ -107,6 +99,26 @@ module Devise
|
|
107
99
|
send_devise_notification(:reset_password_instructions, token, {})
|
108
100
|
end
|
109
101
|
|
102
|
+
if Devise.activerecord51?
|
103
|
+
def clear_reset_password_token?
|
104
|
+
encrypted_password_changed = respond_to?(:will_save_change_to_encrypted_password?) && will_save_change_to_encrypted_password?
|
105
|
+
authentication_keys_changed = self.class.authentication_keys.any? do |attribute|
|
106
|
+
respond_to?("will_save_change_to_#{attribute}?") && send("will_save_change_to_#{attribute}?")
|
107
|
+
end
|
108
|
+
|
109
|
+
authentication_keys_changed || encrypted_password_changed
|
110
|
+
end
|
111
|
+
else
|
112
|
+
def clear_reset_password_token?
|
113
|
+
encrypted_password_changed = respond_to?(:encrypted_password_changed?) && encrypted_password_changed?
|
114
|
+
authentication_keys_changed = self.class.authentication_keys.any? do |attribute|
|
115
|
+
respond_to?("#{attribute}_changed?") && send("#{attribute}_changed?")
|
116
|
+
end
|
117
|
+
|
118
|
+
authentication_keys_changed || encrypted_password_changed
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
110
122
|
module ClassMethods
|
111
123
|
# Attempt to find a user by password reset token. If a user is found, return it
|
112
124
|
# If a user is not found, return nil
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Devise
|
2
4
|
module Models
|
3
5
|
# Registerable is responsible for everything related to registering a new
|
@@ -19,6 +21,8 @@ module Devise
|
|
19
21
|
def new_with_session(params, session)
|
20
22
|
new(params)
|
21
23
|
end
|
24
|
+
|
25
|
+
Devise::Models.config(self, :sign_in_after_change_password)
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'devise/strategies/rememberable'
|
2
4
|
require 'devise/hooks/rememberable'
|
3
5
|
require 'devise/hooks/forgetable'
|
4
6
|
|
5
7
|
module Devise
|
6
8
|
module Models
|
7
|
-
# Rememberable manages generating and clearing token for
|
9
|
+
# Rememberable manages generating and clearing token for remembering the user
|
8
10
|
# from a saved cookie. Rememberable also has utility methods for dealing
|
9
11
|
# with serializing the user into the cookie and back from the cookie, trying
|
10
12
|
# to lookup the record based on the saved information.
|
@@ -45,9 +47,7 @@ module Devise
|
|
45
47
|
[:remember_created_at]
|
46
48
|
end
|
47
49
|
|
48
|
-
|
49
|
-
# Remove this for Devise 4.0.
|
50
|
-
def remember_me!(*)
|
50
|
+
def remember_me!
|
51
51
|
self.remember_token ||= self.class.remember_token if respond_to?(:remember_token)
|
52
52
|
self.remember_created_at ||= Time.now.utc
|
53
53
|
save(validate: false) if self.changed?
|
@@ -62,11 +62,6 @@ module Devise
|
|
62
62
|
save(validate: false)
|
63
63
|
end
|
64
64
|
|
65
|
-
# Remember token should be expired if expiration time not overpass now.
|
66
|
-
def remember_expired?
|
67
|
-
remember_created_at.nil?
|
68
|
-
end
|
69
|
-
|
70
65
|
def remember_expires_at
|
71
66
|
self.class.remember_for.from_now
|
72
67
|
end
|
@@ -81,7 +76,7 @@ module Devise
|
|
81
76
|
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt.presence)
|
82
77
|
salt
|
83
78
|
else
|
84
|
-
raise "
|
79
|
+
raise "authenticatable_salt returned nil for the #{self.class.name} model. " \
|
85
80
|
"In order to use rememberable, you must ensure a password is always set " \
|
86
81
|
"or have a remember_token column in your model or implement your own " \
|
87
82
|
"rememberable_value in the model with custom logic."
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'devise/hooks/trackable'
|
2
4
|
|
3
5
|
module Devise
|
@@ -20,7 +22,7 @@ module Devise
|
|
20
22
|
self.last_sign_in_at = old_current || new_current
|
21
23
|
self.current_sign_in_at = new_current
|
22
24
|
|
23
|
-
old_current, new_current = self.current_sign_in_ip, request
|
25
|
+
old_current, new_current = self.current_sign_in_ip, extract_ip_from(request)
|
24
26
|
self.last_sign_in_ip = old_current || new_current
|
25
27
|
self.current_sign_in_ip = new_current
|
26
28
|
|
@@ -29,9 +31,21 @@ module Devise
|
|
29
31
|
end
|
30
32
|
|
31
33
|
def update_tracked_fields!(request)
|
34
|
+
# We have to check if the user is already persisted before running
|
35
|
+
# `save` here because invalid users can be saved if we don't.
|
36
|
+
# See https://github.com/plataformatec/devise/issues/4673 for more details.
|
37
|
+
return if new_record?
|
38
|
+
|
32
39
|
update_tracked_fields(request)
|
33
40
|
save(validate: false)
|
34
41
|
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def extract_ip_from(request)
|
46
|
+
request.remote_ip
|
47
|
+
end
|
48
|
+
|
35
49
|
end
|
36
50
|
end
|
37
51
|
end
|