summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorChris <ccbrown112@gmail.com>2018-02-09 10:04:48 -0600
committerGitHub <noreply@github.com>2018-02-09 10:04:48 -0600
commita6309aaf48e216fe5f6779188071d4b621b643b6 (patch)
tree9abbac7f172822e2286c755725fe3533cde8de8a /app
parent7e8106b95c11a4187f8c00256f3067433d20b24e (diff)
downloadchat-a6309aaf48e216fe5f6779188071d4b621b643b6.tar.gz
chat-a6309aaf48e216fe5f6779188071d4b621b643b6.tar.bz2
chat-a6309aaf48e216fe5f6779188071d4b621b643b6.zip
Remove license globals entirely (#8229)
* remove license globals entirely * fix infinite recursion * test fix
Diffstat (limited to 'app')
-rw-r--r--app/admin.go3
-rw-r--r--app/app.go24
-rw-r--r--app/apptestlib.go5
-rw-r--r--app/config.go2
-rw-r--r--app/email.go3
-rw-r--r--app/file.go3
-rw-r--r--app/license.go105
-rw-r--r--app/license_test.go75
-rw-r--r--app/role.go6
-rw-r--r--app/session_test.go9
10 files changed, 197 insertions, 38 deletions
diff --git a/app/admin.go b/app/admin.go
index b838ed3bd..154fa8899 100644
--- a/app/admin.go
+++ b/app/admin.go
@@ -237,7 +237,8 @@ func (a *App) TestEmail(userId string, cfg *model.Config) *model.AppError {
return err
} else {
T := utils.GetUserTranslations(user.Locale)
- if err := utils.SendMailUsingConfig(user.Email, T("api.admin.test_email.subject"), T("api.admin.test_email.body"), cfg); err != nil {
+ license := a.License()
+ if err := utils.SendMailUsingConfig(user.Email, T("api.admin.test_email.subject"), T("api.admin.test_email.body"), cfg, license != nil && *license.Features.Compliance); err != nil {
return err
}
}
diff --git a/app/app.go b/app/app.go
index 3c37ec252..dd5deb342 100644
--- a/app/app.go
+++ b/app/app.go
@@ -59,6 +59,10 @@ type App struct {
configFile string
configListeners map[string]func(*model.Config, *model.Config)
+ licenseValue atomic.Value
+ clientLicenseValue atomic.Value
+ licenseListeners map[string]func()
+
newStore func() store.Store
htmlTemplateWatcher *utils.HTMLTemplateWatcher
@@ -88,18 +92,16 @@ func New(options ...Option) (*App, error) {
panic("Only one App should exist at a time. Did you forget to call Shutdown()?")
}
- // TODO: remove this once utils global license state is eliminated
- utils.SetLicense(nil)
-
app := &App{
goroutineExitSignal: make(chan struct{}, 1),
Srv: &Server{
Router: mux.NewRouter(),
},
- sessionCache: utils.NewLru(model.SESSION_CACHE_SIZE),
- configFile: "config.json",
- configListeners: make(map[string]func(*model.Config, *model.Config)),
- clientConfig: make(map[string]string),
+ sessionCache: utils.NewLru(model.SESSION_CACHE_SIZE),
+ configFile: "config.json",
+ configListeners: make(map[string]func(*model.Config, *model.Config)),
+ clientConfig: make(map[string]string),
+ licenseListeners: map[string]func(){},
}
for _, option := range options {
@@ -123,9 +125,9 @@ func New(options ...Option) (*App, error) {
app.configListenerId = app.AddConfigListener(func(_, _ *model.Config) {
app.configOrLicenseListener()
})
- app.licenseListenerId = utils.AddLicenseListener(app.configOrLicenseListener)
+ app.licenseListenerId = app.AddLicenseListener(app.configOrLicenseListener)
app.regenerateClientConfig()
- app.SetDefaultRolesBasedOnConfig()
+ app.setDefaultRolesBasedOnConfig()
l4g.Info(utils.T("api.server.new_server.init.info"))
@@ -166,7 +168,7 @@ func New(options ...Option) (*App, error) {
func (a *App) configOrLicenseListener() {
a.regenerateClientConfig()
- a.SetDefaultRolesBasedOnConfig()
+ a.setDefaultRolesBasedOnConfig()
}
func (a *App) Shutdown() {
@@ -188,7 +190,7 @@ func (a *App) Shutdown() {
}
a.RemoveConfigListener(a.configListenerId)
- utils.RemoveLicenseListener(a.licenseListenerId)
+ a.RemoveLicenseListener(a.licenseListenerId)
l4g.Info(utils.T("api.server.stop_server.stopped.info"))
a.DisableConfigWatch()
diff --git a/app/apptestlib.go b/app/apptestlib.go
index 016a68bec..c7846c9b5 100644
--- a/app/apptestlib.go
+++ b/app/apptestlib.go
@@ -106,9 +106,10 @@ func setupTestHelper(enterprise bool) *TestHelper {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = true })
- utils.SetIsLicensed(enterprise)
if enterprise {
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
+ } else {
+ th.App.SetLicense(nil)
}
return th
diff --git a/app/config.go b/app/config.go
index 55be24352..b4925e8fb 100644
--- a/app/config.go
+++ b/app/config.go
@@ -201,7 +201,7 @@ func (a *App) AsymmetricSigningKey() *ecdsa.PrivateKey {
}
func (a *App) regenerateClientConfig() {
- a.clientConfig = utils.GenerateClientConfig(a.Config(), a.DiagnosticId())
+ a.clientConfig = utils.GenerateClientConfig(a.Config(), a.DiagnosticId(), a.License())
if key := a.AsymmetricSigningKey(); key != nil {
der, _ := x509.MarshalPKIXPublicKey(&key.PublicKey)
a.clientConfig["AsymmetricSigningPublicKey"] = base64.StdEncoding.EncodeToString(der)
diff --git a/app/email.go b/app/email.go
index b809b972d..89de2ae65 100644
--- a/app/email.go
+++ b/app/email.go
@@ -316,5 +316,6 @@ func (a *App) NewEmailTemplate(name, locale string) *utils.HTMLTemplate {
}
func (a *App) SendMail(to, subject, htmlBody string) *model.AppError {
- return utils.SendMailUsingConfig(to, subject, htmlBody, a.Config())
+ license := a.License()
+ return utils.SendMailUsingConfig(to, subject, htmlBody, a.Config(), license != nil && *license.Features.Compliance)
}
diff --git a/app/file.go b/app/file.go
index d66c64adb..bb20585bb 100644
--- a/app/file.go
+++ b/app/file.go
@@ -58,7 +58,8 @@ const (
)
func (a *App) FileBackend() (utils.FileBackend, *model.AppError) {
- return utils.NewFileBackend(&a.Config().FileSettings)
+ license := a.License()
+ return utils.NewFileBackend(&a.Config().FileSettings, license != nil && *license.Features.Compliance)
}
func (a *App) ReadFile(path string) ([]byte, *model.AppError) {
diff --git a/app/license.go b/app/license.go
index 7402b5c22..efb725a20 100644
--- a/app/license.go
+++ b/app/license.go
@@ -4,16 +4,19 @@
package app
import (
+ "crypto/md5"
+ "fmt"
"net/http"
"strings"
l4g "github.com/alecthomas/log4go"
+
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
)
func (a *App) LoadLicense() {
- utils.RemoveLicense()
+ a.SetLicense(nil)
licenseId := ""
if result := <-a.Srv.Store.System().Get(); result.Err == nil {
@@ -36,7 +39,7 @@ func (a *App) LoadLicense() {
if result := <-a.Srv.Store.License().Get(licenseId); result.Err == nil {
record := result.Data.(*model.LicenseRecord)
- utils.LoadLicense([]byte(record.Bytes))
+ a.ValidateAndSetLicenseBytes([]byte(record.Bytes))
l4g.Info("License key valid unlocking enterprise features.")
} else {
l4g.Info(utils.T("mattermost.load_license.find.warn"))
@@ -104,33 +107,113 @@ func (a *App) SaveLicense(licenseBytes []byte) (*model.License, *model.AppError)
// License returns the currently active license or nil if the application is unlicensed.
func (a *App) License() *model.License {
- if utils.IsLicensed() {
- return utils.License()
- }
- return nil
+ license, _ := a.licenseValue.Load().(*model.License)
+ return license
}
func (a *App) SetLicense(license *model.License) bool {
- ok := utils.SetLicense(license)
- a.SetDefaultRolesBasedOnConfig()
- return ok
+ defer func() {
+ a.setDefaultRolesBasedOnConfig()
+ for _, listener := range a.licenseListeners {
+ listener()
+ }
+ }()
+
+ if license != nil {
+ license.Features.SetDefaults()
+
+ if !license.IsExpired() {
+ a.licenseValue.Store(license)
+ a.clientLicenseValue.Store(utils.GetClientLicense(license))
+ return true
+ }
+ }
+
+ a.licenseValue.Store((*model.License)(nil))
+ a.SetClientLicense(map[string]string{"IsLicensed": "false"})
+ return false
+}
+
+func (a *App) ValidateAndSetLicenseBytes(b []byte) {
+ if success, licenseStr := utils.ValidateLicense(b); success {
+ license := model.LicenseFromJson(strings.NewReader(licenseStr))
+ a.SetLicense(license)
+ return
+ }
+
+ l4g.Warn(utils.T("utils.license.load_license.invalid.warn"))
+}
+
+func (a *App) SetClientLicense(m map[string]string) {
+ a.clientLicenseValue.Store(m)
+}
+
+func (a *App) ClientLicense() map[string]string {
+ clientLicense, _ := a.clientLicenseValue.Load().(map[string]string)
+ return clientLicense
}
func (a *App) RemoveLicense() *model.AppError {
- utils.RemoveLicense()
+ if license, _ := a.licenseValue.Load().(*model.License); license == nil {
+ return nil
+ }
sysVar := &model.System{}
sysVar.Name = model.SYSTEM_ACTIVE_LICENSE_ID
sysVar.Value = ""
if result := <-a.Srv.Store.System().SaveOrUpdate(sysVar); result.Err != nil {
- utils.RemoveLicense()
return result.Err
}
+ a.SetLicense(nil)
a.ReloadConfig()
a.InvalidateAllCaches()
return nil
}
+
+func (a *App) AddLicenseListener(listener func()) string {
+ id := model.NewId()
+ a.licenseListeners[id] = listener
+ return id
+}
+
+func (a *App) RemoveLicenseListener(id string) {
+ delete(a.licenseListeners, id)
+}
+
+func (a *App) GetClientLicenseEtag(useSanitized bool) string {
+ value := ""
+
+ lic := a.ClientLicense()
+
+ if useSanitized {
+ lic = a.GetSanitizedClientLicense()
+ }
+
+ for k, v := range lic {
+ value += fmt.Sprintf("%s:%s;", k, v)
+ }
+
+ return model.Etag(fmt.Sprintf("%x", md5.Sum([]byte(value))))
+}
+
+func (a *App) GetSanitizedClientLicense() map[string]string {
+ sanitizedLicense := make(map[string]string)
+
+ for k, v := range a.ClientLicense() {
+ sanitizedLicense[k] = v
+ }
+
+ delete(sanitizedLicense, "Id")
+ delete(sanitizedLicense, "Name")
+ delete(sanitizedLicense, "Email")
+ delete(sanitizedLicense, "PhoneNumber")
+ delete(sanitizedLicense, "IssuedAt")
+ delete(sanitizedLicense, "StartsAt")
+ delete(sanitizedLicense, "ExpiresAt")
+
+ return sanitizedLicense
+}
diff --git a/app/license_test.go b/app/license_test.go
index 5b73d9d18..f86d604d1 100644
--- a/app/license_test.go
+++ b/app/license_test.go
@@ -4,8 +4,9 @@
package app
import (
- //"github.com/mattermost/mattermost-server/model"
"testing"
+
+ "github.com/mattermost/mattermost-server/model"
)
func TestLoadLicense(t *testing.T) {
@@ -37,3 +38,75 @@ func TestRemoveLicense(t *testing.T) {
t.Fatal("should have removed license")
}
}
+
+func TestSetLicense(t *testing.T) {
+ th := Setup()
+ defer th.TearDown()
+
+ l1 := &model.License{}
+ l1.Features = &model.Features{}
+ l1.Customer = &model.Customer{}
+ l1.StartsAt = model.GetMillis() - 1000
+ l1.ExpiresAt = model.GetMillis() + 100000
+ if ok := th.App.SetLicense(l1); !ok {
+ t.Fatal("license should have worked")
+ }
+
+ l2 := &model.License{}
+ l2.Features = &model.Features{}
+ l2.Customer = &model.Customer{}
+ l2.StartsAt = model.GetMillis() - 1000
+ l2.ExpiresAt = model.GetMillis() - 100
+ if ok := th.App.SetLicense(l2); ok {
+ t.Fatal("license should have failed")
+ }
+
+ l3 := &model.License{}
+ l3.Features = &model.Features{}
+ l3.Customer = &model.Customer{}
+ l3.StartsAt = model.GetMillis() + 10000
+ l3.ExpiresAt = model.GetMillis() + 100000
+ if ok := th.App.SetLicense(l3); !ok {
+ t.Fatal("license should have passed")
+ }
+}
+
+func TestClientLicenseEtag(t *testing.T) {
+ th := Setup()
+ defer th.TearDown()
+
+ etag1 := th.App.GetClientLicenseEtag(false)
+
+ th.App.SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "true"})
+
+ etag2 := th.App.GetClientLicenseEtag(false)
+ if etag1 == etag2 {
+ t.Fatal("etags should not match")
+ }
+
+ th.App.SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "false"})
+
+ etag3 := th.App.GetClientLicenseEtag(false)
+ if etag2 == etag3 {
+ t.Fatal("etags should not match")
+ }
+}
+
+func TestGetSanitizedClientLicense(t *testing.T) {
+ th := Setup()
+ defer th.TearDown()
+
+ l1 := &model.License{}
+ l1.Features = &model.Features{}
+ l1.Customer = &model.Customer{}
+ l1.Customer.Name = "TestName"
+ l1.StartsAt = model.GetMillis() - 1000
+ l1.ExpiresAt = model.GetMillis() + 100000
+ th.App.SetLicense(l1)
+
+ m := th.App.GetSanitizedClientLicense()
+
+ if _, ok := m["Name"]; ok {
+ t.Fatal("should have been sanatized")
+ }
+}
diff --git a/app/role.go b/app/role.go
index 5f39dd623..9f271ea7a 100644
--- a/app/role.go
+++ b/app/role.go
@@ -12,8 +12,6 @@ func (a *App) Role(id string) *model.Role {
return a.roles[id]
}
-// Updates the roles based on the app config and the global license check. You may need to invoke
-// this when license changes are made.
-func (a *App) SetDefaultRolesBasedOnConfig() {
- a.roles = utils.DefaultRolesBasedOnConfig(a.Config())
+func (a *App) setDefaultRolesBasedOnConfig() {
+ a.roles = utils.DefaultRolesBasedOnConfig(a.Config(), a.License() != nil)
}
diff --git a/app/session_test.go b/app/session_test.go
index 09d81f4ac..bf8198a4e 100644
--- a/app/session_test.go
+++ b/app/session_test.go
@@ -6,11 +6,10 @@ package app
import (
"testing"
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/utils"
-
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/mattermost/mattermost-server/model"
)
func TestCache(t *testing.T) {
@@ -111,7 +110,7 @@ func TestGetSessionIdleTimeoutInMinutes(t *testing.T) {
assert.Nil(t, err)
// Test regular session with license off, should not timeout
- *utils.License().Features.Compliance = false
+ th.App.SetLicense(nil)
session = &model.Session{
UserId: model.NewId(),
@@ -125,7 +124,7 @@ func TestGetSessionIdleTimeoutInMinutes(t *testing.T) {
_, err = th.App.GetSession(session.Token)
assert.Nil(t, err)
- *utils.License().Features.Compliance = true
+ th.App.SetLicense(model.NewTestLicense("compliance"))
// Test regular session with timeout set to 0, should not timeout
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionIdleTimeoutInMinutes = 0 })