devise 4.1.1 → 5.0.4

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 (255) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +68 -111
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +315 -98
  5. data/app/controllers/devise/confirmations_controller.rb +3 -0
  6. data/app/controllers/devise/omniauth_callbacks_controller.rb +7 -5
  7. data/app/controllers/devise/passwords_controller.rb +10 -2
  8. data/app/controllers/devise/registrations_controller.rb +42 -20
  9. data/app/controllers/devise/sessions_controller.rb +9 -7
  10. data/app/controllers/devise/unlocks_controller.rb +3 -0
  11. data/app/controllers/devise_controller.rb +19 -3
  12. data/app/helpers/devise_helper.rb +3 -23
  13. data/app/mailers/devise/mailer.rb +10 -4
  14. data/app/views/devise/confirmations/new.html.erb +3 -3
  15. data/app/views/devise/mailer/email_changed.html.erb +7 -0
  16. data/app/views/devise/passwords/edit.html.erb +6 -6
  17. data/app/views/devise/passwords/new.html.erb +4 -4
  18. data/app/views/devise/registrations/edit.html.erb +13 -10
  19. data/app/views/devise/registrations/new.html.erb +9 -9
  20. data/app/views/devise/sessions/new.html.erb +8 -8
  21. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  22. data/app/views/devise/shared/_links.html.erb +13 -13
  23. data/app/views/devise/unlocks/new.html.erb +3 -3
  24. data/config/locales/en.yml +5 -2
  25. data/lib/devise/controllers/helpers.rb +24 -9
  26. data/lib/devise/controllers/rememberable.rb +3 -1
  27. data/lib/devise/controllers/responder.rb +35 -0
  28. data/lib/devise/controllers/scoped_views.rb +2 -0
  29. data/lib/devise/controllers/sign_in_out.rb +31 -21
  30. data/lib/devise/controllers/store_location.rb +25 -7
  31. data/lib/devise/controllers/url_helpers.rb +3 -1
  32. data/lib/devise/delegator.rb +2 -0
  33. data/lib/devise/encryptor.rb +2 -0
  34. data/lib/devise/failure_app.rb +71 -38
  35. data/lib/devise/hooks/activatable.rb +3 -1
  36. data/lib/devise/hooks/csrf_cleaner.rb +8 -1
  37. data/lib/devise/hooks/forgetable.rb +2 -0
  38. data/lib/devise/hooks/lockable.rb +4 -2
  39. data/lib/devise/hooks/proxy.rb +3 -1
  40. data/lib/devise/hooks/rememberable.rb +2 -0
  41. data/lib/devise/hooks/timeoutable.rb +5 -3
  42. data/lib/devise/hooks/trackable.rb +2 -0
  43. data/lib/devise/mailers/helpers.rb +15 -18
  44. data/lib/devise/mapping.rb +4 -2
  45. data/lib/devise/models/authenticatable.rb +58 -44
  46. data/lib/devise/models/confirmable.rb +52 -14
  47. data/lib/devise/models/database_authenticatable.rb +52 -20
  48. data/lib/devise/models/lockable.rb +19 -5
  49. data/lib/devise/models/omniauthable.rb +4 -2
  50. data/lib/devise/models/recoverable.rb +22 -21
  51. data/lib/devise/models/registerable.rb +4 -0
  52. data/lib/devise/models/rememberable.rb +6 -4
  53. data/lib/devise/models/timeoutable.rb +3 -1
  54. data/lib/devise/models/trackable.rb +15 -1
  55. data/lib/devise/models/validatable.rb +10 -6
  56. data/lib/devise/models.rb +4 -1
  57. data/lib/devise/modules.rb +2 -0
  58. data/lib/devise/omniauth/config.rb +2 -0
  59. data/lib/devise/omniauth/url_helpers.rb +2 -51
  60. data/lib/devise/omniauth.rb +4 -5
  61. data/lib/devise/orm/active_record.rb +5 -1
  62. data/lib/devise/orm/mongoid.rb +6 -2
  63. data/lib/devise/orm.rb +80 -0
  64. data/lib/devise/parameter_filter.rb +4 -0
  65. data/lib/devise/parameter_sanitizer.rb +16 -58
  66. data/lib/devise/rails/routes.rb +12 -11
  67. data/lib/devise/rails/warden_compat.rb +2 -0
  68. data/lib/devise/rails.rb +16 -6
  69. data/lib/devise/strategies/authenticatable.rb +3 -1
  70. data/lib/devise/strategies/base.rb +2 -0
  71. data/lib/devise/strategies/database_authenticatable.rb +8 -1
  72. data/lib/devise/strategies/rememberable.rb +2 -0
  73. data/lib/devise/test/controller_helpers.rb +156 -0
  74. data/lib/devise/test/integration_helpers.rb +63 -0
  75. data/lib/devise/time_inflector.rb +2 -0
  76. data/lib/devise/token_generator.rb +2 -0
  77. data/lib/devise/version.rb +3 -1
  78. data/lib/devise.rb +69 -28
  79. data/lib/generators/active_record/devise_generator.rb +38 -16
  80. data/lib/generators/active_record/templates/migration.rb +3 -1
  81. data/lib/generators/active_record/templates/migration_existing.rb +2 -0
  82. data/lib/generators/devise/controllers_generator.rb +4 -2
  83. data/lib/generators/devise/devise_generator.rb +5 -3
  84. data/lib/generators/devise/install_generator.rb +3 -5
  85. data/lib/generators/devise/orm_helpers.rb +5 -3
  86. data/lib/generators/devise/views_generator.rb +8 -9
  87. data/lib/generators/mongoid/devise_generator.rb +7 -5
  88. data/lib/generators/templates/README +9 -8
  89. data/lib/generators/templates/controllers/confirmations_controller.rb +2 -0
  90. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +3 -1
  91. data/lib/generators/templates/controllers/passwords_controller.rb +2 -0
  92. data/lib/generators/templates/controllers/registrations_controller.rb +4 -2
  93. data/lib/generators/templates/controllers/sessions_controller.rb +3 -1
  94. data/lib/generators/templates/controllers/unlocks_controller.rb +2 -0
  95. data/lib/generators/templates/devise.rb +59 -11
  96. data/lib/generators/templates/markerb/email_changed.markerb +7 -0
  97. data/lib/generators/templates/markerb/password_change.markerb +2 -2
  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 +5 -2
  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 +23 -302
  106. data/.gitignore +0 -10
  107. data/.travis.yml +0 -44
  108. data/.yardopts +0 -9
  109. data/CODE_OF_CONDUCT.md +0 -22
  110. data/CONTRIBUTING.md +0 -16
  111. data/Gemfile +0 -30
  112. data/Gemfile.lock +0 -182
  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 -170
  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-beta +0 -37
  122. data/gemfiles/Gemfile.rails-5.0-beta.lock +0 -199
  123. data/lib/devise/test_helpers.rb +0 -137
  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 -320
  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/omniauthable_test.rb +0 -135
  150. data/test/integration/recoverable_test.rb +0 -347
  151. data/test/integration/registerable_test.rb +0 -357
  152. data/test/integration/rememberable_test.rb +0 -211
  153. data/test/integration/timeoutable_test.rb +0 -184
  154. data/test/integration/trackable_test.rb +0 -92
  155. data/test/mailers/confirmation_instructions_test.rb +0 -115
  156. data/test/mailers/reset_password_instructions_test.rb +0 -96
  157. data/test/mailers/unlock_instructions_test.rb +0 -91
  158. data/test/mapping_test.rb +0 -134
  159. data/test/models/authenticatable_test.rb +0 -23
  160. data/test/models/confirmable_test.rb +0 -511
  161. data/test/models/database_authenticatable_test.rb +0 -269
  162. data/test/models/lockable_test.rb +0 -350
  163. data/test/models/omniauthable_test.rb +0 -7
  164. data/test/models/recoverable_test.rb +0 -251
  165. data/test/models/registerable_test.rb +0 -7
  166. data/test/models/rememberable_test.rb +0 -169
  167. data/test/models/serializable_test.rb +0 -49
  168. data/test/models/timeoutable_test.rb +0 -51
  169. data/test/models/trackable_test.rb +0 -41
  170. data/test/models/validatable_test.rb +0 -119
  171. data/test/models_test.rb +0 -153
  172. data/test/omniauth/config_test.rb +0 -57
  173. data/test/omniauth/url_helpers_test.rb +0 -51
  174. data/test/orm/active_record.rb +0 -17
  175. data/test/orm/mongoid.rb +0 -13
  176. data/test/parameter_sanitizer_test.rb +0 -131
  177. data/test/rails_app/Rakefile +0 -6
  178. data/test/rails_app/app/active_record/admin.rb +0 -6
  179. data/test/rails_app/app/active_record/shim.rb +0 -2
  180. data/test/rails_app/app/active_record/user.rb +0 -7
  181. data/test/rails_app/app/active_record/user_on_engine.rb +0 -7
  182. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -7
  183. data/test/rails_app/app/active_record/user_without_email.rb +0 -8
  184. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
  185. data/test/rails_app/app/controllers/admins_controller.rb +0 -6
  186. data/test/rails_app/app/controllers/application_controller.rb +0 -11
  187. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -30
  188. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -31
  189. data/test/rails_app/app/controllers/home_controller.rb +0 -29
  190. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
  191. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
  192. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
  193. data/test/rails_app/app/controllers/users_controller.rb +0 -31
  194. data/test/rails_app/app/helpers/application_helper.rb +0 -3
  195. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -3
  196. data/test/rails_app/app/mailers/users/mailer.rb +0 -3
  197. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -4
  198. data/test/rails_app/app/mongoid/admin.rb +0 -29
  199. data/test/rails_app/app/mongoid/shim.rb +0 -23
  200. data/test/rails_app/app/mongoid/user.rb +0 -39
  201. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -39
  202. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -39
  203. data/test/rails_app/app/mongoid/user_without_email.rb +0 -33
  204. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  205. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  206. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  207. data/test/rails_app/app/views/home/index.html.erb +0 -1
  208. data/test/rails_app/app/views/home/join.html.erb +0 -1
  209. data/test/rails_app/app/views/home/private.html.erb +0 -1
  210. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  211. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  212. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  213. data/test/rails_app/app/views/users/index.html.erb +0 -1
  214. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  215. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  216. data/test/rails_app/bin/bundle +0 -3
  217. data/test/rails_app/bin/rails +0 -4
  218. data/test/rails_app/bin/rake +0 -4
  219. data/test/rails_app/config/application.rb +0 -44
  220. data/test/rails_app/config/boot.rb +0 -14
  221. data/test/rails_app/config/database.yml +0 -18
  222. data/test/rails_app/config/environment.rb +0 -5
  223. data/test/rails_app/config/environments/development.rb +0 -30
  224. data/test/rails_app/config/environments/production.rb +0 -84
  225. data/test/rails_app/config/environments/test.rb +0 -46
  226. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  227. data/test/rails_app/config/initializers/devise.rb +0 -180
  228. data/test/rails_app/config/initializers/inflections.rb +0 -2
  229. data/test/rails_app/config/initializers/secret_token.rb +0 -3
  230. data/test/rails_app/config/initializers/session_store.rb +0 -1
  231. data/test/rails_app/config/routes.rb +0 -126
  232. data/test/rails_app/config.ru +0 -4
  233. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -71
  234. data/test/rails_app/db/schema.rb +0 -55
  235. data/test/rails_app/lib/shared_admin.rb +0 -17
  236. data/test/rails_app/lib/shared_user.rb +0 -30
  237. data/test/rails_app/lib/shared_user_without_email.rb +0 -26
  238. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -13
  239. data/test/rails_app/public/404.html +0 -26
  240. data/test/rails_app/public/422.html +0 -26
  241. data/test/rails_app/public/500.html +0 -26
  242. data/test/rails_app/public/favicon.ico +0 -0
  243. data/test/rails_test.rb +0 -9
  244. data/test/routes_test.rb +0 -279
  245. data/test/support/action_controller/record_identifier.rb +0 -10
  246. data/test/support/assertions.rb +0 -39
  247. data/test/support/helpers.rb +0 -77
  248. data/test/support/http_method_compatibility.rb +0 -51
  249. data/test/support/integration.rb +0 -92
  250. data/test/support/locale/en.yml +0 -8
  251. data/test/support/mongoid.yml +0 -6
  252. data/test/support/webrat/integrations/rails.rb +0 -33
  253. data/test/test_helper.rb +0 -34
  254. data/test/test_helpers_test.rb +0 -178
  255. data/test/test_models.rb +0 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/object/try"
