devise 4.3.0 → 4.9.2

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 (259) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +205 -2
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +214 -57
  5. data/app/controllers/devise/confirmations_controller.rb +3 -0
  6. data/app/controllers/devise/omniauth_callbacks_controller.rb +3 -1
  7. data/app/controllers/devise/passwords_controller.rb +5 -2
  8. data/app/controllers/devise/registrations_controller.rb +32 -12
  9. data/app/controllers/devise/sessions_controller.rb +4 -2
  10. data/app/controllers/devise/unlocks_controller.rb +3 -0
  11. data/app/controllers/devise_controller.rb +6 -3
  12. data/app/helpers/devise_helper.rb +23 -18
  13. data/app/mailers/devise/mailer.rb +7 -5
  14. data/app/views/devise/confirmations/new.html.erb +2 -2
  15. data/app/views/devise/passwords/edit.html.erb +3 -3
  16. data/app/views/devise/passwords/new.html.erb +2 -2
  17. data/app/views/devise/registrations/edit.html.erb +6 -6
  18. data/app/views/devise/registrations/new.html.erb +4 -4
  19. data/app/views/devise/sessions/new.html.erb +4 -4
  20. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  21. data/app/views/devise/shared/_links.html.erb +8 -8
  22. data/app/views/devise/unlocks/new.html.erb +2 -2
  23. data/config/locales/en.yml +3 -2
  24. data/lib/devise/controllers/helpers.rb +10 -8
  25. data/lib/devise/controllers/rememberable.rb +2 -0
  26. data/lib/devise/controllers/responder.rb +35 -0
  27. data/lib/devise/controllers/scoped_views.rb +2 -0
  28. data/lib/devise/controllers/sign_in_out.rb +14 -4
  29. data/lib/devise/controllers/store_location.rb +24 -6
  30. data/lib/devise/controllers/url_helpers.rb +3 -1
  31. data/lib/devise/delegator.rb +2 -0
  32. data/lib/devise/encryptor.rb +2 -0
  33. data/lib/devise/failure_app.rb +33 -7
  34. data/lib/devise/hooks/activatable.rb +2 -0
  35. data/lib/devise/hooks/csrf_cleaner.rb +8 -1
  36. data/lib/devise/hooks/forgetable.rb +2 -0
  37. data/lib/devise/hooks/lockable.rb +4 -5
  38. data/lib/devise/hooks/proxy.rb +2 -0
  39. data/lib/devise/hooks/rememberable.rb +2 -0
  40. data/lib/devise/hooks/timeoutable.rb +4 -2
  41. data/lib/devise/hooks/trackable.rb +2 -0
  42. data/lib/devise/mailers/helpers.rb +2 -0
  43. data/lib/devise/mapping.rb +3 -1
  44. data/lib/devise/models/authenticatable.rb +55 -50
  45. data/lib/devise/models/confirmable.rb +36 -40
  46. data/lib/devise/models/database_authenticatable.rb +57 -36
  47. data/lib/devise/models/lockable.rb +18 -4
  48. data/lib/devise/models/omniauthable.rb +4 -2
  49. data/lib/devise/models/recoverable.rb +10 -19
  50. data/lib/devise/models/registerable.rb +4 -0
  51. data/lib/devise/models/rememberable.rb +5 -3
  52. data/lib/devise/models/timeoutable.rb +3 -1
  53. data/lib/devise/models/trackable.rb +15 -1
  54. data/lib/devise/models/validatable.rb +7 -10
  55. data/lib/devise/models.rb +3 -0
  56. data/lib/devise/modules.rb +2 -0
  57. data/lib/devise/omniauth/config.rb +2 -0
  58. data/lib/devise/omniauth/url_helpers.rb +2 -0
  59. data/lib/devise/omniauth.rb +4 -5
  60. data/lib/devise/orm/active_record.rb +2 -0
  61. data/lib/devise/orm/mongoid.rb +2 -0
  62. data/lib/devise/orm.rb +71 -0
  63. data/lib/devise/parameter_filter.rb +4 -0
  64. data/lib/devise/parameter_sanitizer.rb +15 -1
  65. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  66. data/lib/devise/rails/routes.rb +8 -6
  67. data/lib/devise/rails/warden_compat.rb +2 -0
  68. data/lib/devise/rails.rb +3 -5
  69. data/lib/devise/secret_key_finder.rb +27 -0
  70. data/lib/devise/strategies/authenticatable.rb +3 -1
  71. data/lib/devise/strategies/base.rb +2 -0
  72. data/lib/devise/strategies/database_authenticatable.rb +8 -1
  73. data/lib/devise/strategies/rememberable.rb +2 -0
  74. data/lib/devise/test/controller_helpers.rb +6 -1
  75. data/lib/devise/test/integration_helpers.rb +3 -1
  76. data/lib/devise/test_helpers.rb +2 -0
  77. data/lib/devise/time_inflector.rb +2 -0
  78. data/lib/devise/token_generator.rb +2 -0
  79. data/lib/devise/version.rb +3 -1
  80. data/lib/devise.rb +38 -12
  81. data/lib/generators/active_record/devise_generator.rb +40 -12
  82. data/lib/generators/active_record/templates/migration.rb +3 -1
  83. data/lib/generators/active_record/templates/migration_existing.rb +2 -0
  84. data/lib/generators/devise/controllers_generator.rb +3 -1
  85. data/lib/generators/devise/devise_generator.rb +5 -3
  86. data/lib/generators/devise/install_generator.rb +3 -5
  87. data/lib/generators/devise/orm_helpers.rb +9 -3
  88. data/lib/generators/devise/views_generator.rb +8 -9
  89. data/lib/generators/mongoid/devise_generator.rb +7 -5
  90. data/lib/generators/templates/README +9 -1
  91. data/lib/generators/templates/controllers/confirmations_controller.rb +2 -0
  92. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +3 -1
  93. data/lib/generators/templates/controllers/passwords_controller.rb +2 -0
  94. data/lib/generators/templates/controllers/registrations_controller.rb +2 -0
  95. data/lib/generators/templates/controllers/sessions_controller.rb +2 -0
  96. data/lib/generators/templates/controllers/unlocks_controller.rb +2 -0
  97. data/lib/generators/templates/devise.rb +43 -7
  98. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +5 -1
  99. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +10 -2
  100. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +4 -1
  101. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +12 -4
  102. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +11 -3
  103. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +7 -2
  104. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +4 -1
  105. metadata +24 -307
  106. data/.gitignore +0 -10
  107. data/.travis.yml +0 -58
  108. data/.yardopts +0 -9
  109. data/CODE_OF_CONDUCT.md +0 -22
  110. data/CONTRIBUTING.md +0 -79
  111. data/Gemfile +0 -40
  112. data/Gemfile.lock +0 -194
  113. data/Rakefile +0 -36
  114. data/bin/test +0 -13
  115. data/devise.gemspec +0 -26
  116. data/devise.png +0 -0
  117. data/gemfiles/Gemfile.rails-4.1-stable +0 -30
  118. data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
  119. data/gemfiles/Gemfile.rails-4.2-stable +0 -30
  120. data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -192
  121. data/gemfiles/Gemfile.rails-5.0-stable +0 -34
  122. data/gemfiles/Gemfile.rails-5.0-stable.lock +0 -193
  123. data/guides/bug_report_templates/integration_test.rb +0 -104
  124. data/test/controllers/custom_registrations_controller_test.rb +0 -40
  125. data/test/controllers/custom_strategy_test.rb +0 -64
  126. data/test/controllers/helper_methods_test.rb +0 -22
  127. data/test/controllers/helpers_test.rb +0 -316
  128. data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -51
  129. data/test/controllers/internal_helpers_test.rb +0 -127
  130. data/test/controllers/load_hooks_controller_test.rb +0 -19
  131. data/test/controllers/passwords_controller_test.rb +0 -32
  132. data/test/controllers/sessions_controller_test.rb +0 -106
  133. data/test/controllers/url_helpers_test.rb +0 -65
  134. data/test/delegator_test.rb +0 -19
  135. data/test/devise_test.rb +0 -107
  136. data/test/failure_app_test.rb +0 -338
  137. data/test/generators/active_record_generator_test.rb +0 -83
  138. data/test/generators/controllers_generator_test.rb +0 -48
  139. data/test/generators/devise_generator_test.rb +0 -39
  140. data/test/generators/install_generator_test.rb +0 -24
  141. data/test/generators/mongoid_generator_test.rb +0 -23
  142. data/test/generators/views_generator_test.rb +0 -103
  143. data/test/helpers/devise_helper_test.rb +0 -49
  144. data/test/integration/authenticatable_test.rb +0 -698
  145. data/test/integration/confirmable_test.rb +0 -324
  146. data/test/integration/database_authenticatable_test.rb +0 -95
  147. data/test/integration/http_authenticatable_test.rb +0 -106
  148. data/test/integration/lockable_test.rb +0 -240
  149. data/test/integration/mounted_engine_test.rb +0 -36
  150. data/test/integration/omniauthable_test.rb +0 -135
  151. data/test/integration/recoverable_test.rb +0 -347
  152. data/test/integration/registerable_test.rb +0 -363
  153. data/test/integration/rememberable_test.rb +0 -217
  154. data/test/integration/timeoutable_test.rb +0 -184
  155. data/test/integration/trackable_test.rb +0 -92
  156. data/test/mailers/confirmation_instructions_test.rb +0 -115
  157. data/test/mailers/email_changed_test.rb +0 -130
  158. data/test/mailers/mailer_test.rb +0 -18
  159. data/test/mailers/reset_password_instructions_test.rb +0 -96
  160. data/test/mailers/unlock_instructions_test.rb +0 -91
  161. data/test/mapping_test.rb +0 -134
  162. data/test/models/authenticatable_test.rb +0 -23
  163. data/test/models/confirmable_test.rb +0 -536
  164. data/test/models/database_authenticatable_test.rb +0 -281
  165. data/test/models/lockable_test.rb +0 -350
  166. data/test/models/omniauthable_test.rb +0 -7
  167. data/test/models/recoverable_test.rb +0 -261
  168. data/test/models/registerable_test.rb +0 -7
  169. data/test/models/rememberable_test.rb +0 -182
  170. data/test/models/serializable_test.rb +0 -54
  171. data/test/models/timeoutable_test.rb +0 -51
  172. data/test/models/trackable_test.rb +0 -41
  173. data/test/models/validatable_test.rb +0 -119
  174. data/test/models_test.rb +0 -153
  175. data/test/omniauth/config_test.rb +0 -59
  176. data/test/omniauth/url_helpers_test.rb +0 -51
  177. data/test/orm/active_record.rb +0 -17
  178. data/test/orm/mongoid.rb +0 -13
  179. data/test/parameter_sanitizer_test.rb +0 -75
  180. data/test/rails_app/Rakefile +0 -6
  181. data/test/rails_app/app/active_record/admin.rb +0 -6
  182. data/test/rails_app/app/active_record/shim.rb +0 -2
  183. data/test/rails_app/app/active_record/user.rb +0 -7
  184. data/test/rails_app/app/active_record/user_on_engine.rb +0 -7
  185. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -7
  186. data/test/rails_app/app/active_record/user_without_email.rb +0 -8
  187. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
  188. data/test/rails_app/app/controllers/admins_controller.rb +0 -6
  189. data/test/rails_app/app/controllers/application_controller.rb +0 -11
  190. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -30
  191. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -31
  192. data/test/rails_app/app/controllers/home_controller.rb +0 -29
  193. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
  194. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
  195. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
  196. data/test/rails_app/app/controllers/users_controller.rb +0 -31
  197. data/test/rails_app/app/helpers/application_helper.rb +0 -3
  198. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -3
  199. data/test/rails_app/app/mailers/users/mailer.rb +0 -3
  200. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -4
  201. data/test/rails_app/app/mongoid/admin.rb +0 -29
  202. data/test/rails_app/app/mongoid/shim.rb +0 -23
  203. data/test/rails_app/app/mongoid/user.rb +0 -39
  204. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -39
  205. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -39
  206. data/test/rails_app/app/mongoid/user_without_email.rb +0 -33
  207. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  208. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  209. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  210. data/test/rails_app/app/views/home/index.html.erb +0 -1
  211. data/test/rails_app/app/views/home/join.html.erb +0 -1
  212. data/test/rails_app/app/views/home/private.html.erb +0 -1
  213. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  214. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  215. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  216. data/test/rails_app/app/views/users/index.html.erb +0 -1
  217. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  218. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  219. data/test/rails_app/bin/bundle +0 -3
  220. data/test/rails_app/bin/rails +0 -4
  221. data/test/rails_app/bin/rake +0 -4
  222. data/test/rails_app/config/application.rb +0 -44
  223. data/test/rails_app/config/boot.rb +0 -20
  224. data/test/rails_app/config/database.yml +0 -18
  225. data/test/rails_app/config/environment.rb +0 -5
  226. data/test/rails_app/config/environments/development.rb +0 -30
  227. data/test/rails_app/config/environments/production.rb +0 -86
  228. data/test/rails_app/config/environments/test.rb +0 -45
  229. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  230. data/test/rails_app/config/initializers/devise.rb +0 -180
  231. data/test/rails_app/config/initializers/inflections.rb +0 -2
  232. data/test/rails_app/config/initializers/secret_token.rb +0 -3
  233. data/test/rails_app/config/initializers/session_store.rb +0 -1
  234. data/test/rails_app/config/routes.rb +0 -126
  235. data/test/rails_app/config.ru +0 -4
  236. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -75
  237. data/test/rails_app/db/schema.rb +0 -55
  238. data/test/rails_app/lib/shared_admin.rb +0 -21
  239. data/test/rails_app/lib/shared_user.rb +0 -30
  240. data/test/rails_app/lib/shared_user_without_email.rb +0 -26
  241. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -13
  242. data/test/rails_app/public/404.html +0 -26
  243. data/test/rails_app/public/422.html +0 -26
  244. data/test/rails_app/public/500.html +0 -26
  245. data/test/rails_app/public/favicon.ico +0 -0
  246. data/test/rails_test.rb +0 -9
  247. data/test/routes_test.rb +0 -279
  248. data/test/support/action_controller/record_identifier.rb +0 -10
  249. data/test/support/assertions.rb +0 -28
  250. data/test/support/helpers.rb +0 -77
  251. data/test/support/http_method_compatibility.rb +0 -51
  252. data/test/support/integration.rb +0 -92
  253. data/test/support/locale/en.yml +0 -8
  254. data/test/support/mongoid.yml +0 -6
  255. data/test/support/webrat/integrations/rails.rb +0 -33
  256. data/test/test/controller_helpers_test.rb +0 -186
  257. data/test/test/integration_helpers_test.rb +0 -32
  258. data/test/test_helper.rb +0 -34
  259. data/test/test_models.rb +0 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "action_controller/metal"
