devise 4.5.0 → 4.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +96 -4
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +93 -56
  5. data/app/controllers/devise/passwords_controller.rb +1 -0
  6. data/app/controllers/devise/registrations_controller.rb +25 -7
  7. data/app/controllers/devise_controller.rb +2 -2
  8. data/app/helpers/devise_helper.rb +21 -18
  9. data/app/mailers/devise/mailer.rb +5 -5
  10. data/app/views/devise/confirmations/new.html.erb +1 -1
  11. data/app/views/devise/passwords/edit.html.erb +2 -2
  12. data/app/views/devise/passwords/new.html.erb +1 -1
  13. data/app/views/devise/registrations/edit.html.erb +1 -1
  14. data/app/views/devise/registrations/new.html.erb +1 -1
  15. data/app/views/devise/sessions/new.html.erb +2 -2
  16. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  17. data/app/views/devise/shared/_links.html.erb +8 -8
  18. data/app/views/devise/unlocks/new.html.erb +1 -1
  19. data/config/locales/en.yml +3 -2
  20. data/lib/devise/controllers/helpers.rb +8 -8
  21. data/lib/devise/controllers/sign_in_out.rb +6 -4
  22. data/lib/devise/controllers/url_helpers.rb +1 -1
  23. data/lib/devise/failure_app.rb +23 -5
  24. data/lib/devise/hooks/lockable.rb +2 -5
  25. data/lib/devise/hooks/timeoutable.rb +2 -2
  26. data/lib/devise/mapping.rb +1 -1
  27. data/lib/devise/models/authenticatable.rb +20 -24
  28. data/lib/devise/models/confirmable.rb +18 -3
  29. data/lib/devise/models/database_authenticatable.rb +44 -6
  30. data/lib/devise/models/lockable.rb +12 -4
  31. data/lib/devise/models/omniauthable.rb +2 -2
  32. data/lib/devise/models/recoverable.rb +3 -3
  33. data/lib/devise/models/registerable.rb +2 -0
  34. data/lib/devise/models/rememberable.rb +2 -2
  35. data/lib/devise/models/timeoutable.rb +1 -1
  36. data/lib/devise/models/trackable.rb +1 -1
  37. data/lib/devise/models/validatable.rb +2 -2
  38. data/lib/devise/omniauth.rb +2 -5
  39. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  40. data/lib/devise/rails/routes.rb +6 -6
  41. data/lib/devise/strategies/authenticatable.rb +1 -1
  42. data/lib/devise/strategies/database_authenticatable.rb +3 -0
  43. data/lib/devise/test/controller_helpers.rb +4 -2
  44. data/lib/devise/test/integration_helpers.rb +1 -1
  45. data/lib/devise/version.rb +1 -1
  46. data/lib/devise.rb +14 -6
  47. data/lib/generators/active_record/devise_generator.rb +21 -6
  48. data/lib/generators/devise/controllers_generator.rb +1 -1
  49. data/lib/generators/devise/devise_generator.rb +1 -1
  50. data/lib/generators/devise/install_generator.rb +1 -5
  51. data/lib/generators/devise/views_generator.rb +1 -1
  52. data/lib/generators/templates/README +9 -1
  53. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
  54. data/lib/generators/templates/devise.rb +27 -6
  55. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +4 -1
  56. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +1 -1
  57. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +1 -1
  58. metadata +18 -318
  59. data/.gitignore +0 -10
  60. data/.travis.yml +0 -69
  61. data/.yardopts +0 -9
  62. data/CODE_OF_CONDUCT.md +0 -22
  63. data/CONTRIBUTING.md +0 -79
  64. data/Gemfile +0 -39
  65. data/Gemfile.lock +0 -202
  66. data/ISSUE_TEMPLATE.md +0 -19
  67. data/Rakefile +0 -37
  68. data/bin/test +0 -13
  69. data/devise.gemspec +0 -28
  70. data/devise.png +0 -0
  71. data/gemfiles/Gemfile.rails-4.1-stable +0 -32
  72. data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
  73. data/gemfiles/Gemfile.rails-4.2-stable +0 -32
  74. data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -192
  75. data/gemfiles/Gemfile.rails-5.0-stable +0 -33
  76. data/gemfiles/Gemfile.rails-5.0-stable.lock +0 -192
  77. data/gemfiles/Gemfile.rails-5.2-rc1 +0 -26
  78. data/gemfiles/Gemfile.rails-5.2-rc1.lock +0 -201
  79. data/guides/bug_report_templates/integration_test.rb +0 -106
  80. data/test/controllers/custom_registrations_controller_test.rb +0 -42
  81. data/test/controllers/custom_strategy_test.rb +0 -66
  82. data/test/controllers/helper_methods_test.rb +0 -24
  83. data/test/controllers/helpers_test.rb +0 -318
  84. data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -53
  85. data/test/controllers/internal_helpers_test.rb +0 -129
  86. data/test/controllers/load_hooks_controller_test.rb +0 -21
  87. data/test/controllers/passwords_controller_test.rb +0 -34
  88. data/test/controllers/sessions_controller_test.rb +0 -108
  89. data/test/controllers/url_helpers_test.rb +0 -67
  90. data/test/delegator_test.rb +0 -21
  91. data/test/devise_test.rb +0 -109
  92. data/test/failure_app_test.rb +0 -346
  93. data/test/generators/active_record_generator_test.rb +0 -130
  94. data/test/generators/controllers_generator_test.rb +0 -50
  95. data/test/generators/devise_generator_test.rb +0 -41
  96. data/test/generators/install_generator_test.rb +0 -26
  97. data/test/generators/mongoid_generator_test.rb +0 -25
  98. data/test/generators/views_generator_test.rb +0 -105
  99. data/test/helpers/devise_helper_test.rb +0 -51
  100. data/test/integration/authenticatable_test.rb +0 -706
  101. data/test/integration/confirmable_test.rb +0 -326
  102. data/test/integration/database_authenticatable_test.rb +0 -110
  103. data/test/integration/http_authenticatable_test.rb +0 -114
  104. data/test/integration/lockable_test.rb +0 -242
  105. data/test/integration/mounted_engine_test.rb +0 -38
  106. data/test/integration/omniauthable_test.rb +0 -148
  107. data/test/integration/recoverable_test.rb +0 -349
  108. data/test/integration/registerable_test.rb +0 -365
  109. data/test/integration/rememberable_test.rb +0 -219
  110. data/test/integration/timeoutable_test.rb +0 -186
  111. data/test/integration/trackable_test.rb +0 -99
  112. data/test/mailers/confirmation_instructions_test.rb +0 -117
  113. data/test/mailers/email_changed_test.rb +0 -132
  114. data/test/mailers/mailer_test.rb +0 -20
  115. data/test/mailers/reset_password_instructions_test.rb +0 -98
  116. data/test/mailers/unlock_instructions_test.rb +0 -93
  117. data/test/mapping_test.rb +0 -136
  118. data/test/models/authenticatable_test.rb +0 -25
  119. data/test/models/confirmable_test.rb +0 -549
  120. data/test/models/database_authenticatable_test.rb +0 -290
  121. data/test/models/lockable_test.rb +0 -352
  122. data/test/models/omniauthable_test.rb +0 -9
  123. data/test/models/recoverable_test.rb +0 -263
  124. data/test/models/registerable_test.rb +0 -9
  125. data/test/models/rememberable_test.rb +0 -184
  126. data/test/models/serializable_test.rb +0 -60
  127. data/test/models/timeoutable_test.rb +0 -53
  128. data/test/models/trackable_test.rb +0 -80
  129. data/test/models/validatable_test.rb +0 -121
  130. data/test/models_test.rb +0 -155
  131. data/test/omniauth/config_test.rb +0 -61
  132. data/test/omniauth/url_helpers_test.rb +0 -53
  133. data/test/orm/active_record.rb +0 -24
  134. data/test/orm/mongoid.rb +0 -15
  135. data/test/parameter_sanitizer_test.rb +0 -105
  136. data/test/rails_app/Rakefile +0 -6
  137. data/test/rails_app/app/active_record/admin.rb +0 -8
  138. data/test/rails_app/app/active_record/shim.rb +0 -4
  139. data/test/rails_app/app/active_record/user.rb +0 -20
  140. data/test/rails_app/app/active_record/user_on_engine.rb +0 -9
  141. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -9
  142. data/test/rails_app/app/active_record/user_with_validations.rb +0 -12
  143. data/test/rails_app/app/active_record/user_without_email.rb +0 -10
  144. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -8
  145. data/test/rails_app/app/controllers/admins_controller.rb +0 -8
  146. data/test/rails_app/app/controllers/application_controller.rb +0 -13
  147. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -32
  148. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -33
  149. data/test/rails_app/app/controllers/home_controller.rb +0 -31
  150. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -4
  151. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -4
  152. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -16
  153. data/test/rails_app/app/controllers/users_controller.rb +0 -33
  154. data/test/rails_app/app/helpers/application_helper.rb +0 -5
  155. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -5
  156. data/test/rails_app/app/mailers/users/mailer.rb +0 -5
  157. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -6
  158. data/test/rails_app/app/mongoid/admin.rb +0 -31
  159. data/test/rails_app/app/mongoid/shim.rb +0 -25
  160. data/test/rails_app/app/mongoid/user.rb +0 -50
  161. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -41
  162. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -41
  163. data/test/rails_app/app/mongoid/user_with_validations.rb +0 -37
  164. data/test/rails_app/app/mongoid/user_without_email.rb +0 -35
  165. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  166. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  167. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  168. data/test/rails_app/app/views/home/index.html.erb +0 -1
  169. data/test/rails_app/app/views/home/join.html.erb +0 -1
  170. data/test/rails_app/app/views/home/private.html.erb +0 -1
  171. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  172. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  173. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  174. data/test/rails_app/app/views/users/index.html.erb +0 -1
  175. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  176. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  177. data/test/rails_app/bin/bundle +0 -3
  178. data/test/rails_app/bin/rails +0 -4
  179. data/test/rails_app/bin/rake +0 -4
  180. data/test/rails_app/config/application.rb +0 -48
  181. data/test/rails_app/config/boot.rb +0 -27
  182. data/test/rails_app/config/database.yml +0 -18
  183. data/test/rails_app/config/environment.rb +0 -7
  184. data/test/rails_app/config/environments/development.rb +0 -32
  185. data/test/rails_app/config/environments/production.rb +0 -88
  186. data/test/rails_app/config/environments/test.rb +0 -47
  187. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -9
  188. data/test/rails_app/config/initializers/devise.rb +0 -187
  189. data/test/rails_app/config/initializers/inflections.rb +0 -4
  190. data/test/rails_app/config/initializers/secret_token.rb +0 -5
  191. data/test/rails_app/config/initializers/session_store.rb +0 -3
  192. data/test/rails_app/config/routes.rb +0 -128
  193. data/test/rails_app/config.ru +0 -4
  194. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -77
  195. data/test/rails_app/db/schema.rb +0 -57
  196. data/test/rails_app/lib/lazy_load_test_module.rb +0 -5
  197. data/test/rails_app/lib/shared_admin.rb +0 -23
  198. data/test/rails_app/lib/shared_user.rb +0 -32
  199. data/test/rails_app/lib/shared_user_without_email.rb +0 -28
  200. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -15
  201. data/test/rails_app/public/404.html +0 -26
  202. data/test/rails_app/public/422.html +0 -26
  203. data/test/rails_app/public/500.html +0 -26
  204. data/test/rails_app/public/favicon.ico +0 -0
  205. data/test/rails_test.rb +0 -11
  206. data/test/routes_test.rb +0 -281
  207. data/test/secret_key_finder_test.rb +0 -121
  208. data/test/support/action_controller/record_identifier.rb +0 -12
  209. data/test/support/assertions.rb +0 -30
  210. data/test/support/helpers.rb +0 -83
  211. data/test/support/http_method_compatibility.rb +0 -53
  212. data/test/support/integration.rb +0 -95
  213. data/test/support/locale/en.yml +0 -8
  214. data/test/support/mongoid.yml +0 -6
  215. data/test/support/webrat/integrations/rails.rb +0 -35
  216. data/test/test/controller_helpers_test.rb +0 -193
  217. data/test/test/integration_helpers_test.rb +0 -34
  218. data/test/test_helper.rb +0 -36
  219. data/test/test_models.rb +0 -35
