devise-security 0.12.0 → 0.18.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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +3 -1
  3. data/README.md +199 -65
  4. data/app/controllers/devise/paranoid_verification_code_controller.rb +28 -12
  5. data/app/controllers/devise/password_expired_controller.rb +34 -10
  6. data/app/views/devise/paranoid_verification_code/show.html.erb +4 -4
  7. data/app/views/devise/password_expired/show.html.erb +6 -6
  8. data/config/locales/bg.yml +42 -0
  9. data/config/locales/by.yml +50 -0
  10. data/config/locales/cs.yml +46 -0
  11. data/config/locales/de.yml +33 -7
  12. data/config/locales/en.yml +26 -1
  13. data/config/locales/es.yml +31 -6
  14. data/config/locales/fa.yml +42 -0
  15. data/config/locales/fr.yml +42 -0
  16. data/config/locales/hi.yml +43 -0
  17. data/config/locales/it.yml +36 -4
  18. data/config/locales/ja.yml +42 -0
  19. data/config/locales/nl.yml +42 -0
  20. data/config/locales/pt.yml +42 -0
  21. data/config/locales/ru.yml +50 -0
  22. data/config/locales/tr.yml +42 -0
  23. data/config/locales/uk.yml +50 -0
  24. data/config/locales/zh_CN.yml +42 -0
  25. data/config/locales/zh_TW.yml +42 -0
  26. data/lib/devise-security/controllers/helpers.rb +74 -51
  27. data/lib/devise-security/hooks/expirable.rb +6 -4
  28. data/lib/devise-security/hooks/paranoid_verification.rb +3 -3
  29. data/lib/devise-security/hooks/password_expirable.rb +5 -3
  30. data/lib/devise-security/hooks/session_limitable.rb +31 -14
  31. data/lib/devise-security/models/active_record/old_password.rb +5 -0
  32. data/lib/devise-security/models/compatibility/active_record_patch.rb +41 -0
  33. data/lib/devise-security/models/compatibility/mongoid_patch.rb +32 -0
  34. data/lib/devise-security/models/compatibility.rb +8 -15
  35. data/lib/devise-security/models/database_authenticatable_patch.rb +20 -10
  36. data/lib/devise-security/models/expirable.rb +14 -7
  37. data/lib/devise-security/models/mongoid/old_password.rb +21 -0
  38. data/lib/devise-security/models/paranoid_verification.rb +4 -2
  39. data/lib/devise-security/models/password_archivable.rb +19 -8
  40. data/lib/devise-security/models/password_expirable.rb +103 -48
  41. data/lib/devise-security/models/secure_validatable.rb +69 -12
  42. data/lib/devise-security/models/security_questionable.rb +2 -0
  43. data/lib/devise-security/models/session_limitable.rb +19 -2
  44. data/lib/devise-security/orm/mongoid.rb +7 -0
  45. data/lib/devise-security/patches/controller_captcha.rb +2 -0
  46. data/lib/devise-security/patches/controller_security_question.rb +3 -1
  47. data/lib/devise-security/patches.rb +16 -8
  48. data/lib/devise-security/rails.rb +2 -0
  49. data/lib/devise-security/routes.rb +4 -3
  50. data/lib/devise-security/validators/password_complexity_validator.rb +62 -0
  51. data/lib/devise-security/version.rb +3 -1
  52. data/lib/devise-security.rb +23 -11
  53. data/lib/generators/devise_security/install_generator.rb +6 -6
  54. data/lib/generators/templates/devise_security.rb +52 -0
  55. data/test/{test_captcha_controller.rb → controllers/test_captcha_controller.rb} +2 -0
  56. data/test/controllers/test_paranoid_verification_code_controller.rb +133 -0
  57. data/test/controllers/test_password_expired_controller.rb +164 -0
  58. data/test/controllers/test_security_question_controller.rb +66 -0
  59. data/test/dummy/Rakefile +3 -1
  60. data/test/dummy/app/assets/config/manifest.js +3 -0
  61. data/test/dummy/app/controllers/application_controller.rb +2 -0
  62. data/test/dummy/app/controllers/captcha/sessions_controller.rb +2 -0
  63. data/test/dummy/app/controllers/overrides/paranoid_verification_code_controller.rb +7 -0
  64. data/test/dummy/app/controllers/overrides/password_expired_controller.rb +17 -0
  65. data/test/dummy/app/controllers/security_question/unlocks_controller.rb +2 -0
  66. data/test/dummy/app/controllers/widgets_controller.rb +9 -0
  67. data/test/dummy/app/models/application_record.rb +10 -2
  68. data/test/dummy/app/models/application_user_record.rb +12 -0
  69. data/test/dummy/app/models/captcha_user.rb +7 -2
  70. data/test/dummy/app/models/mongoid/confirmable_fields.rb +15 -0
  71. data/test/dummy/app/models/mongoid/database_authenticable_fields.rb +18 -0
  72. data/test/dummy/app/models/mongoid/expirable_fields.rb +13 -0
  73. data/test/dummy/app/models/mongoid/lockable_fields.rb +15 -0
  74. data/test/dummy/app/models/mongoid/mappings.rb +15 -0
  75. data/test/dummy/app/models/mongoid/omniauthable_fields.rb +13 -0
  76. data/test/dummy/app/models/mongoid/paranoid_verification_fields.rb +12 -0
  77. data/test/dummy/app/models/mongoid/password_archivable_fields.rb +11 -0
  78. data/test/dummy/app/models/mongoid/password_expirable_fields.rb +12 -0
  79. data/test/dummy/app/models/mongoid/recoverable_fields.rb +13 -0
  80. data/test/dummy/app/models/mongoid/registerable_fields.rb +21 -0
  81. data/test/dummy/app/models/mongoid/rememberable_fields.rb +12 -0
  82. data/test/dummy/app/models/mongoid/secure_validatable_fields.rb +13 -0
  83. data/test/dummy/app/models/mongoid/security_questionable_fields.rb +15 -0
  84. data/test/dummy/app/models/mongoid/session_limitable_fields.rb +12 -0
  85. data/test/dummy/app/models/mongoid/timeoutable_fields.rb +11 -0
  86. data/test/dummy/app/models/mongoid/trackable_fields.rb +16 -0
  87. data/test/dummy/app/models/mongoid/validatable_fields.rb +9 -0
  88. data/test/dummy/app/models/paranoid_verification_user.rb +26 -0
  89. data/test/dummy/app/models/password_expired_user.rb +26 -0
  90. data/test/dummy/app/models/security_question_user.rb +9 -4
  91. data/test/dummy/app/models/user.rb +16 -1
  92. data/test/dummy/app/models/widget.rb +4 -0
  93. data/test/dummy/app/mongoid/admin.rb +31 -0
  94. data/test/dummy/app/mongoid/one_user.rb +58 -0
  95. data/test/dummy/app/mongoid/shim.rb +25 -0
  96. data/test/dummy/app/mongoid/user_on_engine.rb +41 -0
  97. data/test/dummy/app/mongoid/user_on_main_app.rb +41 -0
  98. data/test/dummy/app/mongoid/user_with_validations.rb +37 -0
  99. data/test/dummy/app/mongoid/user_without_email.rb +38 -0
  100. data/test/dummy/config/application.rb +13 -11
  101. data/test/dummy/config/boot.rb +3 -1
  102. data/test/dummy/config/environment.rb +3 -1
  103. data/test/dummy/config/environments/test.rb +6 -13
  104. data/test/dummy/config/initializers/devise.rb +6 -3
  105. data/test/dummy/config/initializers/migration_class.rb +3 -6
  106. data/test/dummy/config/locales/en.yml +10 -0
  107. data/test/dummy/config/mongoid.yml +6 -0
  108. data/test/dummy/config/routes.rb +8 -3
  109. data/test/dummy/config.ru +3 -1
  110. data/test/dummy/db/migrate/20120508165529_create_tables.rb +17 -6
  111. data/test/dummy/db/migrate/20150402165590_add_verification_columns.rb +2 -0
  112. data/test/dummy/db/migrate/20150407162345_add_verification_attempt_column.rb +2 -0
  113. data/test/dummy/db/migrate/20160320162345_add_security_questions_fields.rb +2 -0
  114. data/test/dummy/db/migrate/20180318103603_add_expireable_columns.rb +2 -0
  115. data/test/dummy/db/migrate/20180318105329_add_confirmable_columns.rb +2 -0
  116. data/test/dummy/db/migrate/20180318105732_add_rememberable_columns.rb +2 -0
  117. data/test/dummy/db/migrate/20180318111336_add_recoverable_columns.rb +2 -0
  118. data/test/dummy/db/migrate/20180319114023_add_widget.rb +2 -0
  119. data/test/dummy/lib/shared_expirable_columns.rb +15 -0
  120. data/test/dummy/lib/shared_security_questions_fields.rb +17 -0
  121. data/test/dummy/lib/shared_user.rb +43 -0
  122. data/test/dummy/lib/shared_user_with_password_verification.rb +13 -0
  123. data/test/dummy/lib/shared_user_without_omniauth.rb +24 -0
  124. data/test/dummy/lib/shared_verification_fields.rb +16 -0
  125. data/test/dummy/log/test.log +45240 -0
  126. data/test/i18n_test.rb +22 -0
  127. data/test/integration/test_paranoid_verification_code_workflow.rb +53 -0
  128. data/test/integration/test_password_expirable_workflow.rb +53 -0
  129. data/test/integration/test_session_limitable_workflow.rb +69 -0
  130. data/test/orm/active_record.rb +15 -0
  131. data/test/orm/mongoid.rb +13 -0
  132. data/test/support/integration_helpers.rb +35 -0
  133. data/test/support/mongoid.yml +6 -0
  134. data/test/test_compatibility.rb +15 -0
  135. data/test/test_complexity_validator.rb +282 -0
  136. data/test/test_database_authenticatable_patch.rb +146 -0
  137. data/test/test_helper.rb +41 -9
  138. data/test/test_install_generator.rb +20 -3
  139. data/test/test_paranoid_verification.rb +10 -9
  140. data/test/test_password_archivable.rb +37 -13
  141. data/test/test_password_expirable.rb +72 -9
  142. data/test/test_secure_validatable.rb +289 -55
  143. data/test/test_secure_validatable_overrides.rb +185 -0
  144. data/test/test_session_limitable.rb +57 -0
  145. data/test/tmp/config/initializers/devise_security.rb +52 -0
  146. data/test/tmp/config/locales/devise.security_extension.by.yml +50 -0
  147. data/test/tmp/config/locales/devise.security_extension.cs.yml +46 -0
  148. data/test/tmp/config/locales/devise.security_extension.de.yml +42 -0
  149. data/test/tmp/config/locales/devise.security_extension.en.yml +42 -0
  150. data/test/tmp/config/locales/devise.security_extension.es.yml +42 -0
  151. data/test/tmp/config/locales/devise.security_extension.fa.yml +42 -0
  152. data/test/tmp/config/locales/devise.security_extension.fr.yml +42 -0
  153. data/test/tmp/config/locales/devise.security_extension.hi.yml +43 -0
  154. data/test/tmp/config/locales/devise.security_extension.it.yml +42 -0
  155. data/test/tmp/config/locales/devise.security_extension.ja.yml +42 -0
  156. data/test/tmp/config/locales/devise.security_extension.nl.yml +42 -0
  157. data/test/tmp/config/locales/devise.security_extension.pt.yml +42 -0
  158. data/test/tmp/config/locales/devise.security_extension.ru.yml +50 -0
  159. data/test/tmp/config/locales/devise.security_extension.tr.yml +42 -0
  160. data/test/tmp/config/locales/devise.security_extension.uk.yml +50 -0
  161. data/test/tmp/config/locales/devise.security_extension.zh_CN.yml +42 -0
  162. data/test/tmp/config/locales/devise.security_extension.zh_TW.yml +42 -0
  163. metadata +290 -124
  164. data/.circleci/config.yml +0 -41
  165. data/.document +0 -5
  166. data/.gitignore +0 -40
  167. data/.rubocop.yml +0 -63
  168. data/.ruby-version +0 -1
  169. data/.travis.yml +0 -25
  170. data/Appraisals +0 -19
  171. data/Gemfile +0 -3
  172. data/Rakefile +0 -28
  173. data/devise-security.gemspec +0 -44
  174. data/gemfiles/rails_4.1_stable.gemfile +0 -8
  175. data/gemfiles/rails_4.2_stable.gemfile +0 -8
  176. data/gemfiles/rails_5.0_stable.gemfile +0 -8
  177. data/gemfiles/rails_5.1_stable.gemfile +0 -8
  178. data/gemfiles/rails_5.2_rc1.gemfile +0 -8
  179. data/lib/devise-security/models/old_password.rb +0 -4
  180. data/lib/devise-security/orm/active_record.rb +0 -18
  181. data/lib/devise-security/patches/confirmations_controller_captcha.rb +0 -21
  182. data/lib/devise-security/patches/confirmations_controller_security_question.rb +0 -24
  183. data/lib/devise-security/patches/passwords_controller_captcha.rb +0 -20
  184. data/lib/devise-security/patches/passwords_controller_security_question.rb +0 -23
  185. data/lib/devise-security/patches/registrations_controller_captcha.rb +0 -33
  186. data/lib/devise-security/patches/sessions_controller_captcha.rb +0 -24
  187. data/lib/devise-security/patches/unlocks_controller_captcha.rb +0 -20
  188. data/lib/devise-security/patches/unlocks_controller_security_question.rb +0 -23
  189. data/lib/devise-security/schema.rb +0 -64
  190. data/lib/generators/templates/devise-security.rb +0 -38
  191. data/test/dummy/app/controllers/foos_controller.rb +0 -0
  192. data/test/dummy/app/models/.gitkeep +0 -0
  193. data/test/dummy/app/models/secure_user.rb +0 -3
  194. data/test/test_password_expired_controller.rb +0 -44
  195. data/test/test_security_question_controller.rb +0 -84