2
4
 
3
5
  module Devise
@@ -69,8 +71,11 @@ module Devise
69
71
  end
70
72
 
71
73
  flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
72
- # self.response = recall_app(warden_options[:recall]).call(env)
73
- 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
+ }
74
79
  end
75
80
 
76
81
  def redirect
@@ -105,7 +110,7 @@ module Devise
105
110
  options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
106
111
  options = i18n_options(options)
107
112
 
108
- I18n.t(:"#{scope}.#{message}", options)
113
+ I18n.t(:"#{scope}.#{message}", **options)
109
114
  else
110
115
  message.to_s
111
116
  end
@@ -142,11 +147,20 @@ module Devise
142
147
 
143
148
  opts[:format] = request_format unless skip_format?
144
149
 
145
- opts[:script_name] = relative_url_root if relative_url_root?
146
-
147
150
  router_name = Devise.mappings[scope].router_name || Devise.available_router_name
148
151
  context = send(router_name)
149
152
 
153
+ if relative_url_root?
154
+ opts[:script_name] = relative_url_root
155
+
156
+ # We need to add the rootpath to `script_name` manually for applications that use a Rails
157
+ # version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
158
+ # that use Devise. Remove it when the support of Rails 5.0 is dropped.
159
+ elsif root_path_defined?(context) && !rails_51_and_up?
160
+ rootpath = context.routes.url_helpers.root_path
161
+ opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
162
+ end
163
+
150
164
  if context.respond_to?(route)
