devise 3.5.3 → 4.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +256 -1099
- data/MIT-LICENSE +1 -1
- data/README.md +254 -67
- data/app/controllers/devise/confirmations_controller.rb +3 -1
- data/app/controllers/devise/omniauth_callbacks_controller.rb +8 -6
- data/app/controllers/devise/passwords_controller.rb +7 -4
- data/app/controllers/devise/registrations_controller.rb +39 -18
- data/app/controllers/devise/sessions_controller.rb +9 -7
- data/app/controllers/devise/unlocks_controller.rb +4 -2
- data/app/controllers/devise_controller.rb +23 -10
- data/app/helpers/devise_helper.rb +12 -19
- data/app/mailers/devise/mailer.rb +6 -0
- data/app/views/devise/confirmations/new.html.erb +2 -2
- data/app/views/devise/mailer/email_changed.html.erb +7 -0
- data/app/views/devise/passwords/edit.html.erb +3 -3
- data/app/views/devise/passwords/new.html.erb +2 -2
- data/app/views/devise/registrations/edit.html.erb +9 -5
- data/app/views/devise/registrations/new.html.erb +4 -4
- data/app/views/devise/sessions/new.html.erb +4 -4
- data/app/views/devise/shared/_error_messages.html.erb +15 -0
- data/app/views/devise/shared/_links.html.erb +7 -7
- data/app/views/devise/unlocks/new.html.erb +2 -2
- data/config/locales/en.yml +4 -1
- data/lib/devise/controllers/helpers.rb +23 -20
- data/lib/devise/controllers/rememberable.rb +11 -2
- data/lib/devise/controllers/scoped_views.rb +2 -0
- data/lib/devise/controllers/sign_in_out.rb +34 -11
- data/lib/devise/controllers/store_location.rb +25 -7
- data/lib/devise/controllers/url_helpers.rb +2 -0
- data/lib/devise/delegator.rb +2 -0
- data/lib/devise/encryptor.rb +6 -4
- data/lib/devise/failure_app.rb +75 -37
- data/lib/devise/hooks/activatable.rb +2 -0
- data/lib/devise/hooks/csrf_cleaner.rb +2 -0
- data/lib/devise/hooks/forgetable.rb +2 -0
- data/lib/devise/hooks/lockable.rb +6 -1
- data/lib/devise/hooks/proxy.rb +3 -1
- data/lib/devise/hooks/rememberable.rb +2 -0
- data/lib/devise/hooks/timeoutable.rb +5 -2
- 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 +89 -27
- data/lib/devise/models/database_authenticatable.rb +88 -21
- data/lib/devise/models/lockable.rb +15 -5
- data/lib/devise/models/omniauthable.rb +2 -0
- data/lib/devise/models/recoverable.rb +32 -20
- 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 +44 -33
- data/lib/devise/rails/warden_compat.rb +3 -10
- data/lib/devise/rails.rb +7 -16
- data/lib/devise/secret_key_finder.rb +27 -0
- data/lib/devise/strategies/authenticatable.rb +3 -1
- data/lib/devise/strategies/base.rb +2 -0
- data/lib/devise/strategies/database_authenticatable.rb +11 -4
- data/lib/devise/strategies/rememberable.rb +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 +61 -40
- data/lib/generators/active_record/devise_generator.rb +29 -10
- data/lib/generators/active_record/templates/migration.rb +4 -2
- data/lib/generators/active_record/templates/migration_existing.rb +4 -2
- data/lib/generators/devise/controllers_generator.rb +3 -1
- data/lib/generators/devise/devise_generator.rb +4 -2
- data/lib/generators/devise/install_generator.rb +17 -0
- data/lib/generators/devise/orm_helpers.rb +10 -21
- data/lib/generators/devise/views_generator.rb +7 -8
- data/lib/generators/mongoid/devise_generator.rb +7 -5
- data/lib/generators/templates/README +1 -8
- data/lib/generators/templates/controllers/confirmations_controller.rb +2 -0
- data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +2 -0
- data/lib/generators/templates/controllers/passwords_controller.rb +2 -0
- data/lib/generators/templates/controllers/registrations_controller.rb +6 -4
- data/lib/generators/templates/controllers/sessions_controller.rb +4 -2
- data/lib/generators/templates/controllers/unlocks_controller.rb +2 -0
- data/lib/generators/templates/devise.rb +50 -20
- data/lib/generators/templates/markerb/email_changed.markerb +7 -0
- data/lib/generators/templates/markerb/password_change.markerb +2 -2
- data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +5 -1
- data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +10 -2
- data/lib/generators/templates/simple_form_for/passwords/new.html.erb +4 -1
- data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +11 -3
- data/lib/generators/templates/simple_form_for/registrations/new.html.erb +11 -3
- data/lib/generators/templates/simple_form_for/sessions/new.html.erb +7 -2
- data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +4 -1
- metadata +13 -310
- 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 -29
- data/Gemfile.lock +0 -183
- 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 -29
- data/gemfiles/Gemfile.rails-4.0-stable.lock +0 -166
- data/gemfiles/Gemfile.rails-4.1-stable +0 -29
- data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -172
- data/gemfiles/Gemfile.rails-4.2-stable +0 -29
- data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -194
- 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 -176
- 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 -489
- data/test/models/database_authenticatable_test.rb +0 -269
- data/test/models/lockable_test.rb +0 -328
- 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 -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 -153
- data/test/omniauth/config_test.rb +0 -57
- data/test/omniauth/url_helpers_test.rb +0 -54
- data/test/orm/active_record.rb +0 -10
- data/test/orm/mongoid.rb +0 -13
- data/test/parameter_sanitizer_test.rb +0 -81
- data/test/rails_app/Rakefile +0 -6
- data/test/rails_app/app/active_record/admin.rb +0 -6
- data/test/rails_app/app/active_record/shim.rb +0 -2
- data/test/rails_app/app/active_record/user.rb +0 -6
- data/test/rails_app/app/active_record/user_on_engine.rb +0 -7
- data/test/rails_app/app/active_record/user_on_main_app.rb +0 -7
- data/test/rails_app/app/active_record/user_without_email.rb +0 -8
- data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
- data/test/rails_app/app/controllers/admins_controller.rb +0 -6
- data/test/rails_app/app/controllers/application_controller.rb +0 -12
- data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -30
- data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -31
- data/test/rails_app/app/controllers/home_controller.rb +0 -25
- data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
- data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
- data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
- data/test/rails_app/app/controllers/users_controller.rb +0 -31
- data/test/rails_app/app/helpers/application_helper.rb +0 -3
- data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -3
- data/test/rails_app/app/mailers/users/mailer.rb +0 -3
- data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -4
- data/test/rails_app/app/mongoid/admin.rb +0 -29
- data/test/rails_app/app/mongoid/shim.rb +0 -23
- data/test/rails_app/app/mongoid/user.rb +0 -39
- data/test/rails_app/app/mongoid/user_on_engine.rb +0 -39
- data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -39
- data/test/rails_app/app/mongoid/user_without_email.rb +0 -33
- data/test/rails_app/app/views/admins/index.html.erb +0 -1
- data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
- data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
- data/test/rails_app/app/views/home/index.html.erb +0 -1
- data/test/rails_app/app/views/home/join.html.erb +0 -1
- data/test/rails_app/app/views/home/private.html.erb +0 -1
- data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
- data/test/rails_app/app/views/layouts/application.html.erb +0 -24
- data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
- data/test/rails_app/app/views/users/index.html.erb +0 -1
- data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
- data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
- data/test/rails_app/bin/bundle +0 -3
- data/test/rails_app/bin/rails +0 -4
- data/test/rails_app/bin/rake +0 -4
- data/test/rails_app/config/application.rb +0 -40
- data/test/rails_app/config/boot.rb +0 -14
- data/test/rails_app/config/database.yml +0 -18
- data/test/rails_app/config/environment.rb +0 -5
- data/test/rails_app/config/environments/development.rb +0 -30
- data/test/rails_app/config/environments/production.rb +0 -84
- data/test/rails_app/config/environments/test.rb +0 -41
- data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
- data/test/rails_app/config/initializers/devise.rb +0 -180
- data/test/rails_app/config/initializers/inflections.rb +0 -2
- data/test/rails_app/config/initializers/secret_token.rb +0 -8
- data/test/rails_app/config/initializers/session_store.rb +0 -1
- data/test/rails_app/config/routes.rb +0 -125
- data/test/rails_app/config.ru +0 -4
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -71
- data/test/rails_app/db/schema.rb +0 -55
- data/test/rails_app/lib/shared_admin.rb +0 -17
- data/test/rails_app/lib/shared_user.rb +0 -29
- data/test/rails_app/lib/shared_user_without_email.rb +0 -26
- data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -13
- data/test/rails_app/public/404.html +0 -26
- data/test/rails_app/public/422.html +0 -26
- data/test/rails_app/public/500.html +0 -26
- data/test/rails_app/public/favicon.ico +0 -0
- data/test/rails_test.rb +0 -9
- data/test/routes_test.rb +0 -264
- data/test/support/action_controller/record_identifier.rb +0 -10
- data/test/support/assertions.rb +0 -39
- data/test/support/helpers.rb +0 -77
- data/test/support/integration.rb +0 -92
- data/test/support/locale/en.yml +0 -8
- data/test/support/mongoid.yml +0 -6
- data/test/support/webrat/integrations/rails.rb +0 -24
- data/test/test_helper.rb +0 -34
- data/test/test_helpers_test.rb +0 -178
- data/test/test_models.rb +0 -33
| @@ -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
         | 
