devise 4.6.1 → 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 +58 -3
- data/MIT-LICENSE +2 -1
- data/README.md +75 -56
- data/app/controllers/devise_controller.rb +2 -2
- data/app/helpers/devise_helper.rb +18 -6
- data/app/mailers/devise/mailer.rb +5 -5
- data/app/views/devise/passwords/edit.html.erb +1 -1
- data/app/views/devise/shared/_links.html.erb +1 -1
- data/config/locales/en.yml +3 -3
- data/lib/devise.rb +1 -5
- data/lib/devise/controllers/helpers.rb +7 -7
- data/lib/devise/controllers/sign_in_out.rb +6 -4
- data/lib/devise/controllers/url_helpers.rb +1 -1
- data/lib/devise/failure_app.rb +5 -12
- data/lib/devise/hooks/lockable.rb +2 -5
- data/lib/devise/hooks/timeoutable.rb +2 -2
- data/lib/devise/mapping.rb +1 -1
- data/lib/devise/models/authenticatable.rb +12 -8
- data/lib/devise/models/confirmable.rb +14 -2
- data/lib/devise/models/database_authenticatable.rb +7 -4
- data/lib/devise/models/lockable.rb +10 -2
- data/lib/devise/models/recoverable.rb +2 -2
- data/lib/devise/models/rememberable.rb +1 -1
- data/lib/devise/models/trackable.rb +1 -1
- data/lib/devise/models/validatable.rb +1 -1
- data/lib/devise/omniauth.rb +2 -5
- data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
- data/lib/devise/rails/routes.rb +6 -6
- data/lib/devise/strategies/authenticatable.rb +1 -1
- data/lib/devise/test/controller_helpers.rb +3 -1
- data/lib/devise/test/integration_helpers.rb +1 -1
- data/lib/devise/version.rb +1 -1
- data/lib/generators/active_record/devise_generator.rb +17 -2
- data/lib/generators/devise/devise_generator.rb +1 -1
- data/lib/generators/devise/install_generator.rb +1 -5
- data/lib/generators/devise/views_generator.rb +1 -1
- data/lib/generators/templates/README +9 -1
- data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
- data/lib/generators/templates/devise.rb +15 -3
- data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +4 -1
- metadata +9 -15
| @@ -4,26 +4,26 @@ if defined?(ActionMailer) | |
| 4 4 | 
             
              class Devise::Mailer < Devise.parent_mailer.constantize
         | 
| 5 5 | 
             
                include Devise::Mailers::Helpers
         | 
| 6 6 |  | 
| 7 | 
            -
                def confirmation_instructions(record, token, opts={})
         | 
| 7 | 
            +
                def confirmation_instructions(record, token, opts = {})
         | 
| 8 8 | 
             
                  @token = token
         | 
| 9 9 | 
             
                  devise_mail(record, :confirmation_instructions, opts)
         | 
| 10 10 | 
             
                end
         | 
| 11 11 |  | 
| 12 | 
            -
                def reset_password_instructions(record, token, opts={})
         | 
| 12 | 
            +
                def reset_password_instructions(record, token, opts = {})
         | 
| 13 13 | 
             
                  @token = token
         | 
| 14 14 | 
             
                  devise_mail(record, :reset_password_instructions, opts)
         | 
| 15 15 | 
             
                end
         | 
| 16 16 |  | 
| 17 | 
            -
                def unlock_instructions(record, token, opts={})
         | 
| 17 | 
            +
                def unlock_instructions(record, token, opts = {})
         | 
| 18 18 | 
             
                  @token = token
         | 
| 19 19 | 
             
                  devise_mail(record, :unlock_instructions, opts)
         | 
| 20 20 | 
             
                end
         | 
| 21 21 |  | 
| 22 | 
            -
                def email_changed(record, opts={})
         | 
| 22 | 
            +
                def email_changed(record, opts = {})
         | 
| 23 23 | 
             
                  devise_mail(record, :email_changed, opts)
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| 26 | 
            -
                def password_change(record, opts={})
         | 