@@ -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
+ 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
+ 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
@@ -1,20 +1,52 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV['RAILS_ENV'] ||= 'test'
2
4
 
3
5
  require 'simplecov'
4
- require 'coveralls'
5
- Coveralls.wear!
6
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
+
13
+ SimpleCov.start do
14
+ add_filter 'gemfiles'
15
+ add_filter 'test/dummy/db'
16
+ add_group 'ActiveRecord', 'active_record'
17
+ add_group 'Expirable', /(?<!password_)expirable/
18
+ add_group 'Mongoid', 'mongoid'
19
+ add_group 'Paranoid Verifiable', 'paranoid_verification'
20
+ add_group 'Password Archivable', /password_archivable|old_password/
21
+ add_group 'Password Expirable', /password_expirable|password_expired/
22
+ add_group 'Secure Validateable', 'secure_validatable'
23
+ add_group 'Security Questionable', 'security_question'
24
+ add_group 'Session Limitable', 'session_limitable'
25
+ add_group 'Tests', 'test'
26
+ end
27
+
28
+ require 'pry'
7
29
  require 'dummy/config/environment'
8
30
  require 'minitest/autorun'
9
31
  require 'rails/test_help'
10
32
  require 'devise-security'
33
+ require 'database_cleaner'
34
+ require "orm/#{DEVISE_ORM}"
11
35
 