151
165
  context.send(route, opts)
152
166
  elsif respond_to?(:root_url)
@@ -157,7 +171,7 @@ module Devise
157
171
  end
158
172
 
159
173
  def skip_format?
160
- %w(html */*).include? request_format.to_s
174
+ %w(html */* turbo_stream).include? request_format.to_s
161
175
  end
162
176
 
163
177
  # Choose whether we should respond in an HTTP authentication fashion,
@@ -240,7 +254,7 @@ module Devise
240
254
  # Check if flash messages should be emitted. Default is to do it on
241
255
  # navigational formats
242
256
  def is_flashing_format?
243
- is_navigational_format?
257
+ request.respond_to?(:flash) && is_navigational_format?
244
258
  end
245
259
 
246
260
  def request_format
@@ -258,5 +272,17 @@ module Devise
258
272
  def relative_url_root?
259
273
  relative_url_root.present?
260
274
  end
275
+
276
+ ActiveSupport.run_load_hooks(:devise_failure_app, self)
277
+
278
+ private
279
+
280
+ def root_path_defined?(context)
281
+ defined?(context.routes) && context.routes.url_helpers.respond_to?(:root_path)
282
+ end
283
+
284
+ def rails_51_and_up?
285
+ Rails.gem_version >= Gem::Version.new("5.1")
286
+ end
261
287
  end
