devise 4.4.2 → 4.8.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.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +124 -4
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +97 -61
  5. data/app/controllers/devise/passwords_controller.rb +1 -0
  6. data/app/controllers/devise/registrations_controller.rb +26 -8
  7. data/app/controllers/devise_controller.rb +3 -3
  8. data/app/helpers/devise_helper.rb +21 -18
  9. data/app/mailers/devise/mailer.rb +5 -5
  10. data/app/views/devise/confirmations/new.html.erb +1 -1
  11. data/app/views/devise/passwords/edit.html.erb +3 -3
  12. data/app/views/devise/passwords/new.html.erb +1 -1
  13. data/app/views/devise/registrations/edit.html.erb +4 -4
  14. data/app/views/devise/registrations/new.html.erb +3 -3
  15. data/app/views/devise/sessions/new.html.erb +3 -3
  16. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  17. data/app/views/devise/shared/_links.html.erb +8 -8
  18. data/app/views/devise/unlocks/new.html.erb +1 -1
  19. data/config/locales/en.yml +3 -2
  20. data/lib/devise/controllers/helpers.rb +8 -8
  21. data/lib/devise/controllers/sign_in_out.rb +8 -3
  22. data/lib/devise/controllers/url_helpers.rb +1 -1
  23. data/lib/devise/failure_app.rb +25 -5
  24. data/lib/devise/hooks/lockable.rb +2 -5
  25. data/lib/devise/hooks/timeoutable.rb +2 -2
  26. data/lib/devise/mapping.rb +1 -1
  27. data/lib/devise/models/authenticatable.rb +51 -48
  28. data/lib/devise/models/confirmable.rb +18 -3
  29. data/lib/devise/models/database_authenticatable.rb +51 -13
  30. data/lib/devise/models/lockable.rb +12 -4
  31. data/lib/devise/models/omniauthable.rb +2 -2
  32. data/lib/devise/models/recoverable.rb +3 -3
  33. data/lib/devise/models/registerable.rb +2 -0
  34. data/lib/devise/models/rememberable.rb +2 -2
  35. data/lib/devise/models/timeoutable.rb +1 -1
  36. data/lib/devise/models/trackable.rb +9 -2
  37. data/lib/devise/models/validatable.rb +2 -2
  38. data/lib/devise/omniauth.rb +2 -5
  39. data/lib/devise/parameter_filter.rb +2 -0
  40. data/lib/devise/parameter_sanitizer.rb +13 -1
  41. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  42. data/lib/devise/rails/routes.rb +6 -6
  43. data/lib/devise/rails.rb +1 -7
  44. data/lib/devise/secret_key_finder.rb +27 -0
  45. data/lib/devise/strategies/authenticatable.rb +1 -1
  46. data/lib/devise/strategies/database_authenticatable.rb +6 -1
  47. data/lib/devise/test/controller_helpers.rb +4 -2
  48. data/lib/devise/test/integration_helpers.rb +1 -1
  49. data/lib/devise/version.rb +1 -1
  50. data/lib/devise.rb +15 -6
  51. data/lib/generators/active_record/devise_generator.rb +26 -11
  52. data/lib/generators/devise/controllers_generator.rb +1 -1
  53. data/lib/generators/devise/devise_generator.rb +1 -1
  54. data/lib/generators/devise/install_generator.rb +1 -5
  55. data/lib/generators/devise/orm_helpers.rb +2 -2
  56. data/lib/generators/devise/views_generator.rb +1 -1
  57. data/lib/generators/mongoid/devise_generator.rb +5 -5
  58. data/lib/generators/templates/README +9 -1
  59. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
  60. data/lib/generators/templates/devise.rb +34 -6
  61. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +5 -1
  62. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +10 -2
  63. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +4 -1
  64. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +11 -3
  65. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +11 -3
  66. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +7 -2
  67. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +4 -1
  68. metadata +19 -314
  69. data/.gitignore +0 -10
  70. data/.travis.yml +0 -68
  71. data/.yardopts +0 -9
  72. data/CODE_OF_CONDUCT.md +0 -22
  73. data/CONTRIBUTING.md +0 -79
  74. data/Gemfile +0 -39
  75. data/Gemfile.lock +0 -193
  76. data/ISSUE_TEMPLATE.md +0 -19
  77. data/Rakefile +0 -37
  78. data/bin/test +0 -13
  79. data/devise.gemspec +0 -28
  80. data/devise.png +0 -0
  81. data/gemfiles/Gemfile.rails-4.1-stable +0 -32
  82. data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
  83. data/gemfiles/Gemfile.rails-4.2-stable +0 -32
  84. data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -192
  85. data/gemfiles/Gemfile.rails-5.0-stable +0 -33
  86. data/gemfiles/Gemfile.rails-5.0-stable.lock +0 -192
  87. data/gemfiles/Gemfile.rails-5.2-rc1 +0 -26
  88. data/gemfiles/Gemfile.rails-5.2-rc1.lock +0 -201
  89. data/guides/bug_report_templates/integration_test.rb +0 -106
  90. data/test/controllers/custom_registrations_controller_test.rb +0 -42
  91. data/test/controllers/custom_strategy_test.rb +0 -66
  92. data/test/controllers/helper_methods_test.rb +0 -24
  93. data/test/controllers/helpers_test.rb +0 -318
  94. data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -53
  95. data/test/controllers/internal_helpers_test.rb +0 -129
  96. data/test/controllers/load_hooks_controller_test.rb +0 -21
  97. data/test/controllers/passwords_controller_test.rb +0 -34
  98. data/test/controllers/sessions_controller_test.rb +0 -108
  99. data/test/controllers/url_helpers_test.rb +0 -67
  100. data/test/delegator_test.rb +0 -21
  101. data/test/devise_test.rb +0 -109
  102. data/test/failure_app_test.rb +0 -340
  103. data/test/generators/active_record_generator_test.rb +0 -130
  104. data/test/generators/controllers_generator_test.rb +0 -50
  105. data/test/generators/devise_generator_test.rb +0 -41
  106. data/test/generators/install_generator_test.rb +0 -26
  107. data/test/generators/mongoid_generator_test.rb +0 -25
  108. data/test/generators/views_generator_test.rb +0 -105
  109. data/test/helpers/devise_helper_test.rb +0 -51
  110. data/test/integration/authenticatable_test.rb +0 -706
  111. data/test/integration/confirmable_test.rb +0 -326
  112. data/test/integration/database_authenticatable_test.rb +0 -97
  113. data/test/integration/http_authenticatable_test.rb +0 -114
  114. data/test/integration/lockable_test.rb +0 -242
  115. data/test/integration/mounted_engine_test.rb +0 -38
  116. data/test/integration/omniauthable_test.rb +0 -148
  117. data/test/integration/recoverable_test.rb +0 -349
  118. data/test/integration/registerable_test.rb +0 -365
  119. data/test/integration/rememberable_test.rb +0 -219
  120. data/test/integration/timeoutable_test.rb +0 -186
  121. data/test/integration/trackable_test.rb +0 -99
  122. data/test/mailers/confirmation_instructions_test.rb +0 -117
  123. data/test/mailers/email_changed_test.rb +0 -132
  124. data/test/mailers/mailer_test.rb +0 -20
  125. data/test/mailers/reset_password_instructions_test.rb +0 -98
  126. data/test/mailers/unlock_instructions_test.rb +0 -93
  127. data/test/mapping_test.rb +0 -136
  128. data/test/models/authenticatable_test.rb +0 -25
  129. data/test/models/confirmable_test.rb +0 -549
  130. data/test/models/database_authenticatable_test.rb +0 -283
  131. data/test/models/lockable_test.rb +0 -352
  132. data/test/models/omniauthable_test.rb +0 -9
  133. data/test/models/recoverable_test.rb +0 -263
  134. data/test/models/registerable_test.rb +0 -9
  135. data/test/models/rememberable_test.rb +0 -184
  136. data/test/models/serializable_test.rb +0 -60
  137. data/test/models/timeoutable_test.rb +0 -53
  138. data/test/models/trackable_test.rb +0 -62
  139. data/test/models/validatable_test.rb +0 -121
  140. data/test/models_test.rb +0 -155
  141. data/test/omniauth/config_test.rb +0 -61
  142. data/test/omniauth/url_helpers_test.rb +0 -53
  143. data/test/orm/active_record.rb +0 -24
  144. data/test/orm/mongoid.rb +0 -15
  145. data/test/parameter_sanitizer_test.rb +0 -77
  146. data/test/rails_app/Rakefile +0 -6
  147. data/test/rails_app/app/active_record/admin.rb +0 -8
  148. data/test/rails_app/app/active_record/shim.rb +0 -4
  149. data/test/rails_app/app/active_record/user.rb +0 -20
  150. data/test/rails_app/app/active_record/user_on_engine.rb +0 -9
  151. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -9
  152. data/test/rails_app/app/active_record/user_with_validations.rb +0 -12
  153. data/test/rails_app/app/active_record/user_without_email.rb +0 -10
  154. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -8
  155. data/test/rails_app/app/controllers/admins_controller.rb +0 -8
  156. data/test/rails_app/app/controllers/application_controller.rb +0 -13
  157. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -32
  158. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -33
  159. data/test/rails_app/app/controllers/home_controller.rb +0 -31
  160. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -4
  161. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -4
  162. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -16
  163. data/test/rails_app/app/controllers/users_controller.rb +0 -33
  164. data/test/rails_app/app/helpers/application_helper.rb +0 -5
  165. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -5
  166. data/test/rails_app/app/mailers/users/mailer.rb +0 -5
  167. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -6
  168. data/test/rails_app/app/mongoid/admin.rb +0 -31
  169. data/test/rails_app/app/mongoid/shim.rb +0 -25
  170. data/test/rails_app/app/mongoid/user.rb +0 -50
  171. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -41
  172. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -41
  173. data/test/rails_app/app/mongoid/user_with_validations.rb +0 -37
  174. data/test/rails_app/app/mongoid/user_without_email.rb +0 -35
  175. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  176. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  177. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  178. data/test/rails_app/app/views/home/index.html.erb +0 -1
  179. data/test/rails_app/app/views/home/join.html.erb +0 -1
  180. data/test/rails_app/app/views/home/private.html.erb +0 -1
  181. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  182. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  183. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  184. data/test/rails_app/app/views/users/index.html.erb +0 -1
  185. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  186. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  187. data/test/rails_app/bin/bundle +0 -3
  188. data/test/rails_app/bin/rails +0 -4
  189. data/test/rails_app/bin/rake +0 -4
  190. data/test/rails_app/config/application.rb +0 -48
  191. data/test/rails_app/config/boot.rb +0 -27
  192. data/test/rails_app/config/database.yml +0 -18
  193. data/test/rails_app/config/environment.rb +0 -7
  194. data/test/rails_app/config/environments/development.rb +0 -32
  195. data/test/rails_app/config/environments/production.rb +0 -88
  196. data/test/rails_app/config/environments/test.rb +0 -47
  197. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -9
  198. data/test/rails_app/config/initializers/devise.rb +0 -182
  199. data/test/rails_app/config/initializers/inflections.rb +0 -4
  200. data/test/rails_app/config/initializers/secret_token.rb +0 -5
  201. data/test/rails_app/config/initializers/session_store.rb +0 -3
  202. data/test/rails_app/config/routes.rb +0 -128
  203. data/test/rails_app/config.ru +0 -4
  204. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -77
  205. data/test/rails_app/db/schema.rb +0 -57
  206. data/test/rails_app/lib/shared_admin.rb +0 -23
  207. data/test/rails_app/lib/shared_user.rb +0 -32
  208. data/test/rails_app/lib/shared_user_without_email.rb +0 -28
  209. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -15
  210. data/test/rails_app/public/404.html +0 -26
  211. data/test/rails_app/public/422.html +0 -26
  212. data/test/rails_app/public/500.html +0 -26
  213. data/test/rails_app/public/favicon.ico +0 -0
  214. data/test/rails_test.rb +0 -11
  215. data/test/routes_test.rb +0 -281
  216. data/test/support/action_controller/record_identifier.rb +0 -12
  217. data/test/support/assertions.rb +0 -30
  218. data/test/support/helpers.rb +0 -83
  219. data/test/support/http_method_compatibility.rb +0 -53
  220. data/test/support/integration.rb +0 -95
  221. data/test/support/locale/en.yml +0 -8
  222. data/test/support/mongoid.yml +0 -6
  223. data/test/support/webrat/integrations/rails.rb +0 -35
  224. data/test/test/controller_helpers_test.rb +0 -193
  225. data/test/test/integration_helpers_test.rb +0 -34
  226. data/test/test_helper.rb +0 -36
  227. data/test/test_models.rb +0 -35
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_model/version'
4
3
  require 'devise/hooks/activatable'
