devise 4.7.1 → 4.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -3
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +100 -65
  5. data/app/controllers/devise/confirmations_controller.rb +1 -0
  6. data/app/controllers/devise/passwords_controller.rb +2 -2
  7. data/app/controllers/devise/registrations_controller.rb +1 -1
  8. data/app/controllers/devise/sessions_controller.rb +1 -1
  9. data/app/controllers/devise/unlocks_controller.rb +1 -0
  10. data/app/controllers/devise_controller.rb +3 -2
  11. data/app/helpers/devise_helper.rb +18 -6
  12. data/app/mailers/devise/mailer.rb +5 -5
  13. data/app/views/devise/registrations/edit.html.erb +1 -1
  14. data/app/views/devise/shared/_error_messages.html.erb +1 -1
  15. data/app/views/devise/shared/_links.html.erb +1 -1
  16. data/config/locales/en.yml +2 -2
  17. data/lib/devise/controllers/helpers.rb +7 -7
  18. data/lib/devise/controllers/responder.rb +35 -0
  19. data/lib/devise/controllers/sign_in_out.rb +6 -4
  20. data/lib/devise/controllers/url_helpers.rb +1 -1
  21. data/lib/devise/failure_app.rb +8 -5
  22. data/lib/devise/hooks/csrf_cleaner.rb +6 -1
  23. data/lib/devise/hooks/lockable.rb +2 -5
  24. data/lib/devise/hooks/timeoutable.rb +2 -2
  25. data/lib/devise/mapping.rb +1 -1
  26. data/lib/devise/models/authenticatable.rb +13 -8
  27. data/lib/devise/models/confirmable.rb +18 -39
  28. data/lib/devise/models/database_authenticatable.rb +14 -29
  29. data/lib/devise/models/lockable.rb +11 -3
  30. data/lib/devise/models/omniauthable.rb +2 -2
  31. data/lib/devise/models/recoverable.rb +8 -19
  32. data/lib/devise/models/rememberable.rb +2 -2
  33. data/lib/devise/models/timeoutable.rb +1 -1
  34. data/lib/devise/models/trackable.rb +1 -1
  35. data/lib/devise/models/validatable.rb +4 -9
  36. data/lib/devise/models.rb +1 -0
  37. data/lib/devise/omniauth.rb +2 -5
  38. data/lib/devise/orm.rb +71 -0
  39. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  40. data/lib/devise/rails/routes.rb +4 -4
  41. data/lib/devise/test/controller_helpers.rb +3 -1
  42. data/lib/devise/test/integration_helpers.rb +1 -1
  43. data/lib/devise/version.rb +1 -1
  44. data/lib/devise.rb +31 -12
  45. data/lib/generators/active_record/devise_generator.rb +17 -2
  46. data/lib/generators/devise/devise_generator.rb +1 -1
  47. data/lib/generators/devise/install_generator.rb +1 -5
  48. data/lib/generators/devise/views_generator.rb +1 -1
  49. data/lib/generators/templates/README +9 -1
  50. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
  51. data/lib/generators/templates/devise.rb +25 -11
  52. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +1 -1
  53. metadata +21 -9
@@ -1,14 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeviseHelper
4
- # Retain this method for backwards compatibility, deprecated in favour of modifying the
5
- # devise/shared/error_messages partial
4
+ # Retain this method for backwards compatibility, deprecated in favor of modifying the
5
+ # devise/shared/error_messages partial.
6
6
  def devise_error_messages!
7
7
  ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
8
- [Devise] `DeviseHelper.devise_error_messages!`
9
- is deprecated and it will be removed in the next major version.
10
- To customize the errors styles please run `rails g devise:views` and modify the
11
- `devise/shared/error_messages` partial.
8
+ [Devise] `DeviseHelper#devise_error_messages!` is deprecated and will be
9
+ removed in the next major version.
10
+
11
+ Devise now uses a partial under "devise/shared/error_messages" to display
12
+ error messages by default, and make them easier to customize. Update your
13
+ views changing calls from:
14
+
15
+ <%= devise_error_messages! %>
16
+
17
+ to:
18
+
19
+ <%= render "devise/shared/error_messages", resource: resource %>
20
+
21
+ To start customizing how errors are displayed, you can copy the partial
22
+ from devise to your `app/views` folder. Alternatively, you can run
23
+ `rails g devise:views` which will copy all of them again to your app.
12
24
  DEPRECATION