@@ -1,7 +1,7 @@
1
1
  <h2>Resend confirmation instructions</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -1,7 +1,7 @@
1
1
  <h2>Change your password</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
  <%= f.hidden_field :reset_password_token %>
6
6
 
7
7
  <div class="field">
@@ -14,7 +14,7 @@
14
14
 
15
15
  <div class="field">
16
16
  <%= f.label :password_confirmation, "Confirm new password" %><br />
17
- <%= f.password_field :password_confirmation, autocomplete: "off" %>
17
+ <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
18
18
  </div>
19
19
 
20
20
  <div class="actions">
@@ -1,7 +1,7 @@
1
1
  <h2>Forgot your password?</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -1,7 +1,7 @@
1
1
  <h2>Edit <%= resource_name.to_s.humanize %></h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -1,7 +1,7 @@
1
1
  <h2>Sign up</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -11,12 +11,12 @@
11
11
  <%= f.password_field :password, autocomplete: "current-password" %>
12
12
  </div>
13
13
 
14
- <% if devise_mapping.rememberable? -%>
14
+ <% if devise_mapping.rememberable? %>
15
15
  <div class="field">
16
16
  <%= f.check_box :remember_me %>
17
17
  <%= f.label :remember_me %>
18
18
  </div>
19
- <% end -%>
19
+ <% end %>
20
20
 
21
21
  <div class="actions">
22
22
  <%= f.submit "Log in" %>
@@ -0,0 +1,15 @@
1
+ <% if resource.errors.any? %>
2
+ <div id="error_explanation">
3
+ <h2>
4
+ <%= I18n.t("errors.messages.not_saved",
5
+ count: resource.errors.count,
6
+ resource: resource.class.model_name.human.downcase)
7
+ %>
8
+ </h2>
9
+ <ul>
10
+ <% resource.errors.full_messages.each do |message| %>
11
+ <li><%= message %></li>
12
+ <% end %>
13
+ </ul>
14
+ </div>
15
+ <% end %>
@@ -1,25 +1,25 @@
1
1
  <%- if controller_name != 'sessions' %>
2
2
  <%= link_to "Log in", new_session_path(resource_name) %><br />
3
- <% end -%>
3
+ <% end %>
4
4
 
5
5
  <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
6
6
  <%= link_to "Sign up", new_registration_path(resource_name) %><br />
7
- <% end -%>
7
+ <% end %>
8
8
 
9
9
  <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
10
10
  <%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
11
- <% end -%>
11
+ <% end %>
12
12
 
13
13
  <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
14
14
  <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
15
- <% end -%>
15
+ <% end %>
16
16
 
17
17
  <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
18
18
  <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
19
- <% end -%>
19
+ <% end %>
20
20
 
21
21
  <%- if devise_mapping.omniauthable? %>
22
22
  <%- resource_class.omniauth_providers.each do |provider| %>
23
- <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
24
- <% end -%>
25
- <% end -%>
23
+ <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %><br />
24
+ <% end %>
25
+ <% end %>
@@ -1,7 +1,7 @@
1
1
  <h2>Resend unlock instructions</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render "devise/shared/error_messages", resource: resource %>
5
5
 
6
6
  <div class="field">
7
7
  <%= f.label :email %><br />
@@ -1,4 +1,4 @@
1
- # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
1
+ # Additional translations at https://github.com/heartcombo/devise/wiki/I18n
2
2
 
3
3
  en:
4
4
  devise:
@@ -42,8 +42,9 @@ en:
42
42
  signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
43
43
  signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
44
44
  signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
45
- update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
45
+ update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address."
46
46
  updated: "Your account has been updated successfully."
47
+ updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again."
47
48
  sessions:
48
49
  signed_in: "Signed in successfully."
49
50
  signed_out: "Signed out successfully."
@@ -36,14 +36,14 @@ module Devise
36
36
  # before_action ->{ authenticate_blogger! :admin } # Redirects to the admin login page
37
37
  # current_blogger :user # Preferably returns a User if one is signed in
38
38
  #
39
- def devise_group(group_name, opts={})
39
+ def devise_group(group_name, opts = {})
40
40
  mappings = "[#{ opts[:contains].map { |m| ":#{m}" }.join(',') }]"
41
41
 
42
42
  class_eval <<-METHODS, __FILE__, __LINE__ + 1
43
- def authenticate_#{group_name}!(favourite=nil, opts={})
43
+ def authenticate_#{group_name}!(favorite = nil, opts = {})
44
44
  unless #{group_name}_signed_in?
45
45
  mappings = #{mappings}
46
- mappings.unshift mappings.delete(favourite.to_sym) if favourite
46
+ mappings.unshift mappings.delete(favorite.to_sym) if favorite
47
47
  mappings.each do |mapping|
48
48
  opts[:scope] = mapping
49
49
  warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
@@ -57,9 +57,9 @@ module Devise
57
57
  end
58
58
  end
59
59
 
60
- def current_#{group_name}(favourite=nil)
60
+ def current_#{group_name}(favorite = nil)
61
61
  mappings = #{mappings}
62
- mappings.unshift mappings.delete(favourite.to_sym) if favourite
62
+ mappings.unshift mappings.delete(favorite.to_sym) if favorite
63
63
  mappings.each do |mapping|
64
64
  current = warden.authenticate(scope: mapping)
65
65
  return current if current