| 26 | 
            +
                def password_change(record, opts = {})
         | 
| 27 27 | 
             
                  devise_mail(record, :password_change, opts)
         | 
| 28 28 | 
             
                end
         | 
| 29 29 | 
             
              end
         | 
| @@ -14,7 +14,7 @@ | |
| 14 14 |  | 
| 15 15 | 
             
              <div class="field">
         | 
| 16 16 | 
             
                <%= f.label :password_confirmation, "Confirm new password" %><br />
         | 
| 17 | 
            -
                <%= f.password_field :password_confirmation, autocomplete: " | 
| 17 | 
            +
                <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
         | 
| 18 18 | 
             
              </div>
         | 
| 19 19 |  | 
| 20 20 | 
             
              <div class="actions">
         | 
| @@ -20,6 +20,6 @@ | |
| 20 20 |  | 
| 21 21 | 
             
            <%- if devise_mapping.omniauthable? %>
         | 
| 22 22 | 
             
              <%- resource_class.omniauth_providers.each do |provider| %>
         | 
| 23 | 
            -
                <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
         | 
| 23 | 
            +
                <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %><br />
         | 
| 24 24 | 
             
              <% end %>
         | 
| 25 25 | 
             
            <% end %>
         | 
    
        data/config/locales/en.yml
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Additional translations at https://github.com/ | 
| 1 | 
            +
            # Additional translations at https://github.com/heartcombo/devise/wiki/I18n
         | 
| 2 2 |  | 
| 3 3 | 
             
            en:
         | 
| 4 4 | 
             
              devise:
         | 
| @@ -42,9 +42,9 @@ en: | |
| 42 42 | 
             
                  signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
         | 
| 43 43 | 
             
                  signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
         | 
| 44 44 | 
             
                  signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
         | 
| 45 | 
            -
                  update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the  | 
| 45 | 
            +
                  update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address."
         | 
| 46 46 | 
             
                  updated: "Your account has been updated successfully."
         | 
| 47 | 
            -
                  updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again"
         | 
| 47 | 
            +
                  updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again."
         | 
| 48 48 | 
             
                sessions:
         | 
| 49 49 | 
             
                  signed_in: "Signed in successfully."
         | 
| 50 50 | 
             
                  signed_out: "Signed out successfully."
         | 
    
        data/lib/devise.rb
    CHANGED
    
    | @@ -71,7 +71,7 @@ module Devise | |
| 71 71 |  | 
| 72 72 | 
             
              # The number of times to hash the password.
         | 
| 73 73 | 
             
              mattr_accessor :stretches
         | 
| 74 | 
            -
              @@stretches =  | 
| 74 | 
            +
              @@stretches = 12
         | 
| 75 75 |  | 
| 76 76 | 
             
              # The default key used when authenticating over http auth.
         | 
| 77 77 | 
             
              mattr_accessor :http_authentication_key
         | 
| @@ -297,10 +297,6 @@ module Devise | |
| 297 297 | 
             
              mattr_accessor :sign_in_after_change_password
         | 
| 298 298 | 
             
              @@sign_in_after_change_password = true
         | 
| 299 299 |  | 
| 300 | 
            -
              def self.rails51? # :nodoc:
         | 
| 301 | 
            -
                Rails.gem_version >= Gem::Version.new("5.1.x")
         | 
| 302 | 
            -
              end
         | 
| 303 | 
            -
             | 
| 304 300 | 
             
              def self.activerecord51? # :nodoc:
         | 
| 305 301 | 
             
                defined?(ActiveRecord) && ActiveRecord.gem_version >= Gem::Version.new("5.1.x")
         | 
| 306 302 | 
             
              end
         | 
| @@ -36,14 +36,14 @@ module Devise | |
| 36 36 | 
             
                    #     before_action ->{ authenticate_blogger! :admin }  # Redirects to the admin login page
         | 
