From 059ea7eb4497fc6125d8a1449e3cd1ba12c535e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Wed, 13 Jul 2022 12:05:35 +0200 Subject: [PATCH] MM-45174 - split validate business email logic (#20581) * MM-45174 - split validate business email logic * remove unnecessary interface method * check for error just after the cloud call to prevent server panic Co-authored-by: Pablo Velez Vidal Co-authored-by: Mattermod --- api4/cloud.go | 56 ++++++++++++++++++++++--------------- api4/cloud_test.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++ model/client4.go | 10 +++++++ 3 files changed, 113 insertions(+), 22 deletions(-) diff --git a/api4/cloud.go b/api4/cloud.go index f9d1aa3c32..0f833c8bdc 100644 --- a/api4/cloud.go +++ b/api4/cloud.go @@ -45,6 +45,7 @@ func (api *API) InitCloud() { // GET /api/v4/cloud/validate-business-email api.BaseRoutes.Cloud.Handle("/validate-business-email", api.APISessionRequired(validateBusinessEmail)).Methods("POST") + api.BaseRoutes.Cloud.Handle("/validate-workspace-business-email", api.APISessionRequired(validateWorkspaceBusinessEmail)).Methods("POST") // POST /api/v4/cloud/webhook api.BaseRoutes.Cloud.Handle("/webhook", api.CloudAPIKeyRequired(handleCWSWebhook)).Methods("POST") @@ -219,7 +220,6 @@ func validateBusinessEmail(c *Context, w http.ResponseWriter, r *http.Request) { return } - // if an email was sent as a body param, validate it and return wether is valid or not bodyBytes, err := ioutil.ReadAll(r.Body) if err != nil { c.Err = model.NewAppError("Api4.requestCloudTrial", "api.cloud.app_error", nil, err.Error(), http.StatusInternalServerError) @@ -232,33 +232,45 @@ func validateBusinessEmail(c *Context, w http.ResponseWriter, r *http.Request) { return } - if emailToValidate.Email != "" { - errValidatingEmail := c.App.Cloud().ValidateBusinessEmail(user.Id, emailToValidate.Email) - if errValidatingEmail != nil { - c.Err = model.NewAppError("Api4.valiateBusinessEmail", "api.cloud.request_error", nil, errValidatingEmail.Error(), http.StatusInternalServerError) - return - } - ReturnStatusOK(w) + errValidatingEmail := c.App.Cloud().ValidateBusinessEmail(user.Id, emailToValidate.Email) + if errValidatingEmail != nil { + c.Err = model.NewAppError("Api4.valiateBusinessEmail", "api.cloud.request_error", nil, errValidatingEmail.Error(), http.StatusInternalServerError) + return + } + ReturnStatusOK(w) +} + +func validateWorkspaceBusinessEmail(c *Context, w http.ResponseWriter, r *http.Request) { + if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + c.Err = model.NewAppError("Api4.validateWorkspaceBusinessEmail", "api.cloud.license_error", nil, "", http.StatusForbidden) return } - // If no email was sent as body param, then validate current userAdmin email - errValidatingAdminEmail := c.App.Cloud().ValidateBusinessEmail(user.Id, user.Email) + if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleWriteBilling) { + c.SetPermissionError(model.PermissionSysconsoleWriteBilling) + return + } - // if the current admin email is not a valid email - if errValidatingAdminEmail != nil { + user, userErr := c.App.GetUser(c.AppContext.Session().UserId) + if userErr != nil { + c.Err = model.NewAppError("Api4.validateWorkspaceBusinessEmail", "api.cloud.request_error", nil, userErr.Error(), http.StatusInternalServerError) + return + } - // get the cloud customer email - cloudCustomer, err := c.App.Cloud().GetCloudCustomer(user.Id) - if err != nil { - c.Err = model.NewAppError("Api4.valiateBusinessEmail", "api.cloud.request_error", nil, err.Error(), http.StatusInternalServerError) - return - } + // get the cloud customer email to validate if is a valid business email + cloudCustomer, err := c.App.Cloud().GetCloudCustomer(user.Id) + if err != nil { + c.Err = model.NewAppError("Api4.validateWorkspaceBusinessEmail", "api.cloud.request_error", nil, err.Error(), http.StatusInternalServerError) + return + } + errValidatingSystemEmail := c.App.Cloud().ValidateBusinessEmail(user.Id, cloudCustomer.Email) - // and validate that one - errValidatingSystemEmail := c.App.Cloud().ValidateBusinessEmail(user.Id, cloudCustomer.Email) - if errValidatingSystemEmail != nil { - c.Err = model.NewAppError("Api4.valiateBusinessEmail", "api.cloud.request_error", nil, errValidatingSystemEmail.Error(), http.StatusInternalServerError) + // if the current workspace email is not a valid business email + if errValidatingSystemEmail != nil { + // grab the current admin email and validate it + errValidatingAdminEmail := c.App.Cloud().ValidateBusinessEmail(user.Id, user.Email) + if errValidatingAdminEmail != nil { + c.Err = model.NewAppError("Api4.validateWorkspaceBusinessEmail", "api.cloud.request_error", nil, errValidatingAdminEmail.Error(), http.StatusInternalServerError) return } } diff --git a/api4/cloud_test.go b/api4/cloud_test.go index 4d77d9089d..b959998f32 100644 --- a/api4/cloud_test.go +++ b/api4/cloud_test.go @@ -428,6 +428,75 @@ func Test_validateBusinessEmail(t *testing.T) { }) } +func Test_validateWorkspaceBusinessEmail(t *testing.T) { + t.Run("validate the Cloud Customer has used a valid email to create the workspace", func(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + + th.Client.Login(th.BasicUser.Email, th.BasicUser.Password) + + th.App.Srv().SetLicense(model.NewTestLicense("cloud")) + + cloud := mocks.CloudInterface{} + + cloudCustomerInfo := model.CloudCustomerInfo{ + Email: "valid@mattermost.com", + } + + cloudCustomer := &model.CloudCustomer{ + CloudCustomerInfo: cloudCustomerInfo, + } + + cloud.Mock.On("GetCloudCustomer", th.SystemAdminUser.Id).Return(cloudCustomer, nil) + cloud.Mock.On("ValidateBusinessEmail", th.SystemAdminUser.Id, cloudCustomerInfo.Email).Return(nil) + + cloudImpl := th.App.Srv().Cloud + defer func() { + th.App.Srv().Cloud = cloudImpl + }() + th.App.Srv().Cloud = &cloud + + _, err := th.SystemAdminClient.ValidateWorkspaceBusinessEmail() + require.NoError(t, err) + }) + + t.Run("validate the Cloud Customer has used a invalid email to create the workspace and must validate admin email", func(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + + th.Client.Login(th.BasicUser.Email, th.BasicUser.Password) + + th.App.Srv().SetLicense(model.NewTestLicense("cloud")) + + cloud := mocks.CloudInterface{} + + cloudCustomerInfo := model.CloudCustomerInfo{ + Email: "invalid@gmail.com", + } + + cloudCustomer := &model.CloudCustomer{ + CloudCustomerInfo: cloudCustomerInfo, + } + + cloud.Mock.On("GetCloudCustomer", th.SystemAdminUser.Id).Return(cloudCustomer, nil) + + // first call to validate the cloud customer email + cloud.Mock.On("ValidateBusinessEmail", th.SystemAdminUser.Id, cloudCustomerInfo.Email).Return(errors.New("invalid email")) + + // second call to validate the user admin email + cloud.Mock.On("ValidateBusinessEmail", th.SystemAdminUser.Id, th.SystemAdminUser.Email).Return(nil) + + cloudImpl := th.App.Srv().Cloud + defer func() { + th.App.Srv().Cloud = cloudImpl + }() + th.App.Srv().Cloud = &cloud + + _, err := th.SystemAdminClient.ValidateWorkspaceBusinessEmail() + require.NoError(t, err) + }) +} + func TestGetCloudProducts(t *testing.T) { cloudProducts := []*model.Product{ { diff --git a/model/client4.go b/model/client4.go index 37cb49b3f4..76555fd9da 100644 --- a/model/client4.go +++ b/model/client4.go @@ -7916,6 +7916,16 @@ func (c *Client4) RequestCloudTrial(email *StartCloudTrialRequest) (*Subscriptio return subscription, BuildResponse(r), nil } +func (c *Client4) ValidateWorkspaceBusinessEmail() (*Response, error) { + r, err := c.DoAPIPost(c.cloudRoute()+"/validate-workspace-business-email", "") + if err != nil { + return BuildResponse(r), err + } + defer closeBody(r) + + return BuildResponse(r), nil +} + func (c *Client4) NotifyAdmin(nr *NotifyAdminToUpgradeRequest) int { nrJSON, jsonErr := json.Marshal(nr) if jsonErr != nil {