@@ -113,7 +113,7 @@ module Devise
113
113
  mapping = mapping.name
114
114
 
115
115
  class_eval <<-METHODS, __FILE__, __LINE__ + 1
116
- def authenticate_#{mapping}!(opts={})
116
+ def authenticate_#{mapping}!(opts = {})
117
117
  opts[:scope] = :#{mapping}
118
118
  warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
119
119
  end
@@ -252,7 +252,7 @@ module Devise
252
252
  # Overwrite Rails' handle unverified request to sign out all scopes,
253
253
  # clear run strategies and remove cached variables.
254
254
  def handle_unverified_request
255
- super # call the default behaviour which resets/nullifies/raises
255
+ super # call the default behavior which resets/nullifies/raises
256
256
  request.env["devise.skip_storage"] = true
257
257
  sign_out_all_scopes(false)
258
258
  end
@@ -268,7 +268,7 @@ module Devise
268
268
  # Check if flash messages should be emitted. Default is to do it on
269
269
  # navigational formats
270
270
  def is_flashing_format?
271
- is_navigational_format?
271
+ request.respond_to?(:flash) && is_navigational_format?
272
272
  end
273
273
 
274
274
  private
@@ -10,7 +10,7 @@ module Devise
10
10
  # cause exceptions to be thrown from this method; if you simply want to check
11
11
  # if a scope has already previously been authenticated without running
12
12
  # authentication hooks, you can directly call `warden.authenticated?(scope: scope)`
13
- def signed_in?(scope=nil)
13
+ def signed_in?(scope = nil)
14
14
  [scope || Devise.mappings.keys].flatten.any? do |_scope|
15
15
  warden.authenticate?(scope: _scope)
16
16
  end
@@ -21,7 +21,7 @@ module Devise
21
21
  # to the set_user method in warden.
22
22
  # If you are using a custom warden strategy and the timeoutable module, you have to
23
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
24
+ # in the sessions controller: https://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
25
25
  #
26
26
  # Examples:
27
27
  #
@@ -77,7 +77,7 @@ module Devise
77
77
  # sign_out :user # sign_out(scope)
78
78
  # sign_out @user # sign_out(resource)
79
79
  #
80
- def sign_out(resource_or_scope=nil)
80
+ def sign_out(resource_or_scope = nil)
81
81
  return sign_out_all_scopes unless resource_or_scope
82
82
  scope = Devise::Mapping.find_scope!(resource_or_scope)
83
83
  user = warden.user(scope: scope, run_callbacks: false) # If there is no user
@@ -92,7 +92,7 @@ module Devise
92
92
  # Sign out all active users or scopes. This helper is useful for signing out all roles
93
93
  # in one click. This signs out ALL scopes in warden. Returns true if there was at least one logout
94
94
  # and false if there was no user logged in on all scopes.
95
- def sign_out_all_scopes(lock=true)
95
+ def sign_out_all_scopes(lock = true)
96
96
  users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) }
97
97
 
98
98
  warden.logout
@@ -106,10 +106,12 @@ module Devise
106
106
  private
107
107
 
108
108
  def expire_data_after_sign_in!
109
+ # TODO: remove once Rails 5.2+ and forward are only supported.
109
110
  # session.keys will return an empty array if the session is not yet loaded.
110
111
  # This is a bug in both Rack and Rails.
111
112
  # A call to #empty? forces the session to be loaded.
112
113
  session.empty?
114
+
113
115
  session.keys.grep(/^devise\./).each { |k| session.delete(k) }
114
116
  end
115
117
 
@@ -34,7 +34,7 @@ module Devise
34
34
  end
35
35
  end
36
36
 
37
- def self.generate_helpers!(routes=nil)
37
+ def self.generate_helpers!(routes = nil)
38
38
  routes ||= begin
39
39
  mappings = Devise.mappings.values.map(&:used_helpers).flatten.uniq
40
40
  Devise::URL_HELPERS.slice(*mappings)
@@ -71,7 +71,6 @@ module Devise
71
71
  end
72
72
 
73
73
  flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
74
- # self.response = recall_app(warden_options[:recall]).call(env)
75
74
  self.response = recall_app(warden_options[:recall]).call(request.env)
76
75
  end
77
76
 
@@ -107,7 +106,7 @@ module Devise
107
106
  options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
108
107
  options = i18n_options(options)
109
108
 
110
- I18n.t(:"#{scope}.#{message}", options)
109
+ I18n.t(:"#{scope}.#{message}", **options)
111
110
  else
