devise 3.5.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 (256) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +256 -1099
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +254 -67
  5. data/app/controllers/devise/confirmations_controller.rb +3 -1
  6. data/app/controllers/devise/omniauth_callbacks_controller.rb +8 -6
  7. data/app/controllers/devise/passwords_controller.rb +7 -4
  8. data/app/controllers/devise/registrations_controller.rb +39 -18
  9. data/app/controllers/devise/sessions_controller.rb +9 -7
  10. data/app/controllers/devise/unlocks_controller.rb +4 -2
  11. data/app/controllers/devise_controller.rb +23 -10
  12. data/app/helpers/devise_helper.rb +12 -19
  13. data/app/mailers/devise/mailer.rb +6 -0
  14. data/app/views/devise/confirmations/new.html.erb +2 -2
  15. data/app/views/devise/mailer/email_changed.html.erb +7 -0
  16. data/app/views/devise/passwords/edit.html.erb +3 -3
  17. data/app/views/devise/passwords/new.html.erb +2 -2
  18. data/app/views/devise/registrations/edit.html.erb +9 -5
  19. data/app/views/devise/registrations/new.html.erb +4 -4
  20. data/app/views/devise/sessions/new.html.erb +4 -4
  21. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  22. data/app/views/devise/shared/_links.html.erb +7 -7
  23. data/app/views/devise/unlocks/new.html.erb +2 -2
  24. data/config/locales/en.yml +4 -1
  25. data/lib/devise/controllers/helpers.rb +23 -20
  26. data/lib/devise/controllers/rememberable.rb +11 -2
  27. data/lib/devise/controllers/scoped_views.rb +2 -0
  28. data/lib/devise/controllers/sign_in_out.rb +34 -11
  29. data/lib/devise/controllers/store_location.rb +25 -7
  30. data/lib/devise/controllers/url_helpers.rb +2 -0
  31. data/lib/devise/delegator.rb +2 -0
  32. data/lib/devise/encryptor.rb +6 -4
  33. data/lib/devise/failure_app.rb +75 -37
  34. data/lib/devise/hooks/activatable.rb +2 -0
  35. data/lib/devise/hooks/csrf_cleaner.rb +2 -0
  36. data/lib/devise/hooks/forgetable.rb +2 -0
  37. data/lib/devise/hooks/lockable.rb +6 -1
  38. data/lib/devise/hooks/proxy.rb +3 -1
  39. data/lib/devise/hooks/rememberable.rb +2 -0
  40. data/lib/devise/hooks/timeoutable.rb +5 -2
  41. data/lib/devise/hooks/trackable.rb +2 -0
  42. data/lib/devise/mailers/helpers.rb +7 -4
  43. data/lib/devise/mapping.rb +2 -0
  44. data/lib/devise/models/authenticatable.rb +51 -26
  45. data/lib/devise/models/confirmable.rb +89 -27
  46. data/lib/devise/models/database_authenticatable.rb +88 -21
  47. data/lib/devise/models/lockable.rb +15 -5
  48. data/lib/devise/models/omniauthable.rb +2 -0
  49. data/lib/devise/models/recoverable.rb +32 -20
  50. data/lib/devise/models/registerable.rb +4 -0
  51. data/lib/devise/models/rememberable.rb +42 -26
  52. data/lib/devise/models/timeoutable.rb +2 -6
  53. data/lib/devise/models/trackable.rb +15 -1
  54. data/lib/devise/models/validatable.rb +10 -3
  55. data/lib/devise/models.rb +3 -1
  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 +14 -5
  59. data/lib/devise/omniauth.rb +2 -0
  60. data/lib/devise/orm/active_record.rb +5 -1
  61. data/lib/devise/orm/mongoid.rb +6 -2
  62. data/lib/devise/parameter_filter.rb +4 -0
  63. data/lib/devise/parameter_sanitizer.rb +139 -65
  64. data/lib/devise/rails/routes.rb +44 -33
  65. data/lib/devise/rails/warden_compat.rb +3 -10
  66. data/lib/devise/rails.rb +7 -16
  67. data/lib/devise/secret_key_finder.rb +27 -0
  68. data/lib/devise/strategies/authenticatable.rb +3 -1
  69. data/lib/devise/strategies/base.rb +2 -0
  70. data/lib/devise/strategies/database_authenticatable.rb +11 -4
  71. data/lib/devise/strategies/rememberable.rb +5 -6
  72. data/lib/devise/test/controller_helpers.rb +165 -0
  73. data/lib/devise/test/integration_helpers.rb +63 -0
  74. data/lib/devise/test_helpers.rb +7 -124
  75. data/lib/devise/time_inflector.rb +2 -0
  76. data/lib/devise/token_generator.rb +3 -41
  77. data/lib/devise/version.rb +3 -1
  78. data/lib/devise.rb +61 -40
  79. data/lib/generators/active_record/devise_generator.rb +29 -10
  80. data/lib/generators/active_record/templates/migration.rb +4 -2
  81. data/lib/generators/active_record/templates/migration_existing.rb +4 -2
  82. data/lib/generators/devise/controllers_generator.rb +3 -1
  83. data/lib/generators/devise/devise_generator.rb +4 -2
  84. data/lib/generators/devise/install_generator.rb +17 -0
  85. data/lib/generators/devise/orm_helpers.rb +10 -21
  86. data/lib/generators/devise/views_generator.rb +7 -8
  87. data/lib/generators/mongoid/devise_generator.rb +7 -5
  88. data/lib/generators/templates/README +1 -8
  89. data/lib/generators/templates/controllers/confirmations_controller.rb +2 -0
  90. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +2 -0
  91. data/lib/generators/templates/controllers/passwords_controller.rb +2 -0
  92. data/lib/generators/templates/controllers/registrations_controller.rb +6 -4
  93. data/lib/generators/templates/controllers/sessions_controller.rb +4 -2
  94. data/lib/generators/templates/controllers/unlocks_controller.rb +2 -0
  95. data/lib/generators/templates/devise.rb +50 -20
  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 +4 -1
  101. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +11 -3
  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 +13 -310
  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 -29
  112. data/Gemfile.lock +0 -183
  113. data/Rakefile +0 -36
  114. data/devise.gemspec +0 -27
  115. data/devise.png +0 -0
  116. data/gemfiles/Gemfile.rails-3.2-stable +0 -29
  117. data/gemfiles/Gemfile.rails-3.2-stable.lock +0 -172
  118. data/gemfiles/Gemfile.rails-4.0-stable +0 -29
  119. data/gemfiles/Gemfile.rails-4.0-stable.lock +0 -166
  120. data/gemfiles/Gemfile.rails-4.1-stable +0 -29
  121. data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -172
  122. data/gemfiles/Gemfile.rails-4.2-stable +0 -29
  123. data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -194
  124. data/script/cached-bundle +0 -49
  125. data/script/s3-put +0 -71
  126. data/test/controllers/custom_registrations_controller_test.rb +0 -40
  127. data/test/controllers/custom_strategy_test.rb +0 -62
  128. data/test/controllers/helper_methods_test.rb +0 -21
  129. data/test/controllers/helpers_test.rb +0 -316
  130. data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -51
  131. data/test/controllers/internal_helpers_test.rb +0 -129
  132. data/test/controllers/load_hooks_controller_test.rb +0 -19
  133. data/test/controllers/passwords_controller_test.rb +0 -31
  134. data/test/controllers/sessions_controller_test.rb +0 -103
  135. data/test/controllers/url_helpers_test.rb +0 -65
  136. data/test/delegator_test.rb +0 -19
  137. data/test/devise_test.rb +0 -107
  138. data/test/failure_app_test.rb +0 -315
  139. data/test/generators/active_record_generator_test.rb +0 -109
  140. data/test/generators/controllers_generator_test.rb +0 -48
  141. data/test/generators/devise_generator_test.rb +0 -39
  142. data/test/generators/install_generator_test.rb +0 -13
  143. data/test/generators/mongoid_generator_test.rb +0 -23
  144. data/test/generators/views_generator_test.rb +0 -103
  145. data/test/helpers/devise_helper_test.rb +0 -49
  146. data/test/integration/authenticatable_test.rb +0 -729
  147. data/test/integration/confirmable_test.rb +0 -324
  148. data/test/integration/database_authenticatable_test.rb +0 -95
  149. data/test/integration/http_authenticatable_test.rb +0 -105
  150. data/test/integration/lockable_test.rb +0 -239
  151. data/test/integration/omniauthable_test.rb +0 -135
  152. data/test/integration/recoverable_test.rb +0 -347
  153. data/test/integration/registerable_test.rb +0 -359
  154. data/test/integration/rememberable_test.rb +0 -176
  155. data/test/integration/timeoutable_test.rb +0 -184
  156. data/test/integration/trackable_test.rb +0 -92
  157. data/test/mailers/confirmation_instructions_test.rb +0 -115
  158. data/test/mailers/reset_password_instructions_test.rb +0 -96
  159. data/test/mailers/unlock_instructions_test.rb +0 -91
  160. data/test/mapping_test.rb +0 -134
  161. data/test/models/authenticatable_test.rb +0 -23
  162. data/test/models/confirmable_test.rb +0 -489
  163. data/test/models/database_authenticatable_test.rb +0 -269
  164. data/test/models/lockable_test.rb +0 -328
  165. data/test/models/omniauthable_test.rb +0 -7
  166. data/test/models/recoverable_test.rb +0 -251
  167. data/test/models/registerable_test.rb +0 -7
  168. data/test/models/rememberable_test.rb +0 -204
  169. data/test/models/serializable_test.rb +0 -49
  170. data/test/models/timeoutable_test.rb +0 -51
  171. data/test/models/trackable_test.rb +0 -41
  172. data/test/models/validatable_test.rb +0 -127
  173. data/test/models_test.rb +0 -153
  174. data/test/omniauth/config_test.rb +0 -57
  175. data/test/omniauth/url_helpers_test.rb +0 -54
  176. data/test/orm/active_record.rb +0 -10
  177. data/test/orm/mongoid.rb +0 -13
  178. data/test/parameter_sanitizer_test.rb +0 -81
  179. data/test/rails_app/Rakefile +0 -6
  180. data/test/rails_app/app/active_record/admin.rb +0 -6
  181. data/test/rails_app/app/active_record/shim.rb +0 -2
  182. data/test/rails_app/app/active_record/user.rb +0 -6
  183. data/test/rails_app/app/active_record/user_on_engine.rb +0 -7
  184. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -7
  185. data/test/rails_app/app/active_record/user_without_email.rb +0 -8
  186. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
  187. data/test/rails_app/app/controllers/admins_controller.rb +0 -6
  188. data/test/rails_app/app/controllers/application_controller.rb +0 -12
  189. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -30
  190. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -31
  191. data/test/rails_app/app/controllers/home_controller.rb +0 -25
  192. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
  193. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
  194. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
  195. data/test/rails_app/app/controllers/users_controller.rb +0 -31
  196. data/test/rails_app/app/helpers/application_helper.rb +0 -3
  197. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -3
  198. data/test/rails_app/app/mailers/users/mailer.rb +0 -3
  199. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -4
  200. data/test/rails_app/app/mongoid/admin.rb +0 -29
  201. data/test/rails_app/app/mongoid/shim.rb +0 -23
  202. data/test/rails_app/app/mongoid/user.rb +0 -39
  203. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -39
  204. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -39
  205. data/test/rails_app/app/mongoid/user_without_email.rb +0 -33
  206. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  207. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  208. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  209. data/test/rails_app/app/views/home/index.html.erb +0 -1
  210. data/test/rails_app/app/views/home/join.html.erb +0 -1
  211. data/test/rails_app/app/views/home/private.html.erb +0 -1
  212. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  213. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  214. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  215. data/test/rails_app/app/views/users/index.html.erb +0 -1
  216. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  217. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  218. data/test/rails_app/bin/bundle +0 -3
  219. data/test/rails_app/bin/rails +0 -4
  220. data/test/rails_app/bin/rake +0 -4
  221. data/test/rails_app/config/application.rb +0 -40
  222. data/test/rails_app/config/boot.rb +0 -14
  223. data/test/rails_app/config/database.yml +0 -18
  224. data/test/rails_app/config/environment.rb +0 -5
  225. data/test/rails_app/config/environments/development.rb +0 -30
  226. data/test/rails_app/config/environments/production.rb +0 -84
  227. data/test/rails_app/config/environments/test.rb +0 -41
  228. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  229. data/test/rails_app/config/initializers/devise.rb +0 -180
  230. data/test/rails_app/config/initializers/inflections.rb +0 -2
  231. data/test/rails_app/config/initializers/secret_token.rb +0 -8
  232. data/test/rails_app/config/initializers/session_store.rb +0 -1
  233. data/test/rails_app/config/routes.rb +0 -125
  234. data/test/rails_app/config.ru +0 -4
  235. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -71
  236. data/test/rails_app/db/schema.rb +0 -55
  237. data/test/rails_app/lib/shared_admin.rb +0 -17
  238. data/test/rails_app/lib/shared_user.rb +0 -29
  239. data/test/rails_app/lib/shared_user_without_email.rb +0 -26
  240. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -13
  241. data/test/rails_app/public/404.html +0 -26
  242. data/test/rails_app/public/422.html +0 -26
  243. data/test/rails_app/public/500.html +0 -26
  244. data/test/rails_app/public/favicon.ico +0 -0
  245. data/test/rails_test.rb +0 -9
  246. data/test/routes_test.rb +0 -264
  247. data/test/support/action_controller/record_identifier.rb +0 -10
  248. data/test/support/assertions.rb +0 -39
  249. data/test/support/helpers.rb +0 -77
  250. data/test/support/integration.rb +0 -92
  251. data/test/support/locale/en.yml +0 -8
  252. data/test/support/mongoid.yml +0 -6
  253. data/test/support/webrat/integrations/rails.rb +0 -24
  254. data/test/test_helper.rb +0 -34
  255. data/test/test_helpers_test.rb +0 -178
  256. data/test/test_models.rb +0 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Controllers