262
288
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Deny user access whenever their account is not active yet.
2
4
  # We need this as hook to validate the user activity on each request
3
5
  # and in case the user is using other strategies beside Devise ones.
@@ -1,7 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Warden::Manager.after_authentication do |record, warden, options|
2
4
  clean_up_for_winning_strategy = !warden.winning_strategy.respond_to?(:clean_up_csrf?) ||
3
5
  warden.winning_strategy.clean_up_csrf?
4
6
  if Devise.clean_up_csrf_token_on_authentication && clean_up_for_winning_strategy
5
- 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
6
13
  end
7
14
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Before logout hook to forget the user in the given scope, if it responds
2
4
  # to forget_me! Also clear remember token to ensure the user won't be
3
5
  # remembered again. Notice that we forget the user unless the record is not persisted.
@@ -1,10 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # After each sign in, if resource responds to failed_attempts, sets it to 0
2
4
  # This is only triggered when the user is explicitly set (with set_user)
3
5
  Warden::Manager.after_set_user except: :fetch do |record, warden, options|
4
- if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
5
- unless record.failed_attempts.to_i.zero?
6
- record.failed_attempts = 0
7
- record.save(validate: false)
8
- end
6
+ if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
7
+ record.reset_failed_attempts!
9
8
  end
10
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Hooks
3
5
  # A small warden proxy so we can remember, forget and
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Warden::Manager.after_set_user except: :fetch do |record, warden, options|
2
4
  scope = options[:scope]
