Merge branch 'release-4.7' into rm-willnorris-proxy-support

This commit is contained in:
Chris
2018-02-12 18:36:39 -06:00
committed by GitHub
86 changed files with 1357 additions and 1348 deletions

View File

@@ -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/mattermost/go-bindata/...
go get github.com/jteeuwen/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/mattermost/go-bindata/...
go get github.com/jteeuwen/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

View File

@@ -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(api.Handle404))
root.Handle("/api/{anything:.*}", http.HandlerFunc(Handle404))
a.InitEmailBatching()
@@ -120,10 +120,6 @@ 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

View File

@@ -105,11 +105,7 @@ func setupTestHelper(enterprise bool) *TestHelper {
if testStore != nil {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
}
serverErr := th.App.StartServer()
if serverErr != nil {
panic(serverErr)
}
th.App.StartServer()
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)
@@ -118,10 +114,9 @@ func setupTestHelper(enterprise bool) *TestHelper {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = true })
utils.SetIsLicensed(enterprise)
if enterprise {
th.App.SetLicense(model.NewTestLicense())
} else {
th.App.SetLicense(nil)
utils.License().Features.SetDefaults()
}
return th

View File

@@ -12,6 +12,7 @@ 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) {
@@ -96,9 +97,23 @@ 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.SetLicense(model.NewTestLicense())
th.App.SetDefaultRolesBasedOnConfig()
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
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}
@@ -115,6 +130,7 @@ 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"
@@ -144,6 +160,7 @@ 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"
@@ -164,7 +181,9 @@ func TestCreateChannel(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
th.App.SetLicense(nil)
utils.SetIsLicensed(false)
utils.SetLicense(nil)
th.App.SetDefaultRolesBasedOnConfig()
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}
@@ -177,6 +196,7 @@ 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) {
@@ -347,9 +367,23 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
channel2 := th.CreateChannel(Client, team)
channel3 := th.CreatePrivateChannel(Client, team)
@@ -370,8 +404,14 @@ 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()
@@ -407,9 +447,14 @@ 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
})
th.App.SetLicense(model.NewTestLicense())
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 team admin")
@@ -432,8 +477,14 @@ 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")
@@ -452,7 +503,9 @@ func TestUpdateChannel(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
th.App.SetLicense(nil)
utils.SetIsLicensed(false)
utils.SetLicense(nil)
th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.UpdateChannel(channel2); err != nil {
t.Fatal(err)
@@ -565,9 +618,23 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
channel2 := th.CreateChannel(Client, team)
@@ -592,8 +659,11 @@ 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()
@@ -618,8 +688,11 @@ 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")
@@ -642,8 +715,11 @@ 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")
@@ -665,7 +741,9 @@ func TestUpdateChannelHeader(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
th.App.SetLicense(nil)
utils.SetIsLicensed(false)
utils.SetLicense(nil)
th.App.SetDefaultRolesBasedOnConfig()
if _, err := SystemAdminClient.UpdateChannelHeader(data2); err != nil {
t.Fatal(err)
@@ -736,9 +814,23 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
channel2 := th.CreateChannel(Client, team)
@@ -763,8 +855,11 @@ 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()
@@ -789,8 +884,11 @@ 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")
@@ -813,8 +911,11 @@ 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")
@@ -836,7 +937,9 @@ func TestUpdateChannelPurpose(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
th.App.SetLicense(nil)
utils.SetIsLicensed(false)
utils.SetLicense(nil)
th.App.SetDefaultRolesBasedOnConfig()
if _, err := SystemAdminClient.UpdateChannelHeader(data2); err != nil {
t.Fatal(err)
}
@@ -1297,9 +1400,23 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
th.LoginSystemAdmin()
th.LinkUserToTeam(th.BasicUser, team)
@@ -1321,10 +1438,16 @@ 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()
@@ -1375,11 +1498,16 @@ func TestDeleteChannel(t *testing.T) {
th.UpdateUserToNonTeamAdmin(th.BasicUser, team)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
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_TEAM_ADMIN
})
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.TeamSettings.RestrictPrivateChannelDeletion = model.PERMISSIONS_TEAM_ADMIN
})
th.App.SetDefaultRolesBasedOnConfig()
th.LoginSystemAdmin()
@@ -1409,10 +1537,16 @@ 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()
@@ -1444,7 +1578,9 @@ func TestDeleteChannel(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
th.App.SetLicense(nil)
utils.SetIsLicensed(false)
utils.SetLicense(nil)
th.App.SetDefaultRolesBasedOnConfig()
channel2 = th.CreateChannel(Client, team)
channel3 = th.CreatePrivateChannel(Client, team)
@@ -1459,6 +1595,10 @@ 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) {
@@ -1535,9 +1675,16 @@ 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)
@@ -1547,8 +1694,18 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
// 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}
@@ -1562,6 +1719,10 @@ 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)
@@ -1572,7 +1733,10 @@ func TestAddChannelMember(t *testing.T) {
th.MakeUserChannelAdmin(user1, channel5)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.AddChannelMember(channel5.Id, user2.Id); err != nil {
t.Fatal(err)
@@ -1582,6 +1746,10 @@ 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)
@@ -1592,7 +1760,10 @@ func TestAddChannelMember(t *testing.T) {
th.UpdateUserToTeamAdmin(user1, team)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.AddChannelMember(channel6.Id, user2.Id); err != nil {
t.Fatal(err)
@@ -1602,6 +1773,10 @@ 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)
@@ -1685,9 +1860,16 @@ 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)
@@ -1698,8 +1880,18 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
// 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}
@@ -1714,6 +1906,10 @@ 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)
@@ -1725,7 +1921,9 @@ func TestRemoveChannelMember(t *testing.T) {
th.MakeUserChannelAdmin(user1, channel5)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
if _, err := Client.RemoveChannelMember(channel5.Id, user2.Id); err != nil {
t.Fatal(err)
@@ -1735,6 +1933,10 @@ 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)
@@ -1746,7 +1948,10 @@ func TestRemoveChannelMember(t *testing.T) {
th.UpdateUserToTeamAdmin(user1, team)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
if _, err := Client.RemoveChannelMember(channel6.Id, user2.Id); err != nil {
t.Fatal(err)
@@ -1756,6 +1961,10 @@ 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)

View File

@@ -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.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
utils.RenderWebError(c.Err, w, r)
}
}
@@ -434,7 +434,7 @@ func IsApiCall(r *http.Request) bool {
return strings.Index(r.URL.Path, "/api/") == 0
}
func Handle404(a *app.App, w http.ResponseWriter, r *http.Request) {
func Handle404(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(a *app.App, 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.RenderWebAppError(w, r, err, a.AsymmetricSigningKey())
utils.RenderWebError(err, w, r)
}
}

View File

@@ -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)
utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
return
}
} else {
c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest)
utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
return
}

View File

@@ -9,6 +9,7 @@ import (
"net/http"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
)
func (api *API) InitLicense() {
@@ -82,7 +83,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 := c.App.GetClientLicenseEtag(useSanitizedLicense)
etag := utils.GetClientLicenseEtag(useSanitizedLicense)
if c.HandleEtag(etag, "Get Client License Config", w, r) {
return
}
@@ -90,9 +91,9 @@ func getClientLicenceConfig(c *Context, w http.ResponseWriter, r *http.Request)
var clientLicense map[string]string
if useSanitizedLicense {
clientLicense = c.App.ClientLicense()
clientLicense = utils.ClientLicense()
} else {
clientLicense = c.App.GetSanitizedClientLicense()
clientLicense = utils.GetSanitizedClientLicense()
}
w.Header().Set(model.HEADER_ETAG_SERVER, etag)

View File

@@ -5,6 +5,8 @@ package api
import (
"testing"
"github.com/mattermost/mattermost-server/utils"
)
func TestGetLicenceConfig(t *testing.T) {
@@ -30,7 +32,7 @@ func TestGetLicenceConfig(t *testing.T) {
t.Fatal("cache should be empty")
}
th.App.SetClientLicense(map[string]string{"IsLicensed": "true"})
utils.SetClientLicense(map[string]string{"IsLicensed": "true"})
if cache_result, err := Client.GetClientLicenceConfig(result.Etag); err != nil {
t.Fatal(err)
@@ -38,7 +40,7 @@ func TestGetLicenceConfig(t *testing.T) {
t.Fatal("result should not be empty")
}
th.App.SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "true"})
utils.SetClientLicense(map[string]string{"SomeFeature": "true", "IsLicensed": "true"})
if cache_result, err := Client.GetClientLicenceConfig(result.Etag); err != nil {
t.Fatal(err)
@@ -46,6 +48,6 @@ func TestGetLicenceConfig(t *testing.T) {
t.Fatal("result should not be empty")
}
th.App.SetClientLicense(map[string]string{"IsLicensed": "false"})
utils.SetClientLicense(map[string]string{"IsLicensed": "false"})
}
}