2
4
  require "active_support/core_ext/hash/slice"
3
5
 
@@ -133,10 +135,10 @@ module ActionDispatch::Routing
133
135
  # * failure_app: a rack app which is invoked whenever there is a failure. Strings representing a given
134
136
  # are also allowed as parameter.
135
137
  #
136
- # * 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),
137
139
  # if you wish to restrict this to accept only :post or :delete requests you should do:
138
140
  #
139
- # devise_for :users, sign_out_via: [:post, :delete]
141
+ # devise_for :users, sign_out_via: [:get, :post]
140
142
  #
141
143
  # You need to make sure that your sign_out controls trigger a request with a matching HTTP method.
142
144
  #
@@ -233,7 +235,6 @@ module ActionDispatch::Routing
233
235
  options[:constraints] = (@scope[:constraints] || {}).merge(options[:constraints] || {})
234
236
  options[:defaults] = (@scope[:defaults] || {}).merge(options[:defaults] || {})
235
237
  options[:options] = @scope[:options] || {}
236
- options[:options][:format] = false if options[:format] == false
237
238
 
238
239
  resources.map!(&:to_sym)
239
240
 
@@ -285,7 +286,7 @@ module ActionDispatch::Routing
285
286
  # root to: "admin/dashboard#show", as: :user_root