13
25
 
14
26
  return "" if resource.errors.empty?
@@ -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
@@ -38,6 +38,6 @@
38
38
 
39
39
  <h3>Cancel my account</h3>
40
40
 
41
- <p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
41
+ <div>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %></div>
42
42
 
43
43
  <%= link_to "Back", :back %>
@@ -1,5 +1,5 @@
1
1
  <% if resource.errors.any? %>
2
- <div id="error_explanation">
2
+ <div id="error_explanation" data-turbo-cache="false">
3
3
  <h2>
4
4
  <%= I18n.t("errors.messages.not_saved",
5
5
  count: resource.errors.count,
@@ -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
+ <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %><br />
24
24
  <% end %>
25
25
  <% end %>
@@ -1,4 +1,4 @@
1
- # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
1
+ # Additional translations at https://github.com/heartcombo/devise/wiki/I18n
2
2
 
3
3
  en:
4
4
  devise:
@@ -44,7 +44,7 @@ en:
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
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."
@@ -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}!(favourite=nil, opts={})
43
+ def authenticate_#{group_name}!(favorite = nil, opts = {})
44
44
  unless #{group_name}_signed_in?
45
45
  mappings = #{mappings}
46
- mappings.unshift mappings.delete(favourite.to_sym) if favourite
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}(favourite=nil)
60
+ def current_#{group_name}(favorite = nil)
61
61
  mappings = #{mappings}
62
- mappings.unshift mappings.delete(favourite.to_sym) if favourite
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 behaviour which resets/nullifies/raises
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
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module Controllers
5
+ # Custom Responder to configure default statuses that only apply to Devise,
6
+ # and allow to integrate more easily with Hotwire/Turbo.
7
+ class Responder < ActionController::Responder
8
+ if respond_to?(:error_status=) && respond_to?(:redirect_status=)
9
+ self.error_status = :ok
10
+ self.redirect_status = :found
11
+ else
12
+ # TODO: remove this support for older Rails versions, which aren't supported by Turbo
13
+ # and/or responders. It won't allow configuring a custom response, but it allows Devise
14
+ # to use these methods and defaults across the implementation more easily.
15
+ def self.error_status
16
+ :ok
17
+ end
18
+
19
+ def self.redirect_status
20
+ :found
21
+ end
22
+
23
+ def self.error_status=(*)
24
+ warn "[DEVISE] Setting the error status on the Devise responder has no effect with this " \
25
+ "version of `responders`, please make sure you're using a newer version. Check the changelog for more info."
26
+ end
27
+
28
+ def self.redirect_status=(*)
29
+ warn "[DEVISE] Setting the redirect status on the Devise responder has no effect with this " \
30
+ "version of `responders`, please make sure you're using a newer version. Check the changelog for more info."
31
+ end
32
+ end
33
+ end
34
+ end
35
+ 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/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
24
+ # in the sessions controller: https://github.com/heartcombo/devise/blob/main/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
 
@@ -34,7 +34,7 @@ module Devise
34
34
  end
35
35
  end
36
36
 
37
- def self.generate_helpers!(routes=nil)
37
+ def self.generate_helpers!(routes = nil)
38
38
  routes ||= begin
39
39
  mappings = Devise.mappings.values.map(&:used_helpers).flatten.uniq
40
40
  Devise::URL_HELPERS.slice(*mappings)
@@ -71,8 +71,11 @@ 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
- self.response = recall_app(warden_options[:recall]).call(request.env)
74
+ self.response = recall_app(warden_options[:recall]).call(request.env).tap { |response|
75
+ response[0] = Rack::Utils.status_code(
76
+ response[0].in?(300..399) ? Devise.responder.redirect_status : Devise.responder.error_status
77
+ )
78
+ }
76
79
  end