12
- ActiveRecord::Migration.verbose = false
13
- ActiveRecord::Base.logger = Logger.new(nil)
14
- ActiveRecord::Migrator.migrate(File.expand_path('../dummy/db/migrate', __FILE__))
36
+ # Controller testing is the way that Devise itself tests the functionality of
37
+ # controller, even though it has been deprecated in favor of request tests.
38
+ require 'rails-controller-testing'
39
+ Rails::Controller::Testing.install
40
+ require 'support/integration_helpers'
15
41
 
16
- SimpleCov.formatter = Coveralls::SimpleCov::Formatter
17
- SimpleCov.start do
18
- add_filter 'test/dummy'
19
- add_filter 'gemfiles'
42
+ class Minitest::Test
43
+ def before_setup
44
+ DatabaseCleaner.start
45
+ end
46
+
47
+ def after_teardown
48
+ DatabaseCleaner.clean
49
+ end
20
50
  end
51
+
52
+ DatabaseCleaner.clean
@@ -1,16 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'rails/generators/test_case'
3
5
  require 'generators/devise_security/install_generator'
4
6
 
5
7
  class TestInstallGenerator < Rails::Generators::TestCase
6
8
  tests DeviseSecurity::Generators::InstallGenerator
7
- destination File.expand_path('../tmp', __FILE__)
9
+ destination File.expand_path('tmp', __dir__)
8
10
  setup :prepare_destination