286
287
  # end
287
288
  #
288
- def authenticate(scope=nil, block=nil)
289
+ def authenticate(scope = nil, block = nil)
289
290
  constraints_for(:authenticate!, scope, block) do
290
291
  yield
291
292
  end
@@ -309,7 +310,7 @@ module ActionDispatch::Routing
309
310
  #
310
311
  # root to: 'landing#show'
311
312
  #
312
- def authenticated(scope=nil, block=nil)
313
+ def authenticated(scope = nil, block = nil)
313
314
  constraints_for(:authenticate?, scope, block) do
314
315
  yield
315
316
  end
@@ -326,7 +327,7 @@ module ActionDispatch::Routing
326
327
  #
327
328
  # root to: 'dashboard#show'
328
329
  #
329
- def unauthenticated(scope=nil)
330
+ def unauthenticated(scope = nil)
330
331
  constraint = lambda do |request|
331
332
  not request.env["warden"].authenticate? scope: scope
332
333
  end
@@ -338,7 +339,7 @@ module ActionDispatch::Routing
338
339
 
339
340
  # Sets the devise scope to be used in the controller. If you have custom routes,
340
341
  # you are required to call this method (also aliased as :as) in order to specify
341
- # to which controller it is targetted.
342
+ # to which controller it is targeted.
342
343
  #