5
4
  require 'devise/hooks/csrf_cleaner'
5
+ require 'devise/rails/deprecated_constant_accessor'
6
6
 
7
7
  module Devise
8
8
  module Models
@@ -10,7 +10,7 @@ module Devise
10
10
  #
11
11
  # == Options
12
12
  #
13
- # Authenticatable adds the following options to devise_for:
13
+ # Authenticatable adds the following options to +devise+:
14
14
  #
15
15
  # * +authentication_keys+: parameters used for authentication. By default [:email].
16
16
  #
@@ -56,11 +56,14 @@ module Devise
56
56
  module Authenticatable
57
57
  extend ActiveSupport::Concern
58
58
 
59
- 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,
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 BLACKLIST_FOR_SERIALIZATION
116
+ options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
114
117
  end
115
118
 
116
119
  super(options)
@@ -134,16 +137,18 @@ module Devise
134
137
  # This is an internal method called every time Devise needs
135
138
  # to send a notification/mail. This can be overridden if you
136
139
  # need to customize the e-mail delivery logic. For instance,
137
- # if you are using a queue to deliver e-mails (delayed job,
138
- # sidekiq, resque, etc), you must add the delivery to the queue
140
+ # if you are using a queue to deliver e-mails (active job, delayed
141
+ # job, sidekiq, resque, etc), you must add the delivery to the queue
139
142
  # just after the transaction was committed. To achieve this,
