devise-security 0.14.2 → 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.
- checksums.yaml +4 -4
- data/README.md +125 -59
- data/app/controllers/devise/paranoid_verification_code_controller.rb +13 -1
- data/app/controllers/devise/password_expired_controller.rb +24 -6
- data/app/views/devise/paranoid_verification_code/show.html.erb +3 -3
- data/app/views/devise/password_expired/show.html.erb +5 -5
- data/config/locales/bg.yml +41 -0
- data/config/locales/by.yml +49 -0
- data/config/locales/cs.yml +41 -0
- data/config/locales/de.yml +15 -2
- data/config/locales/en.yml +15 -2
- data/config/locales/es.yml +10 -9
- data/config/locales/fa.yml +41 -0
- data/config/locales/fr.yml +1 -0
- data/config/locales/hi.yml +42 -0
- data/config/locales/it.yml +35 -4
- data/config/locales/ja.yml +2 -1
- data/config/locales/nl.yml +41 -0
- data/config/locales/pt.yml +41 -0
- data/config/locales/ru.yml +49 -0
- data/config/locales/tr.yml +1 -0
- data/config/locales/uk.yml +49 -0
- data/config/locales/zh_CN.yml +41 -0
- data/config/locales/zh_TW.yml +41 -0
- data/lib/devise-security/controllers/helpers.rb +59 -50
- data/lib/devise-security/hooks/password_expirable.rb +2 -0
- data/lib/devise-security/hooks/session_limitable.rb +21 -11
- data/lib/devise-security/models/database_authenticatable_patch.rb +15 -5
- data/lib/devise-security/models/password_archivable.rb +2 -2
- data/lib/devise-security/models/password_expirable.rb +5 -1
- data/lib/devise-security/models/secure_validatable.rb +56 -6
- data/lib/devise-security/models/session_limitable.rb +10 -1
- data/lib/devise-security/validators/password_complexity_validator.rb +53 -24
- data/lib/devise-security/version.rb +1 -1
- data/lib/devise-security.rb +13 -5
- data/lib/generators/devise_security/install_generator.rb +3 -3
- data/lib/generators/templates/{devise-security.rb → devise_security.rb} +6 -1
- data/test/controllers/test_paranoid_verification_code_controller.rb +68 -0
- data/test/controllers/test_password_expired_controller.rb +121 -19
- data/test/controllers/test_security_question_controller.rb +16 -40
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/controllers/overrides/paranoid_verification_code_controller.rb +7 -0
- data/test/dummy/app/controllers/overrides/password_expired_controller.rb +7 -0
- data/test/dummy/app/controllers/widgets_controller.rb +3 -0
- data/test/dummy/app/models/application_user_record.rb +2 -1
- data/test/dummy/app/models/mongoid/confirmable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/database_authenticable_fields.rb +4 -3
- data/test/dummy/app/models/mongoid/expirable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/lockable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/mappings.rb +4 -2
- data/test/dummy/app/models/mongoid/omniauthable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/paranoid_verification_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/password_archivable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/password_expirable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/recoverable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/registerable_fields.rb +4 -2
- data/test/dummy/app/models/mongoid/rememberable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/secure_validatable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/security_questionable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/session_limitable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/timeoutable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/trackable_fields.rb +2 -0
- data/test/dummy/app/models/mongoid/validatable_fields.rb +2 -0
- data/test/dummy/app/models/paranoid_verification_user.rb +26 -0
- data/test/dummy/app/models/password_expired_user.rb +26 -0
- data/test/dummy/app/models/user.rb +1 -2
- data/test/dummy/app/models/widget.rb +1 -3
- data/test/dummy/app/mongoid/one_user.rb +5 -5
- data/test/dummy/app/mongoid/user_on_engine.rb +2 -2
- data/test/dummy/app/mongoid/user_on_main_app.rb +2 -2
- data/test/dummy/app/mongoid/user_with_validations.rb +3 -3
- data/test/dummy/app/mongoid/user_without_email.rb +3 -3
- data/test/dummy/config/application.rb +4 -4
- data/test/dummy/config/boot.rb +1 -1
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/test.rb +3 -13
- data/test/dummy/config/initializers/migration_class.rb +1 -8
- data/test/dummy/config/locales/en.yml +10 -0
- data/test/dummy/config/mongoid.yml +1 -1
- data/test/dummy/config/routes.rb +5 -3
- data/test/dummy/db/migrate/20120508165529_create_tables.rb +3 -3
- data/test/dummy/lib/shared_expirable_columns.rb +1 -0
- data/test/dummy/lib/shared_security_questions_fields.rb +1 -0
- data/test/dummy/lib/shared_user.rb +17 -6
- data/test/dummy/lib/shared_user_without_email.rb +2 -1
- data/test/dummy/lib/shared_user_without_omniauth.rb +12 -3
- data/test/dummy/lib/shared_verification_fields.rb +1 -0
- data/test/dummy/{app/models/.gitkeep → log/development.log} +0 -0
- data/test/dummy/log/test.log +101533 -0
- data/test/integration/test_password_expirable_workflow.rb +53 -0
- data/test/integration/test_session_limitable_workflow.rb +2 -0
- data/test/orm/active_record.rb +7 -4
- data/test/orm/mongoid.rb +2 -1
- data/test/support/integration_helpers.rb +15 -33
- data/test/support/mongoid.yml +1 -1
- data/test/test_compatibility.rb +2 -0
- data/test/test_complexity_validator.rb +250 -29
- data/test/test_database_authenticatable_patch.rb +146 -0
- data/test/test_helper.rb +12 -6
- data/test/test_install_generator.rb +12 -2
- data/test/test_paranoid_verification.rb +0 -1
- data/test/test_password_archivable.rb +34 -11
- data/test/test_password_expirable.rb +26 -26
- data/test/test_secure_validatable.rb +292 -50
- data/test/test_secure_validatable_overrides.rb +185 -0
- data/test/test_session_limitable.rb +27 -1
- data/test/tmp/config/initializers/devise_security.rb +49 -0
- data/test/tmp/config/locales/devise.security_extension.by.yml +49 -0
- data/test/tmp/config/locales/devise.security_extension.cs.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.de.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.en.yml +42 -0
- data/test/tmp/config/locales/devise.security_extension.es.yml +30 -0
- data/test/tmp/config/locales/devise.security_extension.fa.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.fr.yml +30 -0
- data/test/tmp/config/locales/devise.security_extension.hi.yml +42 -0
- data/test/tmp/config/locales/devise.security_extension.it.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.ja.yml +30 -0
- data/test/tmp/config/locales/devise.security_extension.nl.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.pt.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.ru.yml +49 -0
- data/test/tmp/config/locales/devise.security_extension.tr.yml +18 -0
- data/test/tmp/config/locales/devise.security_extension.uk.yml +49 -0
- data/test/tmp/config/locales/devise.security_extension.zh_CN.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.zh_TW.yml +41 -0
- metadata +168 -132
- data/.codeclimate.yml +0 -63
- data/.document +0 -5
- data/.gitignore +0 -43
- data/.mdlrc +0 -1
- data/.rubocop.yml +0 -64
- data/.ruby-version +0 -1
- data/.travis.yml +0 -39
- data/Appraisals +0 -35
- data/Gemfile +0 -10
- data/Rakefile +0 -27
- data/devise-security.gemspec +0 -50
- data/gemfiles/rails_4.2_stable.gemfile +0 -16
- data/gemfiles/rails_5.0_stable.gemfile +0 -15
- data/gemfiles/rails_5.1_stable.gemfile +0 -15
- data/gemfiles/rails_5.2_stable.gemfile +0 -15
- data/gemfiles/rails_6.0_beta.gemfile +0 -15
- data/lib/devise-security/orm/active_record.rb +0 -20
- data/lib/devise-security/schema.rb +0 -66
- data/test/dummy/app/models/secure_user.rb +0 -9
@@ -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,
|
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,
|
45
|
+
set_password(user, 'Password2')
|
47
46
|
assert_equal 1, OldPassword.count
|
48
47
|
|
49
|
-
assert_raises(ORMInvalidRecordException) { set_password(user,
|
50
|
-
set_password(user,
|
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,
|
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,
|
58
|
-
assert set_password(user,
|
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,
|
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
|
-
|
92
|
+
# rotate first password out of archive
|
93
|
+
assert set_password(user, 'Password4')
|
73
94
|
|
74
|
-
|
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
|
@@ -14,59 +14,59 @@ class TestPasswordArchivable < ActiveSupport::TestCase
|
|
14
14
|
test 'does nothing if disabled' do
|
15
15
|
Devise.expire_password_after = false
|
16
16
|
user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
|
17
|
-
|
18
|
-
|
17
|
+
assert_not user.need_change_password?
|
18
|
+
assert_not user.password_expired?
|
19
19
|
user.need_change_password!
|
20
|
-
|
21
|
-
|
20
|
+
assert_not user.need_change_password?
|
21
|
+
assert_not user.password_expired?
|
22
22
|
end
|
23
23
|
|
24
24
|
test 'password change can be requested' do
|
25
25
|
Devise.expire_password_after = true
|
26
26
|
user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
assert_not user.need_change_password?
|
28
|
+
assert_not user.password_expired?
|
29
|
+
assert_not user.password_change_requested?
|
30
30
|
user.need_change_password!
|
31
31
|
assert user.need_change_password?
|
32
|
-
|
32
|
+
assert_not user.password_expired? # it's not too old because it's not set at all
|
33
33
|
assert user.password_change_requested?
|
34
34
|
end
|
35
35
|
|
36
36
|
test 'password expires' do
|
37
37
|
user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
user.update(password_changed_at: Time.now.ago(3.months))
|
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
42
|
assert user.password_too_old?
|
43
43
|
assert user.need_change_password?
|
44
44
|
assert user.password_expired?
|
45
|
-
|
45
|
+
assert_not user.password_change_requested?
|
46
46
|
end
|
47
47
|
|
48
48
|
test 'saving a record records the time the password was changed' do
|
49
49
|
user = User.new email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
|
50
50
|
assert user.password_changed_at.nil?
|
51
|
-
|
52
|
-
|
51
|
+
assert_not user.password_change_requested?
|
52
|
+
assert_not user.password_expired?
|
53
53
|
user.save
|
54
54
|
assert user.password_changed_at.present?
|
55
|
-
|
56
|
-
|
55
|
+
assert_not user.password_change_requested?
|
56
|
+
assert_not user.password_expired?
|
57
57
|
end
|
58
58
|
|
59
59
|
test 'updating a record updates the time the password was changed if the password is changed' do
|
60
60
|
user = User.create email: 'bob@microsoft.com', password: 'Password1', password_confirmation: 'Password1'
|
61
|
-
user.update(password_changed_at: Time.now.ago(3.months))
|
61
|
+
user.update(password_changed_at: Time.zone.now.ago(3.months))
|
62
62
|
original_password_changed_at = user.password_changed_at
|
63
63
|
user.expire_password!
|
64
64
|
assert user.password_change_requested?
|
65
|
-
user.password =
|
66
|
-
user.password_confirmation =
|
65
|
+
user.password = 'NewPassword1'
|
66
|
+
user.password_confirmation = 'NewPassword1'
|
67
67
|
user.save
|
68
68
|
assert user.password_changed_at > original_password_changed_at
|
69
|
-
|
69
|
+
assert_not user.password_change_requested?
|
70
70
|
end
|
71
71
|
|
72
72
|
test 'updating a record does not updates the time the password was changed if the password was not changed' do
|
@@ -74,7 +74,7 @@ class TestPasswordArchivable < ActiveSupport::TestCase
|
|
74
74
|
user.expire_password!
|
75
75
|
assert user.password_change_requested?
|
76
76
|
user.save
|
77
|
-
|
77
|
+
assert_not user.previous_changes.key?(:password_changed_at)
|
78
78
|
assert user.password_change_requested?
|
79
79
|
end
|
80
80
|
|
@@ -85,10 +85,10 @@ class TestPasswordArchivable < ActiveSupport::TestCase
|
|
85
85
|
4.months
|
86
86
|
end
|
87
87
|
end
|
88
|
-
user.password_changed_at = Time.now.ago(3.months)
|
89
|
-
|
90
|
-
|
91
|
-
user.password_changed_at = Time.now.ago(5.months)
|
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)
|
92
92
|
assert user.need_change_password?
|
93
93
|
assert user.password_expired?
|
94
94
|
end
|
@@ -1,85 +1,327 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'test_helper'
|
4
|
-
require 'rails_email_validator'
|
5
4
|
|
6
5
|
class TestSecureValidatable < ActiveSupport::TestCase
|
7
6
|
class User < ApplicationRecord
|
8
|
-
devise :database_authenticatable, :
|
9
|
-
:paranoid_verification, :password_expirable, :secure_validatable
|
7
|
+
devise :database_authenticatable, :secure_validatable
|
10
8
|
include ::Mongoid::Mappings if DEVISE_ORM == :mongoid
|
11
9
|
end
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
user = User.create password: 'passWord1', password_confirmation: 'passWord1'
|
11
|
+
class EmailNotRequiredUser < User
|
12
|
+
protected
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
assert_raises(ORMInvalidRecordException) do
|
20
|
-
user.save!
|
14
|
+
def email_required?
|
15
|
+
false
|
21
16
|
end
|
22
17
|
end
|
23
18
|
|
19
|
+
test 'email cannot be blank upon creation' do
|
20
|
+
user = User.new(
|
21
|
+
password: 'Password1!', password_confirmation: 'Password1!'
|
22
|
+
)
|
23
|
+
|
24
|
+
assert user.invalid?
|
25
|
+
assert_equal(["Email can't be blank"], user.errors.full_messages)
|
26
|
+
end
|
27
|
+
|
28
|
+
test 'email can be blank upon creation if email not required' do
|
29
|
+
user = EmailNotRequiredUser.new(
|
30
|
+
password: 'Password1!', password_confirmation: 'Password1!'
|
31
|
+
)
|
32
|
+
|
33
|
+
assert user.valid?
|
34
|
+
end
|
35
|
+
|
36
|
+
test 'email cannot be updated to be blank' do
|
37
|
+
user = User.new(
|
38
|
+
email: 'bob@microsoft.com',
|
39
|
+
password: 'Password1!',
|
40
|
+
password_confirmation: 'Password1!'
|
41
|
+
)
|
42
|
+
|
43
|
+
assert user.valid?
|
44
|
+
|
45
|
+
user.email = nil
|
46
|
+
|
47
|
+
assert user.invalid?
|
48
|
+
assert_equal(["Email can't be blank"], user.errors.full_messages)
|
49
|
+
end
|
50
|
+
|
51
|
+
test 'email can be updated to be blank if email not required' do
|
52
|
+
user = EmailNotRequiredUser.new(
|
53
|
+
email: 'bob@microsoft.com',
|
54
|
+
password: 'Password1!',
|
55
|
+
password_confirmation: 'Password1!'
|
56
|
+
)
|
57
|
+
|
58
|
+
assert user.valid?
|
59
|
+
|
60
|
+
user.email = nil
|
61
|
+
|
62
|
+
assert user.valid?
|
63
|
+
end
|
64
|
+
|
24
65
|
test 'email must be valid' do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
66
|
+
user = User.new(
|
67
|
+
email: 'bob', password: 'Password1!', password_confirmation: 'Password1!'
|
68
|
+
)
|
69
|
+
|
70
|
+
assert user.invalid?
|
71
|
+
assert_equal(['Email is invalid'], user.errors.full_messages)
|
32
72
|
end
|
33
73
|
|
34
74
|
test 'validate both email and password' do
|
35
|
-
|
36
|
-
|
37
|
-
|
75
|
+
user = User.new(
|
76
|
+
email: 'bob',
|
77
|
+
password: 'password1!',
|
78
|
+
password_confirmation: 'password1!'
|
79
|
+
)
|
80
|
+
|
81
|
+
assert user.invalid?
|
82
|
+
assert_equal(
|
83
|
+
[
|
84
|
+
'Email is invalid',
|
85
|
+
'Password must contain at least one upper-case letter'
|
86
|
+
],
|
87
|
+
user.errors.full_messages
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
test 'password cannot be blank upon creation' do
|
92
|
+
user = User.new(email: 'bob@microsoft.com')
|
93
|
+
|
94
|
+
msgs = ["Password can't be blank"]
|
95
|
+
|
96
|
+
msgs << "Encrypted password can't be blank" if DEVISE_ORM == :mongoid
|
97
|
+
|
98
|
+
assert user.invalid?
|
38
99
|
assert_equal(msgs, user.errors.full_messages)
|
39
|
-
|
100
|
+
end
|
101
|
+
|
102
|
+
test 'password cannot be updated to be blank' do
|
103
|
+
user = User.new(
|
104
|
+
email: 'bob@microsoft.com',
|
105
|
+
password: 'Password1!',
|
106
|
+
password_confirmation: 'Password1!'
|
107
|
+
)
|
108
|
+
|
109
|
+
assert user.valid?
|
110
|
+
|
111
|
+
user.password = nil
|
112
|
+
user.password_confirmation = nil
|
113
|
+
|
114
|
+
assert user.invalid?
|
115
|
+
assert_equal(["Password can't be blank"],user.errors.full_messages)
|
116
|
+
end
|
117
|
+
|
118
|
+
test 'password_confirmation must match password' do
|
119
|
+
user = User.new(
|
120
|
+
email: 'bob@microsoft.com',
|
121
|
+
password: 'Password1!',
|
122
|
+
password_confirmation: 'not the same password'
|
123
|
+
)
|
124
|
+
|
125
|
+
assert user.invalid?
|
126
|
+
assert_equal(
|
127
|
+
["Password confirmation doesn't match Password"],
|
128
|
+
user.errors.full_messages
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
test 'password_confirmation cannot be blank' do
|
133
|
+
user = User.new(
|
134
|
+
email: 'bob@microsoft.com',
|
135
|
+
password: 'Password1!',
|
136
|
+
password_confirmation: ''
|
137
|
+
)
|
138
|
+
|
139
|
+
assert user.invalid?
|
140
|
+
assert_equal(
|
141
|
+
["Password confirmation doesn't match Password"],
|
142
|
+
user.errors.full_messages
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
test 'password_confirmation can be skipped' do
|
147
|
+
user = User.new(
|
148
|
+
email: 'bob@microsoft.com',
|
149
|
+
password: 'Password1!',
|
150
|
+
password_confirmation: nil
|
151
|
+
)
|
152
|
+
|
153
|
+
assert user.valid?
|
40
154
|
end
|
41
155
|
|
42
156
|
test 'password must have capital letter' do
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
157
|
+
user = User.new(
|
158
|
+
email: 'bob@microsoft.com',
|
159
|
+
password: 'password1',
|
160
|
+
password_confirmation: 'password1'
|
161
|
+
)
|
162
|
+
|
163
|
+
assert user.invalid?
|
164
|
+
assert_equal(
|
165
|
+
['Password must contain at least one upper-case letter'],
|
166
|
+
user.errors.full_messages
|
167
|
+
)
|
48
168
|
end
|
49
169
|
|
50
170
|
test 'password must have lowercase letter' do
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
171
|
+
user = User.new(
|
172
|
+
email: 'bob@microsoft.com',
|
173
|
+
password: 'PASSWORD1',
|
174
|
+
password_confirmation: 'PASSWORD1'
|
175
|
+
)
|
176
|
+
|
177
|
+
assert user.invalid?
|
178
|
+
assert_equal(
|
179
|
+
['Password must contain at least one lower-case letter'],
|
180
|
+
user.errors.full_messages
|
181
|
+
)
|
56
182
|
end
|
57
183
|
|
58
184
|
test 'password must have number' do
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
185
|
+
user = User.new(
|
186
|
+
email: 'bob@microsoft.com',
|
187
|
+
password: 'PASSword',
|
188
|
+
password_confirmation: 'PASSword'
|
189
|
+
)
|
190
|
+
|
191
|
+
assert user.invalid?
|
192
|
+
assert_equal(
|
193
|
+
['Password must contain at least one digit'],
|
194
|
+
user.errors.full_messages
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
test 'password must meet minimum length' do
|
199
|
+
user = User.new(
|
200
|
+
email: 'bob@microsoft.com',
|
201
|
+
password: 'Pa3zZ',
|
202
|
+
password_confirmation: 'Pa3zZ'
|
203
|
+
)
|
204
|
+
|
205
|
+
assert user.invalid?
|
206
|
+
assert_equal(
|
207
|
+
['Password is too short (minimum is 7 characters)'],
|
208
|
+
user.errors.full_messages
|
209
|
+
)
|
64
210
|
end
|
65
211
|
|
66
|
-
test '
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
212
|
+
test "new user can't use existing user's email" do
|
213
|
+
options = {
|
214
|
+
email: 'bob@microsoft.com',
|
215
|
+
password: 'Password1!',
|
216
|
+
password_confirmation: 'Password1!',
|
217
|
+
}
|
218
|
+
User.create!(options)
|
219
|
+
user = User.new(options)
|
220
|
+
|
221
|
+
assert user.invalid?
|
222
|
+
if DEVISE_ORM == :active_record
|
223
|
+
assert_equal(['Email has already been taken'], user.errors.full_messages)
|
224
|
+
else
|
225
|
+
assert_equal(['Email is already taken'], user.errors.full_messages)
|
226
|
+
end
|
72
227
|
end
|
73
228
|
|
74
|
-
test '
|
229
|
+
test "new user can't use existing user's email with different casing" do
|
75
230
|
options = {
|
76
|
-
email: '
|
77
|
-
password: '
|
78
|
-
password_confirmation: '
|
231
|
+
email: 'bob@microsoft.com',
|
232
|
+
password: 'Password1!',
|
233
|
+
password_confirmation: 'Password1!',
|
79
234
|
}
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
235
|
+
User.create!(options)
|
236
|
+
options[:email] = 'BOB@MICROSOFT.COM'
|
237
|
+
user = User.new(options)
|
238
|
+
|
239
|
+
assert user.invalid?
|
240
|
+
if DEVISE_ORM == :active_record
|
241
|
+
assert_equal(['Email has already been taken'], user.errors.full_messages)
|
242
|
+
else
|
243
|
+
assert_equal(['Email is already taken'], user.errors.full_messages)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
test 'password cannot equal email for new user' do
|
248
|
+
user = User.new(
|
249
|
+
email: 'Bob1@microsoft.com',
|
250
|
+
password: 'Bob1@microsoft.com',
|
251
|
+
password_confirmation: 'Bob1@microsoft.com'
|
252
|
+
)
|
253
|
+
|
254
|
+
assert user.invalid?
|
255
|
+
assert_equal(
|
256
|
+
['Password must be different than the email.'],
|
257
|
+
user.errors.full_messages
|
258
|
+
)
|
259
|
+
end
|
260
|
+
|
261
|
+
test 'password cannot equal case sensitive version of email for new user' do
|
262
|
+
user = User.new(
|
263
|
+
email: 'bob1@microsoft.com',
|
264
|
+
password: 'BoB1@microsoft.com',
|
265
|
+
password_confirmation: 'BoB1@microsoft.com'
|
266
|
+
)
|
267
|
+
|
268
|
+
assert user.invalid?
|
269
|
+
assert_equal(
|
270
|
+
['Password must be different than the email.'],
|
271
|
+
user.errors.full_messages
|
272
|
+
)
|
273
|
+
end
|
274
|
+
|
275
|
+
test 'password cannot equal email with spaces for new user' do
|
276
|
+
user = User.new(
|
277
|
+
email: 'Bob1@microsoft.com',
|
278
|
+
password: 'Bob1@microsoft.com ',
|
279
|
+
password_confirmation: 'Bob1@microsoft.com '
|
280
|
+
)
|
281
|
+
|
282
|
+
assert user.invalid?
|
283
|
+
assert_equal(
|
284
|
+
['Password must be different than the email.'],
|
285
|
+
user.errors.full_messages
|
286
|
+
)
|
287
|
+
end
|
288
|
+
|
289
|
+
test 'password cannot equal case sensitive version of email with spaces '\
|
290
|
+
'for new user' do
|
291
|
+
user = User.new(
|
292
|
+
email: 'Bob1@microsoft.com',
|
293
|
+
password: ' boB1@microsoft.com ',
|
294
|
+
password_confirmation: ' boB1@microsoft.com '
|
295
|
+
)
|
296
|
+
|
297
|
+
assert user.invalid?
|
298
|
+
assert_equal(
|
299
|
+
['Password must be different than the email.'],
|
300
|
+
user.errors.full_messages
|
301
|
+
)
|
302
|
+
end
|
303
|
+
|
304
|
+
test 'new password cannot equal current password' do
|
305
|
+
user = User.create(
|
306
|
+
email: 'bob@microsoft.com',
|
307
|
+
password: 'Password1!',
|
308
|
+
password_confirmation: 'Password1!'
|
309
|
+
)
|
310
|
+
|
311
|
+
user.password = 'Password1!'
|
312
|
+
|
313
|
+
assert user.invalid?
|
314
|
+
assert_equal(
|
315
|
+
['Password must be different than the current password.'],
|
316
|
+
user.errors.full_messages
|
317
|
+
)
|
318
|
+
end
|
319
|
+
|
320
|
+
test 'should not be included in objects with invalid API' do
|
321
|
+
error = assert_raise RuntimeError do
|
322
|
+
class ::Dog; include Devise::Models::SecureValidatable; end
|
323
|
+
end
|
324
|
+
|
325
|
+
assert_equal('Could not use SecureValidatable on Dog', error.message)
|
84
326
|
end
|
85
327
|
end
|