devise 4.4.3 → 4.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -2
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +50 -21
  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 +1 -1
  8. data/app/helpers/devise_helper.rb +10 -19
  9. data/app/views/devise/confirmations/new.html.erb +1 -1
  10. data/app/views/devise/passwords/edit.html.erb +3 -3
  11. data/app/views/devise/passwords/new.html.erb +1 -1
  12. data/app/views/devise/registrations/edit.html.erb +4 -4
  13. data/app/views/devise/registrations/new.html.erb +3 -3
  14. data/app/views/devise/sessions/new.html.erb +3 -3
  15. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  16. data/app/views/devise/shared/_links.html.erb +7 -7
  17. data/app/views/devise/unlocks/new.html.erb +1 -1
  18. data/config/locales/en.yml +2 -1
  19. data/lib/devise/controllers/helpers.rb +1 -1
  20. data/lib/devise/controllers/sign_in_out.rb +3 -0
  21. data/lib/devise/failure_app.rb +24 -3
  22. data/lib/devise/models/authenticatable.rb +38 -40
  23. data/lib/devise/models/confirmable.rb +16 -1
  24. data/lib/devise/models/database_authenticatable.rb +45 -11
  25. data/lib/devise/models/lockable.rb +2 -2
  26. data/lib/devise/models/registerable.rb +2 -0
  27. data/lib/devise/models/trackable.rb +8 -1
  28. data/lib/devise/models/validatable.rb +1 -1
  29. data/lib/devise/parameter_filter.rb +2 -0
  30. data/lib/devise/parameter_sanitizer.rb +13 -1
  31. data/lib/devise/rails/routes.rb +2 -2
  32. data/lib/devise/secret_key_finder.rb +2 -0
  33. data/lib/devise/strategies/authenticatable.rb +1 -1
  34. data/lib/devise/strategies/database_authenticatable.rb +6 -1
  35. data/lib/devise/test/controller_helpers.rb +1 -1
  36. data/lib/devise/version.rb +1 -1
  37. data/lib/devise.rb +4 -0
  38. data/lib/generators/active_record/devise_generator.rb +9 -9
  39. data/lib/generators/devise/controllers_generator.rb +1 -1
  40. data/lib/generators/devise/orm_helpers.rb +2 -2
  41. data/lib/generators/mongoid/devise_generator.rb +5 -5
  42. data/lib/generators/templates/devise.rb +19 -3
  43. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +5 -1
  44. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +10 -2
  45. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +4 -1
  46. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +11 -3
  47. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +11 -3
  48. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +7 -2
  49. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +4 -1
  50. metadata +5 -310
  51. data/.gitignore +0 -10
  52. data/.travis.yml +0 -68
  53. data/.yardopts +0 -9
  54. data/CODE_OF_CONDUCT.md +0 -22
  55. data/CONTRIBUTING.md +0 -79
  56. data/Gemfile +0 -39
  57. data/Gemfile.lock +0 -193
  58. data/ISSUE_TEMPLATE.md +0 -19
  59. data/Rakefile +0 -37
  60. data/bin/test +0 -13
  61. data/devise.gemspec +0 -28
  62. data/devise.png +0 -0
  63. data/gemfiles/Gemfile.rails-4.1-stable +0 -32
  64. data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
  65. data/gemfiles/Gemfile.rails-4.2-stable +0 -32
  66. data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -192
  67. data/gemfiles/Gemfile.rails-5.0-stable +0 -33
  68. data/gemfiles/Gemfile.rails-5.0-stable.lock +0 -192
  69. data/gemfiles/Gemfile.rails-5.2-rc1 +0 -26
  70. data/gemfiles/Gemfile.rails-5.2-rc1.lock +0 -201
  71. data/guides/bug_report_templates/integration_test.rb +0 -106
  72. data/test/controllers/custom_registrations_controller_test.rb +0 -42
  73. data/test/controllers/custom_strategy_test.rb +0 -66
  74. data/test/controllers/helper_methods_test.rb +0 -24
  75. data/test/controllers/helpers_test.rb +0 -318
  76. data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -53
  77. data/test/controllers/internal_helpers_test.rb +0 -129
  78. data/test/controllers/load_hooks_controller_test.rb +0 -21
  79. data/test/controllers/passwords_controller_test.rb +0 -34
  80. data/test/controllers/sessions_controller_test.rb +0 -108
  81. data/test/controllers/url_helpers_test.rb +0 -67
  82. data/test/delegator_test.rb +0 -21
  83. data/test/devise_test.rb +0 -109
  84. data/test/failure_app_test.rb +0 -340
  85. data/test/generators/active_record_generator_test.rb +0 -130
  86. data/test/generators/controllers_generator_test.rb +0 -50
  87. data/test/generators/devise_generator_test.rb +0 -41
  88. data/test/generators/install_generator_test.rb +0 -26
  89. data/test/generators/mongoid_generator_test.rb +0 -25
  90. data/test/generators/views_generator_test.rb +0 -105
  91. data/test/helpers/devise_helper_test.rb +0 -51
  92. data/test/integration/authenticatable_test.rb +0 -706
  93. data/test/integration/confirmable_test.rb +0 -326
  94. data/test/integration/database_authenticatable_test.rb +0 -97
  95. data/test/integration/http_authenticatable_test.rb +0 -114
  96. data/test/integration/lockable_test.rb +0 -242
  97. data/test/integration/mounted_engine_test.rb +0 -38
  98. data/test/integration/omniauthable_test.rb +0 -148
  99. data/test/integration/recoverable_test.rb +0 -349
  100. data/test/integration/registerable_test.rb +0 -365
  101. data/test/integration/rememberable_test.rb +0 -219
  102. data/test/integration/timeoutable_test.rb +0 -186
  103. data/test/integration/trackable_test.rb +0 -99
  104. data/test/mailers/confirmation_instructions_test.rb +0 -117
  105. data/test/mailers/email_changed_test.rb +0 -132
  106. data/test/mailers/mailer_test.rb +0 -20
  107. data/test/mailers/reset_password_instructions_test.rb +0 -98
  108. data/test/mailers/unlock_instructions_test.rb +0 -93
  109. data/test/mapping_test.rb +0 -136
  110. data/test/models/authenticatable_test.rb +0 -25
  111. data/test/models/confirmable_test.rb +0 -549
  112. data/test/models/database_authenticatable_test.rb +0 -283
  113. data/test/models/lockable_test.rb +0 -352
  114. data/test/models/omniauthable_test.rb +0 -9
  115. data/test/models/recoverable_test.rb +0 -263
  116. data/test/models/registerable_test.rb +0 -9
  117. data/test/models/rememberable_test.rb +0 -184
  118. data/test/models/serializable_test.rb +0 -60
  119. data/test/models/timeoutable_test.rb +0 -53
  120. data/test/models/trackable_test.rb +0 -62
  121. data/test/models/validatable_test.rb +0 -121
  122. data/test/models_test.rb +0 -155
  123. data/test/omniauth/config_test.rb +0 -61
  124. data/test/omniauth/url_helpers_test.rb +0 -53
  125. data/test/orm/active_record.rb +0 -24
  126. data/test/orm/mongoid.rb +0 -15
  127. data/test/parameter_sanitizer_test.rb +0 -77
  128. data/test/rails_app/Rakefile +0 -6
  129. data/test/rails_app/app/active_record/admin.rb +0 -8
  130. data/test/rails_app/app/active_record/shim.rb +0 -4
  131. data/test/rails_app/app/active_record/user.rb +0 -20
  132. data/test/rails_app/app/active_record/user_on_engine.rb +0 -9
  133. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -9
  134. data/test/rails_app/app/active_record/user_with_validations.rb +0 -12
  135. data/test/rails_app/app/active_record/user_without_email.rb +0 -10
  136. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -8
  137. data/test/rails_app/app/controllers/admins_controller.rb +0 -8
  138. data/test/rails_app/app/controllers/application_controller.rb +0 -13
  139. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -32
  140. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -33
  141. data/test/rails_app/app/controllers/home_controller.rb +0 -31
  142. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -4
  143. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -4
  144. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -16
  145. data/test/rails_app/app/controllers/users_controller.rb +0 -33
  146. data/test/rails_app/app/helpers/application_helper.rb +0 -5
  147. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -5
  148. data/test/rails_app/app/mailers/users/mailer.rb +0 -5
  149. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -6
  150. data/test/rails_app/app/mongoid/admin.rb +0 -31
  151. data/test/rails_app/app/mongoid/shim.rb +0 -25
  152. data/test/rails_app/app/mongoid/user.rb +0 -50
  153. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -41
  154. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -41
  155. data/test/rails_app/app/mongoid/user_with_validations.rb +0 -37
  156. data/test/rails_app/app/mongoid/user_without_email.rb +0 -35
  157. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  158. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  159. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  160. data/test/rails_app/app/views/home/index.html.erb +0 -1
  161. data/test/rails_app/app/views/home/join.html.erb +0 -1
  162. data/test/rails_app/app/views/home/private.html.erb +0 -1
  163. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  164. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  165. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  166. data/test/rails_app/app/views/users/index.html.erb +0 -1
  167. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  168. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  169. data/test/rails_app/bin/bundle +0 -3
  170. data/test/rails_app/bin/rails +0 -4
  171. data/test/rails_app/bin/rake +0 -4
  172. data/test/rails_app/config/application.rb +0 -48
  173. data/test/rails_app/config/boot.rb +0 -27
  174. data/test/rails_app/config/database.yml +0 -18
  175. data/test/rails_app/config/environment.rb +0 -7
  176. data/test/rails_app/config/environments/development.rb +0 -32
  177. data/test/rails_app/config/environments/production.rb +0 -88
  178. data/test/rails_app/config/environments/test.rb +0 -47
  179. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -9
  180. data/test/rails_app/config/initializers/devise.rb +0 -182
  181. data/test/rails_app/config/initializers/inflections.rb +0 -4
  182. data/test/rails_app/config/initializers/secret_token.rb +0 -5
  183. data/test/rails_app/config/initializers/session_store.rb +0 -3
  184. data/test/rails_app/config/routes.rb +0 -128
  185. data/test/rails_app/config.ru +0 -4
  186. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -77
  187. data/test/rails_app/db/schema.rb +0 -57
  188. data/test/rails_app/lib/shared_admin.rb +0 -23
  189. data/test/rails_app/lib/shared_user.rb +0 -32
  190. data/test/rails_app/lib/shared_user_without_email.rb +0 -28
  191. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -15
  192. data/test/rails_app/public/404.html +0 -26
  193. data/test/rails_app/public/422.html +0 -26
  194. data/test/rails_app/public/500.html +0 -26
  195. data/test/rails_app/public/favicon.ico +0 -0
  196. data/test/rails_test.rb +0 -11
  197. data/test/routes_test.rb +0 -281
  198. data/test/secret_key_finder_test.rb +0 -97
  199. data/test/support/action_controller/record_identifier.rb +0 -12
  200. data/test/support/assertions.rb +0 -30
  201. data/test/support/helpers.rb +0 -83
  202. data/test/support/http_method_compatibility.rb +0 -53
  203. data/test/support/integration.rb +0 -95
  204. data/test/support/locale/en.yml +0 -8
  205. data/test/support/mongoid.yml +0 -6
  206. data/test/support/webrat/integrations/rails.rb +0 -35
  207. data/test/test/controller_helpers_test.rb +0 -193
  208. data/test/test/integration_helpers_test.rb +0 -34
  209. data/test/test_helper.rb +0 -36
  210. data/test/test_models.rb +0 -35