140
143
  # you can override send_devise_notification to store the
141
- # deliveries until the after_commit callback is triggered:
144
+ # deliveries until the after_commit callback is triggered.
145
+ #
146
+ # The following example uses Active Job's `deliver_later` :
142
147
  #
143
148
  # class User
144
149
  # devise :database_authenticatable, :confirmable
145
150
  #
146
- # after_commit :send_pending_notifications
151
+ # after_commit :send_pending_devise_notifications
147
152
  #
148
153
  # protected
149
154
  #
@@ -151,39 +156,45 @@ module Devise
151
156
  # # If the record is new or changed then delay the
152
157
  # # delivery until the after_commit callback otherwise
153
158
  # # send now because after_commit will not be called.
154
- # if new_record? || changed?
155
- # pending_notifications << [notification, args]
159
+ # # For Rails < 6 use `changed?` instead of `saved_changes?`.
160
+ # if new_record? || saved_changes?
161
+ # pending_devise_notifications << [notification, args]
156
162
  # else
157
- # message = devise_mailer.send(notification, self, *args)
158
- # Remove once we move to Rails 4.2+ only.
159
- # if message.respond_to?(:deliver_now)
160
- # message.deliver_now
161
- # else
162
- # message.deliver
163
- # end
163
+ # render_and_send_devise_message(notification, *args)
164
164
  # end
