devise 3.5.10 → 4.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (258) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +279 -1126
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +291 -97
  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 +25 -12
  12. data/app/helpers/devise_helper.rb +23 -18
  13. data/app/mailers/devise/mailer.rb +10 -4
  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 +8 -8
  23. data/app/views/devise/unlocks/new.html.erb +2 -2
  24. data/config/locales/en.yml +5 -2
  25. data/lib/devise.rb +57 -40
  26. data/lib/devise/controllers/helpers.rb +30 -27
  27. data/lib/devise/controllers/rememberable.rb +3 -1
  28. data/lib/devise/controllers/scoped_views.rb +2 -0
  29. data/lib/devise/controllers/sign_in_out.rb +39 -14
  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 +6 -4
  34. data/lib/devise/failure_app.rb +75 -38
  35. data/lib/devise/hooks/activatable.rb +2 -0
  36. data/lib/devise/hooks/csrf_cleaner.rb +2 -0
  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 +4 -2
  42. data/lib/devise/hooks/trackable.rb +2 -0
  43. data/lib/devise/mailers/helpers.rb +7 -4
  44. data/lib/devise/mapping.rb +3 -1
  45. data/lib/devise/models.rb +3 -1
  46. data/lib/devise/models/authenticatable.rb +63 -33
  47. data/lib/devise/models/confirmable.rb +90 -29
  48. data/lib/devise/models/database_authenticatable.rb +93 -22
  49. data/lib/devise/models/lockable.rb +19 -5
  50. data/lib/devise/models/omniauthable.rb +2 -0
  51. data/lib/devise/models/recoverable.rb +33 -21
  52. data/lib/devise/models/registerable.rb +4 -0
  53. data/lib/devise/models/rememberable.rb +6 -11
  54. data/lib/devise/models/timeoutable.rb +2 -0
  55. data/lib/devise/models/trackable.rb +15 -1
  56. data/lib/devise/models/validatable.rb +10 -3
  57. data/lib/devise/modules.rb +2 -0
  58. data/lib/devise/omniauth.rb +4 -5
  59. data/lib/devise/omniauth/config.rb +2 -0
  60. data/lib/devise/omniauth/url_helpers.rb +14 -5
  61. data/lib/devise/orm/active_record.rb +5 -1
  62. data/lib/devise/orm/mongoid.rb +6 -2
  63. data/lib/devise/parameter_filter.rb +4 -0
  64. data/lib/devise/parameter_sanitizer.rb +139 -65
  65. data/lib/devise/rails.rb +7 -16
  66. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  67. data/lib/devise/rails/routes.rb +48 -37
  68. data/lib/devise/rails/warden_compat.rb +3 -10
  69. data/lib/devise/secret_key_finder.rb +27 -0
  70. data/lib/devise/strategies/authenticatable.rb +3 -1
  71. data/lib/devise/strategies/base.rb +2 -0
  72. data/lib/devise/strategies/database_authenticatable.rb +11 -4
  73. data/lib/devise/strategies/rememberable.rb +2 -0
  74. data/lib/devise/test/controller_helpers.rb +167 -0
  75. data/lib/devise/test/integration_helpers.rb +63 -0
  76. data/lib/devise/test_helpers.rb +7 -124
  77. data/lib/devise/time_inflector.rb +2 -0
  78. data/lib/devise/token_generator.rb +3 -41
  79. data/lib/devise/version.rb +3 -1
  80. data/lib/generators/active_record/devise_generator.rb +46 -12
  81. data/lib/generators/active_record/templates/migration.rb +4 -2
  82. data/lib/generators/active_record/templates/migration_existing.rb +4 -2
  83. data/lib/generators/devise/controllers_generator.rb +3 -1
  84. data/lib/generators/devise/devise_generator.rb +5 -3
  85. data/lib/generators/devise/install_generator.rb +18 -5
  86. data/lib/generators/devise/orm_helpers.rb +10 -21
  87. data/lib/generators/devise/views_generator.rb +8 -9
  88. data/lib/generators/mongoid/devise_generator.rb +7 -5
  89. data/lib/generators/templates/README +9 -8
  90. data/lib/generators/templates/controllers/confirmations_controller.rb +2 -0
  91. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +3 -1
  92. data/lib/generators/templates/controllers/passwords_controller.rb +2 -0
  93. data/lib/generators/templates/controllers/registrations_controller.rb +6 -4
  94. data/lib/generators/templates/controllers/sessions_controller.rb +4 -2
  95. data/lib/generators/templates/controllers/unlocks_controller.rb +2 -0
  96. data/lib/generators/templates/devise.rb +63 -21
  97. data/lib/generators/templates/markerb/email_changed.markerb +7 -0
  98. data/lib/generators/templates/markerb/password_change.markerb +2 -2
  99. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +5 -1
  100. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +10 -2
  101. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +4 -1
  102. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +11 -3
  103. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +11 -3
  104. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +7 -2
  105. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +4 -1
  106. metadata +19 -317
  107. data/.gitignore +0 -10
  108. data/.travis.yml +0 -44
  109. data/.yardopts +0 -9
  110. data/CODE_OF_CONDUCT.md +0 -22
  111. data/CONTRIBUTING.md +0 -16
  112. data/Gemfile +0 -30
  113. data/Gemfile.lock +0 -187
  114. data/Rakefile +0 -36
  115. data/devise.gemspec +0 -27
  116. data/devise.png +0 -0
  117. data/gemfiles/Gemfile.rails-3.2-stable +0 -29
  118. data/gemfiles/Gemfile.rails-3.2-stable.lock +0 -172
  119. data/gemfiles/Gemfile.rails-4.0-stable +0 -30
  120. data/gemfiles/Gemfile.rails-4.0-stable.lock +0 -166
  121. data/gemfiles/Gemfile.rails-4.1-stable +0 -30
  122. data/gemfiles/Gemfile.rails-4.1-stable.lock +0 -171
  123. data/gemfiles/Gemfile.rails-4.2-stable +0 -30
  124. data/gemfiles/Gemfile.rails-4.2-stable.lock +0 -193
  125. data/script/cached-bundle +0 -49
  126. data/script/s3-put +0 -71
  127. data/test/controllers/custom_registrations_controller_test.rb +0 -40
  128. data/test/controllers/custom_strategy_test.rb +0 -62
  129. data/test/controllers/helper_methods_test.rb +0 -21
  130. data/test/controllers/helpers_test.rb +0 -316
  131. data/test/controllers/inherited_controller_i18n_messages_test.rb +0 -51
  132. data/test/controllers/internal_helpers_test.rb +0 -129
  133. data/test/controllers/load_hooks_controller_test.rb +0 -19
  134. data/test/controllers/passwords_controller_test.rb +0 -31
  135. data/test/controllers/sessions_controller_test.rb +0 -103
  136. data/test/controllers/url_helpers_test.rb +0 -65
  137. data/test/delegator_test.rb +0 -19
  138. data/test/devise_test.rb +0 -107
  139. data/test/failure_app_test.rb +0 -315
  140. data/test/generators/active_record_generator_test.rb +0 -109
  141. data/test/generators/controllers_generator_test.rb +0 -48
  142. data/test/generators/devise_generator_test.rb +0 -39
  143. data/test/generators/install_generator_test.rb +0 -13
  144. data/test/generators/mongoid_generator_test.rb +0 -23
  145. data/test/generators/views_generator_test.rb +0 -103
  146. data/test/helpers/devise_helper_test.rb +0 -49
  147. data/test/integration/authenticatable_test.rb +0 -729
  148. data/test/integration/confirmable_test.rb +0 -324
  149. data/test/integration/database_authenticatable_test.rb +0 -95
  150. data/test/integration/http_authenticatable_test.rb +0 -105
  151. data/test/integration/lockable_test.rb +0 -239
  152. data/test/integration/omniauthable_test.rb +0 -135
  153. data/test/integration/recoverable_test.rb +0 -347
  154. data/test/integration/registerable_test.rb +0 -359
  155. data/test/integration/rememberable_test.rb +0 -214
  156. data/test/integration/timeoutable_test.rb +0 -184
  157. data/test/integration/trackable_test.rb +0 -92
  158. data/test/mailers/confirmation_instructions_test.rb +0 -115
  159. data/test/mailers/reset_password_instructions_test.rb +0 -96
  160. data/test/mailers/unlock_instructions_test.rb +0 -91
  161. data/test/mapping_test.rb +0 -134
  162. data/test/models/authenticatable_test.rb +0 -23
  163. data/test/models/confirmable_test.rb +0 -511
  164. data/test/models/database_authenticatable_test.rb +0 -269
  165. data/test/models/lockable_test.rb +0 -350
  166. data/test/models/omniauthable_test.rb +0 -7
  167. data/test/models/recoverable_test.rb +0 -251
  168. data/test/models/registerable_test.rb +0 -7
  169. data/test/models/rememberable_test.rb +0 -169
  170. data/test/models/serializable_test.rb +0 -49
  171. data/test/models/timeoutable_test.rb +0 -51
  172. data/test/models/trackable_test.rb +0 -41
  173. data/test/models/validatable_test.rb +0 -127
  174. data/test/models_test.rb +0 -153
  175. data/test/omniauth/config_test.rb +0 -57
  176. data/test/omniauth/url_helpers_test.rb +0 -54
  177. data/test/orm/active_record.rb +0 -10
  178. data/test/orm/mongoid.rb +0 -13
  179. data/test/parameter_sanitizer_test.rb +0 -81
  180. data/test/rails_app/Rakefile +0 -6
  181. data/test/rails_app/app/active_record/admin.rb +0 -6
  182. data/test/rails_app/app/active_record/shim.rb +0 -2
  183. data/test/rails_app/app/active_record/user.rb +0 -6
  184. data/test/rails_app/app/active_record/user_on_engine.rb +0 -7
  185. data/test/rails_app/app/active_record/user_on_main_app.rb +0 -7
  186. data/test/rails_app/app/active_record/user_without_email.rb +0 -8
  187. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
  188. data/test/rails_app/app/controllers/admins_controller.rb +0 -6
  189. data/test/rails_app/app/controllers/application_controller.rb +0 -12
  190. data/test/rails_app/app/controllers/application_with_fake_engine.rb +0 -30
  191. data/test/rails_app/app/controllers/custom/registrations_controller.rb +0 -31
  192. data/test/rails_app/app/controllers/home_controller.rb +0 -25
  193. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
  194. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
  195. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
  196. data/test/rails_app/app/controllers/users_controller.rb +0 -31
  197. data/test/rails_app/app/helpers/application_helper.rb +0 -3
  198. data/test/rails_app/app/mailers/users/from_proc_mailer.rb +0 -3
  199. data/test/rails_app/app/mailers/users/mailer.rb +0 -3
  200. data/test/rails_app/app/mailers/users/reply_to_mailer.rb +0 -4
  201. data/test/rails_app/app/mongoid/admin.rb +0 -29
  202. data/test/rails_app/app/mongoid/shim.rb +0 -23
  203. data/test/rails_app/app/mongoid/user.rb +0 -39
  204. data/test/rails_app/app/mongoid/user_on_engine.rb +0 -39
  205. data/test/rails_app/app/mongoid/user_on_main_app.rb +0 -39
  206. data/test/rails_app/app/mongoid/user_without_email.rb +0 -33
  207. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  208. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  209. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  210. data/test/rails_app/app/views/home/index.html.erb +0 -1
  211. data/test/rails_app/app/views/home/join.html.erb +0 -1
  212. data/test/rails_app/app/views/home/private.html.erb +0 -1
  213. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  214. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  215. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  216. data/test/rails_app/app/views/users/index.html.erb +0 -1
  217. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  218. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  219. data/test/rails_app/bin/bundle +0 -3
  220. data/test/rails_app/bin/rails +0 -4
  221. data/test/rails_app/bin/rake +0 -4
  222. data/test/rails_app/config.ru +0 -4
  223. data/test/rails_app/config/application.rb +0 -40
  224. data/test/rails_app/config/boot.rb +0 -14
  225. data/test/rails_app/config/database.yml +0 -18
  226. data/test/rails_app/config/environment.rb +0 -5
  227. data/test/rails_app/config/environments/development.rb +0 -30
  228. data/test/rails_app/config/environments/production.rb +0 -84
  229. data/test/rails_app/config/environments/test.rb +0 -41
  230. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  231. data/test/rails_app/config/initializers/devise.rb +0 -180
  232. data/test/rails_app/config/initializers/inflections.rb +0 -2
  233. data/test/rails_app/config/initializers/secret_token.rb +0 -8
  234. data/test/rails_app/config/initializers/session_store.rb +0 -1
  235. data/test/rails_app/config/routes.rb +0 -125
  236. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -71
  237. data/test/rails_app/db/schema.rb +0 -55
  238. data/test/rails_app/lib/shared_admin.rb +0 -17
  239. data/test/rails_app/lib/shared_user.rb +0 -29
  240. data/test/rails_app/lib/shared_user_without_email.rb +0 -26
  241. data/test/rails_app/lib/shared_user_without_omniauth.rb +0 -13
  242. data/test/rails_app/public/404.html +0 -26
  243. data/test/rails_app/public/422.html +0 -26
  244. data/test/rails_app/public/500.html +0 -26
  245. data/test/rails_app/public/favicon.ico +0 -0
  246. data/test/rails_test.rb +0 -9
  247. data/test/routes_test.rb +0 -264
  248. data/test/support/action_controller/record_identifier.rb +0 -10
  249. data/test/support/assertions.rb +0 -39
  250. data/test/support/helpers.rb +0 -77
  251. data/test/support/integration.rb +0 -92
  252. data/test/support/locale/en.yml +0 -8
  253. data/test/support/mongoid.yml +0 -6
  254. data/test/support/webrat/integrations/rails.rb +0 -24
  255. data/test/test_helper.rb +0 -34
  256. data/test/test_helpers_test.rb +0 -178
  257. data/test/test_models.rb +0 -33
  258. data/test/time_helpers.rb +0 -137