@@ -144,11 +144,20 @@ module Devise
144
144
 
145
145
  opts[:format] = request_format unless skip_format?
146
146
 
147
- opts[:script_name] = relative_url_root if relative_url_root?
148
-
149
147
  router_name = Devise.mappings[scope].router_name || Devise.available_router_name
150
148
  context = send(router_name)
151
149
 
150
+ if relative_url_root?
151
+ opts[:script_name] = relative_url_root
152
+
153
+ # We need to add the rootpath to `script_name` manually for applications that use a Rails
154
+ # 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.
156
+ elsif root_path_defined?(context) && !rails_51_and_up?
157
+ rootpath = context.routes.url_helpers.root_path
158
+ opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
159
+ end
160
+
152
161
  if context.respond_to?(route)
153
162
  context.send(route, opts)
154
163
  elsif respond_to?(:root_url)
@@ -242,7 +251,7 @@ module Devise
242
251
  # Check if flash messages should be emitted. Default is to do it on
243
252
  # navigational formats
244
253
  def is_flashing_format?
245
- is_navigational_format?
254
+ request.respond_to?(:flash) && is_navigational_format?
246
255
  end
247
256
 
248
257
  def request_format
@@ -260,5 +269,17 @@ module Devise
260
269
  def relative_url_root?
