devise 3.5.1 → 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 +259 -1076
- data/MIT-LICENSE +1 -1
- data/README.md +256 -68
- 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 +10 -7
- 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 +10 -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/mailer/password_change.html.erb +3 -0
- data/app/views/devise/passwords/edit.html.erb +5 -5
- 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 +8 -8
- data/app/views/devise/unlocks/new.html.erb +2 -2
- data/config/locales/en.yml +6 -1
- data/lib/devise/controllers/helpers.rb +35 -26
- data/lib/devise/controllers/rememberable.rb +11 -2
- data/lib/devise/controllers/scoped_views.rb +2 -0
- data/lib/devise/controllers/sign_in_out.rb +35 -18
- 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 +84 -27
- 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 +7 -7
- 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 +106 -33
- data/lib/devise/models/database_authenticatable.rb +97 -21
- data/lib/devise/models/lockable.rb +15 -5
- data/lib/devise/models/omniauthable.rb +2 -0
- data/lib/devise/models/recoverable.rb +32 -24
- data/lib/devise/models/registerable.rb +4 -0
- data/lib/devise/models/rememberable.rb +42 -26
- data/lib/devise/models/timeoutable.rb +2 -6
- 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 +67 -47
- 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 +5 -3
- data/lib/devise/strategies/base.rb +2 -0
- data/lib/devise/strategies/database_authenticatable.rb +11 -4
- data/lib/devise/strategies/rememberable.rb +5 -6
- 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 +73 -46
- 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 +21 -11
- data/lib/generators/mongoid/devise_generator.rb +7 -5
- data/lib/generators/templates/README +1 -8
- data/lib/generators/templates/controllers/README +1 -1
- 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 +52 -22
- data/lib/generators/templates/markerb/confirmation_instructions.markerb +1 -1
- data/lib/generators/templates/markerb/email_changed.markerb +7 -0
- data/lib/generators/templates/markerb/password_change.markerb +3 -0
- data/lib/generators/templates/markerb/reset_password_instructions.markerb +1 -1
- data/lib/generators/templates/markerb/unlock_instructions.markerb +1 -1
- 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 +15 -301
- data/.gitignore +0 -10
- data/.travis.yml +0 -45
- data/.yardopts +0 -9
- data/CONTRIBUTING.md +0 -14
- data/Gemfile +0 -29
- data/Gemfile.lock +0 -191
- data/Rakefile +0 -36
- data/devise.gemspec +0 -29
- data/devise.png +0 -0
- data/gemfiles/Gemfile.rails-3.2-stable +0 -29
- data/gemfiles/Gemfile.rails-3.2-stable.lock +0 -169
- data/gemfiles/Gemfile.rails-4.0-stable +0 -29
- data/gemfiles/Gemfile.rails-4.0-stable.lock +0 -163
- data/gemfiles/Gemfile.rails-4.1-stable +0 -29
- data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -169
- data/gemfiles/Gemfile.rails-4.2-stable +0 -29
- data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -191
- 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/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 -298
- 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 -96
- 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 -133
- data/test/integration/recoverable_test.rb +0 -347
- data/test/integration/registerable_test.rb +0 -359
- data/test/integration/rememberable_test.rb +0 -176
- data/test/integration/timeoutable_test.rb +0 -189
- 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 -468
- data/test/models/database_authenticatable_test.rb +0 -249
- data/test/models/lockable_test.rb +0 -328
- data/test/models/omniauthable_test.rb +0 -7
- data/test/models/recoverable_test.rb +0 -228
- data/test/models/registerable_test.rb +0 -7
- data/test/models/rememberable_test.rb +0 -204
- 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 -144
- 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/controllers/admins/sessions_controller.rb +0 -6
- data/test/rails_app/app/controllers/admins_controller.rb +0 -11
- 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/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 -122
- 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_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 -73
- 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
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Devise
|
2
4
|
module Mailers
|
3
5
|
module Helpers
|
@@ -5,15 +7,16 @@ module Devise
|
|
5
7
|
|
6
8
|
included do
|
7
9
|
include Devise::Controllers::ScopedViews
|
8
|
-
attr_reader :scope_name, :resource
|
9
10
|
end
|
10
11
|
|
11
12
|
protected
|
12
13
|
|
14
|
+
attr_reader :scope_name, :resource
|
15
|
+
|
13
16
|
# Configure default email options
|
14
|
-
def devise_mail(record, action, opts={})
|
17
|
+
def devise_mail(record, action, opts = {}, &block)
|
15
18
|
initialize_from_record(record)
|
16
|
-
mail headers_for(action, opts)
|
19
|
+
mail headers_for(action, opts), &block
|
17
20
|
end
|
18
21
|
|
19
22
|
def initialize_from_record(record)
|
@@ -64,7 +67,7 @@ module Devise
|
|
64
67
|
template_path
|
65
68
|
end
|
66
69
|
|
67
|
-
#
|
70
|
+
# Set up a subject doing an I18n lookup. At first, it attempts to set a subject
|
68
71
|
# based on the current mapping:
|
69
72
|
#
|
70
73
|
# en:
|
data/lib/devise/mapping.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'devise/hooks/activatable'
|
3
4
|
require 'devise/hooks/csrf_cleaner'
|
4
5
|
|
@@ -102,7 +103,7 @@ module Devise
|
|
102
103
|
# and passing a new list of attributes you want to exempt. All attributes
|
103
104
|
# given to :except will simply add names to exempt to Devise internal list.
|
104
105
|
def serializable_hash(options = nil)
|
105
|
-
options
|
106
|
+
options = options.try(:dup) || {}
|
106
107
|
options[:except] = Array(options[:except])
|
107
108
|
|
108
109
|
if options[:force_except]
|
@@ -114,6 +115,15 @@ module Devise
|
|
114
115
|
super(options)
|
115
116
|
end
|
116
117
|
|
118
|
+
# Redefine inspect using serializable_hash, to ensure we don't accidentally
|
119
|
+
# leak passwords into exceptions.
|
120
|
+
def inspect
|
121
|
+
inspection = serializable_hash.collect do |k,v|
|
122
|
+
"#{k}: #{respond_to?(:attribute_for_inspect) ? attribute_for_inspect(k) : v.inspect}"
|
123
|
+
end
|
124
|
+
"#<#{self.class} #{inspection.join(", ")}>"
|
125
|
+
end
|
126
|
+
|
117
127
|
protected
|
118
128
|
|
119
129
|
def devise_mailer
|
@@ -123,16 +133,18 @@ module Devise
|
|
123
133
|
# This is an internal method called every time Devise needs
|
124
134
|
# to send a notification/mail. This can be overridden if you
|
125
135
|
# need to customize the e-mail delivery logic. For instance,
|
126
|
-
# if you are using a queue to deliver e-mails (
|
127
|
-
# sidekiq, resque, etc), you must add the delivery to the queue
|
136
|
+
# if you are using a queue to deliver e-mails (active job, delayed
|
137
|
+
# job, sidekiq, resque, etc), you must add the delivery to the queue
|
128
138
|
# just after the transaction was committed. To achieve this,
|
129
139
|
# you can override send_devise_notification to store the
|
130
|
-
# deliveries until the after_commit callback is triggered
|
140
|
+
# deliveries until the after_commit callback is triggered.
|
141
|
+
#
|
142
|
+
# The following example uses Active Job's `deliver_later` :
|
131
143
|
#
|
132
144
|
# class User
|
133
145
|
# devise :database_authenticatable, :confirmable
|
134
146
|
#
|
135
|
-
# after_commit :
|
147
|
+
# after_commit :send_pending_devise_notifications
|
136
148
|
#
|
137
149
|
# protected
|
138
150
|
#
|
@@ -141,26 +153,43 @@ module Devise
|
|
141
153
|
# # delivery until the after_commit callback otherwise
|
142
154
|
# # send now because after_commit will not be called.
|
143
155
|
# if new_record? || changed?
|
144
|
-
#
|
156
|
+
# pending_devise_notifications << [notification, args]
|
145
157
|
# else
|
146
|
-
#
|
158
|
+
# render_and_send_devise_message(notification, *args)
|
147
159
|
# end
|
148
160
|
# end
|
149
161
|
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
162
|
+
# private
|
163
|
+
#
|
164
|
+
# def send_pending_devise_notifications
|
165
|
+
# pending_devise_notifications.each do |notification, args|
|
166
|
+
# render_and_send_devise_message(notification, *args)
|
153
167
|
# end
|
154
168
|
#
|
155
169
|
# # Empty the pending notifications array because the
|
156
170
|
# # after_commit hook can be called multiple times which
|
157
171
|
# # could cause multiple emails to be sent.
|
158
|
-
#
|
172
|
+
# pending_devise_notifications.clear
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
# def pending_devise_notifications
|
176
|
+
# @pending_devise_notifications ||= []
|
159
177
|
# end
|
160
178
|
#
|
161
|
-
# def
|
162
|
-
#
|
179
|
+
# def render_and_send_devise_message(notification, *args)
|
180
|
+
# message = devise_mailer.send(notification, self, *args)
|
181
|
+
#
|
182
|
+
# # Deliver later with Active Job's `deliver_later`
|
183
|
+
# if message.respond_to?(:deliver_later)
|
184
|
+
# message.deliver_later
|
185
|
+
# # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
|
186
|
+
# elsif message.respond_to?(:deliver_now)
|
187
|
+
# message.deliver_now
|
188
|
+
# else
|
189
|
+
# message.deliver
|
190
|
+
# end
|
163
191
|
# end
|
192
|
+
#
|
164
193
|
# end
|
165
194
|
#
|
166
195
|
def send_devise_notification(notification, *args)
|
@@ -235,7 +264,7 @@ module Devise
|
|
235
264
|
# end
|
236
265
|
#
|
237
266
|
# Finally, notice that Devise also queries for users in other scenarios
|
238
|
-
# besides authentication, for example when retrieving
|
267
|
+
# besides authentication, for example when retrieving a user to send
|
239
268
|
# an e-mail for password reset. In such cases, find_for_authentication
|
240
269
|
# is not called.
|
241
270
|
def find_for_authentication(tainted_conditions)
|
@@ -253,24 +282,20 @@ module Devise
|
|
253
282
|
|
254
283
|
# Find or initialize a record with group of attributes based on a list of required attributes.
|
255
284
|
def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
|
256
|
-
attributes
|
257
|
-
attributes
|
285
|
+
attributes.try(:permit!)
|
286
|
+
attributes = attributes.to_h.with_indifferent_access
|
287
|
+
.slice(*required_attributes)
|
288
|
+
.delete_if { |key, value| value.blank? }
|
258
289
|
|
259
290
|
if attributes.size == required_attributes.size
|
260
|
-
record = find_first_by_auth_conditions(attributes)
|
291
|
+
record = find_first_by_auth_conditions(attributes) and return record
|
261
292
|
end
|
262
293
|
|
263
|
-
|
264
|
-
record = new
|
265
|
-
|
294
|
+
new(devise_parameter_filter.filter(attributes)).tap do |record|
|
266
295
|
required_attributes.each do |key|
|
267
|
-
|
268
|
-
record.send("#{key}=", value)
|
269
|
-
record.errors.add(key, value.present? ? error : :blank)
|
296
|
+
record.errors.add(key, attributes[key].blank? ? :blank : error)
|
270
297
|
end
|
271
298
|
end
|
272
|
-
|
273
|
-
record
|
274
299
|
end
|
275
300
|
|
276
301
|
protected
|
@@ -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
|
@@ -7,7 +9,7 @@ module Devise
|
|
7
9
|
#
|
8
10
|
# Confirmable tracks the following columns:
|
9
11
|
#
|
10
|
-
# * confirmation_token -
|
12
|
+
# * confirmation_token - A unique random token
|
11
13
|
# * confirmed_at - A timestamp when the user clicked the confirmation link
|
12
14
|
# * confirmation_sent_at - A timestamp when the confirmation_token was generated (not sent)
|
13
15
|
# * unconfirmed_email - An email address copied from the email attr. After confirmation
|
@@ -24,11 +26,15 @@ 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.
|
36
|
+
# Confirmable will not generate a new token if a repeat confirmation is requested
|
37
|
+
# during this time frame, unless the user's email changed too.
|
32
38
|
#
|
33
39
|
# == Examples
|
34
40
|
#
|
@@ -38,17 +44,23 @@ module Devise
|
|
38
44
|
#
|
39
45
|
module Confirmable
|
40
46
|
extend ActiveSupport::Concern
|
41
|
-
include ActionView::Helpers::DateHelper
|
42
47
|
|
43
48
|
included do
|
44
49
|
before_create :generate_confirmation_token, if: :confirmation_required?
|
45
|
-
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
|
46
58
|
before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, if: :postpone_email_change?
|
47
|
-
after_update :send_reconfirmation_instructions, if: :reconfirmation_required?
|
48
59
|
end
|
49
60
|
|
50
61
|
def initialize(*args, &block)
|
51
62
|
@bypass_confirmation_postpone = false
|
63
|
+
@skip_reconfirmation_in_callback = false
|
52
64
|
@reconfirmation_required = false
|
53
65
|
@skip_confirmation_notification = false
|
54
66
|
@raw_confirmation_token = nil
|
@@ -74,7 +86,7 @@ module Devise
|
|
74
86
|
|
75
87
|
self.confirmed_at = Time.now.utc
|
76
88
|
|
77
|
-
saved = if
|
89
|
+
saved = if pending_reconfirmation?
|
78
90
|
skip_reconfirmation!
|
79
91
|
self.email = unconfirmed_email
|
80
92
|
self.unconfirmed_email = nil
|
@@ -90,11 +102,6 @@ module Devise
|
|
90
102
|
end
|
91
103
|
end
|
92
104
|
|
93
|
-
def confirm!(args={})
|
94
|
-
ActiveSupport::Deprecation.warn "confirm! is deprecated in favor of confirm"
|
95
|
-
confirm(args)
|
96
|
-
end
|
97
|
-
|
98
105
|
# Verifies whether a user is confirmed or not
|
99
106
|
def confirmed?
|
100
107
|
!!confirmed_at
|
@@ -163,6 +170,12 @@ module Devise
|
|
163
170
|
|
164
171
|
protected
|
165
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
|
+
|
166
179
|
# A callback method used to deliver confirmation
|
167
180
|
# instructions on creation. This can be overridden
|
168
181
|
# in models to map to a nice sign up e-mail.
|
@@ -178,7 +191,7 @@ module Devise
|
|
178
191
|
# Checks if the confirmation for the user is within the limit time.
|
179
192
|
# We do this by calculating if the difference between today and the
|
180
193
|
# confirmation sent date does not exceed the confirm in time configured.
|
181
|
-
#
|
194
|
+
# allow_unconfirmed_access_for is a model configuration, must always be an integer value.
|
182
195
|
#
|
183
196
|
# Example:
|
184
197
|
#
|
@@ -198,7 +211,10 @@ module Devise
|
|
198
211
|
# confirmation_period_valid? # will always return true
|
199
212
|
#
|
200
213
|
def confirmation_period_valid?
|
201
|
-
|
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
|
202
218
|
end
|
203
219
|
|
204
220
|
# Checks if the user confirmation happens before the token becomes invalid
|
@@ -214,7 +230,7 @@ module Devise
|
|
214
230
|
# confirmation_period_expired? # will always return false
|
215
231
|
#
|
216
232
|
def confirmation_period_expired?
|
217
|
-
self.class.confirm_within && (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)
|
218
234
|
end
|
219
235
|
|
220
236
|
# Checks whether the record requires any confirmation.
|
@@ -230,37 +246,76 @@ module Devise
|
|
230
246
|
# Generates a new random token for confirmation, and stores
|
231
247
|
# the time this token is being generated in confirmation_sent_at
|
232
248
|
def generate_confirmation_token
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
249
|
+
if self.confirmation_token && !confirmation_period_expired?
|
250
|
+
@raw_confirmation_token = self.confirmation_token
|
251
|
+
else
|
252
|
+
self.confirmation_token = @raw_confirmation_token = Devise.friendly_token
|
253
|
+
self.confirmation_sent_at = Time.now.utc
|
254
|
+
end
|
237
255
|
end
|
238
256
|
|
239
257
|
def generate_confirmation_token!
|
240
258
|
generate_confirmation_token && save(validate: false)
|
241
259
|
end
|
242
260
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
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
|
248
277
|
end
|
249
278
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
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
|
254
299
|
end
|
255
300
|
|
256
301
|
def reconfirmation_required?
|
257
|
-
self.class.reconfirmable && @reconfirmation_required && self.email.present?
|
302
|
+
self.class.reconfirmable && @reconfirmation_required && (self.email.present? || self.unconfirmed_email.present?)
|
258
303
|
end
|
259
304
|
|
260
305
|
def send_confirmation_notification?
|
261
306
|
confirmation_required? && !@skip_confirmation_notification && self.email.present?
|
262
307
|
end
|
263
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
|
+
|
264
319
|
# A callback initiated after successfully confirming. This can be
|
265
320
|
# used to insert your own logic that is only run after the user successfully
|
266
321
|
# confirms.
|
@@ -293,17 +348,35 @@ module Devise
|
|
293
348
|
# If the user is already confirmed, create an error for the user
|
294
349
|
# Options must have the confirmation_token
|
295
350
|
def confirm_by_token(confirmation_token)
|
296
|
-
|
297
|
-
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
|
+
|
362
|
+
confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
|
363
|
+
|
364
|
+
unless confirmable
|
365
|
+
confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
|
366
|
+
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
|
367
|
+
end
|
368
|
+
|
369
|
+
# TODO: replace above lines with
|
370
|
+
# confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
|
371
|
+
# after enough time has passed that Devise clients do not use digested tokens
|
298
372
|
|
299
|
-
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
|
300
373
|
confirmable.confirm if confirmable.persisted?
|
301
|
-
confirmable.confirmation_token = original_token
|
302
374
|
confirmable
|
303
375
|
end
|
304
376
|
|
305
377
|
# Find a record for confirmation by unconfirmed email field
|
306
378
|
def find_by_unconfirmed_email_with_errors(attributes = {})
|
379
|
+
attributes = attributes.slice(*confirmation_keys).permit!.to_h if attributes.respond_to? :permit
|
307
380
|
unconfirmed_required_attributes = confirmation_keys.map { |k| k == :email ? :unconfirmed_email : k }
|
308
381
|
unconfirmed_attributes = attributes.symbolize_keys
|
309
382
|
unconfirmed_attributes[:unconfirmed_email] = unconfirmed_attributes.delete(:email)
|
@@ -1,25 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'devise/strategies/database_authenticatable'
|
2
|
-
require 'devise/encryptor'
|
3
4
|
|
4
5
|
module Devise
|
5
|
-
def self.bcrypt(klass, password)
|
6
|
-
ActiveSupport::Deprecation.warn "Devise.bcrypt is deprecated; use Devise::Encryptor.digest instead"
|
7
|
-
Devise::Encryptor.digest(klass, password)
|
8
|
-
end
|
9
|
-
|
10
6
|
module Models
|
11
|
-
# Authenticatable Module, responsible for
|
12
|
-
# 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.
|
13
9
|
#
|
14
10
|
# == Options
|
15
11
|
#
|
16
|
-
#
|
12
|
+
# DatabaseAuthenticatable adds the following options to devise_for:
|
17
13
|
#
|
18
14
|
# * +pepper+: a random string used to provide a more secure hash. Use
|
19
|
-
# `
|
15
|
+
# `rails secret` to generate new keys.
|
20
16
|
#
|
21
17
|
# * +stretches+: the cost given to bcrypt.
|
22
18
|
#
|
19
|
+
# * +send_email_changed_notification+: notify original email when it changes.
|
20
|
+
#
|
21
|
+
# * +send_password_change_notification+: notify email when password changes.
|
22
|
+
#
|
23
23
|
# == Examples
|
24
24
|
#
|
25
25
|
# User.find(1).valid_password?('password123') # returns true/false
|
@@ -28,15 +28,36 @@ module Devise
|
|
28
28
|
extend ActiveSupport::Concern
|
29
29
|
|
30
30
|
included do
|
31
|
+
after_update :send_email_changed_notification, if: :send_email_changed_notification?
|
32
|
+
after_update :send_password_change_notification, if: :send_password_change_notification?
|
33
|
+
|
31
34
|
attr_reader :password, :current_password
|
32
35
|
attr_accessor :password_confirmation
|
33
36
|
end
|
34
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
|
+
|
35
54
|
def self.required_fields(klass)
|
36
55
|
[:encrypted_password] + klass.authentication_keys
|
37
56
|
end
|
38
57
|
|
39
|
-
# 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.
|
40
61
|
def password=(new_password)
|
41
62
|
@password = new_password
|
42
63
|
self.encrypted_password = password_digest(@password) if @password.present?
|
@@ -60,6 +81,15 @@ module Devise
|
|
60
81
|
# their password). In case the password field is rejected, the confirmation
|
61
82
|
# is also rejected as long as it is also blank.
|
62
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
|
+
|
63
93
|
current_password = params.delete(:current_password)
|
64
94
|
|
65
95
|
if params[:password].blank?
|
@@ -68,11 +98,11 @@ module Devise
|
|
68
98
|
end
|
69
99
|
|
70
100
|
result = if valid_password?(current_password)
|
71
|
-
|
101
|
+
update(params, *options)
|
72
102
|
else
|
73
|
-
|
74
|
-
|
75
|
-
|
103
|
+
assign_attributes(params, *options)
|
104
|
+
valid?
|
105
|
+
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
76
106
|
false
|
77
107
|
end
|
78
108
|
|
@@ -93,10 +123,19 @@ module Devise
|
|
93
123
|
# end
|
94
124
|
#
|
95
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
|
+
|
96
135
|
params.delete(:password)
|
97
136
|
params.delete(:password_confirmation)
|
98
137
|
|
99
|
-
result =
|
138
|
+
result = update(params, *options)
|
100
139
|
clean_up_passwords
|
101
140
|
result
|
102
141
|
end
|
@@ -108,8 +147,8 @@ module Devise
|
|
108
147
|
result = if valid_password?(current_password)
|
109
148
|
destroy
|
110
149
|
else
|
111
|
-
|
112
|
-
|
150
|
+
valid?
|
151
|
+
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
113
152
|
false
|
114
153
|
end
|
115
154
|
|
@@ -134,19 +173,56 @@ module Devise
|
|
134
173
|
encrypted_password[0,29] if encrypted_password
|
135
174
|
end
|
136
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.
|
189
|
+
def send_password_change_notification
|
190
|
+
send_devise_notification(:password_change)
|
191
|
+
end
|
192
|
+
|
137
193
|
protected
|
138
194
|
|
139
|
-
#
|
195
|
+
# Hashes the password using bcrypt. Custom hash functions should override
|
140
196
|
# this method to apply their own algorithm.
|
141
197
|
#
|
142
198
|
# See https://github.com/plataformatec/devise-encryptable for examples
|
143
|
-
# of other
|
199
|
+
# of other hashing engines.
|
144
200
|
def password_digest(password)
|
145
201
|
Devise::Encryptor.digest(self.class, password)
|
146
202
|
end
|
147
203
|
|
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
|
222
|
+
end
|
223
|
+
|
148
224
|
module ClassMethods
|
149
|
-
Devise::Models.config(self, :pepper, :stretches)
|
225
|
+
Devise::Models.config(self, :pepper, :stretches, :send_email_changed_notification, :send_password_change_notification)
|
150
226
|
|
151
227
|
# We assume this method already gets the sanitized values from the
|
152
228
|
# DatabaseAuthenticatable strategy. If you are using this method on
|