devise 3.5.10 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +279 -1126
- data/MIT-LICENSE +2 -1
- data/README.md +291 -97
- 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 +25 -12
- data/app/helpers/devise_helper.rb +23 -18
- data/app/mailers/devise/mailer.rb +10 -4
- 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 +8 -8
- data/app/views/devise/unlocks/new.html.erb +2 -2
- data/config/locales/en.yml +5 -2
- data/lib/devise.rb +57 -40
- data/lib/devise/controllers/helpers.rb +30 -27
- 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 +39 -14
- data/lib/devise/controllers/store_location.rb +25 -7
- data/lib/devise/controllers/url_helpers.rb +3 -1
- data/lib/devise/delegator.rb +2 -0
- data/lib/devise/encryptor.rb +6 -4
- data/lib/devise/failure_app.rb +75 -38
- 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 +4 -2
- data/lib/devise/hooks/proxy.rb +3 -1
- data/lib/devise/hooks/rememberable.rb +2 -0
- data/lib/devise/hooks/timeoutable.rb +4 -2
- data/lib/devise/hooks/trackable.rb +2 -0
- data/lib/devise/mailers/helpers.rb +7 -4
- data/lib/devise/mapping.rb +3 -1
- data/lib/devise/models.rb +3 -1
- data/lib/devise/models/authenticatable.rb +63 -33
- data/lib/devise/models/confirmable.rb +90 -29
- data/lib/devise/models/database_authenticatable.rb +93 -22
- data/lib/devise/models/lockable.rb +19 -5
- data/lib/devise/models/omniauthable.rb +2 -0
- data/lib/devise/models/recoverable.rb +33 -21
- data/lib/devise/models/registerable.rb +4 -0
- data/lib/devise/models/rememberable.rb +6 -11
- 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/modules.rb +2 -0
- data/lib/devise/omniauth.rb +4 -5
- data/lib/devise/omniauth/config.rb +2 -0
- data/lib/devise/omniauth/url_helpers.rb +14 -5
- 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.rb +7 -16
- data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
- data/lib/devise/rails/routes.rb +48 -37
- data/lib/devise/rails/warden_compat.rb +3 -10
- 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 +167 -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/generators/active_record/devise_generator.rb +46 -12
- 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 +5 -3
- data/lib/generators/devise/install_generator.rb +18 -5
- data/lib/generators/devise/orm_helpers.rb +10 -21
- data/lib/generators/devise/views_generator.rb +8 -9
- data/lib/generators/mongoid/devise_generator.rb +7 -5
- data/lib/generators/templates/README +9 -8
- data/lib/generators/templates/controllers/confirmations_controller.rb +2 -0
- data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +3 -1
- 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 +63 -21
- 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 +19 -317
- 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.ru +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/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,7 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# After each sign in, if resource responds to failed_attempts, sets it to 0
|
|
2
4
|
# This is only triggered when the user is explicitly set (with set_user)
|
|
3
5
|
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
|
4
|
-
if record.respond_to?(:
|
|
5
|
-
record.
|
|
6
|
+
if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
|
|
7
|
+
record.reset_failed_attempts!
|
|
6
8
|
end
|
|
7
9
|
end
|
data/lib/devise/hooks/proxy.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Devise
|
|
2
4
|
module Hooks
|
|
3
5
|
# A small warden proxy so we can remember, forget and
|
|
@@ -7,7 +9,7 @@ module Devise
|
|
|
7
9
|
include Devise::Controllers::SignInOut
|
|
8
10
|
|
|
9
11
|
attr_reader :warden
|
|
10
|
-
delegate :cookies, :
|
|
12
|
+
delegate :cookies, :request, to: :warden
|
|
11
13
|
|
|
12
14
|
def initialize(warden)
|
|
13
15
|
@warden = warden
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Each time a record is set we check whether its session has already timed out
|
|
2
4
|
# or not, based on last request time. If so, the record is logged out and
|
|
3
5
|
# redirected to the sign in page. Also, each time the request comes and the
|
|
@@ -19,8 +21,8 @@ Warden::Manager.after_set_user do |record, warden, options|
|
|
|
19
21
|
|
|
20
22
|
proxy = Devise::Hooks::Proxy.new(warden)
|
|
21
23
|
|
|
22
|
-
if
|
|
23
|
-
|
|
24
|
+
if !env['devise.skip_timeout'] &&
|
|
25
|
+
record.timedout?(last_request_at) &&
|
|
24
26
|
!proxy.remember_me_is_active?(record)
|
|
25
27
|
Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
|
|
26
28
|
throw :warden, scope: scope, message: :timeout
|
|
@@ -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,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Devise
|
|
2
4
|
# Responsible for handling devise mappings and routes configuration. Each
|
|
3
5
|
# resource configured by devise_for in routes is actually creating a mapping
|
|
@@ -44,7 +46,7 @@ module Devise
|
|
|
44
46
|
raise "Could not find a valid mapping for #{obj.inspect}"
|
|
45
47
|
end
|
|
46
48
|
|
|
47
|
-
def self.find_by_path!(path, path_type
|
|
49
|
+
def self.find_by_path!(path, path_type = :fullpath)
|
|
48
50
|
Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
|
|
49
51
|
raise "Could not find a valid mapping for path #{path.inspect}"
|
|
50
52
|
end
|
data/lib/devise/models.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Devise
|
|
2
4
|
module Models
|
|
3
5
|
class MissingAttribute < StandardError
|
|
@@ -12,7 +14,7 @@ module Devise
|
|
|
12
14
|
|
|
13
15
|
# Creates configuration values for Devise and for the given module.
|
|
14
16
|
#
|
|
15
|
-
# Devise::Models.config(Devise::DatabaseAuthenticatable, :stretches)
|
|
17
|
+
# Devise::Models.config(Devise::Models::DatabaseAuthenticatable, :stretches)
|
|
16
18
|
#
|
|
17
19
|
# The line above creates:
|
|
18
20
|
#
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'devise/hooks/activatable'
|
|
3
4
|
require 'devise/hooks/csrf_cleaner'
|
|
5
|
+
require 'devise/rails/deprecated_constant_accessor'
|
|
4
6
|
|
|
5
7
|
module Devise
|
|
6
8
|
module Models
|
|
@@ -54,11 +56,14 @@ module Devise
|
|
|
54
56
|
module Authenticatable
|
|
55
57
|
extend ActiveSupport::Concern
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
|
|
58
60
|
:remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
|
|
59
61
|
:last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
|
|
60
62
|
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
|
|
61
63
|
|
|
64
|
+
include Devise::DeprecatedConstantAccessor
|
|
65
|
+
deprecate_constant "BLACKLIST_FOR_SERIALIZATION", "Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION"
|
|
66
|
+
|
|
62
67
|
included do
|
|
63
68
|
class_attribute :devise_modules, instance_writer: false
|
|
64
69
|
self.devise_modules ||= []
|
|
@@ -102,18 +107,27 @@ module Devise
|
|
|
102
107
|
# and passing a new list of attributes you want to exempt. All attributes
|
|
103
108
|
# given to :except will simply add names to exempt to Devise internal list.
|
|
104
109
|
def serializable_hash(options = nil)
|
|
105
|
-
options
|
|
106
|
-
options[:except] = Array(options[:except])
|
|
110
|
+
options = options.try(:dup) || {}
|
|
111
|
+
options[:except] = Array(options[:except]).dup
|
|
107
112
|
|
|
108
113
|
if options[:force_except]
|
|
109
114
|
options[:except].concat Array(options[:force_except])
|
|
110
115
|
else
|
|
111
|
-
options[:except].concat
|
|
116
|
+
options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
|
|
112
117
|
end
|
|
113
118
|
|
|
114
119
|
super(options)
|
|
115
120
|
end
|
|
116
121
|
|
|
122
|
+
# Redefine inspect using serializable_hash, to ensure we don't accidentally
|
|
123
|
+
# leak passwords into exceptions.
|
|
124
|
+
def inspect
|
|
125
|
+
inspection = serializable_hash.collect do |k,v|
|
|
126
|
+
"#{k}: #{respond_to?(:attribute_for_inspect) ? attribute_for_inspect(k) : v.inspect}"
|
|
127
|
+
end
|
|
128
|
+
"#<#{self.class} #{inspection.join(", ")}>"
|
|
129
|
+
end
|
|
130
|
+
|
|
117
131
|
protected
|
|
118
132
|
|
|
119
133
|
def devise_mailer
|
|
@@ -123,16 +137,18 @@ module Devise
|
|
|
123
137
|
# This is an internal method called every time Devise needs
|
|
124
138
|
# to send a notification/mail. This can be overridden if you
|
|
125
139
|
# 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
|
|
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
|
|
128
142
|
# just after the transaction was committed. To achieve this,
|
|
129
143
|
# you can override send_devise_notification to store the
|
|
130
|
-
# 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` :
|
|
131
147
|
#
|
|
132
148
|
# class User
|
|
133
149
|
# devise :database_authenticatable, :confirmable
|
|
134
150
|
#
|
|
135
|
-
# after_commit :
|
|
151
|
+
# after_commit :send_pending_devise_notifications
|
|
136
152
|
#
|
|
137
153
|
# protected
|
|
138
154
|
#
|
|
@@ -140,27 +156,45 @@ module Devise
|
|
|
140
156
|
# # If the record is new or changed then delay the
|
|
141
157
|
# # delivery until the after_commit callback otherwise
|
|
142
158
|
# # send now because after_commit will not be called.
|
|
143
|
-
#
|
|
144
|
-
#
|
|
159
|
+
# # For Rails < 6 use `changed?` instead of `saved_changes?`.
|
|
160
|
+
# if new_record? || saved_changes?
|
|
161
|
+
# pending_devise_notifications << [notification, args]
|
|
145
162
|
# else
|
|
146
|
-
#
|
|
163
|
+
# render_and_send_devise_message(notification, *args)
|
|
147
164
|
# end
|
|
148
165
|
# end
|
|
149
166
|
#
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
#
|
|
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)
|
|
153
172
|
# end
|
|
154
173
|
#
|
|
155
174
|
# # Empty the pending notifications array because the
|
|
156
175
|
# # after_commit hook can be called multiple times which
|
|
157
176
|
# # could cause multiple emails to be sent.
|
|
158
|
-
#
|
|
177
|
+
# pending_devise_notifications.clear
|
|
159
178
|
# end
|
|
160
179
|
#
|
|
161
|
-
# def
|
|
162
|
-
# @
|
|
180
|
+
# def pending_devise_notifications
|
|
181
|
+
# @pending_devise_notifications ||= []
|
|
163
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
|
|
196
|
+
# end
|
|
197
|
+
#
|
|
164
198
|
# end
|
|
165
199
|
#
|
|
166
200
|
def send_devise_notification(notification, *args)
|
|
@@ -235,42 +269,38 @@ module Devise
|
|
|
235
269
|
# end
|
|
236
270
|
#
|
|
237
271
|
# Finally, notice that Devise also queries for users in other scenarios
|
|
238
|
-
# besides authentication, for example when retrieving
|
|
272
|
+
# besides authentication, for example when retrieving a user to send
|
|
239
273
|
# an e-mail for password reset. In such cases, find_for_authentication
|
|
240
274
|
# is not called.
|
|
241
275
|
def find_for_authentication(tainted_conditions)
|
|
242
276
|
find_first_by_auth_conditions(tainted_conditions)
|
|
243
277
|
end
|
|
244
278
|
|
|
245
|
-
def find_first_by_auth_conditions(tainted_conditions, opts={})
|
|
279
|
+
def find_first_by_auth_conditions(tainted_conditions, opts = {})
|
|
246
280
|
to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
|
|
247
281
|
end
|
|
248
282
|
|
|
249
283
|
# Find or initialize a record setting an error if it can't be found.
|
|
250
|
-
def find_or_initialize_with_error_by(attribute, value, error
|
|
284
|
+
def find_or_initialize_with_error_by(attribute, value, error = :invalid) #:nodoc:
|
|
251
285
|
find_or_initialize_with_errors([attribute], { attribute => value }, error)
|
|
252
286
|
end
|
|
253
287
|
|
|
254
288
|
# Find or initialize a record with group of attributes based on a list of required attributes.
|
|
255
|
-
def find_or_initialize_with_errors(required_attributes, attributes, error
|
|
256
|
-
attributes
|
|
257
|
-
attributes
|
|
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? }
|
|
258
294
|
|
|
259
295
|
if attributes.size == required_attributes.size
|
|
260
|
-
record = find_first_by_auth_conditions(attributes)
|
|
296
|
+
record = find_first_by_auth_conditions(attributes) and return record
|
|
261
297
|
end
|
|
262
298
|
|
|
263
|
-
|
|
264
|
-
record = new
|
|
265
|
-
|
|
299
|
+
new(devise_parameter_filter.filter(attributes)).tap do |record|
|
|
266
300
|
required_attributes.each do |key|
|
|
267
|
-
|
|
268
|
-
record.send("#{key}=", value)
|
|
269
|
-
record.errors.add(key, value.present? ? error : :blank)
|
|
301
|
+
record.errors.add(key, attributes[key].blank? ? :blank : error)
|
|
270
302
|
end
|
|
271
303
|
end
|
|
272
|
-
|
|
273
|
-
record
|
|
274
304
|
end
|
|
275
305
|
|
|
276
306
|
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
|
|
@@ -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
|
|
@@ -66,7 +76,7 @@ module Devise
|
|
|
66
76
|
# Confirm a user by setting it's confirmed_at to actual time. If the user
|
|
67
77
|
# is already confirmed, add an error to email field. If the user is invalid
|
|
68
78
|
# add errors
|
|
69
|
-
def confirm(args={})
|
|
79
|
+
def confirm(args = {})
|
|
70
80
|
pending_any_confirmation do
|
|
71
81
|
if confirmation_period_expired?
|
|
72
82
|
self.errors.add(:email, :confirmation_period_expired,
|
|
@@ -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.
|
|
@@ -286,7 +334,7 @@ module Devise
|
|
|
286
334
|
# confirmation instructions to it. If not, try searching for a user by unconfirmed_email
|
|
287
335
|
# field. If no user is found, returns a new user with an email not found error.
|
|
288
336
|
# Options must contain the user email
|
|
289
|
-
def send_confirmation_instructions(attributes={})
|
|
337
|
+
def send_confirmation_instructions(attributes = {})
|
|
290
338
|
confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
|
|
291
339
|
unless confirmable.try(:persisted?)
|
|
292
340
|
confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
|
|
@@ -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)
|