Invalidate cloud caches when a new license is loaded (#21579)

Automatic Merge
This commit is contained in:
Nick Misasi
2022-11-02 16:40:26 -04:00
committed by GitHub
parent 1ae97fc381
commit a541cda9d0
19 changed files with 69 additions and 43 deletions

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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")

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 != ""
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -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(),

View File

@@ -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

View File

@@ -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
}

View File

@@ -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 {