1// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2// See LICENSE.txt for license information.
3
4package users
5
6import (
7	"strings"
8	"testing"
9
10	"github.com/stretchr/testify/assert"
11	"github.com/stretchr/testify/require"
12
13	"github.com/mattermost/mattermost-server/v6/model"
14)
15
16func TestComparePassword(t *testing.T) {
17	hash := HashPassword("Test")
18
19	assert.NoError(t, ComparePassword(hash, "Test"), "Passwords don't match")
20	assert.Error(t, ComparePassword(hash, "Test2"), "Passwords should not have matched")
21}
22
23func TestIsPasswordValidWithSettings(t *testing.T) {
24	for name, tc := range map[string]struct {
25		Password      string
26		Settings      *model.PasswordSettings
27		ExpectedError string
28	}{
29		"Short": {
30			Password: strings.Repeat("x", 3),
31			Settings: &model.PasswordSettings{
32				MinimumLength: model.NewInt(3),
33				Lowercase:     model.NewBool(false),
34				Uppercase:     model.NewBool(false),
35				Number:        model.NewBool(false),
36				Symbol:        model.NewBool(false),
37			},
38		},
39		"Long": {
40			Password: strings.Repeat("x", model.PasswordMaximumLength),
41			Settings: &model.PasswordSettings{
42				Lowercase: model.NewBool(false),
43				Uppercase: model.NewBool(false),
44				Number:    model.NewBool(false),
45				Symbol:    model.NewBool(false),
46			},
47		},
48		"TooShort": {
49			Password: strings.Repeat("x", 2),
50			Settings: &model.PasswordSettings{
51				MinimumLength: model.NewInt(3),
52				Lowercase:     model.NewBool(false),
53				Uppercase:     model.NewBool(false),
54				Number:        model.NewBool(false),
55				Symbol:        model.NewBool(false),
56			},
57			ExpectedError: "model.user.is_valid.pwd.app_error",
58		},
59		"TooLong": {
60			Password: strings.Repeat("x", model.PasswordMaximumLength+1),
61			Settings: &model.PasswordSettings{
62				Lowercase: model.NewBool(false),
63				Uppercase: model.NewBool(false),
64				Number:    model.NewBool(false),
65				Symbol:    model.NewBool(false),
66			},
67			ExpectedError: "model.user.is_valid.pwd.app_error",
68		},
69		"MissingLower": {
70			Password: "AAAAAAAAAAASD123!@#",
71			Settings: &model.PasswordSettings{
72				Lowercase: model.NewBool(true),
73				Uppercase: model.NewBool(false),
74				Number:    model.NewBool(false),
75				Symbol:    model.NewBool(false),
76			},
77			ExpectedError: "model.user.is_valid.pwd_lowercase.app_error",
78		},
79		"MissingUpper": {
80			Password: "aaaaaaaaaaaaasd123!@#",
81			Settings: &model.PasswordSettings{
82				Uppercase: model.NewBool(true),
83				Lowercase: model.NewBool(false),
84				Number:    model.NewBool(false),
85				Symbol:    model.NewBool(false),
86			},
87			ExpectedError: "model.user.is_valid.pwd_uppercase.app_error",
88		},
89		"MissingNumber": {
90			Password: "asasdasdsadASD!@#",
91			Settings: &model.PasswordSettings{
92				Number:    model.NewBool(true),
93				Lowercase: model.NewBool(false),
94				Uppercase: model.NewBool(false),
95				Symbol:    model.NewBool(false),
96			},
97			ExpectedError: "model.user.is_valid.pwd_number.app_error",
98		},
99		"MissingSymbol": {
100			Password: "asdasdasdasdasdASD123",
101			Settings: &model.PasswordSettings{
102				Symbol:    model.NewBool(true),
103				Lowercase: model.NewBool(false),
104				Uppercase: model.NewBool(false),
105				Number:    model.NewBool(false),
106			},
107			ExpectedError: "model.user.is_valid.pwd_symbol.app_error",
108		},
109		"MissingMultiple": {
110			Password: "asdasdasdasdasdasd",
111			Settings: &model.PasswordSettings{
112				Lowercase: model.NewBool(true),
113				Uppercase: model.NewBool(true),
114				Number:    model.NewBool(true),
115				Symbol:    model.NewBool(true),
116			},
117			ExpectedError: "model.user.is_valid.pwd_lowercase_uppercase_number_symbol.app_error",
118		},
119		"Everything": {
120			Password: "asdASD!@#123",
121			Settings: &model.PasswordSettings{
122				Lowercase: model.NewBool(true),
123				Uppercase: model.NewBool(true),
124				Number:    model.NewBool(true),
125				Symbol:    model.NewBool(true),
126			},
127		},
128	} {
129		tc.Settings.SetDefaults()
130		t.Run(name, func(t *testing.T) {
131			if err := IsPasswordValidWithSettings(tc.Password, tc.Settings); tc.ExpectedError == "" {
132				assert.NoError(t, err)
133			} else {
134				invErr, ok := err.(*ErrInvalidPassword)
135				require.True(t, ok)
136				assert.Equal(t, tc.ExpectedError, invErr.Id())
137			}
138		})
139	}
140}
141