261
270
  relative_url_root.present?
262
271
  end
272
+
273
+ ActiveSupport.run_load_hooks(:devise_failure_app, self)
274
+
275
+ private
276
+
277
+ def root_path_defined?(context)
278
+ defined?(context.routes) && context.routes.url_helpers.respond_to?(:root_path)
279
+ end
280
+
281
+ def rails_51_and_up?
282
+ Rails.gem_version >= Gem::Version.new("5.1")
283
+ end
263
284
  end
264
285
  end
@@ -1,6 +1,5 @@
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'
6
5
 
@@ -134,16 +133,18 @@ module Devise
134
133
  # This is an internal method called every time Devise needs
135
134
  # to send a notification/mail. This can be overridden if you
136
135
  # 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
136
+ # if you are using a queue to deliver e-mails (active job, delayed
137
+ # job, sidekiq, resque, etc), you must add the delivery to the queue
139
138
  # just after the transaction was committed. To achieve this,
140
139
  # you can override send_devise_notification to store the
141
- # deliveries until the after_commit callback is triggered:
140
+ # deliveries until the after_commit callback is triggered.
141
+ #
142
+ # The following example uses Active Job's `deliver_later` :
142
143
  #
143
144
  # class User
144
145
  # devise :database_authenticatable, :confirmable