View File

@@ -160,8 +160,20 @@ 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.SetLicense(model.NewTestLicense())
th.App.SetDefaultRolesBasedOnConfig()
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
defaultChannel := store.Must(th.App.Srv.Store.Channel().GetByName(team.Id, model.DEFAULT_CHANNEL, true)).(*model.Channel)
defaultPost := &model.Post{
@@ -454,7 +466,16 @@ func TestUpdatePost(t *testing.T) {
}
// Test licensed policy controls for edit post
th.App.SetLicense(model.NewTestLicense())
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.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}
@@ -945,6 +966,7 @@ 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"}
@@ -999,7 +1021,15 @@ func TestDeletePosts(t *testing.T) {
}
// Test licensed policy controls for delete post
th.App.SetLicense(model.NewTestLicense())
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.UpdateUserToTeamAdmin(th.BasicUser2, th.BasicTeam)
@@ -1014,6 +1044,7 @@ 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()
@@ -1038,6 +1069,7 @@ 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()
@@ -1056,7 +1088,9 @@ func TestDeletePosts(t *testing.T) {
}
// Check that if unlicensed the policy restriction is not enforced.
th.App.SetLicense(nil)
utils.SetIsLicensed(false)
utils.SetLicense(nil)
th.App.SetDefaultRolesBasedOnConfig()
time.Sleep(10 * time.Millisecond)
post7 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}

View File

@@ -139,8 +139,20 @@ 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)
@@ -149,7 +161,10 @@ func TestAddUserToTeam(t *testing.T) {
}
// Add an EE license.
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
// Check that a regular user can't add someone to the team.
user4 := th.CreateUser(th.BasicClient)
@@ -160,8 +175,11 @@ 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 {
@@ -170,6 +188,7 @@ 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)
@@ -546,7 +565,13 @@ 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)
@@ -555,7 +580,17 @@ func TestInviteMembers(t *testing.T) {
t.Fatal(err)
}
th.App.SetLicense(model.NewTestLicense())
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()
if _, err := Client.InviteMembers(invites); err == nil {
t.Fatal("should have errored not team admin and licensed")
@@ -571,6 +606,7 @@ 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")

View File

@@ -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 = c.App.ClientLicense()
il.LicenseCfg = utils.ClientLicense()
} else {
il.LicenseCfg = c.App.GetSanitizedClientLicense()
il.LicenseCfg = utils.GetSanitizedClientLicense()
}
w.Write([]byte(il.ToJson()))

View File

@@ -1889,7 +1889,17 @@ func TestUpdateMfa(t *testing.T) {
Client := th.BasicClient
th.App.SetLicense(nil)
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)
}
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, _ := Client.CreateTeam(&team)
@@ -1915,7 +1925,8 @@ func TestUpdateMfa(t *testing.T) {
t.Fatal("should have failed - not licensed")
}
th.App.SetLicense(model.NewTestLicense("mfa"))
utils.SetIsLicensed(true)
*utils.License().Features.MFA = true
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
if _, err := Client.UpdateMfa(true, "123456"); err == nil {

View File

@@ -9,6 +9,7 @@ import (
"testing"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
)
func TestCreateIncomingHook(t *testing.T) {
@@ -92,6 +93,7 @@ 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)
@@ -131,6 +133,7 @@ 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)
@@ -214,6 +217,7 @@ 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}
@@ -236,6 +240,7 @@ 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)
@@ -319,6 +324,7 @@ 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)
@@ -345,6 +351,7 @@ 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)
@@ -369,6 +376,7 @@ 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)
@@ -402,6 +410,7 @@ 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")
@@ -438,6 +447,7 @@ 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"}}
@@ -508,6 +518,7 @@ 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)
@@ -540,6 +551,7 @@ 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)
@@ -566,6 +578,7 @@ 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)
@@ -596,6 +609,7 @@ 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)
@@ -669,6 +683,7 @@ 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 {
@@ -676,6 +691,7 @@ 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)
@@ -763,6 +779,7 @@ 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)
@@ -796,6 +813,7 @@ 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")
@@ -830,6 +848,7 @@ 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)
@@ -864,6 +883,7 @@ 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)
@@ -897,6 +917,10 @@ 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}
@@ -938,8 +962,20 @@ 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.SetLicense(model.NewTestLicense())
th.App.SetDefaultRolesBasedOnConfig()
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
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")

View File

@@ -113,11 +113,7 @@ func setupTestHelper(enterprise bool) *TestHelper {
if testStore != nil {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
}
serverErr := th.App.StartServer()
if serverErr != nil {
panic(serverErr)
}
th.App.StartServer()
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)
@@ -125,10 +121,9 @@ func setupTestHelper(enterprise bool) *TestHelper {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = true })
utils.SetIsLicensed(enterprise)
if enterprise {
th.App.SetLicense(model.NewTestLicense())
} else {
th.App.SetLicense(nil)
utils.License().Features.SetDefaults()
}
th.Client = th.CreateClient()
@@ -303,7 +298,8 @@ func (me *TestHelper) CreateUserWithClient(client *model.Client4) *model.User {
}
utils.DisableDebugLogForTest()
ruser, _ := client.CreateUser(user)
ruser, r := client.CreateUser(user)
fmt.Println(r)
ruser.Password = "Password1"
store.Must(me.App.Srv.Store.User().VerifyEmail(ruser.Id))
utils.EnableDebugLogForTest()

View File