9
11
 
10
12
  test 'Assert all files are properly created' do
11
13
  run_generator
12
- assert_file 'config/initializers/devise-security.rb'
13
- assert_file 'config/locales/devise.security_extension.en.yml'
14
+ assert_file 'config/initializers/devise_security.rb'
15
+ assert_file 'config/locales/devise.security_extension.by.yml'
16
+ assert_file 'config/locales/devise.security_extension.cs.yml'
14
17
  assert_file 'config/locales/devise.security_extension.de.yml'
18
+ assert_file 'config/locales/devise.security_extension.en.yml'
19
+ assert_file 'config/locales/devise.security_extension.es.yml'
20
+ assert_file 'config/locales/devise.security_extension.fa.yml'
21
+ assert_file 'config/locales/devise.security_extension.fr.yml'
22
+ assert_file 'config/locales/devise.security_extension.hi.yml'
23
+ assert_file 'config/locales/devise.security_extension.it.yml'
24
+ assert_file 'config/locales/devise.security_extension.ja.yml'
25
+ assert_file 'config/locales/devise.security_extension.nl.yml'
26
+ assert_file 'config/locales/devise.security_extension.pt.yml'
27
+ assert_file 'config/locales/devise.security_extension.ru.yml'
28
+ assert_file 'config/locales/devise.security_extension.tr.yml'
29
+ assert_file 'config/locales/devise.security_extension.uk.yml'
30
+ assert_file 'config/locales/devise.security_extension.zh_CN.yml'
31
+ assert_file 'config/locales/devise.security_extension.zh_TW.yml'
15
32
  end