| @@ -24,9 +26,11 @@ module Devise | |
| 24 26 | 
             
                #     By default allow_unconfirmed_access_for is zero, it means users always have to confirm to sign in.
         | 
| 25 27 | 
             
                #   * +reconfirmable+: requires any email changes to be confirmed (exactly the same way as
         | 
| 26 28 | 
             
                #     initial account confirmation) to be applied. Requires additional unconfirmed_email
         | 
| 27 | 
            -
                #     db field to be  | 
| 29 | 
            +
                #     db field to be set up (t.reconfirmable in migrations). Until confirmed, new email is
         | 
| 28 30 | 
             
                #     stored in unconfirmed email column, and copied to email column on successful
         | 
| 29 | 
            -
                #     confirmation.
         | 
| 31 | 
            +
                #     confirmation. Also, when used in conjunction with `send_email_changed_notification`,
         | 
| 32 | 
            +
                #     the notification is sent to the original email when the change is requested,
         | 
| 33 | 
            +
                #     not when the unconfirmed email is confirmed.
         | 
| 30 34 | 
             
                #   * +confirm_within+: the time before a sent confirmation token becomes invalid.
         | 
| 31 35 | 
             
                #     You can use this to force the user to confirm within a set period of time.
         | 
| 32 36 | 
             
                #     Confirmable will not generate a new token if a repeat confirmation is requested
         | 