@@ -14,6 +14,7 @@ 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) {
@@ -81,9 +82,23 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
channel.Name = GenerateTestChannelName()
_, resp = Client.CreateChannel(channel)
@@ -95,8 +110,11 @@ 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)
@@ -124,8 +142,11 @@ 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()
@@ -152,7 +173,9 @@ func TestCreateChannel(t *testing.T) {
CheckNoError(t, resp)
// Check that if unlicensed the policy restriction is not enforced.
th.App.SetLicense(nil)
utils.SetIsLicensed(false)
utils.SetLicense(nil)
th.App.SetDefaultRolesBasedOnConfig()
channel.Name = GenerateTestChannelName()
_, resp = Client.CreateChannel(channel)
@@ -864,9 +887,23 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
Client = th.Client
team = th.BasicTeam
@@ -889,8 +926,11 @@ 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)
@@ -927,7 +967,9 @@ func TestDeleteChannel(t *testing.T) {
// successful delete by team admin
th.UpdateUserToTeamAdmin(user, team)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckNoError(t, resp)
@@ -937,11 +979,16 @@ 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()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
// channels created by SystemAdmin
publicChannel6 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN)
@@ -971,7 +1018,9 @@ func TestDeleteChannel(t *testing.T) {
// successful delete by team admin
th.UpdateUserToTeamAdmin(th.BasicUser, team)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckNoError(t, resp)
@@ -981,8 +1030,11 @@ 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)
@@ -1012,7 +1064,9 @@ func TestDeleteChannel(t *testing.T) {
// cannot delete by team admin
th.UpdateUserToTeamAdmin(th.BasicUser, team)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
_, resp = Client.DeleteChannel(publicChannel6.Id)
CheckForbiddenStatus(t, resp)
@@ -1769,9 +1823,16 @@ 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()
@@ -1785,8 +1846,18 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
// Check that a regular channel user can add other users.
Client.Login(user2.Username, user2.Password)
@@ -1804,6 +1875,10 @@ 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()
@@ -1818,7 +1893,10 @@ func TestAddChannelMember(t *testing.T) {
th.MakeUserChannelAdmin(user, privateChannel)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
Client.Login(user.Username, user.Password)
_, resp = Client.AddChannelMember(privateChannel.Id, user3.Id)
@@ -1829,6 +1907,10 @@ 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()
@@ -1843,7 +1925,10 @@ func TestAddChannelMember(t *testing.T) {
th.UpdateUserToTeamAdmin(user, team)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
Client.Login(user.Username, user.Password)
_, resp = Client.AddChannelMember(privateChannel.Id, user3.Id)
@@ -1854,6 +1939,10 @@ 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()
@@ -1930,9 +2019,16 @@ 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)
@@ -1944,8 +2040,18 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
// Check that a regular channel user can remove other users.
privateChannel = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE)
@@ -1961,6 +2067,10 @@ 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)
@@ -1973,7 +2083,9 @@ func TestRemoveChannelMember(t *testing.T) {
th.MakeUserChannelAdmin(user1, privateChannel)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
_, resp = Client.RemoveUserFromChannel(privateChannel.Id, user2.Id)
CheckNoError(t, resp)
@@ -1982,6 +2094,10 @@ 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)
@@ -1994,7 +2110,9 @@ func TestRemoveChannelMember(t *testing.T) {
th.UpdateUserToTeamAdmin(user1, team)
th.App.InvalidateAllCaches()
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
_, resp = Client.RemoveUserFromChannel(privateChannel.Id, user2.Id)
CheckNoError(t, resp)
@@ -2003,6 +2121,10 @@ 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)

View File

@@ -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)
utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
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)
utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey())
http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect)
return
}

View File

@@ -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.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
utils.RenderWebError(err, w, r)
return
}
@@ -326,13 +326,13 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
}
if err := authRequest.IsValid(); err != nil {
utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
utils.RenderWebError(err, w, r)
return
}
oauthApp, err := c.App.GetOAuthApp(authRequest.ClientId)
if err != nil {
utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
utils.RenderWebError(err, w, r)
return
}
@@ -343,8 +343,7 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
}
if !oauthApp.IsValidRedirectURL(authRequest.RedirectUri) {
err := model.NewAppError("authorizeOAuthPage", "api.oauth.allow_oauth.redirect_callback.app_error", nil, "", http.StatusBadRequest)
utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
utils.RenderWebError(model.NewAppError("authorizeOAuthPage", "api.oauth.allow_oauth.redirect_callback.app_error", nil, "", http.StatusBadRequest), w, r)
return
}
@@ -361,7 +360,7 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
redirectUrl, err := c.App.AllowOAuthAppAccessToUser(c.Session.UserId, authRequest)
if err != nil {
utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
utils.RenderWebError(err, w, r)
return
}
@@ -442,10 +441,7 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
if len(code) == 0 {
utils.RenderWebError(w, r, http.StatusTemporaryRedirect, url.Values{
"type": []string{"oauth_missing_code"},
"service": []string{strings.Title(service)},
}, c.App.AsymmetricSigningKey())
http.Redirect(w, r, c.GetSiteURLHeader()+"/error?type=oauth_missing_code&service="+strings.Title(service), http.StatusTemporaryRedirect)
return
}
@@ -466,7 +462,7 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
if action == model.OAUTH_ACTION_MOBILE {
w.Write([]byte(err.ToJson()))
} else {
utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+url.QueryEscape(err.Message), http.StatusTemporaryRedirect)
}
return
}
@@ -478,7 +474,7 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
if action == model.OAUTH_ACTION_MOBILE {
w.Write([]byte(err.ToJson()))
} else {
utils.RenderWebAppError(w, r, err, c.App.AsymmetricSigningKey())
http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+url.QueryEscape(err.Message), http.StatusTemporaryRedirect)
}
return
}
@@ -563,9 +559,7 @@ func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
}
if !c.App.Config().TeamSettings.EnableUserCreation {
utils.RenderWebError(w, r, http.StatusBadRequest, url.Values{
"message": []string{utils.T("api.oauth.singup_with_oauth.disabled.app_error")},
}, c.App.AsymmetricSigningKey())
http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+url.QueryEscape(utils.T("api.oauth.singup_with_oauth.disabled.app_error")), http.StatusTemporaryRedirect)
return
}

View File

@@ -18,7 +18,14 @@ 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}
@@ -35,10 +42,12 @@ 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)
@@ -77,7 +86,14 @@ 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",
@@ -156,6 +172,7 @@ 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)
@@ -182,8 +199,15 @@ 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"}}
@@ -227,6 +251,7 @@ 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)
@@ -247,8 +272,15 @@ 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"}}
@@ -288,6 +320,7 @@ 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)
@@ -314,8 +347,15 @@ 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"}}
@@ -355,6 +395,7 @@ 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)
@@ -381,8 +422,15 @@ 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"}}
@@ -417,6 +465,7 @@ 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)
@@ -441,8 +490,15 @@ 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"}}
@@ -481,6 +537,7 @@ 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)
@@ -565,7 +622,12 @@ 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"}}

View File

@@ -17,6 +17,7 @@ import (
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
)
func TestCreatePost(t *testing.T) {
@@ -129,8 +130,20 @@ 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"
})
@@ -476,8 +489,21 @@ func TestUpdatePost(t *testing.T) {
Client := th.Client
channel := th.BasicChannel
th.App.SetLicense(model.NewTestLicense())
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.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)
@@ -548,8 +574,21 @@ func TestPatchPost(t *testing.T) {
Client := th.Client
channel := th.BasicChannel
th.App.SetLicense(model.NewTestLicense())
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.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = model.ALLOW_EDIT_POST_ALWAYS })
th.App.SetDefaultRolesBasedOnConfig()
post := &model.Post{
ChannelId: channel.Id,

View File

@@ -266,7 +266,7 @@ func getClientLicense(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
etag := c.App.GetClientLicenseEtag(true)
etag := utils.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 = c.App.ClientLicense()
clientLicense = utils.ClientLicense()
} else {
clientLicense = c.App.GetSanitizedClientLicense()
clientLicense = utils.GetSanitizedClientLicense()
}
w.Header().Set(model.HEADER_ETAG_SERVER, etag)

View File

@@ -68,7 +68,13 @@ 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)
@@ -1286,8 +1292,20 @@ 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.
@@ -1295,7 +1313,10 @@ func TestAddTeamMember(t *testing.T) {
CheckNoError(t, resp)
// Add an EE license.
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
// Check that a regular user can't add someone to the team.
@@ -1306,7 +1327,10 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
// Should work as a team admin.
@@ -1315,6 +1339,7 @@ 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)
@@ -1328,13 +1353,21 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
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
@@ -1474,8 +1507,20 @@ 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.
@@ -1483,7 +1528,10 @@ func TestAddTeamMembers(t *testing.T) {
CheckNoError(t, resp)
// Add an EE license.
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
// Check that a regular user can't add someone to the team.
@@ -1494,7 +1542,10 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
// Should work as a team admin.
@@ -1503,6 +1554,7 @@ 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)
@@ -1516,7 +1568,10 @@ 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 })
th.App.SetLicense(model.NewTestLicense())
utils.SetIsLicensed(true)
utils.SetLicense(&model.License{Features: &model.Features{}})
utils.License().Features.SetDefaults()
th.App.SetDefaultRolesBasedOnConfig()
th.LoginBasic()
// Should work as a regular user.
@@ -1875,6 +1930,10 @@ 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)