112
111
  message.to_s
113
112
  end
@@ -144,11 +143,20 @@ module Devise
144
143
 
145
144
  opts[:format] = request_format unless skip_format?
146
145
 
147
- opts[:script_name] = relative_url_root if relative_url_root?
148
-
149
146
  router_name = Devise.mappings[scope].router_name || Devise.available_router_name
150
147
  context = send(router_name)
151
148
 
149
+ if relative_url_root?
150
+ opts[:script_name] = relative_url_root
151
+
152
+ # We need to add the rootpath to `script_name` manually for applications that use a Rails
153
+ # version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
154
+ # that use Devise. Remove it when the support of Rails 5.0 is dropped.
155
+ elsif root_path_defined?(context) && !rails_51_and_up?
156
+ rootpath = context.routes.url_helpers.root_path
157
+ opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
158
+ end
159
+
152
160
  if context.respond_to?(route)
153
161
  context.send(route, opts)
154
162
  elsif respond_to?(:root_url)
@@ -242,7 +250,7 @@ module Devise
242
250
  # Check if flash messages should be emitted. Default is to do it on
243
251
  # navigational formats
244
252
  def is_flashing_format?
245
- is_navigational_format?
253
+ request.respond_to?(:flash) && is_navigational_format?
246
254
  end
247
255
 
248
256
  def request_format
@@ -262,5 +270,15 @@ module Devise
262
270
  end
263
271
 
264
272
  ActiveSupport.run_load_hooks(:devise_failure_app, self)
273
+
274
+ private
275
+
276
+ def root_path_defined?(context)
277
+ defined?(context.routes) && context.routes.url_helpers.respond_to?(:root_path)
278
+ end
279
+
280
+ def rails_51_and_up?
281
+ Rails.gem_version >= Gem::Version.new("5.1")
282
+ end
265
283
  end
266
284
  end
@@ -3,10 +3,7 @@
3
3
  # After each sign in, if resource responds to failed_attempts, sets it to 0
4
4
  # This is only triggered when the user is explicitly set (with set_user)
5
5
  Warden::Manager.after_set_user except: :fetch do |record, warden, options|
6
- if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
7
- unless record.failed_attempts.to_i.zero?
8
- record.failed_attempts = 0
9
- record.save(validate: false)
10
- end
6
+ if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
7
+ record.reset_failed_attempts!
11
8
  end
12
9
  end
@@ -21,8 +21,8 @@ Warden::Manager.after_set_user do |record, warden, options|
21
21
 
22
22
  proxy = Devise::Hooks::Proxy.new(warden)
23
23
 
24
- if record.timedout?(last_request_at) &&
25
- !env['devise.skip_timeout'] &&
24
+ if !env['devise.skip_timeout'] &&
25
+ record.timedout?(last_request_at) &&
26
26
  !proxy.remember_me_is_active?(record)
27
27
  Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
28
28
  throw :warden, scope: scope, message: :timeout
@@ -46,7 +46,7 @@ module Devise
46
46
  raise "Could not find a valid mapping for #{obj.inspect}"
47
47
  end
48
48
 
49
- def self.find_by_path!(path, path_type=:fullpath)
49
+ def self.find_by_path!(path, path_type = :fullpath)
50
50
  Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
51
51
  raise "Could not find a valid mapping for path #{path.inspect}"
52
52
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_model/version'
4
3
  require 'devise/hooks/activatable'
5
4
  require 'devise/hooks/csrf_cleaner'
5
+ require 'devise/rails/deprecated_constant_accessor'
6
6
 
7
7
  module Devise
8
8
  module Models
@@ -10,7 +10,7 @@ module Devise
10
10
  #
11
11
  # == Options
12
12
  #
13
- # Authenticatable adds the following options to devise_for:
13
+ # Authenticatable adds the following options to +devise+:
14
14
  #
15
15
  # * +authentication_keys+: parameters used for authentication. By default [:email].
16
16
  #
@@ -56,11 +56,14 @@ module Devise
56
56
  module Authenticatable
57
57
  extend ActiveSupport::Concern
58
58
 
59
- BLACKLIST_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
59
+ UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
60
60
  :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
61
61
  :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
62
62
  :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
63
63
 
64
+ include Devise::DeprecatedConstantAccessor
65
+ deprecate_constant "BLACKLIST_FOR_SERIALIZATION", "Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION"
66
+
64
67
  included do
65
68
  class_attribute :devise_modules, instance_writer: false
66
69
  self.devise_modules ||= []
