devise-security 0.16.0 → 0.17.0

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/app/controllers/devise/paranoid_verification_code_controller.rb +13 -1
  4. data/app/controllers/devise/password_expired_controller.rb +14 -1
  5. data/config/locales/bg.yml +41 -0
  6. data/config/locales/de.yml +2 -0
  7. data/config/locales/en.yml +2 -1
  8. data/lib/devise-security/models/database_authenticatable_patch.rb +15 -5
  9. data/lib/devise-security/models/password_archivable.rb +2 -2
  10. data/lib/devise-security/models/secure_validatable.rb +51 -15
  11. data/lib/devise-security/validators/password_complexity_validator.rb +53 -26
  12. data/lib/devise-security/version.rb +1 -1
  13. data/lib/devise-security.rb +7 -2
  14. data/lib/generators/templates/devise_security.rb +3 -1
  15. data/test/controllers/test_paranoid_verification_code_controller.rb +68 -0
  16. data/test/controllers/test_password_expired_controller.rb +38 -0
  17. data/test/dummy/app/controllers/overrides/paranoid_verification_code_controller.rb +7 -0
  18. data/test/dummy/app/controllers/overrides/password_expired_controller.rb +7 -0
  19. data/test/dummy/app/controllers/widgets_controller.rb +3 -0
  20. data/test/dummy/app/models/application_user_record.rb +2 -1
  21. data/test/dummy/app/models/mongoid/confirmable_fields.rb +2 -0
  22. data/test/dummy/app/models/mongoid/database_authenticable_fields.rb +4 -3
  23. data/test/dummy/app/models/mongoid/expirable_fields.rb +2 -0
  24. data/test/dummy/app/models/mongoid/lockable_fields.rb +2 -0
  25. data/test/dummy/app/models/mongoid/mappings.rb +4 -2
  26. data/test/dummy/app/models/mongoid/omniauthable_fields.rb +2 -0
  27. data/test/dummy/app/models/mongoid/paranoid_verification_fields.rb +2 -0
  28. data/test/dummy/app/models/mongoid/password_archivable_fields.rb +2 -0
  29. data/test/dummy/app/models/mongoid/password_expirable_fields.rb +2 -0
  30. data/test/dummy/app/models/mongoid/recoverable_fields.rb +2 -0
  31. data/test/dummy/app/models/mongoid/registerable_fields.rb +4 -2
  32. data/test/dummy/app/models/mongoid/rememberable_fields.rb +2 -0
  33. data/test/dummy/app/models/mongoid/secure_validatable_fields.rb +2 -0
  34. data/test/dummy/app/models/mongoid/security_questionable_fields.rb +2 -0
  35. data/test/dummy/app/models/mongoid/session_limitable_fields.rb +2 -0
  36. data/test/dummy/app/models/mongoid/timeoutable_fields.rb +2 -0
  37. data/test/dummy/app/models/mongoid/trackable_fields.rb +2 -0
  38. data/test/dummy/app/models/mongoid/validatable_fields.rb +2 -0
  39. data/test/dummy/app/models/paranoid_verification_user.rb +26 -0
  40. data/test/dummy/app/models/password_expired_user.rb +26 -0
  41. data/test/dummy/app/models/user.rb +1 -2
  42. data/test/dummy/app/models/widget.rb +1 -3
  43. data/test/dummy/app/mongoid/one_user.rb +5 -5
  44. data/test/dummy/app/mongoid/user_on_engine.rb +2 -2
  45. data/test/dummy/app/mongoid/user_on_main_app.rb +2 -2
  46. data/test/dummy/app/mongoid/user_with_validations.rb +3 -3
  47. data/test/dummy/app/mongoid/user_without_email.rb +3 -3
  48. data/test/dummy/config/application.rb +4 -4
  49. data/test/dummy/config/boot.rb +1 -1
  50. data/test/dummy/config/environment.rb +1 -1
  51. data/test/dummy/config/locales/en.yml +10 -0
  52. data/test/dummy/config/routes.rb +2 -0
  53. data/test/dummy/db/migrate/20120508165529_create_tables.rb +3 -3
  54. data/test/dummy/lib/shared_expirable_columns.rb +1 -0
  55. data/test/dummy/lib/shared_security_questions_fields.rb +1 -0
  56. data/test/dummy/lib/shared_user.rb +17 -6
  57. data/test/dummy/lib/shared_user_without_email.rb +2 -1
  58. data/test/dummy/lib/shared_user_without_omniauth.rb +12 -3
  59. data/test/dummy/lib/shared_verification_fields.rb +1 -0
  60. data/test/dummy/log/development.log +0 -883
  61. data/test/dummy/log/test.log +95414 -15570
  62. data/test/integration/test_session_limitable_workflow.rb +2 -0
  63. data/test/orm/active_record.rb +7 -7
  64. data/test/test_compatibility.rb +2 -0
  65. data/test/test_complexity_validator.rb +246 -37
  66. data/test/test_database_authenticatable_patch.rb +146 -0
  67. data/test/test_helper.rb +7 -8
  68. data/test/test_install_generator.rb +1 -1
  69. data/test/test_paranoid_verification.rb +0 -1
  70. data/test/test_password_archivable.rb +34 -11
  71. data/test/test_password_expirable.rb +26 -26
  72. data/test/test_secure_validatable.rb +273 -107
  73. data/test/test_secure_validatable_overrides.rb +185 -0
  74. data/test/test_session_limitable.rb +2 -2
  75. data/test/tmp/config/initializers/{devise-security.rb → devise_security.rb} +3 -1
  76. data/test/tmp/config/locales/devise.security_extension.de.yml +2 -0
  77. data/test/tmp/config/locales/devise.security_extension.en.yml +2 -1
  78. data/test/tmp/config/locales/devise.security_extension.hi.yml +20 -20
  79. metadata +42 -19
  80. data/test/dummy/app/models/secure_user.rb +0 -9
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class TestSessionLimitableWorkflow < ActionDispatch::IntegrationTest
@@ -1,14 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_record'
2
4
 