145
146
  #
146
- # after_commit :send_pending_notifications
147
+ # after_commit :send_pending_devise_notifications
147
148
  #
148
149
  # protected
149
150
  #
@@ -152,38 +153,43 @@ module Devise
152
153
  # # delivery until the after_commit callback otherwise
153
154
  # # send now because after_commit will not be called.
154
155
  # if new_record? || changed?
155
- # pending_notifications << [notification, args]
156
+ # pending_devise_notifications << [notification, args]
156
157
  # 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
158
+ # render_and_send_devise_message(notification, *args)
164
159
  # end
165
160
  # end
166
161
  #
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
162
+ # private
163
+ #
164
+ # def send_pending_devise_notifications
165
+ # pending_devise_notifications.each do |notification, args|
166
+ # render_and_send_devise_message(notification, *args)
176
167
  # end
177
168
  #
178
169
  # # Empty the pending notifications array because the
179
170
  # # after_commit hook can be called multiple times which
180
171
  # # could cause multiple emails to be sent.
181
- # pending_notifications.clear
172
+ # pending_devise_notifications.clear
182
173
  # end
183
174
  #
184
- # def pending_notifications
185
- # @pending_notifications ||= []
175
+ # def pending_devise_notifications
176
+ # @pending_devise_notifications ||= []
186
177
  # end