@@ -1,24 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/strategies/database_authenticatable'
2
4
 
3
5
  module Devise
4
- def self.bcrypt(klass, password)
5
- ActiveSupport::Deprecation.warn "Devise.bcrypt is deprecated; use Devise::Encryptor.digest instead"
6
- Devise::Encryptor.digest(klass, password)
7
- end
8
-
9
6
  module Models
10
- # Authenticatable Module, responsible for encrypting password and validating
11
- # authenticity of a user while signing in.
7
+ # Authenticatable Module, responsible for hashing the password and
8
+ # validating the authenticity of a user while signing in.
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.
12
13
  #
13
14
  # == Options
14
15
  #
15
16
  # DatabaseAuthenticatable adds the following options to devise_for:
16
17
  #
17
18
  # * +pepper+: a random string used to provide a more secure hash. Use
18
- # `rake secret` to generate new keys.
19
+ # `rails secret` to generate new keys.
19
20
  #
20
21
  # * +stretches+: the cost given to bcrypt.
21
22
  #
23
+ # * +send_email_changed_notification+: notify original email when it changes.
24
+ #
25
+ # * +send_password_change_notification+: notify email when password changes.
26
+ #
22
27
  # == Examples
23
28
  #
24
29
  # User.find(1).valid_password?('password123') # returns true/false