3
5
  ActiveRecord::Migration.verbose = false
4
6
  ActiveRecord::Base.logger = Logger.new(nil)
5
- case
6
- when Rails.gem_version >= Gem::Version.new('6.0.0')
7
- ActiveRecord::MigrationContext.new(File.expand_path('../../dummy/db/migrate', __FILE__), ActiveRecord::SchemaMigration).migrate
8
- when Rails.gem_version >= Gem::Version.new('5.2.0')
9
- ActiveRecord::MigrationContext.new(File.expand_path('../../dummy/db/migrate', __FILE__)).migrate
10
- else
11
- ActiveRecord::Migrator.migrate(File.expand_path('../../dummy/db/migrate', __FILE__))
7
+
8
+ if Rails.gem_version >= Gem::Version.new('6.0.0')
9
+ ActiveRecord::MigrationContext.new(File.expand_path('../dummy/db/migrate', __dir__), ActiveRecord::SchemaMigration).migrate
10
+ elsif Rails.gem_version >= Gem::Version.new('5.2.0')
11
+ ActiveRecord::MigrationContext.new(File.expand_path('../dummy/db/migrate', __dir__)).migrate
12
12
  end
13
13
 
14
14
  DatabaseCleaner[:active_record].strategy = :transaction
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class TestCompatibility < ActiveSupport::TestCase
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
- class PasswordComplexityValidatorTest < Minitest::Test
5
+ class PasswordComplexityValidatorTest < ActiveSupport::TestCase
4
6
  class ModelWithPassword
5
7
  include ActiveModel::Validations
6
8
 
@@ -15,58 +17,265 @@ class PasswordComplexityValidatorTest < Minitest::Test
15
17
  ModelWithPassword.clear_validators!
16
18
  end
17
19
 
20
+ def create_model(password, opts = {})
21
+ ModelWithPassword.validates(
22
+ :password, 'devise_security/password_complexity': opts
23
+ )
24
+ ModelWithPassword.new(password)
25
+ end
26
+
18
27
  def test_with_no_rules_anything_goes