165
165
  # end
166
166
  #
167
- # def send_pending_notifications
168
- # pending_notifications.each do |notification, args|
169
- # message = devise_mailer.send(notification, self, *args)
170
- # Remove once we move to Rails 4.2+ only.
171
- # if message.respond_to?(:deliver_now)
172
- # message.deliver_now
173
- # else
174
- # message.deliver
175
- # end
167
+ # private
168
+ #
169
+ # def send_pending_devise_notifications
170
+ # pending_devise_notifications.each do |notification, args|
171
+ # render_and_send_devise_message(notification, *args)
176
172
  # end
177
173
  #
178
174
  # # Empty the pending notifications array because the
179
175
  # # after_commit hook can be called multiple times which
180
176
  # # could cause multiple emails to be sent.
181
- # pending_notifications.clear
177
+ # pending_devise_notifications.clear
182
178
  # end
183
179
  #
184
- # def pending_notifications
185
- # @pending_notifications ||= []
180
+ # def pending_devise_notifications
181
+ # @pending_devise_notifications ||= []
182
+ # end
183
+ #
184
+ # def render_and_send_devise_message(notification, *args)
185
+ # message = devise_mailer.send(notification, self, *args)
186
+ #
187
+ # # Deliver later with Active Job's `deliver_later`
188
+ # if message.respond_to?(:deliver_later)
189
+ # message.deliver_later
190
+ # # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
191
+ # elsif message.respond_to?(:deliver_now)
192
+ # message.deliver_now
193
+ # else
194
+ # message.deliver
195
+ # end
186
196
  # end
197
+ #
187
198
  # end
188
199
  #
189
200
  def send_devise_notification(notification, *args)
@@ -265,39 +276,31 @@ module Devise
265
276
  find_first_by_auth_conditions(tainted_conditions)
266
277
  end
267
278
 
268
- def find_first_by_auth_conditions(tainted_conditions, opts={})
279
+ def find_first_by_auth_conditions(tainted_conditions, opts = {})
269
280
  to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
270
281
  end
271
282
 
272
283
  # Find or initialize a record setting an error if it can't be found.
273
- def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
284
+ def find_or_initialize_with_error_by(attribute, value, error = :invalid) #:nodoc:
274
285
  find_or_initialize_with_errors([attribute], { attribute => value }, error)