@@ -27,17 +32,36 @@ module Devise
27
32
  extend ActiveSupport::Concern
28
33
 
29
34
  included do
35
+ after_update :send_email_changed_notification, if: :send_email_changed_notification?
30
36
  after_update :send_password_change_notification, if: :send_password_change_notification?
31
37
 
32
38
  attr_reader :password, :current_password
33
39
  attr_accessor :password_confirmation
34
40
  end
35
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
+
36
58
  def self.required_fields(klass)
37
59
  [:encrypted_password] + klass.authentication_keys
38
60
  end
39
61
 
40
- # Generates password encryption based on the given value.
62
+ # Generates a hashed password based on the given value.
63
+ # For legacy reasons, we use `encrypted_password` to store
64
+ # the hashed password.
41
65
  def password=(new_password)
42
66
  @password = new_password
43
67
  self.encrypted_password = password_digest(@password) if @password.present?
@@ -61,6 +85,15 @@ module Devise
61
85
  # their password). In case the password field is rejected, the confirmation
62
86
  # is also rejected as long as it is also blank.
63
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
+
64
97
  current_password = params.delete(:current_password)
65
98
 
66
99
  if params[:password].blank?
@@ -69,11 +102,11 @@ module Devise
69
102
  end
70
103
 
71
104
  result = if valid_password?(current_password)