3
5
  if record.respond_to?(:remember_me) && options[:store] != false &&
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Each time a record is set we check whether its session has already timed out
2
4
  # or not, based on last request time. If so, the record is logged out and
3
5
  # redirected to the sign in page. Also, each time the request comes and the
@@ -19,8 +21,8 @@ Warden::Manager.after_set_user do |record, warden, options|
19
21
 
20
22
  proxy = Devise::Hooks::Proxy.new(warden)
21
23
 
22
- if record.timedout?(last_request_at) &&
23
- !env['devise.skip_timeout'] &&
24
+ if !env['devise.skip_timeout'] &&
25
+ record.timedout?(last_request_at) &&
24
26
  !proxy.remember_me_is_active?(record)
25
27
  Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
26
28
  throw :warden, scope: scope, message: :timeout
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # After each sign in, update sign in time, sign in count and sign in IP.
2
4
  # This is only triggered when the user is explicitly set (with set_user)
3
5
  # and on authentication. Retrieving the user from session (:fetch) does
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Mailers
3
5
  module Helpers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  # Responsible for handling devise mappings and routes configuration. Each
3
5
  # resource configured by devise_for in routes is actually creating a mapping
@@ -44,7 +46,7 @@ module Devise
44
46
  raise "Could not find a valid mapping for #{obj.inspect}"