3
5
  # A module that may be optionally included in a controller in order
@@ -9,11 +11,18 @@ module Devise
9
11
  Rails.configuration.session_options.slice(:path, :domain, :secure)
10
12
  end
11
13
 
14
+ def remember_me_is_active?(resource)
15
+ return false unless resource.respond_to?(:remember_me)
16
+ scope = Devise::Mapping.find_scope!(resource)
17
+ _, token, generated_at = cookies.signed[remember_key(resource, scope)]
18
+ resource.remember_me?(token, generated_at)
19
+ end
20
+
12
21
  # Remembers the given resource by setting up a cookie
13
22
  def remember_me(resource)
14
- return if env["devise.skip_storage"]
23
+ return if request.env["devise.skip_storage"]
15
24
  scope = Devise::Mapping.find_scope!(resource)
16
- resource.remember_me!(resource.extend_remember_period)
25
+ resource.remember_me!
17
26
  cookies.signed[remember_key(resource, scope)] = remember_cookie_values(resource)
18
27
  end
19
28
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Controllers
3
5
  module ScopedViews
@@ -1,10 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Controllers
3
5
  # Provide sign in and sign out functionality.
4
6
  # Included by default in all controllers.
5
7
  module SignInOut
6
8
  # Return true if the given scope is signed in session. If no scope given, return