| 37 37 | 
             
                    #     current_blogger :user                             # Preferably returns a User if one is signed in
         | 
| 38 38 | 
             
                    #
         | 
| 39 | 
            -
                    def devise_group(group_name, opts={})
         | 
| 39 | 
            +
                    def devise_group(group_name, opts = {})
         | 
| 40 40 | 
             
                      mappings = "[#{ opts[:contains].map { |m| ":#{m}" }.join(',') }]"
         | 
| 41 41 |  | 
| 42 42 | 
             
                      class_eval <<-METHODS, __FILE__, __LINE__ + 1
         | 
| 43 | 
            -
                        def authenticate_#{group_name}!( | 
| 43 | 
            +
                        def authenticate_#{group_name}!(favorite = nil, opts = {})
         | 
| 44 44 | 
             
                          unless #{group_name}_signed_in?
         | 
| 45 45 | 
             
                            mappings = #{mappings}
         | 
| 46 | 
            -
                            mappings.unshift mappings.delete( | 
| 46 | 
            +
                            mappings.unshift mappings.delete(favorite.to_sym) if favorite
         | 
| 47 47 | 
             
                            mappings.each do |mapping|
         | 
| 48 48 | 
             
                              opts[:scope] = mapping
         | 
| 49 49 | 
             
                              warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
         | 
| @@ -57,9 +57,9 @@ module Devise | |
| 57 57 | 
             
                          end
         | 
| 58 58 | 
             
                        end
         | 
| 59 59 |  | 
| 60 | 
            -
                        def current_#{group_name}( | 
| 60 | 
            +
                        def current_#{group_name}(favorite = nil)
         | 
| 61 61 | 
             
                          mappings = #{mappings}
         | 
| 62 | 
            -
                          mappings.unshift mappings.delete( | 
| 62 | 
            +
                          mappings.unshift mappings.delete(favorite.to_sym) if favorite
         | 
| 63 63 | 
             
                          mappings.each do |mapping|
         | 
| 64 64 | 
             
                            current = warden.authenticate(scope: mapping)
         | 
| 65 65 | 
             
                            return current if current
         | 
| @@ -113,7 +113,7 @@ module Devise | |
| 113 113 | 
             
                    mapping = mapping.name
         | 
| 114 114 |  | 
| 115 115 | 
             
                    class_eval <<-METHODS, __FILE__, __LINE__ + 1
         | 
| 116 | 
            -
                      def authenticate_#{mapping}!(opts={})
         | 
| 116 | 
            +
                      def authenticate_#{mapping}!(opts = {})
         | 
| 117 117 | 
             
                        opts[:scope] = :#{mapping}
         | 
| 118 118 | 
             
                        warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
         | 
| 119 119 | 
             
                      end
         | 
| @@ -252,7 +252,7 @@ module Devise | |
| 252 252 | 
             
                  # Overwrite Rails' handle unverified request to sign out all scopes,
         | 
| 253 253 | 
             
                  # clear run strategies and remove cached variables.
         | 
| 254 254 | 
             
                  def handle_unverified_request
         | 
| 255 | 
            -
                    super # call the default  | 
| 255 | 
            +
                    super # call the default behavior which resets/nullifies/raises
         | 
| 256 256 | 
             
                    request.env["devise.skip_storage"] = true
         | 
| 257 257 | 
             
                    sign_out_all_scopes(false)
         | 
| 258 258 | 
             
                  end
         | 
| @@ -10,7 +10,7 @@ module Devise | |
| 10 10 | 
             
                  # cause exceptions to be thrown from this method; if you simply want to check
         | 
| 11 11 | 
             
                  # if a scope has already previously been authenticated without running
         | 
| 12 12 | 
             
                  # authentication hooks, you can directly call `warden.authenticated?(scope: scope)`
         | 
| 13 | 
            -
                  def signed_in?(scope=nil)
         | 
| 13 | 
            +
                  def signed_in?(scope = nil)
         | 
| 14 14 | 
             
                    [scope || Devise.mappings.keys].flatten.any? do |_scope|
         | 
| 15 15 | 
             
                      warden.authenticate?(scope: _scope)
         | 
| 16 16 | 
             
                    end
         | 
| @@ -21,7 +21,7 @@ module Devise | |
| 21 21 | 
             
                  # to the set_user method in warden.
         | 
| 22 22 | 
             
                  # If you are using a custom warden strategy and the timeoutable module, you have to
         | 
| 23 23 | 
             
                  # set `env["devise.skip_timeout"] = true` in the request to use this method, like we do
         | 
| 24 | 
            -
                  # in the sessions controller: https://github.com/ | 
| 24 | 
            +
                  # in the sessions controller: https://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
         | 
| 25 25 | 
             
                  #
         | 
| 26 26 | 
             
                  # Examples:
         | 
| 27 27 | 
             
                  #
         | 
| @@ -77,7 +77,7 @@ module Devise | |
| 77 77 | 
             
                  #   sign_out :user     # sign_out(scope)
         | 
| 78 78 | 
             
                  #   sign_out @user     # sign_out(resource)
         | 
| 79 79 | 
             
                  #
         | 
| 80 | 
            -
                  def sign_out(resource_or_scope=nil)
         | 
| 80 | 
            +
                  def sign_out(resource_or_scope = nil)
         | 
| 81 81 | 
             
                    return sign_out_all_scopes unless resource_or_scope
         | 
| 82 82 | 
             
                    scope = Devise::Mapping.find_scope!(resource_or_scope)
         | 
| 83 83 | 
             
                    user = warden.user(scope: scope, run_callbacks: false) # If there is no user
         | 
| @@ -92,7 +92,7 @@ module Devise | |
| 92 92 | 
             
                  # Sign out all active users or scopes. This helper is useful for signing out all roles
         | 
| 93 93 | 
             
                  # in one click. This signs out ALL scopes in warden. Returns true if there was at least one logout
         | 
| 94 94 | 
             
                  # and false if there was no user logged in on all scopes.
         | 
| 95 | 
            -
                  def sign_out_all_scopes(lock=true)
         | 
| 95 | 
            +
                  def sign_out_all_scopes(lock = true)
         | 
| 96 96 | 
             
                    users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) }
         | 
