From 7fc5dc236aa2437e81b238f65d39c2f795eac493 Mon Sep 17 00:00:00 2001 From: Carlos Tadeu Panato Junior Date: Fri, 24 Feb 2017 14:27:47 +0100 Subject: add implementation for verify email for apiv4 (#5502) --- api4/apitestlib.go | 4 ++++ api4/user.go | 32 ++++++++++++++++++++++++++++++++ api4/user_test.go | 26 ++++++++++++++++++++++++++ model/client4.go | 11 +++++++++++ 4 files changed, 73 insertions(+) diff --git a/api4/apitestlib.go b/api4/apitestlib.go index d77438e04..2647f20f6 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -323,6 +323,10 @@ func GenerateTestChannelName() string { return "fakechannel" + model.NewRandomString(10) } +func GenerateTestId() string { + return model.NewId() +} + func VerifyUserEmail(userId string) { store.Must(app.Srv.Store.User().VerifyEmail(userId)) } diff --git a/api4/user.go b/api4/user.go index 4c40ef4b4..94891d11c 100644 --- a/api4/user.go +++ b/api4/user.go @@ -27,6 +27,7 @@ func InitUser() { BaseRoutes.User.Handle("/password", ApiSessionRequired(updatePassword)).Methods("PUT") BaseRoutes.Users.Handle("/password/reset", ApiHandler(resetPassword)).Methods("POST") BaseRoutes.Users.Handle("/password/reset/send", ApiHandler(sendPasswordReset)).Methods("POST") + BaseRoutes.User.Handle("/email/verify", ApiHandler(verify)).Methods("POST") BaseRoutes.Users.Handle("/login", ApiHandler(login)).Methods("POST") BaseRoutes.Users.Handle("/logout", ApiHandler(logout)).Methods("POST") @@ -550,3 +551,34 @@ func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { return } } + +func verify(c *Context, w http.ResponseWriter, r *http.Request) { + props := model.MapFromJson(r.Body) + + userId := props["uid"] + if len(userId) != 26 { + c.SetInvalidParam("uid") + return + } + + hashedId := props["hid"] + if len(hashedId) == 0 { + c.SetInvalidParam("hid") + return + } + + hashed := model.HashPassword(hashedId) + if model.ComparePassword(hashed, userId+utils.Cfg.EmailSettings.InviteSalt) { + if c.Err = app.VerifyUserEmail(userId); c.Err != nil { + return + } else { + c.LogAudit("Email Verified") + ReturnStatusOK(w) + return + } + } + + c.Err = model.NewLocAppError("verifyEmail", "api.user.verify_email.bad_link.app_error", nil, "") + c.Err.StatusCode = http.StatusBadRequest + return +} diff --git a/api4/user_test.go b/api4/user_test.go index 07b9745c6..ee6cf079b 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -924,3 +924,29 @@ func TestGetAudits(t *testing.T) { _, resp = th.SystemAdminClient.GetAudits(user.Id, 0, 100, "") CheckNoError(t, resp) } + +func TestVerify(t *testing.T) { + th := Setup().InitBasic() + defer TearDown() + Client := th.Client + + user := model.User{Email: GenerateTestEmail(), Nickname: "Darth Vader", Password: "hello1", Username: GenerateTestUsername(), Roles: model.ROLE_SYSTEM_ADMIN.Id + " " + model.ROLE_SYSTEM_USER.Id} + + ruser, resp := Client.CreateUser(&user) + + hashId := ruser.Id+utils.Cfg.EmailSettings.InviteSalt + _, resp = Client.VerifyUserEmail(ruser.Id, hashId) + CheckNoError(t, resp) + + hashId = ruser.Id+GenerateTestId() + _, resp = Client.VerifyUserEmail(ruser.Id, hashId) + CheckBadRequestStatus(t, resp) + + // Comment per request from Joram, he will investigate why it fail with a wrong status + // hashId = ruser.Id+GenerateTestId() + // _, resp = Client.VerifyUserEmail("", hashId) + // CheckBadRequestStatus(t, resp) + + _, resp = Client.VerifyUserEmail(ruser.Id, "") + CheckBadRequestStatus(t, resp) +} diff --git a/model/client4.go b/model/client4.go index 6b9a389c9..f51e86a56 100644 --- a/model/client4.go +++ b/model/client4.go @@ -479,6 +479,17 @@ func (c *Client4) GetAudits(userId string, page int, perPage int, etag string) ( } } +// Verify user email user id and hash strings. +func (c *Client4) VerifyUserEmail(userId, hashId string) (bool, *Response) { + requestBody := map[string]string{"uid": userId, "hid": hashId} + if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/email/verify", MapToJson(requestBody)); err != nil { + return false, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) + } +} + // Team Section // CreateTeam creates a team in the system based on the provided team struct. -- cgit v1.2.3-1-g7c22