diff --git a/api4/channel_test.go b/api4/channel_test.go index 974426dc06..5c2781e7cf 100644 --- a/api4/channel_test.go +++ b/api4/channel_test.go @@ -1001,8 +1001,8 @@ func TestDeleteChannel2(t *testing.T) { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.TEAM_USER_ROLE_ID) - th.AddPermissionToRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.CHANNEL_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.CHANNEL_USER_ROLE_ID) // channels created by SystemAdmin publicChannel6 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN) @@ -1019,8 +1019,8 @@ func TestDeleteChannel2(t *testing.T) { CheckNoError(t, resp) // Restrict permissions to Channel Admins - th.RemovePermissionFromRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.TEAM_USER_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.TEAM_USER_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.CHANNEL_USER_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.CHANNEL_USER_ROLE_ID) th.AddPermissionToRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.CHANNEL_ADMIN_ROLE_ID) th.AddPermissionToRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.CHANNEL_ADMIN_ROLE_ID) diff --git a/app/app_test.go b/app/app_test.go index 83d9ee75d5..cdf9909edc 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -78,6 +78,10 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { model.PERMISSION_GET_PUBLIC_LINK.Id, model.PERMISSION_CREATE_POST.Id, model.PERMISSION_USE_SLASH_COMMANDS.Id, + model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, + model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, + model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, + model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, model.PERMISSION_DELETE_POST.Id, model.PERMISSION_EDIT_POST.Id, @@ -91,11 +95,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { model.PERMISSION_READ_PUBLIC_CHANNEL.Id, model.PERMISSION_VIEW_TEAM.Id, model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, - model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, - model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, - model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, - model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.PERMISSION_INVITE_USER.Id, model.PERMISSION_ADD_USER_TO_TEAM.Id, }, @@ -258,6 +258,8 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { model.PERMISSION_GET_PUBLIC_LINK.Id, model.PERMISSION_CREATE_POST.Id, model.PERMISSION_USE_SLASH_COMMANDS.Id, + model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, + model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, model.PERMISSION_DELETE_POST.Id, model.PERMISSION_EDIT_POST.Id, @@ -271,9 +273,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { model.PERMISSION_READ_PUBLIC_CHANNEL.Id, model.PERMISSION_VIEW_TEAM.Id, model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, - model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, - model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.PERMISSION_INVITE_USER.Id, model.PERMISSION_ADD_USER_TO_TEAM.Id, }, diff --git a/app/command_channel_header_test.go b/app/command_channel_header_test.go index 1ffcceae4e..fb042dee7c 100644 --- a/app/command_channel_header_test.go +++ b/app/command_channel_header_test.go @@ -17,6 +17,8 @@ func TestHeaderProviderDoCommand(t *testing.T) { hp := HeaderProvider{} + th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + // Try a public channel *with* permission. args := &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, @@ -32,16 +34,20 @@ func TestHeaderProviderDoCommand(t *testing.T) { assert.Equal(t, expected, actual) } + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + // Try a public channel *without* permission. args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: th.BasicChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual := hp.DoCommand(th.App, args, "hello").Text assert.Equal(t, "api.command_channel_header.permission.app_error", actual) + th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + // Try a private channel *with* permission. privateChannel := th.CreatePrivateChannel(th.BasicTeam) @@ -54,11 +60,13 @@ func TestHeaderProviderDoCommand(t *testing.T) { actual = hp.DoCommand(th.App, args, "hello").Text assert.Equal(t, "", actual) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + // Try a private channel *without* permission. args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: privateChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = hp.DoCommand(th.App, args, "hello").Text @@ -74,7 +82,7 @@ func TestHeaderProviderDoCommand(t *testing.T) { args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: groupChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = hp.DoCommand(th.App, args, "hello").Text @@ -84,7 +92,7 @@ func TestHeaderProviderDoCommand(t *testing.T) { args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: groupChannel.Id, - Session: model.Session{UserId: user3.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: user3.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = hp.DoCommand(th.App, args, "hello").Text @@ -96,7 +104,7 @@ func TestHeaderProviderDoCommand(t *testing.T) { args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: directChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = hp.DoCommand(th.App, args, "hello").Text @@ -106,7 +114,7 @@ func TestHeaderProviderDoCommand(t *testing.T) { args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: directChannel.Id, - Session: model.Session{UserId: user2.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: user2.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = hp.DoCommand(th.App, args, "hello").Text diff --git a/app/command_channel_purpose_test.go b/app/command_channel_purpose_test.go index 2fdd42b020..432ab566ef 100644 --- a/app/command_channel_purpose_test.go +++ b/app/command_channel_purpose_test.go @@ -18,6 +18,8 @@ func TestPurposeProviderDoCommand(t *testing.T) { pp := PurposeProvider{} // Try a public channel *with* permission. + th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + args := &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: th.BasicChannel.Id, @@ -33,10 +35,12 @@ func TestPurposeProviderDoCommand(t *testing.T) { } // Try a public channel *without* permission. + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: th.BasicChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual := pp.DoCommand(th.App, args, "hello").Text @@ -45,6 +49,8 @@ func TestPurposeProviderDoCommand(t *testing.T) { // Try a private channel *with* permission. privateChannel := th.CreatePrivateChannel(th.BasicTeam) + th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: privateChannel.Id, @@ -55,10 +61,12 @@ func TestPurposeProviderDoCommand(t *testing.T) { assert.Equal(t, "", actual) // Try a private channel *without* permission. + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: privateChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = pp.DoCommand(th.App, args, "hello").Text @@ -73,7 +81,7 @@ func TestPurposeProviderDoCommand(t *testing.T) { args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: groupChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = pp.DoCommand(th.App, args, "hello").Text @@ -85,7 +93,7 @@ func TestPurposeProviderDoCommand(t *testing.T) { args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: directChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = pp.DoCommand(th.App, args, "hello").Text diff --git a/app/command_channel_rename_test.go b/app/command_channel_rename_test.go index 74241fb7eb..8fb31340cd 100644 --- a/app/command_channel_rename_test.go +++ b/app/command_channel_rename_test.go @@ -15,6 +15,8 @@ func TestRenameProviderDoCommand(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() + th.AddPermissionToRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + rp := RenameProvider{} args := &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, @@ -35,10 +37,12 @@ func TestRenameProviderDoCommand(t *testing.T) { } // Try a public channel *without* permission. + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: th.BasicChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual := rp.DoCommand(th.App, args, "hello").Text @@ -47,6 +51,8 @@ func TestRenameProviderDoCommand(t *testing.T) { // Try a private channel *with* permission. privateChannel := th.CreatePrivateChannel(th.BasicTeam) + th.AddPermissionToRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: privateChannel.Id, @@ -57,10 +63,12 @@ func TestRenameProviderDoCommand(t *testing.T) { assert.Equal(t, "", actual) // Try a private channel *without* permission. + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.CHANNEL_USER_ROLE_ID) + args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: privateChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = rp.DoCommand(th.App, args, "hello").Text @@ -75,7 +83,7 @@ func TestRenameProviderDoCommand(t *testing.T) { args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: groupChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = rp.DoCommand(th.App, args, "hello").Text @@ -87,7 +95,7 @@ func TestRenameProviderDoCommand(t *testing.T) { args = &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: directChannel.Id, - Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}}, + Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}}, } actual = rp.DoCommand(th.App, args, "hello").Text diff --git a/app/helper_test.go b/app/helper_test.go index fe5d400e5d..6ba78486a9 100644 --- a/app/helper_test.go +++ b/app/helper_test.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "time" "testing" @@ -503,3 +504,62 @@ func (me *TestHelper) SetupPluginAPI() *PluginAPI { return NewPluginAPI(me.App, manifest) } + +func (me *TestHelper) RemovePermissionFromRole(permission string, roleName string) { + utils.DisableDebugLogForTest() + + role, err1 := me.App.GetRoleByName(roleName) + if err1 != nil { + utils.EnableDebugLogForTest() + panic(err1) + } + + var newPermissions []string + for _, p := range role.Permissions { + if p != permission { + newPermissions = append(newPermissions, p) + } + } + + if strings.Join(role.Permissions, " ") == strings.Join(newPermissions, " ") { + utils.EnableDebugLogForTest() + return + } + + role.Permissions = newPermissions + + _, err2 := me.App.UpdateRole(role) + if err2 != nil { + utils.EnableDebugLogForTest() + panic(err2) + } + + utils.EnableDebugLogForTest() +} + +func (me *TestHelper) AddPermissionToRole(permission string, roleName string) { + utils.DisableDebugLogForTest() + + role, err1 := me.App.GetRoleByName(roleName) + if err1 != nil { + utils.EnableDebugLogForTest() + panic(err1) + } + + for _, existingPermission := range role.Permissions { + if existingPermission == permission { + utils.EnableDebugLogForTest() + return + } + } + + role.Permissions = append(role.Permissions, permission) + + _, err2 := me.App.UpdateRole(role) + if err2 != nil { + utils.EnableDebugLogForTest() + panic(err2) + } + + utils.EnableDebugLogForTest() +} diff --git a/app/permissions_migrations.go b/app/permissions_migrations.go index fde3fae616..283836edc2 100644 --- a/app/permissions_migrations.go +++ b/app/permissions_migrations.go @@ -8,67 +8,79 @@ import ( ) type permissionTransformation struct { - On func(string, map[string]bool) bool + On func(string, map[string]map[string]bool) bool Add []string Remove []string } type permissionsMap []permissionTransformation const ( - MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT = "emoji_permissions_split" - MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT = "webhook_permissions_split" - MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS = "list_join_public_private_teams" - MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER = "remove_permanent_delete_user" - MIGRATION_KEY_ADD_BOT_PERMISSIONS = "add_bot_permissions" + MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT = "emoji_permissions_split" + MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT = "webhook_permissions_split" + MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS = "list_join_public_private_teams" + MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER = "remove_permanent_delete_user" + MIGRATION_KEY_ADD_BOT_PERMISSIONS = "add_bot_permissions" + MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER = "apply_channel_manage_delete_to_channel_user" + MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER = "remove_channel_manage_delete_from_team_user" - PERMISSION_MANAGE_SYSTEM = "manage_system" - PERMISSION_MANAGE_EMOJIS = "manage_emojis" - PERMISSION_MANAGE_OTHERS_EMOJIS = "manage_others_emojis" - PERMISSION_CREATE_EMOJIS = "create_emojis" - PERMISSION_DELETE_EMOJIS = "delete_emojis" - PERMISSION_DELETE_OTHERS_EMOJIS = "delete_others_emojis" - PERMISSION_MANAGE_WEBHOOKS = "manage_webhooks" - PERMISSION_MANAGE_OTHERS_WEBHOOKS = "manage_others_webhooks" - PERMISSION_MANAGE_INCOMING_WEBHOOKS = "manage_incoming_webhooks" - PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = "manage_others_incoming_webhooks" - PERMISSION_MANAGE_OUTGOING_WEBHOOKS = "manage_outgoing_webhooks" - PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = "manage_others_outgoing_webhooks" - PERMISSION_LIST_PUBLIC_TEAMS = "list_public_teams" - PERMISSION_LIST_PRIVATE_TEAMS = "list_private_teams" - PERMISSION_JOIN_PUBLIC_TEAMS = "join_public_teams" - PERMISSION_JOIN_PRIVATE_TEAMS = "join_private_teams" - PERMISSION_PERMANENT_DELETE_USER = "permanent_delete_user" - PERMISSION_CREATE_BOT = "create_bot" - PERMISSION_READ_BOTS = "read_bots" - PERMISSION_READ_OTHERS_BOTS = "read_others_bots" - PERMISSION_MANAGE_BOTS = "manage_bots" - PERMISSION_MANAGE_OTHERS_BOTS = "manage_others_bots" + PERMISSION_MANAGE_SYSTEM = "manage_system" + PERMISSION_MANAGE_EMOJIS = "manage_emojis" + PERMISSION_MANAGE_OTHERS_EMOJIS = "manage_others_emojis" + PERMISSION_CREATE_EMOJIS = "create_emojis" + PERMISSION_DELETE_EMOJIS = "delete_emojis" + PERMISSION_DELETE_OTHERS_EMOJIS = "delete_others_emojis" + PERMISSION_MANAGE_WEBHOOKS = "manage_webhooks" + PERMISSION_MANAGE_OTHERS_WEBHOOKS = "manage_others_webhooks" + PERMISSION_MANAGE_INCOMING_WEBHOOKS = "manage_incoming_webhooks" + PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = "manage_others_incoming_webhooks" + PERMISSION_MANAGE_OUTGOING_WEBHOOKS = "manage_outgoing_webhooks" + PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = "manage_others_outgoing_webhooks" + PERMISSION_LIST_PUBLIC_TEAMS = "list_public_teams" + PERMISSION_LIST_PRIVATE_TEAMS = "list_private_teams" + PERMISSION_JOIN_PUBLIC_TEAMS = "join_public_teams" + PERMISSION_JOIN_PRIVATE_TEAMS = "join_private_teams" + PERMISSION_PERMANENT_DELETE_USER = "permanent_delete_user" + PERMISSION_CREATE_BOT = "create_bot" + PERMISSION_READ_BOTS = "read_bots" + PERMISSION_READ_OTHERS_BOTS = "read_others_bots" + PERMISSION_MANAGE_BOTS = "manage_bots" + PERMISSION_MANAGE_OTHERS_BOTS = "manage_others_bots" + PERMISSION_DELETE_PUBLIC_CHANNEL = "delete_public_channel" + PERMISSION_DELETE_PRIVATE_CHANNEL = "delete_private_channel" + PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES = "manage_public_channel_properties" + PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES = "manage_private_channel_properties" ) -func isRole(role string) func(string, map[string]bool) bool { - return func(roleName string, permissions map[string]bool) bool { +func isRole(role string) func(string, map[string]map[string]bool) bool { + return func(roleName string, permissionsMap map[string]map[string]bool) bool { return roleName == role } } -func permissionExists(permission string) func(string, map[string]bool) bool { - return func(roleName string, permissions map[string]bool) bool { - val, ok := permissions[permission] +func permissionExists(permission string) func(string, map[string]map[string]bool) bool { + return func(roleName string, permissionsMap map[string]map[string]bool) bool { + val, ok := permissionsMap[roleName][permission] return ok && val } } -func permissionNotExists(permission string) func(string, map[string]bool) bool { - return func(roleName string, permissions map[string]bool) bool { - val, ok := permissions[permission] +func permissionNotExists(permission string) func(string, map[string]map[string]bool) bool { + return func(roleName string, permissionsMap map[string]map[string]bool) bool { + val, ok := permissionsMap[roleName][permission] return !(ok && val) } } -func permissionOr(funcs ...func(string, map[string]bool) bool) func(string, map[string]bool) bool { - return func(roleName string, permissions map[string]bool) bool { +func onOtherRole(otherRole string, function func(string, map[string]map[string]bool) bool) func(string, map[string]map[string]bool) bool { + return func(roleName string, permissionsMap map[string]map[string]bool) bool { + return function(otherRole, permissionsMap) + } +} + +func permissionOr(funcs ...func(string, map[string]map[string]bool) bool) func(string, map[string]map[string]bool) bool { + return func(roleName string, permissionsMap map[string]map[string]bool) bool { for _, f := range funcs { - if f(roleName, permissions) { + if f(roleName, permissionsMap) { return true } } @@ -76,10 +88,10 @@ func permissionOr(funcs ...func(string, map[string]bool) bool) func(string, map[ } } -func permissionAnd(funcs ...func(string, map[string]bool) bool) func(string, map[string]bool) bool { - return func(roleName string, permissions map[string]bool) bool { +func permissionAnd(funcs ...func(string, map[string]map[string]bool) bool) func(string, map[string]map[string]bool) bool { + return func(roleName string, permissionsMap map[string]map[string]bool) bool { for _, f := range funcs { - if !f(roleName, permissions) { + if !f(roleName, permissionsMap) { return false } } @@ -87,25 +99,21 @@ func permissionAnd(funcs ...func(string, map[string]bool) bool) func(string, map } } -func applyPermissionsMap(roleName string, permissions []string, migrationMap permissionsMap) []string { - finalMap := make(map[string]bool) +func applyPermissionsMap(roleName string, roleMap map[string]map[string]bool, migrationMap permissionsMap) []string { var result []string - for _, permission := range permissions { - finalMap[permission] = true - } for _, transformation := range migrationMap { - if transformation.On(roleName, finalMap) { - for _, add := range transformation.Add { - finalMap[add] = true + if transformation.On(roleName, roleMap) { + for _, permission := range transformation.Add { + roleMap[roleName][permission] = true } - for _, remove := range transformation.Remove { - finalMap[remove] = false + for _, permission := range transformation.Remove { + roleMap[roleName][permission] = false } } } - for key, active := range finalMap { + for key, active := range roleMap[roleName] { if active { result = append(result, key) } @@ -123,8 +131,16 @@ func (a *App) doPermissionsMigration(key string, migrationMap permissionsMap) *m return err } + roleMap := make(map[string]map[string]bool) for _, role := range roles { - role.Permissions = applyPermissionsMap(role.Name, role.Permissions, migrationMap) + roleMap[role.Name] = make(map[string]bool) + for _, permission := range role.Permissions { + roleMap[role.Name][permission] = true + } + } + + for _, role := range roles { + role.Permissions = applyPermissionsMap(role.Name, roleMap, migrationMap) if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { return result.Err } @@ -200,6 +216,48 @@ func getAddBotPermissionsMigration() permissionsMap { } } +func applyChannelManageDeleteToChannelUser() permissionsMap { + return permissionsMap{ + permissionTransformation{ + On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES))), + Add: []string{PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES}, + }, + permissionTransformation{ + On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_DELETE_PRIVATE_CHANNEL))), + Add: []string{PERMISSION_DELETE_PRIVATE_CHANNEL}, + }, + permissionTransformation{ + On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES))), + Add: []string{PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES}, + }, + permissionTransformation{ + On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_DELETE_PUBLIC_CHANNEL))), + Add: []string{PERMISSION_DELETE_PUBLIC_CHANNEL}, + }, + } +} + +func removeChannelManageDeleteFromTeamUser() permissionsMap { + return permissionsMap{ + permissionTransformation{ + On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES)), + Remove: []string{PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES}, + }, + permissionTransformation{ + On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_DELETE_PRIVATE_CHANNEL)), + Remove: []string{model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id}, + }, + permissionTransformation{ + On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES)), + Remove: []string{PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES}, + }, + permissionTransformation{ + On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_DELETE_PUBLIC_CHANNEL)), + Remove: []string{PERMISSION_DELETE_PUBLIC_CHANNEL}, + }, + } +} + // DoPermissionsMigrations execute all the permissions migrations need by the current version. func (a *App) DoPermissionsMigrations() *model.AppError { PermissionsMigrations := []struct { @@ -211,6 +269,8 @@ func (a *App) DoPermissionsMigrations() *model.AppError { {Key: MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS, Migration: getListJoinPublicPrivateTeamsPermissionsMigration}, {Key: MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER, Migration: removePermanentDeleteUserMigration}, {Key: MIGRATION_KEY_ADD_BOT_PERMISSIONS, Migration: getAddBotPermissionsMigration}, + {Key: MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER, Migration: applyChannelManageDeleteToChannelUser}, + {Key: MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER, Migration: removeChannelManageDeleteFromTeamUser}, } for _, migration := range PermissionsMigrations { diff --git a/app/permissions_migrations_test.go b/app/permissions_migrations_test.go index 80a45e42b7..a02904764d 100644 --- a/app/permissions_migrations_test.go +++ b/app/permissions_migrations_test.go @@ -13,37 +13,67 @@ import ( func TestApplyPermissionsMap(t *testing.T) { tt := []struct { Name string - Permissions []string + RoleMap map[string]map[string]bool TranslationMap permissionsMap ExpectedResult []string }{ { "Split existing", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{On: permissionExists("test2"), Add: []string{"test4", "test5"}}}, []string{"test1", "test2", "test3", "test4", "test5"}, }, { "Remove existing", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{On: permissionExists("test2"), Remove: []string{"test2"}}}, []string{"test1", "test3"}, }, { "Rename existing", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{On: permissionExists("test2"), Add: []string{"test5"}, Remove: []string{"test2"}}}, []string{"test1", "test3", "test5"}, }, { "Remove when other not exists", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{On: permissionNotExists("test5"), Remove: []string{"test2"}}}, []string{"test1", "test3"}, }, { "Add when at least one exists", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{ On: permissionOr(permissionExists("test5"), permissionExists("test3")), Add: []string{"test4"}, @@ -52,7 +82,13 @@ func TestApplyPermissionsMap(t *testing.T) { }, { "Add when all exists", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{ On: permissionAnd(permissionExists("test1"), permissionExists("test2")), Add: []string{"test4"}, @@ -61,7 +97,13 @@ func TestApplyPermissionsMap(t *testing.T) { }, { "Not add when one in the and not exists", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{ On: permissionAnd(permissionExists("test1"), permissionExists("test5")), Add: []string{"test4"}, @@ -70,7 +112,13 @@ func TestApplyPermissionsMap(t *testing.T) { }, { "Not Add when none on the or exists", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{ On: permissionOr(permissionExists("test7"), permissionExists("test9")), Add: []string{"test4"}, @@ -79,7 +127,13 @@ func TestApplyPermissionsMap(t *testing.T) { }, { "When the role matches", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{ On: isRole("system_admin"), Add: []string{"test4"}, @@ -88,18 +142,60 @@ func TestApplyPermissionsMap(t *testing.T) { }, { "When the role doesn't match", - []string{"test1", "test2", "test3"}, + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + }, permissionsMap{permissionTransformation{ On: isRole("system_user"), Add: []string{"test4"}, }}, []string{"test1", "test2", "test3"}, }, + { + "Remove a permission conditional on another role having it, success case", + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test3": true, + }, + "other_role": { + "test4": true, + }, + }, + permissionsMap{permissionTransformation{ + On: onOtherRole("other_role", permissionExists("test4")), + Remove: []string{"test1"}, + }}, + []string{"test2", "test3"}, + }, + { + "Remove a permission conditional on another role having it, failure case", + map[string]map[string]bool{ + "system_admin": { + "test1": true, + "test2": true, + "test4": true, + }, + "other_role": { + "test1": true, + }, + }, + permissionsMap{permissionTransformation{ + On: onOtherRole("other_role", permissionExists("test4")), + Remove: []string{"test1"}, + }}, + []string{"test1", "test2", "test4"}, + }, } for _, tc := range tt { t.Run(tc.Name, func(t *testing.T) { - result := applyPermissionsMap("system_admin", tc.Permissions, tc.TranslationMap) + result := applyPermissionsMap("system_admin", tc.RoleMap, tc.TranslationMap) sort.Strings(result) assert.Equal(t, tc.ExpectedResult, result) }) diff --git a/utils/authorization.go b/utils/authorization.go index d08f885bc3..5125b45e63 100644 --- a/utils/authorization.go +++ b/utils/authorization.go @@ -31,8 +31,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi if isLicensed { switch *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement { case model.PERMISSIONS_ALL: - roles[model.TEAM_USER_ROLE_ID].Permissions = append( - roles[model.TEAM_USER_ROLE_ID].Permissions, + roles[model.CHANNEL_USER_ROLE_ID].Permissions = append( + roles[model.CHANNEL_USER_ROLE_ID].Permissions, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, ) case model.PERMISSIONS_CHANNEL_ADMIN: @@ -51,8 +51,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi ) } } else { - roles[model.TEAM_USER_ROLE_ID].Permissions = append( - roles[model.TEAM_USER_ROLE_ID].Permissions, + roles[model.CHANNEL_USER_ROLE_ID].Permissions = append( + roles[model.CHANNEL_USER_ROLE_ID].Permissions, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, ) } @@ -60,8 +60,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi if isLicensed { switch *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion { case model.PERMISSIONS_ALL: - roles[model.TEAM_USER_ROLE_ID].Permissions = append( - roles[model.TEAM_USER_ROLE_ID].Permissions, + roles[model.CHANNEL_USER_ROLE_ID].Permissions = append( + roles[model.CHANNEL_USER_ROLE_ID].Permissions, model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, ) case model.PERMISSIONS_CHANNEL_ADMIN: @@ -80,8 +80,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi ) } } else { - roles[model.TEAM_USER_ROLE_ID].Permissions = append( - roles[model.TEAM_USER_ROLE_ID].Permissions, + roles[model.CHANNEL_USER_ROLE_ID].Permissions = append( + roles[model.CHANNEL_USER_ROLE_ID].Permissions, model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, ) } @@ -109,8 +109,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi if isLicensed { switch *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement { case model.PERMISSIONS_ALL: - roles[model.TEAM_USER_ROLE_ID].Permissions = append( - roles[model.TEAM_USER_ROLE_ID].Permissions, + roles[model.CHANNEL_USER_ROLE_ID].Permissions = append( + roles[model.CHANNEL_USER_ROLE_ID].Permissions, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, ) case model.PERMISSIONS_CHANNEL_ADMIN: @@ -129,8 +129,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi ) } } else { - roles[model.TEAM_USER_ROLE_ID].Permissions = append( - roles[model.TEAM_USER_ROLE_ID].Permissions, + roles[model.CHANNEL_USER_ROLE_ID].Permissions = append( + roles[model.CHANNEL_USER_ROLE_ID].Permissions, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, ) } @@ -138,8 +138,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi if isLicensed { switch *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion { case model.PERMISSIONS_ALL: - roles[model.TEAM_USER_ROLE_ID].Permissions = append( - roles[model.TEAM_USER_ROLE_ID].Permissions, + roles[model.CHANNEL_USER_ROLE_ID].Permissions = append( + roles[model.CHANNEL_USER_ROLE_ID].Permissions, model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, ) case model.PERMISSIONS_CHANNEL_ADMIN: @@ -158,8 +158,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi ) } } else { - roles[model.TEAM_USER_ROLE_ID].Permissions = append( - roles[model.TEAM_USER_ROLE_ID].Permissions, + roles[model.CHANNEL_USER_ROLE_ID].Permissions = append( + roles[model.CHANNEL_USER_ROLE_ID].Permissions, model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, ) } diff --git a/utils/policies-roles-mapping.json b/utils/policies-roles-mapping.json index f2c99d8f1b..414ab62f16 100644 --- a/utils/policies-roles-mapping.json +++ b/utils/policies-roles-mapping.json @@ -101,14 +101,14 @@ "restrictPublicChannelManagement": { "all": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "manage_public_channel_properties", "shouldHave": true } ], "channel_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "manage_public_channel_properties", "shouldHave": false }, @@ -125,7 +125,7 @@ ], "team_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "manage_public_channel_properties", "shouldHave": false }, @@ -142,7 +142,7 @@ ], "system_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "manage_public_channel_properties", "shouldHave": false }, @@ -161,14 +161,14 @@ "restrictPublicChannelDeletion": { "all": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "delete_public_channel", "shouldHave": true } ], "channel_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "delete_public_channel", "shouldHave": false }, @@ -185,7 +185,7 @@ ], "team_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "delete_public_channel", "shouldHave": false }, @@ -202,7 +202,7 @@ ], "system_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "delete_public_channel", "shouldHave": false }, @@ -221,14 +221,14 @@ "restrictPrivateChannelManagement": { "all": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "manage_private_channel_properties", "shouldHave": true } ], "channel_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "manage_private_channel_properties", "shouldHave": false }, @@ -245,7 +245,7 @@ ], "team_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "manage_private_channel_properties", "shouldHave": false }, @@ -262,7 +262,7 @@ ], "system_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "manage_private_channel_properties", "shouldHave": false }, @@ -341,14 +341,14 @@ "restrictPrivateChannelDeletion": { "all": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "delete_private_channel", "shouldHave": true } ], "channel_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "delete_private_channel", "shouldHave": false }, @@ -365,7 +365,7 @@ ], "team_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "delete_private_channel", "shouldHave": false }, @@ -382,7 +382,7 @@ ], "system_admin": [ { - "roleName": "team_user", + "roleName": "channel_user", "permission": "delete_private_channel", "shouldHave": false },