| @@ -40,17 +44,23 @@ module Devise | |
| 40 44 | 
             
                #
         | 
| 41 45 | 
             
                module Confirmable
         | 
| 42 46 | 
             
                  extend ActiveSupport::Concern
         | 
| 43 | 
            -
                  include ActionView::Helpers::DateHelper
         | 
| 44 47 |  | 
| 45 48 | 
             
                  included do
         | 
| 46 49 | 
             
                    before_create :generate_confirmation_token, if: :confirmation_required?
         | 
| 47 | 
            -
                    after_create | 
| 50 | 
            +
                    after_create :skip_reconfirmation_in_callback!, if: :send_confirmation_notification?
         | 
| 51 | 
            +
                    if defined?(ActiveRecord) && self < ActiveRecord::Base # ActiveRecord
         | 
| 52 | 
            +
                      after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
         | 
| 53 | 
            +
                      after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
         | 
| 54 | 
            +
                    else # Mongoid
         | 
| 55 | 
            +
                      after_create :send_on_create_confirmation_instructions, if: :send_confirmation_notification?
         | 
| 56 | 
            +
                      after_update :send_reconfirmation_instructions, if: :reconfirmation_required?
         | 
| 57 | 
            +
                    end
         | 
| 48 58 | 
             
                    before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, if: :postpone_email_change?
         | 
| 49 | 
            -
                    after_update  :send_reconfirmation_instructions,  if: :reconfirmation_required?
         | 
| 50 59 | 
             
                  end
         | 
| 51 60 |  | 
| 52 61 | 
             
                  def initialize(*args, &block)
         | 
| 53 62 | 
             
                    @bypass_confirmation_postpone = false
         | 
| 63 | 
            +
                    @skip_reconfirmation_in_callback = false
         | 
| 54 64 | 
             
                    @reconfirmation_required = false
         | 
| 55 65 | 
             
                    @skip_confirmation_notification = false
         | 
| 56 66 | 
             
                    @raw_confirmation_token = nil
         | 
| @@ -76,7 +86,7 @@ module Devise | |
| 76 86 |  | 
| 77 87 | 
             
                      self.confirmed_at = Time.now.utc
         | 