7
- # true if any scope is signed in. Does not run authentication hooks.
9
+ # true if any scope is signed in. This will run authentication hooks, which may
10
+ # cause exceptions to be thrown from this method; if you simply want to check
11
+ # if a scope has already previously been authenticated without running
12
+ # authentication hooks, you can directly call `warden.authenticated?(scope: scope)`
8
13
  def signed_in?(scope=nil)
9
14
  [scope || Devise.mappings.keys].flatten.any? do |_scope|
10
15
  warden.authenticate?(scope: _scope)
@@ -12,20 +17,18 @@ module Devise
12
17
  end
13
18
 
14
19
  # Sign in a user that already was authenticated. This helper is useful for logging
15
- # users in after sign up.
16
- #
17
- # All options given to sign_in is passed forward to the set_user method in warden.
18
- # The only exception is the :bypass option, which bypass warden callbacks and stores
19
- # the user straight in session. This option is useful in cases the user is already
20
- # signed in, but we want to refresh the credentials in session.
20
+ # users in after sign up. All options given to sign_in is passed forward
21
+ # to the set_user method in warden.
22
+ # If you are using a custom warden strategy and the timeoutable module, you have to
23
+ # set `env["devise.skip_timeout"] = true` in the request to use this method, like we do
24
+ # in the sessions controller: https://github.com/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
21
25
  #