343
344
  # as :user do
344
345
  # get "sign_in", to: "devise/sessions#new"
@@ -411,7 +412,7 @@ module ActionDispatch::Routing
411
412
  controller: controllers[:registrations]
412
413
  }
413
414
 
414
- resource :registration, options do
415
+ resource :registration, **options do
415
416
  get :cancel
416
417
  end
417
418
  end
@@ -445,7 +446,7 @@ ERROR
445
446
  match "#{path_prefix}/#{provider}",
446
447
  to: "#{controllers[:omniauth_callbacks]}#passthru",
447
448
  as: "#{provider}_omniauth_authorize",
448
- via: [:get, :post]
449
+ via: OmniAuth.config.allowed_request_methods
449
450
 
450
451
  match "#{path_prefix}/#{provider}/callback",
451
452
  to: "#{controllers[:omniauth_callbacks]}##{provider}",
@@ -460,7 +461,7 @@ ERROR
460
461
  current_scope = @scope.dup
461
462
 
462
463
  exclusive = { as: new_as, path: new_path, module: nil }
463
- exclusive.merge!(options.slice(:constraints, :defaults, :options))
464
+ exclusive.merge!(options.slice(:constraints, :format, :defaults, :options))
464
465
 
465
466
  if @scope.respond_to? :new
466
467
  @scope = @scope.new exclusive
@@ -472,7 +473,7 @@ ERROR
472
473
  @scope = current_scope
473
474
  end
474
475
 
475
- def constraints_for(method_to_apply, scope=nil, block=nil)
476
+ def constraints_for(method_to_apply, scope = nil, block = nil)
476
477
  constraint = lambda do |request|
477
478
  request.env['warden'].send(method_to_apply, scope: scope) &&
478
479
  (block.nil? || block.call(request.env["warden"].user(scope)))
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Warden::Mixins::Common
2
4
  def request
3
5
  @request ||= ActionDispatch::Request.new(env)
data/lib/devise/rails.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/rails/routes'
2
4
  require 'devise/rails/warden_compat'
3
5
 
@@ -11,7 +13,13 @@ module Devise
11
13
  end
12
14
 
13
15
  # Force routes to be loaded if we are doing any eager load.
14
- config.before_eager_load { |app| app.reload_routes! }
16
+ config.before_eager_load do |app|
17
+ app.reload_routes! if Devise.reload_routes
18
+ end
19
+
20
+ initializer "devise.deprecator" do |app|
21
+ app.deprecators[:devise] = Devise.deprecator if app.respond_to?(:deprecators)
22
+ end
15
23
 
16
24
  initializer "devise.url_helpers" do
17
25
  Devise.include_helpers(Devise::Controllers)
@@ -30,11 +38,7 @@ module Devise
30
38
  end
31
39
 
32
40
  initializer "devise.secret_key" do |app|
33
- if app.respond_to?(:secrets)
34
- Devise.secret_key ||= app.secrets.secret_key_base
35
- elsif app.config.respond_to?(:secret_key_base)
36
- Devise.secret_key ||= app.config.secret_key_base
37
- end
41
+ Devise.secret_key ||= app.secret_key_base
38
42
 
39
43
  Devise.token_generator ||=
40
44
  if secret_key = Devise.secret_key