16
33
  end
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class TestParanoidVerification < ActiveSupport::TestCase
4
6
  test 'need to paranoid verify if code present' do
5
7
  user = User.new
6
8
  user.generate_paranoid_code
7
- assert_equal(true, user.need_paranoid_verification?)
9
+ assert(user.need_paranoid_verification?)
8
10
  end
9
11
 
10
12
  test 'no need to paranoid verify if no code' do
11
13
  user = User.new
12
- assert_equal(false, user.need_paranoid_verification?)
14
+ assert_not(user.need_paranoid_verification?)
13
15
  end
14
16
 
15
17
  test 'generate code' do
@@ -27,23 +29,23 @@ class TestParanoidVerification < ActiveSupport::TestCase
27
29
  user.generate_paranoid_code
28
30
  # default generator generates 5 char string
29
31
  assert_equal(user.paranoid_verification_code.class, String)
30
- assert_equal(user.paranoid_verification_code.length, 5)
32
+ assert_equal(5, user.paranoid_verification_code.length)
31
33
  end
32
34
 
33
35
  test 'when code match upon verify code, should mark record that it\'s no loger needed to verify' do
34
36
  user = User.new(paranoid_verification_code: 'abcde')
35
37
 
36
- assert_equal(true, user.need_paranoid_verification?)
38
+ assert(user.need_paranoid_verification?)
37
39
  user.verify_code('abcde')
38
- assert_equal(false, user.need_paranoid_verification?)
40
+ assert_not(user.need_paranoid_verification?)
39
41
  end