178
+ #
179
+ # def render_and_send_devise_message(notification, *args)
180
+ # message = devise_mailer.send(notification, self, *args)
181
+ #
182
+ # # Deliver later with Active Job's `deliver_later`
183
+ # if message.respond_to?(:deliver_later)
184
+ # message.deliver_later
185
+ # # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
186
+ # elsif message.respond_to?(:deliver_now)
187
+ # message.deliver_now
188
+ # else
189
+ # message.deliver
190
+ # end
191
+ # end
192
+ #
187
193
  # end
188
194
  #
189
195
  def send_devise_notification(notification, *args)
@@ -276,28 +282,20 @@ module Devise
276
282
 
277
283
  # Find or initialize a record with group of attributes based on a list of required attributes.
278
284
  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? }
285
+ attributes.try(:permit!)
286
+ attributes = attributes.to_h.with_indifferent_access
287
+ .slice(*required_attributes)
288
+ .delete_if { |key, value| value.blank? }
285
289
 
286
290
  if attributes.size == required_attributes.size
287
- record = find_first_by_auth_conditions(attributes)
291
+ record = find_first_by_auth_conditions(attributes) and return record
288
292
  end
289
293
 
290
- unless record
291
- record = new
292
-
294
+ new(devise_parameter_filter.filter(attributes)).tap do |record|
293
295
  required_attributes.each do |key|
294
- value = attributes[key]
295
- record.send("#{key}=", value)
296
- record.errors.add(key, value.present? ? error : :blank)
296
+ record.errors.add(key, attributes[key].blank? ? :blank : error)
297
297
  end
298
298
  end
299
-
300
- record
301
299
  end
302
300
 
303
301
  protected
@@ -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
@@ -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)
@@ -35,6 +35,22 @@ module Devise
35
35
  attr_accessor :password_confirmation
36
36
  end
37
37
 
38
+ def initialize(*args, &block)
39
+ @skip_email_changed_notification = false
40
+ @skip_password_change_notification = false
41
+ super
42
+ end
43
+
44
+ # Skips sending the email changed notification after_update
45
+ def skip_email_changed_notification!
46
+ @skip_email_changed_notification = true
47
+ end
48
+
49
+ # Skips sending the password change notification after_update
50
+ def skip_password_change_notification!
51
+ @skip_password_change_notification = true
52
+ end
53
+
38
54
  def self.required_fields(klass)
39
55
  [:encrypted_password] + klass.authentication_keys
40
56
  end
@@ -65,6 +81,15 @@ module Devise
65
81
  # their password). In case the password field is rejected, the confirmation
66
82
  # is also rejected as long as it is also blank.
67
83
  def update_with_password(params, *options)