View File

@@ -1566,7 +1566,18 @@ func TestUpdateUserMfa(t *testing.T) {
defer th.TearDown()
Client := th.Client
th.App.SetLicense(model.NewTestLicense("mfa"))
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.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
session, _ := th.App.GetSession(Client.AuthToken)
@@ -1601,7 +1612,18 @@ func TestCheckUserMfa(t *testing.T) {
t.Fatal("should be false - mfa not active")
}
th.App.SetLicense(model.NewTestLicense("mfa"))
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.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
th.LoginBasic()
@@ -1637,7 +1659,18 @@ func TestGenerateMfaSecret(t *testing.T) {
_, resp = Client.GenerateMfaSecret("junk")
CheckBadRequestStatus(t, resp)
th.App.SetLicense(model.NewTestLicense("mfa"))
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.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableMultifactorAuthentication = true })
_, resp = Client.GenerateMfaSecret(model.NewId())
@@ -2154,7 +2187,19 @@ func TestSwitchAccount(t *testing.T) {
t.Fatal("bad link")
}
th.App.SetLicense(model.NewTestLicense())
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.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ExperimentalEnableAuthenticationTransfer = false })
sr = &model.SwitchRequest{

View File

@@ -237,8 +237,7 @@ func (a *App) TestEmail(userId string, cfg *model.Config) *model.AppError {
return err
} else {
T := utils.GetUserTranslations(user.Locale)
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 {
if err := utils.SendMailUsingConfig(user.Email, T("api.admin.test_email.subject"), T("api.admin.test_email.body"), cfg); err != nil {
return err
}
}

View File

@@ -4,7 +4,6 @@
package app
import (
"crypto/ecdsa"
"html/template"
"net"
"net/http"
@@ -59,20 +58,15 @@ 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
asymmetricSigningKey *ecdsa.PrivateKey
htmlTemplateWatcher *utils.HTMLTemplateWatcher
sessionCache *utils.Cache
roles map[string]*model.Role
configListenerId string
licenseListenerId string
disableConfigWatch bool
configWatcher *utils.ConfigWatcher
pluginCommands []*PluginCommand
pluginCommandsLock sync.RWMutex
@@ -86,7 +80,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) (outApp *App, outErr error) {
func New(options ...Option) (*App, error) {
appCount++
if appCount > 1 {
panic("Only one App should exist at a time. Did you forget to call Shutdown()?")
@@ -97,17 +91,11 @@ func New(options ...Option) (outApp *App, outErr 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),
licenseListeners: map[string]func(){},
sessionCache: utils.NewLru(model.SESSION_CACHE_SIZE),
configFile: "config.json",
configListeners: make(map[string]func(*model.Config, *model.Config)),
clientConfig: make(map[string]string),
}
defer func() {
if outErr != nil {
app.Shutdown()
}
}()
for _, option := range options {
option(app)
@@ -130,9 +118,9 @@ func New(options ...Option) (outApp *App, outErr error) {
app.configListenerId = app.AddConfigListener(func(_, _ *model.Config) {
app.configOrLicenseListener()
})
app.licenseListenerId = app.AddLicenseListener(app.configOrLicenseListener)
app.licenseListenerId = utils.AddLicenseListener(app.configOrLicenseListener)
app.regenerateClientConfig()
app.setDefaultRolesBasedOnConfig()
app.SetDefaultRolesBasedOnConfig()
l4g.Info(utils.T("api.server.new_server.init.info"))
@@ -151,10 +139,6 @@ func New(options ...Option) (outApp *App, outErr 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()
@@ -173,7 +157,7 @@ func New(options ...Option) (outApp *App, outErr error) {
func (a *App) configOrLicenseListener() {
a.regenerateClientConfig()
a.setDefaultRolesBasedOnConfig()
a.SetDefaultRolesBasedOnConfig()
}
func (a *App) Shutdown() {
@@ -187,9 +171,7 @@ func (a *App) Shutdown() {
a.ShutDownPlugins()
a.WaitForGoroutines()
if a.Srv.Store != nil {
a.Srv.Store.Close()
}
a.Srv.Store.Close()
a.Srv = nil
if a.htmlTemplateWatcher != nil {
@@ -197,7 +179,7 @@ func (a *App) Shutdown() {
}
a.RemoveConfigListener(a.configListenerId)
a.RemoveLicenseListener(a.licenseListenerId)
utils.RemoveLicenseListener(a.licenseListenerId)
l4g.Info(utils.T("api.server.stop_server.stopped.info"))
a.DisableConfigWatch()
@@ -466,5 +448,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.RenderWebAppError(w, r, err, a.AsymmetricSigningKey())
utils.RenderWebError(err, w, r)
}

View File

@@ -51,8 +51,7 @@ func TestAppRace(t *testing.T) {
a, err := New()
require.NoError(t, err)
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
serverErr := a.StartServer()
require.NoError(t, serverErr)
a.StartServer()
a.Shutdown()
}
}

View File

@@ -96,20 +96,15 @@ func setupTestHelper(enterprise bool) *TestHelper {
if testStore != nil {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
}
serverErr := th.App.StartServer()
if serverErr != nil {
panic(serverErr)
}
th.App.StartServer()
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 {
th.App.SetLicense(model.NewTestLicense())
} else {
th.App.SetLicense(nil)
utils.License().Features.SetDefaults()
}
return th

View File

@@ -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, user *model.User) *model.AppError {
func (a *App) MoveChannel(team *model.Team, channel *model.Channel) *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,37 +1378,11 @@ func (a *App) MoveChannel(team *model.Team, channel *model.Channel, user *model.
}
}
// 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)
}
// Change the Team ID of the channel.
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
}

View File

@@ -97,7 +97,7 @@ func TestMoveChannel(t *testing.T) {
t.Fatal(err)
}
if err := th.App.MoveChannel(targetTeam, channel1, th.BasicUser); err == nil {
if err := th.App.MoveChannel(targetTeam, channel1); 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, th.BasicUser); err != nil {
if err := th.App.MoveChannel(targetTeam, channel1); err != nil {
t.Fatal(err)
}
}

View File

@@ -4,12 +4,7 @@
package app
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/md5"
"crypto/rand"
"crypto/x509"
"encoding/base64"
"encoding/json"
"fmt"
"runtime/debug"
@@ -121,91 +116,8 @@ 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.License())
if key := a.AsymmetricSigningKey(); key != nil {
der, _ := x509.MarshalPKIXPublicKey(&key.PublicKey)
a.clientConfig["AsymmetricSigningPublicKey"] = base64.StdEncoding.EncodeToString(der)
}
a.clientConfig = utils.GenerateClientConfig(a.Config(), a.DiagnosticId())
clientConfigJSON, _ := json.Marshal(a.clientConfig)
a.clientConfigHash = fmt.Sprintf("%x", md5.Sum(clientConfigJSON))
}
@@ -254,3 +166,11 @@ 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
}

View File

@@ -6,8 +6,6 @@ package app
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost-server/model"
)
@@ -56,10 +54,3 @@ 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"])
}

View File

@@ -501,7 +501,6 @@ 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,

View File

@@ -317,6 +317,5 @@ func (a *App) NewEmailTemplate(name, locale string) *utils.HTMLTemplate {
}
func (a *App) SendMail(to, subject, htmlBody string) *model.AppError {
license := a.License()
return utils.SendMailUsingConfig(to, subject, htmlBody, a.Config(), license != nil && *license.Features.Compliance)
return utils.SendMailUsingConfig(to, subject, htmlBody, a.Config())
}

View File

@@ -58,8 +58,7 @@ const (
)
func (a *App) FileBackend() (utils.FileBackend, *model.AppError) {
license := a.License()
return utils.NewFileBackend(&a.Config().FileSettings, license != nil && *license.Features.Compliance)
return utils.NewFileBackend(&a.Config().FileSettings)
}
func (a *App) ReadFile(path string) ([]byte, *model.AppError) {

View File

@@ -4,19 +4,16 @@
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() {
a.SetLicense(nil)
utils.RemoveLicense()
licenseId := ""
if result := <-a.Srv.Store.System().Get(); result.Err == nil {
@@ -39,7 +36,7 @@ func (a *App) LoadLicense() {
if result := <-a.Srv.Store.License().Get(licenseId); result.Err == nil {
record := result.Data.(*model.LicenseRecord)
a.ValidateAndSetLicenseBytes([]byte(record.Bytes))
utils.LoadLicense([]byte(record.Bytes))
l4g.Info("License key valid unlocking enterprise features.")
} else {
l4g.Info(utils.T("mattermost.load_license.find.warn"))
@@ -62,7 +59,7 @@ func (a *App) SaveLicense(licenseBytes []byte) (*model.License, *model.AppError)
}
}
if ok := a.SetLicense(license); !ok {
if ok := utils.SetLicense(license); !ok {
return nil, model.NewAppError("addLicense", model.EXPIRED_LICENSE_ERROR, nil, "", http.StatusBadRequest)
}
@@ -105,115 +102,21 @@ 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 {
if license, _ := a.licenseValue.Load().(*model.License); license == nil {
return nil
}
utils.RemoveLicense()
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
}

View File

@@ -4,9 +4,8 @@
package app
import (
//"github.com/mattermost/mattermost-server/model"
"testing"
"github.com/mattermost/mattermost-server/model"
)
func TestLoadLicense(t *testing.T) {
@@ -38,75 +37,3 @@ 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")
}
}

View File

@@ -565,7 +565,6 @@ 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,
}

View File

@@ -10,6 +10,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"regexp"
"strings"
@@ -732,23 +733,68 @@ func (a *App) GetFileInfosForPost(postId string, readFromMaster bool) ([]*model.
return infos, nil
}
func (a *App) GetOpenGraphMetadata(url string) *opengraph.OpenGraph {
func (a *App) GetOpenGraphMetadata(requestURL string) *opengraph.OpenGraph {
og := opengraph.NewOpenGraph()
res, err := a.HTTPClient(false).Get(url)
res, err := a.HTTPClient(false).Get(requestURL)
if err != nil {
l4g.Error("GetOpenGraphMetadata request failed for url=%v with err=%v", url, err.Error())
l4g.Error("GetOpenGraphMetadata request failed for url=%v with err=%v", requestURL, err.Error())
return og
}
defer consumeAndClose(res)
if err := og.ProcessHTML(res.Body); err != nil {
l4g.Error("GetOpenGraphMetadata processing failed for url=%v with err=%v", url, err.Error())
l4g.Error("GetOpenGraphMetadata processing failed for url=%v with err=%v", requestURL, err.Error())
}
makeOpenGraphURLsAbsolute(og, requestURL)
return og
}
func makeOpenGraphURLsAbsolute(og *opengraph.OpenGraph, requestURL string) {
parsedRequestURL, err := url.Parse(requestURL)
if err != nil {
l4g.Warn("makeOpenGraphURLsAbsolute failed to parse url=%v", requestURL)
return
}
makeURLAbsolute := func(resultURL string) string {
if resultURL == "" {
return resultURL
}
parsedResultURL, err := url.Parse(resultURL)
if err != nil {
l4g.Warn("makeOpenGraphURLsAbsolute failed to parse result url=%v", resultURL)
return resultURL
}
if parsedResultURL.IsAbs() {
return resultURL
}
return parsedRequestURL.ResolveReference(parsedResultURL).String()
}
og.URL = makeURLAbsolute(og.URL)
for _, image := range og.Images {
image.URL = makeURLAbsolute(image.URL)
image.SecureURL = makeURLAbsolute(image.SecureURL)
}
for _, audio := range og.Audios {
audio.URL = makeURLAbsolute(audio.URL)
audio.SecureURL = makeURLAbsolute(audio.SecureURL)
}
for _, video := range og.Videos {
video.URL = makeURLAbsolute(video.URL)
video.SecureURL = makeURLAbsolute(video.SecureURL)
}
}
func (a *App) DoPostAction(postId string, actionId string, userId string) *model.AppError {
pchan := a.Srv.Store.Post().GetSingle(postId)

View File

@@ -8,9 +8,11 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/dyatlov/go-opengraph/opengraph"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -254,3 +256,93 @@ func TestImageProxy(t *testing.T) {
})
}
}
func TestMakeOpenGraphURLsAbsolute(t *testing.T) {
for name, tc := range map[string]struct {
HTML string
RequestURL string
URL string
ImageURL string
}{
"absolute URLs": {
HTML: `
<html>
<head>
<meta property="og:url" content="https://example.com/apps/mattermost">
<meta property="og:image" content="https://images.example.com/image.png">
</head>
</html>`,
RequestURL: "https://example.com",
URL: "https://example.com/apps/mattermost",
ImageURL: "https://images.example.com/image.png",
},
"URLs starting with /": {
HTML: `
<html>
<head>
<meta property="og:url" content="/apps/mattermost">
<meta property="og:image" content="/image.png">
</head>
</html>`,
RequestURL: "http://example.com",
URL: "http://example.com/apps/mattermost",
ImageURL: "http://example.com/image.png",
},
"HTTPS URLs starting with /": {
HTML: `
<html>
<head>
<meta property="og:url" content="/apps/mattermost">
<meta property="og:image" content="/image.png">
</head>
</html>`,
RequestURL: "https://example.com",
URL: "https://example.com/apps/mattermost",
ImageURL: "https://example.com/image.png",
},
"missing image URL": {
HTML: `
<html>
<head>
<meta property="og:url" content="/apps/mattermost">
</head>
</html>`,
RequestURL: "http://example.com",
URL: "http://example.com/apps/mattermost",
ImageURL: "",
},
"relative URLs": {
HTML: `
<html>
<head>
<meta property="og:url" content="index.html">
<meta property="og:image" content="../resources/image.png">
</head>
</html>`,
RequestURL: "http://example.com/content/index.html",
URL: "http://example.com/content/index.html",
ImageURL: "http://example.com/resources/image.png",
},
} {
t.Run(name, func(t *testing.T) {
og := opengraph.NewOpenGraph()
if err := og.ProcessHTML(strings.NewReader(tc.HTML)); err != nil {
t.Fatal(err)
}
makeOpenGraphURLsAbsolute(og, tc.RequestURL)
if og.URL != tc.URL {
t.Fatalf("incorrect url, expected %v, got %v", tc.URL, og.URL)
}
if len(og.Images) > 0 {
if og.Images[0].URL != tc.ImageURL {
t.Fatalf("incorrect image url, expected %v, got %v", tc.ImageURL, og.Images[0].URL)
}
} else if tc.ImageURL != "" {
t.Fatalf("missing image url, expected %v, got nothing", tc.ImageURL)
}
})
}
}

View File

@@ -12,6 +12,8 @@ func (a *App) Role(id string) *model.Role {
return a.roles[id]
}
func (a *App) setDefaultRolesBasedOnConfig() {
a.roles = utils.DefaultRolesBasedOnConfig(a.Config(), a.License() != nil)
// 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())
}

View File

@@ -17,7 +17,6 @@ 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"
@@ -117,7 +116,7 @@ func redirectHTTPToHTTPS(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, url.String(), http.StatusFound)
}
func (a *App) StartServer() error {
func (a *App) StartServer() {
l4g.Info(utils.T("api.server.start_server.starting.info"))
var handler http.Handler = &CorsWrapper{a.Config, a.Srv.Router}
@@ -127,7 +126,8 @@ func (a *App) StartServer() error {
rateLimiter, err := NewRateLimiter(&a.Config().RateLimitSettings)
if err != nil {
return err
l4g.Critical(err.Error())
return
}
a.Srv.RateLimiter = rateLimiter
@@ -151,8 +151,8 @@ func (a *App) StartServer() error {
listener, err := net.Listen("tcp", addr)
if err != nil {
errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err)
return err
l4g.Critical(utils.T("api.server.start_server.starting.critical"), err)
return
}
a.Srv.ListenAddr = listener.Addr().(*net.TCPAddr)
@@ -214,8 +214,6 @@ func (a *App) StartServer() error {
}
close(a.Srv.didFinishListen)
}()
return nil
}
type tcpKeepAliveListener struct {

View File

@@ -1,50 +0,0 @@
// 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)
}

View File

@@ -6,10 +6,11 @@ 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) {
@@ -47,7 +48,18 @@ func TestGetSessionIdleTimeoutInMinutes(t *testing.T) {
session, _ = th.App.CreateSession(session)
th.App.SetLicense(model.NewTestLicense("compliance"))
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.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionIdleTimeoutInMinutes = 5 })
rsession, err := th.App.GetSession(session.Token)
@@ -110,7 +122,7 @@ func TestGetSessionIdleTimeoutInMinutes(t *testing.T) {
assert.Nil(t, err)
// Test regular session with license off, should not timeout
th.App.SetLicense(nil)
*utils.License().Features.Compliance = false
session = &model.Session{
UserId: model.NewId(),
@@ -124,7 +136,7 @@ func TestGetSessionIdleTimeoutInMinutes(t *testing.T) {
_, err = th.App.GetSession(session.Token)
assert.Nil(t, err)
th.App.SetLicense(model.NewTestLicense("compliance"))
*utils.License().Features.Compliance = true
// Test regular session with timeout set to 0, should not timeout
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionIdleTimeoutInMinutes = 0 })

View File

@@ -106,8 +106,6 @@ 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")
@@ -321,33 +319,26 @@ 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
}
originTeamID := channel.TeamId
if err := moveChannel(a, team, channel, user); err != nil {
if err := moveChannel(a, team, channel); err != nil {
CommandPrintErrorln("Unable to move channel '" + channel.Name + "' error: " + err.Error())
} else {
CommandPrettyPrintln("Moved channel '" + channel.Name + "' to " + team.Name + "(" + team.Id + ") from " + originTeamID + ".")
CommandPrettyPrintln("Moved channel '" + channel.Name + "'")
}
}
return nil
}
func moveChannel(a *app.App, team *model.Team, channel *model.Channel, user *model.User) *model.AppError {
func moveChannel(a *app.App, team *model.Team, channel *model.Channel) *model.AppError {
oldTeamId := channel.TeamId
if err := a.MoveChannel(team, channel, user); err != nil {
if err := a.MoveChannel(team, channel); err != nil {
return err
}

View File

@@ -44,33 +44,6 @@ 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()

View File

@@ -35,7 +35,7 @@ func jobserverCmdF(cmd *cobra.Command, args []string) {
defer l4g.Close()
defer a.Shutdown()
a.LoadLicense()
a.Jobs.LoadLicense()
// Run jobs
l4g.Info("Starting Mattermost job server")

View File

@@ -42,11 +42,10 @@ func runServerCmd(cmd *cobra.Command, args []string) error {
disableConfigWatch, _ := cmd.Flags().GetBool("disableconfigwatch")
interruptChan := make(chan os.Signal, 1)
return runServer(config, disableConfigWatch, interruptChan)
return runServer(config, disableConfigWatch)
}
func runServer(configFileLocation string, disableConfigWatch bool, interruptChan chan os.Signal) error {
func runServer(configFileLocation string, disableConfigWatch bool) error {
options := []app.Option{app.ConfigFile(configFileLocation)}
if disableConfigWatch {
options = append(options, app.DisableConfigWatch)
@@ -54,7 +53,7 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan
a, err := app.New(options...)
if err != nil {
l4g.Critical(err.Error())
l4g.Error(err.Error())
return err
}
defer a.Shutdown()
@@ -88,12 +87,7 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan
}
})
serverErr := a.StartServer()
if serverErr != nil {
l4g.Critical(serverErr.Error())
return serverErr
}
a.StartServer()
api4.Init(a, a.Srv.Router, false)
api3 := api.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)
@@ -166,8 +160,9 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan
// wait for kill signal before attempting to gracefully shutdown
// the running service
signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
<-interruptChan
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
<-c
if a.Cluster != nil {
a.Cluster.StopInterNodeCommunication()

View File

@@ -1,72 +0,0 @@
// 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)
}

View File

@@ -53,11 +53,7 @@ func webClientTestsCmdF(cmd *cobra.Command, args []string) error {
defer a.Shutdown()
utils.InitTranslations(a.Config().LocalizationSettings)
serverErr := a.StartServer()
if serverErr != nil {
return serverErr
}
a.StartServer()
api4.Init(a, a.Srv.Router, false)
api.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)
@@ -75,11 +71,7 @@ func serverForWebClientTestsCmdF(cmd *cobra.Command, args []string) error {
defer a.Shutdown()
utils.InitTranslations(a.Config().LocalizationSettings)
serverErr := a.StartServer()
if serverErr != nil {
return serverErr
}
a.StartServer()
api4.Init(a, a.Srv.Router, false)
api.Init(a, a.Srv.Router)
wsapi.Init(a, a.Srv.WebSocketRouter)

View File

@@ -131,6 +131,10 @@
"id": "api.admin.upload_brand_image.too_large.app_error",
"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"
@@ -3130,14 +3134,6 @@
"id": "app.channel.move_channel.members_do_not_match.error",
"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"
@@ -4862,14 +4858,6 @@
"id": "model.config.is_valid.message_export.batch_size.app_error",
"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."
@@ -7094,10 +7082,6 @@
"id": "utils.mail.new_client.auth.app_error",
"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"
@@ -7174,6 +7158,10 @@
"id": "web.create_dir.error",
"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"
@@ -7278,10 +7266,18 @@
"id": "web.parsing_templates.debug",
"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"

View File

@@ -11,9 +11,9 @@ import (
"github.com/mattermost/mattermost-server/model"
)
// Default polling interval for jobs termination.
// (Defining as `var` rather than `const` allows tests to lower the interval.)
var DEFAULT_WATCHER_POLLING_INTERVAL = 15000
const (
DEFAULT_WATCHER_POLLING_INTERVAL = 15000
)
type Watcher struct {
srv *JobServer

View File

@@ -4,9 +4,12 @@
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 {
@@ -47,6 +50,36 @@ 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()
}

39
jobs/server_test.go Normal file
View File

@@ -0,0 +1,39 @@
// 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()
}

View File

@@ -6,10 +6,7 @@ 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
}

View File

@@ -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.ToUnsanitizedJson()); err != nil {
if r, err := c.DoApiPost(c.GetPostsRoute(), post.ToJson()); 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.ToUnsanitizedJson()); err != nil {
if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToJson()); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)

View File

@@ -1,58 +0,0 @@
// 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)
}