77
80
 
78
81
  def redirect
@@ -107,7 +110,7 @@ module Devise
107
110
  options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
108
111
  options = i18n_options(options)
109
112
 
110
- I18n.t(:"#{scope}.#{message}", options)
113
+ I18n.t(:"#{scope}.#{message}", **options)
111
114
  else
112
115
  message.to_s
113
116
  end
@@ -152,7 +155,7 @@ module Devise
152
155
 
153
156
  # We need to add the rootpath to `script_name` manually for applications that use a Rails
154
157
  # 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 droped.
158
+ # that use Devise. Remove it when the support of Rails 5.0 is dropped.
156
159
  elsif root_path_defined?(context) && !rails_51_and_up?
157
160
  rootpath = context.routes.url_helpers.root_path
158
161
  opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
@@ -168,7 +171,7 @@ module Devise
168
171
  end
169
172
 
170
173
  def skip_format?
171
- %w(html */*).include? request_format.to_s
174
+ %w(html */* turbo_stream).include? request_format.to_s
172
175
  end
173
176
 
174
177
  # Choose whether we should respond in an HTTP authentication fashion,
@@ -4,6 +4,11 @@ Warden::Manager.after_authentication do |record, warden, options|
4
4
  clean_up_for_winning_strategy = !warden.winning_strategy.respond_to?(:clean_up_csrf?) ||
5
5
  warden.winning_strategy.clean_up_csrf?
6
6
  if Devise.clean_up_csrf_token_on_authentication && clean_up_for_winning_strategy
7
- warden.request.session.try(:delete, :_csrf_token)
7
+ if warden.request.respond_to?(:reset_csrf_token)
8
+ # Rails 7.1+
9
+ warden.request.reset_csrf_token
10
+ else
11
+ warden.request.session.try(:delete, :_csrf_token)
12
+ end
8
13
  end
9
14
  end
@@ -3,10 +3,7 @@
3
3
  # After each sign in, if resource responds to failed_attempts, sets it to 0
4
4
  # This is only triggered when the user is explicitly set (with set_user)
5
5
  Warden::Manager.after_set_user except: :fetch do |record, warden, options|
6
- if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
7
- unless record.failed_attempts.to_i.zero?
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 record.timedout?(last_request_at) &&
25
- !env['devise.skip_timeout'] &&
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
@@ -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=:fullpath)
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
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'devise/hooks/activatable'
4
4
  require 'devise/hooks/csrf_cleaner'
5
+ require 'devise/rails/deprecated_constant_accessor'
5
6
 
6
7
  module Devise
7
8
  module Models
@@ -9,7 +10,7 @@ module Devise
9
10
  #
10
11
  # == Options
11
12
  #
12
- # Authenticatable adds the following options to devise_for:
13
+ # Authenticatable adds the following options to +devise+:
13
14
  #
14
15
  # * +authentication_keys+: parameters used for authentication. By default [:email].
15
16
  #
@@ -55,11 +56,14 @@ module Devise
55
56
  module Authenticatable
56
57
  extend ActiveSupport::Concern
57
58
 
58
- BLACKLIST_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
59
+ UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
59
60
  :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
60
61
  :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
61
62
  :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
62
63
 
64
+ include Devise::DeprecatedConstantAccessor
65
+ deprecate_constant "BLACKLIST_FOR_SERIALIZATION", "Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION"
66
+
63
67
  included do
64
68
  class_attribute :devise_modules, instance_writer: false
65
69
  self.devise_modules ||= []
@@ -104,12 +108,12 @@ module Devise
104
108
  # given to :except will simply add names to exempt to Devise internal list.
105
109
  def serializable_hash(options = nil)
106
110
  options = options.try(:dup) || {}
107
- options[:except] = Array(options[:except])
111
+ options[:except] = Array(options[:except]).dup
108
112
 
109
113
  if options[:force_except]
110
114
  options[:except].concat Array(options[:force_except])