@@ -43,5 +47,11 @@ module Devise
43
47
  )
44
48
  end
45
49
  end
50
+
51
+ initializer "devise.configure_zeitwerk" do
52
+ if Rails.autoloaders.zeitwerk_enabled? && !defined?(ActionMailer)
53
+ Rails.autoloaders.main.ignore("#{root}/app/mailers/devise/mailer.rb")
54
+ end
55
+ end
46
56
  end
47
57
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/strategies/base'
2
4
 
3
5
  module Devise
@@ -26,7 +28,7 @@ module Devise
26
28
  private
27
29
 
28
30
  # Receives a resource and check if it is valid by calling valid_for_authentication?
29
- # An optional block that will be triggered while validating can be optionally
31
+ # A block that will be triggered while validating can be optionally
30
32
  # given as parameter. Check Devise::Models::Authenticatable.valid_for_authentication?
31
33
  # for more information.
32
34
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Strategies
3
5
  # Base strategy for Devise. Responsible for verifying correct scope and mapping.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/strategies/authenticatable'
2
4
 
3
5
  module Devise
@@ -14,8 +16,13 @@ module Devise
14
16
  success!(resource)
15
17
  end
16
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.
17
22
  mapping.to.new.password = password if !hashed && Devise.paranoid
18
- fail(:not_found_in_database) unless resource
23
+ unless resource
24
+ Devise.paranoid ? fail(:invalid) : fail(:not_found_in_database)
25
+ end
19
26
  end
20
27
  end
21
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/strategies/authenticatable'
2
4
 
