PLT-1465 Added password requirements (#3489)
* Added password requirements * added tweaks * fixed error code * removed http.StatusNotAcceptable
Этот коммит содержится в:
коммит произвёл
Corey Hulen
родитель
0c3c52b8d3
Коммит
683f713319
@@ -550,7 +550,8 @@ func adminResetPassword(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
newPassword := props["new_password"]
|
||||
if len(newPassword) < model.MIN_PASSWORD_LENGTH {
|
||||
if err := utils.IsPasswordValid(newPassword); err != nil {
|
||||
c.Err = err
|
||||
c.SetInvalidParam("adminResetPassword", "new_password")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -454,20 +454,20 @@ func TestAdminResetPassword(t *testing.T) {
|
||||
Client := th.SystemAdminClient
|
||||
team := th.SystemAdminTeam
|
||||
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
if _, err := Client.AdminResetPassword("", "newpwd"); err == nil {
|
||||
if _, err := Client.AdminResetPassword("", "newpwd1"); err == nil {
|
||||
t.Fatal("Should have errored - empty user id")
|
||||
}
|
||||
|
||||
if _, err := Client.AdminResetPassword("123", "newpwd"); err == nil {
|
||||
if _, err := Client.AdminResetPassword("123", "newpwd1"); err == nil {
|
||||
t.Fatal("Should have errored - bad user id")
|
||||
}
|
||||
|
||||
if _, err := Client.AdminResetPassword("12345678901234567890123456", "newpwd"); err == nil {
|
||||
if _, err := Client.AdminResetPassword("12345678901234567890123456", "newpwd1"); err == nil {
|
||||
t.Fatal("Should have errored - bad user id")
|
||||
}
|
||||
|
||||
@@ -481,15 +481,15 @@ func TestAdminResetPassword(t *testing.T) {
|
||||
LinkUserToTeam(user2, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
if _, err := Client.AdminResetPassword(user.Id, "newpwd"); err != nil {
|
||||
if _, err := Client.AdminResetPassword(user.Id, "newpwd1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Client.Logout()
|
||||
Client.Must(Client.LoginById(user.Id, "newpwd"))
|
||||
Client.Must(Client.LoginById(user.Id, "newpwd1"))
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, err := Client.AdminResetPassword(user.Id, "newpwd"); err == nil {
|
||||
if _, err := Client.AdminResetPassword(user.Id, "newpwd1"); err == nil {
|
||||
t.Fatal("Should have errored - not sytem admin")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1092,13 +1092,13 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
|
||||
Client2 := model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
|
||||
|
||||
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Tester 2", Password: "pwd"}
|
||||
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Tester 2", Password: "passwd1"}
|
||||
user2 = Client2.Must(Client2.CreateUser(user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user2, team)
|
||||
Client2.SetTeamId(team.Id)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client2.Login(user2.Email, "pwd")
|
||||
Client2.Login(user2.Email, "passwd1")
|
||||
Client2.Must(Client2.JoinChannel(channel1.Id))
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, -1, currentEtag); err != nil {
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestCliCreateUserWithTeam(t *testing.T) {
|
||||
email := "success+" + id + "@simulator.amazonses.com"
|
||||
username := "name" + id
|
||||
|
||||
cmd := exec.Command("bash", "-c", `go run ../mattermost.go -create_user -team_name="`+th.SystemAdminTeam.Name+`" -email="`+email+`" -password="mypassword" -username="`+username+`"`)
|
||||
cmd := exec.Command("bash", "-c", `go run ../mattermost.go -create_user -team_name="`+th.SystemAdminTeam.Name+`" -email="`+email+`" -password="mypassword1" -username="`+username+`"`)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Log(string(output))
|
||||
@@ -94,7 +94,7 @@ func TestCliCreateUserWithoutTeam(t *testing.T) {
|
||||
email := "success+" + id + "@simulator.amazonses.com"
|
||||
username := "name" + id
|
||||
|
||||
cmd := exec.Command("bash", "-c", `go run ../mattermost.go -create_user -email="`+email+`" -password="mypassword" -username="`+username+`"`)
|
||||
cmd := exec.Command("bash", "-c", `go run ../mattermost.go -create_user -email="`+email+`" -password="mypassword1" -username="`+username+`"`)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Log(string(output))
|
||||
|
||||
@@ -37,7 +37,7 @@ func TestCreateFromSignupTeam(t *testing.T) {
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
|
||||
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}
|
||||
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello1"}
|
||||
|
||||
ts := model.TeamSignup{Team: team, User: user, Invites: []string{"success+test@simulator.amazonses.com"}, Data: data, Hash: hash}
|
||||
|
||||
@@ -85,12 +85,12 @@ func TestCreateTeam(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(rteam.Data.(*model.Team).Id)
|
||||
|
||||
c1 := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
|
||||
@@ -132,7 +132,7 @@ func TestAddUserToTeam(t *testing.T) {
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
|
||||
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: props["email"], Type: model.TEAM_OPEN}
|
||||
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}
|
||||
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello1"}
|
||||
|
||||
ts := model.TeamSignup{Team: team, User: user, Invites: []string{"success+test@simulator.amazonses.com"}, Data: data, Hash: hash}
|
||||
|
||||
@@ -215,7 +215,7 @@ func TestAddUserToTeamFromInvite(t *testing.T) {
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
|
||||
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: props["email"], Type: model.TEAM_OPEN}
|
||||
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}
|
||||
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello1"}
|
||||
|
||||
ts := model.TeamSignup{Team: team, User: user, Invites: []string{"success+test@simulator.amazonses.com"}, Data: data, Hash: hash}
|
||||
|
||||
@@ -262,12 +262,12 @@ func TestGetAllTeams(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if r1, err := Client.GetAllTeams(); err != nil {
|
||||
@@ -287,7 +287,7 @@ func TestGetAllTeams(t *testing.T) {
|
||||
c.IpAddress = "cmd_line"
|
||||
UpdateUserRoles(c, user, model.ROLE_SYSTEM_ADMIN)
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if r1, err := Client.GetAllTeams(); err != nil {
|
||||
@@ -311,12 +311,12 @@ func TestGetAllTeamListings(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN, AllowOpenInvite: true}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if r1, err := Client.GetAllTeamListings(); err != nil {
|
||||
@@ -336,7 +336,7 @@ func TestGetAllTeamListings(t *testing.T) {
|
||||
c.IpAddress = "cmd_line"
|
||||
UpdateUserRoles(c, user, model.ROLE_SYSTEM_ADMIN)
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if r1, err := Client.GetAllTeams(); err != nil {
|
||||
@@ -360,12 +360,12 @@ func TestTeamPermDelete(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user1, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.Login(user1.Email, "pwd")
|
||||
Client.Login(user1.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
@@ -404,12 +404,12 @@ func TestInviteMembers(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
invite := make(map[string]string)
|
||||
@@ -481,17 +481,17 @@ func TestUpdateTeamDisplayName(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "success+" + model.NewId() + "@simulator.amazonses.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: team.Email, Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user2, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
vteam := &model.Team{DisplayName: team.DisplayName, Name: team.Name, Email: team.Email, Type: team.Type}
|
||||
@@ -500,7 +500,7 @@ func TestUpdateTeamDisplayName(t *testing.T) {
|
||||
t.Fatal("Should have errored, not admin")
|
||||
}
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
|
||||
vteam.DisplayName = ""
|
||||
if _, err := Client.UpdateTeam(vteam); err == nil {
|
||||
@@ -547,7 +547,7 @@ func TestGetMyTeam(t *testing.T) {
|
||||
rteam, _ := Client.CreateTeam(team)
|
||||
team = rteam.Data.(*model.Team)
|
||||
|
||||
user := model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
34
api/user.go
34
api/user.go
@@ -245,6 +245,10 @@ func CreateUser(user *model.User) (*model.User, *model.AppError) {
|
||||
user.MakeNonNil()
|
||||
user.Locale = *utils.Cfg.LocalizationSettings.DefaultClientLocale
|
||||
|
||||
if err := utils.IsPasswordValid(user.Password); user.AuthService == "" && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.User().Save(user); result.Err != nil {
|
||||
l4g.Error(utils.T("api.user.create_user.save.error"), result.Err)
|
||||
return nil, result.Err
|
||||
@@ -1295,6 +1299,11 @@ func updateUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := utils.IsPasswordValid(user.Password); user.Password != "" && err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.User().Update(user, false); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
return
|
||||
@@ -1339,8 +1348,9 @@ func updatePassword(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
newPassword := props["new_password"]
|
||||
if len(newPassword) < 5 {
|
||||
c.SetInvalidParam("updatePassword", "new_password")
|
||||
|
||||
if err := utils.IsPasswordValid(newPassword); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1732,18 +1742,18 @@ func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
func resetPassword(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
newPassword := props["new_password"]
|
||||
if len(newPassword) < model.MIN_PASSWORD_LENGTH {
|
||||
c.SetInvalidParam("resetPassword", "new_password")
|
||||
return
|
||||
}
|
||||
|
||||
code := props["code"]
|
||||
if len(code) != model.PASSWORD_RECOVERY_CODE_SIZE {
|
||||
c.SetInvalidParam("resetPassword", "code")
|
||||
return
|
||||
}
|
||||
|
||||
newPassword := props["new_password"]
|
||||
if err := utils.IsPasswordValid(newPassword); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
c.LogAudit("attempt")
|
||||
|
||||
userId := ""
|
||||
@@ -2042,8 +2052,8 @@ func oauthToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
password := props["password"]
|
||||
if len(password) == 0 {
|
||||
c.SetInvalidParam("oauthToEmail", "password")
|
||||
if err := utils.IsPasswordValid(password); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2174,8 +2184,8 @@ func ldapToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
emailPassword := props["email_password"]
|
||||
if len(emailPassword) == 0 {
|
||||
c.SetInvalidParam("ldapToEmail", "email_password")
|
||||
if err := utils.IsPasswordValid(emailPassword); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
143
api/user_test.go
143
api/user_test.go
@@ -31,7 +31,7 @@ func TestCreateUser(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower("success+"+model.NewId()) + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "hello", Username: "n" + model.NewId()}
|
||||
user := model.User{Email: strings.ToLower("success+"+model.NewId()) + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "hello1", Username: "n" + model.NewId()}
|
||||
|
||||
ruser, err := Client.CreateUser(&user, "")
|
||||
if err != nil {
|
||||
@@ -54,6 +54,7 @@ func TestCreateUser(t *testing.T) {
|
||||
|
||||
ruser.Data.(*model.User).Id = ""
|
||||
ruser.Data.(*model.User).Username = "n" + model.NewId()
|
||||
ruser.Data.(*model.User).Password = "passwd1"
|
||||
if _, err := Client.CreateUser(ruser.Data.(*model.User), ""); err != nil {
|
||||
if err.Message != "An account with that email already exists." {
|
||||
t.Fatal(err)
|
||||
@@ -100,7 +101,7 @@ func TestLogin(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Username: "corey" + model.NewId(), Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Username: "corey" + model.NewId(), Password: "passwd1"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
@@ -167,7 +168,7 @@ func TestLogin(t *testing.T) {
|
||||
team2 := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_INVITE}
|
||||
rteam2 := Client.Must(Client.CreateTeam(&team2))
|
||||
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
|
||||
if _, err := Client.CreateUserFromSignup(&user2, "junk", "1231312"); err == nil {
|
||||
t.Fatal("Should have errored, signed up without hashed email")
|
||||
@@ -193,7 +194,7 @@ func TestLogin(t *testing.T) {
|
||||
Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com",
|
||||
Nickname: "Corey Hulen",
|
||||
Username: "corey" + model.NewId(),
|
||||
Password: "pwd",
|
||||
Password: "passwd1",
|
||||
AuthService: model.USER_AUTH_SERVICE_LDAP,
|
||||
}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
@@ -211,7 +212,7 @@ func TestLoginByLdap(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Username: "corey" + model.NewId(), Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Username: "corey" + model.NewId(), Password: "passwd1"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
@@ -303,12 +304,12 @@ func TestGetUser(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser2, _ := Client.CreateUser(&user2, "")
|
||||
LinkUserToTeam(ruser2.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Data.(*model.User).Id))
|
||||
@@ -316,7 +317,7 @@ func TestGetUser(t *testing.T) {
|
||||
team2 := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam2, _ := Client.CreateTeam(&team2)
|
||||
|
||||
user3 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser3, _ := Client.CreateUser(&user3, "")
|
||||
LinkUserToTeam(ruser3.Data.(*model.User), rteam2.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser3.Data.(*model.User).Id))
|
||||
@@ -385,7 +386,7 @@ func TestGetUser(t *testing.T) {
|
||||
c.IpAddress = "cmd_line"
|
||||
UpdateUserRoles(c, ruser.Data.(*model.User), model.ROLE_SYSTEM_ADMIN)
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
|
||||
if _, err := Client.GetProfiles(rteam2.Data.(*model.Team).Id, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -435,7 +436,7 @@ func TestGetAudits(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
@@ -490,12 +491,12 @@ func TestUserCreateImage(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
|
||||
Client.DoApiGet("/users/"+user.Id+"/image", "", "")
|
||||
|
||||
@@ -525,7 +526,7 @@ func TestUserUploadProfileImage(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
@@ -539,7 +540,7 @@ func TestUserUploadProfileImage(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, upErr := Client.UploadProfileFile(body.Bytes(), writer.FormDataContentType()); upErr == nil {
|
||||
@@ -634,7 +635,7 @@ func TestUserUpdate(t *testing.T) {
|
||||
|
||||
time1 := model.GetMillis()
|
||||
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd", LastActivityAt: time1, LastPingAt: time1, Roles: ""}
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", LastActivityAt: time1, LastPingAt: time1, Roles: ""}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
@@ -643,7 +644,7 @@ func TestUserUpdate(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@@ -678,12 +679,12 @@ func TestUserUpdate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user2, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
user.Nickname = "Tim Timmy"
|
||||
@@ -701,18 +702,18 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "pwd", "newpwd"); err == nil {
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "passwd1", "newpasswd1"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
|
||||
if _, err := Client.UpdateUserPassword("123", "pwd", "newpwd"); err == nil {
|
||||
if _, err := Client.UpdateUserPassword("123", "passwd1", "newpwd"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
@@ -720,11 +721,11 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "pwd", "npwd"); err == nil {
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "passwd1", "npwd"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
if _, err := Client.UpdateUserPassword("12345678901234567890123456", "pwd", "newpwd"); err == nil {
|
||||
if _, err := Client.UpdateUserPassword("12345678901234567890123456", "passwd1", "newpwd1"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
@@ -732,7 +733,7 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "pwd", "newpwd"); err != nil {
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "passwd1", "newpwd1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -741,17 +742,17 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
t.Fatal("LastPasswordUpdate should have changed")
|
||||
}
|
||||
|
||||
if _, err := Client.Login(user.Email, "newpwd"); err != nil {
|
||||
if _, err := Client.Login(user.Email, "newpwd1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user2, team)
|
||||
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "passwd1")
|
||||
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "pwd", "newpwd"); err == nil {
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "passwd1", "newpwd"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
}
|
||||
@@ -763,12 +764,12 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user2, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
@@ -781,7 +782,7 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
t.Fatal("Should have errored, not logged in")
|
||||
}
|
||||
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, err := Client.UpdateUserRoles(data); err == nil {
|
||||
@@ -791,12 +792,12 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user3 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user3, team2)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.Login(user3.Email, "pwd")
|
||||
Client.Login(user3.Email, "passwd1")
|
||||
Client.SetTeamId(team2.Id)
|
||||
|
||||
data["user_id"] = user2.Id
|
||||
@@ -805,7 +806,7 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
t.Fatal("Should have errored, wrong team")
|
||||
}
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
|
||||
data["user_id"] = "junk"
|
||||
|
||||
@@ -962,12 +963,12 @@ func TestUserUpdateDeviceId(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
deviceId := model.PUSH_NOTIFY_APPLE + ":1234567890"
|
||||
|
||||
@@ -993,12 +994,12 @@ func TestUserUpdateActive(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user2, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
@@ -1007,7 +1008,7 @@ func TestUserUpdateActive(t *testing.T) {
|
||||
t.Fatal("Should have errored, not logged in")
|
||||
}
|
||||
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, err := Client.UpdateActive(user.Id, false); err == nil {
|
||||
@@ -1019,19 +1020,19 @@ func TestUserUpdateActive(t *testing.T) {
|
||||
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user3 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user2, team2)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.Login(user3.Email, "pwd")
|
||||
Client.Login(user3.Email, "passwd1")
|
||||
Client.SetTeamId(team2.Id)
|
||||
|
||||
if _, err := Client.UpdateActive(user.Id, false); err == nil {
|
||||
t.Fatal("Should have errored, not yourself")
|
||||
}
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, err := Client.UpdateActive("junk", false); err == nil {
|
||||
@@ -1050,12 +1051,12 @@ func TestUserPermDelete(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user1, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.Login(user1.Email, "pwd")
|
||||
Client.Login(user1.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
@@ -1092,7 +1093,7 @@ func TestSendPasswordReset(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
@@ -1125,7 +1126,7 @@ func TestResetPassword(t *testing.T) {
|
||||
Client := th.SystemAdminClient
|
||||
team := th.SystemAdminTeam
|
||||
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
@@ -1159,16 +1160,16 @@ func TestResetPassword(t *testing.T) {
|
||||
for i := 0; i < model.PASSWORD_RECOVERY_CODE_SIZE; i++ {
|
||||
code += "a"
|
||||
}
|
||||
if _, err := Client.ResetPassword(code, "newpwd"); err == nil {
|
||||
if _, err := Client.ResetPassword(code, "newpwd1"); err == nil {
|
||||
t.Fatal("Should have errored - bad code")
|
||||
}
|
||||
|
||||
if _, err := Client.ResetPassword(recovery.Code, "newpwd"); err != nil {
|
||||
if _, err := Client.ResetPassword(recovery.Code, "newpwd1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Client.Logout()
|
||||
Client.Must(Client.LoginById(user.Id, "newpwd"))
|
||||
Client.Must(Client.LoginById(user.Id, "newpwd1"))
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
Client.Must(Client.SendPasswordReset(user.Email))
|
||||
@@ -1184,7 +1185,7 @@ func TestResetPassword(t *testing.T) {
|
||||
t.Fatal(result.Err)
|
||||
}
|
||||
|
||||
if _, err := Client.ResetPassword(recovery.Code, "newpwd"); err == nil {
|
||||
if _, err := Client.ResetPassword(recovery.Code, "newpwd1"); err == nil {
|
||||
t.Fatal("Should have errored - sso user")
|
||||
}
|
||||
}
|
||||
@@ -1196,7 +1197,7 @@ func TestUserUpdateNotify(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd", Roles: ""}
|
||||
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", Roles: ""}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
@@ -1211,7 +1212,7 @@ func TestUserUpdateNotify(t *testing.T) {
|
||||
t.Fatal("Should have errored - not logged in")
|
||||
}
|
||||
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.Login(user.Email, "passwd1")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if result, err := Client.UpdateUserNotify(data); err != nil {
|
||||
@@ -1279,7 +1280,7 @@ func TestFuzzyUserCreate(t *testing.T) {
|
||||
testEmail = utils.FUZZY_STRINGS_EMAILS[i]
|
||||
}
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + testEmail, Nickname: testName, Password: "hello"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + testEmail, Nickname: testName, Password: "hello1"}
|
||||
|
||||
ruser, err := Client.CreateUser(&user, "")
|
||||
if err != nil {
|
||||
@@ -1297,12 +1298,12 @@ func TestStatuses(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(ruser, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser2 := Client.Must(Client.CreateUser(&user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(ruser2, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Id))
|
||||
@@ -1339,7 +1340,7 @@ func TestEmailToOAuth(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(ruser, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
@@ -1349,7 +1350,7 @@ func TestEmailToOAuth(t *testing.T) {
|
||||
t.Fatal("should have failed - empty data")
|
||||
}
|
||||
|
||||
m["password"] = "pwd"
|
||||
m["password"] = "passwd1"
|
||||
_, err := Client.EmailToOAuth(m)
|
||||
if err == nil {
|
||||
t.Fatal("should have failed - missing team_name, service, email")
|
||||
@@ -1390,12 +1391,12 @@ func TestOAuthToEmail(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(ruser, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser2 := Client.Must(Client.CreateUser(&user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(ruser2, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Id))
|
||||
@@ -1411,7 +1412,7 @@ func TestOAuthToEmail(t *testing.T) {
|
||||
t.Fatal("should have failed - empty data")
|
||||
}
|
||||
|
||||
m["password"] = "pwd"
|
||||
m["password"] = "passwd1"
|
||||
_, err := Client.OAuthToEmail(m)
|
||||
if err == nil {
|
||||
t.Fatal("should have failed - missing team_name, service, email")
|
||||
@@ -1441,7 +1442,7 @@ func TestLDAPToEmail(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(ruser, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
@@ -1453,7 +1454,7 @@ func TestLDAPToEmail(t *testing.T) {
|
||||
t.Fatal("should have failed - empty data")
|
||||
}
|
||||
|
||||
m["email_password"] = "pwd"
|
||||
m["email_password"] = "passwd1"
|
||||
_, err := Client.LDAPToEmail(m)
|
||||
if err == nil {
|
||||
t.Fatal("should have failed - missing team_name, ldap_password, email")
|
||||
@@ -1464,7 +1465,7 @@ func TestLDAPToEmail(t *testing.T) {
|
||||
t.Fatal("should have failed - missing email, ldap_password")
|
||||
}
|
||||
|
||||
m["ldap_password"] = "pwd"
|
||||
m["ldap_password"] = "passwd1"
|
||||
if _, err := Client.LDAPToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - missing email")
|
||||
}
|
||||
@@ -1494,7 +1495,7 @@ func TestEmailToLDAP(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(ruser, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
@@ -1506,7 +1507,7 @@ func TestEmailToLDAP(t *testing.T) {
|
||||
t.Fatal("should have failed - empty data")
|
||||
}
|
||||
|
||||
m["email_password"] = "pwd"
|
||||
m["email_password"] = "passwd1"
|
||||
_, err := Client.EmailToLDAP(m)
|
||||
if err == nil {
|
||||
t.Fatal("should have failed - missing team_name, ldap_id, ldap_password, email")
|
||||
@@ -1522,7 +1523,7 @@ func TestEmailToLDAP(t *testing.T) {
|
||||
t.Fatal("should have failed - missing email, ldap_password")
|
||||
}
|
||||
|
||||
m["ldap_password"] = "pwd"
|
||||
m["ldap_password"] = "passwd1"
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - missing email")
|
||||
}
|
||||
@@ -1545,7 +1546,7 @@ func TestEmailToLDAP(t *testing.T) {
|
||||
t.Fatal("should have failed - bad password")
|
||||
}
|
||||
|
||||
m["email_password"] = "pwd"
|
||||
m["email_password"] = "passwd1"
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - missing ldap bits or user")
|
||||
}
|
||||
@@ -1625,7 +1626,7 @@ func TestGenerateMfaQrCode(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
@@ -1663,7 +1664,7 @@ func TestUpdateMfa(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
@@ -1702,7 +1703,7 @@ func TestCheckMfa(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
@@ -60,6 +60,13 @@
|
||||
"FileLocation": "",
|
||||
"EnableWebhookDebugging": true
|
||||
},
|
||||
"PasswordSettings": {
|
||||
"MinimumLength": 5,
|
||||
"Lowercase": false,
|
||||
"Number": false,
|
||||
"Uppercase": false,
|
||||
"Symbol": false
|
||||
},
|
||||
"FileSettings": {
|
||||
"MaxFileSize": 52428800,
|
||||
"DriverName": "local",
|
||||
|
||||
70
i18n/en.json
70
i18n/en.json
@@ -2679,6 +2679,14 @@
|
||||
"id": "model.config.is_valid.max_users.app_error",
|
||||
"translation": "Invalid maximum users per team for team settings. Must be a positive number."
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.password_length_max_min.app_error",
|
||||
"translation": "Maximum password length must be greater than or equal to minimum password length."
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.password_length.app_error",
|
||||
"translation": "Minimum password length must be a whole number greater than or equal to {{.MinLength}} and less than or equal to {{.MaxLength}}."
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.rate_mem.app_error",
|
||||
"translation": "Invalid memory store size for rate limit settings. Must be a positive number"
|
||||
@@ -3057,7 +3065,67 @@
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd.app_error",
|
||||
"translation": "Invalid password"
|
||||
"translation": "Your password must contain at least {{.Min}} characters."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_lowercase.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_lowercase_uppercase.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter and at least one uppercase letter."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_lowercase_number.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter and at least one number."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_lowercase_symbol.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter and at least one symbol (e.g. \"~!@#$%^&*()\")."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_lowercase_uppercase_number.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter, at least one uppercase letter, and at least one number."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_lowercase_uppercase_symbol.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter, at least one uppercase letter, and at least one symbol (e.g. \"~!@#$%^&*()\")."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_lowercase_number_symbol.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter, at least one number, and at least one symbol (e.g. \"~!@#$%^&*()\")."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_lowercase_uppercase_number_symbol.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter, at least one uppercase letter, at least one number, and at least one symbol (e.g. \"~!@#$%^&*()\")."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_uppercase.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one uppercase letter."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_uppercase_number.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one uppercase letter and at least one number."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_uppercase_symbol.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one uppercase letter and at least one symbol (e.g. \"~!@#$%^&*()\")."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_uppercase_number_symbol.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one uppercase letter, at least one number, and at least one symbol (e.g. \"~!@#$%^&*()\")."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_number.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one number."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_number_symbol.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one number and at least one symbol (e.g. \"~!@#$%^&*()\")."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.pwd_symbol.app_error",
|
||||
"translation": "Your password must contain at least {{.Min}} characters made up of at least one symbol (e.g. \"~!@#$%^&*()\")."
|
||||
},
|
||||
{
|
||||
"id": "model.user.is_valid.team_id.app_error",
|
||||
|
||||
@@ -19,6 +19,9 @@ const (
|
||||
DATABASE_DRIVER_MYSQL = "mysql"
|
||||
DATABASE_DRIVER_POSTGRES = "postgres"
|
||||
|
||||
PASSWORD_MAXIMUM_LENGTH = 64
|
||||
PASSWORD_MINIMUM_LENGTH = 5
|
||||
|
||||
SERVICE_GITLAB = "gitlab"
|
||||
SERVICE_GOOGLE = "google"
|
||||
|
||||
@@ -102,6 +105,14 @@ type LogSettings struct {
|
||||
EnableWebhookDebugging bool
|
||||
}
|
||||
|
||||
type PasswordSettings struct {
|
||||
MinimumLength *int
|
||||
Lowercase *bool
|
||||
Number *bool
|
||||
Uppercase *bool
|
||||
Symbol *bool
|
||||
}
|
||||
|
||||
type FileSettings struct {
|
||||
MaxFileSize *int64
|
||||
DriverName string
|
||||
@@ -259,6 +270,7 @@ type Config struct {
|
||||
TeamSettings TeamSettings
|
||||
SqlSettings SqlSettings
|
||||
LogSettings LogSettings
|
||||
PasswordSettings PasswordSettings
|
||||
FileSettings FileSettings
|
||||
EmailSettings EmailSettings
|
||||
RateLimitSettings RateLimitSettings
|
||||
@@ -356,6 +368,31 @@ func (o *Config) SetDefaults() {
|
||||
*o.ServiceSettings.EnableMultifactorAuthentication = false
|
||||
}
|
||||
|
||||
if o.PasswordSettings.MinimumLength == nil {
|
||||
o.PasswordSettings.MinimumLength = new(int)
|
||||
*o.PasswordSettings.MinimumLength = PASSWORD_MINIMUM_LENGTH
|
||||
}
|
||||
|
||||
if o.PasswordSettings.Lowercase == nil {
|
||||
o.PasswordSettings.Lowercase = new(bool)
|
||||
*o.PasswordSettings.Lowercase = false
|
||||
}
|
||||
|
||||
if o.PasswordSettings.Number == nil {
|
||||
o.PasswordSettings.Number = new(bool)
|
||||
*o.PasswordSettings.Number = false
|
||||
}
|
||||
|
||||
if o.PasswordSettings.Uppercase == nil {
|
||||
o.PasswordSettings.Uppercase = new(bool)
|
||||
*o.PasswordSettings.Uppercase = false
|
||||
}
|
||||
|
||||
if o.PasswordSettings.Symbol == nil {
|
||||
o.PasswordSettings.Symbol = new(bool)
|
||||
*o.PasswordSettings.Symbol = false
|
||||
}
|
||||
|
||||
if o.TeamSettings.RestrictTeamNames == nil {
|
||||
o.TeamSettings.RestrictTeamNames = new(bool)
|
||||
*o.TeamSettings.RestrictTeamNames = true
|
||||
@@ -919,6 +956,10 @@ func (o *Config) IsValid() *AppError {
|
||||
}
|
||||
}
|
||||
|
||||
if *o.PasswordSettings.MinimumLength < PASSWORD_MINIMUM_LENGTH || *o.PasswordSettings.MinimumLength > PASSWORD_MAXIMUM_LENGTH {
|
||||
return NewLocAppError("Config.IsValid", "model.config.is_valid.password_length.app_error", map[string]interface{}{"MinLength": PASSWORD_MINIMUM_LENGTH, "MaxLength": PASSWORD_MAXIMUM_LENGTH}, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -32,15 +32,16 @@ type Customer struct {
|
||||
}
|
||||
|
||||
type Features struct {
|
||||
Users *int `json:"users"`
|
||||
LDAP *bool `json:"ldap"`
|
||||
MFA *bool `json:"mfa"`
|
||||
GoogleSSO *bool `json:"google_sso"`
|
||||
Compliance *bool `json:"compliance"`
|
||||
CustomBrand *bool `json:"custom_brand"`
|
||||
MHPNS *bool `json:"mhpns"`
|
||||
SAML *bool `json:"saml"`
|
||||
FutureFeatures *bool `json:"future_features"`
|
||||
Users *int `json:"users"`
|
||||
LDAP *bool `json:"ldap"`
|
||||
MFA *bool `json:"mfa"`
|
||||
GoogleSSO *bool `json:"google_sso"`
|
||||
Compliance *bool `json:"compliance"`
|
||||
CustomBrand *bool `json:"custom_brand"`
|
||||
MHPNS *bool `json:"mhpns"`
|
||||
SAML *bool `json:"saml"`
|
||||
PasswordRequirements *bool `json:"password_requirements"`
|
||||
FutureFeatures *bool `json:"future_features"`
|
||||
}
|
||||
|
||||
func (f *Features) SetDefaults() {
|
||||
@@ -88,6 +89,11 @@ func (f *Features) SetDefaults() {
|
||||
f.SAML = new(bool)
|
||||
*f.SAML = *f.FutureFeatures
|
||||
}
|
||||
|
||||
if f.PasswordRequirements == nil {
|
||||
f.PasswordRequirements = new(bool)
|
||||
*f.PasswordRequirements = *f.FutureFeatures
|
||||
}
|
||||
}
|
||||
|
||||
func (l *License) IsExpired() bool {
|
||||
|
||||
@@ -27,7 +27,6 @@ const (
|
||||
DEFAULT_LOCALE = "en"
|
||||
USER_AUTH_SERVICE_EMAIL = "email"
|
||||
USER_AUTH_SERVICE_USERNAME = "username"
|
||||
MIN_PASSWORD_LENGTH = 5
|
||||
)
|
||||
|
||||
type User struct {
|
||||
@@ -95,10 +94,6 @@ func (u *User) IsValid() *AppError {
|
||||
return NewLocAppError("User.IsValid", "model.user.is_valid.last_name.app_error", nil, "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if len(u.Password) > 128 {
|
||||
return NewLocAppError("User.IsValid", "model.user.is_valid.pwd.app_error", nil, "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if u.AuthData != nil && len(*u.AuthData) > 128 {
|
||||
return NewLocAppError("User.IsValid", "model.user.is_valid.auth_data.app_error", nil, "user_id="+u.Id)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,13 @@ import (
|
||||
"github.com/pborman/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
LOWERCASE_LETTERS = "abcdefghijklmnopqrstuvwxyz"
|
||||
UPPERCASE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
NUMBERS = "0123456789"
|
||||
SYMBOLS = " !\"\\#$%&'()*+,-./:;<=>?@[]^_`|~"
|
||||
)
|
||||
|
||||
type StringInterface map[string]interface{}
|
||||
type StringMap map[string]string
|
||||
type StringArray []string
|
||||
|
||||
@@ -288,6 +288,14 @@ func getClientConfig(c *model.Config) map[string]string {
|
||||
props["EnableSaml"] = strconv.FormatBool(*c.SamlSettings.Enable)
|
||||
props["SamlLoginButtonText"] = *c.SamlSettings.LoginButtonText
|
||||
}
|
||||
|
||||
if *License.Features.PasswordRequirements {
|
||||
props["PasswordMinimumLength"] = fmt.Sprintf("%v", *c.PasswordSettings.MinimumLength)
|
||||
props["PasswordRequireLowercase"] = strconv.FormatBool(*c.PasswordSettings.Lowercase)
|
||||
props["PasswordRequireUppercase"] = strconv.FormatBool(*c.PasswordSettings.Uppercase)
|
||||
props["PasswordRequireNumber"] = strconv.FormatBool(*c.PasswordSettings.Number)
|
||||
props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol)
|
||||
}
|
||||
}
|
||||
|
||||
return props
|
||||
|
||||
@@ -126,6 +126,7 @@ func getClientLicense(l *model.License) map[string]string {
|
||||
props["Compliance"] = strconv.FormatBool(*l.Features.Compliance)
|
||||
props["CustomBrand"] = strconv.FormatBool(*l.Features.CustomBrand)
|
||||
props["MHPNS"] = strconv.FormatBool(*l.Features.MHPNS)
|
||||
props["PasswordRequirements"] = strconv.FormatBool(*l.Features.PasswordRequirements)
|
||||
props["IssuedAt"] = strconv.FormatInt(l.IssuedAt, 10)
|
||||
props["StartsAt"] = strconv.FormatInt(l.StartsAt, 10)
|
||||
props["ExpiresAt"] = strconv.FormatInt(l.ExpiresAt, 10)
|
||||
|
||||
64
utils/password.go
Обычный файл
64
utils/password.go
Обычный файл
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/mattermost/platform/model"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func IsPasswordValid(password string) *model.AppError {
|
||||
id := "model.user.is_valid.pwd"
|
||||
isError := false
|
||||
min := model.PASSWORD_MINIMUM_LENGTH
|
||||
|
||||
if IsLicensed && *License.Features.PasswordRequirements {
|
||||
if len(password) < *Cfg.PasswordSettings.MinimumLength || len(password) > model.PASSWORD_MAXIMUM_LENGTH {
|
||||
isError = true
|
||||
}
|
||||
|
||||
if *Cfg.PasswordSettings.Lowercase {
|
||||
if !strings.ContainsAny(password, model.LOWERCASE_LETTERS) {
|
||||
isError = true
|
||||
}
|
||||
|
||||
id = id + "_lowercase"
|
||||
}
|
||||
|
||||
if *Cfg.PasswordSettings.Uppercase {
|
||||
if !strings.ContainsAny(password, model.UPPERCASE_LETTERS) {
|
||||
isError = true
|
||||
}
|
||||
|
||||
id = id + "_uppercase"
|
||||
}
|
||||
|
||||
if *Cfg.PasswordSettings.Number {
|
||||
if !strings.ContainsAny(password, model.NUMBERS) {
|
||||
isError = true
|
||||
}
|
||||
|
||||
id = id + "_number"
|
||||
}
|
||||
|
||||
if *Cfg.PasswordSettings.Symbol {
|
||||
if !strings.ContainsAny(password, model.SYMBOLS) {
|
||||
isError = true
|
||||
}
|
||||
|
||||
id = id + "_symbol"
|
||||
}
|
||||
|
||||
min = *Cfg.PasswordSettings.MinimumLength
|
||||
} else if len(password) > model.PASSWORD_MAXIMUM_LENGTH || len(password) < model.PASSWORD_MINIMUM_LENGTH {
|
||||
isError = true
|
||||
min = model.PASSWORD_MINIMUM_LENGTH
|
||||
}
|
||||
|
||||
if isError {
|
||||
return model.NewLocAppError("User.IsValid", id+".app_error", map[string]interface{}{"Min": min}, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func TestGetAccessToken(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := ApiClient.CreateTeam(&team)
|
||||
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Password: "pwd"}
|
||||
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Password: "passwd1"}
|
||||
ruser := ApiClient.Must(ApiClient.CreateUser(&user, "")).Data.(*model.User)
|
||||
api.JoinUserToTeam(rteam.Data.(*model.Team), ruser)
|
||||
store.Must(api.Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
@@ -80,7 +80,7 @@ func TestGetAccessToken(t *testing.T) {
|
||||
}
|
||||
} else {
|
||||
|
||||
ApiClient.Must(ApiClient.LoginById(ruser.Id, "pwd"))
|
||||
ApiClient.Must(ApiClient.LoginById(ruser.Id, "passwd1"))
|
||||
ApiClient.SetTeamId(rteam.Data.(*model.Team).Id)
|
||||
app = ApiClient.Must(ApiClient.RegisterApp(app)).Data.(*model.OAuthApp)
|
||||
|
||||
@@ -196,7 +196,7 @@ func TestIncomingWebhook(t *testing.T) {
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = ApiClient.Must(ApiClient.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
|
||||
user = ApiClient.Must(ApiClient.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(api.Srv.Store.User().VerifyEmail(user.Id))
|
||||
api.JoinUserToTeam(team, user)
|
||||
@@ -205,7 +205,7 @@ func TestIncomingWebhook(t *testing.T) {
|
||||
c.RequestId = model.NewId()
|
||||
c.IpAddress = "cmd_line"
|
||||
api.UpdateUserRoles(c, user, model.ROLE_SYSTEM_ADMIN)
|
||||
ApiClient.Login(user.Email, "pwd")
|
||||
ApiClient.Login(user.Email, "passwd1")
|
||||
ApiClient.SetTeamId(team.Id)
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
|
||||
@@ -428,11 +428,11 @@ export default class AdminSidebar extends React.Component {
|
||||
}
|
||||
/>
|
||||
<AdminSidebarSection
|
||||
name='login'
|
||||
name='password'
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.login'
|
||||
defaultMessage='Login'
|
||||
id='admin.sidebar.password'
|
||||
defaultMessage='Password'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import AdminSettings from './admin_settings.jsx';
|
||||
import BooleanSetting from './boolean_setting.jsx';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import GeneratedSetting from './generated_setting.jsx';
|
||||
import SettingsGroup from './settings_group.jsx';
|
||||
import TextSetting from './text_setting.jsx';
|
||||
|
||||
export default class LoginSettings extends AdminSettings {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.getConfigFromState = this.getConfigFromState.bind(this);
|
||||
|
||||
this.renderSettings = this.renderSettings.bind(this);
|
||||
}
|
||||
|
||||
getConfigFromState(config) {
|
||||
config.EmailSettings.PasswordResetSalt = this.state.passwordResetSalt;
|
||||
config.ServiceSettings.MaximumLoginAttempts = this.parseIntNonZero(this.state.maximumLoginAttempts);
|
||||
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') {
|
||||
config.ServiceSettings.EnableMultifactorAuthentication = this.state.enableMultifactorAuthentication;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
getStateFromConfig(config) {
|
||||
return {
|
||||
passwordResetSalt: config.EmailSettings.PasswordResetSalt,
|
||||
maximumLoginAttempts: config.ServiceSettings.MaximumLoginAttempts,
|
||||
enableMultifactorAuthentication: config.ServiceSettings.EnableMultifactorAuthentication
|
||||
};
|
||||
}
|
||||
|
||||
renderTitle() {
|
||||
return (
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.security.login'
|
||||
defaultMessage='Login'
|
||||
/>
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
|
||||
renderSettings() {
|
||||
let mfaSetting = null;
|
||||
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') {
|
||||
mfaSetting = (
|
||||
<BooleanSetting
|
||||
id='enableMultifactorAuthentication'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.service.mfaTitle'
|
||||
defaultMessage='Enable Multi-factor Authentication:'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.service.mfaDesc'
|
||||
defaultMessage='When true, users will be given the option to add multi-factor authentication to their account. They will need a smartphone and an authenticator app such as Google Authenticator.'
|
||||
/>
|
||||
}
|
||||
value={this.state.enableMultifactorAuthentication}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsGroup>
|
||||
<GeneratedSetting
|
||||
id='passwordResetSalt'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.email.passwordSaltTitle'
|
||||
defaultMessage='Password Reset Salt:'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.email.passwordSaltDescription'
|
||||
defaultMessage='32-character salt added to signing of password reset emails. Randomly generated on install. Click "Regenerate" to create new salt.'
|
||||
/>
|
||||
}
|
||||
value={this.state.passwordResetSalt}
|
||||
onChange={this.handleChange}
|
||||
disabled={this.state.sendEmailNotifications}
|
||||
disabledText={
|
||||
<FormattedMessage
|
||||
id='admin.security.passwordResetSalt.disabled'
|
||||
defaultMessage='Password reset salt cannot be changed while sending emails is disabled.'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<TextSetting
|
||||
id='maximumLoginAttempts'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.service.attemptTitle'
|
||||
defaultMessage='Maximum Login Attempts:'
|
||||
/>
|
||||
}
|
||||
placeholder={Utils.localizeMessage('admin.service.attemptExample', 'Ex "10"')}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.service.attemptDescription'
|
||||
defaultMessage='Login attempts allowed before user is locked out and required to reset password via email.'
|
||||
/>
|
||||
}
|
||||
value={this.state.maximumLoginAttempts}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{mfaSetting}
|
||||
</SettingsGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
310
webapp/components/admin_console/password_settings.jsx
Обычный файл
310
webapp/components/admin_console/password_settings.jsx
Обычный файл
@@ -0,0 +1,310 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import AdminSettings from './admin_settings.jsx';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import SettingsGroup from './settings_group.jsx';
|
||||
import TextSetting from './text_setting.jsx';
|
||||
import BooleanSetting from './boolean_setting.jsx';
|
||||
import Setting from './setting.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import GeneratedSetting from './generated_setting.jsx';
|
||||
|
||||
export default class PasswordSettings extends AdminSettings {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.getConfigFromState = this.getConfigFromState.bind(this);
|
||||
|
||||
this.renderSettings = this.renderSettings.bind(this);
|
||||
|
||||
this.getSampleErrorMsg = this.getSampleErrorMsg.bind(this);
|
||||
|
||||
this.state = Object.assign(this.state, {
|
||||
passwordMinimumLength: props.config.PasswordSettings.MinimumLength,
|
||||
passwordLowercase: props.config.PasswordSettings.Lowercase,
|
||||
passwordNumber: props.config.PasswordSettings.Number,
|
||||
passwordUppercase: props.config.PasswordSettings.Uppercase,
|
||||
passwordSymbol: props.config.PasswordSettings.Symbol,
|
||||
maximumLoginAttempts: props.config.ServiceSettings.MaximumLoginAttempts,
|
||||
enableMultifactorAuthentication: props.config.ServiceSettings.EnableMultifactorAuthentication,
|
||||
passwordResetSalt: props.config.EmailSettings.PasswordResetSalt
|
||||
});
|
||||
|
||||
// Update sample message from config settings
|
||||
let sampleErrorMsgId = 'user.settings.security.passwordError';
|
||||
if (props.config.PasswordSettings.Lowercase) {
|
||||
sampleErrorMsgId = sampleErrorMsgId + 'Lowercase';
|
||||
}
|
||||
if (props.config.PasswordSettings.Uppercase) {
|
||||
sampleErrorMsgId = sampleErrorMsgId + 'Uppercase';
|
||||
}
|
||||
if (props.config.PasswordSettings.Number) {
|
||||
sampleErrorMsgId = sampleErrorMsgId + 'Number';
|
||||
}
|
||||
if (props.config.PasswordSettings.Symbol) {
|
||||
sampleErrorMsgId = sampleErrorMsgId + 'Symbol';
|
||||
}
|
||||
this.sampleErrorMsg = (
|
||||
<FormattedMessage
|
||||
id={sampleErrorMsgId}
|
||||
default='Your password must be at least {min} characters.'
|
||||
values={{
|
||||
min: props.config.PasswordSettings.MinimumLength
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
componentWillUpdate() {
|
||||
this.sampleErrorMsg = this.getSampleErrorMsg();
|
||||
}
|
||||
|
||||
getConfigFromState(config) {
|
||||
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
|
||||
config.PasswordSettings.MinimumLength = this.parseIntNonZero(this.state.passwordMinimumLength, 10);
|
||||
config.PasswordSettings.Lowercase = this.refs.lowercase.checked;
|
||||
config.PasswordSettings.Uppercase = this.refs.uppercase.checked;
|
||||
config.PasswordSettings.Number = this.refs.number.checked;
|
||||
config.PasswordSettings.Symbol = this.refs.symbol.checked;
|
||||
}
|
||||
|
||||
config.ServiceSettings.MaximumLoginAttempts = this.parseIntNonZero(this.state.maximumLoginAttempts);
|
||||
config.EmailSettings.PasswordResetSalt = this.state.passwordResetSalt;
|
||||
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') {
|
||||
config.ServiceSettings.EnableMultifactorAuthentication = this.state.enableMultifactorAuthentication;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
getSampleErrorMsg() {
|
||||
if (this.props.config.PasswordSettings.MinimumLength > Constants.MAX_PASSWORD_LENGTH || this.props.config.PasswordSettings.MinimumLength < Constants.MIN_PASSWORD_LENGTH) {
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='user.settings.security.passwordMinLength'
|
||||
default='Invalid minimum length, cannot show preview.'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let sampleErrorMsgId = 'user.settings.security.passwordError';
|
||||
if (this.refs.lowercase.checked) {
|
||||
sampleErrorMsgId = sampleErrorMsgId + 'Lowercase';
|
||||
}
|
||||
if (this.refs.uppercase.checked) {
|
||||
sampleErrorMsgId = sampleErrorMsgId + 'Uppercase';
|
||||
}
|
||||
if (this.refs.number.checked) {
|
||||
sampleErrorMsgId = sampleErrorMsgId + 'Number';
|
||||
}
|
||||
if (this.refs.symbol.checked) {
|
||||
sampleErrorMsgId = sampleErrorMsgId + 'Symbol';
|
||||
}
|
||||
return (
|
||||
<FormattedMessage
|
||||
id={sampleErrorMsgId}
|
||||
default='Your password must be at least {min} characters.'
|
||||
values={{
|
||||
min: this.props.config.PasswordSettings.MinimumLength
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderTitle() {
|
||||
return (
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.security.password'
|
||||
defaultMessage='Password'
|
||||
/>
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
|
||||
renderSettings() {
|
||||
let mfaSetting = null;
|
||||
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') {
|
||||
mfaSetting = (
|
||||
<BooleanSetting
|
||||
id='enableMultifactorAuthentication'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.service.mfaTitle'
|
||||
defaultMessage='Enable Multi-factor Authentication:'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.service.mfaDesc'
|
||||
defaultMessage='When true, users will be given the option to add multi-factor authentication to their account. They will need a smartphone and an authenticator app such as Google Authenticator.'
|
||||
/>
|
||||
}
|
||||
value={this.state.enableMultifactorAuthentication}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let passwordSettings = null;
|
||||
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
|
||||
passwordSettings = (
|
||||
<div>
|
||||
<TextSetting
|
||||
id='passwordMinimumLength'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.password.minimumLength'
|
||||
defaultMessage='Minimum Password Length:'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.password.minimumLengthDescription'
|
||||
defaultMessage='Minimum number of characters required for a valid password. Must be a whole number greater than or equal to {min} and less than or equal to {max}.'
|
||||
values={{
|
||||
min: Constants.MIN_PASSWORD_LENGTH,
|
||||
max: Constants.MAX_PASSWORD_LENGTH
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value={this.state.passwordMinimumLength}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<Setting
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='passwordRequirements'
|
||||
defaultMessage='Password Requirements:'
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<label className='checkbox-inline'>
|
||||
<input
|
||||
type='checkbox'
|
||||
ref='lowercase'
|
||||
defaultChecked={this.state.passwordLowercase}
|
||||
name='admin.password.lowercase'
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='admin.password.lowercase'
|
||||
defaultMessage='At least one lowercase letter'
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label className='checkbox-inline'>
|
||||
<input
|
||||
type='checkbox'
|
||||
ref='uppercase'
|
||||
defaultChecked={this.state.passwordUppercase}
|
||||
name='admin.password.uppercase'
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='admin.password.uppercase'
|
||||
defaultMessage='At least one uppercase letter'
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label className='checkbox-inline'>
|
||||
<input
|
||||
type='checkbox'
|
||||
ref='number'
|
||||
defaultChecked={this.state.passwordNumber}
|
||||
name='admin.password.number'
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='admin.password.number'
|
||||
defaultMessage='At least one number'
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label className='checkbox-inline'>
|
||||
<input
|
||||
type='checkbox'
|
||||
ref='symbol'
|
||||
defaultChecked={this.state.passwordSymbol}
|
||||
name='admin.password.symbol'
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='admin.password.symbol'
|
||||
defaultMessage='At least one symbol (e.g. "~!@#$%^&*()")'
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<br/>
|
||||
<label>
|
||||
<FormattedMessage
|
||||
id='admin.password.preview'
|
||||
defaultMessage='Error message preview:'
|
||||
/>
|
||||
</label>
|
||||
<br/>
|
||||
{this.sampleErrorMsg}
|
||||
</div>
|
||||
</Setting>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsGroup>
|
||||
{passwordSettings}
|
||||
<GeneratedSetting
|
||||
id='passwordResetSalt'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.email.passwordSaltTitle'
|
||||
defaultMessage='Password Reset Salt:'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.email.passwordSaltDescription'
|
||||
defaultMessage='32-character salt added to signing of password reset emails. Randomly generated on install. Click "Regenerate" to create new salt.'
|
||||
/>
|
||||
}
|
||||
value={this.state.passwordResetSalt}
|
||||
onChange={this.handleChange}
|
||||
disabled={this.state.sendEmailNotifications}
|
||||
disabledText={
|
||||
<FormattedMessage
|
||||
id='admin.security.passwordResetSalt.disabled'
|
||||
defaultMessage='Password reset salt cannot be changed while sending emails is disabled.'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<TextSetting
|
||||
id='maximumLoginAttempts'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.service.attemptTitle'
|
||||
defaultMessage='Maximum Login Attempts:'
|
||||
/>
|
||||
}
|
||||
placeholder={Utils.localizeMessage('admin.service.attemptExample', 'Ex "10"')}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.service.attemptDescription'
|
||||
defaultMessage='Login attempts allowed before user is locked out and required to reset password via email.'
|
||||
/>
|
||||
}
|
||||
value={this.state.maximumLoginAttempts}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{mfaSetting}
|
||||
</SettingsGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -46,9 +46,17 @@ export default class LDAPToEmail extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
const passwordErr = Utils.isValidPassword(password);
|
||||
if (passwordErr !== '') {
|
||||
this.setState({
|
||||
passwordError: passwordErr
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmPassword = ReactDOM.findDOMNode(this.refs.passwordconfirm).value;
|
||||
if (!confirmPassword || password !== confirmPassword) {
|
||||
state.confirmError = Utils.localizeMessage('claim.ldap_to_email.pwdNotMatch', 'Passwords do not match.');
|
||||
state.error = Utils.localizeMessage('claim.ldap_to_email.pwdNotMatch', 'Passwords do not match.');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ export default class OAuthToEmail extends React.Component {
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
submit(e) {
|
||||
e.preventDefault();
|
||||
const state = {};
|
||||
@@ -29,6 +30,14 @@ export default class OAuthToEmail extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
const passwordErr = Utils.isValidPassword(password);
|
||||
if (passwordErr !== '') {
|
||||
this.setState({
|
||||
error: passwordErr
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmPassword = ReactDOM.findDOMNode(this.refs.passwordconfirm).value;
|
||||
if (!confirmPassword || password !== confirmPassword) {
|
||||
state.error = Utils.localizeMessage('claim.oauth_to_email.pwdNotMatch', 'Password do not match.');
|
||||
|
||||
@@ -317,21 +317,14 @@ export default class SignupUserComplete extends React.Component {
|
||||
}
|
||||
|
||||
const providedPassword = ReactDOM.findDOMNode(this.refs.password).value;
|
||||
if (!providedPassword || providedPassword.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
const pwdError = Utils.isValidPassword(providedPassword);
|
||||
if (pwdError != null) {
|
||||
this.setState({
|
||||
nameError: '',
|
||||
emailError: '',
|
||||
passwordError: (
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.passwordLength'
|
||||
values={{
|
||||
min: Constants.MIN_PASSWORD_LENGTH
|
||||
}}
|
||||
/>
|
||||
),
|
||||
passwordError: pwdError,
|
||||
serverError: ''
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
|
||||
@@ -26,7 +26,7 @@ const holders = defineMessages({
|
||||
},
|
||||
passwordLengthError: {
|
||||
id: 'user.settings.security.passwordLengthError',
|
||||
defaultMessage: 'New passwords must be at least {chars} characters'
|
||||
defaultMessage: 'New passwords must be at least {min} characters and at most {max} characters.'
|
||||
},
|
||||
passwordMatchError: {
|
||||
id: 'user.settings.security.passwordMatchError',
|
||||
@@ -90,8 +90,12 @@ class SecurityTab extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPassword.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
this.setState({passwordError: formatMessage(holders.passwordLengthError, {chars: Constants.MIN_PASSWORD_LENGTH}), serverError: ''});
|
||||
const passwordErr = Utils.isValidPassword(newPassword);
|
||||
if (passwordErr !== '') {
|
||||
this.setState({
|
||||
passwordError: passwordErr,
|
||||
serverError: ''
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -407,6 +407,15 @@
|
||||
"admin.notifications.email": "Email",
|
||||
"admin.notifications.push": "Mobile Push",
|
||||
"admin.notifications.title": "Notification Settings",
|
||||
"admin.password.lowercase": "At least one lowercase letter",
|
||||
"admin.password.minimumLength": "Minimum Password Length:",
|
||||
"admin.password.minimumLengthDescription": "Minimum number of characters required for a valid password. Must be a whole number greater than or equal to {min} and less than or equal to {max}.",
|
||||
"admin.password.number": "At least one number",
|
||||
"admin.password.preview": "Error message preview",
|
||||
"admin.password.requirements": "Password Requirements:",
|
||||
"admin.password.requirementsDescription": "Character types required in a valid password.",
|
||||
"admin.password.symbol": "At least one symbol (e.g. \"~!@#$%^&*()\")",
|
||||
"admin.password.uppercase": "At least one uppercase letter",
|
||||
"admin.privacy.showEmailDescription": "When false, hides email address of users from other users in the user interface, including team owners and team administrators. Used when system is set up for managing teams where some users choose to keep their contact information private.",
|
||||
"admin.privacy.showEmailTitle": "Show Email Address: ",
|
||||
"admin.privacy.showFullNameDescription": "When false, hides full name of users from other users, including team owners and team administrators. Username is shown in place of full name.",
|
||||
@@ -504,7 +513,16 @@
|
||||
"admin.select_team.close": "Close",
|
||||
"admin.select_team.select": "Select",
|
||||
"admin.select_team.selectTeam": "Select Team",
|
||||
"admin.service.attemptDescription": "Login attempts allowed before user is locked out and required to reset password via email.",
|
||||
"admin.security.password": "Password",
|
||||
"admin.security.login": "Login",
|
||||
"admin.security.connection": "Connections",
|
||||
"admin.security.public_links": "Public Links",
|
||||
"admin.security.session": "Sessions",
|
||||
"admin.security.signup": "Signup",
|
||||
"admin.security.requireEmailVerification.disabled": "Email verification cannot be changed while sending emails is disabled.",
|
||||
"admin.security.passwordResetSalt.disabled": "Password reset salt cannot be changed while sending emails is disabled.",
|
||||
"admin.security.inviteSalt.disabled": "Invite salt cannot be changed while sending emails is disabled.",
|
||||
"admin.service.attemptDescription": "Number of login attempts allowed before a user is locked out and required to reset their password via email.",
|
||||
"admin.service.attemptExample": "Ex \"10\"",
|
||||
"admin.service.attemptTitle": "Maximum Login Attempts:",
|
||||
"admin.service.cmdsDesc": "When true, user created slash commands will be allowed.",
|
||||
@@ -575,6 +593,7 @@
|
||||
"admin.sidebar.localization": "Localization",
|
||||
"admin.sidebar.logging": "Logging",
|
||||
"admin.sidebar.login": "Login",
|
||||
"admin.sidebar.password": "Password",
|
||||
"admin.sidebar.logs": "Logs",
|
||||
"admin.sidebar.notifications": "Notifications",
|
||||
"admin.sidebar.other": "OTHER",
|
||||
@@ -1632,7 +1651,23 @@
|
||||
"user.settings.security.password": "Password",
|
||||
"user.settings.security.passwordGitlabCantUpdate": "Login occurs through GitLab. Password cannot be updated.",
|
||||
"user.settings.security.passwordLdapCantUpdate": "Login occurs through LDAP. Password cannot be updated.",
|
||||
"user.settings.security.passwordLengthError": "New passwords must be at least {chars} characters",
|
||||
"user.settings.security.passwordError": "Your password must contain at least {min} characters.",
|
||||
"user.settings.security.passwordErrorLowercase": "Your password must contain at least {min} characters made up of at least one lowercase letter.",
|
||||
"user.settings.security.passwordErrorLowercaseNumber": "Your password must contain at least {min} characters made up of at least one lowercase letter and at least one number.",
|
||||
"user.settings.security.passwordErrorLowercaseUppercase": "Your password must contain at least {min} characters made up of at least one lowercase letter and at least one uppercase letter.",
|
||||
"user.settings.security.passwordErrorLowercaseSymbol": "Your password must contain at least {min} characters made up of at least one lowercase letter and at least one symbol (e.g. \"~!@#$%^&*()\").",
|
||||
"user.settings.security.passwordErrorLowercaseUppercaseNumber": "Your password must contain at least {min} characters made up of at least one lowercase letter, at least one uppercase letter, and at least one number.",
|
||||
"user.settings.security.passwordErrorLowercaseNumberSymbol": "Your password must contain at least {min} characters made up of at least one lowercase letter, at least one number, and at least one symbol (e.g. \"~!@#$%^&*()\").",
|
||||
"user.settings.security.passwordErrorLowercaseUppercaseSymbol": "Your password must contain at least {min} characters made up of at least one lowercase letter, at least one uppercase letter, and at least one symbol (e.g. \"~!@#$%^&*()\").",
|
||||
"user.settings.security.passwordErrorLowercaseUppercaseNumberSymbol": "Your password must contain at least {min} characters made up of at least one lowercase letter, at least one uppercase letter, at least one number, and at least one symbol (e.g. \"~!@#$%^&*()\").",
|
||||
"user.settings.security.passwordErrorUppercase": "Your password must contain at least {min} characters made up of at least one uppercase letter.",
|
||||
"user.settings.security.passwordErrorUppercaseNumber": "Your password must contain at least {min} characters made up of at least one uppercase letter and at least one number.",
|
||||
"user.settings.security.passwordErrorUppercaseSymbol": "Your password must contain at least {min} characters made up of at least one uppercase letter and at least one symbol (e.g. \"~!@#$%^&*()\").",
|
||||
"user.settings.security.passwordErrorUppercaseNumberSymbol": "Your password must contain at least {min} characters made up of at least one uppercase letter, at least one number, and at least one symbol (e.g. \"~!@#$%^&*()\").",
|
||||
"user.settings.security.passwordErrorNumber": "Your password must contain at least {min} characters made up of at least one number.",
|
||||
"user.settings.security.passwordErrorNumberSymbol": "Your password must contain at least {min} characters made up of at least one number and at least one symbol (e.g. \"~!@#$%^&*()\").",
|
||||
"user.settings.security.passwordErrorSymbol": "Your password must contain at least {min} characters made up of at least one symbol (e.g. \"~!@#$%^&*()\").",
|
||||
"user.settings.security.passwordMinLength": "Invalid minimum length, cannot show preview.",
|
||||
"user.settings.security.passwordMatchError": "The new passwords you entered do not match",
|
||||
"user.settings.security.retypePassword": "Retype New Password",
|
||||
"user.settings.security.saml": "SAML",
|
||||
|
||||
@@ -17,7 +17,7 @@ import GitLabSettings from 'components/admin_console/gitlab_settings.jsx';
|
||||
import LdapSettings from 'components/admin_console/ldap_settings.jsx';
|
||||
import SamlSettings from 'components/admin_console/saml_settings.jsx';
|
||||
import SignupSettings from 'components/admin_console/signup_settings.jsx';
|
||||
import LoginSettings from 'components/admin_console/login_settings.jsx';
|
||||
import PasswordSettings from 'components/admin_console/password_settings.jsx';
|
||||
import PublicLinkSettings from 'components/admin_console/public_link_settings.jsx';
|
||||
import SessionSettings from 'components/admin_console/session_settings.jsx';
|
||||
import ConnectionSettings from 'components/admin_console/connection_settings.jsx';
|
||||
@@ -103,8 +103,8 @@ export default (
|
||||
component={SignupSettings}
|
||||
/>
|
||||
<Route
|
||||
path='login'
|
||||
component={LoginSettings}
|
||||
path='password'
|
||||
component={PasswordSettings}
|
||||
/>
|
||||
<Route
|
||||
path='public_links'
|
||||
|
||||
@@ -758,7 +758,7 @@ export default {
|
||||
MAX_USERNAME_LENGTH: 22,
|
||||
MAX_NICKNAME_LENGTH: 22,
|
||||
MIN_PASSWORD_LENGTH: 5,
|
||||
MAX_PASSWORD_LENGTH: 50,
|
||||
MAX_PASSWORD_LENGTH: 64,
|
||||
MIN_TRIGGER_LENGTH: 1,
|
||||
MAX_TRIGGER_LENGTH: 128,
|
||||
TIME_SINCE_UPDATE_INTERVAL: 30000,
|
||||
|
||||
@@ -14,10 +14,13 @@ import * as AsyncClient from './async_client.jsx';
|
||||
import Client from './web_client.jsx';
|
||||
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import icon50 from 'images/icon50x50.png';
|
||||
import bing from 'images/bing.mp3';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export function isEmail(email) {
|
||||
// writing a regex to match all valid email addresses is really, really hard (see http://stackoverflow.com/a/201378)
|
||||
// so we just do a simple check and rely on a verification email to tell if it's a real address
|
||||
@@ -1366,4 +1369,67 @@ export function canCreateCustomEmoji(user) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function isValidPassword(password) {
|
||||
let errorMsg = '';
|
||||
let errorId = 'user.settings.security.passwordError';
|
||||
let error = false;
|
||||
let minimumLength = Constants.MIN_PASSWORD_LENGTH;
|
||||
|
||||
if (global.window.mm_config.BuildEnterpriseReady === 'true' && global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
|
||||
if (password.length < parseInt(global.window.mm_config.PasswordMinimumLength, 10) || password.length > Constants.MAX_PASSWORD_LENGTH) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (global.window.mm_config.PasswordRequireLowercase === 'true') {
|
||||
if (!password.match(/[a-z]/)) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
errorId = errorId + 'Lowercase';
|
||||
}
|
||||
|
||||
if (global.window.mm_config.PasswordRequireUppercase === 'true') {
|
||||
if (!password.match(/[0-9]/)) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
errorId = errorId + 'Uppercase';
|
||||
}
|
||||
|
||||
if (global.window.mm_config.PasswordRequireNumber === 'true') {
|
||||
if (!password.match(/[A-Z]/)) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
errorId = errorId + 'Number';
|
||||
}
|
||||
|
||||
if (global.window.mm_config.PasswordRequireSymbol === 'true') {
|
||||
if (!password.match(/[ !"\\#$%&'()*+,-./:;<=>?@[\]^_`|~]/)) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
errorId = errorId + 'Symbol';
|
||||
}
|
||||
|
||||
minimumLength = global.window.mm_config.PasswordMinimumLength;
|
||||
} else if (password.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
errorMsg = (
|
||||
<FormattedMessage
|
||||
id={errorId}
|
||||
default='Your password must be at least {min} characters.'
|
||||
values={{
|
||||
min: minimumLength
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user