111
115
  else
112
- options[:except].concat BLACKLIST_FOR_SERIALIZATION
116
+ options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
113
117
  end
114
118
 
115
119
  super(options)
@@ -152,7 +156,8 @@ module Devise
152
156
  # # If the record is new or changed then delay the
153
157
  # # delivery until the after_commit callback otherwise
154
158
  # # send now because after_commit will not be called.
155
- # if new_record? || changed?
159
+ # # For Rails < 6 use `changed?` instead of `saved_changes?`.
160
+ # if new_record? || saved_changes?
156
161
  # pending_devise_notifications << [notification, args]
157
162
  # else
158
163
  # render_and_send_devise_message(notification, *args)
@@ -271,17 +276,17 @@ module Devise
271
276
  find_first_by_auth_conditions(tainted_conditions)
272
277
  end
273
278
 
274
- def find_first_by_auth_conditions(tainted_conditions, opts={})
279
+ def find_first_by_auth_conditions(tainted_conditions, opts = {})
275
280
  to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
276
281
  end
277
282
 
278
283
  # Find or initialize a record setting an error if it can't be found.
279
- def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
284
+ def find_or_initialize_with_error_by(attribute, value, error = :invalid) #:nodoc:
280
285
  find_or_initialize_with_errors([attribute], { attribute => value }, error)
281
286
  end
282
287
 
283
288
  # Find or initialize a record with group of attributes based on a list of required attributes.
284
- def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
289
+ def find_or_initialize_with_errors(required_attributes, attributes, error = :invalid) #:nodoc:
285
290
  attributes.try(:permit!)
286
291
  attributes = attributes.to_h.with_indifferent_access
287
292
  .slice(*required_attributes)
@@ -48,7 +48,7 @@ module Devise
48
48
  included do
49
49
  before_create :generate_confirmation_token, if: :confirmation_required?
50
50
  after_create :skip_reconfirmation_in_callback!, if: :send_confirmation_notification?
51
- if defined?(ActiveRecord) && self < ActiveRecord::Base # ActiveRecord
51
+ if Devise::Orm.active_record?(self) # ActiveRecord
52
52
  after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
53
53
  after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
54
54
  else # Mongoid
@@ -76,7 +76,7 @@ module Devise
76
76
  # Confirm a user by setting it's confirmed_at to actual time. If the user
77
77
  # is already confirmed, add an error to email field. If the user is invalid
78
78
  # add errors
79
- def confirm(args={})
79
+ def confirm(args = {})
80
80
  pending_any_confirmation do
81
81
  if confirmation_period_expired?