| 78 88 |  | 
| 79 | 
            -
                      saved = if  | 
| 89 | 
            +
                      saved = if pending_reconfirmation?
         | 
| 80 90 | 
             
                        skip_reconfirmation!
         | 
| 81 91 | 
             
                        self.email = unconfirmed_email
         | 
| 82 92 | 
             
                        self.unconfirmed_email = nil
         | 
| @@ -92,11 +102,6 @@ module Devise | |
| 92 102 | 
             
                    end
         | 
| 93 103 | 
             
                  end
         | 
| 94 104 |  | 
| 95 | 
            -
                  def confirm!(args={})
         | 
| 96 | 
            -
                    ActiveSupport::Deprecation.warn "confirm! is deprecated in favor of confirm"
         | 
| 97 | 
            -
                    confirm(args)
         | 
| 98 | 
            -
                  end
         | 
| 99 | 
            -
             | 
| 100 105 | 
             
                  # Verifies whether a user is confirmed or not
         | 
| 101 106 | 
             
                  def confirmed?
         | 
| 102 107 | 
             
                    !!confirmed_at
         | 
| @@ -165,6 +170,12 @@ 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.
         | 
| @@ -180,7 +191,7 @@ module Devise | |
| 180 191 | 
             
                    # Checks if the confirmation for the user is within the limit time.
         | 
| 181 192 | 
             
                    # We do this by calculating if the difference between today and the
         | 
| 182 193 | 
             
                    # confirmation sent date does not exceed the confirm in time configured.
         | 
| 183 | 
            -
                    #  | 
| 194 | 
            +
                    # allow_unconfirmed_access_for is a model configuration, must always be an integer value.
         | 
| 184 195 | 
             
                    #
         | 
| 185 196 | 
             
                    # Example:
         | 
| 186 197 | 
             
                    #
         | 
| @@ -200,7 +211,10 @@ module Devise | |
| 200 211 | 
             
                    #   confirmation_period_valid?   # will always return true
         | 
| 201 212 | 
             
                    #
         | 
| 202 213 | 
             
                    def confirmation_period_valid?
         | 
| 203 | 
            -
                       | 
| 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
         | 
| 204 218 | 
             
                    end
         | 
| 205 219 |  | 
| 206 220 | 
             
                    # Checks if the user confirmation happens before the token becomes invalid
         | 
| @@ -216,7 +230,7 @@ module Devise | |
| 216 230 | 
             
                    #   confirmation_period_expired?  # will always return false
         | 
| 217 231 | 
             
                    #
         | 
| 218 232 | 
             
                    def confirmation_period_expired?
         | 
| 219 | 
            -
                      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)
         | 
| 220 234 | 
             
                    end
         | 
| 221 235 |  | 
| 222 236 | 
             
                    # Checks whether the record requires any confirmation.
         | 
| @@ -235,8 +249,7 @@ module Devise | |
| 235 249 | 
             
                      if self.confirmation_token && !confirmation_period_expired?
         | 
| 236 250 | 
             
                        @raw_confirmation_token = self.confirmation_token
         | 
| 237 251 | 
             
                      else
         | 
| 238 | 
            -
                         | 
| 239 | 
            -
                        self.confirmation_token = @raw_confirmation_token = raw
         | 
| 252 | 
            +
                        self.confirmation_token = @raw_confirmation_token = Devise.friendly_token
         | 
| 240 253 | 
             
                        self.confirmation_sent_at = Time.now.utc
         | 
| 241 254 | 
             
                      end
         | 
| 242 255 | 
             
                    end
         | 
| @@ -245,28 +258,64 @@ module Devise | |
| 245 258 | 
             
                      generate_confirmation_token && save(validate: false)
         | 
| 246 259 | 
             
                    end
         | 
| 247 260 |  | 
| 248 | 
            -
                     | 
| 249 | 
            -
                       | 
| 250 | 
            -
             | 
| 251 | 
            -
             | 
| 252 | 
            -
             | 
| 253 | 
            -
             | 
| 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
         | 
| 254 277 | 
             
                    end
         | 
| 255 278 |  | 
| 256 | 
            -
                     | 
| 257 | 
            -
                       | 
| 258 | 
            -
             | 
| 259 | 
            -
             | 
| 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
         | 
| 260 299 | 
             
                    end
         | 
| 261 300 |  | 
| 262 301 | 
             
                    def reconfirmation_required?
         | 
| 263 | 
            -
                      self.class.reconfirmable && @reconfirmation_required && self.email.present?
         | 