45
47
  end
46
48
 
47
- def self.find_by_path!(path, path_type=:fullpath)
49
+ def self.find_by_path!(path, path_type = :fullpath)
48
50
  Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
49
51
  raise "Could not find a valid mapping for path #{path.inspect}"
50
52
  end
@@ -1,6 +1,8 @@
1
- require 'active_model/version'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'devise/hooks/activatable'
3
4
  require 'devise/hooks/csrf_cleaner'
5
+ require 'devise/rails/deprecated_constant_accessor'
4
6
 
5
7
  module Devise
6
8
  module Models
@@ -8,7 +10,7 @@ module Devise
8
10
  #
9
11
  # == Options
10
12
  #
11
- # Authenticatable adds the following options to devise_for:
13
+ # Authenticatable adds the following options to +devise+:
12
14
  #
13
15
  # * +authentication_keys+: parameters used for authentication. By default [:email].
14
16
  #
@@ -54,11 +56,14 @@ module Devise
54
56
  module Authenticatable
55
57
  extend ActiveSupport::Concern
56
58
 
57
- 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,
58
60
  :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
59
61
  :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
60
62
  :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
61
63
 
64
+ include Devise::DeprecatedConstantAccessor
65
+ deprecate_constant "BLACKLIST_FOR_SERIALIZATION", "Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION"
66
+
62
67
  included do
63
68
  class_attribute :devise_modules, instance_writer: false
64
69
  self.devise_modules ||= []
@@ -102,13 +107,13 @@ module Devise
102
107
  # and passing a new list of attributes you want to exempt. All attributes
103
108
  # given to :except will simply add names to exempt to Devise internal list.
104
109
  def serializable_hash(options = nil)
105
- options ||= {}
106
- options[:except] = Array(options[:except])
110
+ options = options.try(:dup) || {}
111
+ options[:except] = Array(options[:except]).dup
107
112
 
108
113
  if options[:force_except]
109
114
  options[:except].concat Array(options[:force_except])
110
115
  else
111
- options[:except].concat BLACKLIST_FOR_SERIALIZATION
116
+ options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
112
117
  end
113
118
 
114
119
  super(options)
@@ -132,16 +137,18 @@ module Devise
132
137
  # This is an internal method called every time Devise needs
133
138
  # to send a notification/mail. This can be overridden if you
134
139
  # need to customize the e-mail delivery logic. For instance,
135
- # if you are using a queue to deliver e-mails (delayed job,
136
- # 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
137
142
  # just after the transaction was committed. To achieve this,
138
143
  # you can override send_devise_notification to store the
139
- # 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` :
140
147
  #
141
148
  # class User
142
149
  # devise :database_authenticatable, :confirmable
143
150
  #