@@ -105,12 +108,12 @@ module Devise
105
108
  # given to :except will simply add names to exempt to Devise internal list.
106
109
  def serializable_hash(options = nil)
107
110
  options = options.try(:dup) || {}
108
- options[:except] = Array(options[:except])
111
+ options[:except] = Array(options[:except]).dup
109
112
 
110
113
  if options[:force_except]
111
114
  options[:except].concat Array(options[:force_except])
112
115
  else
113
- options[:except].concat BLACKLIST_FOR_SERIALIZATION
116
+ options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
114
117
  end
115
118
 
116
119
  super(options)
@@ -153,7 +156,8 @@ module Devise
153
156
  # # If the record is new or changed then delay the
154
157
  # # delivery until the after_commit callback otherwise
155
158
  # # send now because after_commit will not be called.
156
- # if new_record? || changed?
159
+ # # For Rails < 6 use `changed?` instead of `saved_changes?`.
160
+ # if new_record? || saved_changes?
157
161
  # pending_devise_notifications << [notification, args]
158
162
  # else
159
163
  # render_and_send_devise_message(notification, *args)
@@ -272,39 +276,31 @@ module Devise
272
276
  find_first_by_auth_conditions(tainted_conditions)
273
277
  end
274
278
 
275
- def find_first_by_auth_conditions(tainted_conditions, opts={})
279
+ def find_first_by_auth_conditions(tainted_conditions, opts = {})
276
280
  to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
277
281
  end
278
282
 
279
283
  # Find or initialize a record setting an error if it can't be found.
280
- 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:
281
285
  find_or_initialize_with_errors([attribute], { attribute => value }, error)
282
286
  end
283
287
 
284
288
  # Find or initialize a record with group of attributes based on a list of required attributes.
285
- def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
286
- attributes = if attributes.respond_to? :permit!
287
- attributes.slice(*required_attributes).permit!.to_h.with_indifferent_access
288
- else
289
- attributes.with_indifferent_access.slice(*required_attributes)
290
- end
291
- 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? }
292
294
 
293
295
  if attributes.size == required_attributes.size
294
- record = find_first_by_auth_conditions(attributes)
296
+ record = find_first_by_auth_conditions(attributes) and return record
295
297
  end
296
298
 
297
- unless record
298
- record = new
299
-
299
+ new(devise_parameter_filter.filter(attributes)).tap do |record|
300
300
  required_attributes.each do |key|
301
- value = attributes[key]
302
- record.send("#{key}=", value)
303
- record.errors.add(key, value.present? ? error : :blank)
301
+ record.errors.add(key, attributes[key].blank? ? :blank : error)
304
302
  end
305
303
  end
306
-
307
- record
308
304
  end
309
305
 
310
306
  protected
@@ -76,7 +76,7 @@ module Devise
76
76
  # Confirm a user by setting it's confirmed_at to actual time. If the user
77
77
  # is already confirmed, add an error to email field. If the user is invalid
78
78
  # add errors
79
- def confirm(args={})
79
+ def confirm(args = {})
80
80
  pending_any_confirmation do
81
81
  if confirmation_period_expired?