| 97 97 |  | 
| 98 98 | 
             
                    warden.logout
         | 
| @@ -106,10 +106,12 @@ module Devise | |
| 106 106 | 
             
                  private
         | 
| 107 107 |  | 
| 108 108 | 
             
                  def expire_data_after_sign_in!
         | 
| 109 | 
            +
                    # TODO: remove once Rails 5.2+ and forward are only supported.
         | 
| 109 110 | 
             
                    # session.keys will return an empty array if the session is not yet loaded.
         | 
| 110 111 | 
             
                    # This is a bug in both Rack and Rails.
         | 
| 111 112 | 
             
                    # A call to #empty? forces the session to be loaded.
         | 
| 112 113 | 
             
                    session.empty?
         | 
| 114 | 
            +
             | 
| 113 115 | 
             
                    session.keys.grep(/^devise\./).each { |k| session.delete(k) }
         | 
| 114 116 | 
             
                  end
         | 
| 115 117 |  | 
    
        data/lib/devise/failure_app.rb
    CHANGED
    
    | @@ -71,7 +71,6 @@ module Devise | |
| 71 71 | 
             
                  end
         | 
| 72 72 |  | 
| 73 73 | 
             
                  flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
         | 
| 74 | 
            -
                  # self.response = recall_app(warden_options[:recall]).call(env)
         | 
| 75 74 | 
             
                  self.response = recall_app(warden_options[:recall]).call(request.env)
         | 
| 76 75 | 
             
                end
         | 
| 77 76 |  | 
| @@ -107,7 +106,7 @@ module Devise | |
| 107 106 | 
             
                    options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
         | 
| 108 107 | 
             
                    options = i18n_options(options)
         | 