| 302 | 
            +
                      self.class.reconfirmable && @reconfirmation_required && (self.email.present? || self.unconfirmed_email.present?)
         | 
| 264 303 | 
             
                    end
         | 
| 265 304 |  | 
| 266 305 | 
             
                    def send_confirmation_notification?
         | 
| 267 306 | 
             
                      confirmation_required? && !@skip_confirmation_notification && self.email.present?
         | 
| 268 307 | 
             
                    end
         | 
| 269 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 | 
            +
             | 
| 270 319 | 
             
                    # A callback initiated after successfully confirming. This can be
         | 
| 271 320 | 
             
                    # used to insert your own logic that is only run after the user successfully
         | 
| 272 321 | 
             
                    # confirms.
         | 
| @@ -299,7 +348,19 @@ module Devise | |
| 299 348 | 
             
                    # If the user is already confirmed, create an error for the user
         | 
| 300 349 | 
             
                    # Options must have the confirmation_token
         | 
| 301 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 | 
            +
             | 
| 302 362 | 
             
                      confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
         | 
| 363 | 
            +
             | 
| 303 364 | 
             
                      unless confirmable
         | 
| 304 365 | 
             
                        confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
         | 
| 305 366 | 
             
                        confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
         | 
| @@ -315,6 +376,7 @@ module Devise | |
| 315 376 |  | 
| 316 377 | 
             
                    # Find a record for confirmation by unconfirmed email field
         | 
| 317 378 | 
             
                    def find_by_unconfirmed_email_with_errors(attributes = {})
         | 
| 379 | 
            +
                      attributes = attributes.slice(*confirmation_keys).permit!.to_h if attributes.respond_to? :permit
         | 
| 318 380 | 
             
                      unconfirmed_required_attributes = confirmation_keys.map { |k| k == :email ? :unconfirmed_email : k }
         | 
| 319 381 | 
             
                      unconfirmed_attributes = attributes.symbolize_keys
         | 
| 320 382 | 
             
                      unconfirmed_attributes[:unconfirmed_email] = unconfirmed_attributes.delete(:email)
         | 
| @@ -1,24 +1,25 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require 'devise/strategies/database_authenticatable'
         | 
| 2 4 |  | 
| 3 5 | 
             
            module Devise
         | 
| 4 | 
            -
              def self.bcrypt(klass, password)
         | 
| 5 | 
            -
                ActiveSupport::Deprecation.warn "Devise.bcrypt is deprecated; use Devise::Encryptor.digest instead"
         | 
| 6 | 
            -
                Devise::Encryptor.digest(klass, password)
         | 
| 7 | 
            -
              end
         | 
| 8 | 
            -
             | 
| 9 6 | 
             
              module Models
         | 
| 10 | 
            -
                # Authenticatable Module, responsible for  | 
| 11 | 
            -
                # authenticity of a user while signing in.
         | 
| 7 | 
            +
                # Authenticatable Module, responsible for hashing the password and
         | 
| 8 | 
            +
                # validating the authenticity of a user while signing in.
         | 
| 12 9 | 
             
                #
         | 
| 13 10 | 
             
                # == Options
         | 
| 14 11 | 
             
                #
         | 
| 15 12 | 
             
                # DatabaseAuthenticatable adds the following options to devise_for:
         | 
| 16 13 | 
             
                #
         | 
| 17 14 | 
             
                #   * +pepper+: a random string used to provide a more secure hash. Use
         | 
| 18 | 
            -
                #     ` | 
| 15 | 
            +
                #     `rails secret` to generate new keys.
         | 
| 19 16 | 
             
                #
         | 
| 20 17 | 
             
                #   * +stretches+: the cost given to bcrypt.
         | 
| 21 18 | 
             
                #
         | 
| 19 | 
            +
                #   * +send_email_changed_notification+: notify original email when it changes.
         | 
| 20 | 
            +
                #
         | 
| 21 | 
            +
                #   * +send_password_change_notification+: notify email when password changes.
         | 
| 22 | 
            +
                #
         | 
| 22 23 | 
             
                # == Examples
         | 
| 23 24 | 
             
                #
         | 
| 24 25 | 
             
                #    User.find(1).valid_password?('password123')         # returns true/false
         | 
| @@ -27,17 +28,36 @@ module Devise | |
| 27 28 | 
             
                  extend ActiveSupport::Concern
         | 