19
- assert(ModelWithPassword.new('aaaa').valid?)
28
+ assert(create_model('aaaa').valid?)
29
+ end
30
+
31
+ def test_allows_blank
32
+ assert(create_model('', { upper: 1 }).valid?)
33
+ end
34
+
35
+ def test_enforces_uppercase_invalid
36
+ model = create_model('aaaa', { upper: 1 })
37
+
38
+ assert_not(model.valid?)
39
+ assert_equal(
40
+ model.errors.messages,
41
+ { password: ["must contain at least one upper-case letter"] }
42
+ )
43
+ end
44
+
45
+ def test_enforces_uppercase_valid
46
+ assert(create_model('Aaaa', { upper: 1 }).valid?)
47
+ end
48
+
49
+ def test_enforces_uppercase_count_invalid
50
+ model = create_model('Aaaa', { upper: 2 })
51
+
52
+ assert_not(model.valid?)
53
+ assert_equal(
54
+ model.errors.messages,
55
+ { password: ["must contain at least 2 upper-case letters"] }
56
+ )
57
+ end
58
+
59
+ def test_enforces_uppercase_count_valid
60
+ assert(create_model('AAaa', { upper: 2 }).valid?)
61
+ end
62
+
63
+ def test_enforces_digit_invalid
64
+ model = create_model('aaaa', { digit: 1 })
65
+
66
+ assert_not(model.valid?)
67
+ assert_equal(
68
+ model.errors.messages, { password: ["must contain at least one digit"] }
69
+ )
20
70
  end
21
71
 
22
- def test_enforces_uppercase
23
- ModelWithPassword.validates :password, 'devise_security/password_complexity': { upper: 1 }
24
- refute(ModelWithPassword.new('aaaa').valid?)
25
- assert(ModelWithPassword.new('Aaaa').valid?)
72
+ def test_enforces_digit_valid
73
+ assert(create_model('1aaa', { digit: 1 }).valid?)
26
74
  end
27
75
 
28
- def test_enforces_count
29
- ModelWithPassword.validates :password, 'devise_security/password_complexity': { upper: 2 }
30
- refute(ModelWithPassword.new('Aaaa').valid?)
31
- assert(ModelWithPassword.new('AAaa').valid?)
76
+ def test_enforces_digit_count_invalid
77
+ model = create_model('1aaa', { digit: 2 })
78
+
79
+ assert_not(model.valid?)
80
+ assert_equal(
81
+ model.errors.messages, { password: ["must contain at least 2 digits"] }
82
+ )
32
83
  end
33
84
 
34
- def test_enforces_digit
35
- ModelWithPassword.validates :password, 'devise_security/password_complexity': { digit: 1 }
36
- refute(ModelWithPassword.new('aaaa').valid?)
37
- assert(ModelWithPassword.new('aaa1').valid?)
85
+ def test_enforces_digit_count_valid
86
+ assert(create_model('11aa', { digit: 2 }).valid?)
38
87
  end
39
88
 
40
- def test_enforces_digits
41
- ModelWithPassword.validates :password, 'devise_security/password_complexity': { digits: 2 }
42
- refute(ModelWithPassword.new('aaa1').valid?)
43
- assert(ModelWithPassword.new('aa12').valid?)
89
+ def test_enforces_digits_invalid
90
+ model = create_model('aaaa', { digits: 1 })
91
+
92
+ assert_not(model.valid?)
93
+ assert_equal(
94
+ model.errors.messages, { password: ["must contain at least one digit"] }
95
+ )
44
96
  end
45
97
 
46
- def test_enforces_lower
47
- ModelWithPassword.validates :password, 'devise_security/password_complexity': { lower: 1 }
48
- refute(ModelWithPassword.new('AAAA').valid?)
49
- assert(ModelWithPassword.new('AAAa').valid?)
98
+ def test_enforces_digits_valid
99
+ assert(create_model('1aaa', { digits: 1 }).valid?)
50
100
  end