84
+ if options.present?
85
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
86
+ [Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
87
+ (`options`) is deprecated and it will be removed in the next major version.
88
+ It was added to support a feature deprecated in Rails 4, so you can safely remove it
89
+ from your code.
90
+ DEPRECATION
91
+ end
92
+
68
93
  current_password = params.delete(:current_password)
69
94
 
70
95
  if params[:password].blank?
@@ -73,11 +98,11 @@ module Devise
73
98
  end
74
99
 
75
100
  result = if valid_password?(current_password)
76
- update_attributes(params, *options)
101
+ update(params, *options)
77
102
  else
78
- self.assign_attributes(params, *options)
79
- self.valid?
80
- self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
103
+ assign_attributes(params, *options)
104
+ valid?
105
+ errors.add(:current_password, current_password.blank? ? :blank : :invalid)
81
106
  false
82
107
  end
83
108
 
@@ -98,10 +123,19 @@ module Devise
98
123
  # end
99
124
  #
100
125
  def update_without_password(params, *options)
126
+ if options.present?
127
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
128
+ [Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
129
+ (`options`) is deprecated and it will be removed in the next major version.
130
+ It was added to support a feature deprecated in Rails 4, so you can safely remove it
131
+ from your code.
132
+ DEPRECATION
133
+ end
134
+
101
135
  params.delete(:password)
102
136
  params.delete(:password_confirmation)
103
137
 
104
- result = update_attributes(params, *options)
138
+ result = update(params, *options)
105
139
  clean_up_passwords
106
140
  result
107
141
  end
@@ -113,8 +147,8 @@ module Devise
113
147
  result = if valid_password?(current_password)
114
148
  destroy
115
149
  else
116
- self.valid?
117
- self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
150
+ valid?
151
+ errors.add(:current_password, current_password.blank? ? :blank : :invalid)
118
152
  false
119
153
  end
120
154
 
@@ -169,21 +203,21 @@ module Devise
169
203
 
170
204
  if Devise.activerecord51?
171
205
  def send_email_changed_notification?
172
- self.class.send_email_changed_notification && saved_change_to_email?
206
+ self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
173
207
  end
174
208
  else
175
209
  def send_email_changed_notification?
176
- self.class.send_email_changed_notification && email_changed?
210
+ self.class.send_email_changed_notification && email_changed? && !@skip_email_changed_notification
177
211
  end
178
212
  end
179
213
 
180
214
  if Devise.activerecord51?
181
215
  def send_password_change_notification?
182
- self.class.send_password_change_notification && saved_change_to_encrypted_password?
216
+ self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
183
217
  end
184
218
  else
185
219
  def send_password_change_notification?
186
- self.class.send_password_change_notification && encrypted_password_changed?
220
+ self.class.send_password_change_notification && encrypted_password_changed? && !@skip_password_change_notification
187
221
  end
188
222
  end
189
223
 
@@ -112,8 +112,8 @@ module Devise
112
112
  end
113
113
 
114
114
  def increment_failed_attempts
115
- self.failed_attempts ||= 0
116
- self.failed_attempts += 1
115
+ self.class.increment_counter(:failed_attempts, id)
116
+ reload
117
117
  end
118
118
 
119
119
  def unauthenticated_message
@@ -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
@@ -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
 
@@ -39,6 +39,13 @@ module Devise
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
@@ -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?
@@ -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)
@@ -135,10 +135,10 @@ module ActionDispatch::Routing
135
135
  # * failure_app: a rack app which is invoked whenever there is a failure. Strings representing a given
136
136
  # are also allowed as parameter.
137
137
  #
138
- # * sign_out_via: the HTTP method(s) accepted for the :sign_out action (default: :get),
138
+ # * sign_out_via: the HTTP method(s) accepted for the :sign_out action (default: :delete),
139
139
  # if you wish to restrict this to accept only :post or :delete requests you should do:
140
140
  #
141
- # devise_for :users, sign_out_via: [:post, :delete]
141
+ # devise_for :users, sign_out_via: [:get, :post]
142
142
  #
143
143
  # You need to make sure that your sign_out controls trigger a request with a matching HTTP method.
144
144
  #
@@ -13,6 +13,8 @@ module Devise
13
13
  @application.secrets.secret_key_base
14
14
  elsif @application.config.respond_to?(:secret_key_base) && key_exists?(@application.config)
15
15
  @application.config.secret_key_base
16
+ elsif @application.respond_to?(:secret_key_base) && key_exists?(@application)
17
+ @application.secret_key_base
16
18
  end
17
19
  end
18
20
 
@@ -28,7 +28,7 @@ module Devise
28
28
  private
29
29
 
30
30
  # Receives a resource and check if it is valid by calling valid_for_authentication?
31
- # An optional block that will be triggered while validating can be optionally
31
+ # A block that will be triggered while validating can be optionally
32
32
  # given as parameter. Check Devise::Models::Authenticatable.valid_for_authentication?
33
33
  # for more information.
34
34
  #
@@ -16,8 +16,13 @@ module Devise
16
16
  success!(resource)
17
17
  end
18
18
 
19
+ # In paranoid mode, hash the password even when a resource doesn't exist for the given authentication key.
20
+ # This is necessary to prevent enumeration attacks - e.g. the request is faster when a resource doesn't
21
+ # exist in the database if the password hashing algorithm is not called.
19
22
  mapping.to.new.password = password if !hashed && Devise.paranoid
20
- fail(:not_found_in_database) unless resource
23
+ unless resource
24
+ Devise.paranoid ? fail(:invalid) : fail(:not_found_in_database)
25
+ end
21
26
  end
22
27
  end
23
28
  end
@@ -139,7 +139,7 @@ module Devise
139
139
 
140
140
  status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
141
141
  @controller.response.headers.merge!(headers)
142
- @controller.response.content_type = headers["Content-Type"] unless Rails.version.start_with?('5')
142
+ @controller.response.content_type = headers["Content-Type"] unless Rails::VERSION::MAJOR >= 5
143
143
  @controller.status = status
144
144
  @controller.response.body = response.body
145
145
  nil # causes process return @response
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Devise
4
- VERSION = "4.4.3".freeze
4
+ VERSION = "4.7.1".freeze
5
5
  end
data/lib/devise.rb CHANGED
@@ -293,6 +293,10 @@ module Devise
293
293
  mattr_accessor :token_generator
294
294
  @@token_generator = nil
295
295
 
296
+ # When set to false, changing a password does not automatically sign in a user
297
+ mattr_accessor :sign_in_after_change_password
298
+ @@sign_in_after_change_password = true
299
+
296
300
  def self.rails51? # :nodoc:
297
301
  Rails.gem_version >= Gem::Version.new("5.1.x")
298
302
  end
@@ -54,11 +54,11 @@ module ActiveRecord
54
54
  t.datetime :remember_created_at
55
55
 
56
56
  ## Trackable
57
- t.integer :sign_in_count, default: 0, null: false
58
- t.datetime :current_sign_in_at
59
- t.datetime :last_sign_in_at
60
- t.#{ip_column} :current_sign_in_ip
61
- t.#{ip_column} :last_sign_in_ip
57
+ # t.integer :sign_in_count, default: 0, null: false
58
+ # t.datetime :current_sign_in_at
59
+ # t.datetime :last_sign_in_at
60
+ # t.#{ip_column} :current_sign_in_ip
61
+ # t.#{ip_column} :last_sign_in_ip
62
62
 
63
63
  ## Confirmable
64
64
  # t.string :confirmation_token
@@ -82,8 +82,8 @@ RUBY
82
82
  postgresql?
83
83
  end
84
84
 
85
- def rails5?
86
- Rails.version.start_with? '5'
85
+ def rails5_and_up?
86
+ Rails::VERSION::MAJOR >= 5
87
87
  end
88
88
 
89
89
  def postgresql?
@@ -92,13 +92,13 @@ RUBY
92
92
  end
93
93
 
94
94
  def migration_version
95
- if rails5?
95
+ if rails5_and_up?
96
96
  "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
97
97
  end
98
98
  end
99
99
 
100
100
  def primary_key_type
101
- primary_key_string if rails5?
101
+ primary_key_string if rails5_and_up?
102
102
  end
103
103
 
104
104
  def primary_key_string
@@ -18,7 +18,7 @@ module Devise
18
18
 
19
19
  This will create a controller class at app/controllers/users/sessions_controller.rb like this:
20
20
 
21
- class Users::ConfirmationsController < Devise::ConfirmationsController
21
+ class Users::SessionsController < Devise::SessionsController
22
22
  content...
23
23
  end
24
24
  DESC
@@ -6,9 +6,9 @@ module Devise
6
6
  def model_contents
7
7
  buffer = <<-CONTENT
8
8
  # Include default devise modules. Others available are:
9
- # :confirmable, :lockable, :timeoutable and :omniauthable
9
+ # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
10
10
  devise :database_authenticatable, :registerable,
11
- :recoverable, :rememberable, :trackable, :validatable
11
+ :recoverable, :rememberable, :validatable
12
12
 
13
13
  CONTENT
14
14
  buffer
@@ -34,11 +34,11 @@ module Mongoid
34
34
  field :remember_created_at, type: Time
35
35
 
36
36
  ## Trackable
37
- field :sign_in_count, type: Integer, default: 0
38
- field :current_sign_in_at, type: Time
39
- field :last_sign_in_at, type: Time
40
- field :current_sign_in_ip, type: String
41
- field :last_sign_in_ip, type: String
37
+ # field :sign_in_count, type: Integer, default: 0
38
+ # field :current_sign_in_at, type: Time
39
+ # field :last_sign_in_at, type: Time
40
+ # field :current_sign_in_ip, type: String
41
+ # field :last_sign_in_ip, type: String
42
42
 
43
43
  ## Confirmable
44
44
  # field :confirmation_token, type: String
@@ -9,7 +9,7 @@ Devise.setup do |config|
9
9
  # Devise will use the `secret_key_base` as its `secret_key`
10
10
  # by default. You can change it below and use your own secret key.
11
11
  # config.secret_key = '<%= SecureRandom.hex(64) %>'
12
-
12
+
13
13
  # ==> Controller configuration
14
14
  # Configure the parent class to the devise controllers.
15
15
  # config.parent_controller = 'DeviseController'
@@ -126,8 +126,11 @@ Devise.setup do |config|
126
126
  # A period that the user is allowed to access the website even without
127
127
  # confirming their account. For instance, if set to 2.days, the user will be
128
128
  # able to access the website for two days without confirming their account,
129
- # access will be blocked just in the third day. Default is 0.days, meaning
130
- # the user cannot access the website without confirming their account.
129
+ # access will be blocked just in the third day.
130
+ # You can also set it to nil, which will allow the user to access the website
131
+ # without confirming their account.
132
+ # Default is 0.days, meaning the user cannot access the website without
133
+ # confirming their account.
131
134
  # config.allow_unconfirmed_access_for = 2.days
132
135
 
133
136
  # A period that the user is allowed to confirm their account before their
@@ -280,4 +283,17 @@ Devise.setup do |config|
280
283
  # When using OmniAuth, Devise cannot automatically set OmniAuth path,
281
284
  # so you need to do it manually. For the users scope, it would be:
282
285
  # config.omniauth_path_prefix = '/my_engine/users/auth'
286
+
287
+ # ==> Turbolinks configuration
288
+ # If your app is using Turbolinks, Turbolinks::Controller needs to be included to make redirection work correctly:
289
+ #
290
+ # ActiveSupport.on_load(:devise_failure_app) do
291
+ # include Turbolinks::Controller
292
+ # end
293
+
294
+ # ==> Configuration for :registerable
295
+
296
+ # When set to false, does not sign a user in automatically after their password is
297
+ # changed. Defaults to true, so a user is signed in automatically after changing a password.
298
+ # config.sign_in_after_change_password = true
283
299
  end
@@ -5,7 +5,11 @@
5
5
  <%= f.full_error :confirmation_token %>
6
6
 
7
7
  <div class="form-inputs">
8
- <%= f.input :email, required: true, autofocus: true %>
8
+ <%= f.input :email,
9
+ required: true,
10
+ autofocus: true,
11
+ value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email),
12
+ input_html: { autocomplete: "email" } %>
9
13
  </div>
10
14
 
11
15
  <div class="form-actions">
@@ -7,8 +7,16 @@
7
7
  <%= f.full_error :reset_password_token %>
8
8
 
9
9
  <div class="form-inputs">
10
- <%= f.input :password, label: "New password", required: true, autofocus: true, hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length) %>
11
- <%= f.input :password_confirmation, label: "Confirm your new password", required: true %>
10
+ <%= f.input :password,
11
+ label: "New password",
12
+ required: true,
13
+ autofocus: true,
14
+ hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length),
15
+ input_html: { autocomplete: "new-password" } %>
16
+ <%= f.input :password_confirmation,
17
+ label: "Confirm your new password",
18
+ required: true,
19
+ input_html: { autocomplete: "new-password" } %>
12
20
  </div>
13
21
 
14
22
  <div class="form-actions">