72
- update_attributes(params, *options)
105
+ update(params, *options)
73
106
  else
74
- self.assign_attributes(params, *options)
75
- self.valid?
76
- self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
107
+ assign_attributes(params, *options)
108
+ valid?
109
+ errors.add(:current_password, current_password.blank? ? :blank : :invalid)
77
110
  false
78
111
  end
79
112
 
@@ -94,10 +127,19 @@ module Devise
94
127
  # end
95
128
  #
96
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
+
97
139
  params.delete(:password)
98
140
  params.delete(:password_confirmation)
99
141
 
100
- result = update_attributes(params, *options)
142
+ result = update(params, *options)
101
143
  clean_up_passwords
102
144
  result
103
145
  end
@@ -109,8 +151,8 @@ module Devise
109
151
  result = if valid_password?(current_password)
110
152
  destroy
111
153
  else
112
- self.valid?
113
- self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
154
+ valid?
155
+ errors.add(:current_password, current_password.blank? ? :blank : :invalid)
114
156
  false
115
157
  end
116
158
 
@@ -135,27 +177,56 @@ module Devise
135
177
  encrypted_password[0,29] if encrypted_password
136
178
  end
137
179
 
180
+ if Devise.activerecord51?
181
+ # Send notification to user when email changes.
182
+ def send_email_changed_notification
183
+ send_devise_notification(:email_changed, to: email_before_last_save)
184
+ end
185
+ else
186
+ # Send notification to user when email changes.
187
+ def send_email_changed_notification
188
+ send_devise_notification(:email_changed, to: email_was)
189
+ end
190
+ end
191
+
192
+ # Send notification to user when password changes.
138
193
  def send_password_change_notification