| 28 29 |  | 
| 29 30 | 
             
                  included do
         | 
| 31 | 
            +
                    after_update :send_email_changed_notification, if: :send_email_changed_notification?
         | 
| 30 32 | 
             
                    after_update :send_password_change_notification, if: :send_password_change_notification?
         | 
| 31 33 |  | 
| 32 34 | 
             
                    attr_reader :password, :current_password
         | 
| 33 35 | 
             
                    attr_accessor :password_confirmation
         | 
| 34 36 | 
             
                  end
         | 
| 35 37 |  | 
| 38 | 
            +
                  def initialize(*args, &block)
         | 
| 39 | 
            +
                    @skip_email_changed_notification = false
         | 
| 40 | 
            +
                    @skip_password_change_notification = false
         | 
| 41 | 
            +
                    super 
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  # Skips sending the email changed notification after_update
         | 
| 45 | 
            +
                  def skip_email_changed_notification!
         | 
| 46 | 
            +
                    @skip_email_changed_notification = true
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  # Skips sending the password change notification after_update
         | 
| 50 | 
            +
                  def skip_password_change_notification!
         | 
| 51 | 
            +
                    @skip_password_change_notification = true
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 36 54 | 
             
                  def self.required_fields(klass)
         | 
| 37 55 | 
             
                    [:encrypted_password] + klass.authentication_keys
         | 
| 38 56 | 
             
                  end
         | 
| 39 57 |  | 
| 40 | 
            -
                  # Generates password  | 
| 58 | 
            +
                  # Generates a hashed password based on the given value.
         | 
| 59 | 
            +
                  # For legacy reasons, we use `encrypted_password` to store
         | 
| 60 | 
            +
                  # the hashed password.
         | 
| 41 61 | 
             
                  def password=(new_password)
         | 
| 42 62 | 
             
                    @password = new_password
         | 
| 43 63 | 
             
                    self.encrypted_password = password_digest(@password) if @password.present?
         | 
| @@ -61,6 +81,15 @@ module Devise | |
| 61 81 | 
             
                  # their password). In case the password field is rejected, the confirmation
         | 
| 62 82 | 
             
                  # is also rejected as long as it is also blank.
         | 
| 63 83 | 
             
                  def update_with_password(params, *options)
         | 
| 84 | 
            +
                    if options.present?
         | 
| 85 | 
            +
                      ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
         | 