40
42
 
41
43
  test 'when code match upon verify code, should no longer need verification' do
42
44
  user = User.new(paranoid_verification_code: 'abcde')
43
45
 
44
- assert_equal(true, user.need_paranoid_verification?)
46
+ assert(user.need_paranoid_verification?)
45
47
  user.verify_code('abcde')
46
- assert_equal(false, user.need_paranoid_verification?)
48
+ assert_not(user.need_paranoid_verification?)
47
49
  end
48
50
 
49
51
  test 'when code match upon verification code, should set when verification was accepted' do
@@ -55,7 +57,7 @@ class TestParanoidVerification < ActiveSupport::TestCase
55
57
  test 'when code not match upon verify code, should still need verification' do
56
58
  user = User.new(paranoid_verification_code: 'abcde')
57
59
  user.verify_code('wrong')
58
- assert_equal(true, user.need_paranoid_verification?)
60
+ assert(user.need_paranoid_verification?)
59
61
  end
60
62
 
61
63
  test 'when code not match upon verification code, should not set paranoid_verified_at' do
@@ -92,7 +94,6 @@ class TestParanoidVerification < ActiveSupport::TestCase
92
94
  Devise.paranoid_code_regenerate_after_attempt = original_regenerate
93
95
  end
94
96
 
95
-
96
97
  test 'by default paranoid code regenerate should have 10 attempts' do
97
98
  user = User.new(paranoid_verification_code: 'abcde')
98
99
  assert_equal 10, user.paranoid_attempts_remaining
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class TestPasswordArchivable < ActiveSupport::TestCase
@@ -17,7 +19,7 @@ class TestPasswordArchivable < ActiveSupport::TestCase
17
19
 
18
20
  test 'cannot use same password' do
19
21
  user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
20
- assert_raises(ActiveRecord::RecordInvalid) { set_password(user, 'Password1') }
22
+ assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
21
23
  end
22
24
 
23
25
  test 'indirectly saving associated user does not cause deprecation warning' do
@@ -35,26 +37,24 @@ class TestPasswordArchivable < ActiveSupport::TestCase
35
37
  assert_equal 0, OldPassword.count
36
38
  end
37
39
 
38
- test 'cannot use archived passwords' do
40
+ test 'cannot reuse archived passwords' do
39
41
  assert_equal 2, Devise.password_archiving_count
40
42
 
41
43
  user = User.create! email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
42
44
  assert_equal 0, OldPassword.count
43
-
44
- set_password(user, 'Password2')
45
+ set_password(user, 'Password2')
45
46
  assert_equal 1, OldPassword.count
46
47
 
47
- assert_raises(ActiveRecord::RecordInvalid) { set_password(user, 'Password1') }
48
-
49
- set_password(user, 'Password3')
48
+ assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
49
+ set_password(user, 'Password3')
50
50
  assert_equal 2, OldPassword.count
51
51
 
52
52
  # rotate first password out of archive
53
- assert set_password(user, 'Password4')
53
+ assert set_password(user, 'Password4')
54
54
 
55
55
  # archive count was 2, so first password should work again
56
- assert set_password(user, 'Password1')
57
- assert set_password(user, 'Password2')
56
+ assert set_password(user, 'Password1')
57
+ assert set_password(user, 'Password2')
58
58
  end
59
59
 
60
60
  test 'the option should be dynamic during runtime' do
@@ -66,10 +66,34 @@ class TestPasswordArchivable < ActiveSupport::TestCase
66
66
 
67
67
  user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
68
68
 
69
- 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
70
82
 
71
- assert_raises(ActiveRecord::RecordInvalid) { set_password(user, 'Password2') }
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
72
87
 
73
- assert_raises(ActiveRecord::RecordInvalid) { set_password(user, 'Password1') }
88
+ assert_raises(ORMInvalidRecordException) { set_password(user, 'Password1') }
89
+ set_password(user, 'Password3')
90
+ assert_equal 2, OldPassword.count
91
+
92
+ # rotate first password out of archive
93
+ assert set_password(user, 'Password4')
94
+
95
+ # archive count was 2, so first password should work again
96
+ assert set_password(user, 'Password1')
97
+ assert set_password(user, 'Password2')
74
98
  end
75
99
  end
@@ -1,32 +1,95 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class TestPasswordArchivable < ActiveSupport::TestCase
4
6
  setup do
5
- Devise.expire_password_after = 2.month
7
+ Devise.expire_password_after = 2.months
6
8
  end
7
9
 
8
10
  teardown do
9
11
  Devise.expire_password_after = 90.days
10
12
  end
11
13
 
12
- test 'password expires' do
14
+ test 'does nothing if disabled' do
15
+ Devise.expire_password_after = false
13
16
  user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
14
- refute user.need_change_password?
17
+ assert_not user.need_change_password?
18
+ assert_not user.password_expired?
19
+ user.need_change_password!
20
+ assert_not user.need_change_password?
21
+ assert_not user.password_expired?
22
+ end
15
23
 
16
- user.update(password_changed_at: Time.now.ago(3.month))
24
+ test 'password change can be requested' do
25
+ Devise.expire_password_after = true
26
+ user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
27
+ assert_not user.need_change_password?
28
+ assert_not user.password_expired?
29
+ assert_not user.password_change_requested?
30
+ user.need_change_password!
17
31
  assert user.need_change_password?
32
+ assert_not user.password_expired? # it's not too old because it's not set at all
33
+ assert user.password_change_requested?
18
34
  end
19
35
 
20
- test 'override expire after at runtime' do
36
+ test 'password expires' do
37
+ user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
38
+ assert_not user.need_change_password?
39
+ assert_not user.password_expired?
40
+ assert_not user.password_too_old?
41
+ user.update(password_changed_at: Time.zone.now.ago(3.months))
42
+ assert user.password_too_old?
43
+ assert user.need_change_password?
44
+ assert user.password_expired?
45
+ assert_not user.password_change_requested?
46
+ end
47
+
48
+ test 'saving a record records the time the password was changed' do
21
49
  user = User.new email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
50
+ assert_nil user.password_changed_at
51
+ assert_not user.password_change_requested?
52
+ assert_not user.password_expired?
53
+ user.save
54
+ assert user.password_changed_at.present?
55
+ assert_not user.password_change_requested?
56
+ assert_not user.password_expired?
57
+ end
58
+
59
+ test 'updating a record updates the time the password was changed if the password is changed' do
60
+ user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
61
+ user.update(password_changed_at: Time.zone.now.ago(3.months))
62
+ original_password_changed_at = user.password_changed_at
63
+ user.expire_password!
64
+ assert user.password_change_requested?
65
+ user.password = 'NewPassword1'
66
+ user.password_confirmation = 'NewPassword1'
67
+ user.save
68
+ assert user.password_changed_at > original_password_changed_at
69
+ assert_not user.password_change_requested?
70
+ end
71
+
72
+ test 'updating a record does not updates the time the password was changed if the password was not changed' do
73
+ user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
74
+ user.expire_password!
75
+ assert user.password_change_requested?
76
+ user.save
77
+ assert_not user.previous_changes.key?(:password_changed_at)
78
+ assert user.password_change_requested?
79
+ end
80
+
81
+ test 'override expire after at runtime' do
82
+ user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
22
83
  user.instance_eval do
23
84
  def expire_password_after
24
- 4.month
85
+ 4.months
25
86
  end
26
87
  end
27
- user.password_changed_at = Time.now.ago(3.month)
28
- refute user.need_change_password?
29
- user.password_changed_at = Time.now.ago(5.month)
88
+ user.password_changed_at = Time.zone.now.ago(3.months)
89
+ assert_not user.need_change_password?
90
+ assert_not user.password_expired?
91
+ user.password_changed_at = Time.zone.now.ago(5.months)
30
92
  assert user.need_change_password?
93
+ assert user.password_expired?
31
94
  end
32
95
  end