139
194
  send_devise_notification(:password_change)
140
195
  end
141
196
 
142
197
  protected
143
198
 
144
- # Digests the password using bcrypt. Custom encryption should override
199
+ # Hashes the password using bcrypt. Custom hash functions should override
145
200
  # this method to apply their own algorithm.
146
201
  #
147
- # See https://github.com/plataformatec/devise-encryptable for examples
148
- # of other encryption engines.
202
+ # See https://github.com/heartcombo/devise-encryptable for examples
203
+ # of other hashing engines.
149
204
  def password_digest(password)
150
205
  Devise::Encryptor.digest(self.class, password)
151
206
  end
152
207
 
153
- def send_password_change_notification?
154
- self.class.send_password_change_notification && encrypted_password_changed?
208
+ if Devise.activerecord51?
209
+ def send_email_changed_notification?
210
+ self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
211
+ end
212
+ else
213
+ def send_email_changed_notification?
214
+ self.class.send_email_changed_notification && email_changed? && !@skip_email_changed_notification
215
+ end
216
+ end
217
+
218
+ if Devise.activerecord51?
219
+ def send_password_change_notification?
220
+ self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
221
+ end
222
+ else
223
+ def send_password_change_notification?
224
+ self.class.send_password_change_notification && encrypted_password_changed? && !@skip_password_change_notification
225
+ end
155
226
  end