51
101
 
52
- def test_enforces_symbol
53
- ModelWithPassword.validates :password, 'devise_security/password_complexity': { symbol: 1 }
54
- refute(ModelWithPassword.new('aaaa').valid?)
55
- assert(ModelWithPassword.new('aaa!').valid?)
102
+ def test_enforces_digits_count_invalid
103
+ model = create_model('1aaa', { digits: 2 })
104
+
105
+ assert_not(model.valid?)
106
+ assert_equal(
107
+ model.errors.messages, { password: ["must contain at least 2 digits"] }
108
+ )
109
+ end
110
+
111
+ def test_enforces_digits_count_valid
112
+ assert(create_model('11aa', { digits: 2 }).valid?)
113
+ end
114
+
115
+ def test_enforces_lower_invalid
116
+ model = create_model('AAAA', { lower: 1 })
117
+
118
+ assert_not(model.valid?)
119
+ assert_equal(
120
+ model.errors.messages,
121
+ { password: ["must contain at least one lower-case letter"] }
122
+ )
56
123
  end
57
124
 
58
- def test_enforces_symbols
59
- ModelWithPassword.validates :password, 'devise_security/password_complexity': { symbols: 2 }
60
- refute(ModelWithPassword.new('aaa!').valid?)
61
- assert(ModelWithPassword.new('aa!?').valid?)
125
+ def test_enforces_lower_valid
126
+ assert(create_model('aAAA', { lower: 1 }).valid?)
127
+ end
128
+
129
+ def test_enforces_lower_count_invalid
130
+ model = create_model('aAAA', { lower: 2 })
131
+
132
+ assert_not(model.valid?)
133
+ assert_equal(
134
+ model.errors.messages,
135
+ { password: ["must contain at least 2 lower-case letters"] }
136
+ )
137
+ end
138
+
139
+ def test_enforces_lower_count_valid
140
+ assert(create_model('aaAA', { lower: 2 }).valid?)
141
+ end
142
+
143
+ def test_enforces_symbol_invalid
144
+ model = create_model('aaaa', { symbol: 1 })
145
+
146
+ assert_not(model.valid?)
147
+ assert_equal(
148
+ model.errors.messages,
149
+ { password: ["must contain at least one punctuation mark or symbol"] }
150
+ )
62
151
  end
63
152
 