82
82
  self.errors.add(:email, :confirmation_period_expired,
@@ -258,44 +258,23 @@ module Devise
258
258
  generate_confirmation_token && save(validate: false)
259
259
  end
260
260
 
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
261
+
262
+ def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
263
+ @reconfirmation_required = true
264
+ self.unconfirmed_email = self.email
265
+ self.email = self.devise_email_in_database
266
+ self.confirmation_token = nil
267
+ generate_confirmation_token
277
268
  end
278
269
 
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
270
+ def postpone_email_change?
271
+ postpone = self.class.reconfirmable &&
272
+ devise_will_save_change_to_email? &&
273
+ !@bypass_confirmation_postpone &&
274
+ self.email.present? &&
275
+ (!@skip_reconfirmation_in_callback || !self.devise_email_in_database.nil?)
276
+ @bypass_confirmation_postpone = false
277
+ postpone
299
278
  end
300
279
 
301
280
  def reconfirmation_required?
@@ -334,7 +313,7 @@ module Devise
334
313
  # confirmation instructions to it. If not, try searching for a user by unconfirmed_email
335
314
  # field. If no user is found, returns a new user with an email not found error.
336
315
  # Options must contain the user email
337
- def send_confirmation_instructions(attributes={})
316
+ def send_confirmation_instructions(attributes = {})
338
317
  confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
339
318
  unless confirmable.try(:persisted?)
340
319
  confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
@@ -7,9 +7,13 @@ module Devise
7
7
  # Authenticatable Module, responsible for hashing the password and
8
8
  # validating the authenticity of a user while signing in.
9
9
  #
10
+ # This module defines a `password=` method. This method will hash the argument
11
+ # and store it in the `encrypted_password` column, bypassing any pre-existing
12
+ # `password` column if it exists.
13
+ #
10
14
  # == Options
11
15
  #
12
- # DatabaseAuthenticatable adds the following options to devise_for:
16
+ # DatabaseAuthenticatable adds the following options to +devise+:
13
17
  #
14
18
  # * +pepper+: a random string used to provide a more secure hash. Use
15
19
  # `rails secret` to generate new keys.
@@ -38,7 +42,7 @@ module Devise
38
42
  def initialize(*args, &block)
39
43
  @skip_email_changed_notification = false
40
44
  @skip_password_change_notification = false
41
- super
45
+ super
42
46
  end
43
47
 
44
48
  # Skips sending the email changed notification after_update
@@ -173,16 +177,9 @@ module Devise
173
177
  encrypted_password[0,29] if encrypted_password
174
178
  end
175
179
 
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
180
+ # Send notification to user when email changes.
181
+ def send_email_changed_notification
182
+ send_devise_notification(:email_changed, to: devise_email_before_last_save)
186
183
  end
187
184
 
188
185
  # Send notification to user when password changes.
@@ -195,30 +192,18 @@ module Devise
195
192
  # Hashes the password using bcrypt. Custom hash functions should override
196
193
  # this method to apply their own algorithm.
197
194
  #
198
- # See https://github.com/plataformatec/devise-encryptable for examples
195
+ # See https://github.com/heartcombo/devise-encryptable for examples
199
196
  # of other hashing engines.
200
197
  def password_digest(password)
201
198
  Devise::Encryptor.digest(self.class, password)
202
199
  end
203
200
 
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
201
+ def send_email_changed_notification?
202
+ self.class.send_email_changed_notification && devise_saved_change_to_email? && !@skip_email_changed_notification
212
203
  end
213
204
 
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
205
+ def send_password_change_notification?
206
+ self.class.send_password_change_notification && devise_saved_change_to_encrypted_password? && !@skip_password_change_notification
222
207
  end
223
208
 
224
209
  module ClassMethods
@@ -18,7 +18,7 @@ module Devise
18
18
  # * +maximum_attempts+: how many attempts should be accepted before blocking the user.
19
19
  # * +lock_strategy+: lock the user account by :failed_attempts or :none.
20
20
  # * +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
21
- # * +unlock_in+: the time you want to lock the user after to lock happens. Only available when unlock_strategy is :time or :both.
21
+ # * +unlock_in+: the time you want to unlock the user after lock happens. Only available when unlock_strategy is :time or :both.
22
22
  # * +unlock_keys+: the keys you want to use when locking and unlocking an account
23
23
  #
24
24
  module Lockable
@@ -57,6 +57,14 @@ module Devise
57
57
  save(validate: false)
58
58
  end
59
59
 
60
+ # Resets failed attempts counter to 0.
61
+ def reset_failed_attempts!
62
+ if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
63
+ self.failed_attempts = 0
64
+ save(validate: false)
65
+ end
66
+ end
67
+
60
68
  # Verifies whether a user is locked or not.
61
69
  def access_locked?
62
70
  !!locked_at && !lock_expired?
@@ -110,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
@@ -8,11 +8,11 @@ module Devise
8
8
  #
9
9
  # == Options
10
10
  #
11
- # Oauthable adds the following options to devise_for:
11
+ # Oauthable adds the following options to +devise+:
12
12
  #
13
13
  # * +omniauth_providers+: Which providers are available to this model. It expects an array:
14
14
  #
15
- # devise_for :database_authenticatable, :omniauthable, omniauth_providers: [:twitter]
15
+ # devise :database_authenticatable, :omniauthable, omniauth_providers: [:twitter]
16
16
  #
17
17
  module Omniauthable
18
18
  extend ActiveSupport::Concern