3
5
  module Devise
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module Test
5
+ # `Devise::Test::ControllerHelpers` provides a facility to test controllers
6
+ # in isolation when using `ActionController::TestCase` allowing you to
7
+ # quickly sign_in or sign_out a user. Do not use
8
+ # `Devise::Test::ControllerHelpers` in integration tests.
9
+ #
10
+ # Examples
11
+ #
12
+ # class PostsTest < ActionController::TestCase
13
+ # include Devise::Test::ControllerHelpers
14
+ #
15
+ # test 'authenticated users can GET index' do
16
+ # sign_in users(:bob)
17
+ #
18
+ # get :index
19
+ # assert_response :success
20
+ # end
21
+ # end
22
+ #
23
+ # Important: you should not test Warden specific behavior (like callbacks)
24
+ # using `Devise::Test::ControllerHelpers` since it is a stub of the actual
25
+ # behavior. Such callbacks should be tested in your integration suite instead.
26
+ module ControllerHelpers
27
+ extend ActiveSupport::Concern
28
+
29
+ included do
30
+ setup :setup_controller_for_warden, :warden
31
+ end
32
+
33
+ # Override process to consider warden.
34
+ def process(*)
35
+ _catch_warden { super }
36
+
37
+ @response
38
+ end
39
+
40
+ ruby2_keywords(:process) if respond_to?(:ruby2_keywords, true)
41
+
42
+ # We need to set up the environment variables and the response in the controller.
43
+ def setup_controller_for_warden #:nodoc:
44
+ @request.env['action_controller.instance'] = @controller
45
+ end
46
+
47
+ # Quick access to Warden::Proxy.
48
+ def warden #:nodoc:
49
+ @request.env['warden'] ||= begin
50
+ manager = Warden::Manager.new(nil) do |config|
51
+ config.merge! Devise.warden_config
52
+ end
53
+ Warden::Proxy.new(@request.env, manager)
54
+ end
55
+ end
56
+
57
+ # sign_in a given resource by storing its keys in the session.
58
+ # This method bypass any warden authentication callback.
59
+ #
60
+ # * +resource+ - The resource that should be authenticated
61
+ # * +scope+ - An optional +Symbol+ with the scope where the resource
62
+ # should be signed in with.
63
+ # Examples:
64
+ #
65
+ # sign_in users(:alice)
66
+ # sign_in users(:alice), scope: :admin
67
+ def sign_in(resource, scope: nil)
68
+ scope ||= Devise::Mapping.find_scope!(resource)
69
+
70
+ warden.instance_variable_get(:@users).delete(scope)
71
+ warden.session_serializer.store(resource, scope)
72
+ end
73
+
74
+ # Sign out a given resource or scope by calling logout on Warden.
75
+ # This method bypass any warden logout callback.
76
+ #
77
+ # Examples:
78
+ #
79
+ # sign_out :user # sign_out(scope)
80
+ # sign_out @user # sign_out(resource)
81
+ #
82
+ def sign_out(resource_or_scope)
83
+ scope = Devise::Mapping.find_scope!(resource_or_scope)
84
+ @controller.instance_variable_set(:"@current_#{scope}", nil)
85
+ user = warden.instance_variable_get(:@users).delete(scope)
86
+ warden.session_serializer.delete(scope, user)
87
+ end
88
+
89
+ protected
90
+
91
+ # Catch warden continuations and handle like the middleware would.
92
+ # Returns nil when interrupted, otherwise the normal result of the block.
93
+ def _catch_warden(&block)
94
+ result = catch(:warden, &block)
95
+
96
+ env = @controller.request.env
97
+
98
+ result ||= {}
99
+
100
+ # Set the response. In production, the rack result is returned
101
+ # from Warden::Manager#call, which the following is modelled on.
102
+ case result
103
+ when Array
104
+ if result.first == 401 && intercept_401?(env) # does this happen during testing?
105
+ _process_unauthenticated(env)
106
+ else
107
+ result
108
+ end
109
+ when Hash
110
+ _process_unauthenticated(env, result)
111
+ else
112
+ result
113
+ end
114
+ end
115
+
116
+ def _process_unauthenticated(env, options = {})
117
+ options[:action] ||= :unauthenticated
118
+ proxy = request.env['warden']
119
+ result = options[:result] || proxy.result
120
+
121
+ ret = case result
122
+ when :redirect
123
+ body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
124
+ [proxy.status, proxy.headers, [body]]
125
+ when :custom
126
+ proxy.custom_response
127
+ else
128
+ request.env["PATH_INFO"] = "/#{options[:action]}"
129
+ request.env["warden.options"] = options
130
+ Warden::Manager._run_callbacks(:before_failure, env, options)
131
+
132
+ status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
133
+ @controller.response.headers.merge!(headers)
134
+ @controller.status = status
135
+ @controller.response_body = response.body
136
+ nil # causes process return @response
137
+ end
138
+
139
+ # ensure that the controller response is set up. In production, this is
140
+ # not necessary since warden returns the results to rack. However, at
141
+ # testing time, we want the response to be available to the testing
142
+ # framework to verify what would be returned to rack.
143
+ if ret.is_a?(Array)
144
+ status, headers, body = *ret
145
+ # ensure the controller response is set to our response.
146
+ @controller.response ||= @response
147
+ @response.status = status
148
+ @response.headers.merge!(headers)
149
+ @response.body = body
150
+ end
151
+
152
+ ret
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ # Devise::Test::IntegrationHelpers is a helper module for facilitating
5
+ # authentication on Rails integration tests to bypass the required steps for
6
+ # signin in or signin out a record.
7
+ #
8
+ # Examples
9
+ #
10
+ # class PostsTest < ActionDispatch::IntegrationTest
11
+ # include Devise::Test::IntegrationHelpers
12
+ #
13
+ # test 'authenticated users can see posts' do
14
+ # sign_in users(:bob)
15
+ #
16
+ # get '/posts'
17
+ # assert_response :success
18
+ # end
19
+ # end
20
+ module Test
21
+ module IntegrationHelpers
22
+ def self.included(base)
23
+ base.class_eval do
24
+ include Warden::Test::Helpers
25
+
26
+ setup :setup_integration_for_devise
27
+ teardown :teardown_integration_for_devise
28
+ end
29
+ end
30
+
31
+ # Signs in a specific resource, mimicking a successful sign in
32
+ # operation through +Devise::SessionsController#create+.
33
+ #
34
+ # * +resource+ - The resource that should be authenticated
35
+ # * +scope+ - An optional +Symbol+ with the scope where the resource
36
+ # should be signed in with.
37
+ def sign_in(resource, scope: nil)
38
+ scope ||= Devise::Mapping.find_scope!(resource)
39
+
40
+ login_as(resource, scope: scope)
41
+ end
42
+
43
+ # Signs out a specific scope from the session.
44
+ #
45
+ # * +resource_or_scope+ - The resource or scope that should be signed out.
46
+ def sign_out(resource_or_scope)
47
+ scope = Devise::Mapping.find_scope!(resource_or_scope)
48
+
49
+ logout scope
50
+ end
51
+
52
+ protected
53
+
54
+ def setup_integration_for_devise
55
+ Warden.test_mode!
56
+ end
57
+
58
+ def teardown_integration_for_devise
59
+ Warden.test_reset!
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/module/delegation"
2
4
 
3
5
  module Devise
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'openssl'
2
4
 
3
5
  module Devise
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
- VERSION = "4.1.1".freeze
4
+ VERSION = "5.0.4".freeze
3
5
  end
data/lib/devise.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails'
2
4
  require 'active_support/core_ext/numeric/time'
3
5
  require 'active_support/dependencies'