64
- def test_enforces_combination
65
- ModelWithPassword.validates :password, 'devise_security/password_complexity': { lower: 1, upper: 1, digit: 1, symbol: 1 }
66
- refute(ModelWithPassword.new('abcd').valid?)
67
- refute(ModelWithPassword.new('ABCD').valid?)
68
- refute(ModelWithPassword.new('1234').valid?)
69
- refute(ModelWithPassword.new('$!,*').valid?)
70
- assert(ModelWithPassword.new('aB3*').valid?)
153
+ def test_enforces_symbol_valid
154
+ assert(create_model('!aaa', { symbol: 1 }).valid?)
155
+ end
156
+
157
+ def test_enforces_symbol_count_invalid
158
+ model = create_model('!aaa', { symbol: 2 })
159
+
160
+ assert_not(model.valid?)
161
+ assert_equal(
162
+ model.errors.messages,
163
+ { password: ["must contain at least 2 punctuation marks or symbols"] }
164
+ )
165
+ end
166
+
167
+ def test_enforces_symbol_count_valid
168
+ assert(create_model('!!aa', { symbol: 2 }).valid?)
169
+ end
170
+
171
+ def test_enforces_symbols_invalid
172
+ model = create_model('aaaa', { symbols: 1 })
173
+
174
+ assert_not(model.valid?)
175
+ assert_equal(
176
+ model.errors.messages,
177
+ { password: ["must contain at least one punctuation mark or symbol"] }
178
+ )
179
+ end
180
+
181
+ def test_enforces_symbols_valid
182
+ assert(create_model('!aaa', { symbols: 1 }).valid?)
183
+ end
184
+
185
+ def test_enforces_symbols_count_invalid
186
+ model = create_model('!aaa', { symbols: 2 })
187
+
188
+ assert_not(model.valid?)
189
+ assert_equal(
190
+ model.errors.messages,
191
+ { password: ["must contain at least 2 punctuation marks or symbols"] }
192
+ )
193
+ end
194
+
195
+ def test_enforces_symbols_count_valid
196
+ assert(create_model('!!aa', { symbols: 2 }).valid?)
197
+ end
198
+
199
+ def test_enforces_combination_only_lower_invalid
200
+ model = create_model('aaaa', { lower: 1, upper: 1, digit: 1, symbol: 1 })
201
+
202
+ assert_not(model.valid?)
203
+ assert_equal(
204
+ model.errors.messages,
205
+ {
206
+ password:
207
+ [
208
+ "must contain at least one digit",
209
+ "must contain at least one punctuation mark or symbol",
210
+ "must contain at least one upper-case letter"
211
+ ]
212
+ }
213
+ )
214
+ end
215
+
216
+ def test_enforces_combination_only_upper_invalid
217
+ model = create_model('AAAA', { lower: 1, upper: 1, digit: 1, symbol: 1 })
218
+
219
+ assert_not(model.valid?)
220
+ assert_equal(
221
+ model.errors.messages,
222
+ {
223
+ password:
224
+ [
225
+ "must contain at least one digit",
226
+ "must contain at least one lower-case letter",
227
+ "must contain at least one punctuation mark or symbol"
228
+ ]
229
+ }
230
+ )
231
+ end
232
+
233
+ def test_enforces_combination_only_digit_invalid
234
+ model = create_model('1111', { lower: 1, upper: 1, digit: 1, symbol: 1 })
235
+
236
+ assert_not(model.valid?)
237
+ assert_equal(
238
+ model.errors.messages,
239
+ {
240
+ password:
241
+ [
242
+ "must contain at least one lower-case letter",
243
+ "must contain at least one punctuation mark or symbol",
244
+ "must contain at least one upper-case letter"
245
+ ]
246
+ }
247
+ )
248
+ end
249
+
250
+ def test_enforces_combination_only_symbol_invalid
251
+ model = create_model('!!!!', { lower: 1, upper: 1, digit: 1, symbol: 1 })
252
+
253
+ assert_not(model.valid?)
254
+ assert_equal(
255
+ model.errors.messages,
256
+ {
257
+ password:
258
+ [
259
+ "must contain at least one digit",
260
+ "must contain at least one lower-case letter",
261
+ "must contain at least one upper-case letter"
262
+ ]
263
+ }
264
+ )
265
+ end
266
+
267
+ def test_enforces_combination_some_but_not_all_invalid
268
+ model = create_model('aAa!', { lower: 1, upper: 1, digit: 1, symbol: 1 })
269
+
270
+ assert_not(model.valid?)
271
+ assert_equal(
272
+ model.errors.messages, { password: ["must contain at least one digit"] }
273
+ )
274
+ end
275
+
276
+ def test_enforces_combination_all_valid
277
+ model = create_model('aA1!', { lower: 1, upper: 1, digit: 1, symbol: 1 })
278
+
279
+ assert(model.valid?)
71
280
  end
72
281
  end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestDatabaseAuthenticatablePatch < ActiveSupport::TestCase
