mirror of
https://github.com/mattermost/mattermost.git
synced 2026-05-28 04:35:04 -04:00
Merge 4b527ba3ad into cfafefe58c
This commit is contained in:
commit
33fc7af27c
21 changed files with 312 additions and 43 deletions
|
|
@ -65,8 +65,7 @@ func ensureCloudInterface(c *Context, where string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func getPreviewSubscription(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
license := c.App.Channels().License()
|
||||
func getPreviewSubscription(c *Context, w http.ResponseWriter, r *http.Request, license *model.License) {
|
||||
subscription := &model.Subscription{
|
||||
ID: "cloud-preview",
|
||||
ProductID: license.SkuName,
|
||||
|
|
@ -90,8 +89,9 @@ func getPreviewSubscription(c *Context, w http.ResponseWriter, r *http.Request)
|
|||
|
||||
func getSubscription(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
// Preview subscription is a special case for cloud preview licenses.
|
||||
if c.App.Channels().License().IsCloudPreview() {
|
||||
getPreviewSubscription(c, w, r)
|
||||
license := c.App.Channels().License()
|
||||
if license != nil && license.IsCloudPreview() {
|
||||
getPreviewSubscription(c, w, r, license)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ func getSubscription(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getSubscription", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -199,7 +199,8 @@ func validateWorkspaceBusinessEmail(c *Context, w http.ResponseWriter, r *http.R
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.validateWorkspaceBusinessEmail", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -250,7 +251,8 @@ func getCloudProducts(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getCloudProducts", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -300,7 +302,8 @@ func getCloudLimits(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getCloudLimits", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -328,7 +331,8 @@ func getCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getCloudCustomer", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -384,7 +388,8 @@ func updateCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.updateCloudCustomer", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -429,7 +434,8 @@ func updateCloudCustomerAddress(c *Context, w http.ResponseWriter, r *http.Reque
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.updateCloudCustomerAddress", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -474,7 +480,8 @@ func getInvoicesForSubscription(c *Context, w http.ResponseWriter, r *http.Reque
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getInvoicesForSubscription", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -507,7 +514,8 @@ func getSubscriptionInvoicePDF(c *Context, w http.ResponseWriter, r *http.Reques
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getSubscriptionInvoicePDF", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -547,7 +555,8 @@ func handleCWSWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.handleCWSWebhook", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -486,3 +486,20 @@ func TestCheckCWSConnection(t *testing.T) {
|
|||
assert.Equal(t, "unavailable", response["status"])
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetSubscriptionNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
// getSubscription calls License().IsCloudPreview() and License().IsCloud()
|
||||
// — must not panic when license is nil. The exact error depends on the
|
||||
// test environment (cloud interface may not be available), but the key
|
||||
// assertion is no panic and no 500.
|
||||
resp, err := th.SystemAdminClient.DoAPIGet(context.Background(), "/cloud/subscription", "")
|
||||
require.Error(t, err)
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ func getConfig(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
RemoveMasked: filterMasked,
|
||||
},
|
||||
}
|
||||
if c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license != nil && license.IsCloud() {
|
||||
filterOpts.TagFilters = append(filterOpts.TagFilters, model.FilterTag{
|
||||
TagType: model.ConfigAccessTagType,
|
||||
TagName: model.ConfigAccessTagCloudRestrictable,
|
||||
|
|
@ -168,7 +169,8 @@ 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().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license != nil && 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 {
|
||||
|
|
@ -233,7 +235,8 @@ 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().IsCloud() {
|
||||
license = c.App.Channels().License()
|
||||
if license != nil && 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)
|
||||
|
|
@ -324,7 +327,8 @@ 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().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license != nil && 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
|
||||
|
|
@ -383,7 +387,8 @@ 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().IsCloud() {
|
||||
license = c.App.Channels().License()
|
||||
if license != nil && 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)
|
||||
|
|
|
|||
|
|
@ -66,6 +66,14 @@ func TestGetConfig(t *testing.T) {
|
|||
require.NotEqual(t, model.FakeSetting, *cfg.SqlSettings.DataSource)
|
||||
require.NotEqual(t, model.FakeSetting, *cfg.FileSettings.PublicLinkSalt)
|
||||
})
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
// GetConfig calls License().IsCloud() — must not panic when license is nil
|
||||
_, _, err := th.SystemAdminClient.GetConfig(context.Background())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetConfigWithAccessTag(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
license, appErr = c.App.Srv().SaveLicense(licenseBytes)
|
||||
_, appErr = c.App.Srv().SaveLicense(licenseBytes)
|
||||
if appErr != nil {
|
||||
if appErr.Id == model.ExpiredLicenseError {
|
||||
c.LogAudit("failed - expired or non-started license")
|
||||
|
|
@ -137,7 +137,8 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if c.App.Channels().License().IsCloud() {
|
||||
license = c.App.Channels().License()
|
||||
if license != nil && license.IsCloud() {
|
||||
// If cloud, invalidate the caches when a new license is loaded
|
||||
defer func() {
|
||||
if err := c.App.Srv().Cloud.HandleLicenseChange(); err != nil {
|
||||
|
|
|
|||
|
|
@ -618,3 +618,18 @@ func TestGetLicenseLoadMetric(t *testing.T) {
|
|||
require.Equal(t, 1500, loadValue)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAddLicenseNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
// addLicense checks License().IsCloud() after saving — but the upload
|
||||
// itself will fail validation. Key assertion: no panic, no 500.
|
||||
resp, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/license", "not-a-real-license")
|
||||
require.Error(t, err)
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,8 @@ 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().IsCloud() {
|
||||
license = c.App.Channels().License()
|
||||
if license != nil && 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, "", http.StatusInternalServerError).Wrap(err)
|
||||
|
|
@ -405,7 +406,8 @@ 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().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license != nil && 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, "", http.StatusInternalServerError).Wrap(err)
|
||||
|
|
@ -1462,7 +1464,8 @@ 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().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license != nil && license.IsCloud() {
|
||||
c.Err = model.NewAppError("importTeam", "api.restricted_system_admin", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -1701,7 +1704,8 @@ func inviteGuestsToChannels(c *Context, w http.ResponseWriter, r *http.Request)
|
|||
return
|
||||
}
|
||||
|
||||
guestEnabled := c.App.Channels().License() != nil && *c.App.Channels().License().Features.GuestAccounts
|
||||
license := c.App.Channels().License()
|
||||
guestEnabled := license != nil && license.Features != nil && license.Features.GuestAccounts != nil && *license.Features.GuestAccounts
|
||||
|
||||
if !guestEnabled {
|
||||
c.Err = model.NewAppError("Api4.InviteGuestsToChannels", "api.team.invite_guests_to_channels.disabled.error", nil, "", http.StatusForbidden)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@
|
|||
package api4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -235,6 +237,17 @@ func TestCreateTeam(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
})
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
team := &model.Team{Name: GenerateTestUsername(), DisplayName: "No License Team", Type: model.TeamOpen}
|
||||
_, resp, err := th.Client.CreateTeam(context.Background(), team)
|
||||
// The request may succeed or fail depending on permissions,
|
||||
// but it must NOT panic due to nil License().IsCloud()
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateTeamSanitization(t *testing.T) {
|
||||
|
|
@ -5062,3 +5075,49 @@ func TestGetTeamMembersForUserRoleDataSanitization(t *testing.T) {
|
|||
require.Fail(t, "basic team membership not found")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRestoreTeamNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
// restoreTeam checks License().IsCloud() — must not panic when nil.
|
||||
resp, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/teams/"+th.BasicTeam.Id+"/restore", "")
|
||||
// May return 403/404 depending on team state, but must not return 500.
|
||||
if err != nil {
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestImportTeamNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
// importTeam checks License().IsCloud() — must not panic when nil.
|
||||
// We send a minimal multipart request that will fail validation but should not panic.
|
||||
var b bytes.Buffer
|
||||
w := multipart.NewWriter(&b)
|
||||
require.NoError(t, w.WriteField("importFrom", "slack"))
|
||||
require.NoError(t, w.WriteField("filesize", "100"))
|
||||
part, err := w.CreateFormFile("file", "import.zip")
|
||||
require.NoError(t, err)
|
||||
_, err = part.Write([]byte("fake"))
|
||||
require.NoError(t, err)
|
||||
w.Close()
|
||||
|
||||
req, _ := http.NewRequest("POST", th.SystemAdminClient.APIURL+"/teams/"+th.BasicTeam.Id+"/import", &b)
|
||||
req.Header.Set("Content-Type", w.FormDataContentType())
|
||||
req.Header.Set(model.HeaderAuth, model.HeaderBearer+" "+th.SystemAdminClient.AuthToken)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
resp.Body.Close()
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode,
|
||||
"nil license must not cause a 500 panic in importTeam")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ func createUpload(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
c.SetPermissionError(model.PermissionManageSystem)
|
||||
return
|
||||
}
|
||||
if c.App.Srv().License().IsCloud() {
|
||||
license := c.App.Srv().License()
|
||||
if license != nil && license.IsCloud() {
|
||||
c.Err = model.NewAppError("createUpload", "api.file.cloud_upload.app_error", nil, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -147,7 +148,8 @@ func uploadData(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
c.SetPermissionError(model.PermissionManageSystem)
|
||||
return
|
||||
}
|
||||
if c.App.Srv().License().IsCloud() {
|
||||
license := c.App.Srv().License()
|
||||
if license != nil && license.IsCloud() {
|
||||
c.Err = model.NewAppError("UploadData", "api.file.cloud_upload.app_error", nil, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -551,3 +551,22 @@ func TestUploadDataMultipart(t *testing.T) {
|
|||
require.Equal(t, file, data)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateUploadNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
t.Run("nil license does not panic on import upload", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
us := &model.UploadSession{
|
||||
Type: model.UploadTypeImport,
|
||||
Filename: "import.zip",
|
||||
FileSize: 1024,
|
||||
}
|
||||
_, resp, err := th.SystemAdminClient.CreateUpload(context.Background(), us)
|
||||
require.Error(t, err)
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode,
|
||||
"nil license must not cause a 500 panic in createUpload")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2276,7 +2276,8 @@ func loginCWS(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
"cyber-defense": "/cyber-defense-hq",
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
c.Err = model.NewAppError("loginCWS", "api.user.login_cws.license.error", nil, "", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
|
@ -2335,7 +2336,8 @@ func loginCWS(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// If a cloud preview, redirect to the correct use case URL
|
||||
if c.App.License().IsCloudPreview() && useCase != "" {
|
||||
license = c.App.License()
|
||||
if license != nil && license.IsCloudPreview() && useCase != "" {
|
||||
if url, ok := useCaseToURL[useCase]; ok {
|
||||
redirectURL += url
|
||||
}
|
||||
|
|
@ -3282,7 +3284,8 @@ func demoteUserToGuest(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
guestEnabled := c.App.Channels().License() != nil && *c.App.Channels().License().Features.GuestAccounts
|
||||
license := c.App.Channels().License()
|
||||
guestEnabled := license != nil && license.Features != nil && license.Features.GuestAccounts != nil && *license.Features.GuestAccounts
|
||||
|
||||
if !guestEnabled {
|
||||
c.Err = model.NewAppError("Api4.demoteUserToGuest", "api.team.invite_guests_to_channels.disabled.error", nil, "", http.StatusForbidden)
|
||||
|
|
@ -3577,7 +3580,8 @@ func migrateAuthToLDAP(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAP {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || license.Features == nil || license.Features.LDAP == nil || !*license.Features.LDAP {
|
||||
c.Err = model.NewAppError("api.migrateAuthToLDAP", "api.admin.ldap.not_available.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
|
@ -3636,7 +3640,8 @@ func migrateAuthToSaml(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.SAML {
|
||||
license := c.App.Channels().License()
|
||||
if license == nil || license.Features == nil || license.Features.SAML == nil || !*license.Features.SAML {
|
||||
c.Err = model.NewAppError("api.migrateAuthToSaml", "api.admin.saml.not_available.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10268,3 +10268,61 @@ func TestSearchUsersWithMfaEnforced(t *testing.T) {
|
|||
CheckForbiddenStatus(t, resp)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoginNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
t.Run("nil license does not panic on login", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
_, err := th.Client.Logout(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Login calls isCWSLogin and AttachSessionCookies, both of which
|
||||
// reference License().IsCloud() — must not panic when license is nil.
|
||||
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDemoteUserToGuestNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
// demoteUserToGuest checks License() == nil — should return 501, not panic.
|
||||
resp, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/users/"+th.BasicUser.Id+"/demote", "")
|
||||
require.Error(t, err)
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMigrateAuthToLDAPNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
jsonBody := `{"from":"email","force":false,"match_field":"email"}`
|
||||
resp, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/users/migrate_auth/ldap", jsonBody)
|
||||
require.Error(t, err)
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMigrateAuthToSamlNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
jsonBody := `{"from":"email","auto":false,"matches":{}}`
|
||||
resp, err := th.SystemAdminClient.DoAPIPost(context.Background(), "/users/migrate_auth/saml", jsonBody)
|
||||
require.Error(t, err)
|
||||
require.NotEqual(t, http.StatusInternalServerError, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,7 +198,8 @@ func (a *App) AddAuditLogCertificate(rctx request.CTX, fileData *multipart.FileH
|
|||
|
||||
a.UpdateConfig(func(dest *model.Config) { *dest = *cfg })
|
||||
|
||||
if a.License().IsCloud() {
|
||||
license := a.License()
|
||||
if license != nil && license.IsCloud() {
|
||||
err = a.Cloud().CreateAuditLoggingCert(rctx.Session().UserId, fileData)
|
||||
if err != nil {
|
||||
return model.NewAppError("AddAuditLogCertificate", "api.admin.add_certificate.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
|
|
@ -224,7 +225,8 @@ func (a *App) RemoveAuditLogCertificate(rctx request.CTX) *model.AppError {
|
|||
|
||||
a.UpdateConfig(func(dest *model.Config) { *dest = *cfg })
|
||||
|
||||
if a.License().IsCloud() {
|
||||
license := a.License()
|
||||
if license != nil && license.IsCloud() {
|
||||
err = a.Cloud().RemoveAuditLoggingCert(rctx.Session().UserId)
|
||||
if err != nil {
|
||||
return model.NewAppError("RemoveAuditLogCertificate", "api.admin.remove_certificate.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ func (a *App) ExportFileBackend() filestore.FileBackend {
|
|||
|
||||
func (a *App) CheckMandatoryS3Fields(settings *model.FileSettings) *model.AppError {
|
||||
var fileBackendSettings filestore.FileBackendSettings
|
||||
if a.License().IsCloud() && a.Config().FeatureFlags.CloudDedicatedExportUI && a.Config().FileSettings.DedicatedExportStore != nil && *a.Config().FileSettings.DedicatedExportStore {
|
||||
license := a.License()
|
||||
if license != nil && license.IsCloud() && a.Config().FeatureFlags.CloudDedicatedExportUI && a.Config().FileSettings.DedicatedExportStore != nil && *a.Config().FileSettings.DedicatedExportStore {
|
||||
fileBackendSettings = filestore.NewExportFileBackendSettingsFromConfig(settings, false, false)
|
||||
} else {
|
||||
fileBackendSettings = filestore.NewFileBackendSettingsFromConfig(settings, false, false)
|
||||
|
|
|
|||
|
|
@ -1207,3 +1207,18 @@ func TestFilterFilesByChannelPermissions_ABAC(t *testing.T) {
|
|||
mockACS.AssertNotCalled(t, "AccessEvaluation")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheckMandatoryS3FieldsNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
settings := &model.FileSettings{}
|
||||
settings.SetDefaults(false)
|
||||
// CheckMandatoryS3Fields calls License().IsCloud() — must not panic when nil.
|
||||
_ = th.App.CheckMandatoryS3Fields(settings)
|
||||
// If we get here without a panic, the test passes.
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import (
|
|||
|
||||
func (a *App) SendIPFiltersChangedEmail(rctx request.CTX, userID string) error {
|
||||
cloudWorkspaceOwnerEmailAddress := ""
|
||||
if a.License().IsCloud() {
|
||||
license := a.License()
|
||||
if license != nil && license.IsCloud() {
|
||||
portalUserCustomer, cErr := a.Cloud().GetCloudCustomer(userID)
|
||||
if cErr != nil {
|
||||
rctx.Logger().Error("Failed to get portal user customer", mlog.Err(cErr))
|
||||
|
|
|
|||
25
server/channels/app/ip_filtering_test.go
Normal file
25
server/channels/app/ip_filtering_test.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
)
|
||||
|
||||
func TestSendIPFiltersChangedEmailNilLicense(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := Setup(t)
|
||||
|
||||
t.Run("nil license does not panic", func(t *testing.T) {
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
rctx := request.TestContext(t)
|
||||
// SendIPFiltersChangedEmail checks License().IsCloud() — must not panic when nil.
|
||||
// It may return an error (e.g., no SMTP configured), but must not panic.
|
||||
_ = th.App.SendIPFiltersChangedEmail(rctx, model.NewId())
|
||||
})
|
||||
}
|
||||
|
|
@ -197,7 +197,8 @@ func (a *App) DoLogin(rctx request.CTX, w http.ResponseWriter, r *http.Request,
|
|||
|
||||
rctx = rctx.WithSession(session)
|
||||
|
||||
if a.Srv().License() != nil && *a.Srv().License().Features.LDAP && a.Ldap() != nil {
|
||||
license := a.Srv().License()
|
||||
if license != nil && *license.Features.LDAP && a.Ldap() != nil {
|
||||
userVal := *user
|
||||
sessionVal := *session
|
||||
a.Srv().Go(func() {
|
||||
|
|
@ -313,7 +314,8 @@ func (a *App) AttachSessionCookies(rctx request.CTX, w http.ResponseWriter, r *h
|
|||
http.SetCookie(w, csrfCookie)
|
||||
|
||||
// For context see: https://mattermost.atlassian.net/browse/MM-39583
|
||||
if a.License().IsCloud() {
|
||||
license := a.License()
|
||||
if license != nil && license.IsCloud() {
|
||||
a.AttachCloudSessionCookie(rctx, w, r)
|
||||
}
|
||||
}
|
||||
|
|
@ -326,5 +328,6 @@ func GetProtocol(r *http.Request) string {
|
|||
}
|
||||
|
||||
func isCWSLogin(a *App, token string) bool {
|
||||
return a.License().IsCloud() && token != ""
|
||||
license := a.License()
|
||||
return license != nil && license.IsCloud() && token != ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1445,7 +1445,8 @@ func (s *Server) sendLicenseUpForRenewalEmail(users map[string]*model.User, lice
|
|||
func (s *Server) doReportUserCountForCloudSubscriptionJob() {
|
||||
s.LoadLicense()
|
||||
|
||||
if !s.License().IsCloud() {
|
||||
license := s.License()
|
||||
if license == nil || !license.IsCloud() {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -217,7 +217,8 @@ 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().IsCloud() {
|
||||
license := c.App.Channels().License()
|
||||
if license != nil && license.IsCloud() {
|
||||
siteURLHeader = *c.App.Config().ServiceSettings.SiteURL + subpath
|
||||
}
|
||||
c.SetSiteURLHeader(siteURLHeader)
|
||||
|
|
@ -289,7 +290,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
c.RemoveSessionCookie(w, r)
|
||||
c.Err = model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token+" Appears to be a CSRF attempt", http.StatusUnauthorized)
|
||||
}
|
||||
} else if token != "" && c.App.Channels().License().IsCloud() && tokenLocation == app.TokenLocationCloudHeader {
|
||||
} else if token != "" && license != nil && 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 {
|
||||
|
|
@ -298,7 +299,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
} else {
|
||||
c.AppContext = c.AppContext.WithSession(session)
|
||||
}
|
||||
} else if token != "" && c.App.Channels().License() != nil && c.App.Channels().License().HasRemoteClusterService() && tokenLocation == app.TokenLocationRemoteClusterHeader {
|
||||
} else if token != "" && license != nil && license.HasRemoteClusterService() && tokenLocation == app.TokenLocationRemoteClusterHeader {
|
||||
// Get the remote cluster
|
||||
if remoteId := c.GetRemoteID(r); remoteId == "" {
|
||||
c.Logger.Warn("Missing remote cluster id") //
|
||||
|
|
|
|||
|
|
@ -1223,3 +1223,21 @@ func TestHandleContextErrorZeroStatusCode(t *testing.T) {
|
|||
assert.Equal(t, http.StatusBadRequest, response.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandlerServeHTTPNilLicense(t *testing.T) {
|
||||
th := Setup(t)
|
||||
|
||||
th.App.Srv().SetLicense(nil)
|
||||
|
||||
web := New(th.Server)
|
||||
handler := web.NewHandler(handlerForServeDefaultSecurityHeaders)
|
||||
|
||||
// ServeHTTP checks License().IsCloud() for siteURL and CWS token — must not panic when nil.
|
||||
request := httptest.NewRequest("GET", "/api/v4/test", nil)
|
||||
response := httptest.NewRecorder()
|
||||
handler.ServeHTTP(response, request)
|
||||
|
||||
// Should complete without panic. Any non-500 status is acceptable.
|
||||
require.NotEqual(t, http.StatusInternalServerError, response.Code,
|
||||
"nil license must not cause a 500 panic in ServeHTTP")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue