devise 4.4.3 → 4.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +159 -3
- data/MIT-LICENSE +2 -1
- data/README.md +128 -64
- data/app/controllers/devise/confirmations_controller.rb +1 -0
- data/app/controllers/devise/passwords_controller.rb +3 -2
- data/app/controllers/devise/registrations_controller.rb +27 -9
- data/app/controllers/devise/sessions_controller.rb +1 -1
- data/app/controllers/devise/unlocks_controller.rb +1 -0
- data/app/controllers/devise_controller.rb +4 -3
- data/app/helpers/devise_helper.rb +21 -18
- data/app/mailers/devise/mailer.rb +5 -5
- data/app/views/devise/confirmations/new.html.erb +1 -1
- data/app/views/devise/passwords/edit.html.erb +3 -3
- data/app/views/devise/passwords/new.html.erb +1 -1
- data/app/views/devise/registrations/edit.html.erb +5 -5
- data/app/views/devise/registrations/new.html.erb +3 -3
- data/app/views/devise/sessions/new.html.erb +3 -3
- 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 +1 -1
- data/config/locales/en.yml +3 -2
- data/lib/devise/controllers/helpers.rb +8 -8
- data/lib/devise/controllers/responder.rb +35 -0
- data/lib/devise/controllers/sign_in_out.rb +8 -3
- data/lib/devise/controllers/url_helpers.rb +1 -1
- data/lib/devise/failure_app.rb +31 -7
- data/lib/devise/hooks/csrf_cleaner.rb +6 -1
- data/lib/devise/hooks/lockable.rb +2 -5
- data/lib/devise/hooks/timeoutable.rb +2 -2
- data/lib/devise/mapping.rb +1 -1
- data/lib/devise/models/authenticatable.rb +51 -48
- data/lib/devise/models/confirmable.rb +34 -40
- data/lib/devise/models/database_authenticatable.rb +54 -35
- data/lib/devise/models/lockable.rb +13 -5
- data/lib/devise/models/omniauthable.rb +2 -2
- data/lib/devise/models/recoverable.rb +8 -19
- data/lib/devise/models/registerable.rb +2 -0
- data/lib/devise/models/rememberable.rb +2 -2
- data/lib/devise/models/timeoutable.rb +1 -1
- data/lib/devise/models/trackable.rb +9 -2
- data/lib/devise/models/validatable.rb +4 -9
- data/lib/devise/models.rb +1 -0
- data/lib/devise/omniauth.rb +2 -5
- data/lib/devise/orm.rb +71 -0
- data/lib/devise/parameter_filter.rb +2 -0
- data/lib/devise/parameter_sanitizer.rb +13 -1
- data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
- data/lib/devise/rails/routes.rb +6 -6
- data/lib/devise/secret_key_finder.rb +2 -0
- data/lib/devise/strategies/authenticatable.rb +1 -1
- data/lib/devise/strategies/database_authenticatable.rb +6 -1
- data/lib/devise/test/controller_helpers.rb +4 -2
- data/lib/devise/test/integration_helpers.rb +1 -1
- data/lib/devise/version.rb +1 -1
- data/lib/devise.rb +34 -11
- data/lib/generators/active_record/devise_generator.rb +26 -11
- data/lib/generators/devise/controllers_generator.rb +1 -1
- data/lib/generators/devise/devise_generator.rb +1 -1
- data/lib/generators/devise/install_generator.rb +1 -5
- data/lib/generators/devise/orm_helpers.rb +2 -2
- data/lib/generators/devise/views_generator.rb +1 -1
- data/lib/generators/mongoid/devise_generator.rb +5 -5
- data/lib/generators/templates/README +9 -1
- data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
- data/lib/generators/templates/devise.rb +38 -8
- 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 +12 -4
- 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 +23 -316
- data/.gitignore +0 -10
- data/.travis.yml +0 -68
- data/.yardopts +0 -9
- data/CODE_OF_CONDUCT.md +0 -22
- data/CONTRIBUTING.md +0 -79
- data/Gemfile +0 -39
- data/Gemfile.lock +0 -193
- data/ISSUE_TEMPLATE.md +0 -19
- data/Rakefile +0 -37
- data/bin/test +0 -13
- data/devise.gemspec +0 -28
- data/devise.png +0 -0
- data/gemfiles/Gemfile.rails-4.1-stable +0 -32
- data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
- data/gemfiles/Gemfile.rails-4.2-stable +0 -32
- data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -192
- data/gemfiles/Gemfile.rails-5.0-stable +0 -33
- data/gemfiles/Gemfile.rails-5.0-stable.lock +0 -192
- data/gemfiles/Gemfile.rails-5.2-rc1 +0 -26
- data/gemfiles/Gemfile.rails-5.2-rc1.lock +0 -201
- data/guides/bug_report_templates/integration_test.rb +0 -106
- data/test/controllers/custom_registrations_controller_test.rb +0 -42
- data/test/controllers/custom_strategy_test.rb +0 -66
- data/test/controllers/helper_methods_test.rb +0 -24
- data/test/controllers/helpers_test.rb +0 -318
- data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -53
- data/test/controllers/internal_helpers_test.rb +0 -129
- data/test/controllers/load_hooks_controller_test.rb +0 -21
- data/test/controllers/passwords_controller_test.rb +0 -34
- data/test/controllers/sessions_controller_test.rb +0 -108
- data/test/controllers/url_helpers_test.rb +0 -67
- data/test/delegator_test.rb +0 -21
- data/test/devise_test.rb +0 -109
- data/test/failure_app_test.rb +0 -340
- data/test/generators/active_record_generator_test.rb +0 -130
- data/test/generators/controllers_generator_test.rb +0 -50
- data/test/generators/devise_generator_test.rb +0 -41
- data/test/generators/install_generator_test.rb +0 -26
- data/test/generators/mongoid_generator_test.rb +0 -25
- data/test/generators/views_generator_test.rb +0 -105
- data/test/helpers/devise_helper_test.rb +0 -51
- data/test/integration/authenticatable_test.rb +0 -706
- data/test/integration/confirmable_test.rb +0 -326
- data/test/integration/database_authenticatable_test.rb +0 -97
- data/test/integration/http_authenticatable_test.rb +0 -114
- data/test/integration/lockable_test.rb +0 -242
- data/test/integration/mounted_engine_test.rb +0 -38
- data/test/integration/omniauthable_test.rb +0 -148
- data/test/integration/recoverable_test.rb +0 -349
- data/test/integration/registerable_test.rb +0 -365
- data/test/integration/rememberable_test.rb +0 -219
- data/test/integration/timeoutable_test.rb +0 -186
- data/test/integration/trackable_test.rb +0 -99
- data/test/mailers/confirmation_instructions_test.rb +0 -117
- data/test/mailers/email_changed_test.rb +0 -132
- data/test/mailers/mailer_test.rb +0 -20
- data/test/mailers/reset_password_instructions_test.rb +0 -98
- data/test/mailers/unlock_instructions_test.rb +0 -93
- data/test/mapping_test.rb +0 -136
- data/test/models/authenticatable_test.rb +0 -25
- data/test/models/confirmable_test.rb +0 -549
- data/test/models/database_authenticatable_test.rb +0 -283
- data/test/models/lockable_test.rb +0 -352
- data/test/models/omniauthable_test.rb +0 -9
- data/test/models/recoverable_test.rb +0 -263
- data/test/models/registerable_test.rb +0 -9
- data/test/models/rememberable_test.rb +0 -184
- data/test/models/serializable_test.rb +0 -60
- data/test/models/timeoutable_test.rb +0 -53
- data/test/models/trackable_test.rb +0 -62
- data/test/models/validatable_test.rb +0 -121
- data/test/models_test.rb +0 -155
- data/test/omniauth/config_test.rb +0 -61
- data/test/omniauth/url_helpers_test.rb +0 -53
- data/test/orm/active_record.rb +0 -24
- data/test/orm/mongoid.rb +0 -15
- data/test/parameter_sanitizer_test.rb +0 -77
- data/test/rails_app/Rakefile +0 -6
- data/test/rails_app/app/active_record/admin.rb +0 -8
- data/test/rails_app/app/active_record/shim.rb +0 -4
- data/test/rails_app/app/active_record/user.rb +0 -20
- data/test/rails_app/app/active_record/user_on_engine.rb +0 -9
- data/test/rails_app/app/active_record/user_on_main_app.rb +0 -9
- data/test/rails_app/app/active_record/user_with_validations.rb +0 -12
- data/test/rails_app/app/active_record/user_without_email.rb +0 -10
- data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -8
- data/test/rails_app/app/controllers/admins_controller.rb +0 -8
- data/test/rails_app/app/controllers/application_controller.rb +0 -13
- data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -32
- data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -33
- data/test/rails_app/app/controllers/home_controller.rb +0 -31
- data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -4
- data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -4
- data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -16
- data/test/rails_app/app/controllers/users_controller.rb +0 -33
- data/test/rails_app/app/helpers/application_helper.rb +0 -5
- data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -5
- data/test/rails_app/app/mailers/users/mailer.rb +0 -5
- data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -6
- data/test/rails_app/app/mongoid/admin.rb +0 -31
- data/test/rails_app/app/mongoid/shim.rb +0 -25
- data/test/rails_app/app/mongoid/user.rb +0 -50
- data/test/rails_app/app/mongoid/user_on_engine.rb +0 -41
- data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -41
- data/test/rails_app/app/mongoid/user_with_validations.rb +0 -37
- data/test/rails_app/app/mongoid/user_without_email.rb +0 -35
- 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 -48
- data/test/rails_app/config/boot.rb +0 -27
- data/test/rails_app/config/database.yml +0 -18
- data/test/rails_app/config/environment.rb +0 -7
- data/test/rails_app/config/environments/development.rb +0 -32
- data/test/rails_app/config/environments/production.rb +0 -88
- data/test/rails_app/config/environments/test.rb +0 -47
- data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -9
- data/test/rails_app/config/initializers/devise.rb +0 -182
- data/test/rails_app/config/initializers/inflections.rb +0 -4
- data/test/rails_app/config/initializers/secret_token.rb +0 -5
- data/test/rails_app/config/initializers/session_store.rb +0 -3
- data/test/rails_app/config/routes.rb +0 -128
- data/test/rails_app/config.ru +0 -4
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -77
- data/test/rails_app/db/schema.rb +0 -57
- data/test/rails_app/lib/shared_admin.rb +0 -23
- data/test/rails_app/lib/shared_user.rb +0 -32
- data/test/rails_app/lib/shared_user_without_email.rb +0 -28
- data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -15
- 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 -11
- data/test/routes_test.rb +0 -281
- data/test/secret_key_finder_test.rb +0 -97
- data/test/support/action_controller/record_identifier.rb +0 -12
- data/test/support/assertions.rb +0 -30
- data/test/support/helpers.rb +0 -83
- data/test/support/http_method_compatibility.rb +0 -53
- data/test/support/integration.rb +0 -95
- data/test/support/locale/en.yml +0 -8
- data/test/support/mongoid.yml +0 -6
- data/test/support/webrat/integrations/rails.rb +0 -35
- data/test/test/controller_helpers_test.rb +0 -193
- data/test/test/integration_helpers_test.rb +0 -34
- data/test/test_helper.rb +0 -36
- data/test/test_models.rb +0 -35
data/lib/devise/failure_app.rb
CHANGED
|
@@ -71,8 +71,11 @@ module Devise
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
self.response = recall_app(warden_options[:recall]).call(request.env).tap { |response|
|
|
75
|
+
response[0] = Rack::Utils.status_code(
|
|
76
|
+
response[0].in?(300..399) ? Devise.responder.redirect_status : Devise.responder.error_status
|
|
77
|
+
)
|
|
78
|
+
}
|
|
76
79
|
end
|
|
77
80
|
|
|
78
81
|
def redirect
|
|
@@ -107,7 +110,7 @@ module Devise
|
|
|
107
110
|
options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
|
|
108
111
|
options = i18n_options(options)
|
|
109
112
|
|
|
110
|
-
I18n.t(:"#{scope}.#{message}", options)
|
|
113
|
+
I18n.t(:"#{scope}.#{message}", **options)
|
|
111
114
|
else
|
|
112
115
|
message.to_s
|
|
113
116
|
end
|
|
@@ -144,11 +147,20 @@ module Devise
|
|
|
144
147
|
|
|
145
148
|
opts[:format] = request_format unless skip_format?
|
|
146
149
|
|
|
147
|
-
opts[:script_name] = relative_url_root if relative_url_root?
|
|
148
|
-
|
|
149
150
|
router_name = Devise.mappings[scope].router_name || Devise.available_router_name
|
|
150
151
|
context = send(router_name)
|
|
151
152
|
|
|
153
|
+
if relative_url_root?
|
|
154
|
+
opts[:script_name] = relative_url_root
|
|
155
|
+
|
|
156
|
+
# We need to add the rootpath to `script_name` manually for applications that use a Rails
|
|
157
|
+
# version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
|
|
158
|
+
# that use Devise. Remove it when the support of Rails 5.0 is dropped.
|
|
159
|
+
elsif root_path_defined?(context) && !rails_51_and_up?
|
|
160
|
+
rootpath = context.routes.url_helpers.root_path
|
|
161
|
+
opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
|
|
162
|
+
end
|
|
163
|
+
|
|
152
164
|
if context.respond_to?(route)
|
|
153
165
|
context.send(route, opts)
|
|
154
166
|
elsif respond_to?(:root_url)
|
|
@@ -159,7 +171,7 @@ module Devise
|
|
|
159
171
|
end
|
|
160
172
|
|
|
161
173
|
def skip_format?
|
|
162
|
-
%w(html */*).include? request_format.to_s
|
|
174
|
+
%w(html */* turbo_stream).include? request_format.to_s
|
|
163
175
|
end
|
|
164
176
|
|
|
165
177
|
# Choose whether we should respond in an HTTP authentication fashion,
|
|
@@ -242,7 +254,7 @@ module Devise
|
|
|
242
254
|
# Check if flash messages should be emitted. Default is to do it on
|
|
243
255
|
# navigational formats
|
|
244
256
|
def is_flashing_format?
|
|
245
|
-
is_navigational_format?
|
|
257
|
+
request.respond_to?(:flash) && is_navigational_format?
|
|
246
258
|
end
|
|
247
259
|
|
|
248
260
|
def request_format
|
|
@@ -260,5 +272,17 @@ module Devise
|
|
|
260
272
|
def relative_url_root?
|
|
261
273
|
relative_url_root.present?
|
|
262
274
|
end
|
|
275
|
+
|
|
276
|
+
ActiveSupport.run_load_hooks(:devise_failure_app, self)
|
|
277
|
+
|
|
278
|
+
private
|
|
279
|
+
|
|
280
|
+
def root_path_defined?(context)
|
|
281
|
+
defined?(context.routes) && context.routes.url_helpers.respond_to?(:root_path)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def rails_51_and_up?
|
|
285
|
+
Rails.gem_version >= Gem::Version.new("5.1")
|
|
286
|
+
end
|
|
263
287
|
end
|
|
264
288
|
end
|
|
@@ -4,6 +4,11 @@ Warden::Manager.after_authentication do |record, warden, options|
|
|
|
4
4
|
clean_up_for_winning_strategy = !warden.winning_strategy.respond_to?(:clean_up_csrf?) ||
|
|
5
5
|
warden.winning_strategy.clean_up_csrf?
|
|
6
6
|
if Devise.clean_up_csrf_token_on_authentication && clean_up_for_winning_strategy
|
|
7
|
-
warden.request.
|
|
7
|
+
if warden.request.respond_to?(:reset_csrf_token)
|
|
8
|
+
# Rails 7.1+
|
|
9
|
+
warden.request.reset_csrf_token
|
|
10
|
+
else
|
|
11
|
+
warden.request.session.try(:delete, :_csrf_token)
|
|
12
|
+
end
|
|
8
13
|
end
|
|
9
14
|
end
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
# After each sign in, if resource responds to failed_attempts, sets it to 0
|
|
4
4
|
# This is only triggered when the user is explicitly set (with set_user)
|
|
5
5
|
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
|
6
|
-
if record.respond_to?(:
|
|
7
|
-
|
|
8
|
-
record.failed_attempts = 0
|
|
9
|
-
record.save(validate: false)
|
|
10
|
-
end
|
|
6
|
+
if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
|
|
7
|
+
record.reset_failed_attempts!
|
|
11
8
|
end
|
|
12
9
|
end
|
|
@@ -21,8 +21,8 @@ Warden::Manager.after_set_user do |record, warden, options|
|
|
|
21
21
|
|
|
22
22
|
proxy = Devise::Hooks::Proxy.new(warden)
|
|
23
23
|
|
|
24
|
-
if
|
|
25
|
-
|
|
24
|
+
if !env['devise.skip_timeout'] &&
|
|
25
|
+
record.timedout?(last_request_at) &&
|
|
26
26
|
!proxy.remember_me_is_active?(record)
|
|
27
27
|
Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
|
|
28
28
|
throw :warden, scope: scope, message: :timeout
|
data/lib/devise/mapping.rb
CHANGED
|
@@ -46,7 +46,7 @@ module Devise
|
|
|
46
46
|
raise "Could not find a valid mapping for #{obj.inspect}"
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def self.find_by_path!(path, path_type
|
|
49
|
+
def self.find_by_path!(path, path_type = :fullpath)
|
|
50
50
|
Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
|
|
51
51
|
raise "Could not find a valid mapping for path #{path.inspect}"
|
|
52
52
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'active_model/version'
|
|
4
3
|
require 'devise/hooks/activatable'
|
|
5
4
|
require 'devise/hooks/csrf_cleaner'
|
|
5
|
+
require 'devise/rails/deprecated_constant_accessor'
|
|
6
6
|
|
|
7
7
|
module Devise
|
|
8
8
|
module Models
|
|
@@ -10,7 +10,7 @@ module Devise
|
|
|
10
10
|
#
|
|
11
11
|
# == Options
|
|
12
12
|
#
|
|
13
|
-
# Authenticatable adds the following options to
|
|
13
|
+
# Authenticatable adds the following options to +devise+:
|
|
14
14
|
#
|
|
15
15
|
# * +authentication_keys+: parameters used for authentication. By default [:email].
|
|
16
16
|
#
|
|
@@ -56,11 +56,14 @@ module Devise
|
|
|
56
56
|
module Authenticatable
|
|
57
57
|
extend ActiveSupport::Concern
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
|
|
60
60
|
:remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
|
|
61
61
|
:last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
|
|
62
62
|
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
|
|
63
63
|
|
|
64
|
+
include Devise::DeprecatedConstantAccessor
|
|
65
|
+
deprecate_constant "BLACKLIST_FOR_SERIALIZATION", "Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION"
|
|
66
|
+
|
|
64
67
|
included do
|
|
65
68
|
class_attribute :devise_modules, instance_writer: false
|
|
66
69
|
self.devise_modules ||= []
|
|
@@ -105,12 +108,12 @@ module Devise
|
|
|
105
108
|
# given to :except will simply add names to exempt to Devise internal list.
|
|
106
109
|
def serializable_hash(options = nil)
|
|
107
110
|
options = options.try(:dup) || {}
|
|
108
|
-
options[:except] = Array(options[:except])
|
|
111
|
+
options[:except] = Array(options[:except]).dup
|
|
109
112
|
|
|
110
113
|
if options[:force_except]
|
|
111
114
|
options[:except].concat Array(options[:force_except])
|
|
112
115
|
else
|
|
113
|
-
options[:except].concat
|
|
116
|
+
options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
|
|
114
117
|
end
|
|
115
118
|
|
|
116
119
|
super(options)
|
|
@@ -134,16 +137,18 @@ module Devise
|
|
|
134
137
|
# This is an internal method called every time Devise needs
|
|
135
138
|
# to send a notification/mail. This can be overridden if you
|
|
136
139
|
# need to customize the e-mail delivery logic. For instance,
|
|
137
|
-
# if you are using a queue to deliver e-mails (
|
|
138
|
-
# sidekiq, resque, etc), you must add the delivery to the queue
|
|
140
|
+
# if you are using a queue to deliver e-mails (active job, delayed
|
|
141
|
+
# job, sidekiq, resque, etc), you must add the delivery to the queue
|
|
139
142
|
# just after the transaction was committed. To achieve this,
|
|
140
143
|
# you can override send_devise_notification to store the
|
|
141
|
-
# deliveries until the after_commit callback is triggered
|
|
144
|
+
# deliveries until the after_commit callback is triggered.
|
|
145
|
+
#
|
|
146
|
+
# The following example uses Active Job's `deliver_later` :
|
|
142
147
|
#
|
|
143
148
|
# class User
|
|
144
149
|
# devise :database_authenticatable, :confirmable
|
|
145
150
|
#
|
|
146
|
-
# after_commit :
|
|
151
|
+
# after_commit :send_pending_devise_notifications
|
|
147
152
|
#
|
|
148
153
|
# protected
|
|
149
154
|
#
|
|
@@ -151,39 +156,45 @@ module Devise
|
|
|
151
156
|
# # If the record is new or changed then delay the
|
|
152
157
|
# # delivery until the after_commit callback otherwise
|
|
153
158
|
# # send now because after_commit will not be called.
|
|
154
|
-
#
|
|
155
|
-
#
|
|
159
|
+
# # For Rails < 6 use `changed?` instead of `saved_changes?`.
|
|
160
|
+
# if new_record? || saved_changes?
|
|
161
|
+
# pending_devise_notifications << [notification, args]
|
|
156
162
|
# else
|
|
157
|
-
#
|
|
158
|
-
# Remove once we move to Rails 4.2+ only.
|
|
159
|
-
# if message.respond_to?(:deliver_now)
|
|
160
|
-
# message.deliver_now
|
|
161
|
-
# else
|
|
162
|
-
# message.deliver
|
|
163
|
-
# end
|
|
163
|
+
# render_and_send_devise_message(notification, *args)
|
|
164
164
|
# end
|
|
165
165
|
# end
|
|
166
166
|
#
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
# message.deliver_now
|
|
173
|
-
# else
|
|
174
|
-
# message.deliver
|
|
175
|
-
# end
|
|
167
|
+
# private
|
|
168
|
+
#
|
|
169
|
+
# def send_pending_devise_notifications
|
|
170
|
+
# pending_devise_notifications.each do |notification, args|
|
|
171
|
+
# render_and_send_devise_message(notification, *args)
|
|
176
172
|
# end
|
|
177
173
|
#
|
|
178
174
|
# # Empty the pending notifications array because the
|
|
179
175
|
# # after_commit hook can be called multiple times which
|
|
180
176
|
# # could cause multiple emails to be sent.
|
|
181
|
-
#
|
|
177
|
+
# pending_devise_notifications.clear
|
|
182
178
|
# end
|
|
183
179
|
#
|
|
184
|
-
# def
|
|
185
|
-
# @
|
|
180
|
+
# def pending_devise_notifications
|
|
181
|
+
# @pending_devise_notifications ||= []
|
|
182
|
+
# end
|
|
183
|
+
#
|
|
184
|
+
# def render_and_send_devise_message(notification, *args)
|
|
185
|
+
# message = devise_mailer.send(notification, self, *args)
|
|
186
|
+
#
|
|
187
|
+
# # Deliver later with Active Job's `deliver_later`
|
|
188
|
+
# if message.respond_to?(:deliver_later)
|
|
189
|
+
# message.deliver_later
|
|
190
|
+
# # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
|
|
191
|
+
# elsif message.respond_to?(:deliver_now)
|
|
192
|
+
# message.deliver_now
|
|
193
|
+
# else
|
|
194
|
+
# message.deliver
|
|
195
|
+
# end
|
|
186
196
|
# end
|
|
197
|
+
#
|
|
187
198
|
# end
|
|
188
199
|
#
|
|
189
200
|
def send_devise_notification(notification, *args)
|
|
@@ -265,39 +276,31 @@ module Devise
|
|
|
265
276
|
find_first_by_auth_conditions(tainted_conditions)
|
|
266
277
|
end
|
|
267
278
|
|
|
268
|
-
def find_first_by_auth_conditions(tainted_conditions, opts={})
|
|
279
|
+
def find_first_by_auth_conditions(tainted_conditions, opts = {})
|
|
269
280
|
to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
|
|
270
281
|
end
|
|
271
282
|
|
|
272
283
|
# Find or initialize a record setting an error if it can't be found.
|
|
273
|
-
def find_or_initialize_with_error_by(attribute, value, error
|
|
284
|
+
def find_or_initialize_with_error_by(attribute, value, error = :invalid) #:nodoc:
|
|
274
285
|
find_or_initialize_with_errors([attribute], { attribute => value }, error)
|
|
275
286
|
end
|
|
276
287
|
|
|
277
288
|
# Find or initialize a record with group of attributes based on a list of required attributes.
|
|
278
|
-
def find_or_initialize_with_errors(required_attributes, attributes, error
|
|
279
|
-
attributes
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
end
|
|
284
|
-
attributes.delete_if { |key, value| value.blank? }
|
|
289
|
+
def find_or_initialize_with_errors(required_attributes, attributes, error = :invalid) #:nodoc:
|
|
290
|
+
attributes.try(:permit!)
|
|
291
|
+
attributes = attributes.to_h.with_indifferent_access
|
|
292
|
+
.slice(*required_attributes)
|
|
293
|
+
.delete_if { |key, value| value.blank? }
|
|
285
294
|
|
|
286
295
|
if attributes.size == required_attributes.size
|
|
287
|
-
record = find_first_by_auth_conditions(attributes)
|
|
296
|
+
record = find_first_by_auth_conditions(attributes) and return record
|
|
288
297
|
end
|
|
289
298
|
|
|
290
|
-
|
|
291
|
-
record = new
|
|
292
|
-
|
|
299
|
+
new(devise_parameter_filter.filter(attributes)).tap do |record|
|
|
293
300
|
required_attributes.each do |key|
|
|
294
|
-
|
|
295
|
-
record.send("#{key}=", value)
|
|
296
|
-
record.errors.add(key, value.present? ? error : :blank)
|
|
301
|
+
record.errors.add(key, attributes[key].blank? ? :blank : error)
|
|
297
302
|
end
|
|
298
303
|
end
|
|
299
|
-
|
|
300
|
-
record
|
|
301
304
|
end
|
|
302
305
|
|
|
303
306
|
protected
|
|
@@ -48,7 +48,7 @@ module Devise
|
|
|
48
48
|
included do
|
|
49
49
|
before_create :generate_confirmation_token, if: :confirmation_required?
|
|
50
50
|
after_create :skip_reconfirmation_in_callback!, if: :send_confirmation_notification?
|
|
51
|
-
if
|
|
51
|
+
if Devise::Orm.active_record?(self) # ActiveRecord
|
|
52
52
|
after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
|
|
53
53
|
after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
|
|
54
54
|
else # Mongoid
|
|
@@ -76,7 +76,7 @@ module Devise
|
|
|
76
76
|
# Confirm a user by setting it's confirmed_at to actual time. If the user
|
|
77
77
|
# is already confirmed, add an error to email field. If the user is invalid
|
|
78
78
|
# add errors
|
|
79
|
-
def confirm(args={})
|
|
79
|
+
def confirm(args = {})
|
|
80
80
|
pending_any_confirmation do
|
|
81
81
|
if confirmation_period_expired?
|
|
82
82
|
self.errors.add(:email, :confirmation_period_expired,
|
|
@@ -211,7 +211,10 @@ module Devise
|
|
|
211
211
|
# confirmation_period_valid? # will always return true
|
|
212
212
|
#
|
|
213
213
|
def confirmation_period_valid?
|
|
214
|
-
|
|
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
|
|
215
218
|
end
|
|
216
219
|
|
|
217
220
|
# Checks if the user confirmation happens before the token becomes invalid
|
|
@@ -255,44 +258,23 @@ module Devise
|
|
|
255
258
|
generate_confirmation_token && save(validate: false)
|
|
256
259
|
end
|
|
257
260
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
end
|
|
266
|
-
else
|
|
267
|
-
def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
|
|
268
|
-
@reconfirmation_required = true
|
|
269
|
-
self.unconfirmed_email = self.email
|
|
270
|
-
self.email = self.email_was
|
|
271
|
-
self.confirmation_token = nil
|
|
272
|
-
generate_confirmation_token
|
|
273
|
-
end
|
|
261
|
+
|
|
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.devise_email_in_database
|
|
266
|
+
self.confirmation_token = nil
|
|
267
|
+
generate_confirmation_token
|
|
274
268
|
end
|
|
275
269
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
postpone
|
|
285
|
-
end
|
|
286
|
-
else
|
|
287
|
-
def postpone_email_change?
|
|
288
|
-
postpone = self.class.reconfirmable &&
|
|
289
|
-
email_changed? &&
|
|
290
|
-
!@bypass_confirmation_postpone &&
|
|
291
|
-
self.email.present? &&
|
|
292
|
-
(!@skip_reconfirmation_in_callback || !self.email_was.nil?)
|
|
293
|
-
@bypass_confirmation_postpone = false
|
|
294
|
-
postpone
|
|
295
|
-
end
|
|
270
|
+
def postpone_email_change?
|
|
271
|
+
postpone = self.class.reconfirmable &&
|
|
272
|
+
devise_will_save_change_to_email? &&
|
|
273
|
+
!@bypass_confirmation_postpone &&
|
|
274
|
+
self.email.present? &&
|
|
275
|
+
(!@skip_reconfirmation_in_callback || !self.devise_email_in_database.nil?)
|
|
276
|
+
@bypass_confirmation_postpone = false
|
|
277
|
+
postpone
|
|
296
278
|
end
|
|
297
279
|
|
|
298
280
|
def reconfirmation_required?
|
|
@@ -331,7 +313,7 @@ module Devise
|
|
|
331
313
|
# confirmation instructions to it. If not, try searching for a user by unconfirmed_email
|
|
332
314
|
# field. If no user is found, returns a new user with an email not found error.
|
|
333
315
|
# Options must contain the user email
|
|
334
|
-
def send_confirmation_instructions(attributes={})
|
|
316
|
+
def send_confirmation_instructions(attributes = {})
|
|
335
317
|
confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
|
|
336
318
|
unless confirmable.try(:persisted?)
|
|
337
319
|
confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
|
|
@@ -345,7 +327,19 @@ module Devise
|
|
|
345
327
|
# If the user is already confirmed, create an error for the user
|
|
346
328
|
# Options must have the confirmation_token
|
|
347
329
|
def confirm_by_token(confirmation_token)
|
|
330
|
+
# When the `confirmation_token` parameter is blank, if there are any users with a blank
|
|
331
|
+
# `confirmation_token` in the database, the first one would be confirmed here.
|
|
332
|
+
# The error is being manually added here to ensure no users are confirmed by mistake.
|
|
333
|
+
# This was done in the model for convenience, since validation errors are automatically
|
|
334
|
+
# displayed in the view.
|
|
335
|
+
if confirmation_token.blank?
|
|
336
|
+
confirmable = new
|
|
337
|
+
confirmable.errors.add(:confirmation_token, :blank)
|
|
338
|
+
return confirmable
|
|
339
|
+
end
|
|
340
|
+
|
|
348
341
|
confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
|
|
342
|
+
|
|
349
343
|
unless confirmable
|
|
350
344
|
confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
|
|
351
345
|
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
|
|
@@ -7,9 +7,13 @@ module Devise
|
|
|
7
7
|
# Authenticatable Module, responsible for hashing the password and
|
|
8
8
|
# validating the authenticity of a user while signing in.
|
|
9
9
|
#
|
|
10
|
+
# This module defines a `password=` method. This method will hash the argument
|
|
11
|
+
# and store it in the `encrypted_password` column, bypassing any pre-existing
|
|
12
|
+
# `password` column if it exists.
|
|
13
|
+
#
|
|
10
14
|
# == Options
|
|
11
15
|
#
|
|
12
|
-
# DatabaseAuthenticatable adds the following options to
|
|
16
|
+
# DatabaseAuthenticatable adds the following options to +devise+:
|
|
13
17
|
#
|
|
14
18
|
# * +pepper+: a random string used to provide a more secure hash. Use
|
|
15
19
|
# `rails secret` to generate new keys.
|
|
@@ -35,6 +39,22 @@ module Devise
|
|
|
35
39
|
attr_accessor :password_confirmation
|
|
36
40
|
end
|
|
37
41
|
|
|
42
|
+
def initialize(*args, &block)
|
|
43
|
+
@skip_email_changed_notification = false
|
|
44
|
+
@skip_password_change_notification = false
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Skips sending the email changed notification after_update
|
|
49
|
+
def skip_email_changed_notification!
|
|
50
|
+
@skip_email_changed_notification = true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Skips sending the password change notification after_update
|
|
54
|
+
def skip_password_change_notification!
|
|
55
|
+
@skip_password_change_notification = true
|
|
56
|
+
end
|
|
57
|
+
|
|
38
58
|
def self.required_fields(klass)
|
|
39
59
|
[:encrypted_password] + klass.authentication_keys
|
|
40
60
|
end
|
|
@@ -65,6 +85,15 @@ module Devise
|
|
|
65
85
|
# their password). In case the password field is rejected, the confirmation
|
|
66
86
|
# is also rejected as long as it is also blank.
|
|
67
87
|
def update_with_password(params, *options)
|
|
88
|
+
if options.present?
|
|
89
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
|
|
90
|
+
[Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
|
|
91
|
+
(`options`) is deprecated and it will be removed in the next major version.
|
|
92
|
+
It was added to support a feature deprecated in Rails 4, so you can safely remove it
|
|
93
|
+
from your code.
|
|
94
|
+
DEPRECATION
|
|
95
|
+
end
|
|
96
|
+
|
|
68
97
|
current_password = params.delete(:current_password)
|
|
69
98
|
|
|
70
99
|
if params[:password].blank?
|
|
@@ -73,11 +102,11 @@ module Devise
|
|
|
73
102
|
end
|
|
74
103
|
|
|
75
104
|
result = if valid_password?(current_password)
|
|
76
|
-
|
|
105
|
+
update(params, *options)
|
|
77
106
|
else
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
107
|
+
assign_attributes(params, *options)
|
|
108
|
+
valid?
|
|
109
|
+
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
|
81
110
|
false
|
|
82
111
|
end
|
|
83
112
|
|
|
@@ -98,10 +127,19 @@ module Devise
|
|
|
98
127
|
# end
|
|
99
128
|
#
|
|
100
129
|
def update_without_password(params, *options)
|
|
130
|
+
if options.present?
|
|
131
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
|
|
132
|
+
[Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
|
|
133
|
+
(`options`) is deprecated and it will be removed in the next major version.
|
|
134
|
+
It was added to support a feature deprecated in Rails 4, so you can safely remove it
|
|
135
|
+
from your code.
|
|
136
|
+
DEPRECATION
|
|
137
|
+
end
|
|
138
|
+
|
|
101
139
|
params.delete(:password)
|
|
102
140
|
params.delete(:password_confirmation)
|
|
103
141
|
|
|
104
|
-
result =
|
|
142
|
+
result = update(params, *options)
|
|
105
143
|
clean_up_passwords
|
|
106
144
|
result
|
|
107
145
|
end
|
|
@@ -113,8 +151,8 @@ module Devise
|
|
|
113
151
|
result = if valid_password?(current_password)
|
|
114
152
|
destroy
|
|
115
153
|
else
|
|
116
|
-
|
|
117
|
-
|
|
154
|
+
valid?
|
|
155
|
+
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
|
118
156
|
false
|
|
119
157
|
end
|
|
120
158
|
|
|
@@ -139,16 +177,9 @@ module Devise
|
|
|
139
177
|
encrypted_password[0,29] if encrypted_password
|
|
140
178
|
end
|
|
141
179
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
send_devise_notification(:email_changed, to: email_before_last_save)
|
|
146
|
-
end
|
|
147
|
-
else
|
|
148
|
-
# Send notification to user when email changes.
|
|
149
|
-
def send_email_changed_notification
|
|
150
|
-
send_devise_notification(:email_changed, to: email_was)
|
|
151
|
-
end
|
|
180
|
+
# Send notification to user when email changes.
|
|
181
|
+
def send_email_changed_notification
|
|
182
|
+
send_devise_notification(:email_changed, to: devise_email_before_last_save)
|
|
152
183
|
end
|
|
153
184
|
|
|
154
185
|
# Send notification to user when password changes.
|
|
@@ -161,30 +192,18 @@ module Devise
|
|
|
161
192
|
# Hashes the password using bcrypt. Custom hash functions should override
|
|
162
193
|
# this method to apply their own algorithm.
|
|
163
194
|
#
|
|
164
|
-
# See https://github.com/
|
|
195
|
+
# See https://github.com/heartcombo/devise-encryptable for examples
|
|
165
196
|
# of other hashing engines.
|
|
166
197
|
def password_digest(password)
|
|
167
198
|
Devise::Encryptor.digest(self.class, password)
|
|
168
199
|
end
|
|
169
200
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
self.class.send_email_changed_notification && saved_change_to_email?
|
|
173
|
-
end
|
|
174
|
-
else
|
|
175
|
-
def send_email_changed_notification?
|
|
176
|
-
self.class.send_email_changed_notification && email_changed?
|
|
177
|
-
end
|
|
201
|
+
def send_email_changed_notification?
|
|
202
|
+
self.class.send_email_changed_notification && devise_saved_change_to_email? && !@skip_email_changed_notification
|
|
178
203
|
end
|
|
179
204
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
self.class.send_password_change_notification && saved_change_to_encrypted_password?
|
|
183
|
-
end
|
|
184
|
-
else
|
|
185
|
-
def send_password_change_notification?
|
|
186
|
-
self.class.send_password_change_notification && encrypted_password_changed?
|
|
187
|
-
end
|
|
205
|
+
def send_password_change_notification?
|
|
206
|
+
self.class.send_password_change_notification && devise_saved_change_to_encrypted_password? && !@skip_password_change_notification
|
|
188
207
|
end
|
|
189
208
|
|
|
190
209
|
module ClassMethods
|
|
@@ -18,7 +18,7 @@ module Devise
|
|
|
18
18
|
# * +maximum_attempts+: how many attempts should be accepted before blocking the user.
|
|
19
19
|
# * +lock_strategy+: lock the user account by :failed_attempts or :none.
|
|
20
20
|
# * +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
|
|
21
|
-
# * +unlock_in+: the time you want to
|
|
21
|
+
# * +unlock_in+: the time you want to unlock the user after lock happens. Only available when unlock_strategy is :time or :both.
|
|
22
22
|
# * +unlock_keys+: the keys you want to use when locking and unlocking an account
|
|
23
23
|
#
|
|
24
24
|
module Lockable
|
|
@@ -57,6 +57,14 @@ module Devise
|
|
|
57
57
|
save(validate: false)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
# Resets failed attempts counter to 0.
|
|
61
|
+
def reset_failed_attempts!
|
|
62
|
+
if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
|
|
63
|
+
self.failed_attempts = 0
|
|
64
|
+
save(validate: false)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
60
68
|
# Verifies whether a user is locked or not.
|
|
61
69
|
def access_locked?
|
|
62
70
|
!!locked_at && !lock_expired?
|
|
@@ -110,10 +118,10 @@ module Devise
|
|
|
110
118
|
false
|
|
111
119
|
end
|
|
112
120
|
end
|
|
113
|
-
|
|
121
|
+
|
|
114
122
|
def increment_failed_attempts
|
|
115
|
-
self.failed_attempts
|
|
116
|
-
|
|
123
|
+
self.class.increment_counter(:failed_attempts, id)
|
|
124
|
+
reload
|
|
117
125
|
end
|
|
118
126
|
|
|
119
127
|
def unauthenticated_message
|
|
@@ -168,7 +176,7 @@ module Devise
|
|
|
168
176
|
# unlock instructions to it. If not user is found, returns a new user
|
|
169
177
|
# with an email not found error.
|
|
170
178
|
# Options must contain the user's unlock keys
|
|
171
|
-
def send_unlock_instructions(attributes={})
|
|
179
|
+
def send_unlock_instructions(attributes = {})
|
|
172
180
|
lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
|
|
173
181
|
lockable.resend_unlock_instructions if lockable.persisted?
|
|
174
182
|
lockable
|
|
@@ -8,11 +8,11 @@ module Devise
|
|
|
8
8
|
#
|
|
9
9
|
# == Options
|
|
10
10
|
#
|
|
11
|
-
# Oauthable adds the following options to
|
|
11
|
+
# Oauthable adds the following options to +devise+:
|
|
12
12
|
#
|
|
13
13
|
# * +omniauth_providers+: Which providers are available to this model. It expects an array:
|
|
14
14
|
#
|
|
15
|
-
#
|
|
15
|
+
# devise :database_authenticatable, :omniauthable, omniauth_providers: [:twitter]
|
|
16
16
|
#
|
|
17
17
|
module Omniauthable
|
|
18
18
|
extend ActiveSupport::Concern
|