156
227
 
157
228
  module ClassMethods
158
- Devise::Models.config(self, :pepper, :stretches, :send_password_change_notification)
229
+ Devise::Models.config(self, :pepper, :stretches, :send_email_changed_notification, :send_password_change_notification)
159
230
 
160
231
  # We assume this method already gets the sanitized values from the
161
232
  # DatabaseAuthenticatable strategy. If you are using this method on
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "devise/hooks/lockable"
2
4
 
3
5
  module Devise
@@ -7,7 +9,7 @@ module Devise
7
9
  # blocked: email and time. The former will send an email to the user when
8
10
  # the lock happens, containing a link to unlock its account. The second
9
11
  # will unlock the user automatically after some configured time (ie 2.hours).
10
- # It's also possible to setup lockable to use both email and time strategies.
12
+ # It's also possible to set up lockable to use both email and time strategies.
11
13
  #
12
14
  # == Options
13
15
  #
@@ -55,6 +57,14 @@ module Devise
55
57
  save(validate: false)
56
58
  end
57
59
 
60
+ # Resets failed attempts counter to 0.
61
+ def reset_failed_attempts!
62
+ if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
63
+ self.failed_attempts = 0
64
+ save(validate: false)
65
+ end
66
+ end
67
+
58
68
  # Verifies whether a user is locked or not.
59
69
  def access_locked?
60
70
  !!locked_at && !lock_expired?
@@ -64,7 +74,7 @@ module Devise
64
74
  def send_unlock_instructions
65
75
  raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
66
76
  self.unlock_token = enc
67
- self.save(validate: false)
77
+ save(validate: false)
68
78
  send_devise_notification(:unlock_instructions, raw, {})
69
79
  raw
70
80
  end
@@ -99,8 +109,7 @@ module Devise
99
109
  if super && !access_locked?
100
110
  true
101
111
  else
102
- self.failed_attempts ||= 0
103
- self.failed_attempts += 1
112
+ increment_failed_attempts
104
113
  if attempts_exceeded?
105
114
  lock_access! unless access_locked?
106
115
  else
@@ -110,6 +119,11 @@ module Devise
110
119
  end
111
120
  end
112
121
 
122
+ def increment_failed_attempts
123
+ self.class.increment_counter(:failed_attempts, id)
124
+ reload
125
+ end
126
+
113
127
  def unauthenticated_message
114
128
  # If set to paranoid mode, do not show the locked message because it
115
129
  # leaks the existence of an account.
@@ -162,7 +176,7 @@ module Devise
162
176
  # unlock instructions to it. If not user is found, returns a new user
163
177
  # with an email not found error.
164
178
  # Options must contain the user's unlock keys
165
- def send_unlock_instructions(attributes={})
179
+ def send_unlock_instructions(attributes = {})
166
180
  lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
167
181
  lockable.resend_unlock_instructions if lockable.persisted?
168
182
  lockable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/omniauth'
2
4
 
3
5
  module Devise
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Models
3
5
 
@@ -27,30 +29,20 @@ module Devise
27
29
  end
28
30
 
29
31
  included do
30
- before_update do
31
- if (respond_to?(:email_changed?) && email_changed?) || encrypted_password_changed?
32
- clear_reset_password_token
33
- end
34
- end
32
+ before_update :clear_reset_password_token, if: :clear_reset_password_token?
35
33
  end