@@ -11,15 +13,16 @@ module Devise
11
13
  autoload :Encryptor, 'devise/encryptor'
12
14
  autoload :FailureApp, 'devise/failure_app'
13
15
  autoload :OmniAuth, 'devise/omniauth'
16
+ autoload :Orm, 'devise/orm'
14
17
  autoload :ParameterFilter, 'devise/parameter_filter'
15
18
  autoload :ParameterSanitizer, 'devise/parameter_sanitizer'
16
- autoload :TestHelpers, 'devise/test_helpers'
17
19
  autoload :TimeInflector, 'devise/time_inflector'
18
20
  autoload :TokenGenerator, 'devise/token_generator'
19
21
 
20
22
  module Controllers
21
23
  autoload :Helpers, 'devise/controllers/helpers'
22
24
  autoload :Rememberable, 'devise/controllers/rememberable'
25
+ autoload :Responder, 'devise/controllers/responder'
23
26
  autoload :ScopedViews, 'devise/controllers/scoped_views'
24
27
  autoload :SignInOut, 'devise/controllers/sign_in_out'
25
28
  autoload :StoreLocation, 'devise/controllers/store_location'
@@ -39,19 +42,24 @@ module Devise
39
42
  autoload :Authenticatable, 'devise/strategies/authenticatable'
40
43
  end
41
44
 
45
+ module Test
46
+ autoload :ControllerHelpers, 'devise/test/controller_helpers'
47
+ autoload :IntegrationHelpers, 'devise/test/integration_helpers'
48
+ end
49
+
42
50
  # Constants which holds devise configuration for extensions. Those should
43
51
  # not be modified by the "end user" (this is why they are constants).
44
52
  ALL = []
45
- CONTROLLERS = ActiveSupport::OrderedHash.new
46
- ROUTES = ActiveSupport::OrderedHash.new
47
- STRATEGIES = ActiveSupport::OrderedHash.new
48
- URL_HELPERS = ActiveSupport::OrderedHash.new
53
+ CONTROLLERS = {}
54
+ ROUTES = {}
55
+ STRATEGIES = {}
56
+ URL_HELPERS = {}
49
57
 
50
58
  # Strategies that do not require user input.
51
59
  NO_INPUT = []
52
60
 
53
61
  # True values used to check params
54
- TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
62
+ TRUE_VALUES = [true, 1, '1', 'on', 'ON', 't', 'T', 'true', 'TRUE']
55
63
 
56
64
  # Secret key used by the key generator
57
65
  mattr_accessor :secret_key
@@ -63,7 +71,7 @@ module Devise
63
71
 
64
72
  # The number of times to hash the password.
65
73
  mattr_accessor :stretches
66
- @@stretches = 11
74
+ @@stretches = 12
67
75
 
68
76
  # The default key used when authenticating over http auth.
69
77
  mattr_accessor :http_authentication_key
@@ -144,11 +152,15 @@ module Devise
144
152
  mattr_accessor :timeout_in
145
153
  @@timeout_in = 30.minutes
146
154
 
147
- # Used to hash the password. Please generate one with rake secret.
155
+ # Used to hash the password. Please generate one with rails secret.
148
156
  mattr_accessor :pepper
149
157
  @@pepper = nil
150
158
 
151
- # Used to enable sending notification to user when their password is changed
159
+ # Used to send notification to the original user email when their email is changed.
160
+ mattr_accessor :send_email_changed_notification
161
+ @@send_email_changed_notification = false
162
+
163
+ # Used to enable sending notification to user when their password is changed.
152
164
  mattr_accessor :send_password_change_notification
153
165
  @@send_password_change_notification = false
154
166
 
@@ -205,7 +217,16 @@ module Devise
205
217
 
206
218
  # Which formats should be treated as navigational.
207
219
  mattr_accessor :navigational_formats
208
- @@navigational_formats = ["*/*", :html]
220
+ @@navigational_formats = ["*/*", :html, :turbo_stream]
221
+
222
+ # The default responder used by Devise, used to customize status codes with:
223
+ #
224
+ # `config.responder.error_status`
225
+ # `config.responder.redirect_status`
226
+ #
227
+ # Can be replaced by a custom application responder.
228
+ mattr_accessor :responder
229
+ @@responder = Devise::Controllers::Responder
209
230
 
210
231
  # When set to true, signing out a user signs out all other scopes.
211
232
  mattr_accessor :sign_out_all_scopes
@@ -242,15 +263,28 @@ module Devise
242
263
  mattr_accessor :clean_up_csrf_token_on_authentication
243
264
  @@clean_up_csrf_token_on_authentication = true
244
265
 