6
+ def create_user
7
+ User.create(
8
+ email: 'bob@microsoft.com',
9
+ password: 'Password1!',
10
+ password_confirmation: 'Password1!'
11
+ ) do |user|
12
+ user.extend(Devise::Models::DatabaseAuthenticatablePatch)
13
+ end
14
+ end
15
+
16
+ test 'updates if all params are present and valid' do
17
+ user = create_user
18
+
19
+ assert(
20
+ user.update_with_password(
21
+ {
22
+ current_password: 'Password1!',
23
+ password: 'Password2!',
24
+ password_confirmation: 'Password2!'
25
+ }
26
+ )
27
+ )
28
+ end
29
+
30
+ test 'does not update if current_password is missing' do
31
+ user = create_user
32
+
33
+ user.update_with_password(
34
+ {
35
+ password: 'Password2!',
36
+ password_confirmation: 'Password2!'
37
+ }
38
+ )
39
+
40
+ assert_equal(["Current password can't be blank"], user.errors.full_messages)
41
+ end
42
+
43
+ test 'does not update if current_password is incorrect' do
44
+ user = create_user
45
+
46
+ user.update_with_password(
47
+ {
48
+ current_password: 'Password2!',
49
+ password: 'Password2!',
50
+ password_confirmation: 'Password2!'
51
+ }
52
+ )
53
+
54
+ assert_equal(["Current password is invalid"], user.errors.full_messages)
55
+ end
56
+
57
+ test 'does not update if password is missing' do
58
+ user = create_user
59
+
60
+ user.update_with_password(
61
+ {
62
+ current_password: 'Password1!',
63
+ password: '',
64
+ password_confirmation: 'Password2!'
65
+ }
66
+ )
67
+
68
+ assert_equal(["Password can't be blank"], user.errors.full_messages)
69
+ end
70
+
71
+ test 'does not update if password is invalid and mismatches confirmation' do
72
+ user = create_user
73
+
74
+ result = user.update_with_password(
75
+ {
76
+ current_password: 'Password1!',
77
+ password: 'f',
78
+ password_confirmation: 'Password2!'
79
+ }
80
+ )
81
+
82
+ assert_equal(
83
+ [
84
+ "Password confirmation doesn't match Password",
85
+ 'Password is too short (minimum is 7 characters)',
86
+ 'Password must contain at least one digit',
87
+ 'Password must contain at least one upper-case letter'
88
+ ],
89
+ user.errors.full_messages
90
+ )
91
+ end
92
+
93
+ test 'does not update if password is invalid and matches confirmation' do
94
+ user = create_user
95
+
96
+ result = user.update_with_password(
97
+ {
98
+ current_password: 'Password1!',
99
+ password: 'f',
100
+ password_confirmation: 'f'
101
+ }
102
+ )
103
+
104
+ assert_equal(
105
+ [
106
+ 'Password is too short (minimum is 7 characters)',
107
+ 'Password must contain at least one digit',
108
+ 'Password must contain at least one upper-case letter'
109
+ ],
110
+ user.errors.full_messages
111
+ )
112
+ end
113
+
114
+ test 'does not update if password_confirmation is missing' do
115
+ user = create_user
116
+
117
+ user.update_with_password(
118
+ {
119
+ current_password: 'Password1!',
120
+ password: 'Password2!',
121
+ password_confirmation: ''
122
+ }
123
+ )
124
+
125
+ assert_equal(
126
+ ["Password confirmation can't be blank"], user.errors.full_messages
127
+ )
128
+ end
129
+
130
+ test 'does not update if password_confirmation is mismatched' do
131
+ user = create_user
132
+
133
+ user.update_with_password(
134
+ {
135
+ current_password: 'Password1!',
136
+ password: 'Password2!',
137
+ password_confirmation: 'Password3!'
138
+ }
139
+ )
140
+
141
+ assert_equal(
142
+ ["Password confirmation doesn't match Password"],
143
+ user.errors.full_messages
144
+ )
145
+ end
146
+ end
data/test/test_helper.rb CHANGED
@@ -3,6 +3,13 @@
3
3
  ENV['RAILS_ENV'] ||= 'test'
4
4
 
5
5
  require 'simplecov'
6
+
7
+ if ENV['CI']
8
+ require 'simplecov-lcov'
9
+ SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
10
+ SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
11
+ end
12
+
6
13
  SimpleCov.start do
7
14
  add_filter 'gemfiles'
8
15
  add_filter 'test/dummy/db'
@@ -18,14 +25,6 @@ SimpleCov.start do
18
25
  add_group 'Tests', 'test'
19
26
  end
20
27
 
21
- if ENV['CI']
22
- require 'simplecov'
23
- require 'simplecov-lcov'
24
- SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
25
- SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
26
- SimpleCov.start
27
- end
28
-
29
28
  require 'pry'