36
34
 
37
35
  # Update password saving the record and clearing token. Returns true if
38
36
  # the passwords are valid and the record was saved, false otherwise.
39
37
  def reset_password(new_password, new_password_confirmation)
40
- self.password = new_password
41
- self.password_confirmation = new_password_confirmation
42
-
43
- if respond_to?(:after_password_reset) && valid?
44
- ActiveSupport::Deprecation.warn "after_password_reset is deprecated"
45
- after_password_reset
38
+ if new_password.present?
39
+ self.password = new_password
40
+ self.password_confirmation = new_password_confirmation
41
+ save
42
+ else
43
+ errors.add(:password, :blank)
44
+ false
46
45
  end
47
-
48
- save
49
- end
50
-
51
- def reset_password!(new_password, new_password_confirmation)
52
- ActiveSupport::Deprecation.warn "reset_password! is deprecated in favor of reset_password"
53
- reset_password(new_password, new_password_confirmation)
54
46
  end
55
47
 
56
48
  # Resets reset password token and send reset password instructions by email.
@@ -99,7 +91,7 @@ module Devise
99
91
 
100
92
  self.reset_password_token = enc
101
93
  self.reset_password_sent_at = Time.now.utc
102
- self.save(validate: false)
94
+ save(validate: false)
103
95
  raw
104
96
  end
105
97
 
@@ -107,6 +99,26 @@ module Devise
107
99
  send_devise_notification(:reset_password_instructions, token, {})
108
100
  end
109
101
 
102
+ if Devise.activerecord51?
103
+ def clear_reset_password_token?
104
+ encrypted_password_changed = respond_to?(:will_save_change_to_encrypted_password?) && will_save_change_to_encrypted_password?
105
+ authentication_keys_changed = self.class.authentication_keys.any? do |attribute|
106
+ respond_to?("will_save_change_to_#{attribute}?") && send("will_save_change_to_#{attribute}?")
107
+ end
108
+
109
+ authentication_keys_changed || encrypted_password_changed
110
+ end
111
+ else
112
+ def clear_reset_password_token?
113
+ encrypted_password_changed = respond_to?(:encrypted_password_changed?) && encrypted_password_changed?
114
+ authentication_keys_changed = self.class.authentication_keys.any? do |attribute|
115
+ respond_to?("#{attribute}_changed?") && send("#{attribute}_changed?")
116
+ end
117
+
118
+ authentication_keys_changed || encrypted_password_changed
119
+ end
120
+ end
121
+
110
122
  module ClassMethods
111
123
  # Attempt to find a user by password reset token. If a user is found, return it
112
124
  # If a user is not found, return nil
@@ -119,7 +131,7 @@ module Devise
119
131
  # password instructions to it. If user is not found, returns a new user
120
132
  # with an email not found error.
121
133
  # Attributes must contain the user's email
122
- def send_reset_password_instructions(attributes={})
134
+ def send_reset_password_instructions(attributes = {})
123
135
  recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
124
136
  recoverable.send_reset_password_instructions if recoverable.persisted?
125
137
  recoverable
@@ -130,7 +142,7 @@ module Devise
130
142
  # try saving the record. If not user is found, returns a new user
131
143
  # containing an error in reset_password_token attribute.
132
144
  # Attributes must contain reset_password_token, password and confirmation
133
- def reset_password_by_token(attributes={})
145
+ def reset_password_by_token(attributes = {})
134
146
  original_token = attributes[:reset_password_token]
135
147
  reset_password_token = Devise.token_generator.digest(self, :reset_password_token, original_token)
136
148
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Models
3
5
  # Registerable is responsible for everything related to registering a new
@@ -19,6 +21,8 @@ module Devise
19
21
  def new_with_session(params, session)
20
22
  new(params)
21
23
  end
24
+
25
+ Devise::Models.config(self, :sign_in_after_change_password)
22
26
  end