View File

@@ -158,9 +158,6 @@ 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 {
@@ -1626,13 +1623,9 @@ 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() {
@@ -1640,10 +1633,6 @@ 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")
}
@@ -2181,16 +2170,6 @@ 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

View File

@@ -136,7 +136,7 @@ func TestMessageExportSettingsIsValidBatchSizeInvalid(t *testing.T) {
require.Error(t, mes.isValid(*fs))
}
func TestMessageExportSettingsIsValidExportFormatInvalid(t *testing.T) {
func TestMessageExportSettingsIsValid(t *testing.T) {
fs := &FileSettings{
DriverName: NewString("foo"), // bypass file location check
}
@@ -147,55 +147,6 @@ func TestMessageExportSettingsIsValidExportFormatInvalid(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))
}
@@ -208,7 +159,6 @@ 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) {

View File

@@ -173,25 +173,6 @@ 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)

View File

@@ -9,7 +9,6 @@ type MessageExport struct {
UserId *string
UserEmail *string
Username *string
PostId *string
PostCreateAt *int64

View File

@@ -28,7 +28,6 @@ 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"
@@ -122,13 +121,12 @@ type PostActionIntegrationResponse struct {
func (o *Post) ToJson() string {
copy := *o
copy.StripActionIntegrations()
b, _ := json.Marshal(&copy)
return string(b)
}
func (o *Post) ToUnsanitizedJson() string {
b, _ := json.Marshal(o)
return string(b)
b, err := json.Marshal(&copy)
if err != nil {
return ""
} else {
return string(b)
}
}
func PostFromJson(data io.Reader) *Post {
@@ -198,7 +196,6 @@ 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,

View File

@@ -6,16 +6,14 @@ 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_ASYMMETRIC_SIGNING_KEY = "AsymmetricSigningKey"
SYSTEM_DIAGNOSTIC_ID = "DiagnosticId"
SYSTEM_RAN_UNIT_TESTS = "RanUnitTests"
SYSTEM_LAST_SECURITY_TIME = "LastSecurityTime"
SYSTEM_ACTIVE_LICENSE_ID = "ActiveLicenseId"
SYSTEM_LAST_COMPLIANCE_TIME = "LastComplianceTime"
)
type System struct {
@@ -33,14 +31,3 @@ 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"`
}

View File

@@ -110,8 +110,7 @@ func (s SqlChannelMemberHistoryStore) getFromChannelMemberHistoryTable(startTime
query := `
SELECT
cmh.*,
u.Email,
u.Username
u.Email
FROM ChannelMemberHistory cmh
INNER JOIN Users u ON cmh.UserId = u.Id
WHERE cmh.ChannelId = :ChannelId
@@ -131,10 +130,9 @@ 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,
u.Username
ch.ChannelId,
ch.UserId,
u.email
FROM ChannelMembers AS ch
INNER JOIN Users AS u ON ch.UserId = u.id
WHERE ch.ChannelId = :ChannelId`
@@ -160,7 +158,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

View File

@@ -225,8 +225,7 @@ 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.Username
Users.Email AS UserEmail
FROM
Posts
LEFT OUTER JOIN Channels ON Posts.ChannelId = Channels.Id

View File

@@ -322,10 +322,7 @@ type etagPosts struct {
func (s SqlPostStore) InvalidateLastPostTimeCache(channelId string) {
lastPostTimeCache.Remove(channelId)
// Keys are "{channelid}{limit}" and caching only occurs on limits of 30 and 60
lastPostsCache.Remove(channelId + "30")
lastPostsCache.Remove(channelId + "60")
lastPostsCache.Remove(channelId)
}
func (s SqlPostStore) GetEtag(channelId string, allowFromCache bool) store.StoreChannel {
@@ -442,9 +439,8 @@ func (s SqlPostStore) GetPosts(channelId string, offset int, limit int, allowFro
return
}
// 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 allowFromCache && offset == 0 && limit == 60 {
if cacheItem, ok := lastPostsCache.Get(channelId); ok {
if s.metrics != nil {
s.metrics.IncrementMemCacheHitCounter("Last Posts Cache")
}
@@ -486,9 +482,8 @@ func (s SqlPostStore) GetPosts(channelId string, offset int, limit int, allowFro
list.MakeNonNil()
// 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)
if offset == 0 && limit == 60 {
lastPostsCache.AddWithExpiresInSecs(channelId, list, LAST_POSTS_CACHE_SEC)
}
result.Data = list

View File

@@ -15,7 +15,6 @@ 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"
@@ -65,7 +64,6 @@ 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.
@@ -349,10 +347,3 @@ 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)
//}
}

View File

@@ -35,7 +35,6 @@ 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)
@@ -58,7 +57,6 @@ 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)
@@ -84,7 +82,6 @@ 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)
@@ -111,7 +108,6 @@ 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)
@@ -121,7 +117,6 @@ 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)
@@ -134,7 +129,6 @@ 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)
@@ -144,7 +138,6 @@ 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)
@@ -167,7 +160,6 @@ 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)
@@ -200,7 +192,6 @@ 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)
@@ -210,7 +201,6 @@ 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)
@@ -220,7 +210,6 @@ 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)
@@ -230,7 +219,6 @@ 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)
@@ -240,7 +228,6 @@ 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)
@@ -250,7 +237,6 @@ 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)
}
@@ -269,14 +255,12 @@ 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)