266
+ # When false, Devise will not attempt to reload routes on eager load.
267
+ # This can reduce the time taken to boot the app but if your application
268
+ # requires the Devise mappings to be loaded during boot time the application
269
+ # won't boot properly.
270
+ mattr_accessor :reload_routes
271
+ @@reload_routes = true
272
+
245
273
  # PRIVATE CONFIGURATION
246
274
 
247
275
  # Store scopes mappings.
248
- mattr_reader :mappings
249
- @@mappings = ActiveSupport::OrderedHash.new
276
+ @@mappings = {}
277
+ def self.mappings
278
+ # Starting from Rails 8.0, routes are lazy-loaded by default in test and development environments.
279
+ # However, Devise's mappings are built during the routes loading phase.
280
+ # To ensure it works correctly, we need to load the routes first before accessing @@mappings.
281
+ Rails.application.try(:reload_routes_unless_loaded)
282
+ @@mappings
283
+ end
250
284
 
251
285
  # OmniAuth configurations.
252
286
  mattr_reader :omniauth_configs
253
- @@omniauth_configs = ActiveSupport::OrderedHash.new
287
+ @@omniauth_configs = {}
254
288
 
255
289
  # Define a set of modules that are called when a mapping is added.
256
290
  mattr_reader :helpers
@@ -274,6 +308,10 @@ module Devise
274
308
  mattr_accessor :token_generator
275
309
  @@token_generator = nil
276
310
 
311
+ # When set to false, changing a password does not automatically sign in a user
312
+ mattr_accessor :sign_in_after_change_password
313
+ @@sign_in_after_change_password = true
314
+
277
315
  # Default way to set up Devise. Run rails generate devise_install to create
278
316
  # a fresh initializer with all configuration values.
279
317
  def self.setup
@@ -281,22 +319,26 @@ module Devise
281
319
  end
282
320
 
283
321
  class Getter
284
- def initialize name
322
+ def initialize(name)
285
323
  @name = name
286
324
  end
287
325
 
288
326
  def get
289
- ActiveSupport::Dependencies.constantize(@name)
327
+ # TODO: Remove AS::Dependencies usage when dropping support to Rails < 7.
328
+ if ActiveSupport::Dependencies.respond_to?(:constantize)
329
+ ActiveSupport::Dependencies.constantize(@name)
330
+ else
331
+ @name.constantize
332
+ end
290
333
  end
291
334
  end
292
335
 
293
336
  def self.ref(arg)
294
- if defined?(ActiveSupport::Dependencies::ClassCache)
295
- ActiveSupport::Dependencies::reference(arg)
296
- Getter.new(arg)
297
- else
298
- ActiveSupport::Dependencies.ref(arg)
337
+ # TODO: Remove AS::Dependencies usage when dropping support to Rails < 7.
338
+ if ActiveSupport::Dependencies.respond_to?(:reference)
339
+ ActiveSupport::Dependencies.reference(arg)
299
340
  end
341
+ Getter.new(arg)
300
342
  end
301
343
 
302
344
  def self.available_router_name
@@ -403,9 +445,9 @@ module Devise
403
445
  # Devise.setup do |config|
404
446
  # config.allow_unconfirmed_access_for = 2.days
405
447
  #
406
- # config.warden do |manager|
448
+ # config.warden do |warden_config|
407
449
  # # Configure warden to use other strategies, like oauth.
408
- # manager.oauth(:twitter)
450
+ # warden_config.oauth(:twitter)
409
451
  # end
410
452
  # end
411
453
  def self.warden(&block)
@@ -417,7 +459,6 @@ module Devise
417
459
  # config.omniauth :github, APP_ID, APP_SECRET
418
460
  #
419
461
  def self.omniauth(provider, *args)
420
- @@helpers << Devise::OmniAuth::UrlHelpers
421
462
  config = Devise::OmniAuth::Config.new(provider, args)
422
463
  @@omniauth_configs[config.strategy_name.to_sym] = config
423
464
  end
@@ -476,12 +517,12 @@ module Devise
476
517
 
477
518
  # constant-time comparison algorithm to prevent timing attacks
478
519
  def self.secure_compare(a, b)
479
- return false if a.blank? || b.blank? || a.bytesize != b.bytesize
480
- l = a.unpack "C#{a.bytesize}"
520
+ return false if a.nil? || b.nil?
521
+ ActiveSupport::SecurityUtils.secure_compare(a, b)
522
+ end
481
523
 
482
- res = 0
483
- b.each_byte { |byte| res |= byte ^ l.shift }
484
- res == 0
524
+ def self.deprecator
525
+ @deprecator ||= ActiveSupport::Deprecation.new("5.0", "Devise")
485
526
  end
486
527
  end
487
528