From e88fe4bb1dea4918284ee3c6e5aee5a8497ff2b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Tue, 29 May 2018 16:58:12 +0200 Subject: MM-8853: Adding MANAGE_EMOJIS and MANAGE_OTHERS_EMOJIS permissions (#8860) * MM-8853: Adding MANAGE_EMOJIS and MANAGE_OTHERS_EMOJIS permissions * MM-8853: Removing unnecesary emoji enterprise feature * Create emojis migration * Adding MANAGE_EMOJIS and MANAGE_OTHERS_EMOJIS always to system admins * Simplifing permissions checks * Revert "Simplifing permissions checks" This reverts commit e2cafc1905fc9e20125dd9a1552d2d0c7340ae59. --- api4/apitestlib.go | 1 + api4/emoji.go | 66 ++++++++++++++++--- api4/emoji_test.go | 124 +++++++++++++++++++++++++++++++++- api4/role.go | 1 + app/app.go | 83 ++++++++++++++++++++--- app/app_test.go | 135 ++++++++++++++++++++++++++++++++++++++ app/apptestlib.go | 13 ++++ app/permissions.go | 1 + cmd/mattermost/commands/init.go | 1 + cmd/mattermost/commands/server.go | 1 + einterfaces/emoji.go | 12 ---- i18n/en.json | 4 -- migrations/migrationstestlib.go | 1 + model/permission.go | 16 +++++ store/sqlstore/upgrade.go | 4 ++ web/web_test.go | 1 + 16 files changed, 427 insertions(+), 37 deletions(-) delete mode 100644 einterfaces/emoji.go diff --git a/api4/apitestlib.go b/api4/apitestlib.go index 952c21df3..22084a1d6 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -125,6 +125,7 @@ func setupTestHelper(enterprise bool) *TestHelper { wsapi.Init(th.App, th.App.Srv.WebSocketRouter) th.App.Srv.Store.MarkSystemRanUnitTests() th.App.DoAdvancedPermissionsMigration() + th.App.DoEmojisPermissionsMigration() th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableOpenServer = true }) diff --git a/api4/emoji.go b/api4/emoji.go index cfb5dd6ab..42f66a22a 100644 --- a/api4/emoji.go +++ b/api4/emoji.go @@ -33,12 +33,6 @@ func createEmoji(c *Context, w http.ResponseWriter, r *http.Request) { return } - if emojiInterface := c.App.Emoji; emojiInterface != nil && - !emojiInterface.CanUserCreateEmoji(c.Session.Roles, c.Session.TeamMembers) { - c.Err = model.NewAppError("getEmoji", "api.emoji.disabled.app_error", nil, "user_id="+c.Session.UserId, http.StatusUnauthorized) - return - } - if len(*c.App.Config().FileSettings.DriverName) == 0 { c.Err = model.NewAppError("createEmoji", "api.emoji.storage.app_error", nil, "", http.StatusNotImplemented) return @@ -54,6 +48,28 @@ func createEmoji(c *Context, w http.ResponseWriter, r *http.Request) { return } + // Allow any user with MANAGE_EMOJIS permission at Team level to manage emojis at system level + memberships, err := c.App.GetTeamMembersForUser(c.Session.UserId) + + if err != nil { + c.Err = err + return + } + + if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_EMOJIS) { + hasPermission := false + for _, membership := range memberships { + if c.App.SessionHasPermissionToTeam(c.Session, membership.TeamId, model.PERMISSION_MANAGE_EMOJIS) { + hasPermission = true + break + } + } + if !hasPermission { + c.SetPermissionError(model.PERMISSION_MANAGE_EMOJIS) + return + } + } + m := r.MultipartForm props := m.Value @@ -110,11 +126,45 @@ func deleteEmoji(c *Context, w http.ResponseWriter, r *http.Request) { return } - if c.Session.UserId != emoji.CreatorId && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { - c.Err = model.NewAppError("deleteImage", "api.emoji.delete.permissions.app_error", nil, "user_id="+c.Session.UserId, http.StatusUnauthorized) + // Allow any user with MANAGE_EMOJIS permission at Team level to manage emojis at system level + memberships, err := c.App.GetTeamMembersForUser(c.Session.UserId) + + if err != nil { + c.Err = err return } + if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_EMOJIS) { + hasPermission := false + for _, membership := range memberships { + if c.App.SessionHasPermissionToTeam(c.Session, membership.TeamId, model.PERMISSION_MANAGE_EMOJIS) { + hasPermission = true + break + } + } + if !hasPermission { + c.SetPermissionError(model.PERMISSION_MANAGE_EMOJIS) + return + } + } + + if c.Session.UserId != emoji.CreatorId { + if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_OTHERS_EMOJIS) { + hasPermission := false + for _, membership := range memberships { + if c.App.SessionHasPermissionToTeam(c.Session, membership.TeamId, model.PERMISSION_MANAGE_OTHERS_EMOJIS) { + hasPermission = true + break + } + } + + if !hasPermission { + c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_EMOJIS) + return + } + } + } + err = c.App.DeleteEmoji(emoji) if err != nil { c.Err = err diff --git a/api4/emoji_test.go b/api4/emoji_test.go index 39da4aaef..cb6398312 100644 --- a/api4/emoji_test.go +++ b/api4/emoji_test.go @@ -26,6 +26,11 @@ func TestCreateEmoji(t *testing.T) { }() th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = false }) + defaultRolePermissions := th.SaveDefaultRolePermissions() + defer func() { + th.RestoreDefaultRolePermissions(defaultRolePermissions) + }() + emoji := &model.Emoji{ CreatorId: th.BasicUser.Id, Name: model.NewId(), @@ -141,6 +146,28 @@ func TestCreateEmoji(t *testing.T) { _, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") CheckForbiddenStatus(t, resp) + + // try to create an emoji without permissions + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + + emoji = &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + + _, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") + CheckForbiddenStatus(t, resp) + + // create an emoji with permissions in one team + th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.TEAM_USER_ROLE_ID) + + emoji = &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + + _, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") + CheckNoError(t, resp) } func TestGetEmojiList(t *testing.T) { @@ -186,7 +213,7 @@ func TestGetEmojiList(t *testing.T) { } } if !found { - t.Fatalf("failed to get emoji with id %v", emoji.Id) + t.Fatalf("failed to get emoji with id %v, %v", emoji.Id, len(listEmoji)) } } @@ -231,6 +258,11 @@ func TestDeleteEmoji(t *testing.T) { }() th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = true }) + defaultRolePermissions := th.SaveDefaultRolePermissions() + defer func() { + th.RestoreDefaultRolePermissions(defaultRolePermissions) + }() + emoji := &model.Emoji{ CreatorId: th.BasicUser.Id, Name: model.NewId(), @@ -277,14 +309,100 @@ func TestDeleteEmoji(t *testing.T) { _, resp = Client.DeleteEmoji("") CheckNotFoundStatus(t, resp) - //Try to delete other user's custom emoji + //Try to delete my custom emoji without permissions + newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") + CheckNoError(t, resp) + + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + _, resp = Client.DeleteEmoji(newEmoji.Id) + CheckForbiddenStatus(t, resp) + th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + + //Try to delete other user's custom emoji without MANAGE_EMOJIS permissions + emoji = &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") CheckNoError(t, resp) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) Client.Logout() th.LoginBasic2() ok, resp = Client.DeleteEmoji(newEmoji.Id) - CheckUnauthorizedStatus(t, resp) + CheckForbiddenStatus(t, resp) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + Client.Logout() + th.LoginBasic() + + //Try to delete other user's custom emoji without MANAGE_OTHERS_EMOJIS permissions + emoji = &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + + newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") + CheckNoError(t, resp) + + Client.Logout() + th.LoginBasic2() + ok, resp = Client.DeleteEmoji(newEmoji.Id) + CheckForbiddenStatus(t, resp) + Client.Logout() + th.LoginBasic() + + //Try to delete other user's custom emoji with permissions + emoji = &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + + newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") + CheckNoError(t, resp) + + th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + Client.Logout() + th.LoginBasic2() + ok, resp = Client.DeleteEmoji(newEmoji.Id) + CheckNoError(t, resp) + + Client.Logout() + th.LoginBasic() + + //Try to delete my custom emoji with permissions at team level + newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") + CheckNoError(t, resp) + + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.TEAM_USER_ROLE_ID) + _, resp = Client.DeleteEmoji(newEmoji.Id) + CheckNoError(t, resp) + th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.TEAM_USER_ROLE_ID) + + //Try to delete other user's custom emoji with permissions at team level + emoji = &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + + newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif") + CheckNoError(t, resp) + + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + + th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, model.TEAM_USER_ROLE_ID) + + Client.Logout() + th.LoginBasic2() + ok, resp = Client.DeleteEmoji(newEmoji.Id) + CheckNoError(t, resp) } func TestGetEmoji(t *testing.T) { diff --git a/api4/role.go b/api4/role.go index c4203137b..2c0465891 100644 --- a/api4/role.go +++ b/api4/role.go @@ -100,6 +100,7 @@ func patchRole(c *Context, w http.ResponseWriter, r *http.Request) { model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, model.PERMISSION_MANAGE_OAUTH.Id, model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id, + model.PERMISSION_MANAGE_EMOJIS.Id, } changedPermissions := model.PermissionsChangedByPatch(oldRole, patch) diff --git a/app/app.go b/app/app.go index e5a496c6b..bda56ca1a 100644 --- a/app/app.go +++ b/app/app.go @@ -30,6 +30,7 @@ import ( ) const ADVANCED_PERMISSIONS_MIGRATION_KEY = "AdvancedPermissionsMigrationComplete" +const EMOJIS_PERMISSIONS_MIGRATION_KEY = "EmojisPermissionsMigrationComplete" type App struct { goroutineCount int32 @@ -57,7 +58,6 @@ type App struct { Compliance einterfaces.ComplianceInterface DataRetention einterfaces.DataRetentionInterface Elasticsearch einterfaces.ElasticsearchInterface - Emoji einterfaces.EmojiInterface Ldap einterfaces.LdapInterface MessageExport einterfaces.MessageExportInterface Metrics einterfaces.MetricsInterface @@ -288,12 +288,6 @@ func RegisterElasticsearchInterface(f func(*App) einterfaces.ElasticsearchInterf elasticsearchInterface = f } -var emojiInterface func(*App) einterfaces.EmojiInterface - -func RegisterEmojiInterface(f func(*App) einterfaces.EmojiInterface) { - emojiInterface = f -} - var jobsDataRetentionJobInterface func(*App) ejobs.DataRetentionJobInterface func RegisterJobsDataRetentionJobInterface(f func(*App) ejobs.DataRetentionJobInterface) { @@ -376,9 +370,6 @@ func (a *App) initEnterprise() { if elasticsearchInterface != nil { a.Elasticsearch = elasticsearchInterface(a) } - if emojiInterface != nil { - a.Emoji = emojiInterface(a) - } if ldapInterface != nil { a.Ldap = ldapInterface(a) a.AddConfigListener(func(_, cfg *model.Config) { @@ -603,3 +594,75 @@ func (a *App) SetPhase2PermissionsMigrationStatus(isComplete bool) error { a.phase2PermissionsMigrationComplete = isComplete return nil } + +func (a *App) DoEmojisPermissionsMigration() { + // If the migration is already marked as completed, don't do it again. + if result := <-a.Srv.Store.System().GetByName(EMOJIS_PERMISSIONS_MIGRATION_KEY); result.Err == nil { + return + } + + var role *model.Role = nil + var systemAdminRole *model.Role = nil + var err *model.AppError = nil + + mlog.Info("Migrating emojis config to database.") + switch *a.Config().ServiceSettings.RestrictCustomEmojiCreation { + case model.RESTRICT_EMOJI_CREATION_ALL: + role, err = a.GetRoleByName(model.SYSTEM_USER_ROLE_ID) + if err != nil { + mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") + mlog.Critical(err.Error()) + return + } + break + case model.RESTRICT_EMOJI_CREATION_ADMIN: + role, err = a.GetRoleByName(model.TEAM_ADMIN_ROLE_ID) + if err != nil { + mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") + mlog.Critical(err.Error()) + return + } + break + case model.RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN: + role = nil + break + default: + mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") + mlog.Critical("Invalid restrict emoji creation setting") + return + } + + if role != nil { + role.Permissions = append(role.Permissions, model.PERMISSION_MANAGE_EMOJIS.Id) + if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { + mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") + mlog.Critical(result.Err.Error()) + return + } + } + + systemAdminRole, err = a.GetRoleByName(model.SYSTEM_ADMIN_ROLE_ID) + if err != nil { + mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") + mlog.Critical(err.Error()) + return + } + + systemAdminRole.Permissions = append(systemAdminRole.Permissions, model.PERMISSION_MANAGE_EMOJIS.Id) + systemAdminRole.Permissions = append(systemAdminRole.Permissions, model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id) + if result := <-a.Srv.Store.Role().Save(systemAdminRole); result.Err != nil { + mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") + mlog.Critical(result.Err.Error()) + return + } + + system := model.System{ + Name: EMOJIS_PERMISSIONS_MIGRATION_KEY, + Value: "true", + } + + if result := <-a.Srv.Store.System().Save(&system); result.Err != nil { + mlog.Critical("Failed to mark emojis permissions migration as completed.") + mlog.Critical(fmt.Sprint(result.Err)) + } +} diff --git a/app/app_test.go b/app/app_test.go index cb6917073..dd6f0b593 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -455,3 +455,138 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { *config.ServiceSettings.PostEditTimeLimit = 300 th.App.SaveConfig(config, false) } + +func TestDoEmojisPermissionsMigration(t *testing.T) { + th := Setup() + defer th.TearDown() + + if testStoreSqlSupplier == nil { + t.Skip("This test requires a TestStore to be run.") + } + + // Add a license and change the policy config. + restrictCustomEmojiCreation := *th.App.Config().ServiceSettings.RestrictCustomEmojiCreation + + defer func() { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ServiceSettings.RestrictCustomEmojiCreation = restrictCustomEmojiCreation + }) + }() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ServiceSettings.RestrictCustomEmojiCreation = model.RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN + }) + + th.ResetEmojisMigration() + th.App.DoEmojisPermissionsMigration() + + expectedSystemAdmin := []string{ + model.PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id, + model.PERMISSION_MANAGE_SYSTEM.Id, + model.PERMISSION_MANAGE_ROLES.Id, + model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, + model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, + model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, + model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, + model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, + model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, + model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, + model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, + model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id, + model.PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id, + model.PERMISSION_EDIT_OTHER_USERS.Id, + model.PERMISSION_MANAGE_OAUTH.Id, + model.PERMISSION_INVITE_USER.Id, + model.PERMISSION_DELETE_POST.Id, + model.PERMISSION_DELETE_OTHERS_POSTS.Id, + model.PERMISSION_CREATE_TEAM.Id, + model.PERMISSION_ADD_USER_TO_TEAM.Id, + model.PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, + model.PERMISSION_MANAGE_JOBS.Id, + model.PERMISSION_CREATE_POST_PUBLIC.Id, + model.PERMISSION_CREATE_POST_EPHEMERAL.Id, + model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, + model.PERMISSION_READ_USER_ACCESS_TOKEN.Id, + model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, + model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id, + model.PERMISSION_LIST_TEAM_CHANNELS.Id, + model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id, + model.PERMISSION_READ_PUBLIC_CHANNEL.Id, + model.PERMISSION_VIEW_TEAM.Id, + model.PERMISSION_READ_CHANNEL.Id, + model.PERMISSION_ADD_REACTION.Id, + model.PERMISSION_REMOVE_REACTION.Id, + model.PERMISSION_UPLOAD_FILE.Id, + model.PERMISSION_GET_PUBLIC_LINK.Id, + model.PERMISSION_CREATE_POST.Id, + model.PERMISSION_USE_SLASH_COMMANDS.Id, + model.PERMISSION_EDIT_OTHERS_POSTS.Id, + model.PERMISSION_REMOVE_USER_FROM_TEAM.Id, + model.PERMISSION_MANAGE_TEAM.Id, + model.PERMISSION_IMPORT_TEAM.Id, + model.PERMISSION_MANAGE_TEAM_ROLES.Id, + model.PERMISSION_MANAGE_CHANNEL_ROLES.Id, + model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, + model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, + model.PERMISSION_MANAGE_WEBHOOKS.Id, + model.PERMISSION_EDIT_POST.Id, + model.PERMISSION_MANAGE_EMOJIS.Id, + model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, + } + + role1, err1 := th.App.GetRoleByName(model.SYSTEM_ADMIN_ROLE_ID) + assert.Nil(t, err1) + assert.Equal(t, expectedSystemAdmin, role1.Permissions, fmt.Sprintf("'%v' did not have expected permissions", model.SYSTEM_ADMIN_ROLE_ID)) + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ServiceSettings.RestrictCustomEmojiCreation = model.RESTRICT_EMOJI_CREATION_ADMIN + }) + + th.ResetEmojisMigration() + th.App.DoEmojisPermissionsMigration() + + role2, err2 := th.App.GetRoleByName(model.TEAM_ADMIN_ROLE_ID) + assert.Nil(t, err2) + expected2 := []string{ + model.PERMISSION_EDIT_OTHERS_POSTS.Id, + model.PERMISSION_REMOVE_USER_FROM_TEAM.Id, + model.PERMISSION_MANAGE_TEAM.Id, + model.PERMISSION_IMPORT_TEAM.Id, + model.PERMISSION_MANAGE_TEAM_ROLES.Id, + model.PERMISSION_MANAGE_CHANNEL_ROLES.Id, + model.PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id, + model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, + model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, + model.PERMISSION_MANAGE_WEBHOOKS.Id, + model.PERMISSION_DELETE_POST.Id, + model.PERMISSION_DELETE_OTHERS_POSTS.Id, + model.PERMISSION_MANAGE_EMOJIS.Id, + } + assert.Equal(t, expected2, role2.Permissions, fmt.Sprintf("'%v' did not have expected permissions", model.TEAM_ADMIN_ROLE_ID)) + + systemAdmin1, systemAdminErr1 := th.App.GetRoleByName(model.SYSTEM_ADMIN_ROLE_ID) + assert.Nil(t, systemAdminErr1) + assert.Equal(t, expectedSystemAdmin, systemAdmin1.Permissions, fmt.Sprintf("'%v' did not have expected permissions", model.SYSTEM_ADMIN_ROLE_ID)) + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ServiceSettings.RestrictCustomEmojiCreation = model.RESTRICT_EMOJI_CREATION_ALL + }) + + th.ResetEmojisMigration() + th.App.DoEmojisPermissionsMigration() + + role3, err3 := th.App.GetRoleByName(model.SYSTEM_USER_ROLE_ID) + assert.Nil(t, err3) + expected3 := []string{ + model.PERMISSION_CREATE_DIRECT_CHANNEL.Id, + model.PERMISSION_CREATE_GROUP_CHANNEL.Id, + model.PERMISSION_PERMANENT_DELETE_USER.Id, + model.PERMISSION_CREATE_TEAM.Id, + model.PERMISSION_MANAGE_EMOJIS.Id, + } + assert.Equal(t, expected3, role3.Permissions, fmt.Sprintf("'%v' did not have expected permissions", model.SYSTEM_USER_ROLE_ID)) + + systemAdmin2, systemAdminErr2 := th.App.GetRoleByName(model.SYSTEM_ADMIN_ROLE_ID) + assert.Nil(t, systemAdminErr2) + assert.Equal(t, expectedSystemAdmin, systemAdmin2.Permissions, fmt.Sprintf("'%v' did not have expected permissions", model.SYSTEM_ADMIN_ROLE_ID)) +} diff --git a/app/apptestlib.go b/app/apptestlib.go index ec4992a75..d4a79bdcc 100644 --- a/app/apptestlib.go +++ b/app/apptestlib.go @@ -110,6 +110,7 @@ func setupTestHelper(enterprise bool) *TestHelper { th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress }) th.App.DoAdvancedPermissionsMigration() + th.App.DoEmojisPermissionsMigration() th.App.Srv.Store.MarkSystemRanUnitTests() @@ -433,6 +434,18 @@ func (me *TestHelper) ResetRoleMigration() { } } +func (me *TestHelper) ResetEmojisMigration() { + if _, err := testStoreSqlSupplier.GetMaster().Exec("UPDATE Roles SET Permissions=REPLACE(Permissions, ', manage_emojis', '') WHERE builtin=True"); err != nil { + panic(err) + } + + testClusterInterface.sendClearRoleCacheMessage() + + if _, err := testStoreSqlSupplier.GetMaster().Exec("DELETE from Systems where Name = :Name", map[string]interface{}{"Name": EMOJIS_PERMISSIONS_MIGRATION_KEY}); err != nil { + panic(err) + } +} + type FakeClusterInterface struct { clusterMessageHandler einterfaces.ClusterMessageHandler } diff --git a/app/permissions.go b/app/permissions.go index 70b8cc689..46090070e 100644 --- a/app/permissions.go +++ b/app/permissions.go @@ -43,6 +43,7 @@ func (a *App) ResetPermissionsSystem() *model.AppError { // Now that the permissions system has been reset, re-run the migration to reinitialise it. a.DoAdvancedPermissionsMigration() + a.DoEmojisPermissionsMigration() return nil } diff --git a/cmd/mattermost/commands/init.go b/cmd/mattermost/commands/init.go index aea2b1230..ea7e8ec84 100644 --- a/cmd/mattermost/commands/init.go +++ b/cmd/mattermost/commands/init.go @@ -23,6 +23,7 @@ func InitDBCommandContextCobra(command *cobra.Command) (*app.App, error) { } a.DoAdvancedPermissionsMigration() + a.DoEmojisPermissionsMigration() return a, nil } diff --git a/cmd/mattermost/commands/server.go b/cmd/mattermost/commands/server.go index 299005b6a..67e2f69c5 100644 --- a/cmd/mattermost/commands/server.go +++ b/cmd/mattermost/commands/server.go @@ -92,6 +92,7 @@ func runServer(configFileLocation string, disableConfigWatch bool, usedPlatform } a.DoAdvancedPermissionsMigration() + a.DoEmojisPermissionsMigration() a.InitPlugins(*a.Config().PluginSettings.Directory, *a.Config().PluginSettings.ClientDirectory, nil) a.AddConfigListener(func(prevCfg, cfg *model.Config) { diff --git a/einterfaces/emoji.go b/einterfaces/emoji.go deleted file mode 100644 index b8d61e748..000000000 --- a/einterfaces/emoji.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package einterfaces - -import ( - "github.com/mattermost/mattermost-server/model" -) - -type EmojiInterface interface { - CanUserCreateEmoji(string, []*model.TeamMember) bool -} diff --git a/i18n/en.json b/i18n/en.json index d631e7e1d..0fc9a733f 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1336,10 +1336,6 @@ "id": "api.emoji.delete.delete_reactions.app_error", "translation": "Unable to delete reactions when deleting emoji with emoji name %v" }, - { - "id": "api.emoji.delete.permissions.app_error", - "translation": "Invalid permissions to delete emoji." - }, { "id": "api.emoji.disabled.app_error", "translation": "Custom emoji have been disabled by the system admin." diff --git a/migrations/migrationstestlib.go b/migrations/migrationstestlib.go index 1b9110425..b501291b0 100644 --- a/migrations/migrationstestlib.go +++ b/migrations/migrationstestlib.go @@ -111,6 +111,7 @@ func setupTestHelper(enterprise bool) *TestHelper { th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress }) th.App.DoAdvancedPermissionsMigration() + th.App.DoEmojisPermissionsMigration() th.App.Srv.Store.MarkSystemRanUnitTests() diff --git a/model/permission.go b/model/permission.go index 792c7d42e..737321cc7 100644 --- a/model/permission.go +++ b/model/permission.go @@ -50,6 +50,8 @@ var PERMISSION_MANAGE_WEBHOOKS *Permission var PERMISSION_MANAGE_OTHERS_WEBHOOKS *Permission var PERMISSION_MANAGE_OAUTH *Permission var PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH *Permission +var PERMISSION_MANAGE_EMOJIS *Permission +var PERMISSION_MANAGE_OTHERS_EMOJIS *Permission var PERMISSION_CREATE_POST *Permission var PERMISSION_CREATE_POST_PUBLIC *Permission var PERMISSION_CREATE_POST_EPHEMERAL *Permission @@ -286,6 +288,18 @@ func initializePermissions() { "authentication.permissions.manage_system_wide_oauth.description", PERMISSION_SCOPE_SYSTEM, } + PERMISSION_MANAGE_EMOJIS = &Permission{ + "manage_emojis", + "authentication.permissions.manage_emojis.name", + "authentication.permissions.manage_emojis.description", + PERMISSION_SCOPE_TEAM, + } + PERMISSION_MANAGE_OTHERS_EMOJIS = &Permission{ + "manage_others_emojis", + "authentication.permissions.manage_others_emojis.name", + "authentication.permissions.manage_others_emojis.description", + PERMISSION_SCOPE_TEAM, + } PERMISSION_CREATE_POST = &Permission{ "create_post", "authentication.permissions.create_post.name", @@ -424,6 +438,8 @@ func initializePermissions() { PERMISSION_MANAGE_OTHERS_WEBHOOKS, PERMISSION_MANAGE_OAUTH, PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH, + PERMISSION_MANAGE_EMOJIS, + PERMISSION_MANAGE_OTHERS_EMOJIS, PERMISSION_CREATE_POST, PERMISSION_CREATE_POST_PUBLIC, PERMISSION_CREATE_POST_EPHEMERAL, diff --git a/store/sqlstore/upgrade.go b/store/sqlstore/upgrade.go index 93399d7d9..98a89f36d 100644 --- a/store/sqlstore/upgrade.go +++ b/store/sqlstore/upgrade.go @@ -425,6 +425,10 @@ func UpgradeDatabaseToVersion410(sqlStore SqlStore) { } func UpgradeDatabaseToVersion50(sqlStore SqlStore) { + // This version of Mattermost includes an App-Layer migration which migrates from hard-coded emojis configured + // in `config.json` to a `Permission` in the database. The migration code can be seen + // in the file `app/app.go` in the function `DoEmojisPermissionsMigration()`. + // TODO: Uncomment following condition when version 5.0.0 is released //if shouldPerformUpgrade(sqlStore, VERSION_4_10_0, VERSION_5_0_0) { diff --git a/web/web_test.go b/web/web_test.go index 9b6230013..b53ed9618 100644 --- a/web/web_test.go +++ b/web/web_test.go @@ -61,6 +61,7 @@ func Setup() *TestHelper { ApiClient = model.NewAPIv4Client(URL) a.DoAdvancedPermissionsMigration() + a.DoEmojisPermissionsMigration() a.Srv.Store.MarkSystemRanUnitTests() -- cgit v1.2.3-1-g7c22