30
29
  require 'dummy/config/environment'
31
30
  require 'minitest/autorun'
@@ -6,7 +6,7 @@ require 'generators/devise_security/install_generator'
6
6
 
7
7
  class TestInstallGenerator < Rails::Generators::TestCase
8
8
  tests DeviseSecurity::Generators::InstallGenerator
9
- destination File.expand_path('../tmp', __FILE__)
9
+ destination File.expand_path('tmp', __dir__)
10
10
  setup :prepare_destination
11
11
 
12
12
  test 'Assert all files are properly created' do
@@ -94,7 +94,6 @@ class TestParanoidVerification < ActiveSupport::TestCase
94
94
  Devise.paranoid_code_regenerate_after_attempt = original_regenerate
95
95
  end
96
96
 
97
-
98
97
  test 'by default paranoid code regenerate should have 10 attempts' do
99
98
  user = User.new(paranoid_verification_code: 'abcde')
100
99
  assert_equal 10, user.paranoid_attempts_remaining
@@ -3,7 +3,6 @@
3
3
  require 'test_helper'
4
4
 
5
5
  class TestPasswordArchivable < ActiveSupport::TestCase
6
-
7
6
  setup do
8
7
  Devise.password_archiving_count = 2
9
8
  end
@@ -20,7 +19,7 @@ class TestPasswordArchivable < ActiveSupport::TestCase
20
19
 
21
20
  test 'cannot use same password' do
22
21
  user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
23
- assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
22
+ assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
24
23
  end
25
24
 
26
25
  test 'indirectly saving associated user does not cause deprecation warning' do
@@ -43,19 +42,19 @@ class TestPasswordArchivable < ActiveSupport::TestCase
43
42
 
44
43
  user = User.create! email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
45
44
  assert_equal 0, OldPassword.count
46
- set_password(user, 'Password2')
45
+ set_password(user, 'Password2')
47
46
  assert_equal 1, OldPassword.count
48
47
 
49
- assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
50
- set_password(user, 'Password3')
48
+ assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
49
+ set_password(user, 'Password3')
51
50
  assert_equal 2, OldPassword.count
52
51
 
53
52
  # rotate first password out of archive
54
- assert set_password(user, 'Password4')
53
+ assert set_password(user, 'Password4')
55
54
 
56
55
  # archive count was 2, so first password should work again
57
- assert set_password(user, 'Password1')
58
- assert set_password(user, 'Password2')
56
+ assert set_password(user, 'Password1')
57
+ assert set_password(user, 'Password2')
59
58
  end
60
59
 
61
60
  test 'the option should be dynamic during runtime' do
@@ -67,10 +66,34 @@ class TestPasswordArchivable < ActiveSupport::TestCase
67
66
 
68
67
  user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
69
68
 
70
- assert set_password(user, 'Password2')
69
+ assert set_password(user, 'Password2')
70
+
71
+ assert_raises(ORMInvalidRecordException) { set_password(user, 'Password2') }
72
+
73
+ assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
74
+ end
75
+
76
+ test 'default sort orders do not affect archiving' do
77
+ class ::OldPassword
78
+ default_scope { order(created_at: :asc) }
79
+ end
80
+
81
+ assert_equal 2, Devise.password_archiving_count
82
+
83
+ user = User.create! email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
84
+ assert_equal 0, OldPassword.count
85
+ set_password(user, 'Password2')
86
+ assert_equal 1, OldPassword.count
87
+
88
+ assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
89
+ set_password(user, 'Password3')
90
+ assert_equal 2, OldPassword.count
71
91
 
72
- assert_raises(ORMInvalidRecordException) { set_password(user, 'Password2') }
92
+ # rotate first password out of archive
93
+ assert set_password(user, 'Password4')
73
94
 
74
- assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
95
+ # archive count was 2, so first password should work again
96
+ assert set_password(user, 'Password1')
97
+ assert set_password(user, 'Password2')
75
98
  end
76
99
  end