23
27
  end
24
28
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/strategies/rememberable'
2
4
  require 'devise/hooks/rememberable'
3
5
  require 'devise/hooks/forgetable'
4
6
 
5
7
  module Devise
6
8
  module Models
7
- # Rememberable manages generating and clearing token for remember the user
9
+ # Rememberable manages generating and clearing token for remembering the user
8
10
  # from a saved cookie. Rememberable also has utility methods for dealing
9
11
  # with serializing the user into the cookie and back from the cookie, trying
10
12
  # to lookup the record based on the saved information.
@@ -45,9 +47,7 @@ module Devise
45
47
  [:remember_created_at]
46
48
  end
47
49
 
48
- # TODO: We were used to receive a extend period argument but we no longer do.
49
- # Remove this for Devise 4.0.
50
- def remember_me!(*)
50
+ def remember_me!
51
51
  self.remember_token ||= self.class.remember_token if respond_to?(:remember_token)
52
52
  self.remember_created_at ||= Time.now.utc
53
53
  save(validate: false) if self.changed?
@@ -62,11 +62,6 @@ module Devise
62
62
  save(validate: false)
63
63
  end
64
64
 
65
- # Remember token should be expired if expiration time not overpass now.
66
- def remember_expired?
67
- remember_created_at.nil?
68
- end
69
-
70
65
  def remember_expires_at
71
66
  self.class.remember_for.from_now
72
67
  end
@@ -81,7 +76,7 @@ module Devise
81
76
  elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt.presence)
82
77
  salt
83
78
  else
84
- raise "authenticable_salt returned nil for the #{self.class.name} model. " \
79
+ raise "authenticatable_salt returned nil for the #{self.class.name} model. " \
85
80
  "In order to use rememberable, you must ensure a password is always set " \
86
81
  "or have a remember_token column in your model or implement your own " \
87
82
  "rememberable_value in the model with custom logic."
@@ -107,7 +102,7 @@ module Devise
107
102
 
108
103
  def remember_me?(token, generated_at)
109
104
  # TODO: Normalize the JSON type coercion along with the Timeoutable hook
110
- # in a single place https://github.com/plataformatec/devise/blob/ffe9d6d406e79108cf32a2c6a1d0b3828849c40b/lib/devise/hooks/timeoutable.rb#L14-L18
105
+ # in a single place https://github.com/heartcombo/devise/blob/ffe9d6d406e79108cf32a2c6a1d0b3828849c40b/lib/devise/hooks/timeoutable.rb#L14-L18
111
106
  if generated_at.is_a?(String)
112
107
  generated_at = time_from_json(generated_at)
113
108
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/hooks/timeoutable'
2
4
 
3
5
  module Devise
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'devise/hooks/trackable'
2
4
 
3
5
  module Devise
@@ -20,7 +22,7 @@ module Devise
20
22
  self.last_sign_in_at = old_current || new_current
21
23
  self.current_sign_in_at = new_current
22
24
 
23
- old_current, new_current = self.current_sign_in_ip, request.remote_ip
25
+ old_current, new_current = self.current_sign_in_ip, extract_ip_from(request)
24
26
  self.last_sign_in_ip = old_current || new_current
25
27
  self.current_sign_in_ip = new_current
26
28
 
@@ -29,9 +31,21 @@ module Devise
29
31
  end
30
32
 
31
33
  def update_tracked_fields!(request)
34
+ # We have to check if the user is already persisted before running
35
+ # `save` here because invalid users can be saved if we don't.
36
+ # See https://github.com/heartcombo/devise/issues/4673 for more details.
37
+ return if new_record?
38
+
32
39
  update_tracked_fields(request)
33
40
  save(validate: false)
34
41
  end
42
+
43
+ protected
44
+
45
+ def extract_ip_from(request)
46
+ request.remote_ip
47
+ end
48
+
35
49
  end
36
50
  end
37
51
  end