View File

@@ -341,8 +341,7 @@ func testComplianceMessageExport(t *testing.T, ss store.Store) {
// and two users that are a part of that team
user1 := &model.User{
Email: model.NewId(),
Username: model.NewId(),
Email: model.NewId(),
}
user1 = store.Must(ss.User().Save(user1)).(*model.User)
store.Must(ss.Team().SaveMember(&model.TeamMember{
@@ -351,8 +350,7 @@ func testComplianceMessageExport(t *testing.T, ss store.Store) {
}, -1))
user2 := &model.User{
Email: model.NewId(),
Username: model.NewId(),
Email: model.NewId(),
}
user2 = store.Must(ss.User().Save(user2)).(*model.User)
store.Must(ss.Team().SaveMember(&model.TeamMember{
@@ -417,7 +415,6 @@ 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)
@@ -427,7 +424,6 @@ 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)
@@ -436,5 +432,4 @@ 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)
}

View File

@@ -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("GetPostsWithDetails", func(t *testing.T) { testPostStoreGetPostsWithDetails(t, ss) })
t.Run("GetPostsWtihDetails", func(t *testing.T) { testPostStoreGetPostsWtihDetails(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 testPostStoreGetPostsWithDetails(t *testing.T, ss store.Store) {
func testPostStoreGetPostsWtihDetails(t *testing.T, ss store.Store) {
o1 := &model.Post{}
o1.ChannelId = model.NewId()
o1.UserId = model.NewId()
@@ -591,25 +591,6 @@ func testPostStoreGetPostsWithDetails(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) {

View File

@@ -1,91 +0,0 @@
{{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}}

View File

@@ -1,8 +0,0 @@
{{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}}

View File

@@ -1,10 +0,0 @@
{{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}}

View File

@@ -4,9 +4,6 @@
package utils
import (
"crypto"
"crypto/rand"
"encoding/base64"
"fmt"
"html/template"
"net/http"
@@ -35,25 +32,13 @@ func OriginChecker(allowedOrigins string) func(*http.Request) bool {
}
}
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
func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) {
status := http.StatusTemporaryRedirect
if err.StatusCode != http.StatusInternalServerError {
status = err.StatusCode
}
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

View File

@@ -1,49 +0,0 @@
// 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))
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/mattermost/mattermost-server/model"
)
func DefaultRolesBasedOnConfig(cfg *model.Config, isLicensed bool) map[string]*model.Role {
func DefaultRolesBasedOnConfig(cfg *model.Config) 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, isLicensed bool) map[string]*m
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, isLicensed bool) map[string]*m
)
}
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, isLicensed bool) map[string]*m
)
}
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, isLicensed bool) map[string]*m
)
}
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, isLicensed bool) map[string]*m
)
}
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, isLicensed bool) map[string]*m
)
}
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, isLicensed bool) map[string]*m
}
// 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, isLicensed bool) map[string]*m
}
// 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, isLicensed bool) map[string]*m
)
}
if isLicensed {
if IsLicensed() {
switch *cfg.ServiceSettings.RestrictPostDelete {
case model.PERMISSIONS_DELETE_POST_ALL:
roles[model.CHANNEL_USER_ROLE_ID].Permissions = append(

View File

@@ -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, license *model.License) map[string]string {
func GenerateClientConfig(c *model.Config, diagnosticId string) map[string]string {
props := make(map[string]string)
props["Version"] = model.CurrentVersion
@@ -459,17 +459,18 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
hasImageProxy := c.ServiceSettings.ImageProxyType != nil && *c.ServiceSettings.ImageProxyType != "" && c.ServiceSettings.ImageProxyURL != nil && *c.ServiceSettings.ImageProxyURL != ""
props["HasImageProxy"] = strconv.FormatBool(hasImageProxy)
if license != nil {
if IsLicensed() {
License := License()
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 != "")
@@ -480,16 +481,16 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
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 != "")
@@ -500,23 +501,23 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
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)
@@ -524,7 +525,7 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
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
@@ -532,14 +533,14 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
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)

View File

@@ -197,7 +197,7 @@ func TestGetClientConfig(t *testing.T) {
cfg, _, err := LoadConfig("config.json")
require.Nil(t, err)
configMap := GenerateClientConfig(cfg, "", nil)
configMap := GenerateClientConfig(cfg, "")
if configMap["EmailNotificationContentsType"] != *cfg.EmailSettings.EmailNotificationContentsType {
t.Fatal("EmailSettings.EmailNotificationContentsType not exposed to client config")
}

View File

@@ -22,7 +22,7 @@ type FileBackend interface {
RemoveDirectory(path string) *model.AppError
}
func NewFileBackend(settings *model.FileSettings, enableComplianceFeatures bool) (FileBackend, *model.AppError) {
func NewFileBackend(settings *model.FileSettings) (FileBackend, *model.AppError) {
switch *settings.DriverName {
case model.IMAGE_DRIVER_S3:
return &S3FileBackend{
@@ -33,7 +33,7 @@ func NewFileBackend(settings *model.FileSettings, enableComplianceFeatures bool)
signV2: settings.AmazonS3SignV2 != nil && *settings.AmazonS3SignV2,
region: settings.AmazonS3Region,
bucket: settings.AmazonS3Bucket,
encrypt: settings.AmazonS3SSE != nil && *settings.AmazonS3SSE && enableComplianceFeatures,
encrypt: settings.AmazonS3SSE != nil && *settings.AmazonS3SSE && IsLicensed() && *License().Features.Compliance,
trace: settings.AmazonS3Trace != nil && *settings.AmazonS3Trace,
}, nil
case model.IMAGE_DRIVER_LOCAL:

View File

@@ -63,7 +63,7 @@ func TestS3FileBackendTestSuite(t *testing.T) {
func (s *FileBackendTestSuite) SetupTest() {
TranslationsPreInit()
backend, err := NewFileBackend(&s.settings, true)
backend, err := NewFileBackend(&s.settings)
require.Nil(s.T(), err)
s.backend = backend
}

View File

@@ -23,7 +23,7 @@ type HTMLTemplateWatcher struct {
func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
templatesDir, _ := FindDir(directory)
l4g.Debug("Parsing server templates at %v", templatesDir)
l4g.Debug(T("api.api.init.parsing_templates.debug"), 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("Re-parsing templates because of modified file %v", event.Name)
l4g.Info(T("web.reparse_templates.info"), event.Name)
if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil {
l4g.Error("Failed to parse templates %v", err)
l4g.Error(T("web.parsing_templates.error"), err)
} else {
ret.templates.Store(htmlTemplates)
}
}
case err := <-watcher.Errors:
l4g.Error("Failed in directory watcher %s", err)
l4g.Error(T("web.dir_fail.error"), err)
}
}
}()

View File

@@ -4,7 +4,6 @@
package utils
import (
"bytes"
"encoding/json"
"fmt"
"io"
@@ -38,12 +37,6 @@ 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 {
@@ -96,54 +89,21 @@ func GetMessageFromMailbox(email, id string) (results JSONMessageInbucket, err e
var record JSONMessageInbucket
url := fmt.Sprintf("%s%s%s/%s", getInbucketHost(), INBUCKET_API, parsedEmail, id)
emailResponse, err := get(url)
req, err := http.NewRequest("GET", url, nil)
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)
}
}
}
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 nil, err
return record, err
}
defer resp.Body.Close()
return resp, nil
err = json.NewDecoder(resp.Body).Decode(&record)
return record, err
}
func DeleteMailBox(email string) (err error) {

View File

@@ -5,21 +5,28 @@ 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
@@ -30,6 +37,92 @@ 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)))
@@ -120,12 +213,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(l != nil)
props["IsLicensed"] = strconv.FormatBool(IsLicensed())
if l != nil {
if IsLicensed() {
props["Id"] = l.Id
props["Users"] = strconv.Itoa(*l.Features.Users)
props["LDAP"] = strconv.FormatBool(*l.Features.LDAP)
@@ -155,3 +248,39 @@ 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
}

View File

@@ -5,20 +5,87 @@ 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 {

View File

@@ -15,8 +15,6 @@ import (
"net/http"
"io"
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/html2text"
"github.com/mattermost/mattermost-server/model"
@@ -105,73 +103,37 @@ func TestConnection(config *model.Config) {
defer c.Close()
}
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 {
func SendMailUsingConfig(to, subject, htmlBody string, config *model.Config) *model.AppError {
if !config.EmailSettings.SendEmailNotifications || len(config.EmailSettings.SMTPServer) == 0 {
return nil
}
l4g.Debug(T("utils.mail.send_mail.sending.debug"), mimeTo, subject)
l4g.Debug(T("utils.mail.send_mail.sending.debug"), to, 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 = ""
}
headers := map[string][]string{
"From": {from.String()},
"To": {mimeTo},
m := gomail.NewMessage(gomail.SetCharset("UTF-8"))
m.SetHeaders(map[string][]string{
"From": {fromMail.String()},
"To": {to},
"Subject": {encodeRFC2047Word(subject)},
"Content-Transfer-Encoding": {"8bit"},
"Auto-Submitted": {"auto-generated"},
"Precedence": {"bulk"},
}
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
@@ -185,11 +147,11 @@ func sendMail(mimeTo, smtpTo string, from mail.Address, subject, htmlBody string
defer c.Quit()
defer c.Close()
if err := c.Mail(from.Address); err != nil {
if err := c.Mail(fromMail.Address); err != nil {
return model.NewAppError("SendMail", "utils.mail.send_mail.from_address.app_error", nil, err.Error(), http.StatusInternalServerError)
}
if err := c.Rcpt(smtpTo); err != nil {
if err := c.Rcpt(to); err != nil {
return model.NewAppError("SendMail", "utils.mail.send_mail.to_address.app_error", nil, err.Error(), http.StatusInternalServerError)
}

View File

@@ -7,10 +7,6 @@ import (
"strings"
"testing"
"net/mail"
"github.com/mattermost/mattermost-server/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -43,18 +39,18 @@ func TestSendMailUsingConfig(t *testing.T) {
require.Nil(t, err)
T = GetUserTranslations("en")
var emailTo = "test@example.com"
var emailSubject = "Testing this email"
var emailBody = "This is a test from autobot"
var emailTo string = "test@example.com"
var emailSubject string = "Testing this email"
var emailBody string = "This is a test from autobot"
//Delete all the messages before check the sample email
DeleteMailBox(emailTo)
if err := SendMailUsingConfig(emailTo, emailSubject, emailBody, cfg, true); err != nil {
if err := SendMailUsingConfig(emailTo, emailSubject, emailBody, cfg); 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
//Check if the email was send to the rigth email address
var resultsMailbox JSONMessageHeaderInbucket
err := RetryInbucket(5, func() error {
var err error
@@ -79,78 +75,3 @@ 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)
}
}
}
}
}

View File

@@ -94,7 +94,7 @@ func root(c *api.Context, w http.ResponseWriter, r *http.Request) {
}
if api.IsApiCall(r) {
api.Handle404(c.App, w, r)
api.Handle404(w, r)
return
}

View File

@@ -44,10 +44,7 @@ func Setup() *app.App {
}
prevListenAddress := *a.Config().ServiceSettings.ListenAddress
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
serverErr := a.StartServer()
if serverErr != nil {
panic(serverErr)
}
a.StartServer()
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress })
api4.Init(a, a.Srv.Router, false)
api3 := api.Init(a, a.Srv.Router)