82
82
  self.errors.add(:email, :confirmation_period_expired,
@@ -211,7 +211,10 @@ module Devise
211
211
  # confirmation_period_valid? # will always return true
212
212
  #
213
213
  def confirmation_period_valid?
214
- self.class.allow_unconfirmed_access_for.nil? || (confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago)
214
+ return true if self.class.allow_unconfirmed_access_for.nil?
215
+ return false if self.class.allow_unconfirmed_access_for == 0.days
216
+
217
+ confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago
215
218
  end
216
219
 
217
220
  # Checks if the user confirmation happens before the token becomes invalid
@@ -331,7 +334,7 @@ module Devise
331
334
  # confirmation instructions to it. If not, try searching for a user by unconfirmed_email
332
335
  # field. If no user is found, returns a new user with an email not found error.
333
336
  # Options must contain the user email
334
- def send_confirmation_instructions(attributes={})
337
+ def send_confirmation_instructions(attributes = {})
335
338
  confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
336
339
  unless confirmable.try(:persisted?)
337
340
  confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
@@ -345,7 +348,19 @@ module Devise
345
348
  # If the user is already confirmed, create an error for the user
346
349
  # Options must have the confirmation_token
347
350
  def confirm_by_token(confirmation_token)
351
+ # When the `confirmation_token` parameter is blank, if there are any users with a blank
352
+ # `confirmation_token` in the database, the first one would be confirmed here.
353
+ # The error is being manually added here to ensure no users are confirmed by mistake.
354
+ # This was done in the model for convenience, since validation errors are automatically
355
+ # displayed in the view.
356
+ if confirmation_token.blank?
357
+ confirmable = new
358
+ confirmable.errors.add(:confirmation_token, :blank)
359
+ return confirmable
360
+ end
361
+
348
362
  confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
363
+
349
364
  unless confirmable
350
365
  confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
351
366
  confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
@@ -7,9 +7,13 @@ module Devise
7
7
  # Authenticatable Module, responsible for hashing the password and
8
8
  # validating the authenticity of a user while signing in.
9
9
  #
10
+ # This module defines a `password=` method. This method will hash the argument
11
+ # and store it in the `encrypted_password` column, bypassing any pre-existing
12
+ # `password` column if it exists.
13
+ #
10
14
  # == Options
11
15
  #
12
- # DatabaseAuthenticatable adds the following options to devise_for:
16
+ # DatabaseAuthenticatable adds the following options to +devise+:
13
17
  #
14
18
  # * +pepper+: a random string used to provide a more secure hash. Use
15
19
  # `rails secret` to generate new keys.
@@ -35,6 +39,22 @@ module Devise
35
39
  attr_accessor :password_confirmation
36
40
  end
37
41
 
42
+ def initialize(*args, &block)
43
+ @skip_email_changed_notification = false
44
+ @skip_password_change_notification = false
45
+ super
46
+ end
47
+
48
+ # Skips sending the email changed notification after_update
49
+ def skip_email_changed_notification!
50
+ @skip_email_changed_notification = true
51
+ end
52
+
53
+ # Skips sending the password change notification after_update
54
+ def skip_password_change_notification!
55
+ @skip_password_change_notification = true
56
+ end
57
+
38
58
  def self.required_fields(klass)
39
59
  [:encrypted_password] + klass.authentication_keys
40
60
  end
@@ -65,6 +85,15 @@ module Devise
65
85
  # their password). In case the password field is rejected, the confirmation
66
86
  # is also rejected as long as it is also blank.
67
87
  def update_with_password(params, *options)
88
+ if options.present?
89
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
90
+ [Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
91
+ (`options`) is deprecated and it will be removed in the next major version.
92
+ It was added to support a feature deprecated in Rails 4, so you can safely remove it
93
+ from your code.
94
+ DEPRECATION
95
+ end
96
+
68
97
  current_password = params.delete(:current_password)
69
98
 
70
99
  if params[:password].blank?
@@ -98,6 +127,15 @@ module Devise
98
127
  # end
99
128
  #
100
129
  def update_without_password(params, *options)
130
+ if options.present?
131
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
132
+ [Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
133
+ (`options`) is deprecated and it will be removed in the next major version.
134
+ It was added to support a feature deprecated in Rails 4, so you can safely remove it
135
+ from your code.
136
+ DEPRECATION
137
+ end
138
+
101
139
  params.delete(:password)
102
140
  params.delete(:password_confirmation)
103
141
 
@@ -161,7 +199,7 @@ module Devise
161
199
  # Hashes the password using bcrypt. Custom hash functions should override
162
200
  # this method to apply their own algorithm.
163
201
  #
164
- # See https://github.com/plataformatec/devise-encryptable for examples
202
+ # See https://github.com/heartcombo/devise-encryptable for examples
165
203
  # of other hashing engines.
166
204
  def password_digest(password)
167
205
  Devise::Encryptor.digest(self.class, password)
@@ -169,21 +207,21 @@ module Devise
169
207
 
170
208
  if Devise.activerecord51?
171
209
  def send_email_changed_notification?
172
- self.class.send_email_changed_notification && saved_change_to_email?
210
+ self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
173
211
  end
174
212
  else
175
213
  def send_email_changed_notification?
176
- self.class.send_email_changed_notification && email_changed?
214
+ self.class.send_email_changed_notification && email_changed? && !@skip_email_changed_notification
177
215
  end
178
216
  end
179
217
 
180
218
  if Devise.activerecord51?
181
219
  def send_password_change_notification?
182
- self.class.send_password_change_notification && saved_change_to_encrypted_password?
220
+ self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
183
221
  end
184
222
  else
185
223
  def send_password_change_notification?
186
- self.class.send_password_change_notification && encrypted_password_changed?
224
+ self.class.send_password_change_notification && encrypted_password_changed? && !@skip_password_change_notification
187
225
  end
188
226
  end
189
227