275
286
  end
276
287
 
277
288
  # Find or initialize a record with group of attributes based on a list of required attributes.
278
- def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
279
- attributes = if attributes.respond_to? :permit!
280
- attributes.slice(*required_attributes).permit!.to_h.with_indifferent_access
281
- else
282
- attributes.with_indifferent_access.slice(*required_attributes)
283
- end
284
- attributes.delete_if { |key, value| value.blank? }
289
+ def find_or_initialize_with_errors(required_attributes, attributes, error = :invalid) #:nodoc:
290
+ attributes.try(:permit!)
291
+ attributes = attributes.to_h.with_indifferent_access
292
+ .slice(*required_attributes)
293
+ .delete_if { |key, value| value.blank? }
285
294
 
286
295
  if attributes.size == required_attributes.size
287
- record = find_first_by_auth_conditions(attributes)
296
+ record = find_first_by_auth_conditions(attributes) and return record
288
297
  end
289
298
 
290
- unless record
291
- record = new
292
-
299
+ new(devise_parameter_filter.filter(attributes)).tap do |record|
293
300
  required_attributes.each do |key|
294
- value = attributes[key]
295
- record.send("#{key}=", value)
296
- record.errors.add(key, value.present? ? error : :blank)
301
+ record.errors.add(key, attributes[key].blank? ? :blank : error)
297
302
  end
298
303
  end
299
-
300
- record
301
304
  end
302
305
 
303
306
  protected
@@ -76,7 +76,7 @@ module Devise
76
76
  # Confirm a user by setting it's confirmed_at to actual time. If the user
77
77
  # is already confirmed, add an error to email field. If the user is invalid
78
78
  # add errors
79
- def confirm(args={})
79
+ def confirm(args = {})
80
80
  pending_any_confirmation do
81
81
  if confirmation_period_expired?
