summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris <ccbrown112@gmail.com>2018-02-12 12:02:54 -0600
committerGitHub <noreply@github.com>2018-02-12 12:02:54 -0600
commit1ae680aefae2deb1e9d07d7c2a1c863ec807a79f (patch)
treea99a74d6b858d73624c06f85e393acbe97c90586
parent9707ac3aaf2cb4352c573aadf54b8535e237dd9e (diff)
parent07fd7aeeb8eb2b198b01b713a4ab57f6352faef2 (diff)
downloadchat-1ae680aefae2deb1e9d07d7c2a1c863ec807a79f.tar.gz
chat-1ae680aefae2deb1e9d07d7c2a1c863ec807a79f.tar.bz2
chat-1ae680aefae2deb1e9d07d7c2a1c863ec807a79f.zip
Merge branch 'master' into release-4.7
-rw-r--r--Makefile4
-rw-r--r--api/api.go6
-rw-r--r--api/apitestlib.go11
-rw-r--r--api/channel_test.go245
-rw-r--r--api/context.go6
-rw-r--r--api/file.go4
-rw-r--r--api/license.go7
-rw-r--r--api/license_test.go8
-rw-r--r--api/post_test.go42
-rw-r--r--api/team_test.go42
-rw-r--r--api/user.go4
-rw-r--r--api/user_test.go15
-rw-r--r--api/webhook_test.go38
-rw-r--r--api4/apitestlib.go14
-rw-r--r--api4/channel_test.go148
-rw-r--r--api4/file.go4
-rw-r--r--api4/oauth.go24
-rw-r--r--api4/oauth_test.go62
-rw-r--r--api4/post_test.go43
-rw-r--r--api4/system.go6
-rw-r--r--api4/team_test.go71
-rw-r--r--api4/user_test.go53
-rw-r--r--app/admin.go3
-rw-r--r--app/app.go56
-rw-r--r--app/app_test.go3
-rw-r--r--app/apptestlib.go11
-rw-r--r--app/channel.go30
-rw-r--r--app/channel_test.go4
-rw-r--r--app/config.go98
-rw-r--r--app/config_test.go9
-rw-r--r--app/diagnostics.go1
-rw-r--r--app/email.go3
-rw-r--r--app/file.go3
-rw-r--r--app/license.go107
-rw-r--r--app/license_test.go75
-rw-r--r--app/plugin.go1
-rw-r--r--app/role.go6
-rw-r--r--app/server.go12
-rw-r--r--app/server_test.go50
-rw-r--r--app/session_test.go22
-rw-r--r--cmd/platform/channel.go17
-rw-r--r--cmd/platform/channel_test.go27
-rw-r--r--cmd/platform/jobserver.go2
-rw-r--r--cmd/platform/server.go19
-rw-r--r--cmd/platform/server_test.go72
-rw-r--r--cmd/platform/test.go12
-rw-r--r--i18n/en.json36
-rw-r--r--jobs/jobs_watcher.go6
-rw-r--r--jobs/server.go33
-rw-r--r--jobs/server_test.go39
-rw-r--r--model/channel_member_history.go5
-rw-r--r--model/client4.go4
-rw-r--r--model/client4_test.go58
-rw-r--r--model/config.go21
-rw-r--r--model/config_test.go52
-rw-r--r--model/license.go19
-rw-r--r--model/message_export.go1
-rw-r--r--model/post.go15
-rw-r--r--model/system.go23
-rw-r--r--store/sqlstore/channel_member_history_store.go12
-rw-r--r--store/sqlstore/compliance_store.go3
-rw-r--r--store/sqlstore/post_store.go15
-rw-r--r--store/sqlstore/upgrade.go9
-rw-r--r--store/storetest/channel_member_history_store.go16
-rw-r--r--store/storetest/compliance_store.go9
-rw-r--r--store/storetest/post_store.go23
-rw-r--r--templates/globalrelay_compliance_export.html91
-rw-r--r--templates/globalrelay_compliance_export_message.html8
-rw-r--r--templates/globalrelay_compliance_export_participant_row.html10
-rw-r--r--utils/api.go25
-rw-r--r--utils/api_test.go49
-rw-r--r--utils/authorization.go20
-rw-r--r--utils/config.go31
-rw-r--r--utils/config_test.go2
-rw-r--r--utils/file_backend.go4
-rw-r--r--utils/file_backend_test.go2
-rw-r--r--utils/html.go8
-rw-r--r--utils/inbucket.go52
-rw-r--r--utils/license.go135
-rw-r--r--utils/license_test.go67
-rw-r--r--utils/mail.go62
-rw-r--r--utils/mail_test.go89
-rw-r--r--web/web.go2
-rw-r--r--web/web_test.go5
84 files changed, 1345 insertions, 1216 deletions
diff --git a/Makefile b/Makefile
index ca8fafdb3..366c27057 100644
--- a/Makefile
+++ b/Makefile
@@ -276,7 +276,7 @@ store-mocks: ## Creates mock files.
GOPATH=$(shell go env GOPATH) $(shell go env GOPATH)/bin/mockery -dir store -all -output store/storetest/mocks -note 'Regenerate this file using `make store-mocks`.'
update-jira-plugin: ## Updates Jira plugin.
- go get github.com/jteeuwen/go-bindata/...
+ go get github.com/mattermost/go-bindata/...
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-jira/releases/latest | grep browser_download_url | grep darwin-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
$(shell go env GOPATH)/bin/go-bindata -pkg jira -o app/plugin/jira/plugin_darwin_amd64.go plugin.tar.gz
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-jira/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
@@ -287,7 +287,7 @@ update-jira-plugin: ## Updates Jira plugin.
gofmt -s -w ./app/plugin/jira
update-zoom-plugin: ## Updates Zoom plugin.
- go get github.com/jteeuwen/go-bindata/...
+ go get github.com/mattermost/go-bindata/...
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-zoom/releases/latest | grep browser_download_url | grep darwin-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
$(shell go env GOPATH)/bin/go-bindata -pkg zoom -o app/plugin/zoom/plugin_darwin_amd64.go plugin.tar.gz
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-zoom/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
diff --git a/api/api.go b/api/api.go
index 2d65bb216..70f36db85 100644
--- a/api/api.go
+++ b/api/api.go
@@ -109,7 +109,7 @@ func Init(a *app.App, root *mux.Router) *API {
api.InitReaction()
// 404 on any api route before web.go has a chance to serve it
- root.Handle("/api/{anything:.*}", http.HandlerFunc(Handle404))
+ root.Handle("/api/{anything:.*}", http.HandlerFunc(api.Handle404))
a.InitEmailBatching()
@@ -120,6 +120,10 @@ func Init(a *app.App, root *mux.Router) *API {
return api
}
+func (api *API) Handle404(w http.ResponseWriter, r *http.Request) {
+ Handle404(api.App, w, r)
+}
+
func ReturnStatusOK(w http.ResponseWriter) {
m := make(map[string]string)
m[model.STATUS] = model.STATUS_OK
diff --git a/api/apitestlib.go b/api/apitestlib.go
index 8d7f54902..47691b2dd 100644
--- a/api/apitestlib.go
+++ b/api/apitestlib.go
@@ -105,7 +105,11 @@ func setupTestHelper(enterprise bool) *TestHelper {
if testStore != nil {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
}
- th.App.StartServer()
+ serverErr := th.App.StartServer()
+ if serverErr != nil {
+ panic(serverErr)
+ }
+
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
api4.Init(th.App, th.App.Srv.Router, false)
Init(th.App, th.App.Srv.Router)
@@ -114,9 +118,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/api/channel_test.go b/api/channel_test.go
index 5533105c3..9268d9071 100644
--- a/api/channel_test.go
+++ b/api/channel_test.go
@@ -12,7 +12,6 @@ import (
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/store/sqlstore"
- "github.com/mattermost/mattermost-server/utils"
)
func TestCreateChannel(t *testing.T) {
@@ -97,23 +96,9 @@ func TestCreateChannel(t *testing.T) {
t.Fatal("Should have errored out on direct channel type")
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- restrictPublicChannel := *th.App.Config().TeamSettings.RestrictPublicChannelManagement
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManagement
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = restrictPublicChannel })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = restrictPrivateChannel })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_ALL })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_ALL })
- th.App.SetDefaultRolesBasedOnConfig()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel3 := &model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
@@ -130,7 +115,6 @@ func TestCreateChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelCreation = model.PERMISSIONS_TEAM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic2()
channel2.Name = "zz" + model.NewId() + "a"
@@ -160,7 +144,6 @@ func TestCreateChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelCreation = model.PERMISSIONS_SYSTEM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
channel2.Name = "zz" + model.NewId() + "a"
channel3.Name = "zz" + model.NewId() + "a"
@@ -181,9 +164,7 @@ func TestCreateChannel(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
- utils.SetIsLicensed(false)
- utils.SetLicense(nil)
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(nil)
channel4 := model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel5 := model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
@@ -196,7 +177,6 @@ func TestCreateChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelCreation = model.PERMISSIONS_ALL })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelCreation = model.PERMISSIONS_ALL })
- th.App.SetDefaultRolesBasedOnConfig()
}
func TestCreateDirectChannel(t *testing.T) {
@@ -367,23 +347,9 @@ func TestUpdateChannel(t *testing.T) {
t.Fatal("should have failed - channel deleted")
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- restrictPublicChannel := *th.App.Config().TeamSettings.RestrictPublicChannelManagement
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManagement
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = restrictPublicChannel })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = restrictPrivateChannel })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_ALL })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
channel2 := th.CreateChannel(Client, team)
channel3 := th.CreatePrivateChannel(Client, team)
@@ -404,14 +370,8 @@ func TestUpdateChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_CHANNEL_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_CHANNEL_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
th.MakeUserChannelUser(th.BasicUser, channel2)
th.MakeUserChannelUser(th.BasicUser, channel3)
sqlstore.ClearChannelCaches()
@@ -447,14 +407,9 @@ func TestUpdateChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_TEAM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_TEAM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
if _, err := Client.UpdateChannel(channel2); err == nil {
t.Fatal("should have errored not team admin")
@@ -477,14 +432,8 @@ func TestUpdateChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_SYSTEM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_SYSTEM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.UpdateChannel(channel2); err == nil {
t.Fatal("should have errored not system admin")
@@ -503,9 +452,7 @@ func TestUpdateChannel(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
- utils.SetIsLicensed(false)
- utils.SetLicense(nil)
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(nil)
if _, err := Client.UpdateChannel(channel2); err != nil {
t.Fatal(err)
@@ -618,23 +565,9 @@ func TestUpdateChannelHeader(t *testing.T) {
t.Fatal("should have errored non-channel member trying to update header")
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- restrictPublicChannel := *th.App.Config().TeamSettings.RestrictPublicChannelManagement
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManagement
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = restrictPublicChannel })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = restrictPrivateChannel })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_ALL })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginBasic()
channel2 := th.CreateChannel(Client, team)
@@ -659,11 +592,8 @@ func TestUpdateChannelHeader(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_CHANNEL_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_CHANNEL_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.MakeUserChannelUser(th.BasicUser, channel2)
th.MakeUserChannelUser(th.BasicUser, channel3)
sqlstore.ClearChannelCaches()
@@ -688,11 +618,8 @@ func TestUpdateChannelHeader(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_TEAM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_TEAM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.UpdateChannelHeader(data2); err == nil {
t.Fatal("should have errored not team admin")
@@ -715,11 +642,8 @@ func TestUpdateChannelHeader(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_SYSTEM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_SYSTEM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.UpdateChannelHeader(data2); err == nil {
t.Fatal("should have errored not system admin")
@@ -741,9 +665,7 @@ func TestUpdateChannelHeader(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
- utils.SetIsLicensed(false)
- utils.SetLicense(nil)
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(nil)
if _, err := SystemAdminClient.UpdateChannelHeader(data2); err != nil {
t.Fatal(err)
@@ -814,23 +736,9 @@ func TestUpdateChannelPurpose(t *testing.T) {
t.Fatal("should have errored non-channel member trying to update purpose")
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- restrictPublicChannel := *th.App.Config().TeamSettings.RestrictPublicChannelManagement
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManagement
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = restrictPublicChannel })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = restrictPrivateChannel })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_ALL })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginBasic()
channel2 := th.CreateChannel(Client, team)
@@ -855,11 +763,8 @@ func TestUpdateChannelPurpose(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_CHANNEL_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_CHANNEL_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.MakeUserChannelUser(th.BasicUser, channel2)
th.MakeUserChannelUser(th.BasicUser, channel3)
sqlstore.ClearChannelCaches()
@@ -884,11 +789,8 @@ func TestUpdateChannelPurpose(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_TEAM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_TEAM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.UpdateChannelPurpose(data2); err == nil {
t.Fatal("should have errored not team admin")
@@ -911,11 +813,8 @@ func TestUpdateChannelPurpose(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_SYSTEM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_SYSTEM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.UpdateChannelPurpose(data2); err == nil {
t.Fatal("should have errored not system admin")
@@ -937,9 +836,7 @@ func TestUpdateChannelPurpose(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
- utils.SetIsLicensed(false)
- utils.SetLicense(nil)
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(nil)
if _, err := SystemAdminClient.UpdateChannelHeader(data2); err != nil {
t.Fatal(err)
}
@@ -1400,23 +1297,9 @@ func TestDeleteChannel(t *testing.T) {
t.Fatal("should have failed - channel already deleted")
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- restrictPublicChannel := *th.App.Config().TeamSettings.RestrictPublicChannelManagement
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManagement
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = restrictPublicChannel })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = restrictPrivateChannel })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_ALL })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginSystemAdmin()
th.LinkUserToTeam(th.BasicUser, team)
@@ -1438,16 +1321,10 @@ func TestDeleteChannel(t *testing.T) {
t.Fatal(err)
}
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelDeletion = model.PERMISSIONS_CHANNEL_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelDeletion = model.PERMISSIONS_CHANNEL_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginSystemAdmin()
@@ -1498,16 +1375,11 @@ func TestDeleteChannel(t *testing.T) {
th.UpdateUserToNonTeamAdmin(th.BasicUser, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelDeletion = model.PERMISSIONS_TEAM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelDeletion = model.PERMISSIONS_TEAM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginSystemAdmin()
@@ -1537,16 +1409,10 @@ func TestDeleteChannel(t *testing.T) {
t.Fatal(err)
}
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelDeletion = model.PERMISSIONS_SYSTEM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelDeletion = model.PERMISSIONS_SYSTEM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginSystemAdmin()
@@ -1578,9 +1444,7 @@ func TestDeleteChannel(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
- utils.SetIsLicensed(false)
- utils.SetLicense(nil)
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(nil)
channel2 = th.CreateChannel(Client, team)
channel3 = th.CreatePrivateChannel(Client, team)
@@ -1595,10 +1459,6 @@ func TestDeleteChannel(t *testing.T) {
if _, err := Client.DeleteChannel(channel3.Id); err != nil {
t.Fatal(err)
}
-
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelDeletion = model.PERMISSIONS_ALL })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelDeletion = model.PERMISSIONS_ALL })
- th.App.SetDefaultRolesBasedOnConfig()
}
func TestGetChannelStats(t *testing.T) {
@@ -1675,16 +1535,9 @@ func TestAddChannelMember(t *testing.T) {
}
// Test policy does not apply to TE.
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManageMembers
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.TeamSettings.RestrictPrivateChannelManageMembers = restrictPrivateChannel
- })
- }()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_CHANNEL_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
channel3 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel3 = Client.Must(th.SystemAdminClient.CreateChannel(channel3)).Data.(*model.Channel)
@@ -1694,18 +1547,8 @@ func TestAddChannelMember(t *testing.T) {
}
// Add a license
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
// Check that a regular channel user can add other users.
channel4 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
@@ -1719,10 +1562,6 @@ func TestAddChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_CHANNEL_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
channel5 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel5 = Client.Must(th.SystemAdminClient.CreateChannel(channel5)).Data.(*model.Channel)
@@ -1733,10 +1572,7 @@ func TestAddChannelMember(t *testing.T) {
th.MakeUserChannelAdmin(user1, channel5)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
if _, err := Client.AddChannelMember(channel5.Id, user2.Id); err != nil {
t.Fatal(err)
@@ -1746,10 +1582,6 @@ func TestAddChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_TEAM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
channel6 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel6 = Client.Must(th.SystemAdminClient.CreateChannel(channel6)).Data.(*model.Channel)
@@ -1760,10 +1592,7 @@ func TestAddChannelMember(t *testing.T) {
th.UpdateUserToTeamAdmin(user1, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
if _, err := Client.AddChannelMember(channel6.Id, user2.Id); err != nil {
t.Fatal(err)
@@ -1773,10 +1602,6 @@ func TestAddChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_SYSTEM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
channel7 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel7 = Client.Must(th.SystemAdminClient.CreateChannel(channel7)).Data.(*model.Channel)
@@ -1860,16 +1685,9 @@ func TestRemoveChannelMember(t *testing.T) {
th.LoginBasic()
// Test policy does not apply to TE.
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManageMembers
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.TeamSettings.RestrictPrivateChannelManageMembers = restrictPrivateChannel
- })
- }()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_CHANNEL_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
channel3 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel3 = Client.Must(th.SystemAdminClient.CreateChannel(channel3)).Data.(*model.Channel)
@@ -1880,18 +1698,8 @@ func TestRemoveChannelMember(t *testing.T) {
}
// Add a license
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
// Check that a regular channel user can remove other users.
channel4 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
@@ -1906,10 +1714,6 @@ func TestRemoveChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_CHANNEL_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
channel5 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel5 = Client.Must(th.SystemAdminClient.CreateChannel(channel5)).Data.(*model.Channel)
@@ -1921,9 +1725,7 @@ func TestRemoveChannelMember(t *testing.T) {
th.MakeUserChannelAdmin(user1, channel5)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
if _, err := Client.RemoveChannelMember(channel5.Id, user2.Id); err != nil {
t.Fatal(err)
@@ -1933,10 +1735,6 @@ func TestRemoveChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_TEAM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
channel6 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel6 = Client.Must(th.SystemAdminClient.CreateChannel(channel6)).Data.(*model.Channel)
@@ -1948,10 +1746,7 @@ func TestRemoveChannelMember(t *testing.T) {
th.UpdateUserToTeamAdmin(user1, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
if _, err := Client.RemoveChannelMember(channel6.Id, user2.Id); err != nil {
t.Fatal(err)
@@ -1961,10 +1756,6 @@ func TestRemoveChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_SYSTEM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
channel7 := &model.Channel{DisplayName: "A Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel7 = Client.Must(th.SystemAdminClient.CreateChannel(channel7)).Data.(*model.Channel)
diff --git a/api/context.go b/api/context.go
index b28a24731..a8ff2b694 100644
--- a/api/context.go
+++ b/api/context.go
@@ -229,7 +229,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if c.Err.StatusCode == http.StatusUnauthorized {
http.Redirect(w, r, c.GetTeamURL()+"/?redirect="+url.QueryEscape(r.URL.Path), http.StatusTemporaryRedirect)
} else {
- utils.RenderWebError(c.Err, w, r)
+ utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
}
}
@@ -434,7 +434,7 @@ func IsApiCall(r *http.Request) bool {
return strings.Index(r.URL.Path, "/api/") == 0
}
-func Handle404(w http.ResponseWriter, r *http.Request) {
+func Handle404(a *app.App, w http.ResponseWriter, r *http.Request) {
err := model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound)
l4g.Debug("%v: code=404 ip=%v", r.URL.Path, utils.GetIpAddress(r))
@@ -444,7 +444,7 @@ func Handle404(w http.ResponseWriter, r *http.Request) {
err.DetailedError = "There doesn't appear to be an api call for the url='" + r.URL.Path + "'. Typo? are you missing a team_id or user_id as part of the url?"
w.Write([]byte(err.ToJson()))
} else {
- utils.RenderWebError(err, w, r)
+ utils.RenderWebAppError(w, r, err, a.AsymmetricSigningKey())
}
}
diff --git a/api/file.go b/api/file.go
index 2d626304e..3b8984816 100644
--- a/api/file.go
+++ b/api/file.go
@@ -174,12 +174,12 @@ func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) {
if hash != correctHash {
c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
+ utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
return
}
} else {
c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
+ utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
return
}
diff --git a/api/license.go b/api/license.go
index 8eb7803e1..432442ad6 100644
--- a/api/license.go
+++ b/api/license.go
@@ -9,7 +9,6 @@ import (
"net/http"
"github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/utils"
)
func (api *API) InitLicense() {
@@ -83,7 +82,7 @@ func removeLicense(c *Context, w http.ResponseWriter, r *http.Request) {
func getClientLicenceConfig(c *Context, w http.ResponseWriter, r *http.Request) {
useSanitizedLicense := !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM)
- etag := utils.GetClientLicenseEtag(useSanitizedLicense)
+ etag := c.App.GetClientLicenseEtag(useSanitizedLicense)
if c.HandleEtag(etag, "Get Client License Config", w, r) {
return
}
@@ -91,9 +90,9 @@ func getClientLicenceConfig(c *Context, w http.ResponseWriter, r *http.Request)
var clientLicense map[string]string
if useSanitizedLicense {
- clientLicense = utils.ClientLicense()
+ clientLicense = c.App.ClientLicense()
} else {
- clientLicense = utils.GetSanitizedClientLicense()
+ clientLicense = c.App.GetSanitizedClientLicense()
}
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
diff --git a/api/license_test.go b/api/license_test.go
index 50d73101d..47586151a 100644
--- a/api/license_test.go
+++ b/api/license_test.go
@@ -5,8 +5,6 @@ package api
import (
"testing"
-
- "github.com/mattermost/mattermost-server/utils"
)
func TestGetLicenceConfig(t *testing.T) {
@@ -32,7 +30,7 @@ func TestGetLicenceConfig(t *testing.T) {
t.Fatal("cache should be empty")
}
- utils.SetClientLicense(map[string]string{"IsLicensed": "true"})
+ th.App.SetClientLicense(map[string]string{"IsLicensed": "true"})
if cache_result, err := Client.GetClientLicenceConfig(result.Etag); err != nil {
t.Fatal(err)
@@ -40,7 +38,7 @@ func TestGetLicenceConfig(t *testing.T) {
t.Fatal("result should not be empty")
}
- utils.SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "true"})
+ th.App.SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "true"})
if cache_result, err := Client.GetClientLicenceConfig(result.Etag); err != nil {
t.Fatal(err)
@@ -48,6 +46,6 @@ func TestGetLicenceConfig(t *testing.T) {
t.Fatal("result should not be empty")
}
- utils.SetClientLicense(map[string]string{"IsLicensed": "false"})
+ th.App.SetClientLicense(map[string]string{"IsLicensed": "false"})
}
}
diff --git a/api/post_test.go b/api/post_test.go
index 299fdf046..2fc79d9b1 100644
--- a/api/post_test.go
+++ b/api/post_test.go
@@ -160,20 +160,8 @@ func TestCreatePost(t *testing.T) {
}
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- disableTownSquareReadOnly := th.App.Config().TeamSettings.ExperimentalTownSquareIsReadOnly
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = disableTownSquareReadOnly })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = true })
- th.App.SetDefaultRolesBasedOnConfig()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
defaultChannel := store.Must(th.App.Srv.Store.Channel().GetByName(team.Id, model.DEFAULT_CHANNEL, true)).(*model.Channel)
defaultPost := &model.Post{
@@ -466,16 +454,7 @@ func TestUpdatePost(t *testing.T) {
}
// Test licensed policy controls for edit post
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
-
+ th.App.SetLicense(model.NewTestLicense())
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = model.ALLOW_EDIT_POST_NEVER })
post4 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
@@ -966,7 +945,6 @@ func TestDeletePosts(t *testing.T) {
team1 := th.BasicTeam
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.RestrictPostDelete = model.PERMISSIONS_DELETE_POST_ALL })
- th.App.SetDefaultRolesBasedOnConfig()
time.Sleep(10 * time.Millisecond)
post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
@@ -1021,15 +999,7 @@ func TestDeletePosts(t *testing.T) {
}
// Test licensed policy controls for delete post
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
th.UpdateUserToTeamAdmin(th.BasicUser2, th.BasicTeam)
@@ -1044,7 +1014,6 @@ func TestDeletePosts(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.RestrictPostDelete = model.PERMISSIONS_DELETE_POST_TEAM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
@@ -1069,7 +1038,6 @@ func TestDeletePosts(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.RestrictPostDelete = model.PERMISSIONS_DELETE_POST_SYSTEM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
@@ -1088,9 +1056,7 @@ func TestDeletePosts(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
- utils.SetIsLicensed(false)
- utils.SetLicense(nil)
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(nil)
time.Sleep(10 * time.Millisecond)
post7 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
diff --git a/api/team_test.go b/api/team_test.go
index b1c892544..696cf31bb 100644
--- a/api/team_test.go
+++ b/api/team_test.go
@@ -139,20 +139,8 @@ func TestAddUserToTeam(t *testing.T) {
t.Fatal(err)
}
- // Restore config/license at end of test case.
- restrictTeamInvite := *th.App.Config().TeamSettings.RestrictTeamInvite
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = restrictTeamInvite })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
-
// Set the config so that only team admins can add a user to a team.
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_TEAM_ADMIN })
- th.App.SetDefaultRolesBasedOnConfig()
// Test without the EE license to see that the permission restriction is ignored.
user3 := th.CreateUser(th.BasicClient)
@@ -161,10 +149,7 @@ func TestAddUserToTeam(t *testing.T) {
}
// Add an EE license.
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
// Check that a regular user can't add someone to the team.
user4 := th.CreateUser(th.BasicClient)
@@ -175,11 +160,8 @@ func TestAddUserToTeam(t *testing.T) {
// Should work as team admin.
th.UpdateUserToTeamAdmin(th.BasicUser, th.BasicTeam)
th.App.InvalidateAllCaches()
+ th.App.SetLicense(model.NewTestLicense())
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_TEAM_ADMIN })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
user5 := th.CreateUser(th.BasicClient)
if _, err := th.BasicClient.AddUserToTeam(th.BasicTeam.Id, user5.Id); err != nil {
@@ -188,7 +170,6 @@ func TestAddUserToTeam(t *testing.T) {
// Change permission level to System Admin
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_SYSTEM_ADMIN })
- th.App.SetDefaultRolesBasedOnConfig()
// Should not work as team admin.
user6 := th.CreateUser(th.BasicClient)
@@ -565,13 +546,7 @@ func TestInviteMembers(t *testing.T) {
t.Fatal("Should have errored out on no invites to send")
}
- restrictTeamInvite := *th.App.Config().TeamSettings.RestrictTeamInvite
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = restrictTeamInvite })
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_TEAM_ADMIN })
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic2()
th.LinkUserToTeam(th.BasicUser2, team)
@@ -580,17 +555,7 @@ func TestInviteMembers(t *testing.T) {
t.Fatal(err)
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
if _, err := Client.InviteMembers(invites); err == nil {
t.Fatal("should have errored not team admin and licensed")
@@ -606,7 +571,6 @@ func TestInviteMembers(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_SYSTEM_ADMIN })
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.InviteMembers(invites); err == nil {
t.Fatal("should have errored not system admin and licensed")
diff --git a/api/user.go b/api/user.go
index 440ea5858..ad4f12ef3 100644
--- a/api/user.go
+++ b/api/user.go
@@ -299,9 +299,9 @@ func getInitialLoad(c *Context, w http.ResponseWriter, r *http.Request) {
il.ClientCfg = c.App.ClientConfig()
if c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- il.LicenseCfg = utils.ClientLicense()
+ il.LicenseCfg = c.App.ClientLicense()
} else {
- il.LicenseCfg = utils.GetSanitizedClientLicense()
+ il.LicenseCfg = c.App.GetSanitizedClientLicense()
}
w.Write([]byte(il.ToJson()))
diff --git a/api/user_test.go b/api/user_test.go
index 8d6aad22b..f65d7c45b 100644
--- a/api/user_test.go
+++ b/api/user_test.go
@@ -1889,17 +1889,7 @@ func TestUpdateMfa(t *testing.T) {
Client := th.BasicClient
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- }()
- utils.SetIsLicensed(false)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- if utils.License().Features.MFA == nil {
- utils.License().Features.MFA = new(bool)
- }
+ th.App.SetLicense(nil)
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, _ := Client.CreateTeam(&team)
@@ -1925,8 +1915,7 @@ func TestUpdateMfa(t *testing.T) {
t.Fatal("should have failed - not licensed")
}
- utils.SetIsLicensed(true)
- *utils.License().Features.MFA = true
+ th.App.SetLicense(model.NewTestLicense("mfa"))
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
if _, err := Client.UpdateMfa(true, "123456"); err == nil {
diff --git a/api/webhook_test.go b/api/webhook_test.go
index b5a836603..f4d46496b 100644
--- a/api/webhook_test.go
+++ b/api/webhook_test.go
@@ -9,7 +9,6 @@ import (
"testing"
"github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/utils"
)
func TestCreateIncomingHook(t *testing.T) {
@@ -93,7 +92,6 @@ func TestCreateIncomingHook(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.CreateIncomingWebhook(hook); err != nil {
t.Fatal(err)
@@ -133,7 +131,6 @@ func TestUpdateIncomingHook(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
hook := createIncomingWebhook(channel1.Id, Client, t)
@@ -217,7 +214,6 @@ func TestUpdateIncomingHook(t *testing.T) {
t.Run("OnlyAdminIntegrationsDisabled", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
t.Run("UpdateHookOfSameUser", func(t *testing.T) {
sameUserHook := &model.IncomingWebhook{ChannelId: channel1.Id, UserId: user2.Id}
@@ -240,7 +236,6 @@ func TestUpdateIncomingHook(t *testing.T) {
})
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
Client.Logout()
th.UpdateUserToTeamAdmin(user2, team)
@@ -324,7 +319,6 @@ func TestListIncomingHooks(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
hook1 := &model.IncomingWebhook{ChannelId: channel1.Id}
hook1 = Client.Must(Client.CreateIncomingWebhook(hook1)).Data.(*model.IncomingWebhook)
@@ -351,7 +345,6 @@ func TestListIncomingHooks(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.ListIncomingWebhooks(); err != nil {
t.Fatal(err)
@@ -376,7 +369,6 @@ func TestDeleteIncomingHook(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
hook := &model.IncomingWebhook{ChannelId: channel1.Id}
hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
@@ -410,7 +402,6 @@ func TestDeleteIncomingHook(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil {
t.Fatal("should have failed - not creator or team admin")
@@ -447,7 +438,6 @@ func TestCreateOutgoingHook(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
@@ -518,7 +508,6 @@ func TestCreateOutgoingHook(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.CreateOutgoingWebhook(hook); err != nil {
t.Fatal(err)
@@ -551,7 +540,6 @@ func TestListOutgoingHooks(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
hook1 := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook1 = Client.Must(Client.CreateOutgoingWebhook(hook1)).Data.(*model.OutgoingWebhook)
@@ -578,7 +566,6 @@ func TestListOutgoingHooks(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.ListOutgoingWebhooks(); err != nil {
t.Fatal(err)
@@ -609,7 +596,6 @@ func TestUpdateOutgoingHook(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
hook := createOutgoingWebhook(channel1.Id, []string{"http://nowhere.com"}, []string{"cats"}, Client, t)
createOutgoingWebhook(channel1.Id, []string{"http://nowhere.com"}, []string{"dogs"}, Client, t)
@@ -683,7 +669,6 @@ func TestUpdateOutgoingHook(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
hook2 := createOutgoingWebhook(channel1.Id, []string{"http://nowhereelse.com"}, []string{"dogs"}, Client, t)
if _, err := Client.UpdateOutgoingWebhook(hook2); err != nil {
@@ -691,7 +676,6 @@ func TestUpdateOutgoingHook(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
Client.Logout()
th.LinkUserToTeam(user3, team)
@@ -779,7 +763,6 @@ func TestDeleteOutgoingHook(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
@@ -813,7 +796,6 @@ func TestDeleteOutgoingHook(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil {
t.Fatal("should have failed - not creator or team admin")
@@ -848,7 +830,6 @@ func TestRegenOutgoingHookToken(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
@@ -883,7 +864,6 @@ func TestRegenOutgoingHookToken(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
@@ -917,10 +897,6 @@ func TestIncomingWebhooks(t *testing.T) {
user2 := th.CreateUser(Client)
th.LinkUserToTeam(user2, team)
- enableIncomingHooks := th.App.Config().ServiceSettings.EnableIncomingWebhooks
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true })
hook := &model.IncomingWebhook{ChannelId: channel1.Id}
@@ -962,20 +938,8 @@ func TestIncomingWebhooks(t *testing.T) {
t.Fatal("should not have failed -- ExperimentalTownSquareIsReadOnly is false and it's not a read only channel")
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- disableTownSquareReadOnly := th.App.Config().TeamSettings.ExperimentalTownSquareIsReadOnly
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = disableTownSquareReadOnly })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = true })
- th.App.SetDefaultRolesBasedOnConfig()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
if _, err := th.BasicClient.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", model.DEFAULT_CHANNEL), "application/json"); err == nil {
t.Fatal("should have failed -- ExperimentalTownSquareIsReadOnly is true and it's a read only channel")
diff --git a/api4/apitestlib.go b/api4/apitestlib.go
index a7e64ae84..db43a6512 100644
--- a/api4/apitestlib.go
+++ b/api4/apitestlib.go
@@ -113,7 +113,11 @@ func setupTestHelper(enterprise bool) *TestHelper {
if testStore != nil {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
}
- th.App.StartServer()
+ serverErr := th.App.StartServer()
+ if serverErr != nil {
+ panic(serverErr)
+ }
+
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
Init(th.App, th.App.Srv.Router, true)
wsapi.Init(th.App, th.App.Srv.WebSocketRouter)
@@ -121,9 +125,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)
}
th.Client = th.CreateClient()
@@ -298,8 +303,7 @@ func (me *TestHelper) CreateUserWithClient(client *model.Client4) *model.User {
}
utils.DisableDebugLogForTest()
- ruser, r := client.CreateUser(user)
- fmt.Println(r)
+ ruser, _ := client.CreateUser(user)
ruser.Password = "Password1"
store.Must(me.App.Srv.Store.User().VerifyEmail(ruser.Id))
utils.EnableDebugLogForTest()
diff --git a/api4/channel_test.go b/api4/channel_test.go
index 724b0d84b..e65918707 100644
--- a/api4/channel_test.go
+++ b/api4/channel_test.go
@@ -14,7 +14,6 @@ import (
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store/sqlstore"
- "github.com/mattermost/mattermost-server/utils"
)
func TestCreateChannel(t *testing.T) {
@@ -82,23 +81,9 @@ func TestCreateChannel(t *testing.T) {
th.LoginBasic()
// Check permissions with policy config changes
- isLicensed := utils.IsLicensed()
- license := utils.License()
- restrictPublicChannel := *th.App.Config().TeamSettings.RestrictPublicChannelCreation
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelCreation
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelCreation = restrictPublicChannel })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelCreation = restrictPrivateChannel })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelCreation = model.PERMISSIONS_ALL })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelCreation = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
channel.Name = GenerateTestChannelName()
_, resp = Client.CreateChannel(channel)
@@ -110,11 +95,8 @@ func TestCreateChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelCreation = model.PERMISSIONS_TEAM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelCreation = model.PERMISSIONS_TEAM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
_, resp = Client.CreateChannel(channel)
CheckForbiddenStatus(t, resp)
@@ -142,11 +124,8 @@ func TestCreateChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelCreation = model.PERMISSIONS_SYSTEM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelCreation = model.PERMISSIONS_SYSTEM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
@@ -173,9 +152,7 @@ func TestCreateChannel(t *testing.T) {
CheckNoError(t, resp)
// Check that if unlicensed the policy restriction is not enforced.
- utils.SetIsLicensed(false)
- utils.SetLicense(nil)
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(nil)
channel.Name = GenerateTestChannelName()
_, resp = Client.CreateChannel(channel)
@@ -887,23 +864,9 @@ func TestDeleteChannel(t *testing.T) {
th.InitBasic().InitSystemAdmin()
- isLicensed := utils.IsLicensed()
- license := utils.License()
- restrictPublicChannel := *th.App.Config().TeamSettings.RestrictPublicChannelManagement
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManagement
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = restrictPublicChannel })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = restrictPrivateChannel })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPublicChannelManagement = model.PERMISSIONS_ALL })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManagement = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
Client = th.Client
team = th.BasicTeam
@@ -926,11 +889,8 @@ func TestDeleteChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelDeletion = model.PERMISSIONS_CHANNEL_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelDeletion = model.PERMISSIONS_CHANNEL_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
// channels created by SystemAdmin
publicChannel6 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN)
@@ -967,9 +927,7 @@ func TestDeleteChannel(t *testing.T) {
// successful delete by team admin
th.UpdateUserToTeamAdmin(user, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckNoError(t, resp)
@@ -979,16 +937,11 @@ func TestDeleteChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelDeletion = model.PERMISSIONS_TEAM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelDeletion = model.PERMISSIONS_TEAM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
th.UpdateUserToNonTeamAdmin(user, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
// channels created by SystemAdmin
publicChannel6 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN)
@@ -1018,9 +971,7 @@ func TestDeleteChannel(t *testing.T) {
// successful delete by team admin
th.UpdateUserToTeamAdmin(th.BasicUser, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckNoError(t, resp)
@@ -1030,11 +981,8 @@ func TestDeleteChannel(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPublicChannelDeletion = model.PERMISSIONS_SYSTEM_ADMIN
- })
- th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelDeletion = model.PERMISSIONS_SYSTEM_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
// channels created by SystemAdmin
publicChannel6 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN)
@@ -1064,9 +1012,7 @@ func TestDeleteChannel(t *testing.T) {
// cannot delete by team admin
th.UpdateUserToTeamAdmin(th.BasicUser, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckForbiddenStatus(t, resp)
@@ -1823,16 +1769,9 @@ func TestAddChannelMember(t *testing.T) {
CheckNoError(t, resp)
// Test policy does not apply to TE.
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManageMembers
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.TeamSettings.RestrictPrivateChannelManageMembers = restrictPrivateChannel
- })
- }()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_CHANNEL_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
Client.Login(user2.Username, user2.Password)
privateChannel = th.CreatePrivateChannel()
@@ -1846,18 +1785,8 @@ func TestAddChannelMember(t *testing.T) {
Client.Logout()
// Add a license
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
// Check that a regular channel user can add other users.
Client.Login(user2.Username, user2.Password)
@@ -1875,10 +1804,6 @@ func TestAddChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_CHANNEL_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
Client.Login(user2.Username, user2.Password)
privateChannel = th.CreatePrivateChannel()
@@ -1893,10 +1818,7 @@ func TestAddChannelMember(t *testing.T) {
th.MakeUserChannelAdmin(user, privateChannel)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
Client.Login(user.Username, user.Password)
_, resp = Client.AddChannelMember(privateChannel.Id, user3.Id)
@@ -1907,10 +1829,6 @@ func TestAddChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_TEAM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
Client.Login(user2.Username, user2.Password)
privateChannel = th.CreatePrivateChannel()
@@ -1925,10 +1843,7 @@ func TestAddChannelMember(t *testing.T) {
th.UpdateUserToTeamAdmin(user, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
Client.Login(user.Username, user.Password)
_, resp = Client.AddChannelMember(privateChannel.Id, user3.Id)
@@ -1939,10 +1854,6 @@ func TestAddChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_SYSTEM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
Client.Login(user2.Username, user2.Password)
privateChannel = th.CreatePrivateChannel()
@@ -2019,16 +1930,9 @@ func TestRemoveChannelMember(t *testing.T) {
th.App.InvalidateAllCaches()
// Test policy does not apply to TE.
- restrictPrivateChannel := *th.App.Config().TeamSettings.RestrictPrivateChannelManageMembers
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.TeamSettings.RestrictPrivateChannelManageMembers = restrictPrivateChannel
- })
- }()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_CHANNEL_ADMIN
})
- th.App.SetDefaultRolesBasedOnConfig()
privateChannel := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE)
_, resp = th.SystemAdminClient.AddChannelMember(privateChannel.Id, user1.Id)
@@ -2040,18 +1944,8 @@ func TestRemoveChannelMember(t *testing.T) {
CheckNoError(t, resp)
// Add a license
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
// Check that a regular channel user can remove other users.
privateChannel = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE)
@@ -2067,10 +1961,6 @@ func TestRemoveChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_CHANNEL_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
privateChannel = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE)
_, resp = th.SystemAdminClient.AddChannelMember(privateChannel.Id, user1.Id)
@@ -2083,9 +1973,7 @@ func TestRemoveChannelMember(t *testing.T) {
th.MakeUserChannelAdmin(user1, privateChannel)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
_, resp = Client.RemoveUserFromChannel(privateChannel.Id, user2.Id)
CheckNoError(t, resp)
@@ -2094,10 +1982,6 @@ func TestRemoveChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_TEAM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
privateChannel = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE)
_, resp = th.SystemAdminClient.AddChannelMember(privateChannel.Id, user1.Id)
@@ -2110,9 +1994,7 @@ func TestRemoveChannelMember(t *testing.T) {
th.UpdateUserToTeamAdmin(user1, team)
th.App.InvalidateAllCaches()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
_, resp = Client.RemoveUserFromChannel(privateChannel.Id, user2.Id)
CheckNoError(t, resp)
@@ -2121,10 +2003,6 @@ func TestRemoveChannelMember(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelManageMembers = model.PERMISSIONS_SYSTEM_ADMIN
})
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
privateChannel = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE)
_, resp = th.SystemAdminClient.AddChannelMember(privateChannel.Id, user1.Id)
diff --git a/api4/file.go b/api4/file.go
index 48ee281fe..acc4c78e5 100644
--- a/api4/file.go
+++ b/api4/file.go
@@ -281,13 +281,13 @@ func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) {
if len(hash) == 0 {
c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
+ utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
return
}
if hash != app.GeneratePublicLinkHash(info.Id, *c.App.Config().FileSettings.PublicLinkSalt) {
c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
+ utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
return
}
diff --git a/api4/oauth.go b/api4/oauth.go
index 655adaaee..d0f43256a 100644
--- a/api4/oauth.go
+++ b/api4/oauth.go
@@ -313,7 +313,7 @@ func deauthorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
if !c.App.Config().ServiceSettings.EnableOAuthServiceProvider {
err := model.NewAppError("authorizeOAuth", "api.oauth.authorize_oauth.disabled.app_error", nil, "", http.StatusNotImplemented)
- utils.RenderWebError(err, w, r)
+ utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
return
}
@@ -326,13 +326,13 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
}
if err := authRequest.IsValid(); err != nil {
- utils.RenderWebError(err, w, r)
+ utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
return
}
oauthApp, err := c.App.GetOAuthApp(authRequest.ClientId)
if err != nil {
- utils.RenderWebError(err, w, r)
+ utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
return
}
@@ -343,7 +343,8 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
}
if !oauthApp.IsValidRedirectURL(authRequest.RedirectUri) {
- utils.RenderWebError(model.NewAppError("authorizeOAuthPage", "api.oauth.allow_oauth.redirect_callback.app_error", nil, "", http.StatusBadRequest), w, r)
+ err := model.NewAppError("authorizeOAuthPage", "api.oauth.allow_oauth.redirect_callback.app_error", nil, "", http.StatusBadRequest)
+ utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
return
}
@@ -360,7 +361,7 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
redirectUrl, err := c.App.AllowOAuthAppAccessToUser(c.Session.UserId, authRequest)
if err != nil {
- utils.RenderWebError(err, w, r)
+ utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
return
}
@@ -441,7 +442,10 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
if len(code) == 0 {
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?type=oauth_missing_code&service="+strings.Title(service), http.StatusTemporaryRedirect)
+ utils.RenderWebError(w, r, http.StatusTemporaryRedirect, url.Values{
+ "type": []string{"oauth_missing_code"},
+ "service": []string{strings.Title(service)},
+ }, c.App.AsymmetricSigningKey())
return
}
@@ -462,7 +466,7 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
if action == model.OAUTH_ACTION_MOBILE {
w.Write([]byte(err.ToJson()))
} else {
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+url.QueryEscape(err.Message), http.StatusTemporaryRedirect)
+ utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
}
return
}
@@ -474,7 +478,7 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
if action == model.OAUTH_ACTION_MOBILE {
w.Write([]byte(err.ToJson()))
} else {
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+url.QueryEscape(err.Message), http.StatusTemporaryRedirect)
+ utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
}
return
}
@@ -559,7 +563,9 @@ func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
}
if !c.App.Config().TeamSettings.EnableUserCreation {
- http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+url.QueryEscape(utils.T("api.oauth.singup_with_oauth.disabled.app_error")), http.StatusTemporaryRedirect)
+ utils.RenderWebError(w, r, http.StatusBadRequest, url.Values{
+ "message": []string{utils.T("api.oauth.singup_with_oauth.disabled.app_error")},
+ }, c.App.AsymmetricSigningKey())
return
}
diff --git a/api4/oauth_test.go b/api4/oauth_test.go
index 8dd602456..c871dafff 100644
--- a/api4/oauth_test.go
+++ b/api4/oauth_test.go
@@ -18,14 +18,7 @@ func TestCreateOAuthApp(t *testing.T) {
Client := th.Client
AdminClient := th.SystemAdminClient
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- adminOnly := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = adminOnly })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
- th.App.SetDefaultRolesBasedOnConfig()
oapp := &model.OAuthApp{Name: GenerateTestAppName(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}, IsTrusted: true}
@@ -42,12 +35,10 @@ func TestCreateOAuthApp(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
_, resp = Client.CreateOAuthApp(oapp)
CheckForbiddenStatus(t, resp)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
rapp, resp = Client.CreateOAuthApp(oapp)
CheckNoError(t, resp)
CheckCreatedStatus(t, resp)
@@ -86,14 +77,7 @@ func TestUpdateOAuthApp(t *testing.T) {
Client := th.Client
AdminClient := th.SystemAdminClient
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- adminOnly := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = adminOnly })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
- th.App.SetDefaultRolesBasedOnConfig()
oapp := &model.OAuthApp{
Name: "oapp",
@@ -172,7 +156,6 @@ func TestUpdateOAuthApp(t *testing.T) {
th.LoginBasic()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
_, resp = Client.UpdateOAuthApp(oapp)
CheckForbiddenStatus(t, resp)
@@ -199,15 +182,8 @@ func TestGetOAuthApps(t *testing.T) {
Client := th.Client
AdminClient := th.SystemAdminClient
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- adminOnly := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = adminOnly })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
oapp := &model.OAuthApp{Name: GenerateTestAppName(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
@@ -251,7 +227,6 @@ func TestGetOAuthApps(t *testing.T) {
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
_, resp = Client.GetOAuthApps(0, 1000)
CheckForbiddenStatus(t, resp)
@@ -272,15 +247,8 @@ func TestGetOAuthApp(t *testing.T) {
Client := th.Client
AdminClient := th.SystemAdminClient
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- adminOnly := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = adminOnly })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
oapp := &model.OAuthApp{Name: GenerateTestAppName(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
@@ -320,7 +288,6 @@ func TestGetOAuthApp(t *testing.T) {
CheckForbiddenStatus(t, resp)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
_, resp = Client.GetOAuthApp(rapp2.Id)
CheckForbiddenStatus(t, resp)
@@ -347,15 +314,8 @@ func TestGetOAuthAppInfo(t *testing.T) {
Client := th.Client
AdminClient := th.SystemAdminClient
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- adminOnly := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = adminOnly })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
oapp := &model.OAuthApp{Name: GenerateTestAppName(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
@@ -395,7 +355,6 @@ func TestGetOAuthAppInfo(t *testing.T) {
CheckNoError(t, resp)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
_, resp = Client.GetOAuthAppInfo(rapp2.Id)
CheckNoError(t, resp)
@@ -422,15 +381,8 @@ func TestDeleteOAuthApp(t *testing.T) {
Client := th.Client
AdminClient := th.SystemAdminClient
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- adminOnly := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = adminOnly })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
oapp := &model.OAuthApp{Name: GenerateTestAppName(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
@@ -465,7 +417,6 @@ func TestDeleteOAuthApp(t *testing.T) {
CheckNoError(t, resp)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
_, resp = Client.DeleteOAuthApp(rapp.Id)
CheckForbiddenStatus(t, resp)
@@ -490,15 +441,8 @@ func TestRegenerateOAuthAppSecret(t *testing.T) {
Client := th.Client
AdminClient := th.SystemAdminClient
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- adminOnly := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = adminOnly })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
oapp := &model.OAuthApp{Name: GenerateTestAppName(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
@@ -537,7 +481,6 @@ func TestRegenerateOAuthAppSecret(t *testing.T) {
CheckNoError(t, resp)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false })
- th.App.SetDefaultRolesBasedOnConfig()
_, resp = Client.RegenerateOAuthAppSecret(rapp.Id)
CheckForbiddenStatus(t, resp)
@@ -622,12 +565,7 @@ func TestAuthorizeOAuthApp(t *testing.T) {
Client := th.Client
AdminClient := th.SystemAdminClient
- enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true })
- th.App.SetDefaultRolesBasedOnConfig()
oapp := &model.OAuthApp{Name: GenerateTestAppName(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
diff --git a/api4/post_test.go b/api4/post_test.go
index 6f770b70a..257918525 100644
--- a/api4/post_test.go
+++ b/api4/post_test.go
@@ -17,7 +17,6 @@ import (
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/utils"
)
func TestCreatePost(t *testing.T) {
@@ -130,20 +129,8 @@ func testCreatePostWithOutgoingHook(
team := th.BasicTeam
channel := th.BasicChannel
- enableOutgoingHooks := th.App.Config().ServiceSettings.EnableOutgoingWebhooks
- enableAdminOnlyHooks := th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations
- allowedInternalConnections := *th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks })
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks })
- th.App.SetDefaultRolesBasedOnConfig()
- th.App.UpdateConfig(func(cfg *model.Config) {
- cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
- })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = true })
- th.App.SetDefaultRolesBasedOnConfig()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
})
@@ -489,21 +476,8 @@ func TestUpdatePost(t *testing.T) {
Client := th.Client
channel := th.BasicChannel
- isLicensed := utils.IsLicensed()
- license := utils.License()
- allowEditPost := *th.App.Config().ServiceSettings.AllowEditPost
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = allowEditPost })
- th.App.SetDefaultRolesBasedOnConfig()
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
-
+ th.App.SetLicense(model.NewTestLicense())
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = model.ALLOW_EDIT_POST_ALWAYS })
- th.App.SetDefaultRolesBasedOnConfig()
post := &model.Post{ChannelId: channel.Id, Message: "zz" + model.NewId() + "a"}
rpost, resp := Client.CreatePost(post)
@@ -574,21 +548,8 @@ func TestPatchPost(t *testing.T) {
Client := th.Client
channel := th.BasicChannel
- isLicensed := utils.IsLicensed()
- license := utils.License()
- allowEditPost := *th.App.Config().ServiceSettings.AllowEditPost
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = allowEditPost })
- th.App.SetDefaultRolesBasedOnConfig()
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
-
+ th.App.SetLicense(model.NewTestLicense())
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = model.ALLOW_EDIT_POST_ALWAYS })
- th.App.SetDefaultRolesBasedOnConfig()
post := &model.Post{
ChannelId: channel.Id,
diff --git a/api4/system.go b/api4/system.go
index 43b941247..061ffe094 100644
--- a/api4/system.go
+++ b/api4/system.go
@@ -266,7 +266,7 @@ func getClientLicense(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- etag := utils.GetClientLicenseEtag(true)
+ etag := c.App.GetClientLicenseEtag(true)
if c.HandleEtag(etag, "Get Client License", w, r) {
return
}
@@ -274,9 +274,9 @@ func getClientLicense(c *Context, w http.ResponseWriter, r *http.Request) {
var clientLicense map[string]string
if c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
- clientLicense = utils.ClientLicense()
+ clientLicense = c.App.ClientLicense()
} else {
- clientLicense = utils.GetSanitizedClientLicense()
+ clientLicense = c.App.GetSanitizedClientLicense()
}
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
diff --git a/api4/team_test.go b/api4/team_test.go
index d365fd686..faa90e511 100644
--- a/api4/team_test.go
+++ b/api4/team_test.go
@@ -68,13 +68,7 @@ func TestCreateTeam(t *testing.T) {
CheckUnauthorizedStatus(t, resp)
// Update permission
- enableTeamCreation := th.App.Config().TeamSettings.EnableTeamCreation
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableTeamCreation = enableTeamCreation })
- th.App.SetDefaultRolesBasedOnConfig()
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableTeamCreation = false })
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
_, resp = Client.CreateTeam(team)
@@ -1292,20 +1286,8 @@ func TestAddTeamMember(t *testing.T) {
Client.Logout()
- // Check effects of config and license changes.
- restrictTeamInvite := *th.App.Config().TeamSettings.RestrictTeamInvite
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = restrictTeamInvite })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
-
// Set the config so that only team admins can add a user to a team.
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_TEAM_ADMIN })
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
// Test without the EE license to see that the permission restriction is ignored.
@@ -1313,10 +1295,7 @@ func TestAddTeamMember(t *testing.T) {
CheckNoError(t, resp)
// Add an EE license.
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginBasic()
// Check that a regular user can't add someone to the team.
@@ -1327,10 +1306,7 @@ func TestAddTeamMember(t *testing.T) {
th.UpdateUserToTeamAdmin(th.BasicUser, th.BasicTeam)
th.App.InvalidateAllCaches()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_TEAM_ADMIN })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginBasic()
// Should work as a team admin.
@@ -1339,7 +1315,6 @@ func TestAddTeamMember(t *testing.T) {
// Change permission level to System Admin
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_SYSTEM_ADMIN })
- th.App.SetDefaultRolesBasedOnConfig()
// Should not work as team admin.
_, resp = Client.AddTeamMember(team.Id, otherUser.Id)
@@ -1353,21 +1328,13 @@ func TestAddTeamMember(t *testing.T) {
th.UpdateUserToNonTeamAdmin(th.BasicUser, th.BasicTeam)
th.App.InvalidateAllCaches()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginBasic()
// Should work as a regular user.
_, resp = Client.AddTeamMember(team.Id, otherUser.Id)
CheckNoError(t, resp)
- // Reset config and license.
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = restrictTeamInvite })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
// by hash and data
@@ -1507,20 +1474,8 @@ func TestAddTeamMembers(t *testing.T) {
Client.Logout()
- // Check effects of config and license changes.
- restrictTeamInvite := *th.App.Config().TeamSettings.RestrictTeamInvite
- isLicensed := utils.IsLicensed()
- license := utils.License()
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = restrictTeamInvite })
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.SetDefaultRolesBasedOnConfig()
- }()
-
// Set the config so that only team admins can add a user to a team.
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_TEAM_ADMIN })
- th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
// Test without the EE license to see that the permission restriction is ignored.
@@ -1528,10 +1483,7 @@ func TestAddTeamMembers(t *testing.T) {
CheckNoError(t, resp)
// Add an EE license.
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginBasic()
// Check that a regular user can't add someone to the team.
@@ -1542,10 +1494,7 @@ func TestAddTeamMembers(t *testing.T) {
th.UpdateUserToTeamAdmin(th.BasicUser, th.BasicTeam)
th.App.InvalidateAllCaches()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_TEAM_ADMIN })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginBasic()
// Should work as a team admin.
@@ -1554,7 +1503,6 @@ func TestAddTeamMembers(t *testing.T) {
// Change permission level to System Admin
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_SYSTEM_ADMIN })
- th.App.SetDefaultRolesBasedOnConfig()
// Should not work as team admin.
_, resp = Client.AddTeamMembers(team.Id, userList)
@@ -1568,10 +1516,7 @@ func TestAddTeamMembers(t *testing.T) {
th.UpdateUserToNonTeamAdmin(th.BasicUser, th.BasicTeam)
th.App.InvalidateAllCaches()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.RestrictTeamInvite = model.PERMISSIONS_ALL })
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- th.App.SetDefaultRolesBasedOnConfig()
+ th.App.SetLicense(model.NewTestLicense())
th.LoginBasic()
// Should work as a regular user.
@@ -1930,10 +1875,6 @@ func TestInviteUsersToTeam(t *testing.T) {
}
}
- restrictCreationToDomains := th.App.Config().TeamSettings.RestrictCreationToDomains
- defer func() {
- th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.RestrictCreationToDomains = restrictCreationToDomains })
- }()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.RestrictCreationToDomains = "@example.com" })
err := th.App.InviteNewUsersToTeam(emailList, th.BasicTeam.Id, th.BasicUser.Id)
diff --git a/api4/user_test.go b/api4/user_test.go
index a7b7d297d..4613a8ea9 100644
--- a/api4/user_test.go
+++ b/api4/user_test.go
@@ -1566,18 +1566,7 @@ func TestUpdateUserMfa(t *testing.T) {
defer th.TearDown()
Client := th.Client
- isLicensed := utils.IsLicensed()
- license := utils.License()
- enableMfa := *th.App.Config().ServiceSettings.EnableMultifactorAuthentication
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = enableMfa })
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- *utils.License().Features.MFA = true
+ th.App.SetLicense(model.NewTestLicense("mfa"))
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
session, _ := th.App.GetSession(Client.AuthToken)
@@ -1612,18 +1601,7 @@ func TestCheckUserMfa(t *testing.T) {
t.Fatal("should be false - mfa not active")
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- enableMfa := *th.App.Config().ServiceSettings.EnableMultifactorAuthentication
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = enableMfa })
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- *utils.License().Features.MFA = true
+ th.App.SetLicense(model.NewTestLicense("mfa"))
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
th.LoginBasic()
@@ -1659,18 +1637,7 @@ func TestGenerateMfaSecret(t *testing.T) {
_, resp = Client.GenerateMfaSecret("junk")
CheckBadRequestStatus(t, resp)
- isLicensed := utils.IsLicensed()
- license := utils.License()
- enableMfa := *th.App.Config().ServiceSettings.EnableMultifactorAuthentication
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = enableMfa })
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- *utils.License().Features.MFA = true
+ th.App.SetLicense(model.NewTestLicense("mfa"))
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
_, resp = Client.GenerateMfaSecret(model.NewId())
@@ -2187,19 +2154,7 @@ func TestSwitchAccount(t *testing.T) {
t.Fatal("bad link")
}
- isLicensed := utils.IsLicensed()
- license := utils.License()
- enableAuthenticationTransfer := *th.App.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.UpdateConfig(func(cfg *model.Config) {
- *cfg.ServiceSettings.ExperimentalEnableAuthenticationTransfer = enableAuthenticationTransfer
- })
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
+ th.App.SetLicense(model.NewTestLicense())
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ExperimentalEnableAuthenticationTransfer = false })
sr = &model.SwitchRequest{
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 1e46d29d0..636f0a428 100644
--- a/app/app.go
+++ b/app/app.go
@@ -4,6 +4,7 @@
package app
import (
+ "crypto/ecdsa"
"html/template"
"net"
"net/http"
@@ -58,15 +59,20 @@ 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
- sessionCache *utils.Cache
- roles map[string]*model.Role
- configListenerId string
- licenseListenerId string
- disableConfigWatch bool
- configWatcher *utils.ConfigWatcher
+ htmlTemplateWatcher *utils.HTMLTemplateWatcher
+ sessionCache *utils.Cache
+ roles map[string]*model.Role
+ configListenerId string
+ licenseListenerId string
+ disableConfigWatch bool
+ configWatcher *utils.ConfigWatcher
+ asymmetricSigningKey *ecdsa.PrivateKey
pluginCommands []*PluginCommand
pluginCommandsLock sync.RWMutex
@@ -80,7 +86,7 @@ var appCount = 0
// New creates a new App. You must call Shutdown when you're done with it.
// XXX: For now, only one at a time is allowed as some resources are still shared.
-func New(options ...Option) (*App, error) {
+func New(options ...Option) (outApp *App, outErr error) {
appCount++
if appCount > 1 {
panic("Only one App should exist at a time. Did you forget to call Shutdown()?")
@@ -91,11 +97,17 @@ func New(options ...Option) (*App, error) {
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(){},
+ }
+ defer func() {
+ if outErr != nil {
+ app.Shutdown()
+ }
+ }()
for _, option := range options {
option(app)
@@ -118,9 +130,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"))
@@ -139,6 +151,10 @@ func New(options ...Option) (*App, error) {
}
app.Srv.Store = app.newStore()
+ if err := app.ensureAsymmetricSigningKey(); err != nil {
+ return nil, errors.Wrapf(err, "unable to ensure asymmetric signing key")
+ }
+
app.initJobs()
app.initBuiltInPlugins()
@@ -157,7 +173,7 @@ func New(options ...Option) (*App, error) {
func (a *App) configOrLicenseListener() {
a.regenerateClientConfig()
- a.SetDefaultRolesBasedOnConfig()
+ a.setDefaultRolesBasedOnConfig()
}
func (a *App) Shutdown() {
@@ -171,7 +187,9 @@ func (a *App) Shutdown() {
a.ShutDownPlugins()
a.WaitForGoroutines()
- a.Srv.Store.Close()
+ if a.Srv.Store != nil {
+ a.Srv.Store.Close()
+ }
a.Srv = nil
if a.htmlTemplateWatcher != nil {
@@ -179,7 +197,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()
@@ -448,5 +466,5 @@ func (a *App) Handle404(w http.ResponseWriter, r *http.Request) {
l4g.Debug("%v: code=404 ip=%v", r.URL.Path, utils.GetIpAddress(r))
- utils.RenderWebError(err, w, r)
+ utils.RenderWebAppError(w, r, err, a.AsymmetricSigningKey())
}
diff --git a/app/app_test.go b/app/app_test.go
index 25b19ead8..09f8725d7 100644
--- a/app/app_test.go
+++ b/app/app_test.go
@@ -51,7 +51,8 @@ func TestAppRace(t *testing.T) {
a, err := New()
require.NoError(t, err)
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
- a.StartServer()
+ serverErr := a.StartServer()
+ require.NoError(t, serverErr)
a.Shutdown()
}
}
diff --git a/app/apptestlib.go b/app/apptestlib.go
index 09afc8f76..c7846c9b5 100644
--- a/app/apptestlib.go
+++ b/app/apptestlib.go
@@ -96,15 +96,20 @@ func setupTestHelper(enterprise bool) *TestHelper {
if testStore != nil {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
}
- th.App.StartServer()
+ serverErr := th.App.StartServer()
+ if serverErr != nil {
+ panic(serverErr)
+ }
+
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
th.App.Srv.Store.MarkSystemRanUnitTests()
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/channel.go b/app/channel.go
index e4bf48654..8ac1f421c 100644
--- a/app/channel.go
+++ b/app/channel.go
@@ -1359,7 +1359,7 @@ func (a *App) PermanentDeleteChannel(channel *model.Channel) *model.AppError {
// This function is intended for use from the CLI. It is not robust against people joining the channel while the move
// is in progress, and therefore should not be used from the API without first fixing this potential race condition.
-func (a *App) MoveChannel(team *model.Team, channel *model.Channel) *model.AppError {
+func (a *App) MoveChannel(team *model.Team, channel *model.Channel, user *model.User) *model.AppError {
// Check that all channel members are in the destination team.
if channelMembers, err := a.GetChannelMembersPage(channel.Id, 0, 10000000); err != nil {
return err
@@ -1378,11 +1378,37 @@ func (a *App) MoveChannel(team *model.Team, channel *model.Channel) *model.AppEr
}
}
- // Change the Team ID of the channel.
+ // keep instance of the previous team
+ var previousTeam *model.Team
+ if result := <-a.Srv.Store.Team().Get(channel.TeamId); result.Err != nil {
+ return result.Err
+ } else {
+ previousTeam = result.Data.(*model.Team)
+ }
channel.TeamId = team.Id
if result := <-a.Srv.Store.Channel().Update(channel); result.Err != nil {
return result.Err
}
+ a.postChannelMoveMessage(user, channel, previousTeam)
+
+ return nil
+}
+
+func (a *App) postChannelMoveMessage(user *model.User, channel *model.Channel, previousTeam *model.Team) *model.AppError {
+
+ post := &model.Post{
+ ChannelId: channel.Id,
+ Message: fmt.Sprintf(utils.T("api.team.move_channel.success"), previousTeam.Name),
+ Type: model.POST_MOVE_CHANNEL,
+ UserId: user.Id,
+ Props: model.StringInterface{
+ "username": user.Username,
+ },
+ }
+
+ if _, err := a.CreatePost(post, channel, false); err != nil {
+ return model.NewAppError("postChannelMoveMessage", "api.team.move_channel.post.error", nil, err.Error(), http.StatusInternalServerError)
+ }
return nil
}
diff --git a/app/channel_test.go b/app/channel_test.go
index a414fbb35..d315fbae6 100644
--- a/app/channel_test.go
+++ b/app/channel_test.go
@@ -97,7 +97,7 @@ func TestMoveChannel(t *testing.T) {
t.Fatal(err)
}
- if err := th.App.MoveChannel(targetTeam, channel1); err == nil {
+ if err := th.App.MoveChannel(targetTeam, channel1, th.BasicUser); err == nil {
t.Fatal("Should have failed due to mismatched members.")
}
@@ -105,7 +105,7 @@ func TestMoveChannel(t *testing.T) {
t.Fatal(err)
}
- if err := th.App.MoveChannel(targetTeam, channel1); err != nil {
+ if err := th.App.MoveChannel(targetTeam, channel1, th.BasicUser); err != nil {
t.Fatal(err)
}
}
diff --git a/app/config.go b/app/config.go
index a2398f9e9..b4925e8fb 100644
--- a/app/config.go
+++ b/app/config.go
@@ -4,7 +4,12 @@
package app
import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
"crypto/md5"
+ "crypto/rand"
+ "crypto/x509"
+ "encoding/base64"
"encoding/json"
"fmt"
"runtime/debug"
@@ -116,8 +121,91 @@ func (a *App) InvokeConfigListeners(old, current *model.Config) {
}
}
+// EnsureAsymmetricSigningKey ensures that an asymmetric signing key exists and future calls to
+// AsymmetricSigningKey will always return a valid signing key.
+func (a *App) ensureAsymmetricSigningKey() error {
+ if a.asymmetricSigningKey != nil {
+ return nil
+ }
+
+ var key *model.SystemAsymmetricSigningKey
+
+ result := <-a.Srv.Store.System().GetByName(model.SYSTEM_ASYMMETRIC_SIGNING_KEY)
+ if result.Err == nil {
+ if err := json.Unmarshal([]byte(result.Data.(*model.System).Value), &key); err != nil {
+ return err
+ }
+ }
+
+ // If we don't already have a key, try to generate one.
+ if key == nil {
+ newECDSAKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ return err
+ }
+ newKey := &model.SystemAsymmetricSigningKey{
+ ECDSAKey: &model.SystemECDSAKey{
+ Curve: "P-256",
+ X: newECDSAKey.X,
+ Y: newECDSAKey.Y,
+ D: newECDSAKey.D,
+ },
+ }
+ system := &model.System{
+ Name: model.SYSTEM_ASYMMETRIC_SIGNING_KEY,
+ }
+ v, err := json.Marshal(newKey)
+ if err != nil {
+ return err
+ }
+ system.Value = string(v)
+ if result = <-a.Srv.Store.System().Save(system); result.Err == nil {
+ // If we were able to save the key, use it, otherwise ignore the error.
+ key = newKey
+ }
+ }
+
+ // If we weren't able to save a new key above, another server must have beat us to it. Get the
+ // key from the database, and if that fails, error out.
+ if key == nil {
+ result := <-a.Srv.Store.System().GetByName(model.SYSTEM_ASYMMETRIC_SIGNING_KEY)
+ if result.Err != nil {
+ return result.Err
+ } else if err := json.Unmarshal([]byte(result.Data.(*model.System).Value), &key); err != nil {
+ return err
+ }
+ }
+
+ var curve elliptic.Curve
+ switch key.ECDSAKey.Curve {
+ case "P-256":
+ curve = elliptic.P256()
+ default:
+ return fmt.Errorf("unknown curve: " + key.ECDSAKey.Curve)
+ }
+ a.asymmetricSigningKey = &ecdsa.PrivateKey{
+ PublicKey: ecdsa.PublicKey{
+ Curve: curve,
+ X: key.ECDSAKey.X,
+ Y: key.ECDSAKey.Y,
+ },
+ D: key.ECDSAKey.D,
+ }
+ a.regenerateClientConfig()
+ return nil
+}
+
+// AsymmetricSigningKey will return a private key that can be used for asymmetric signing.
+func (a *App) AsymmetricSigningKey() *ecdsa.PrivateKey {
+ return a.asymmetricSigningKey
+}
+
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)
+ }
clientConfigJSON, _ := json.Marshal(a.clientConfig)
a.clientConfigHash = fmt.Sprintf("%x", md5.Sum(clientConfigJSON))
}
@@ -166,11 +254,3 @@ func (a *App) Desanitize(cfg *model.Config) {
cfg.SqlSettings.DataSourceSearchReplicas[i] = actual.SqlSettings.DataSourceSearchReplicas[i]
}
}
-
-// 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
-}
diff --git a/app/config_test.go b/app/config_test.go
index e3d50b958..5ee999f0f 100644
--- a/app/config_test.go
+++ b/app/config_test.go
@@ -6,6 +6,8 @@ package app
import (
"testing"
+ "github.com/stretchr/testify/assert"
+
"github.com/mattermost/mattermost-server/model"
)
@@ -54,3 +56,10 @@ func TestConfigListener(t *testing.T) {
t.Fatal("listener 2 should've been called")
}
}
+
+func TestAsymmetricSigningKey(t *testing.T) {
+ th := Setup().InitBasic()
+ defer th.TearDown()
+ assert.NotNil(t, th.App.AsymmetricSigningKey())
+ assert.NotEmpty(t, th.App.ClientConfig()["AsymmetricSigningPublicKey"])
+}
diff --git a/app/diagnostics.go b/app/diagnostics.go
index 809d9ff1e..6d83d3a89 100644
--- a/app/diagnostics.go
+++ b/app/diagnostics.go
@@ -501,6 +501,7 @@ func (a *App) trackConfig() {
a.SendDiagnostic(TRACK_CONFIG_MESSAGE_EXPORT, map[string]interface{}{
"enable_message_export": *cfg.MessageExportSettings.EnableExport,
+ "export_format": *cfg.MessageExportSettings.ExportFormat,
"daily_run_time": *cfg.MessageExportSettings.DailyRunTime,
"default_export_from_timestamp": *cfg.MessageExportSettings.ExportFromTimestamp,
"batch_size": *cfg.MessageExportSettings.BatchSize,
diff --git a/app/email.go b/app/email.go
index 764dc017a..54a272a3b 100644
--- a/app/email.go
+++ b/app/email.go
@@ -317,5 +317,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 c7fd07197..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"))
@@ -59,7 +62,7 @@ func (a *App) SaveLicense(licenseBytes []byte) (*model.License, *model.AppError)
}
}
- if ok := utils.SetLicense(license); !ok {
+ if ok := a.SetLicense(license); !ok {
return nil, model.NewAppError("addLicense", model.EXPIRED_LICENSE_ERROR, nil, "", http.StatusBadRequest)
}
@@ -102,21 +105,115 @@ func (a *App) SaveLicense(licenseBytes []byte) (*model.License, *model.AppError)
return license, nil
}
+// License returns the currently active license or nil if the application is unlicensed.
+func (a *App) License() *model.License {
+ license, _ := a.licenseValue.Load().(*model.License)
+ return license
+}
+
+func (a *App) SetLicense(license *model.License) bool {
+ 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/plugin.go b/app/plugin.go
index 3f06a000f..fe671d26a 100644
--- a/app/plugin.go
+++ b/app/plugin.go
@@ -565,6 +565,7 @@ func (a *App) RegisterPluginCommand(pluginId string, command *model.Command) err
TeamId: command.TeamId,
AutoComplete: command.AutoComplete,
AutoCompleteDesc: command.AutoCompleteDesc,
+ AutoCompleteHint: command.AutoCompleteHint,
DisplayName: command.DisplayName,
}
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/server.go b/app/server.go
index 1659908b6..afa282ad6 100644
--- a/app/server.go
+++ b/app/server.go
@@ -17,6 +17,7 @@ import (
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
+ "github.com/pkg/errors"
"golang.org/x/crypto/acme/autocert"
"github.com/mattermost/mattermost-server/model"
@@ -116,7 +117,7 @@ func redirectHTTPToHTTPS(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, url.String(), http.StatusFound)
}
-func (a *App) StartServer() {
+func (a *App) StartServer() error {
l4g.Info(utils.T("api.server.start_server.starting.info"))
var handler http.Handler = &CorsWrapper{a.Config, a.Srv.Router}
@@ -126,8 +127,7 @@ func (a *App) StartServer() {
rateLimiter, err := NewRateLimiter(&a.Config().RateLimitSettings)
if err != nil {
- l4g.Critical(err.Error())
- return
+ return err
}
a.Srv.RateLimiter = rateLimiter
@@ -151,8 +151,8 @@ func (a *App) StartServer() {
listener, err := net.Listen("tcp", addr)
if err != nil {
- l4g.Critical(utils.T("api.server.start_server.starting.critical"), err)
- return
+ errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err)
+ return err
}
a.Srv.ListenAddr = listener.Addr().(*net.TCPAddr)
@@ -214,6 +214,8 @@ func (a *App) StartServer() {
}
close(a.Srv.didFinishListen)
}()
+
+ return nil
}
type tcpKeepAliveListener struct {
diff --git a/app/server_test.go b/app/server_test.go
new file mode 100644
index 000000000..de358b976
--- /dev/null
+++ b/app/server_test.go
@@ -0,0 +1,50 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package app
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/stretchr/testify/require"
+)
+
+func TestStartServerSuccess(t *testing.T) {
+ a, err := New()
+ require.NoError(t, err)
+
+ a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
+ serverErr := a.StartServer()
+ a.Shutdown()
+ require.NoError(t, serverErr)
+}
+
+func TestStartServerRateLimiterCriticalError(t *testing.T) {
+ a, err := New()
+ require.NoError(t, err)
+
+ // Attempt to use Rate Limiter with an invalid config
+ a.UpdateConfig(func(cfg *model.Config) {
+ *cfg.RateLimitSettings.Enable = true
+ *cfg.RateLimitSettings.MaxBurst = -100
+ })
+
+ serverErr := a.StartServer()
+ a.Shutdown()
+ require.Error(t, serverErr)
+}
+
+func TestStartServerPortUnavailable(t *testing.T) {
+ a, err := New()
+ require.NoError(t, err)
+
+ // Attempt to listen on a system-reserved port
+ a.UpdateConfig(func(cfg *model.Config) {
+ *cfg.ServiceSettings.ListenAddress = ":21"
+ })
+
+ serverErr := a.StartServer()
+ a.Shutdown()
+ require.Error(t, serverErr)
+}
diff --git a/app/session_test.go b/app/session_test.go
index bca3b59b7..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) {
@@ -48,18 +47,7 @@ func TestGetSessionIdleTimeoutInMinutes(t *testing.T) {
session, _ = th.App.CreateSession(session)
- isLicensed := utils.IsLicensed()
- license := utils.License()
- timeout := *th.App.Config().ServiceSettings.SessionIdleTimeoutInMinutes
- defer func() {
- utils.SetIsLicensed(isLicensed)
- utils.SetLicense(license)
- th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionIdleTimeoutInMinutes = timeout })
- }()
- utils.SetIsLicensed(true)
- utils.SetLicense(&model.License{Features: &model.Features{}})
- utils.License().Features.SetDefaults()
- *utils.License().Features.Compliance = true
+ th.App.SetLicense(model.NewTestLicense("compliance"))
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionIdleTimeoutInMinutes = 5 })
rsession, err := th.App.GetSession(session.Token)
@@ -122,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(),
@@ -136,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 })
diff --git a/cmd/platform/channel.go b/cmd/platform/channel.go
index 98bdcebb8..5d86ad9da 100644
--- a/cmd/platform/channel.go
+++ b/cmd/platform/channel.go
@@ -106,6 +106,8 @@ func init() {
channelCreateCmd.Flags().String("purpose", "", "Channel purpose")
channelCreateCmd.Flags().Bool("private", false, "Create a private channel.")
+ moveChannelsCmd.Flags().String("username", "", "Required. Username who is moving the channel.")
+
deleteChannelsCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the channels.")
modifyChannelCmd.Flags().Bool("private", false, "Convert the channel to a private channel")
@@ -319,26 +321,33 @@ func moveChannelsCmdF(cmd *cobra.Command, args []string) error {
return errors.New("Unable to find destination team '" + args[0] + "'")
}
+ username, erru := cmd.Flags().GetString("username")
+ if erru != nil || username == "" {
+ return errors.New("Username is required")
+ }
+ user := getUserFromUserArg(a, username)
+
channels := getChannelsFromChannelArgs(a, args[1:])
for i, channel := range channels {
if channel == nil {
CommandPrintErrorln("Unable to find channel '" + args[i] + "'")
continue
}
- if err := moveChannel(a, team, channel); err != nil {
+ originTeamID := channel.TeamId
+ if err := moveChannel(a, team, channel, user); err != nil {
CommandPrintErrorln("Unable to move channel '" + channel.Name + "' error: " + err.Error())
} else {
- CommandPrettyPrintln("Moved channel '" + channel.Name + "'")
+ CommandPrettyPrintln("Moved channel '" + channel.Name + "' to " + team.Name + "(" + team.Id + ") from " + originTeamID + ".")
}
}
return nil
}
-func moveChannel(a *app.App, team *model.Team, channel *model.Channel) *model.AppError {
+func moveChannel(a *app.App, team *model.Team, channel *model.Channel, user *model.User) *model.AppError {
oldTeamId := channel.TeamId
- if err := a.MoveChannel(team, channel); err != nil {
+ if err := a.MoveChannel(team, channel, user); err != nil {
return err
}
diff --git a/cmd/platform/channel_test.go b/cmd/platform/channel_test.go
index 1e6915679..cf8603cf3 100644
--- a/cmd/platform/channel_test.go
+++ b/cmd/platform/channel_test.go
@@ -44,6 +44,33 @@ func TestRemoveChannel(t *testing.T) {
checkCommand(t, "channel", "remove", th.BasicTeam.Name+":"+channel.Name, th.BasicUser2.Email)
}
+func TestMoveChannel(t *testing.T) {
+ th := api.Setup().InitBasic()
+ defer th.TearDown()
+
+ client := th.BasicClient
+ team1 := th.BasicTeam
+ team2 := th.CreateTeam(client)
+ user1 := th.BasicUser
+ th.LinkUserToTeam(user1, team2)
+ channel := th.BasicChannel
+
+ th.LinkUserToTeam(user1, team1)
+ th.LinkUserToTeam(user1, team2)
+
+ adminEmail := user1.Email
+ adminUsername := user1.Username
+ origin := team1.Name + ":" + channel.Name
+ dest := team2.Name
+
+ checkCommand(t, "channel", "add", origin, adminEmail)
+
+ // should fail with nill because errors are logged instead of returned when a channel does not exist
+ require.Nil(t, runCommand(t, "channel", "move", dest, team1.Name+":doesnotexist", "--username", adminUsername))
+
+ checkCommand(t, "channel", "move", dest, origin, "--username", adminUsername)
+}
+
func TestListChannels(t *testing.T) {
th := api.Setup().InitBasic()
defer th.TearDown()
diff --git a/cmd/platform/jobserver.go b/cmd/platform/jobserver.go
index e664136c0..044ee6b6a 100644
--- a/cmd/platform/jobserver.go
+++ b/cmd/platform/jobserver.go
@@ -35,7 +35,7 @@ func jobserverCmdF(cmd *cobra.Command, args []string) {
defer l4g.Close()
defer a.Shutdown()
- a.Jobs.LoadLicense()
+ a.LoadLicense()
// Run jobs
l4g.Info("Starting Mattermost job server")
diff --git a/cmd/platform/server.go b/cmd/platform/server.go
index e3742cef6..1b411cf20 100644
--- a/cmd/platform/server.go
+++ b/cmd/platform/server.go
@@ -42,10 +42,11 @@ func runServerCmd(cmd *cobra.Command, args []string) error {
disableConfigWatch, _ := cmd.Flags().GetBool("disableconfigwatch")
- return runServer(config, disableConfigWatch)
+ interruptChan := make(chan os.Signal, 1)
+ return runServer(config, disableConfigWatch, interruptChan)
}
-func runServer(configFileLocation string, disableConfigWatch bool) error {
+func runServer(configFileLocation string, disableConfigWatch bool, interruptChan chan os.Signal) error {
options := []app.Option{app.ConfigFile(configFileLocation)}
if disableConfigWatch {
options = append(options, app.DisableConfigWatch)
@@ -53,7 +54,7 @@ func runServer(configFileLocation string, disableConfigWatch bool) error {
a, err := app.New(options...)
if err != nil {
- l4g.Error(err.Error())
+ l4g.Critical(err.Error())
return err
}
defer a.Shutdown()
@@ -87,7 +88,12 @@ func runServer(configFileLocation string, disableConfigWatch bool) error {
}
})
- a.StartServer()
+ serverErr := a.StartServer()
+ if serverErr != nil {
+ l4g.Critical(serverErr.Error())
+ return serverErr
+ }
+
api4.Init(a, a.Srv.Router, false)
api3 := api.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)
@@ -160,9 +166,8 @@ func runServer(configFileLocation string, disableConfigWatch bool) error {
// wait for kill signal before attempting to gracefully shutdown
// the running service
- c := make(chan os.Signal, 1)
- signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
- <-c
+ signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
+ <-interruptChan
if a.Cluster != nil {
a.Cluster.StopInterNodeCommunication()
diff --git a/cmd/platform/server_test.go b/cmd/platform/server_test.go
new file mode 100644
index 000000000..15f9a357a
--- /dev/null
+++ b/cmd/platform/server_test.go
@@ -0,0 +1,72 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package main
+
+import (
+ "io/ioutil"
+ "os"
+ "syscall"
+ "testing"
+
+ "github.com/mattermost/mattermost-server/jobs"
+ "github.com/mattermost/mattermost-server/utils"
+ "github.com/stretchr/testify/require"
+)
+
+type ServerTestHelper struct {
+ configPath string
+ disableConfigWatch bool
+ interruptChan chan os.Signal
+ originalInterval int
+}
+
+func SetupServerTest() *ServerTestHelper {
+ // Build a channel that will be used by the server to receive system signals…
+ interruptChan := make(chan os.Signal, 1)
+ // …and sent it immediately a SIGINT value.
+ // This will make the server loop stop as soon as it started successfully.
+ interruptChan <- syscall.SIGINT
+
+ // Let jobs poll for termination every 0.2s (instead of every 15s by default)
+ // Otherwise we would have to wait the whole polling duration before the test
+ // terminates.
+ originalInterval := jobs.DEFAULT_WATCHER_POLLING_INTERVAL
+ jobs.DEFAULT_WATCHER_POLLING_INTERVAL = 200
+
+ th := &ServerTestHelper{
+ configPath: utils.FindConfigFile("config.json"),
+ disableConfigWatch: true,
+ interruptChan: interruptChan,
+ originalInterval: originalInterval,
+ }
+ return th
+}
+
+func (th *ServerTestHelper) TearDownServerTest() {
+ jobs.DEFAULT_WATCHER_POLLING_INTERVAL = th.originalInterval
+}
+
+func TestRunServerSuccess(t *testing.T) {
+ th := SetupServerTest()
+ defer th.TearDownServerTest()
+
+ err := runServer(th.configPath, th.disableConfigWatch, th.interruptChan)
+ require.NoError(t, err)
+}
+
+func TestRunServerInvalidConfigFile(t *testing.T) {
+ th := SetupServerTest()
+ defer th.TearDownServerTest()
+
+ // Start the server with an unreadable config file
+ unreadableConfigFile, err := ioutil.TempFile("", "mattermost-unreadable-config-file-")
+ if err != nil {
+ panic(err)
+ }
+ os.Chmod(unreadableConfigFile.Name(), 0200)
+ defer os.Remove(unreadableConfigFile.Name())
+
+ err = runServer(unreadableConfigFile.Name(), th.disableConfigWatch, th.interruptChan)
+ require.Error(t, err)
+}
diff --git a/cmd/platform/test.go b/cmd/platform/test.go
index 036df07de..9ab3fbb36 100644
--- a/cmd/platform/test.go
+++ b/cmd/platform/test.go
@@ -53,7 +53,11 @@ func webClientTestsCmdF(cmd *cobra.Command, args []string) error {
defer a.Shutdown()
utils.InitTranslations(a.Config().LocalizationSettings)
- a.StartServer()
+ serverErr := a.StartServer()
+ if serverErr != nil {
+ return serverErr
+ }
+
api4.Init(a, a.Srv.Router, false)
api.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)
@@ -71,7 +75,11 @@ func serverForWebClientTestsCmdF(cmd *cobra.Command, args []string) error {
defer a.Shutdown()
utils.InitTranslations(a.Config().LocalizationSettings)
- a.StartServer()
+ serverErr := a.StartServer()
+ if serverErr != nil {
+ return serverErr
+ }
+
api4.Init(a, a.Srv.Router, false)
api.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)
diff --git a/i18n/en.json b/i18n/en.json
index 4365a44fb..de910fca8 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -132,10 +132,6 @@
"translation": "Unable to upload file. File is too large."
},
{
- "id": "api.api.init.parsing_templates.debug",
- "translation": "Parsing server templates at %v"
- },
- {
"id": "api.api.init.parsing_templates.error",
"translation": "Failed to parse server templates %v"
},
@@ -3135,6 +3131,14 @@
"translation": "Cannot move a channel unless all its members are already members of the destination team."
},
{
+ "id": "api.team.move_channel.success",
+ "translation": "This channel has been moved to this team from %v."
+ },
+ {
+ "id": "api.team.move_channel.post.error",
+ "translation": "Failed to post channel move message."
+ },
+ {
"id": "app.channel.post_update_channel_purpose_message.post.error",
"translation": "Failed to post channel purpose message"
},
@@ -4859,6 +4863,14 @@
"translation": "Message export job BatchSize must be a positive integer"
},
{
+ "id": "model.config.is_valid.message_export.export_type.app_error",
+ "translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
+ },
+ {
+ "id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
+ "translation": "Message export job GlobalRelayEmailAddress must be set to a valid email address"
+ },
+ {
"id": "model.config.is_valid.message_export.daily_runtime.app_error",
"translation": "Message export job DailyRuntime must be a 24-hour time stamp in the form HH:MM."
},
@@ -7083,6 +7095,10 @@
"translation": "Failed to authenticate on SMTP server"
},
{
+ "id": "utils.mail.sendMail.attachments.write_error",
+ "translation": "Failed to write attachment to email"
+ },
+ {
"id": "utils.mail.new_client.helo.error",
"translation": "Failed to to set the HELO to SMTP server %v"
},
@@ -7159,10 +7175,6 @@
"translation": "Failed to create directory watcher %v"
},
{
- "id": "web.dir_fail.error",
- "translation": "Failed in directory watcher %v"
- },
- {
"id": "web.do_load_channel.error",
"translation": "Error in getting users profile for id=%v forcing logout"
},
@@ -7267,18 +7279,10 @@
"translation": "Parsing templates at %v"
},
{
- "id": "web.parsing_templates.error",
- "translation": "Failed to parse templates %v"
- },
- {
"id": "web.post_permalink.app_error",
"translation": "Invalid Post ID"
},
{
- "id": "web.reparse_templates.info",
- "translation": "Re-parsing templates because of modified file %v"
- },
- {
"id": "web.reset_password.expired_link.app_error",
"translation": "The password reset link has expired"
},
diff --git a/jobs/jobs_watcher.go b/jobs/jobs_watcher.go
index f519e7cca..eaa3a4e73 100644
--- a/jobs/jobs_watcher.go
+++ b/jobs/jobs_watcher.go
@@ -11,9 +11,9 @@ import (
"github.com/mattermost/mattermost-server/model"
)
-const (
- DEFAULT_WATCHER_POLLING_INTERVAL = 15000
-)
+// Default polling interval for jobs termination.
+// (Defining as `var` rather than `const` allows tests to lower the interval.)
+var DEFAULT_WATCHER_POLLING_INTERVAL = 15000
type Watcher struct {
srv *JobServer
diff --git a/jobs/server.go b/jobs/server.go
index 4015d581e..01cf821dc 100644
--- a/jobs/server.go
+++ b/jobs/server.go
@@ -4,12 +4,9 @@
package jobs
import (
- l4g "github.com/alecthomas/log4go"
-
ejobs "github.com/mattermost/mattermost-server/einterfaces/jobs"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
- "github.com/mattermost/mattermost-server/utils"
)
type ConfigService interface {
@@ -50,36 +47,6 @@ func (srv *JobServer) Config() *model.Config {
return srv.ConfigService.Config()
}
-func (srv *JobServer) LoadLicense() {
- licenseId := ""
- if result := <-srv.Store.System().Get(); result.Err == nil {
- props := result.Data.(model.StringMap)
- licenseId = props[model.SYSTEM_ACTIVE_LICENSE_ID]
- }
-
- var licenseBytes []byte
-
- if len(licenseId) != 26 {
- // Lets attempt to load the file from disk since it was missing from the DB
- _, licenseBytes = utils.GetAndValidateLicenseFileFromDisk(*srv.ConfigService.Config().ServiceSettings.LicenseFileLocation)
- } else {
- if result := <-srv.Store.License().Get(licenseId); result.Err == nil {
- record := result.Data.(*model.LicenseRecord)
- licenseBytes = []byte(record.Bytes)
- l4g.Info("License key valid unlocking enterprise features.")
- } else {
- l4g.Info(utils.T("mattermost.load_license.find.warn"))
- }
- }
-
- if licenseBytes != nil {
- utils.LoadLicense(licenseBytes)
- l4g.Info("License key valid unlocking enterprise features.")
- } else {
- l4g.Info(utils.T("mattermost.load_license.find.warn"))
- }
-}
-
func (srv *JobServer) StartWorkers() {
srv.Workers = srv.InitWorkers().Start()
}
diff --git a/jobs/server_test.go b/jobs/server_test.go
deleted file mode 100644
index 3b5ef6f3d..000000000
--- a/jobs/server_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package jobs
-
-import (
- "testing"
-
- "github.com/mattermost/mattermost-server/model"
- "github.com/mattermost/mattermost-server/store"
- "github.com/mattermost/mattermost-server/store/storetest"
- "github.com/mattermost/mattermost-server/utils"
-)
-
-func TestJobServer_LoadLicense(t *testing.T) {
- if utils.T == nil {
- utils.TranslationsPreInit()
- }
-
- mockStore := &storetest.Store{}
- defer mockStore.AssertExpectations(t)
-
- server := &JobServer{
- Store: mockStore,
- }
-
- mockStore.SystemStore.On("Get").Return(storetest.NewStoreChannel(store.StoreResult{
- Data: model.StringMap{
- model.SYSTEM_ACTIVE_LICENSE_ID: "thelicenseid00000000000000",
- },
- }))
- mockStore.LicenseStore.On("Get", "thelicenseid00000000000000").Return(storetest.NewStoreChannel(store.StoreResult{
- Data: &model.LicenseRecord{
- Id: "thelicenseid00000000000000",
- },
- }))
-
- server.LoadLicense()
-}
diff --git a/model/channel_member_history.go b/model/channel_member_history.go
index bc71b580a..47c59d54e 100644
--- a/model/channel_member_history.go
+++ b/model/channel_member_history.go
@@ -6,7 +6,10 @@ package model
type ChannelMemberHistory struct {
ChannelId string
UserId string
- UserEmail string `db:"Email"`
JoinTime int64
LeaveTime *int64
+
+ // these two fields are never set in the database - when we SELECT, we join on Users to get them
+ UserEmail string `db:"Email"`
+ Username string
}
diff --git a/model/client4.go b/model/client4.go
index 0694ecbdf..962b816bb 100644
--- a/model/client4.go
+++ b/model/client4.go
@@ -1729,7 +1729,7 @@ func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Respon
// CreatePost creates a post based on the provided post struct.
func (c *Client4) CreatePost(post *Post) (*Post, *Response) {
- if r, err := c.DoApiPost(c.GetPostsRoute(), post.ToJson()); err != nil {
+ if r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson()); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
@@ -1739,7 +1739,7 @@ func (c *Client4) CreatePost(post *Post) (*Post, *Response) {
// UpdatePost updates a post based on the provided post struct.
func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) {
- if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToJson()); err != nil {
+ if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson()); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
diff --git a/model/client4_test.go b/model/client4_test.go
new file mode 100644
index 000000000..f7923fa8f
--- /dev/null
+++ b/model/client4_test.go
@@ -0,0 +1,58 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+// https://github.com/mattermost/mattermost-server/issues/8205
+func TestClient4CreatePost(t *testing.T) {
+ post := &Post{
+ Props: map[string]interface{}{
+ "attachments": []*SlackAttachment{
+ &SlackAttachment{
+ Actions: []*PostAction{
+ &PostAction{
+ Integration: &PostActionIntegration{
+ Context: map[string]interface{}{
+ "foo": "bar",
+ },
+ URL: "http://foo.com",
+ },
+ Name: "Foo",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ attachments := PostFromJson(r.Body).Attachments()
+ assert.Equal(t, []*SlackAttachment{
+ &SlackAttachment{
+ Actions: []*PostAction{
+ &PostAction{
+ Integration: &PostActionIntegration{
+ Context: map[string]interface{}{
+ "foo": "bar",
+ },
+ URL: "http://foo.com",
+ },
+ Name: "Foo",
+ },
+ },
+ },
+ }, attachments)
+ }))
+
+ client := NewAPIv4Client(server.URL)
+ _, resp := client.CreatePost(post)
+ assert.Equal(t, http.StatusOK, resp.StatusCode)
+}
diff --git a/model/config.go b/model/config.go
index 20011f7cb..9010eaeae 100644
--- a/model/config.go
+++ b/model/config.go
@@ -158,6 +158,9 @@ const (
PLUGIN_SETTINGS_DEFAULT_DIRECTORY = "./plugins"
PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY = "./client/plugins"
+
+ COMPLIANCE_EXPORT_TYPE_ACTIANCE = "actiance"
+ COMPLIANCE_EXPORT_TYPE_GLOBALRELAY = "globalrelay"
)
type ServiceSettings struct {
@@ -1623,9 +1626,13 @@ func (s *PluginSettings) SetDefaults() {
type MessageExportSettings struct {
EnableExport *bool
+ ExportFormat *string
DailyRunTime *string
ExportFromTimestamp *int64
BatchSize *int
+
+ // formatter-specific settings - these are only expected to be non-nil if ExportFormat is set to the associated format
+ GlobalRelayEmailAddress *string
}
func (s *MessageExportSettings) SetDefaults() {
@@ -1633,6 +1640,10 @@ func (s *MessageExportSettings) SetDefaults() {
s.EnableExport = NewBool(false)
}
+ if s.ExportFormat == nil {
+ s.ExportFormat = NewString(COMPLIANCE_EXPORT_TYPE_ACTIANCE)
+ }
+
if s.DailyRunTime == nil {
s.DailyRunTime = NewString("01:00")
}
@@ -2170,6 +2181,16 @@ func (mes *MessageExportSettings) isValid(fs FileSettings) *AppError {
return NewAppError("Config.IsValid", "model.config.is_valid.message_export.daily_runtime.app_error", nil, err.Error(), http.StatusBadRequest)
} else if mes.BatchSize == nil || *mes.BatchSize < 0 {
return NewAppError("Config.IsValid", "model.config.is_valid.message_export.batch_size.app_error", nil, "", http.StatusBadRequest)
+ } else if mes.ExportFormat == nil || (*mes.ExportFormat != COMPLIANCE_EXPORT_TYPE_ACTIANCE && *mes.ExportFormat != COMPLIANCE_EXPORT_TYPE_GLOBALRELAY) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.export_type.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *mes.ExportFormat == COMPLIANCE_EXPORT_TYPE_GLOBALRELAY {
+ // validating email addresses is hard - just make sure it contains an '@' sign
+ // see https://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address
+ if mes.GlobalRelayEmailAddress == nil || !strings.Contains(*mes.GlobalRelayEmailAddress, "@") {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay_email_address.app_error", nil, "", http.StatusBadRequest)
+ }
}
}
return nil
diff --git a/model/config_test.go b/model/config_test.go
index 5510c40d0..919f73fd7 100644
--- a/model/config_test.go
+++ b/model/config_test.go
@@ -136,7 +136,7 @@ func TestMessageExportSettingsIsValidBatchSizeInvalid(t *testing.T) {
require.Error(t, mes.isValid(*fs))
}
-func TestMessageExportSettingsIsValid(t *testing.T) {
+func TestMessageExportSettingsIsValidExportFormatInvalid(t *testing.T) {
fs := &FileSettings{
DriverName: NewString("foo"), // bypass file location check
}
@@ -147,6 +147,55 @@ func TestMessageExportSettingsIsValid(t *testing.T) {
BatchSize: NewInt(100),
}
+ // should fail fast because export format isn't set
+ require.Error(t, mes.isValid(*fs))
+}
+
+func TestMessageExportSettingsIsValidGlobalRelayEmailAddressInvalid(t *testing.T) {
+ fs := &FileSettings{
+ DriverName: NewString("foo"), // bypass file location check
+ }
+ mes := &MessageExportSettings{
+ EnableExport: NewBool(true),
+ ExportFormat: NewString(COMPLIANCE_EXPORT_TYPE_GLOBALRELAY),
+ ExportFromTimestamp: NewInt64(0),
+ DailyRunTime: NewString("15:04"),
+ BatchSize: NewInt(100),
+ }
+
+ // should fail fast because global relay email address isn't set
+ require.Error(t, mes.isValid(*fs))
+}
+
+func TestMessageExportSettingsIsValidActiance(t *testing.T) {
+ fs := &FileSettings{
+ DriverName: NewString("foo"), // bypass file location check
+ }
+ mes := &MessageExportSettings{
+ EnableExport: NewBool(true),
+ ExportFormat: NewString(COMPLIANCE_EXPORT_TYPE_ACTIANCE),
+ ExportFromTimestamp: NewInt64(0),
+ DailyRunTime: NewString("15:04"),
+ BatchSize: NewInt(100),
+ }
+
+ // should pass because everything is valid
+ require.Nil(t, mes.isValid(*fs))
+}
+
+func TestMessageExportSettingsIsValidGlobalRelay(t *testing.T) {
+ fs := &FileSettings{
+ DriverName: NewString("foo"), // bypass file location check
+ }
+ mes := &MessageExportSettings{
+ EnableExport: NewBool(true),
+ ExportFormat: NewString(COMPLIANCE_EXPORT_TYPE_GLOBALRELAY),
+ ExportFromTimestamp: NewInt64(0),
+ DailyRunTime: NewString("15:04"),
+ BatchSize: NewInt(100),
+ GlobalRelayEmailAddress: NewString("test@mattermost.com"),
+ }
+
// should pass because everything is valid
require.Nil(t, mes.isValid(*fs))
}
@@ -159,6 +208,7 @@ func TestMessageExportSetDefaults(t *testing.T) {
require.Equal(t, "01:00", *mes.DailyRunTime)
require.Equal(t, int64(0), *mes.ExportFromTimestamp)
require.Equal(t, 10000, *mes.BatchSize)
+ require.Equal(t, COMPLIANCE_EXPORT_TYPE_ACTIANCE, *mes.ExportFormat)
}
func TestMessageExportSetDefaultsExportEnabledExportFromTimestampNil(t *testing.T) {
diff --git a/model/license.go b/model/license.go
index f96cba06c..942a18d55 100644
--- a/model/license.go
+++ b/model/license.go
@@ -173,6 +173,25 @@ func (l *License) ToJson() string {
return string(b)
}
+// NewTestLicense returns a license that expires in the future and has the given features.
+func NewTestLicense(features ...string) *License {
+ ret := &License{
+ ExpiresAt: GetMillis() + 90*24*60*60*1000,
+ Customer: &Customer{},
+ Features: &Features{},
+ }
+ ret.Features.SetDefaults()
+
+ featureMap := map[string]bool{}
+ for _, feature := range features {
+ featureMap[feature] = true
+ }
+ featureJson, _ := json.Marshal(featureMap)
+ json.Unmarshal(featureJson, &ret.Features)
+
+ return ret
+}
+
func LicenseFromJson(data io.Reader) *License {
var o *License
json.NewDecoder(data).Decode(&o)
diff --git a/model/message_export.go b/model/message_export.go
index b59b114d4..22641deee 100644
--- a/model/message_export.go
+++ b/model/message_export.go
@@ -9,6 +9,7 @@ type MessageExport struct {
UserId *string
UserEmail *string
+ Username *string
PostId *string
PostCreateAt *int64
diff --git a/model/post.go b/model/post.go
index 391b948f4..4a774b5d4 100644
--- a/model/post.go
+++ b/model/post.go
@@ -28,6 +28,7 @@ const (
POST_ADD_REMOVE = "system_add_remove" // Deprecated, use POST_ADD_TO_CHANNEL or POST_REMOVE_FROM_CHANNEL instead
POST_ADD_TO_CHANNEL = "system_add_to_channel"
POST_REMOVE_FROM_CHANNEL = "system_remove_from_channel"
+ POST_MOVE_CHANNEL = "system_move_channel"
POST_ADD_TO_TEAM = "system_add_to_team"
POST_REMOVE_FROM_TEAM = "system_remove_from_team"
POST_HEADER_CHANGE = "system_header_change"
@@ -121,12 +122,13 @@ type PostActionIntegrationResponse struct {
func (o *Post) ToJson() string {
copy := *o
copy.StripActionIntegrations()
- b, err := json.Marshal(&copy)
- if err != nil {
- return ""
- } else {
- return string(b)
- }
+ b, _ := json.Marshal(&copy)
+ return string(b)
+}
+
+func (o *Post) ToUnsanitizedJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
}
func PostFromJson(data io.Reader) *Post {
@@ -196,6 +198,7 @@ func (o *Post) IsValid() *AppError {
POST_LEAVE_TEAM,
POST_ADD_TO_CHANNEL,
POST_REMOVE_FROM_CHANNEL,
+ POST_MOVE_CHANNEL,
POST_ADD_TO_TEAM,
POST_REMOVE_FROM_TEAM,
POST_SLACK_ATTACHMENT,
diff --git a/model/system.go b/model/system.go
index 020c50858..2a636b14f 100644
--- a/model/system.go
+++ b/model/system.go
@@ -6,14 +6,16 @@ package model
import (
"encoding/json"
"io"
+ "math/big"
)
const (
- SYSTEM_DIAGNOSTIC_ID = "DiagnosticId"
- SYSTEM_RAN_UNIT_TESTS = "RanUnitTests"
- SYSTEM_LAST_SECURITY_TIME = "LastSecurityTime"
- SYSTEM_ACTIVE_LICENSE_ID = "ActiveLicenseId"
- SYSTEM_LAST_COMPLIANCE_TIME = "LastComplianceTime"
+ SYSTEM_DIAGNOSTIC_ID = "DiagnosticId"
+ SYSTEM_RAN_UNIT_TESTS = "RanUnitTests"
+ SYSTEM_LAST_SECURITY_TIME = "LastSecurityTime"
+ SYSTEM_ACTIVE_LICENSE_ID = "ActiveLicenseId"
+ SYSTEM_LAST_COMPLIANCE_TIME = "LastComplianceTime"
+ SYSTEM_ASYMMETRIC_SIGNING_KEY = "AsymmetricSigningKey"
)
type System struct {
@@ -31,3 +33,14 @@ func SystemFromJson(data io.Reader) *System {
json.NewDecoder(data).Decode(&o)
return o
}
+
+type SystemAsymmetricSigningKey struct {
+ ECDSAKey *SystemECDSAKey `json:"ecdsa_key,omitempty"`
+}
+
+type SystemECDSAKey struct {
+ Curve string `json:"curve"`
+ X *big.Int `json:"x"`
+ Y *big.Int `json:"y"`
+ D *big.Int `json:"d,omitempty"`
+}
diff --git a/store/sqlstore/channel_member_history_store.go b/store/sqlstore/channel_member_history_store.go
index 182f37ce9..0b86aac28 100644
--- a/store/sqlstore/channel_member_history_store.go
+++ b/store/sqlstore/channel_member_history_store.go
@@ -110,7 +110,8 @@ func (s SqlChannelMemberHistoryStore) getFromChannelMemberHistoryTable(startTime
query := `
SELECT
cmh.*,
- u.Email
+ u.Email,
+ u.Username
FROM ChannelMemberHistory cmh
INNER JOIN Users u ON cmh.UserId = u.Id
WHERE cmh.ChannelId = :ChannelId
@@ -130,9 +131,10 @@ func (s SqlChannelMemberHistoryStore) getFromChannelMemberHistoryTable(startTime
func (s SqlChannelMemberHistoryStore) getFromChannelMembersTable(startTime int64, endTime int64, channelId string) ([]*model.ChannelMemberHistory, error) {
query := `
SELECT DISTINCT
- ch.ChannelId,
- ch.UserId,
- u.email
+ ch.ChannelId,
+ ch.UserId,
+ u.Email,
+ u.Username
FROM ChannelMembers AS ch
INNER JOIN Users AS u ON ch.UserId = u.id
WHERE ch.ChannelId = :ChannelId`
@@ -158,7 +160,7 @@ func (s SqlChannelMemberHistoryStore) PermanentDeleteBatch(endTime int64, limit
query =
`DELETE FROM ChannelMemberHistory
WHERE ctid IN (
- SELECT ctid FROM ChannelMemberHistory
+ SELECT ctid FROM ChannelMemberHistory
WHERE LeaveTime IS NOT NULL
AND LeaveTime <= :EndTime
LIMIT :Limit
diff --git a/store/sqlstore/compliance_store.go b/store/sqlstore/compliance_store.go
index a25b01548..03d92d5e1 100644
--- a/store/sqlstore/compliance_store.go
+++ b/store/sqlstore/compliance_store.go
@@ -225,7 +225,8 @@ func (s SqlComplianceStore) MessageExport(after int64, limit int) store.StoreCha
Channels.Id AS ChannelId,
Channels.DisplayName AS ChannelDisplayName,
Users.Id AS UserId,
- Users.Email AS UserEmail
+ Users.Email AS UserEmail,
+ Users.Username
FROM
Posts
LEFT OUTER JOIN Channels ON Posts.ChannelId = Channels.Id
diff --git a/store/sqlstore/post_store.go b/store/sqlstore/post_store.go
index bc336e70d..25c3c4913 100644
--- a/store/sqlstore/post_store.go
+++ b/store/sqlstore/post_store.go
@@ -322,7 +322,10 @@ type etagPosts struct {
func (s SqlPostStore) InvalidateLastPostTimeCache(channelId string) {
lastPostTimeCache.Remove(channelId)
- lastPostsCache.Remove(channelId)
+
+ // Keys are "{channelid}{limit}" and caching only occurs on limits of 30 and 60
+ lastPostsCache.Remove(channelId + "30")
+ lastPostsCache.Remove(channelId + "60")
}
func (s SqlPostStore) GetEtag(channelId string, allowFromCache bool) store.StoreChannel {
@@ -439,8 +442,9 @@ func (s SqlPostStore) GetPosts(channelId string, offset int, limit int, allowFro
return
}
- if allowFromCache && offset == 0 && limit == 60 {
- if cacheItem, ok := lastPostsCache.Get(channelId); ok {
+ // Caching only occurs on limits of 30 and 60, the common limits requested by MM clients
+ if allowFromCache && offset == 0 && (limit == 60 || limit == 30) {
+ if cacheItem, ok := lastPostsCache.Get(fmt.Sprintf("%s%v", channelId, limit)); ok {
if s.metrics != nil {
s.metrics.IncrementMemCacheHitCounter("Last Posts Cache")
}
@@ -482,8 +486,9 @@ func (s SqlPostStore) GetPosts(channelId string, offset int, limit int, allowFro
list.MakeNonNil()
- if offset == 0 && limit == 60 {
- lastPostsCache.AddWithExpiresInSecs(channelId, list, LAST_POSTS_CACHE_SEC)
+ // Caching only occurs on limits of 30 and 60, the common limits requested by MM clients
+ if offset == 0 && (limit == 60 || limit == 30) {
+ lastPostsCache.AddWithExpiresInSecs(fmt.Sprintf("%s%v", channelId, limit), list, LAST_POSTS_CACHE_SEC)
}
result.Data = list
diff --git a/store/sqlstore/upgrade.go b/store/sqlstore/upgrade.go
index 7c1522f25..56fdf9d6c 100644
--- a/store/sqlstore/upgrade.go
+++ b/store/sqlstore/upgrade.go
@@ -15,6 +15,7 @@ import (
)
const (
+ VERSION_4_8_0 = "4.8.0"
VERSION_4_7_0 = "4.7.0"
VERSION_4_6_0 = "4.6.0"
VERSION_4_5_0 = "4.5.0"
@@ -64,6 +65,7 @@ func UpgradeDatabase(sqlStore SqlStore) {
UpgradeDatabaseToVersion45(sqlStore)
UpgradeDatabaseToVersion46(sqlStore)
UpgradeDatabaseToVersion47(sqlStore)
+ UpgradeDatabaseToVersion48(sqlStore)
// If the SchemaVersion is empty this this is the first time it has ran
// so lets set it to the current version.
@@ -347,3 +349,10 @@ func UpgradeDatabaseToVersion47(sqlStore SqlStore) {
saveSchemaVersion(sqlStore, VERSION_4_7_0)
}
}
+
+func UpgradeDatabaseToVersion48(sqlStore SqlStore) {
+ //TODO: Uncomment the following condition when version 4.8.0 is released
+ //if shouldPerformUpgrade(sqlStore, VERSION_4_7_0, VERSION_4_8_0) {
+ // saveSchemaVersion(sqlStore, VERSION_4_8_0)
+ //}
+}
diff --git a/store/storetest/channel_member_history_store.go b/store/storetest/channel_member_history_store.go
index 6fe73478c..fa2e7a8fa 100644
--- a/store/storetest/channel_member_history_store.go
+++ b/store/storetest/channel_member_history_store.go
@@ -35,6 +35,7 @@ func testLogJoinEvent(t *testing.T, ss store.Store) {
user := model.User{
Email: model.NewId() + "@mattermost.com",
Nickname: model.NewId(),
+ Username: model.NewId(),
}
user = *store.Must(ss.User().Save(&user)).(*model.User)
@@ -57,6 +58,7 @@ func testLogLeaveEvent(t *testing.T, ss store.Store) {
user := model.User{
Email: model.NewId() + "@mattermost.com",
Nickname: model.NewId(),
+ Username: model.NewId(),
}
user = *store.Must(ss.User().Save(&user)).(*model.User)
@@ -82,6 +84,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) {
user := model.User{
Email: model.NewId() + "@mattermost.com",
Nickname: model.NewId(),
+ Username: model.NewId(),
}
user = *store.Must(ss.User().Save(&user)).(*model.User)
@@ -108,6 +111,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime, channelMembers[0].JoinTime)
assert.Nil(t, channelMembers[0].LeaveTime)
@@ -117,6 +121,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime, channelMembers[0].JoinTime)
assert.Nil(t, channelMembers[0].LeaveTime)
@@ -129,6 +134,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime, channelMembers[0].JoinTime)
assert.Equal(t, leaveTime, *channelMembers[0].LeaveTime)
@@ -138,6 +144,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime, channelMembers[0].JoinTime)
assert.Equal(t, leaveTime, *channelMembers[0].LeaveTime)
@@ -160,6 +167,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
user := model.User{
Email: model.NewId() + "@mattermost.com",
Nickname: model.NewId(),
+ Username: model.NewId(),
}
user = *store.Must(ss.User().Save(&user)).(*model.User)
@@ -192,6 +200,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime-500, channelMembers[0].JoinTime)
assert.Equal(t, joinTime-100, *channelMembers[0].LeaveTime)
@@ -201,6 +210,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime-100, channelMembers[0].JoinTime)
assert.Equal(t, joinTime+500, *channelMembers[0].LeaveTime)
@@ -210,6 +220,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime+100, channelMembers[0].JoinTime)
assert.Equal(t, joinTime+500, *channelMembers[0].LeaveTime)
@@ -219,6 +230,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime+100, channelMembers[0].JoinTime)
assert.Equal(t, leaveTime-100, *channelMembers[0].LeaveTime)
@@ -228,6 +240,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, joinTime-100, channelMembers[0].JoinTime)
assert.Equal(t, leaveTime+100, *channelMembers[0].LeaveTime)
@@ -237,6 +250,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
assert.Equal(t, user.Id, channelMembers[0].UserId)
assert.Equal(t, user.Email, channelMembers[0].UserEmail)
+ assert.Equal(t, user.Username, channelMembers[0].Username)
assert.Equal(t, leaveTime+100, channelMembers[0].JoinTime)
assert.Equal(t, leaveTime+200, *channelMembers[0].LeaveTime)
}
@@ -255,12 +269,14 @@ func testPermanentDeleteBatch(t *testing.T, ss store.Store) {
user := model.User{
Email: model.NewId() + "@mattermost.com",
Nickname: model.NewId(),
+ Username: model.NewId(),
}
user = *store.Must(ss.User().Save(&user)).(*model.User)
user2 := model.User{
Email: model.NewId() + "@mattermost.com",
Nickname: model.NewId(),
+ Username: model.NewId(),
}
user2 = *store.Must(ss.User().Save(&user2)).(*model.User)
diff --git a/store/storetest/compliance_store.go b/store/storetest/compliance_store.go
index c5bd60f05..eb29bedc7 100644
--- a/store/storetest/compliance_store.go
+++ b/store/storetest/compliance_store.go
@@ -341,7 +341,8 @@ func testComplianceMessageExport(t *testing.T, ss store.Store) {
// and two users that are a part of that team
user1 := &model.User{
- Email: model.NewId(),
+ Email: model.NewId(),
+ Username: model.NewId(),
}
user1 = store.Must(ss.User().Save(user1)).(*model.User)
store.Must(ss.Team().SaveMember(&model.TeamMember{
@@ -350,7 +351,8 @@ func testComplianceMessageExport(t *testing.T, ss store.Store) {
}, -1))
user2 := &model.User{
- Email: model.NewId(),
+ Email: model.NewId(),
+ Username: model.NewId(),
}
user2 = store.Must(ss.User().Save(user2)).(*model.User)
store.Must(ss.Team().SaveMember(&model.TeamMember{
@@ -415,6 +417,7 @@ func testComplianceMessageExport(t *testing.T, ss store.Store) {
assert.Equal(t, channel.DisplayName, *messageExportMap[post1.Id].ChannelDisplayName)
assert.Equal(t, user1.Id, *messageExportMap[post1.Id].UserId)
assert.Equal(t, user1.Email, *messageExportMap[post1.Id].UserEmail)
+ assert.Equal(t, user1.Username, *messageExportMap[post1.Id].Username)
// post2 was made by user1 in channel1 and team1
assert.Equal(t, post2.Id, *messageExportMap[post2.Id].PostId)
@@ -424,6 +427,7 @@ func testComplianceMessageExport(t *testing.T, ss store.Store) {
assert.Equal(t, channel.DisplayName, *messageExportMap[post2.Id].ChannelDisplayName)
assert.Equal(t, user1.Id, *messageExportMap[post2.Id].UserId)
assert.Equal(t, user1.Email, *messageExportMap[post2.Id].UserEmail)
+ assert.Equal(t, user1.Username, *messageExportMap[post2.Id].Username)
// post3 is a DM between user1 and user2
assert.Equal(t, post3.Id, *messageExportMap[post3.Id].PostId)
@@ -432,4 +436,5 @@ func testComplianceMessageExport(t *testing.T, ss store.Store) {
assert.Equal(t, directMessageChannel.Id, *messageExportMap[post3.Id].ChannelId)
assert.Equal(t, user1.Id, *messageExportMap[post3.Id].UserId)
assert.Equal(t, user1.Email, *messageExportMap[post3.Id].UserEmail)
+ assert.Equal(t, user1.Username, *messageExportMap[post3.Id].Username)
}
diff --git a/store/storetest/post_store.go b/store/storetest/post_store.go
index 4deb7f8d4..e663d5a41 100644
--- a/store/storetest/post_store.go
+++ b/store/storetest/post_store.go
@@ -27,7 +27,7 @@ func TestPostStore(t *testing.T, ss store.Store) {
t.Run("PermDelete1Level", func(t *testing.T) { testPostStorePermDelete1Level(t, ss) })
t.Run("PermDelete1Level2", func(t *testing.T) { testPostStorePermDelete1Level2(t, ss) })
t.Run("GetWithChildren", func(t *testing.T) { testPostStoreGetWithChildren(t, ss) })
- t.Run("GetPostsWtihDetails", func(t *testing.T) { testPostStoreGetPostsWtihDetails(t, ss) })
+ t.Run("GetPostsWithDetails", func(t *testing.T) { testPostStoreGetPostsWithDetails(t, ss) })
t.Run("GetPostsBeforeAfter", func(t *testing.T) { testPostStoreGetPostsBeforeAfter(t, ss) })
t.Run("GetPostsSince", func(t *testing.T) { testPostStoreGetPostsSince(t, ss) })
t.Run("Search", func(t *testing.T) { testPostStoreSearch(t, ss) })
@@ -490,7 +490,7 @@ func testPostStoreGetWithChildren(t *testing.T, ss store.Store) {
}
}
-func testPostStoreGetPostsWtihDetails(t *testing.T, ss store.Store) {
+func testPostStoreGetPostsWithDetails(t *testing.T, ss store.Store) {
o1 := &model.Post{}
o1.ChannelId = model.NewId()
o1.UserId = model.NewId()
@@ -591,6 +591,25 @@ func testPostStoreGetPostsWtihDetails(t *testing.T, ss store.Store) {
if r2.Posts[o1.Id].Message != o1.Message {
t.Fatal("Missing parent")
}
+
+ // Run once to fill cache
+ <-ss.Post().GetPosts(o1.ChannelId, 0, 30, true)
+
+ o6 := &model.Post{}
+ o6.ChannelId = o1.ChannelId
+ o6.UserId = model.NewId()
+ o6.Message = "zz" + model.NewId() + "b"
+ o6 = (<-ss.Post().Save(o6)).Data.(*model.Post)
+
+ // Should only be 6 since we hit the cache
+ r3 := (<-ss.Post().GetPosts(o1.ChannelId, 0, 30, true)).Data.(*model.PostList)
+ assert.Equal(t, 6, len(r3.Order))
+
+ ss.Post().InvalidateLastPostTimeCache(o1.ChannelId)
+
+ // Cache was invalidated, we should get all the posts
+ r4 := (<-ss.Post().GetPosts(o1.ChannelId, 0, 30, true)).Data.(*model.PostList)
+ assert.Equal(t, 7, len(r4.Order))
}
func testPostStoreGetPostsBeforeAfter(t *testing.T, ss store.Store) {
diff --git a/templates/globalrelay_compliance_export.html b/templates/globalrelay_compliance_export.html
new file mode 100644
index 000000000..91028d11c
--- /dev/null
+++ b/templates/globalrelay_compliance_export.html
@@ -0,0 +1,91 @@
+{{define "globalrelay_compliance_export"}}
+<style type="text/css">
+ body {
+ font-family:Arial, sans-serif;
+ font-size:14px;
+ font-weight:normal;
+ }
+
+ .summary-list ul {
+ padding: 0px;
+ list-style:none;
+ }
+ .summary-list li {
+ display: inline;
+ padding: 0 1em 0 0;
+ }
+ .summary-list .bold {
+ font-weight: bold;
+ }
+
+ .participants {
+ border-collapse:collapse;
+ border-spacing:0;
+ }
+ .participants td {
+ padding:10px 5px;
+ border:1px solid black;
+ overflow:hidden;
+ text-align: center;
+ word-break:normal;
+ }
+ .participants th {
+ padding:10px 5px;
+ border:1px solid black;
+ overflow:hidden;
+ word-break:normal;
+ }
+ .participants th,td {
+ vertical-align:top
+ }
+
+ .message-list ul {
+ list-style:none;
+ padding: 0;
+ }
+ .message-list li {
+ padding: 0 0 1em 0;
+ }
+ .message .sent_time {
+ font-weight:bold;
+ }
+ .message .username {
+ font-weight:bold;
+ }
+ .message .email {
+ font-weight: bold;
+ }
+</style>
+
+<h1>Mattermost Compliance Export</h1>
+
+<h2>Conversation Summary</h2>
+<div class="summary-list">
+ <ul>
+ <li><span class="bold">Channel:&nbsp;</span>{{.Props.ChannelName}}</li>
+ <li><span class="bold">Started:&nbsp;</span>{{.Props.Started}}</li>
+ <li><span class="bold">Ended:&nbsp;</span>{{.Props.Ended}}</li>
+ <li><span class="bold">Duration:&nbsp;</span>{{.Props.Duration}}&nbsp;Minutes</li>
+ </ul>
+</div>
+<table class="participants">
+ <tr>
+ <th class="username">Username<br></th>
+ <th class="email">Email</th>
+ <th class="joined">Joined</th>
+ <th class="left">Left</th>
+ <th class="duration">Duration</th>
+ <th class="messages">Messages</th>
+ </tr>
+ {{.Props.ParticipantRows}}
+</table>
+
+<h2>Messages</h2>
+<div class="message-list">
+ <ul>
+ {{.Props.Messages}}
+ </ul>
+</div>
+
+<p>Exported on {{.Props.ExportDate}}</p>
+{{end}} \ No newline at end of file
diff --git a/templates/globalrelay_compliance_export_message.html b/templates/globalrelay_compliance_export_message.html
new file mode 100644
index 000000000..3a47b29b7
--- /dev/null
+++ b/templates/globalrelay_compliance_export_message.html
@@ -0,0 +1,8 @@
+{{define "globalrelay_compliance_export_message"}}
+<li class="message">
+ <span class="sent_time">{{.Props.SentTime}}</span>
+ <span class="username">@{{.Props.Username}}</span>
+ <span class="email">({{.Props.Email}}):</span>
+ <span class="message">{{.Props.Message}}</span>
+</li>
+{{end}}
diff --git a/templates/globalrelay_compliance_export_participant_row.html b/templates/globalrelay_compliance_export_participant_row.html
new file mode 100644
index 000000000..7a61e23eb
--- /dev/null
+++ b/templates/globalrelay_compliance_export_participant_row.html
@@ -0,0 +1,10 @@
+{{define "globalrelay_compliance_export_participant_row"}}
+<tr>
+ <td class="username">@{{.Props.Username}}</td>
+ <td class="email">{{.Props.Email}}</td>
+ <td class="joined">{{.Props.Joined}}</td>
+ <td class="left">{{.Props.Left}}</td>
+ <td class="duration">{{.Props.DurationMinutes}} Minutes</td>
+ <td class="messages">{{.Props.NumMessages}}</td>
+</tr>
+{{end}} \ No newline at end of file
diff --git a/utils/api.go b/utils/api.go
index 005c3284b..51524074d 100644
--- a/utils/api.go
+++ b/utils/api.go
@@ -4,6 +4,9 @@
package utils
import (
+ "crypto"
+ "crypto/rand"
+ "encoding/base64"
"fmt"
"html/template"
"net/http"
@@ -32,13 +35,25 @@ func OriginChecker(allowedOrigins string) func(*http.Request) bool {
}
}
-func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) {
- status := http.StatusTemporaryRedirect
- if err.StatusCode != http.StatusInternalServerError {
- status = err.StatusCode
+func RenderWebAppError(w http.ResponseWriter, r *http.Request, err *model.AppError, s crypto.Signer) {
+ RenderWebError(w, r, err.StatusCode, url.Values{
+ "message": []string{err.Message},
+ }, s)
+}
+
+func RenderWebError(w http.ResponseWriter, r *http.Request, status int, params url.Values, s crypto.Signer) {
+ queryString := params.Encode()
+
+ h := crypto.SHA256
+ sum := h.New()
+ sum.Write([]byte("/error?" + queryString))
+ signature, err := s.Sign(rand.Reader, sum.Sum(nil), h)
+ if err != nil {
+ http.Error(w, "", http.StatusInternalServerError)
+ return
}
+ destination := strings.TrimRight(GetSiteURL(), "/") + "/error?" + queryString + "&s=" + base64.URLEncoding.EncodeToString(signature)
- destination := strings.TrimRight(GetSiteURL(), "/") + "/error?message=" + url.QueryEscape(err.Message)
if status >= 300 && status < 400 {
http.Redirect(w, r, destination, status)
return
diff --git a/utils/api_test.go b/utils/api_test.go
new file mode 100644
index 000000000..5e41c7bfe
--- /dev/null
+++ b/utils/api_test.go
@@ -0,0 +1,49 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package utils
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/asn1"
+ "encoding/base64"
+ "math/big"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestRenderWebError(t *testing.T) {
+ r := httptest.NewRequest("GET", "http://foo", nil)
+ w := httptest.NewRecorder()
+ key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ require.NoError(t, err)
+ RenderWebError(w, r, http.StatusTemporaryRedirect, url.Values{
+ "foo": []string{"bar"},
+ }, key)
+
+ resp := w.Result()
+ location, err := url.Parse(resp.Header.Get("Location"))
+ require.NoError(t, err)
+ require.NotEmpty(t, location.Query().Get("s"))
+
+ type ecdsaSignature struct {
+ R, S *big.Int
+ }
+ var rs ecdsaSignature
+ s, err := base64.URLEncoding.DecodeString(location.Query().Get("s"))
+ require.NoError(t, err)
+ _, err = asn1.Unmarshal(s, &rs)
+ require.NoError(t, err)
+
+ assert.Equal(t, "bar", location.Query().Get("foo"))
+ h := sha256.Sum256([]byte("/error?foo=bar"))
+ assert.True(t, ecdsa.Verify(&key.PublicKey, h[:], rs.R, rs.S))
+}
diff --git a/utils/authorization.go b/utils/authorization.go
index 39a0d606c..42815b807 100644
--- a/utils/authorization.go
+++ b/utils/authorization.go
@@ -7,7 +7,7 @@ import (
"github.com/mattermost/mattermost-server/model"
)
-func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
+func DefaultRolesBasedOnConfig(cfg *model.Config, isLicensed bool) map[string]*model.Role {
roles := make(map[string]*model.Role)
for id, role := range model.DefaultRoles {
copy := &model.Role{}
@@ -15,7 +15,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
roles[id] = copy
}
- if IsLicensed() {
+ if isLicensed {
switch *cfg.TeamSettings.RestrictPublicChannelCreation {
case model.PERMISSIONS_ALL:
roles[model.TEAM_USER_ROLE_ID].Permissions = append(
@@ -35,7 +35,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
)
}
- if IsLicensed() {
+ if isLicensed {
switch *cfg.TeamSettings.RestrictPublicChannelManagement {
case model.PERMISSIONS_ALL:
roles[model.TEAM_USER_ROLE_ID].Permissions = append(
@@ -64,7 +64,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
)
}
- if IsLicensed() {
+ if isLicensed {
switch *cfg.TeamSettings.RestrictPublicChannelDeletion {
case model.PERMISSIONS_ALL:
roles[model.TEAM_USER_ROLE_ID].Permissions = append(
@@ -93,7 +93,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
)
}
- if IsLicensed() {
+ if isLicensed {
switch *cfg.TeamSettings.RestrictPrivateChannelCreation {
case model.PERMISSIONS_ALL:
roles[model.TEAM_USER_ROLE_ID].Permissions = append(
@@ -113,7 +113,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
)
}
- if IsLicensed() {
+ if isLicensed {
switch *cfg.TeamSettings.RestrictPrivateChannelManagement {
case model.PERMISSIONS_ALL:
roles[model.TEAM_USER_ROLE_ID].Permissions = append(
@@ -142,7 +142,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
)
}
- if IsLicensed() {
+ if isLicensed {
switch *cfg.TeamSettings.RestrictPrivateChannelDeletion {
case model.PERMISSIONS_ALL:
roles[model.TEAM_USER_ROLE_ID].Permissions = append(
@@ -172,7 +172,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
}
// Restrict permissions for Private Channel Manage Members
- if IsLicensed() {
+ if isLicensed {
switch *cfg.TeamSettings.RestrictPrivateChannelManageMembers {
case model.PERMISSIONS_ALL:
roles[model.CHANNEL_USER_ROLE_ID].Permissions = append(
@@ -214,7 +214,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
}
// Grant permissions for inviting and adding users to a team.
- if IsLicensed() {
+ if isLicensed {
if *cfg.TeamSettings.RestrictTeamInvite == model.PERMISSIONS_TEAM_ADMIN {
roles[model.TEAM_ADMIN_ROLE_ID].Permissions = append(
roles[model.TEAM_ADMIN_ROLE_ID].Permissions,
@@ -236,7 +236,7 @@ func DefaultRolesBasedOnConfig(cfg *model.Config) map[string]*model.Role {
)
}
- if IsLicensed() {
+ if isLicensed {
switch *cfg.ServiceSettings.RestrictPostDelete {
case model.PERMISSIONS_DELETE_POST_ALL:
roles[model.CHANNEL_USER_ROLE_ID].Permissions = append(
diff --git a/utils/config.go b/utils/config.go
index 87ebee693..a855733a7 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -342,7 +342,7 @@ func LoadConfig(fileName string) (config *model.Config, configPath string, appEr
return config, configPath, nil
}
-func GenerateClientConfig(c *model.Config, diagnosticId string) map[string]string {
+func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.License) map[string]string {
props := make(map[string]string)
props["Version"] = model.CurrentVersion
@@ -459,18 +459,17 @@ func GenerateClientConfig(c *model.Config, diagnosticId string) map[string]strin
hasImageProxy := c.ServiceSettings.ImageProxyType != nil && *c.ServiceSettings.ImageProxyType != "" && c.ServiceSettings.ImageProxyURL != nil && *c.ServiceSettings.ImageProxyURL != ""
props["HasImageProxy"] = strconv.FormatBool(hasImageProxy)
- if IsLicensed() {
- License := License()
+ if license != nil {
props["ExperimentalTownSquareIsReadOnly"] = strconv.FormatBool(*c.TeamSettings.ExperimentalTownSquareIsReadOnly)
props["ExperimentalEnableAuthenticationTransfer"] = strconv.FormatBool(*c.ServiceSettings.ExperimentalEnableAuthenticationTransfer)
- if *License.Features.CustomBrand {
+ if *license.Features.CustomBrand {
props["EnableCustomBrand"] = strconv.FormatBool(*c.TeamSettings.EnableCustomBrand)
props["CustomBrandText"] = *c.TeamSettings.CustomBrandText
props["CustomDescriptionText"] = *c.TeamSettings.CustomDescriptionText
}
- if *License.Features.LDAP {
+ if *license.Features.LDAP {
props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable)
props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName
props["LdapNicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "")
@@ -481,16 +480,16 @@ func GenerateClientConfig(c *model.Config, diagnosticId string) map[string]strin
props["LdapLoginButtonTextColor"] = *c.LdapSettings.LoginButtonTextColor
}
- if *License.Features.MFA {
+ if *license.Features.MFA {
props["EnableMultifactorAuthentication"] = strconv.FormatBool(*c.ServiceSettings.EnableMultifactorAuthentication)
props["EnforceMultifactorAuthentication"] = strconv.FormatBool(*c.ServiceSettings.EnforceMultifactorAuthentication)
}
- if *License.Features.Compliance {
+ if *license.Features.Compliance {
props["EnableCompliance"] = strconv.FormatBool(*c.ComplianceSettings.Enable)
}
- if *License.Features.SAML {
+ if *license.Features.SAML {
props["EnableSaml"] = strconv.FormatBool(*c.SamlSettings.Enable)
props["SamlLoginButtonText"] = *c.SamlSettings.LoginButtonText
props["SamlFirstNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.FirstNameAttribute != "")
@@ -501,23 +500,23 @@ func GenerateClientConfig(c *model.Config, diagnosticId string) map[string]strin
props["SamlLoginButtonTextColor"] = *c.SamlSettings.LoginButtonTextColor
}
- if *License.Features.Cluster {
+ if *license.Features.Cluster {
props["EnableCluster"] = strconv.FormatBool(*c.ClusterSettings.Enable)
}
- if *License.Features.Cluster {
+ if *license.Features.Cluster {
props["EnableMetrics"] = strconv.FormatBool(*c.MetricsSettings.Enable)
}
- if *License.Features.GoogleOAuth {
+ if *license.Features.GoogleOAuth {
props["EnableSignUpWithGoogle"] = strconv.FormatBool(c.GoogleSettings.Enable)
}
- if *License.Features.Office365OAuth {
+ if *license.Features.Office365OAuth {
props["EnableSignUpWithOffice365"] = strconv.FormatBool(c.Office365Settings.Enable)
}
- if *License.Features.PasswordRequirements {
+ if *license.Features.PasswordRequirements {
props["PasswordMinimumLength"] = fmt.Sprintf("%v", *c.PasswordSettings.MinimumLength)
props["PasswordRequireLowercase"] = strconv.FormatBool(*c.PasswordSettings.Lowercase)
props["PasswordRequireUppercase"] = strconv.FormatBool(*c.PasswordSettings.Uppercase)
@@ -525,7 +524,7 @@ func GenerateClientConfig(c *model.Config, diagnosticId string) map[string]strin
props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol)
}
- if *License.Features.Announcement {
+ if *license.Features.Announcement {
props["EnableBanner"] = strconv.FormatBool(*c.AnnouncementSettings.EnableBanner)
props["BannerText"] = *c.AnnouncementSettings.BannerText
props["BannerColor"] = *c.AnnouncementSettings.BannerColor
@@ -533,14 +532,14 @@ func GenerateClientConfig(c *model.Config, diagnosticId string) map[string]strin
props["AllowBannerDismissal"] = strconv.FormatBool(*c.AnnouncementSettings.AllowBannerDismissal)
}
- if *License.Features.ThemeManagement {
+ if *license.Features.ThemeManagement {
props["EnableThemeSelection"] = strconv.FormatBool(*c.ThemeSettings.EnableThemeSelection)
props["DefaultTheme"] = *c.ThemeSettings.DefaultTheme
props["AllowCustomThemes"] = strconv.FormatBool(*c.ThemeSettings.AllowCustomThemes)
props["AllowedThemes"] = strings.Join(c.ThemeSettings.AllowedThemes, ",")
}
- if *License.Features.DataRetention {
+ if *license.Features.DataRetention {
props["DataRetentionEnableMessageDeletion"] = strconv.FormatBool(*c.DataRetentionSettings.EnableMessageDeletion)
props["DataRetentionMessageRetentionDays"] = strconv.FormatInt(int64(*c.DataRetentionSettings.MessageRetentionDays), 10)
props["DataRetentionEnableFileDeletion"] = strconv.FormatBool(*c.DataRetentionSettings.EnableFileDeletion)
diff --git a/utils/config_test.go b/utils/config_test.go
index 9abc56d5e..5809422f1 100644
--- a/utils/config_test.go
+++ b/utils/config_test.go
@@ -197,7 +197,7 @@ func TestGetClientConfig(t *testing.T) {
cfg, _, err := LoadConfig("config.json")
require.Nil(t, err)
- configMap := GenerateClientConfig(cfg, "")
+ configMap := GenerateClientConfig(cfg, "", nil)
if configMap["EmailNotificationContentsType"] != *cfg.EmailSettings.EmailNotificationContentsType {
t.Fatal("EmailSettings.EmailNotificationContentsType not exposed to client config")
}
diff --git a/utils/file_backend.go b/utils/file_backend.go
index c7a6c5591..42af7f604 100644
--- a/utils/file_backend.go
+++ b/utils/file_backend.go
@@ -22,7 +22,7 @@ type FileBackend interface {
RemoveDirectory(path string) *model.AppError
}
-func NewFileBackend(settings *model.FileSettings) (FileBackend, *model.AppError) {
+func NewFileBackend(settings *model.FileSettings, enableComplianceFeatures bool) (FileBackend, *model.AppError) {
switch *settings.DriverName {
case model.IMAGE_DRIVER_S3:
return &S3FileBackend{
@@ -33,7 +33,7 @@ func NewFileBackend(settings *model.FileSettings) (FileBackend, *model.AppError)
signV2: settings.AmazonS3SignV2 != nil && *settings.AmazonS3SignV2,
region: settings.AmazonS3Region,
bucket: settings.AmazonS3Bucket,
- encrypt: settings.AmazonS3SSE != nil && *settings.AmazonS3SSE && IsLicensed() && *License().Features.Compliance,
+ encrypt: settings.AmazonS3SSE != nil && *settings.AmazonS3SSE && enableComplianceFeatures,
trace: settings.AmazonS3Trace != nil && *settings.AmazonS3Trace,
}, nil
case model.IMAGE_DRIVER_LOCAL:
diff --git a/utils/file_backend_test.go b/utils/file_backend_test.go
index 76cd1f4a8..46f75574e 100644
--- a/utils/file_backend_test.go
+++ b/utils/file_backend_test.go
@@ -63,7 +63,7 @@ func TestS3FileBackendTestSuite(t *testing.T) {
func (s *FileBackendTestSuite) SetupTest() {
TranslationsPreInit()
- backend, err := NewFileBackend(&s.settings)
+ backend, err := NewFileBackend(&s.settings, true)
require.Nil(s.T(), err)
s.backend = backend
}
diff --git a/utils/html.go b/utils/html.go
index 02db8c97a..6bbe55c6d 100644
--- a/utils/html.go
+++ b/utils/html.go
@@ -23,7 +23,7 @@ type HTMLTemplateWatcher struct {
func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
templatesDir, _ := FindDir(directory)
- l4g.Debug(T("api.api.init.parsing_templates.debug"), templatesDir)
+ l4g.Debug("Parsing server templates at %v", templatesDir)
ret := &HTMLTemplateWatcher{
stop: make(chan struct{}),
@@ -55,15 +55,15 @@ func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
return
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
- l4g.Info(T("web.reparse_templates.info"), event.Name)
+ l4g.Info("Re-parsing templates because of modified file %v", event.Name)
if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil {
- l4g.Error(T("web.parsing_templates.error"), err)
+ l4g.Error("Failed to parse templates %v", err)
} else {
ret.templates.Store(htmlTemplates)
}
}
case err := <-watcher.Errors:
- l4g.Error(T("web.dir_fail.error"), err)
+ l4g.Error("Failed in directory watcher %s", err)
}
}
}()
diff --git a/utils/inbucket.go b/utils/inbucket.go
index 46011989b..5c40d5757 100644
--- a/utils/inbucket.go
+++ b/utils/inbucket.go
@@ -4,6 +4,7 @@
package utils
import (
+ "bytes"
"encoding/json"
"fmt"
"io"
@@ -37,6 +38,12 @@ type JSONMessageInbucket struct {
Text string
HTML string `json:"Html"`
}
+ Attachments []struct {
+ Filename string
+ ContentType string `json:"content-type"`
+ DownloadLink string `json:"download-link"`
+ Bytes []byte `json:"-"`
+ }
}
func ParseEmail(email string) string {
@@ -89,21 +96,54 @@ func GetMessageFromMailbox(email, id string) (results JSONMessageInbucket, err e
var record JSONMessageInbucket
url := fmt.Sprintf("%s%s%s/%s", getInbucketHost(), INBUCKET_API, parsedEmail, id)
- req, err := http.NewRequest("GET", url, nil)
+ emailResponse, err := get(url)
if err != nil {
return record, err
}
+ defer emailResponse.Body.Close()
+
+ err = json.NewDecoder(emailResponse.Body).Decode(&record)
+
+ // download attachments
+ if record.Attachments != nil && len(record.Attachments) > 0 {
+ for i := range record.Attachments {
+ if bytes, err := downloadAttachment(record.Attachments[i].DownloadLink); err != nil {
+ return record, err
+ } else {
+ record.Attachments[i].Bytes = make([]byte, len(bytes))
+ copy(record.Attachments[i].Bytes, bytes)
+ }
+ }
+ }
- client := &http.Client{}
+ return record, err
+}
+
+func downloadAttachment(url string) ([]byte, error) {
+ attachmentResponse, err := get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer attachmentResponse.Body.Close()
+
+ buf := new(bytes.Buffer)
+ io.Copy(buf, attachmentResponse.Body)
+ return buf.Bytes(), nil
+}
+
+func get(url string) (*http.Response, error) {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
- return record, err
+ return nil, err
}
- defer resp.Body.Close()
- err = json.NewDecoder(resp.Body).Decode(&record)
- return record, err
+ return resp, nil
}
func DeleteMailBox(email string) (err error) {
diff --git a/utils/license.go b/utils/license.go
index 2aaa2a549..2853a58d0 100644
--- a/utils/license.go
+++ b/utils/license.go
@@ -5,28 +5,21 @@ package utils
import (
"crypto"
- "crypto/md5"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"encoding/base64"
"encoding/pem"
- "fmt"
"io/ioutil"
"os"
"strconv"
"strings"
- "sync/atomic"
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/mattermost-server/model"
)
-var isLicensedInt32 int32
-var licenseValue atomic.Value
-var clientLicenseValue atomic.Value
-
var publicKey []byte = []byte(`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyZmShlU8Z8HdG0IWSZ8r
tSyzyxrXkJjsFUf0Ke7bm/TLtIggRdqOcUF3XEWqQk5RGD5vuq7Rlg1zZqMEBk8N
@@ -37,92 +30,6 @@ a0v85XL6i9ote2P+fLZ3wX9EoioHzgdgB7arOxY50QRJO7OyCqpKFKv6lRWTXuSt
hwIDAQAB
-----END PUBLIC KEY-----`)
-func init() {
- SetLicense(nil)
-}
-
-func IsLicensed() bool {
- return atomic.LoadInt32(&isLicensedInt32) == 1
-}
-
-func SetIsLicensed(v bool) {
- if v {
- atomic.StoreInt32(&isLicensedInt32, 1)
- } else {
- atomic.StoreInt32(&isLicensedInt32, 0)
- }
-}
-
-func License() *model.License {
- return licenseValue.Load().(*model.License)
-}
-
-func SetClientLicense(m map[string]string) {
- clientLicenseValue.Store(m)
-}
-
-func ClientLicense() map[string]string {
- return clientLicenseValue.Load().(map[string]string)
-}
-
-func LoadLicense(licenseBytes []byte) {
- if success, licenseStr := ValidateLicense(licenseBytes); success {
- license := model.LicenseFromJson(strings.NewReader(licenseStr))
- SetLicense(license)
- return
- }
-
- l4g.Warn(T("utils.license.load_license.invalid.warn"))
-}
-
-var licenseListeners = map[string]func(){}
-
-func AddLicenseListener(listener func()) string {
- id := model.NewId()
- licenseListeners[id] = listener
- return id
-}
-
-func RemoveLicenseListener(id string) {
- delete(licenseListeners, id)
-}
-
-func SetLicense(license *model.License) bool {
- defer func() {
- for _, listener := range licenseListeners {
- listener()
- }
- }()
-
- if license == nil {
- SetIsLicensed(false)
- license = &model.License{
- Features: new(model.Features),
- }
- license.Features.SetDefaults()
- licenseValue.Store(license)
-
- SetClientLicense(map[string]string{"IsLicensed": "false"})
-
- return false
- } else {
- license.Features.SetDefaults()
-
- if !license.IsExpired() {
- licenseValue.Store(license)
- SetIsLicensed(true)
- clientLicenseValue.Store(getClientLicense(license))
- return true
- }
-
- return false
- }
-}
-
-func RemoveLicense() {
- SetLicense(nil)
-}
-
func ValidateLicense(signed []byte) (bool, string) {
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(signed)))
@@ -213,12 +120,12 @@ func GetLicenseFileLocation(fileLocation string) string {
}
}
-func getClientLicense(l *model.License) map[string]string {
+func GetClientLicense(l *model.License) map[string]string {
props := make(map[string]string)
- props["IsLicensed"] = strconv.FormatBool(IsLicensed())
+ props["IsLicensed"] = strconv.FormatBool(l != nil)
- if IsLicensed() {
+ if l != nil {
props["Id"] = l.Id
props["Users"] = strconv.Itoa(*l.Features.Users)
props["LDAP"] = strconv.FormatBool(*l.Features.LDAP)
@@ -248,39 +155,3 @@ func getClientLicense(l *model.License) map[string]string {
return props
}
-
-func GetClientLicenseEtag(useSanitized bool) string {
- value := ""
-
- lic := ClientLicense()
-
- if useSanitized {
- lic = GetSanitizedClientLicense()
- }
-
- for k, v := range lic {
- value += fmt.Sprintf("%s:%s;", k, v)
- }
-
- return model.Etag(fmt.Sprintf("%x", md5.Sum([]byte(value))))
-}
-
-func GetSanitizedClientLicense() map[string]string {
- sanitizedLicense := make(map[string]string)
-
- for k, v := range ClientLicense() {
- sanitizedLicense[k] = v
- }
-
- if IsLicensed() {
- 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/utils/license_test.go b/utils/license_test.go
index 9771ec497..c2d1b4c05 100644
--- a/utils/license_test.go
+++ b/utils/license_test.go
@@ -5,87 +5,20 @@ package utils
import (
"testing"
-
- "github.com/mattermost/mattermost-server/model"
)
-func TestSetLicense(t *testing.T) {
- l1 := &model.License{}
- l1.Features = &model.Features{}
- l1.Customer = &model.Customer{}
- l1.StartsAt = model.GetMillis() - 1000
- l1.ExpiresAt = model.GetMillis() + 100000
- if ok := 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 := 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 := SetLicense(l3); !ok {
- t.Fatal("license should have passed")
- }
-}
-
func TestValidateLicense(t *testing.T) {
b1 := []byte("junk")
if ok, _ := ValidateLicense(b1); ok {
t.Fatal("should have failed - bad license")
}
- LoadLicense(b1)
-
b2 := []byte("junkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunk")
if ok, _ := ValidateLicense(b2); ok {
t.Fatal("should have failed - bad license")
}
}
-func TestClientLicenseEtag(t *testing.T) {
- etag1 := GetClientLicenseEtag(false)
-
- SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "true"})
-
- etag2 := GetClientLicenseEtag(false)
- if etag1 == etag2 {
- t.Fatal("etags should not match")
- }
-
- SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "false"})
-
- etag3 := GetClientLicenseEtag(false)
- if etag2 == etag3 {
- t.Fatal("etags should not match")
- }
-}
-
-func TestGetSanitizedClientLicense(t *testing.T) {
- 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
- SetLicense(l1)
-
- m := GetSanitizedClientLicense()
-
- if _, ok := m["Name"]; ok {
- t.Fatal("should have been sanatized")
- }
-}
-
func TestGetLicenseFileLocation(t *testing.T) {
fileName := GetLicenseFileLocation("")
if len(fileName) == 0 {
diff --git a/utils/mail.go b/utils/mail.go
index b0289da5e..633f97818 100644
--- a/utils/mail.go
+++ b/utils/mail.go
@@ -15,6 +15,8 @@ import (
"net/http"
+ "io"
+
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/html2text"
"github.com/mattermost/mattermost-server/model"
@@ -103,37 +105,73 @@ func TestConnection(config *model.Config) {
defer c.Close()
}
-func SendMailUsingConfig(to, subject, htmlBody string, config *model.Config) *model.AppError {
+func SendMailUsingConfig(to, subject, htmlBody string, config *model.Config, enableComplianceFeatures bool) *model.AppError {
+ fromMail := mail.Address{Name: config.EmailSettings.FeedbackName, Address: config.EmailSettings.FeedbackEmail}
+ return sendMail(to, to, fromMail, subject, htmlBody, nil, nil, config, enableComplianceFeatures)
+}
+
+// allows for sending an email with attachments and differing MIME/SMTP recipients
+func SendMailUsingConfigAdvanced(mimeTo, smtpTo string, from mail.Address, subject, htmlBody string, attachments []*model.FileInfo, mimeHeaders map[string]string, config *model.Config, enableComplianceFeatures bool) *model.AppError {
+ return sendMail(mimeTo, smtpTo, from, subject, htmlBody, attachments, mimeHeaders, config, enableComplianceFeatures)
+}
+
+func sendMail(mimeTo, smtpTo string, from mail.Address, subject, htmlBody string, attachments []*model.FileInfo, mimeHeaders map[string]string, config *model.Config, enableComplianceFeatures bool) *model.AppError {
if !config.EmailSettings.SendEmailNotifications || len(config.EmailSettings.SMTPServer) == 0 {
return nil
}
- l4g.Debug(T("utils.mail.send_mail.sending.debug"), to, subject)
+ l4g.Debug(T("utils.mail.send_mail.sending.debug"), mimeTo, subject)
htmlMessage := "\r\n<html><body>" + htmlBody + "</body></html>"
- fromMail := mail.Address{Name: config.EmailSettings.FeedbackName, Address: config.EmailSettings.FeedbackEmail}
-
txtBody, err := html2text.FromString(htmlBody)
if err != nil {
l4g.Warn(err)
txtBody = ""
}
- m := gomail.NewMessage(gomail.SetCharset("UTF-8"))
- m.SetHeaders(map[string][]string{
- "From": {fromMail.String()},
- "To": {to},
+ headers := map[string][]string{
+ "From": {from.String()},
+ "To": {mimeTo},
"Subject": {encodeRFC2047Word(subject)},
"Content-Transfer-Encoding": {"8bit"},
"Auto-Submitted": {"auto-generated"},
"Precedence": {"bulk"},
- })
- m.SetDateHeader("Date", time.Now())
+ }
+ if mimeHeaders != nil {
+ for k, v := range mimeHeaders {
+ headers[k] = []string{encodeRFC2047Word(v)}
+ }
+ }
+ m := gomail.NewMessage(gomail.SetCharset("UTF-8"))
+ m.SetHeaders(headers)
+ m.SetDateHeader("Date", time.Now())
m.SetBody("text/plain", txtBody)
m.AddAlternative("text/html", htmlMessage)
+ if attachments != nil {
+ fileBackend, err := NewFileBackend(&config.FileSettings, enableComplianceFeatures)
+ if err != nil {
+ return err
+ }
+
+ for _, fileInfo := range attachments {
+ m.Attach(fileInfo.Name, gomail.SetCopyFunc(func(writer io.Writer) error {
+ bytes, err := fileBackend.ReadFile(fileInfo.Path)
+ if err != nil {
+ return err
+ }
+ if _, err := writer.Write(bytes); err != nil {
+ return model.NewAppError("SendMail", "utils.mail.sendMail.attachments.write_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+ return nil
+ }))
+
+ }
+
+ }
+
conn, err1 := connectToSMTPServer(config)
if err1 != nil {
return err1
@@ -147,11 +185,11 @@ func SendMailUsingConfig(to, subject, htmlBody string, config *model.Config) *mo
defer c.Quit()
defer c.Close()
- if err := c.Mail(fromMail.Address); err != nil {
+ if err := c.Mail(from.Address); err != nil {
return model.NewAppError("SendMail", "utils.mail.send_mail.from_address.app_error", nil, err.Error(), http.StatusInternalServerError)
}
- if err := c.Rcpt(to); err != nil {
+ if err := c.Rcpt(smtpTo); err != nil {
return model.NewAppError("SendMail", "utils.mail.send_mail.to_address.app_error", nil, err.Error(), http.StatusInternalServerError)
}
diff --git a/utils/mail_test.go b/utils/mail_test.go
index 574f71f46..703420441 100644
--- a/utils/mail_test.go
+++ b/utils/mail_test.go
@@ -7,6 +7,10 @@ import (
"strings"
"testing"
+ "net/mail"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -39,18 +43,18 @@ func TestSendMailUsingConfig(t *testing.T) {
require.Nil(t, err)
T = GetUserTranslations("en")
- var emailTo string = "test@example.com"
- var emailSubject string = "Testing this email"
- var emailBody string = "This is a test from autobot"
+ var emailTo = "test@example.com"
+ var emailSubject = "Testing this email"
+ var emailBody = "This is a test from autobot"
//Delete all the messages before check the sample email
DeleteMailBox(emailTo)
- if err := SendMailUsingConfig(emailTo, emailSubject, emailBody, cfg); err != nil {
+ if err := SendMailUsingConfig(emailTo, emailSubject, emailBody, cfg, true); err != nil {
t.Log(err)
t.Fatal("Should connect to the STMP Server")
} else {
- //Check if the email was send to the rigth email address
+ //Check if the email was send to the right email address
var resultsMailbox JSONMessageHeaderInbucket
err := RetryInbucket(5, func() error {
var err error
@@ -75,3 +79,78 @@ func TestSendMailUsingConfig(t *testing.T) {
}
}
}
+
+func TestSendMailUsingConfigAdvanced(t *testing.T) {
+ cfg, _, err := LoadConfig("config.json")
+ require.Nil(t, err)
+ T = GetUserTranslations("en")
+
+ var mimeTo = "test@example.com"
+ var smtpTo = "test2@example.com"
+ var from = mail.Address{Name: "Nobody", Address: "nobody@mattermost.com"}
+ var emailSubject = "Testing this email"
+ var emailBody = "This is a test from autobot"
+
+ //Delete all the messages before check the sample email
+ DeleteMailBox(smtpTo)
+
+ // create a file that will be attached to the email
+ fileBackend, err := NewFileBackend(&cfg.FileSettings, true)
+ assert.Nil(t, err)
+ fileContents := []byte("hello world")
+ fileName := "file.txt"
+ assert.Nil(t, fileBackend.WriteFile(fileContents, fileName))
+ defer fileBackend.RemoveFile(fileName)
+
+ attachments := make([]*model.FileInfo, 1)
+ attachments[0] = &model.FileInfo{
+ Name: fileName,
+ Path: fileName,
+ }
+
+ headers := make(map[string]string)
+ headers["TestHeader"] = "TestValue"
+
+ if err := SendMailUsingConfigAdvanced(mimeTo, smtpTo, from, emailSubject, emailBody, attachments, headers, cfg, true); err != nil {
+ t.Log(err)
+ t.Fatal("Should connect to the STMP Server")
+ } else {
+ //Check if the email was send to the right email address
+ var resultsMailbox JSONMessageHeaderInbucket
+ err := RetryInbucket(5, func() error {
+ var err error
+ resultsMailbox, err = GetMailBox(smtpTo)
+ return err
+ })
+ if err != nil {
+ t.Log(err)
+ t.Fatal("No emails found for address " + smtpTo)
+ }
+ if err == nil && len(resultsMailbox) > 0 {
+ if !strings.ContainsAny(resultsMailbox[0].To[0], smtpTo) {
+ t.Fatal("Wrong To recipient")
+ } else {
+ if resultsEmail, err := GetMessageFromMailbox(smtpTo, resultsMailbox[0].ID); err == nil {
+ if !strings.Contains(resultsEmail.Body.Text, emailBody) {
+ t.Log(resultsEmail.Body.Text)
+ t.Fatal("Received message")
+ }
+
+ // verify that the To header of the email message is set to the MIME recipient, even though we got it out of the SMTP recipient's email inbox
+ assert.Equal(t, mimeTo, resultsEmail.Header["To"][0])
+
+ // verify that the MIME from address is correct - unfortunately, we can't verify the SMTP from address
+ assert.Equal(t, from.String(), resultsEmail.Header["From"][0])
+
+ // check that the custom mime headers came through - header case seems to get mutated
+ assert.Equal(t, "TestValue", resultsEmail.Header["Testheader"][0])
+
+ // ensure that the attachment was successfully sent
+ assert.Len(t, resultsEmail.Attachments, 1)
+ assert.Equal(t, fileName, resultsEmail.Attachments[0].Filename)
+ assert.Equal(t, fileContents, resultsEmail.Attachments[0].Bytes)
+ }
+ }
+ }
+ }
+}
diff --git a/web/web.go b/web/web.go
index 321d83a75..e0edd1b7a 100644
--- a/web/web.go
+++ b/web/web.go
@@ -94,7 +94,7 @@ func root(c *api.Context, w http.ResponseWriter, r *http.Request) {
}
if api.IsApiCall(r) {
- api.Handle404(w, r)
+ api.Handle404(c.App, w, r)
return
}
diff --git a/web/web_test.go b/web/web_test.go
index 21a7968b3..c8d64c61d 100644
--- a/web/web_test.go
+++ b/web/web_test.go
@@ -44,7 +44,10 @@ func Setup() *app.App {
}
prevListenAddress := *a.Config().ServiceSettings.ListenAddress
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
- a.StartServer()
+ serverErr := a.StartServer()
+ if serverErr != nil {
+ panic(serverErr)
+ }
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
api4.Init(a, a.Srv.Router, false)
api3 := api.Init(a, a.Srv.Router)