diff options
-rw-r--r-- | api4/user_test.go | 250 | ||||
-rw-r--r-- | i18n/en.json | 8 | ||||
-rw-r--r-- | model/client4.go | 34 |
3 files changed, 289 insertions, 3 deletions
diff --git a/api4/user_test.go b/api4/user_test.go index d73aea292..81c410e96 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -4,10 +4,12 @@ package api4 import ( + "fmt" "net/http" "strconv" "strings" "testing" + "time" "github.com/mattermost/platform/app" "github.com/mattermost/platform/model" @@ -84,6 +86,251 @@ func TestCreateUser(t *testing.T) { } } +func TestCreateUserWithHash(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.Client + + t.Run("CreateWithHashHappyPath", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + props := make(map[string]string) + props["email"] = user.Email + props["id"] = th.BasicTeam.Id + props["display_name"] = th.BasicTeam.DisplayName + props["name"] = th.BasicTeam.Name + props["time"] = fmt.Sprintf("%v", model.GetMillis()) + data := model.MapToJson(props) + hash := utils.HashSha256(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) + + ruser, resp := Client.CreateUserWithHash(&user, hash, data) + CheckNoError(t, resp) + CheckCreatedStatus(t, resp) + + Client.Login(user.Email, user.Password) + if ruser.Nickname != user.Nickname { + t.Fatal("nickname didn't match") + } + if ruser.Roles != model.ROLE_SYSTEM_USER.Id { + t.Log(ruser.Roles) + t.Fatal("did not clear roles") + } + CheckUserSanitization(t, ruser) + }) + + t.Run("NoHashAndNoData", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + props := make(map[string]string) + props["email"] = user.Email + props["id"] = th.BasicTeam.Id + props["display_name"] = th.BasicTeam.DisplayName + props["name"] = th.BasicTeam.Name + props["time"] = fmt.Sprintf("%v", model.GetMillis()) + data := model.MapToJson(props) + hash := utils.HashSha256(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) + + _, resp := Client.CreateUserWithHash(&user, "", data) + CheckBadRequestStatus(t, resp) + CheckErrorMessage(t, resp, "api.user.create_user.missing_hash_or_data.app_error") + + _, resp = Client.CreateUserWithHash(&user, hash, "") + CheckBadRequestStatus(t, resp) + CheckErrorMessage(t, resp, "api.user.create_user.missing_hash_or_data.app_error") + }) + + t.Run("HashExpired", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + timeNow := time.Now() + past49Hours := timeNow.Add(-49*time.Hour).UnixNano() / int64(time.Millisecond) + + props := make(map[string]string) + props["email"] = user.Email + props["id"] = th.BasicTeam.Id + props["display_name"] = th.BasicTeam.DisplayName + props["name"] = th.BasicTeam.Name + props["time"] = fmt.Sprintf("%v", past49Hours) + data := model.MapToJson(props) + hash := utils.HashSha256(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) + + _, resp := Client.CreateUserWithHash(&user, hash, data) + CheckInternalErrorStatus(t, resp) + CheckErrorMessage(t, resp, "api.user.create_user.signup_link_expired.app_error") + }) + + t.Run("WrongHash", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + props := make(map[string]string) + props["email"] = user.Email + props["id"] = th.BasicTeam.Id + props["display_name"] = th.BasicTeam.DisplayName + props["name"] = th.BasicTeam.Name + props["time"] = fmt.Sprintf("%v", model.GetMillis()) + data := model.MapToJson(props) + hash := utils.HashSha256(fmt.Sprintf("%v:%v", data, "WrongHash")) + + _, resp := Client.CreateUserWithHash(&user, hash, data) + CheckInternalErrorStatus(t, resp) + CheckErrorMessage(t, resp, "api.user.create_user.signup_link_invalid.app_error") + }) + + t.Run("EnableUserCreationDisable", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + props := make(map[string]string) + props["email"] = user.Email + props["id"] = th.BasicTeam.Id + props["display_name"] = th.BasicTeam.DisplayName + props["name"] = th.BasicTeam.Name + props["time"] = fmt.Sprintf("%v", model.GetMillis()) + data := model.MapToJson(props) + hash := utils.HashSha256(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) + + canCreateAccount := utils.Cfg.TeamSettings.EnableUserCreation + defer func() { + utils.Cfg.TeamSettings.EnableUserCreation = canCreateAccount + }() + utils.Cfg.TeamSettings.EnableUserCreation = false + + _, resp := Client.CreateUserWithHash(&user, hash, data) + CheckNotImplementedStatus(t, resp) + CheckErrorMessage(t, resp, "api.user.create_user.signup_email_disabled.app_error") + }) + + t.Run("EnableOpenServerDisable", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + props := make(map[string]string) + props["email"] = user.Email + props["id"] = th.BasicTeam.Id + props["display_name"] = th.BasicTeam.DisplayName + props["name"] = th.BasicTeam.Name + props["time"] = fmt.Sprintf("%v", model.GetMillis()) + data := model.MapToJson(props) + hash := utils.HashSha256(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) + + openServer := *utils.Cfg.TeamSettings.EnableOpenServer + defer func() { + *utils.Cfg.TeamSettings.EnableOpenServer = openServer + }() + *utils.Cfg.TeamSettings.EnableOpenServer = false + + ruser, resp := Client.CreateUserWithHash(&user, hash, data) + CheckNoError(t, resp) + CheckCreatedStatus(t, resp) + + Client.Login(user.Email, user.Password) + if ruser.Nickname != user.Nickname { + t.Fatal("nickname didn't match") + } + if ruser.Roles != model.ROLE_SYSTEM_USER.Id { + t.Log(ruser.Roles) + t.Fatal("did not clear roles") + } + CheckUserSanitization(t, ruser) + }) +} + +func TestCreateUserWithInviteId(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.Client + AdminClient := th.SystemAdminClient + + t.Run("CreateWithInviteIdHappyPath", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + inviteId := th.BasicTeam.InviteId + + ruser, resp := Client.CreateUserWithInviteId(&user, inviteId) + CheckNoError(t, resp) + CheckCreatedStatus(t, resp) + + Client.Login(user.Email, user.Password) + if ruser.Nickname != user.Nickname { + t.Fatal("nickname didn't match") + } + if ruser.Roles != model.ROLE_SYSTEM_USER.Id { + t.Log(ruser.Roles) + t.Fatal("did not clear roles") + } + CheckUserSanitization(t, ruser) + }) + + t.Run("WrongInviteId", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + inviteId := model.NewId() + + _, resp := Client.CreateUserWithInviteId(&user, inviteId) + CheckInternalErrorStatus(t, resp) + CheckErrorMessage(t, resp, "store.sql_team.get_by_invite_id.find.app_error") + }) + + t.Run("NoInviteId", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + _, resp := Client.CreateUserWithInviteId(&user, "") + CheckBadRequestStatus(t, resp) + CheckErrorMessage(t, resp, "api.user.create_user.missing_invite_id.app_error") + }) + + t.Run("ExpiredInviteId", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + inviteId := th.BasicTeam.InviteId + + th.BasicTeam.InviteId = model.NewId() + _, resp := AdminClient.UpdateTeam(th.BasicTeam) + CheckNoError(t, resp) + + _, resp = Client.CreateUserWithInviteId(&user, inviteId) + CheckInternalErrorStatus(t, resp) + CheckErrorMessage(t, resp, "store.sql_team.get_by_invite_id.find.app_error") + }) + + t.Run("EnableUserCreationDisable", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + canCreateAccount := utils.Cfg.TeamSettings.EnableUserCreation + defer func() { + utils.Cfg.TeamSettings.EnableUserCreation = canCreateAccount + }() + utils.Cfg.TeamSettings.EnableUserCreation = false + + inviteId := th.BasicTeam.InviteId + + _, resp := Client.CreateUserWithInviteId(&user, inviteId) + CheckNotImplementedStatus(t, resp) + CheckErrorMessage(t, resp, "api.user.create_user.signup_email_disabled.app_error") + }) + + t.Run("EnableOpenServerDisable", func(t *testing.T) { + user := model.User{Email: GenerateTestEmail(), Nickname: "Corey Hulen", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + openServer := *utils.Cfg.TeamSettings.EnableOpenServer + defer func() { + *utils.Cfg.TeamSettings.EnableOpenServer = openServer + }() + *utils.Cfg.TeamSettings.EnableOpenServer = false + + inviteId := th.BasicTeam.InviteId + + ruser, resp := Client.CreateUserWithInviteId(&user, inviteId) + CheckNoError(t, resp) + CheckCreatedStatus(t, resp) + + Client.Login(user.Email, user.Password) + if ruser.Nickname != user.Nickname { + t.Fatal("nickname didn't match") + } + if ruser.Roles != model.ROLE_SYSTEM_USER.Id { + t.Log(ruser.Roles) + t.Fatal("did not clear roles") + } + CheckUserSanitization(t, ruser) + }) + +} + func TestGetMe(t *testing.T) { th := Setup().InitBasic() defer TearDown() @@ -468,7 +715,6 @@ func TestSearchUsers(t *testing.T) { if !findUserInList(th.BasicUser.Id, users) { t.Fatal("should have found user") } - } func findUserInList(id string, users []*model.User) bool { @@ -867,7 +1113,6 @@ func TestDeleteUser(t *testing.T) { _, resp = Client.DeleteUser(testUser.Id) CheckNoError(t, resp) - } func TestUpdateUserRoles(t *testing.T) { @@ -1542,7 +1787,6 @@ func TestGetSessions(t *testing.T) { _, resp = th.SystemAdminClient.GetSessions(model.NewId(), "") CheckNoError(t, resp) - } func TestRevokeSessions(t *testing.T) { diff --git a/i18n/en.json b/i18n/en.json index e43e3fdd2..9db731cdf 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2480,6 +2480,14 @@ "translation": "User sign-up with email is disabled." }, { + "id": "api.user.create_user.missing_invite_id.app_error", + "translation": "Missing Invite Id." + }, + { + "id": "api.user.create_user.missing_hash_or_data.app_error", + "translation": "Missing Hash or URL query data." + }, + { "id": "api.user.create_user.signup_link_expired.app_error", "translation": "The signup link has expired" }, diff --git a/model/client4.go b/model/client4.go index 91c5b2b5f..2e11d98b1 100644 --- a/model/client4.go +++ b/model/client4.go @@ -451,6 +451,40 @@ func (c *Client4) CreateUser(user *User) (*User, *Response) { } } +// CreateUserWithHash creates a user in the system based on the provided user struct and hash created. +func (c *Client4) CreateUserWithHash(user *User, hash, data string) (*User, *Response) { + var query string + if hash != "" && data != "" { + query = fmt.Sprintf("?d=%v&h=%v", url.QueryEscape(data), hash) + } else { + err := NewAppError("MissingHashOrData", "api.user.create_user.missing_hash_or_data.app_error", nil, "", http.StatusBadRequest) + return nil, &Response{StatusCode: err.StatusCode, Error: err} + } + if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) + } +} + +// CreateUserWithInviteId creates a user in the system based on the provided invited id. +func (c *Client4) CreateUserWithInviteId(user *User, inviteId string) (*User, *Response) { + var query string + if inviteId != "" { + query = fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId)) + } else { + err := NewAppError("MissingInviteId", "api.user.create_user.missing_invite_id.app_error", nil, "", http.StatusBadRequest) + return nil, &Response{StatusCode: err.StatusCode, Error: err} + } + if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) + } +} + // GetMe returns the logged in user. func (c *Client4) GetMe(etag string) (*User, *Response) { if r, err := c.DoApiGet(c.GetUserRoute(ME), etag); err != nil { |