22
26
  # Examples:
23
27
  #
24
28
  # sign_in :user, @user # sign_in(scope, resource)
25
29
  # sign_in @user # sign_in(resource)
26
- # sign_in @user, event: :authentication # sign_in(resource, options)
27
- # sign_in @user, store: false # sign_in(resource, options)
28
- # sign_in @user, bypass: true # sign_in(resource, options)
30
+ # sign_in @user, event: :authentication # sign_in(resource, options)
31
+ # sign_in @user, store: false # sign_in(resource, options)
29
32
  #
30
33
  def sign_in(resource_or_scope, *args)
31
34
  options = args.extract_options!
@@ -35,6 +38,13 @@ module Devise
35
38
  expire_data_after_sign_in!
36
39
 
37
40
  if options[:bypass]
41
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
42
+ [Devise] bypass option is deprecated and it will be removed in future version of Devise.
43
+ Please use bypass_sign_in method instead.
44
+ Example:
45
+
46
+ bypass_sign_in(user)
47
+ DEPRECATION
38
48
  warden.session_serializer.store(resource, scope)
39
49
  elsif warden.user(scope) == resource && !options.delete(:force)
40
50
  # Do nothing. User already signed in and we are not forcing it.
@@ -44,6 +54,20 @@ module Devise
44
54
  end