144
- # after_commit :send_pending_notifications
151
+ # after_commit :send_pending_devise_notifications
145
152
  #
146
153
  # protected
147
154
  #
@@ -149,39 +156,45 @@ module Devise
149
156
  # # If the record is new or changed then delay the
150
157
  # # delivery until the after_commit callback otherwise
151
158
  # # send now because after_commit will not be called.
152
- # if new_record? || changed?
153
- # 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]
154
162
  # else
155
- # message = devise_mailer.send(notification, self, *args)
156
- # Remove once we move to Rails 4.2+ only.
157
- # if message.respond_to?(:deliver_now)
158
- # message.deliver_now
159
- # else
160
- # message.deliver
161
- # end
163
+ # render_and_send_devise_message(notification, *args)
162
164
  # end
163
165
  # end
164
166
  #
165
- # def send_pending_notifications
166
- # pending_notifications.each do |notification, args|
167
- # message = devise_mailer.send(notification, self, *args)
168
- # Remove once we move to Rails 4.2+ only.
169
- # if message.respond_to?(:deliver_now)
170
- # message.deliver_now
171
- # else
172
- # message.deliver
173
- # 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)
174
172
  # end
175
173
  #
176
174
  # # Empty the pending notifications array because the
177
175
  # # after_commit hook can be called multiple times which
178
176
  # # could cause multiple emails to be sent.
179
- # pending_notifications.clear
177
+ # pending_devise_notifications.clear
180
178
  # end
181
179
  #
182
- # def pending_notifications
183
- # @pending_notifications ||= []
180
+ # def pending_devise_notifications
181
+ # @pending_devise_notifications ||= []
184
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
196
+ # end
197
+ #
185
198
  # end
186
199
  #
187
200
  def send_devise_notification(notification, *args)
@@ -256,46 +269,38 @@ module Devise
256
269
  # end
257
270
  #
258
271
  # Finally, notice that Devise also queries for users in other scenarios
259
- # besides authentication, for example when retrieving an user to send
272
+ # besides authentication, for example when retrieving a user to send
260
273
  # an e-mail for password reset. In such cases, find_for_authentication
261
274
  # is not called.
262
275
  def find_for_authentication(tainted_conditions)
263
276
  find_first_by_auth_conditions(tainted_conditions)
264
277
  end
265
278
 
266
- def find_first_by_auth_conditions(tainted_conditions, opts={})
279
+ def find_first_by_auth_conditions(tainted_conditions, opts = {})
267
280
  to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
268
281
  end
269
282
 
270
283
  # Find or initialize a record setting an error if it can't be found.
271
- 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:
272
285
  find_or_initialize_with_errors([attribute], { attribute => value }, error)
273
286
  end
274
287
 
275
288
  # Find or initialize a record with group of attributes based on a list of required attributes.
276
- def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
277
- attributes = if attributes.respond_to? :permit!
278
- attributes.slice(*required_attributes).permit!.to_h.with_indifferent_access
279
- else
280
- attributes.with_indifferent_access.slice(*required_attributes)
281
- end
282
- 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? }
283
294
 
284
295
  if attributes.size == required_attributes.size
285
- record = find_first_by_auth_conditions(attributes)
296
+ record = find_first_by_auth_conditions(attributes) and return record
286
297
  end
287
298
 
288
- unless record
289
- record = new
290
-
299
+ new(devise_parameter_filter.filter(attributes)).tap do |record|
291
300
  required_attributes.each do |key|
292
- value = attributes[key]
293
- record.send("#{key}=", value)
294
- record.errors.add(key, value.present? ? error : :blank)
301
+ record.errors.add(key, attributes[key].blank? ? :blank : error)
295
302
  end
296
303
  end
297
-
298
- record
299
304
  end
300
305
 
301
306
  protected
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Models
3
5
  # Confirmable is responsible to verify if an account is already confirmed to
@@ -46,7 +48,7 @@ module Devise
46
48
  included do