| 109 108 |  | 
| 110 | 
            -
                    I18n.t(:"#{scope}.#{message}", options)
         | 
| 109 | 
            +
                    I18n.t(:"#{scope}.#{message}", **options)
         | 
| 111 110 | 
             
                  else
         | 
| 112 111 | 
             
                    message.to_s
         | 
| 113 112 | 
             
                  end
         | 
| @@ -152,8 +151,8 @@ module Devise | |
| 152 151 |  | 
| 153 152 | 
             
                  # We need to add the rootpath to `script_name` manually for applications that use a Rails
         | 
| 154 153 | 
             
                  # version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
         | 
| 155 | 
            -
                  # that use Devise. Remove it when the support of Rails 5.0 is  | 
| 156 | 
            -
                  elsif root_path_defined?(context) &&  | 
| 154 | 
            +
                  # that use Devise. Remove it when the support of Rails 5.0 is dropped.
         | 
| 155 | 
            +
                  elsif root_path_defined?(context) && !rails_51_and_up?
         | 
| 157 156 | 
             
                    rootpath = context.routes.url_helpers.root_path
         | 
| 158 157 | 
             
                    opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
         | 
| 159 158 | 
             
                  end
         | 
| @@ -278,14 +277,8 @@ module Devise | |
| 278 277 | 
             
                  defined?(context.routes) && context.routes.url_helpers.respond_to?(:root_path)
         | 
| 279 278 | 
             
                end
         | 
| 280 279 |  | 
| 281 | 
            -
                def  | 
| 282 | 
            -
                   | 
| 283 | 
            -
             | 
| 284 | 
            -
                  Rails::VERSION::MAJOR >= 4
         | 
| 285 | 
            -
                end
         | 
| 286 | 
            -
             | 
| 287 | 
            -
                def rails_5_up?
         | 
| 288 | 
            -
                  Rails::VERSION::MAJOR >= 5 && Rails::VERSION::MINOR > 0
         | 
| 280 | 
            +
                def rails_51_and_up?
         | 
| 281 | 
            +
                  Rails.gem_version >= Gem::Version.new("5.1")
         | 
| 289 282 | 
             
                end
         | 
| 290 283 | 
             
              end
         | 
| 291 284 | 
             
            end
         | 
| @@ -3,10 +3,7 @@ | |
| 3 3 | 
             
            # After each sign in, if resource responds to failed_attempts, sets it to 0
         | 
| 4 4 | 
             
            # This is only triggered when the user is explicitly set (with set_user)
         | 
| 5 5 | 
             
            Warden::Manager.after_set_user except: :fetch do |record, warden, options|
         | 