45
55
  end
46
56
 
57
+ # Sign in a user bypassing the warden callbacks and stores the user
58
+ # straight in session. This option is useful in cases the user is already
59
+ # signed in, but we want to refresh the credentials in session.
60
+ #
61
+ # Examples:
62
+ #
63
+ # bypass_sign_in @user, scope: :user
64
+ # bypass_sign_in @user
65
+ def bypass_sign_in(resource, scope: nil)
66
+ scope ||= Devise::Mapping.find_scope!(resource)
67
+ expire_data_after_sign_in!
68
+ warden.session_serializer.store(resource, scope)
69
+ end
70
+
47
71
  # Sign out a given user or scope. This helper is useful for signing out a user
48
72
  # after deleting accounts. Returns true if there was a logout and false if there
49
73
  # is no user logged in on the referred scope
@@ -58,7 +82,6 @@ module Devise
58
82
  scope = Devise::Mapping.find_scope!(resource_or_scope)
59
83
  user = warden.user(scope: scope, run_callbacks: false) # If there is no user
60
84
 
61
- warden.raw_session.inspect # Without this inspect here. The session does not clear.
62
85
  warden.logout(scope)
63
86
  warden.clear_strategies_cache!(scope: scope)
64
87
  instance_variable_set(:"@current_#{scope}", nil)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "uri"
2
4
 
3
5
  module Devise
@@ -29,16 +31,13 @@ module Devise
29
31
  # Example:
30
32
  #
31
33
  # store_location_for(:user, dashboard_path)
32
- # redirect_to user_omniauth_authorize_path(:facebook)
34
+ # redirect_to user_facebook_omniauth_authorize_path
33
35
  #