| 86 | 
            +
                        [Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
         | 
| 87 | 
            +
                        (`options`) is deprecated and it will be removed in the next major version.
         | 
| 88 | 
            +
                        It was added to support a feature deprecated in Rails 4, so you can safely remove it
         | 
| 89 | 
            +
                        from your code.
         | 
| 90 | 
            +
                      DEPRECATION
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
             | 
| 64 93 | 
             
                    current_password = params.delete(:current_password)
         | 
| 65 94 |  | 
| 66 95 | 
             
                    if params[:password].blank?
         | 
| @@ -69,11 +98,11 @@ module Devise | |
| 69 98 | 
             
                    end
         | 
| 70 99 |  | 
| 71 100 | 
             
                    result = if valid_password?(current_password)
         | 
| 72 | 
            -
                       | 
| 101 | 
            +
                      update(params, *options)
         | 
| 73 102 | 
             
                    else
         | 
| 74 | 
            -
                       | 
| 75 | 
            -
                       | 
| 76 | 
            -
                       | 
| 103 | 
            +
                      assign_attributes(params, *options)
         | 
| 104 | 
            +
                      valid?
         | 
| 105 | 
            +
                      errors.add(:current_password, current_password.blank? ? :blank : :invalid)
         | 
| 77 106 | 
             
                      false
         | 
| 78 107 | 
             
                    end
         | 
| 79 108 |  | 
| @@ -94,10 +123,19 @@ module Devise | |
| 94 123 | 
             
                  #   end
         | 
| 95 124 | 
             
                  #
         | 
| 96 125 | 
             
                  def update_without_password(params, *options)
         | 
| 126 | 
            +
                    if options.present?
         | 
| 127 | 
            +
                      ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
         | 
| 128 | 
            +
                        [Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
         | 
| 129 | 
            +
                        (`options`) is deprecated and it will be removed in the next major version.
         | 
| 130 | 
            +
                        It was added to support a feature deprecated in Rails 4, so you can safely remove it
         | 
| 131 | 
            +
                        from your code.
         | 
| 132 | 
            +
                      DEPRECATION
         | 
| 133 | 
            +
                    end
         | 
| 134 | 
            +
             | 
| 97 135 | 
             
                    params.delete(:password)
         | 
| 98 136 | 
             
                    params.delete(:password_confirmation)
         | 
| 99 137 |  | 
| 100 | 
            -
                    result =  | 
| 138 | 
            +
                    result = update(params, *options)
         | 
| 101 139 | 
             
                    clean_up_passwords
         | 
| 102 140 | 
             
                    result
         | 
| 103 141 | 
             
                  end
         | 
| @@ -109,8 +147,8 @@ module Devise | |
| 109 147 | 
             
                    result = if valid_password?(current_password)
         | 
| 110 148 | 
             
                      destroy
         | 
| 111 149 | 
             
                    else
         | 
| 112 | 
            -
                       | 
| 113 | 
            -
                       | 
| 150 | 
            +
                      valid?
         | 
| 151 | 
            +
                      errors.add(:current_password, current_password.blank? ? :blank : :invalid)
         | 
| 114 152 | 
             
                      false
         | 
| 115 153 | 
             
                    end
         | 
| 116 154 |  | 
| @@ -135,27 +173,56 @@ module Devise | |
| 135 173 | 
             
                    encrypted_password[0,29] if encrypted_password
         | 
| 136 174 | 
             
                  end
         | 
| 137 175 |  | 
| 176 | 
            +
                  if Devise.activerecord51?
         | 
| 177 | 
            +
                    # Send notification to user when email changes.
         | 
| 178 | 
            +
                    def send_email_changed_notification
         | 
| 179 | 
            +
                      send_devise_notification(:email_changed, to: email_before_last_save)
         | 
| 180 | 
            +
                    end
         | 
| 181 | 
            +
                  else
         | 
| 182 | 
            +
                    # Send notification to user when email changes.
         | 
| 183 | 
            +
                    def send_email_changed_notification
         | 
| 184 | 
            +
                      send_devise_notification(:email_changed, to: email_was)
         | 
| 185 | 
            +
                    end
         | 
| 186 | 
            +
                  end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                  # Send notification to user when password changes.
         | 
| 138 189 | 
             
                  def send_password_change_notification
         | 
| 139 190 | 
             
                    send_devise_notification(:password_change)
         | 
| 140 191 | 
             
                  end
         | 
| 141 192 |  | 
| 142 193 | 
             
                protected
         | 
| 143 194 |  | 
| 144 | 
            -
                  #  | 
| 195 | 
            +
                  # Hashes the password using bcrypt. Custom hash functions should override
         | 
| 145 196 | 
             
                  # this method to apply their own algorithm.
         | 
| 146 197 | 
             
                  #
         | 
| 147 198 | 
             
                  # See https://github.com/plataformatec/devise-encryptable for examples
         | 
| 148 | 
            -
                  # of other  | 
| 199 | 
            +
                  # of other hashing engines.
         | 
| 149 200 | 
             
                  def password_digest(password)
         | 
| 150 201 | 
             
                    Devise::Encryptor.digest(self.class, password)
         | 
| 151 202 | 
             
                  end
         | 
| 152 203 |  | 
| 153 | 
            -
                   | 
| 154 | 
            -
                     | 
| 204 | 
            +
                  if Devise.activerecord51?
         | 
| 205 | 
            +
                    def send_email_changed_notification?
         | 
| 206 | 
            +
                      self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
         | 
| 207 | 
            +
                    end
         | 
| 208 | 
            +
                  else
         | 
| 209 | 
            +
                    def send_email_changed_notification?
         | 
| 210 | 
            +
                      self.class.send_email_changed_notification && email_changed? && !@skip_email_changed_notification
         | 
| 211 | 
            +
                    end
         | 
| 212 | 
            +
                  end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                  if Devise.activerecord51?
         | 
| 215 | 
            +
                    def send_password_change_notification?
         | 
| 216 | 
            +
                      self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
         | 
| 217 | 
            +
                    end
         | 
| 218 | 
            +
                  else
         | 
| 219 | 
            +
                    def send_password_change_notification?
         | 
| 220 | 
            +
                      self.class.send_password_change_notification && encrypted_password_changed? && !@skip_password_change_notification
         | 
| 221 | 
            +
                    end
         | 
| 155 222 | 
             
                  end
         | 
| 156 223 |  | 
| 157 224 | 
             
                  module ClassMethods
         | 
| 158 | 
            -
                    Devise::Models.config(self, :pepper, :stretches, :send_password_change_notification)
         | 
| 225 | 
            +
                    Devise::Models.config(self, :pepper, :stretches, :send_email_changed_notification, :send_password_change_notification)
         | 
| 159 226 |  | 
| 160 227 | 
             
                    # We assume this method already gets the sanitized values from the
         | 
| 161 228 | 
             
                    # DatabaseAuthenticatable strategy. If you are using this method on
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require "devise/hooks/lockable"
         | 
| 2 4 |  | 
| 3 5 | 
             
            module Devise
         | 
| @@ -7,7 +9,7 @@ module Devise | |
| 7 9 | 
             
                # blocked: email and time. The former will send an email to the user when
         | 
| 8 10 | 
             
                # the lock happens, containing a link to unlock its account. The second
         | 
| 9 11 | 
             
                # will unlock the user automatically after some configured time (ie 2.hours).
         | 
| 10 | 
            -
                # It's also possible to  | 
| 12 | 
            +
                # It's also possible to set up lockable to use both email and time strategies.
         | 
| 11 13 | 
             
                #
         | 
| 12 14 | 
             
                # == Options
         | 
| 13 15 | 
             
                #
         | 
| @@ -64,7 +66,7 @@ module Devise | |
| 64 66 | 
             
                  def send_unlock_instructions
         | 
| 65 67 | 
             
                    raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
         | 
| 66 68 | 
             
                    self.unlock_token = enc
         | 
| 67 | 
            -
                     | 
| 69 | 
            +
                    save(validate: false)
         | 
| 68 70 | 
             
                    send_devise_notification(:unlock_instructions, raw, {})
         | 
| 69 71 | 
             
                    raw
         | 
| 70 72 | 
             
                  end
         | 
| @@ -99,8 +101,7 @@ module Devise | |
| 99 101 | 
             
                    if super && !access_locked?
         | 
| 100 102 | 
             
                      true
         | 
| 101 103 | 
             
                    else
         | 
| 102 | 
            -
                       | 
| 103 | 
            -
                      self.failed_attempts += 1
         | 
| 104 | 
            +
                      increment_failed_attempts
         | 
| 104 105 | 
             
                      if attempts_exceeded?
         | 
| 105 106 | 
             
                        lock_access! unless access_locked?
         | 
| 106 107 | 
             
                      else
         | 
| @@ -109,6 +110,11 @@ module Devise | |
| 109 110 | 
             
                      false
         | 
| 110 111 | 
             
                    end
         | 
| 111 112 | 
             
                  end
         | 
| 113 | 
            +
                  
         | 
| 114 | 
            +
                  def increment_failed_attempts
         | 
| 115 | 
            +
                    self.class.increment_counter(:failed_attempts, id)
         | 
| 116 | 
            +
                    reload
         | 
| 117 | 
            +
                  end
         | 
| 112 118 |  | 
| 113 119 | 
             
                  def unauthenticated_message
         | 
| 114 120 | 
             
                    # If set to paranoid mode, do not show the locked message because it
         | 
| @@ -155,6 +161,9 @@ module Devise | |
| 155 161 | 
             
                    end
         | 
| 156 162 |  | 
| 157 163 | 
             
                  module ClassMethods
         | 
| 164 | 
            +
                    # List of strategies that are enabled/supported if :both is used.
         | 
| 165 | 
            +
                    BOTH_STRATEGIES = [:time, :email]
         | 
| 166 | 
            +
             | 
| 158 167 | 
             
                    # Attempt to find a user by its unlock keys. If a record is found, send new
         | 
| 159 168 | 
             
                    # unlock instructions to it. If not user is found, returns a new user
         | 
| 160 169 | 
             
                    # with an email not found error.
         | 
| @@ -181,7 +190,8 @@ module Devise | |
| 181 190 |  | 
| 182 191 | 
             
                    # Is the unlock enabled for the given unlock strategy?
         | 
| 183 192 | 
             
                    def unlock_strategy_enabled?(strategy)
         | 
| 184 | 
            -
                       | 
| 193 | 
            +
                      self.unlock_strategy == strategy ||
         | 
| 194 | 
            +
                        (self.unlock_strategy == :both && BOTH_STRATEGIES.include?(strategy))
         | 
| 185 195 | 
             
                    end
         | 
| 186 196 |  | 
| 187 197 | 
             
                    # Is the lock enabled for the given lock strategy?
         |