| 6 | 
            -
              if record.respond_to?(: | 
| 7 | 
            -
                 | 
| 8 | 
            -
                  record.failed_attempts = 0
         | 
| 9 | 
            -
                  record.save(validate: false)
         | 
| 10 | 
            -
                end
         | 
| 6 | 
            +
              if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
         | 
| 7 | 
            +
                record.reset_failed_attempts!
         | 
| 11 8 | 
             
              end
         | 
| 12 9 | 
             
            end
         | 
| @@ -21,8 +21,8 @@ Warden::Manager.after_set_user do |record, warden, options| | |
| 21 21 |  | 
| 22 22 | 
             
                proxy = Devise::Hooks::Proxy.new(warden)
         | 
| 23 23 |  | 
| 24 | 
            -
                if  | 
| 25 | 
            -
                     | 
| 24 | 
            +
                if !env['devise.skip_timeout'] &&
         | 
| 25 | 
            +
                    record.timedout?(last_request_at) &&
         | 
| 26 26 | 
             
                    !proxy.remember_me_is_active?(record)
         | 
| 27 27 | 
             
                  Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
         | 
| 28 28 | 
             
                  throw :warden, scope: scope, message: :timeout
         | 
    
        data/lib/devise/mapping.rb
    CHANGED
    
    | @@ -46,7 +46,7 @@ module Devise | |
| 46 46 | 
             
                  raise "Could not find a valid mapping for #{obj.inspect}"
         | 
| 47 47 | 
             
                end
         | 
| 48 48 |  | 
| 49 | 
            -
                def self.find_by_path!(path, path_type | 
| 49 | 
            +
                def self.find_by_path!(path, path_type = :fullpath)
         | 
| 50 50 | 
             
                  Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
         | 
| 51 51 | 
             
                  raise "Could not find a valid mapping for path #{path.inspect}"
         | 
| 52 52 | 
             
                end
         | 
| @@ -1,8 +1,8 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require 'active_model/version'
         | 
| 4 3 | 
             
            require 'devise/hooks/activatable'
         | 
| 5 4 | 
             
            require 'devise/hooks/csrf_cleaner'
         | 
| 5 | 
            +
            require 'devise/rails/deprecated_constant_accessor'
         | 
| 6 6 |  | 
| 7 7 | 
             
            module Devise
         | 
| 8 8 | 
             
              module Models
         | 
| @@ -56,11 +56,14 @@ module Devise | |
| 56 56 | 
             
                module Authenticatable
         | 
| 57 57 | 
             
                  extend ActiveSupport::Concern
         | 
| 58 58 |  | 
| 59 | 
            -
                   | 
| 59 | 
            +
                  UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
         | 
| 60 60 | 
             
                    :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
         | 
| 61 61 | 
             
                    :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
         | 
| 62 62 | 
             
                    :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
         | 
| 63 63 |  | 
| 64 | 
            +
                  include Devise::DeprecatedConstantAccessor
         | 
| 65 | 
            +
                  deprecate_constant "BLACKLIST_FOR_SERIALIZATION", "Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION"
         | 
| 66 | 
            +
             | 
| 64 67 | 
             
                  included do
         | 
| 65 68 | 
             
                    class_attribute :devise_modules, instance_writer: false
         | 
| 66 69 | 
             
                    self.devise_modules ||= []
         | 
| @@ -105,12 +108,12 @@ module Devise | |
| 105 108 | 
             
                  # given to :except will simply add names to exempt to Devise internal list.
         | 
| 106 109 | 
             
                  def serializable_hash(options = nil)
         | 
| 107 110 | 
             
                    options = options.try(:dup) || {}
         | 
| 108 | 
            -
                    options[:except] = Array(options[:except])
         | 
| 111 | 
            +
                    options[:except] = Array(options[:except]).dup
         | 
| 109 112 |  | 
| 110 113 | 
             
                    if options[:force_except]
         | 
| 111 114 | 
             
                      options[:except].concat Array(options[:force_except])
         | 
| 112 115 | 
             
                    else
         | 
| 113 | 
            -
                      options[:except].concat  | 
| 116 | 
            +
                      options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
         | 
| 114 117 | 
             
                    end
         | 
| 115 118 |  | 
| 116 119 | 
             
                    super(options)
         | 
| @@ -153,7 +156,8 @@ module Devise | |
| 153 156 | 
             
                  #         # If the record is new or changed then delay the
         | 
| 154 157 | 
             
                  #         # delivery until the after_commit callback otherwise
         | 
| 155 158 | 
             
                  #         # send now because after_commit will not be called.
         | 
| 156 | 
            -
                  #          | 
| 159 | 
            +
                  #         # For Rails < 6 use `changed?` instead of `saved_changes?`.
         | 
| 160 | 
            +
                  #         if new_record? || saved_changes?
         | 
| 157 161 | 
             
                  #           pending_devise_notifications << [notification, args]
         | 
| 158 162 | 
             
                  #         else
         | 
| 159 163 | 
             
                  #           render_and_send_devise_message(notification, *args)
         | 
| @@ -272,17 +276,17 @@ module Devise | |
| 272 276 | 
             
                      find_first_by_auth_conditions(tainted_conditions)
         | 
| 273 277 | 
             
                    end
         | 
| 274 278 |  | 
| 275 | 
            -
                    def find_first_by_auth_conditions(tainted_conditions, opts={})
         | 
| 279 | 
            +
                    def find_first_by_auth_conditions(tainted_conditions, opts = {})
         | 
| 276 280 | 
             
                      to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
         | 
| 277 281 | 
             
                    end
         | 
| 278 282 |  | 
| 279 283 | 
             
                    # Find or initialize a record setting an error if it can't be found.
         | 
| 280 | 
            -
                    def find_or_initialize_with_error_by(attribute, value, error | 
| 284 | 
            +
                    def find_or_initialize_with_error_by(attribute, value, error = :invalid) #:nodoc:
         | 
| 281 285 | 
             
                      find_or_initialize_with_errors([attribute], { attribute => value }, error)
         | 
| 282 286 | 
             
                    end
         | 
| 283 287 |  | 
| 284 288 | 
             
                    # Find or initialize a record with group of attributes based on a list of required attributes.
         | 
| 285 | 
            -
                    def find_or_initialize_with_errors(required_attributes, attributes, error | 
| 289 | 
            +
                    def find_or_initialize_with_errors(required_attributes, attributes, error = :invalid) #:nodoc:
         | 
| 286 290 | 
             
                      attributes.try(:permit!)
         | 
| 287 291 | 
             
                      attributes = attributes.to_h.with_indifferent_access
         | 
| 288 292 | 
             
                                             .slice(*required_attributes)
         | 
| @@ -76,7 +76,7 @@ module Devise | |
| 76 76 | 
             
                  # Confirm a user by setting it's confirmed_at to actual time. If the user
         | 
| 77 77 | 
             
                  # is already confirmed, add an error to email field. If the user is invalid
         | 
| 78 78 | 
             
                  # add errors
         | 
| 79 | 
            -
                  def confirm(args={})
         | 
| 79 | 
            +
                  def confirm(args = {})
         | 
| 80 80 | 
             
                    pending_any_confirmation do
         | 
| 81 81 | 
             
                      if confirmation_period_expired?
         | 
| 82 82 | 
             
                        self.errors.add(:email, :confirmation_period_expired,
         | 
| @@ -334,7 +334,7 @@ module Devise | |
| 334 334 | 
             
                    # confirmation instructions to it. If not, try searching for a user by unconfirmed_email
         | 
| 335 335 | 
             
                    # field. If no user is found, returns a new user with an email not found error.
         | 
| 336 336 | 
             
                    # Options must contain the user email
         | 
| 337 | 
            -
                    def send_confirmation_instructions(attributes={})
         | 
| 337 | 
            +
                    def send_confirmation_instructions(attributes = {})
         | 
| 338 338 | 
             
                      confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
         | 
| 339 339 | 
             
                      unless confirmable.try(:persisted?)
         | 
| 340 340 | 
             
                        confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
         | 
| @@ -348,7 +348,19 @@ module Devise | |
| 348 348 | 
             
                    # If the user is already confirmed, create an error for the user
         | 
| 349 349 | 
             
                    # Options must have the confirmation_token
         | 
| 350 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 | 
            +
             | 
| 351 362 | 
             
                      confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
         | 
| 363 | 
            +
             | 
| 352 364 | 
             
                      unless confirmable
         | 
| 353 365 | 
             
                        confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
         | 
| 354 366 | 
             
                        confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
         | 
| @@ -7,6 +7,10 @@ module Devise | |
| 7 7 | 
             
                # Authenticatable Module, responsible for hashing the password and
         | 
| 8 8 | 
             
                # validating the authenticity of a user while signing in.
         | 
| 9 9 | 
             
                #
         | 
| 10 | 
            +
                # This module defines a `password=` method. This method will hash the argument
         | 
| 11 | 
            +
                # and store it in the `encrypted_password` column, bypassing any pre-existing
         | 
| 12 | 
            +
                # `password` column if it exists.
         | 
| 13 | 
            +
                #
         | 
| 10 14 | 
             
                # == Options
         | 
| 11 15 | 
             
                #
         | 
| 12 16 | 
             
                # DatabaseAuthenticatable adds the following options to devise_for:
         | 
| @@ -60,7 +64,7 @@ module Devise | |
| 60 64 | 
             
                  # the hashed password.
         | 
| 61 65 | 
             
                  def password=(new_password)
         | 
| 62 66 | 
             
                    @password = new_password
         | 
| 63 | 
            -
                    self.encrypted_password = password_digest(@password) 
         | 
| 67 | 
            +
                    self.encrypted_password = password_digest(@password) if @password.present?
         | 
| 64 68 | 
             
                  end
         | 
| 65 69 |  | 
| 66 70 | 
             
                  # Verifies whether a password (ie from sign in) is the user password.
         | 
| @@ -70,7 +74,7 @@ module Devise | |
| 70 74 |  | 
| 71 75 | 
             
                  # Set password and password confirmation to nil
         | 
| 72 76 | 
             
                  def clean_up_passwords
         | 
| 73 | 
            -
                     | 
| 77 | 
            +
                    self.password = self.password_confirmation = nil
         | 
| 74 78 | 
             
                  end
         | 
| 75 79 |  | 
| 76 80 | 
             
                  # Update record attributes when :current_password matches, otherwise
         | 
| @@ -195,10 +199,9 @@ module Devise | |
| 195 199 | 
             
                  # Hashes the password using bcrypt. Custom hash functions should override
         | 
| 196 200 | 
             
                  # this method to apply their own algorithm.
         | 
| 197 201 | 
             
                  #
         | 
| 198 | 
            -
                  # See https://github.com/ | 
| 202 | 
            +
                  # See https://github.com/heartcombo/devise-encryptable for examples
         | 
| 199 203 | 
             
                  # of other hashing engines.
         | 
| 200 204 | 
             
                  def password_digest(password)
         | 
| 201 | 
            -
                    return if password.blank?
         | 
| 202 205 | 
             
                    Devise::Encryptor.digest(self.class, password)
         | 
| 203 206 | 
             
                  end
         | 
| 204 207 |  | 
| @@ -57,6 +57,14 @@ module Devise | |
| 57 57 | 
             
                    save(validate: false)
         | 
| 58 58 | 
             
                  end
         | 
| 59 59 |  | 
| 60 | 
            +
                  # Resets failed attempts counter to 0.
         | 
| 61 | 
            +
                  def reset_failed_attempts!
         | 
| 62 | 
            +
                    if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
         | 
| 63 | 
            +
                      self.failed_attempts = 0
         | 
| 64 | 
            +
                      save(validate: false)
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 60 68 | 
             
                  # Verifies whether a user is locked or not.
         | 
| 61 69 | 
             
                  def access_locked?
         | 
| 62 70 | 
             
                    !!locked_at && !lock_expired?
         | 
| @@ -110,7 +118,7 @@ module Devise | |
| 110 118 | 
             
                      false
         | 
| 111 119 | 
             
                    end
         | 
| 112 120 | 
             
                  end
         | 
| 113 | 
            -
             | 
| 121 | 
            +
             | 
| 114 122 | 
             
                  def increment_failed_attempts
         | 
| 115 123 | 
             
                    self.class.increment_counter(:failed_attempts, id)
         | 
| 116 124 | 
             
                    reload
         | 
| @@ -168,7 +176,7 @@ module Devise | |
| 168 176 | 
             
                    # unlock instructions to it. If not user is found, returns a new user
         | 
| 169 177 | 
             
                    # with an email not found error.
         | 
| 170 178 | 
             
                    # Options must contain the user's unlock keys
         | 
| 171 | 
            -
                    def send_unlock_instructions(attributes={})
         | 
| 179 | 
            +
                    def send_unlock_instructions(attributes = {})
         | 
| 172 180 | 
             
                      lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
         | 
| 173 181 | 
             
                      lockable.resend_unlock_instructions if lockable.persisted?
         | 
| 174 182 | 
             
                      lockable
         |