34
36
  def store_location_for(resource_or_scope, location)
35
37
  session_key = stored_location_key_for(resource_or_scope)
36
- uri = parse_uri(location)
37
- if uri
38
- path = [uri.path.sub(/\A\/+/, '/'), uri.query].compact.join('?')
39
- path = [path, uri.fragment].compact.join('#')
40
- session[session_key] = path
41
- end
38
+
39
+ path = extract_path_from_location(location)
40
+ session[session_key] = path if path
42
41
  end
43
42
 
44
43
  private
@@ -53,6 +52,25 @@ module Devise
53
52
  scope = Devise::Mapping.find_scope!(resource_or_scope)
54
53
  "#{scope}_return_to"
55
54
  end
55
+
56
+ def extract_path_from_location(location)
57
+ uri = parse_uri(location)
58
+
59
+ if uri
60
+ path = remove_domain_from_uri(uri)
61
+ path = add_fragment_back_to_path(uri, path)
62
+
63
+ path
64
+ end
65
+ end
66
+
67
+ def remove_domain_from_uri(uri)
68
+ [uri.path.sub(/\A\/+/, '/'), uri.query].compact.join('?')
69
+ end
70
+
71
+ def add_fragment_back_to_path(uri, path)
72
+ [path, uri.fragment].compact.join('#')
73
+ end
56
74
  end
57
75
  end
58
76
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Controllers
3
5
  # Create url helpers to be used with resource/scope configuration. Acts as
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  # Checks the scope in the given environment and returns the associated failure app.
3
5
  class Delegator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bcrypt'
2
4
 
3
5
  module Devise
@@ -9,14 +11,14 @@ module Devise
9
11
  ::BCrypt::Password.create(password, cost: klass.stretches).to_s
10
12
  end
11
13
 
12
- def self.compare(klass, encrypted_password, password)
13
- return false if encrypted_password.blank?
14
- bcrypt = ::BCrypt::Password.new(encrypted_password)
14
+ def self.compare(klass, hashed_password, password)
15
+ return false if hashed_password.blank?
16
+ bcrypt = ::BCrypt::Password.new(hashed_password)
15
17
  if klass.pepper.present?
16
18
  password = "#{password}#{klass.pepper}"
17
19
  end
18
20
  password = ::BCrypt::Engine.hash_secret(password, bcrypt.salt)
19
- Devise.secure_compare(password, encrypted_password)
21
+ Devise.secure_compare(password, hashed_password)
20
22
  end
21
23
  end
22
24
  end
@@ -1,12 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "action_controller/metal"
2
4
 
3
5
  module Devise
4
6
  # Failure application that will be called every time :warden is thrown from
5
- # any strategy or hook. Responsible for redirect the user to the sign in
6
- # page based on current scope and mapping. If no scope is given, redirect
7
- # to the default_url.
7
+ # any strategy or hook. It is responsible for redirecting the user to the sign
8
+ # in page based on current scope and mapping. If no scope is given, it
9
+ # redirects to the default_url.
8
10
  class FailureApp < ActionController::Metal
9
- include ActionController::RackDelegation
10
11
  include ActionController::UrlFor
11
12
  include ActionController::Redirecting
12
13
 
@@ -22,7 +23,7 @@ module Devise
22
23
  @respond.call(env)
23
24
  end
24
25
 
25
- # Try retrieving the URL options from the parent controller (usually
26
+ # Try retrieving the URL options from the parent controller (usually
26
27
  # ApplicationController). Instance methods are not supported at the moment,
27
28
  # so only the class-level attribute is used.
28
29
  def self.default_url_options(*args)
@@ -51,20 +52,27 @@ module Devise
51
52
  end
52
53
 
53
54
  def recall
54
- config = Rails.application.config
55
-
56
- if config.try(:relative_url_root)
57
- base_path = Pathname.new(config.relative_url_root)
55
+ header_info = if relative_url_root?
56
+ base_path = Pathname.new(relative_url_root)
58
57
  full_path = Pathname.new(attempted_path)
