diff --git a/api4/cloud.go b/api4/cloud.go index a88ac919b3..4537828afb 100644 --- a/api4/cloud.go +++ b/api4/cloud.go @@ -53,7 +53,7 @@ func (api *API) InitCloud() { } func getSubscription(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.getSubscription", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -95,7 +95,7 @@ func getSubscription(c *Context, w http.ResponseWriter, r *http.Request) { } func changeSubscription(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.changeSubscription", "api.cloud.license_error", nil, "", http.StatusInternalServerError) return } @@ -145,7 +145,7 @@ func changeSubscription(c *Context, w http.ResponseWriter, r *http.Request) { } func requestCloudTrial(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.requestCloudTrial", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -187,7 +187,7 @@ func requestCloudTrial(c *Context, w http.ResponseWriter, r *http.Request) { } func validateBusinessEmail(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.validateBusinessEmail", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -232,7 +232,7 @@ func validateBusinessEmail(c *Context, w http.ResponseWriter, r *http.Request) { } func validateWorkspaceBusinessEmail(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.validateWorkspaceBusinessEmail", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -278,7 +278,7 @@ func validateWorkspaceBusinessEmail(c *Context, w http.ResponseWriter, r *http.R } func getCloudProducts(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.getCloudProducts", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -319,7 +319,7 @@ func getCloudProducts(c *Context, w http.ResponseWriter, r *http.Request) { } func getCloudLimits(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.getCloudLimits", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -340,7 +340,7 @@ func getCloudLimits(c *Context, w http.ResponseWriter, r *http.Request) { } func getCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.getCloudCustomer", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -366,7 +366,7 @@ func getCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) { } func updateCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.updateCloudCustomer", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -404,7 +404,7 @@ func updateCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) { } func updateCloudCustomerAddress(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.updateCloudCustomerAddress", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -442,7 +442,7 @@ func updateCloudCustomerAddress(c *Context, w http.ResponseWriter, r *http.Reque } func createCustomerPayment(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.createCustomerPayment", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -473,7 +473,7 @@ func createCustomerPayment(c *Context, w http.ResponseWriter, r *http.Request) { } func confirmCustomerPayment(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.confirmCustomerPayment", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -510,7 +510,7 @@ func confirmCustomerPayment(c *Context, w http.ResponseWriter, r *http.Request) } func getInvoicesForSubscription(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.getInvoicesForSubscription", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -536,7 +536,7 @@ func getInvoicesForSubscription(c *Context, w http.ResponseWriter, r *http.Reque } func getSubscriptionInvoicePDF(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.getSubscriptionInvoicePDF", "api.cloud.license_error", nil, "", http.StatusForbidden) return } @@ -571,7 +571,7 @@ func getSubscriptionInvoicePDF(c *Context, w http.ResponseWriter, r *http.Reques } func handleCWSWebhook(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("Api4.handleCWSWebhook", "api.cloud.license_error", nil, "", http.StatusForbidden) return } diff --git a/api4/config.go b/api4/config.go index 0bcdfbb3f5..d2f2019c36 100644 --- a/api4/config.go +++ b/api4/config.go @@ -68,7 +68,7 @@ func getConfig(c *Context, w http.ResponseWriter, r *http.Request) { auditRec.Success() w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { js, jsonErr := cfg.ToJSONFiltered(model.ConfigAccessTagType, model.ConfigAccessTagCloudRestrictable) if jsonErr != nil { c.Err = model.NewAppError("getConfig", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError) @@ -167,7 +167,7 @@ func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) { } // There are some settings that cannot be changed in a cloud env - if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { // Both of them cannot be nil since cfg.SetDefaults is called earlier for cfg, // and appCfg is the existing earlier config and if it's nil, server sets a default value. if *appCfg.ComplianceSettings.Directory != *cfg.ComplianceSettings.Directory { @@ -214,7 +214,7 @@ func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("updateConfig") w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { js, err := cfg.ToJSONFiltered(model.ConfigAccessTagType, model.ConfigAccessTagCloudRestrictable) if err != nil { c.Err = model.NewAppError("updateConfig", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(err) @@ -310,7 +310,7 @@ func patchConfig(c *Context, w http.ResponseWriter, r *http.Request) { } // There are some settings that cannot be changed in a cloud env - if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { if cfg.ComplianceSettings.Directory != nil && *appCfg.ComplianceSettings.Directory != *cfg.ComplianceSettings.Directory { c.Err = model.NewAppError("patchConfig", "api.config.update_config.not_allowed_security.app_error", map[string]any{"Name": "ComplianceSettings.Directory"}, "", http.StatusForbidden) return @@ -364,7 +364,7 @@ func patchConfig(c *Context, w http.ResponseWriter, r *http.Request) { } w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { js, err := cfg.ToJSONFiltered(model.ConfigAccessTagType, model.ConfigAccessTagCloudRestrictable) if err != nil { c.Err = model.NewAppError("patchConfig", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(err) diff --git a/api4/license.go b/api4/license.go index 4a56ca74ed..15c0b34fa8 100644 --- a/api4/license.go +++ b/api4/license.go @@ -137,6 +137,11 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) { return } + if c.App.Channels().License().IsCloud() { + // If cloud, invalidate the caches when a new license is loaded + defer c.App.Srv().Cloud.InvalidateCaches() + } + auditRec.Success() c.LogAudit("success") diff --git a/api4/team.go b/api4/team.go index 6ad6c9b52b..a4d687f1ff 100644 --- a/api4/team.go +++ b/api4/team.go @@ -95,7 +95,7 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) { } // On a cloud license, we must check limits before allowing to create - if c.App.Channels().License() != nil && c.App.Channels().License().Features != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { limits, err := c.App.Cloud().GetCloudLimits(c.AppContext.Session().UserId) if err != nil { c.Err = model.NewAppError("Api4.createTeam", "api.cloud.app_error", nil, err.Error(), http.StatusInternalServerError) @@ -285,7 +285,7 @@ func restoreTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } // On a cloud license, we must check limits before allowing to restore - if c.App.Channels().License() != nil && c.App.Channels().License().Features != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { limits, err := c.App.Cloud().GetCloudLimits(c.AppContext.Session().UserId) if err != nil { c.Err = model.NewAppError("Api4.restoreTeam", "api.cloud.app_error", nil, err.Error(), http.StatusInternalServerError) @@ -1259,7 +1259,7 @@ func teamExists(c *Context, w http.ResponseWriter, r *http.Request) { } func importTeam(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("importTeam", "api.restricted_system_admin", nil, "", http.StatusForbidden) return } diff --git a/api4/upload.go b/api4/upload.go index a96b1afc9e..e5800df9b3 100644 --- a/api4/upload.go +++ b/api4/upload.go @@ -48,7 +48,7 @@ func createUpload(c *Context, w http.ResponseWriter, r *http.Request) { c.SetPermissionError(model.PermissionManageSystem) return } - if c.App.Srv().License() != nil && *c.App.Srv().License().Features.Cloud { + if c.App.Srv().License().IsCloud() { c.Err = model.NewAppError("createUpload", "api.file.cloud_upload.app_error", nil, "", http.StatusBadRequest) return } @@ -127,7 +127,7 @@ func uploadData(c *Context, w http.ResponseWriter, r *http.Request) { c.SetPermissionError(model.PermissionManageSystem) return } - if c.App.Srv().License() != nil && *c.App.Srv().License().Features.Cloud { + if c.App.Srv().License().IsCloud() { c.Err = model.NewAppError("UploadData", "api.file.cloud_upload.app_error", nil, "", http.StatusBadRequest) return } diff --git a/api4/user.go b/api4/user.go index 69a7c6214a..4b182c6433 100644 --- a/api4/user.go +++ b/api4/user.go @@ -1914,7 +1914,7 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) { } func loginCWS(c *Context, w http.ResponseWriter, r *http.Request) { - if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.Cloud { + if !c.App.Channels().License().IsCloud() { c.Err = model.NewAppError("loginCWS", "api.user.login_cws.license.error", nil, "", http.StatusUnauthorized) return } diff --git a/app/file.go b/app/file.go index 5f899aff70..341c5f655e 100644 --- a/app/file.go +++ b/app/file.go @@ -1348,7 +1348,7 @@ func (a *App) ExtractContentFromFileInfo(fileInfo *model.FileInfo) error { // GetLastAccessibleFileTime returns CreateAt time(from cache) of the last accessible post as per the cloud limit func (a *App) GetLastAccessibleFileTime() (int64, *model.AppError) { license := a.Srv().License() - if license == nil || !*license.Features.Cloud { + if !license.IsCloud() { return 0, nil } @@ -1403,7 +1403,7 @@ func (a *App) ComputeLastAccessibleFileTime() error { // getCloudFilesSizeLimit returns size in bytes func (a *App) getCloudFilesSizeLimit() (int64, *model.AppError) { license := a.Srv().License() - if license == nil || !*license.Features.Cloud { + if license == nil || !license.IsCloud() { return 0, nil } diff --git a/app/integrations.go b/app/integrations.go index 812c7cfaa8..0a810cbf0b 100644 --- a/app/integrations.go +++ b/app/integrations.go @@ -70,7 +70,7 @@ func (ch *Channels) getInstalledIntegrations() ([]*model.InstalledIntegration, * } func (a *App) checkIfIntegrationsMeetFreemiumLimits(originalPluginIds []string) *model.AppError { - if a.License() == nil || !*a.License().Features.Cloud { + if !a.License().IsCloud() { return nil } diff --git a/app/login.go b/app/login.go index 77abb8d0e3..bd63787546 100644 --- a/app/login.go +++ b/app/login.go @@ -333,7 +333,7 @@ func (a *App) AttachSessionCookies(c *request.Context, w http.ResponseWriter, r http.SetCookie(w, csrfCookie) // For context see: https://mattermost.atlassian.net/browse/MM-39583 - if a.Channels().License() != nil && *a.Channels().License().Features.Cloud { + if a.License().IsCloud() { a.AttachCloudSessionCookie(c, w, r) } } @@ -346,5 +346,5 @@ func GetProtocol(r *http.Request) string { } func IsCWSLogin(a *App, token string) bool { - return a.Srv().License() != nil && *a.Srv().License().Features.Cloud && token != "" + return a.License().IsCloud() && token != "" } diff --git a/app/platform/license.go b/app/platform/license.go index 23232b9c93..50c341ca15 100644 --- a/app/platform/license.go +++ b/app/platform/license.go @@ -338,7 +338,7 @@ func (ps *PlatformService) GenerateRenewalToken(expiration time.Duration) (strin return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.no_license", nil, "", http.StatusBadRequest) } - if *license.Features.Cloud { + if license.IsCloud() { return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.bad_license", nil, "", http.StatusBadRequest) } diff --git a/app/plugin.go b/app/plugin.go index 01dc070796..77514f4656 100644 --- a/app/plugin.go +++ b/app/plugin.go @@ -586,7 +586,7 @@ func (a *App) GetMarketplacePlugins(filter *model.MarketplacePluginFilter) ([]*m // This is a short term fix. The long term solution is to have a separate set of // prepacked plugins for cloud: https://mattermost.atlassian.net/browse/MM-31331. license := a.Srv().License() - if license == nil || !*license.Features.Cloud { + if license == nil || !license.IsCloud() { appErr := a.mergePrepackagedPlugins(plugins) if appErr != nil { return nil, appErr @@ -813,7 +813,7 @@ func (ch *Channels) getBaseMarketplaceFilter() *model.MarketplacePluginFilter { filter.EnterprisePlugins = true } - if license != nil && *license.Features.Cloud { + if license != nil && license.IsCloud() { filter.Cloud = true } diff --git a/app/post.go b/app/post.go index 1ad54f19f7..7564396a8c 100644 --- a/app/post.go +++ b/app/post.go @@ -1408,7 +1408,7 @@ func (a *App) convertUserNameToUserIds(usernames []string) []string { // GetLastAccessiblePostTime returns CreateAt time(from cache) of the last accessible post as per the cloud limit func (a *App) GetLastAccessiblePostTime() (int64, *model.AppError) { license := a.Srv().License() - if license == nil || !*license.Features.Cloud { + if license == nil || !license.IsCloud() { return 0, nil } @@ -1467,7 +1467,7 @@ func (a *App) ComputeLastAccessiblePostTime() error { func (a *App) getCloudMessagesHistoryLimit() (int64, *model.AppError) { license := a.Srv().License() - if license == nil || !*license.Features.Cloud { + if license == nil || !license.IsCloud() { return 0, nil } diff --git a/app/server.go b/app/server.go index 26e73ac801..8699a013c6 100644 --- a/app/server.go +++ b/app/server.go @@ -1347,7 +1347,7 @@ func (s *Server) doLicenseExpirationCheck() { return } - if *license.Features.Cloud { + if license.IsCloud() { mlog.Debug("Skipping license expiration check for Cloud") return } diff --git a/config/client.go b/config/client.go index e672d7fca0..d70ad24110 100644 --- a/config/client.go +++ b/config/client.go @@ -194,7 +194,7 @@ func GenerateClientConfig(c *model.Config, telemetryID string, license *model.Li props["DataRetentionBoardsRetentionDays"] = strconv.FormatInt(int64(*c.DataRetentionSettings.BoardsRetentionDays), 10) } - if *license.Features.Cloud { + if license.IsCloud() { props["CWSURL"] = *c.CloudSettings.CWSURL } diff --git a/model/license.go b/model/license.go index 846ce68558..ba0797c168 100644 --- a/model/license.go +++ b/model/license.go @@ -289,6 +289,10 @@ func (l *License) IsStarted() bool { return l.StartsAt < GetMillis() } +func (l *License) IsCloud() bool { + return l != nil && l.Features != nil && l.Features.Cloud != nil && *l.Features.Cloud +} + func (l *License) IsTrialLicense() bool { return l.IsTrial || (l.ExpiresAt-l.StartsAt) == trialDuration.Milliseconds() || (l.ExpiresAt-l.StartsAt) == adminTrialDuration.Milliseconds() } diff --git a/model/license_test.go b/model/license_test.go index 6649ebcd43..62bba9439c 100644 --- a/model/license_test.go +++ b/model/license_test.go @@ -143,6 +143,23 @@ func TestLicenseIsStarted(t *testing.T) { assert.False(t, l1.IsStarted()) } +func TestIsCloud(t *testing.T) { + l1 := License{} + l1.Features = &Features{} + l1.Features.SetDefaults() + assert.False(t, l1.IsCloud()) + + boolTrue := true + l1.Features.Cloud = &boolTrue + assert.True(t, l1.IsCloud()) + + var license *License + assert.False(t, license.IsCloud()) + + l1.Features = nil + assert.False(t, l1.IsCloud()) +} + func TestLicenseRecordIsValid(t *testing.T) { lr := LicenseRecord{ CreateAt: GetMillis(), diff --git a/services/telemetry/telemetry.go b/services/telemetry/telemetry.go index 821b4c8a91..3e2bba1566 100644 --- a/services/telemetry/telemetry.go +++ b/services/telemetry/telemetry.go @@ -353,7 +353,7 @@ func (ts *TelemetryService) trackActivity() { "outgoing_webhooks": outgoingWebhooksCount, } - if license := ts.srv.License(); license != nil && license.Features.Cloud != nil && *license.Features.Cloud { + if license := ts.srv.License(); license.IsCloud() { var tmpStorage int64 if usage, err := ts.dbStore.FileInfo().GetStorageUsage(true, false); err == nil { tmpStorage = usage diff --git a/web/context.go b/web/context.go index d877f1a39f..056dca354c 100644 --- a/web/context.go +++ b/web/context.go @@ -138,7 +138,7 @@ func (c *Context) SessionRequired() { } func (c *Context) CloudKeyRequired() { - if license := c.App.Channels().License(); license == nil || !*license.Features.Cloud || c.AppContext.Session().Props[model.SessionPropType] != model.SessionTypeCloudKey { + if license := c.App.Channels().License(); license == nil || !license.IsCloud() || c.AppContext.Session().Props[model.SessionPropType] != model.SessionTypeCloudKey { c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "TokenRequired", http.StatusUnauthorized) return } diff --git a/web/handlers.go b/web/handlers.go index 65dda02cf0..bc836b72ba 100644 --- a/web/handlers.go +++ b/web/handlers.go @@ -223,7 +223,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { subpath, _ := utils.GetSubpathFromConfig(c.App.Config()) siteURLHeader := app.GetProtocol(r) + "://" + r.Host + subpath - if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { siteURLHeader = *c.App.Config().ServiceSettings.SiteURL + subpath } c.SetSiteURLHeader(siteURLHeader) @@ -236,7 +236,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } cloudCSP := "" - if c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud { + if c.App.Channels().License().IsCloud() { cloudCSP = " js.stripe.com/v3" } @@ -288,7 +288,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } h.checkCSRFToken(c, r, token, tokenLocation, session) - } else if token != "" && c.App.Channels().License() != nil && *c.App.Channels().License().Features.Cloud && tokenLocation == app.TokenLocationCloudHeader { + } else if token != "" && c.App.Channels().License().IsCloud() && tokenLocation == app.TokenLocationCloudHeader { // Check to see if this provided token matches our CWS Token session, err := c.App.GetCloudSession(token) if err != nil {