82
82
  self.errors.add(:email, :confirmation_period_expired,
@@ -211,7 +211,10 @@ module Devise
211
211
  # confirmation_period_valid? # will always return true
212
212
  #
213
213
  def confirmation_period_valid?
214
- self.class.allow_unconfirmed_access_for.nil? || (confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago)
214
+ return true if self.class.allow_unconfirmed_access_for.nil?
215
+ return false if self.class.allow_unconfirmed_access_for == 0.days
216
+
217
+ confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago
215
218
  end
216
219
 
217
220
  # Checks if the user confirmation happens before the token becomes invalid
@@ -331,7 +334,7 @@ module Devise
331
334
  # confirmation instructions to it. If not, try searching for a user by unconfirmed_email
332
335
  # field. If no user is found, returns a new user with an email not found error.
333
336
  # Options must contain the user email
334
- def send_confirmation_instructions(attributes={})
337
+ def send_confirmation_instructions(attributes = {})
335
338
  confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
336
339
  unless confirmable.try(:persisted?)
337
340
  confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
@@ -345,7 +348,19 @@ module Devise
345
348
  # If the user is already confirmed, create an error for the user
346
349
  # Options must have the confirmation_token
347
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
+
348
362
  confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
363
+
349
364
  unless confirmable
350
365
  confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
351
366
  confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
@@ -7,9 +7,13 @@ module Devise
7
7
  # Authenticatable Module, responsible for hashing the password and
8
8
  # validating the authenticity of a user while signing in.
9
9
  #
10
+ # This module defines a `password=` method. This method will hash the argument
11
+ # and store it in the `encrypted_password` column, bypassing any pre-existing
12
+ # `password` column if it exists.
13
+ #
10
14
  # == Options
11
15
  #
12
- # DatabaseAuthenticatable adds the following options to 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.
@@ -35,6 +39,22 @@ module Devise
35
39
  attr_accessor :password_confirmation
36
40
  end
37
41
 
42
+ def initialize(*args, &block)
43
+ @skip_email_changed_notification = false
44
+ @skip_password_change_notification = false
45
+ super
46
+ end
47
+
48
+ # Skips sending the email changed notification after_update
49
+ def skip_email_changed_notification!
50
+ @skip_email_changed_notification = true
51
+ end
52
+
53
+ # Skips sending the password change notification after_update
54
+ def skip_password_change_notification!
55
+ @skip_password_change_notification = true
56
+ end
57
+
38
58
  def self.required_fields(klass)
39
59
  [:encrypted_password] + klass.authentication_keys
40
60
  end
@@ -65,6 +85,15 @@ module Devise
65
85
  # their password). In case the password field is rejected, the confirmation
66
86
  # is also rejected as long as it is also blank.
67
87
  def update_with_password(params, *options)
88
+ if options.present?
89
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
90
+ [Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
91
+ (`options`) is deprecated and it will be removed in the next major version.
92
+ It was added to support a feature deprecated in Rails 4, so you can safely remove it
93
+ from your code.
94
+ DEPRECATION
95
+ end
96
+
68
97
  current_password = params.delete(:current_password)
69
98
 
70
99
  if params[:password].blank?
@@ -73,11 +102,11 @@ module Devise
73
102
  end
74
103
 
75
104
  result = if valid_password?(current_password)
76
- update_attributes(params, *options)
105
+ update(params, *options)
77
106
  else
78
- self.assign_attributes(params, *options)
79
- self.valid?
80
- self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
107
+ assign_attributes(params, *options)
108
+ valid?
109
+ errors.add(:current_password, current_password.blank? ? :blank : :invalid)
81
110
  false
82
111
  end
83
112
 
@@ -98,10 +127,19 @@ module Devise
98
127
  # end
99
128
  #
100
129
  def update_without_password(params, *options)
130
+ if options.present?
131
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
132
+ [Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
133
+ (`options`) is deprecated and it will be removed in the next major version.
134
+ It was added to support a feature deprecated in Rails 4, so you can safely remove it
135
+ from your code.
136
+ DEPRECATION
137
+ end
138
+
101
139
  params.delete(:password)
102
140
  params.delete(:password_confirmation)
103
141
 
104
- result = update_attributes(params, *options)
142
+ result = update(params, *options)
105
143
  clean_up_passwords
106
144
  result
107
145
  end
@@ -113,8 +151,8 @@ module Devise
113
151
  result = if valid_password?(current_password)
114
152
  destroy
115
153
  else
116
- self.valid?
117
- self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
154
+ valid?
155
+ errors.add(:current_password, current_password.blank? ? :blank : :invalid)
118
156
  false
119
157
  end
120
158
 
@@ -161,7 +199,7 @@ module Devise
161
199
  # Hashes the password using bcrypt. Custom hash functions should override
162
200
  # this method to apply their own algorithm.
163
201
  #
164
- # See https://github.com/plataformatec/devise-encryptable for examples
202
+ # See https://github.com/heartcombo/devise-encryptable for examples
165
203
  # of other hashing engines.
166
204
  def password_digest(password)
167
205
  Devise::Encryptor.digest(self.class, password)
@@ -169,21 +207,21 @@ module Devise
169
207
 
170
208
  if Devise.activerecord51?
171
209
  def send_email_changed_notification?
172
- self.class.send_email_changed_notification && saved_change_to_email?
210
+ self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
173
211
  end
174
212
  else
175
213
  def send_email_changed_notification?
176
- self.class.send_email_changed_notification && email_changed?
214
+ self.class.send_email_changed_notification && email_changed? && !@skip_email_changed_notification
177
215
  end
178
216
  end
179
217
 
180
218
  if Devise.activerecord51?
181
219
  def send_password_change_notification?
182
- self.class.send_password_change_notification && saved_change_to_encrypted_password?
220
+ self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
183
221
  end
184
222
  else
185
223
  def send_password_change_notification?
186
- self.class.send_password_change_notification && encrypted_password_changed?
224
+ self.class.send_password_change_notification && encrypted_password_changed? && !@skip_password_change_notification
187
225
  end
188
226
  end
189
227
 
@@ -57,6 +57,14 @@ module Devise
57
57
  save(validate: false)
58
58
  end
59
59
 
60
+ # Resets failed attempts counter to 0.
61
+ def reset_failed_attempts!
62
+ if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
63
+ self.failed_attempts = 0
64
+ save(validate: false)
65
+ end
66
+ end
67
+
60
68
  # Verifies whether a user is locked or not.
61
69
  def access_locked?
62
70
  !!locked_at && !lock_expired?
@@ -110,10 +118,10 @@ module Devise
110
118
  false
111
119
  end
112
120
  end
113
-
121
+
114
122
  def increment_failed_attempts
115
- self.failed_attempts ||= 0
116
- self.failed_attempts += 1
123
+ self.class.increment_counter(:failed_attempts, id)
124
+ reload
117
125
  end
118
126
 
119
127
  def unauthenticated_message
@@ -168,7 +176,7 @@ module Devise
168
176
  # unlock instructions to it. If not user is found, returns a new user
169
177
  # with an email not found error.
170
178
  # Options must contain the user's unlock keys
171
- def send_unlock_instructions(attributes={})
179
+ def send_unlock_instructions(attributes = {})
172
180
  lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
173
181
  lockable.resend_unlock_instructions if lockable.persisted?
174
182
  lockable
@@ -8,11 +8,11 @@ module Devise
8
8
  #
9
9
  # == Options
10
10
  #
11
- # Oauthable adds the following options to 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
@@ -7,7 +7,7 @@ module Devise
7
7
  #
8
8
  # ==Options
9
9
  #
10
- # Recoverable adds the following options to devise_for:
10
+ # Recoverable adds the following options to +devise+:
11
11
  #
12
12
  # * +reset_password_keys+: the keys you want to use when recovering the password for an account
13
13
  # * +reset_password_within+: the time period within which the password must be reset or the token expires.
@@ -131,7 +131,7 @@ module Devise
131
131
  # password instructions to it. If user is not found, returns a new user
132
132
  # with an email not found error.
133
133
  # Attributes must contain the user's email
134
- def send_reset_password_instructions(attributes={})
134
+ def send_reset_password_instructions(attributes = {})
135
135
  recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
136
136
  recoverable.send_reset_password_instructions if recoverable.persisted?
137
137
  recoverable
@@ -142,7 +142,7 @@ module Devise
142
142
  # try saving the record. If not user is found, returns a new user
143
143
  # containing an error in reset_password_token attribute.
144
144
  # Attributes must contain reset_password_token, password and confirmation
145
- def reset_password_by_token(attributes={})
145
+ def reset_password_by_token(attributes = {})
146
146
  original_token = attributes[:reset_password_token]
147
147
  reset_password_token = Devise.token_generator.digest(self, :reset_password_token, original_token)
148
148
 
@@ -21,6 +21,8 @@ module Devise
21
21
  def new_with_session(params, session)
22
22
  new(params)
23
23
  end
24
+
25
+ Devise::Models.config(self, :sign_in_after_change_password)
24
26
  end
25
27
  end
26
28
  end
@@ -15,7 +15,7 @@ module Devise
15
15
  #
16
16
  # == Options
17
17
  #
18
- # Rememberable adds the following options in devise_for:
18
+ # Rememberable adds the following options to +devise+:
19
19
  #
20
20
  # * +remember_for+: the time you want the user will be remembered without
21
21
  # asking for credentials. After this time the user will be blocked and
@@ -102,7 +102,7 @@ module Devise
102
102
 
103
103
  def remember_me?(token, generated_at)
104
104
  # TODO: Normalize the JSON type coercion along with the Timeoutable hook
105
- # in a single place https://github.com/plataformatec/devise/blob/ffe9d6d406e79108cf32a2c6a1d0b3828849c40b/lib/devise/hooks/timeoutable.rb#L14-L18
105
+ # in a single place https://github.com/heartcombo/devise/blob/ffe9d6d406e79108cf32a2c6a1d0b3828849c40b/lib/devise/hooks/timeoutable.rb#L14-L18
106
106
  if generated_at.is_a?(String)
107
107
  generated_at = time_from_json(generated_at)
108
108
  end
@@ -11,7 +11,7 @@ module Devise
11
11
  #
12
12
  # == Options
13
13
  #
14
- # Timeoutable adds the following options to devise_for:
14
+ # Timeoutable adds the following options to +devise+:
15
15
  #
16
16
  # * +timeout_in+: the interval to timeout the user session without activity.
17
17
  #
@@ -22,7 +22,7 @@ module Devise
22
22
  self.last_sign_in_at = old_current || new_current
23
23
  self.current_sign_in_at = new_current
24
24
 
25
- old_current, new_current = self.current_sign_in_ip, request.remote_ip
25
+ old_current, new_current = self.current_sign_in_ip, extract_ip_from(request)
26
26
  self.last_sign_in_ip = old_current || new_current
27
27
  self.current_sign_in_ip = new_current
28
28
 
@@ -33,12 +33,19 @@ module Devise
33
33
  def update_tracked_fields!(request)
34
34
  # We have to check if the user is already persisted before running
35
35
  # `save` here because invalid users can be saved if we don't.
36
- # See https://github.com/plataformatec/devise/issues/4673 for more details.
36
+ # See https://github.com/heartcombo/devise/issues/4673 for more details.
37
37
  return if new_record?
38
38
 
39
39
  update_tracked_fields(request)
40
40
  save(validate: false)
41
41
  end
42
+
43
+ protected
44
+
45
+ def extract_ip_from(request)
46
+ request.remote_ip
47
+ end
48
+
42
49
  end
43
50
  end
44
51
  end
@@ -9,7 +9,7 @@ module Devise
9
9
  #
10
10
  # == Options
11
11
  #
12
- # Validatable adds the following options to devise_for:
12
+ # Validatable adds the following options to +devise+:
13
13
  #
14
14
  # * +email_regexp+: the regular expression used to validate e-mails;
15
15
  # * +password_length+: a range expressing password length. Defaults to 6..128.
@@ -30,7 +30,7 @@ module Devise
30
30
  base.class_eval do
31
31
  validates_presence_of :email, if: :email_required?
32
32
  if Devise.activerecord51?
33
- validates_uniqueness_of :email, allow_blank: true, if: :will_save_change_to_email?
33
+ validates_uniqueness_of :email, allow_blank: true, case_sensitive: true, if: :will_save_change_to_email?
34
34
  validates_format_of :email, with: email_regexp, allow_blank: true, if: :will_save_change_to_email?
35
35
  else
36
36
  validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
@@ -1,17 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
+ gem "omniauth", ">= 1.0.0"
5
+
4
6
  require "omniauth"
5
- require "omniauth/version"
6
7
  rescue LoadError
7
8
  warn "Could not load 'omniauth'. Please ensure you have the omniauth gem >= 1.0.0 installed and listed in your Gemfile."
8
9
  raise
9
10
  end
10
11
 
11
- unless OmniAuth::VERSION =~ /^1\./
12
- raise "You are using an old OmniAuth version, please ensure you have 1.0.0.pr2 version or later installed."
13
- end
14
-
15
12
  # Clean up the default path_prefix. It will be automatically set by Devise.
16
13
  OmniAuth.config.path_prefix = nil
17
14
 
@@ -18,6 +18,8 @@ module Devise
18
18
 
19
19
  def filtered_hash_by_method_for_given_keys(conditions, method, condition_keys)
20
20
  condition_keys.each do |k|
21
+ next unless conditions.key?(k)
22
+
21
23
  value = conditions[k]
22
24
  conditions[k] = value.send(method) if value.respond_to?(method)
23
25
  end
@@ -135,7 +135,19 @@ module Devise
135
135
  end
136
136
 
137
137
  def default_params
138
- @params.fetch(@resource_name, {})
138
+ if hashable_resource_params?
139
+ @params.fetch(@resource_name)
140
+ else
141
+ empty_params
142
+ end
143
+ end
144
+
145
+ def hashable_resource_params?
146
+ @params[@resource_name].respond_to?(:permit)
147
+ end
148
+
149
+ def empty_params
150
+ ActionController::Parameters.new({})
139
151
  end
140
152
 
141
153
  def permit_keys(parameters, keys)
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'active_support/deprecation/constant_accessor'
5
+
6
+ module Devise
7
+ DeprecatedConstantAccessor = ActiveSupport::Deprecation::DeprecatedConstantAccessor #:nodoc:
8
+ end
9
+ rescue LoadError
10
+
11
+ # Copy of constant deprecation module from Rails / Active Support version 6, so we can use it
12
+ # with Rails <= 5.0 versions. This can be removed once we support only Rails 5.1 or greater.
13
+ module Devise
14
+ module DeprecatedConstantAccessor #:nodoc:
15
+ def self.included(base)
16
+ require "active_support/inflector/methods"
17
+
18
+ extension = Module.new do
19
+ def const_missing(missing_const_name)
20
+ if class_variable_defined?(:@@_deprecated_constants)
21
+ if (replacement = class_variable_get(:@@_deprecated_constants)[missing_const_name.to_s])
22
+ replacement[:deprecator].warn(replacement[:message] || "#{name}::#{missing_const_name} is deprecated! Use #{replacement[:new]} instead.", Rails::VERSION::MAJOR == 4 ? caller : caller_locations)
23
+ return ActiveSupport::Inflector.constantize(replacement[:new].to_s)
24
+ end
25
+ end
26
+ super
27
+ end
28
+
29
+ def deprecate_constant(const_name, new_constant, message: nil, deprecator: ActiveSupport::Deprecation.instance)
30
+ class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
31
+ class_variable_get(:@@_deprecated_constants)[const_name.to_s] = { new: new_constant, message: message, deprecator: deprecator }
32
+ end
33
+ end
34
+ base.singleton_class.prepend extension
35
+ end
36
+ end
37
+ end
38
+
39
+ end