59
58
 
60
- env["SCRIPT_NAME"] = config.relative_url_root
61
- env["PATH_INFO"] = '/' + full_path.relative_path_from(base_path).to_s
59
+ { "SCRIPT_NAME" => relative_url_root,
60
+ "PATH_INFO" => '/' + full_path.relative_path_from(base_path).to_s }
62
61
  else
63
- env["PATH_INFO"] = attempted_path
62
+ { "PATH_INFO" => attempted_path }
63
+ end
64
+
65
+ header_info.each do | var, value|
66
+ if request.respond_to?(:set_header)
67
+ request.set_header(var, value)
68
+ else
69
+ request.env[var] = value
70
+ end
64
71
  end
65
72
 
66
73
  flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
67
- self.response = recall_app(warden_options[:recall]).call(env)
74
+ # self.response = recall_app(warden_options[:recall]).call(env)
75
+ self.response = recall_app(warden_options[:recall]).call(request.env)
68
76
  end
69
77
 
70
78
  def redirect
@@ -95,7 +103,7 @@ module Devise
95
103
  options[:scope] = "devise.failure"
96
104
  options[:default] = [message]
97
105
  auth_keys = scope_class.authentication_keys
98
- keys = auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys
106
+ keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key| scope_class.human_attribute_name(key) }
99
107
  options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
100
108
  options = i18n_options(options)
101
109
 
@@ -127,23 +135,29 @@ module Devise
127
135
 
128
136
  def scope_url
129
137
  opts = {}
130
- route = route(scope)
131
- opts[:format] = request_format unless skip_format?
132
138
 
133
- config = Rails.application.config
139
+ # Initialize script_name with nil to prevent infinite loops in
140
+ # authenticated mounted engines in rails 4.2 and 5.0
141
+ opts[:script_name] = nil
134
142
 
135
- # Rails 4.2 goes into an infinite loop if opts[:script_name] is unset
136
- if (Rails::VERSION::MAJOR >= 4) && (Rails::VERSION::MINOR >= 2)
137
- opts[:script_name] = (config.relative_url_root if config.respond_to?(:relative_url_root))
138
- else
139
- if config.respond_to?(:relative_url_root) && config.relative_url_root.present?
140
- opts[:script_name] = config.relative_url_root
141
- end
142
- end
143
+ route = route(scope)
144
+
145
+ opts[:format] = request_format unless skip_format?
143
146
 
144
147
  router_name = Devise.mappings[scope].router_name || Devise.available_router_name
145
148
  context = send(router_name)
146
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
+
147
161
  if context.respond_to?(route)
148
162
  context.send(route, opts)
149
163
  elsif respond_to?(:root_url)