47
49
  before_create :generate_confirmation_token, if: :confirmation_required?
48
50
  after_create :skip_reconfirmation_in_callback!, if: :send_confirmation_notification?
49
- if respond_to?(:after_commit) # ActiveRecord
51
+ if Devise::Orm.active_record?(self) # ActiveRecord
50
52
  after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
51
53
  after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
52
54
  else # Mongoid
@@ -74,7 +76,7 @@ module Devise
74
76
  # Confirm a user by setting it's confirmed_at to actual time. If the user
75
77
  # is already confirmed, add an error to email field. If the user is invalid
76
78
  # add errors
77
- def confirm(args={})
79
+ def confirm(args = {})
78
80
  pending_any_confirmation do
79
81
  if confirmation_period_expired?
80
82
  self.errors.add(:email, :confirmation_period_expired,
@@ -209,7 +211,10 @@ module Devise
209
211
  # confirmation_period_valid? # will always return true
210
212
  #
211
213
  def confirmation_period_valid?
212
- 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
213
218
  end
214
219
 
215
220
  # Checks if the user confirmation happens before the token becomes invalid
@@ -253,44 +258,23 @@ module Devise
253
258
  generate_confirmation_token && save(validate: false)
254
259
  end
255
260
 
256
- if Devise.activerecord51?
257
- def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
258
- @reconfirmation_required = true
259
- self.unconfirmed_email = self.email
260
- self.email = self.email_in_database
261
- self.confirmation_token = nil
262
- generate_confirmation_token
263
- end
264
- else
265
- def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
266
- @reconfirmation_required = true
267
- self.unconfirmed_email = self.email
268
- self.email = self.email_was
269
- self.confirmation_token = nil
270
- generate_confirmation_token
271
- 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
272
268
  end
273
269
 
274
- if Devise.activerecord51?
275
- def postpone_email_change?
276
- postpone = self.class.reconfirmable &&
277
- will_save_change_to_email? &&
278
- !@bypass_confirmation_postpone &&
279
- self.email.present? &&
280
- (!@skip_reconfirmation_in_callback || !self.email_in_database.nil?)
281
- @bypass_confirmation_postpone = false
282
- postpone
283
- end
284
- else
285
- def postpone_email_change?
286
- postpone = self.class.reconfirmable &&
287
- email_changed? &&
288
- !@bypass_confirmation_postpone &&
289
- self.email.present? &&
290
- (!@skip_reconfirmation_in_callback || !self.email_was.nil?)
291
- @bypass_confirmation_postpone = false
292
- postpone
293
- 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
294
278
  end
295
279
 
296
280
  def reconfirmation_required?
@@ -329,7 +313,7 @@ module Devise
329
313
  # confirmation instructions to it. If not, try searching for a user by unconfirmed_email
330
314
  # field. If no user is found, returns a new user with an email not found error.
331
315
  # Options must contain the user email
332
- def send_confirmation_instructions(attributes={})
316
+ def send_confirmation_instructions(attributes = {})
333
317
  confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
334
318
  unless confirmable.try(:persisted?)
335
319
  confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
@@ -343,7 +327,19 @@ module Devise
343
327
  # If the user is already confirmed, create an error for the user
344
328
  # Options must have the confirmation_token
345
329
  def confirm_by_token(confirmation_token)
330
+ # When the `confirmation_token` parameter is blank, if there are any users with a blank
331
+ # `confirmation_token` in the database, the first one would be confirmed here.
332
+ # The error is being manually added here to ensure no users are confirmed by mistake.
333
+ # This was done in the model for convenience, since validation errors are automatically
334
+ # displayed in the view.
335
+ if confirmation_token.blank?
336
+ confirmable = new
337
+ confirmable.errors.add(:confirmation_token, :blank)
338
+ return confirmable
339
+ end
340
+
346
341
  confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
342
+
347
343
  unless confirmable
348
344
  confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
349
345
  confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)