@@ -157,12 +171,12 @@ module Devise
157
171
  %w(html */*).include? request_format.to_s
158
172
  end
159
173
 
160
- # Choose whether we should respond in a http authentication fashion,
174
+ # Choose whether we should respond in an HTTP authentication fashion,
161
175
  # including 401 and optional headers.
162
176
  #
163
- # This method allows the user to explicitly disable http authentication
164
- # on ajax requests in case they want to redirect on failures instead of
165
- # handling the errors on their own. This is useful in case your ajax API
177
+ # This method allows the user to explicitly disable HTTP authentication
178
+ # on AJAX requests in case they want to redirect on failures instead of
179
+ # handling the errors on their own. This is useful in case your AJAX API
166
180
  # is the same as your public API and uses a format like JSON (so you
167
181
  # cannot mark JSON as a navigational format).
168
182
  def http_auth?
@@ -173,7 +187,7 @@ module Devise
173
187
  end
174
188
  end
175
189
 
176
- # It does not make sense to send authenticate headers in ajax requests
190
+ # It doesn't make sense to send authenticate headers in AJAX requests
177
191
  # or if the user disabled them.
178
192
  def http_auth_header?
179
193
  scope_class.http_authenticatable && !request.xhr?
@@ -199,11 +213,11 @@ module Devise
199
213
  end
200
214
 
201
215
  def warden
202
- env['warden']
216
+ request.respond_to?(:get_header) ? request.get_header("warden") : request.env["warden"]
203
217
  end
204
218
 
205
219
  def warden_options
206
- env['warden.options']
220
+ request.respond_to?(:get_header) ? request.get_header("warden.options") : request.env["warden.options"]
207
221
  end
208
222
 
209
223
  def warden_message
@@ -222,10 +236,10 @@ module Devise
222
236
  warden_options[:attempted_path]
223
237
  end
224
238
 
225
- # Stores requested uri to redirect the user after signing in. We cannot use
226
- # scoped session provided by warden here, since the user is not authenticated
227
- # yet, but we still need to store the uri based on scope, so different scopes
228
- # would never use the same uri to redirect.
239
+ # Stores requested URI to redirect the user after signing in. We can't use
240
+ # the scoped session provided by warden here, since the user is not
241
+ # authenticated yet, but we still need to store the URI based on scope, so
242
+ # different scopes would never use the same URI to redirect.
229
243
  def store_location!
230
244
  store_location_for(scope, attempted_path) if request.get? && !http_auth?
231
245
  end
@@ -237,11 +251,35 @@ module Devise
237
251
  # Check if flash messages should be emitted. Default is to do it on
238
252
  # navigational formats
239
253
  def is_flashing_format?
240
- is_navigational_format?
254
+ request.respond_to?(:flash) && is_navigational_format?
241
255
  end
242
256
 
243
257
  def request_format
244
258
  @request_format ||= request.format.try(:ref)
245
259
  end
260
+
261
+ def relative_url_root
262
+ @relative_url_root ||= begin
263
+ config = Rails.application.config
264
+
265
+ config.try(:relative_url_root) || config.action_controller.try(:relative_url_root)
266
+ end
267
+ end
268
+
269
+ def relative_url_root?
270
+ relative_url_root.present?
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
246
284
  end
247
285
  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,3 +1,5 @@
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?
@@ -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,7 +1,12 @@
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
6
  if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
5
- record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.to_i.zero?
7
+ unless record.failed_attempts.to_i.zero?
8
+ record.failed_attempts = 0
9
+ record.save(validate: false)
10
+ end
6
11
  end
7
12
  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
@@ -7,7 +9,7 @@ module Devise
7
9
  include Devise::Controllers::SignInOut
8
10
 
9
11
  attr_reader :warden
10
- delegate :cookies, :env, to: :warden
12
+ delegate :cookies, :request, to: :warden
11
13
 
12
14
  def initialize(warden)
13
15
  @warden = warden
@@ -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,9 +21,10 @@ 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) && !env['devise.skip_timeout']
24
+ if record.timedout?(last_request_at) &&
25
+ !env['devise.skip_timeout'] &&
26
+ !proxy.remember_me_is_active?(record)
23
27
  Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
24
-
25
28
  throw :warden, scope: scope, message: :timeout
26
29
  end
27
30
 
@@ -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
@@ -5,15 +7,16 @@ module Devise
5
7
 
6
8
  included do
7
9
  include Devise::Controllers::ScopedViews
8
- attr_reader :scope_name, :resource
9
10
  end
10
11
 
11
12
  protected
12
13
 
14
+ attr_reader :scope_name, :resource
15
+
13
16
  # Configure default email options
14
- def devise_mail(record, action, opts={})
17
+ def devise_mail(record, action, opts = {}, &block)
15
18
  initialize_from_record(record)
16
- mail headers_for(action, opts)
19
+ mail headers_for(action, opts), &block
17
20
  end
18
21
 
19
22
  def initialize_from_record(record)
@@ -64,7 +67,7 @@ module Devise
64
67
  template_path
65
68
  end
66
69
 
67
- # Setup a subject doing an I18n lookup. At first, it attempts to set a subject
70
+ # Set up a subject doing an I18n lookup. At first, it attempts to set a subject
68
71
  # based on the current mapping:
69
72
  #
70
73
  # en:
@@ -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