diff --git a/api4/emoji.go b/api4/emoji.go index 84c70be62f..81c3e0752a 100644 --- a/api4/emoji.go +++ b/api4/emoji.go @@ -47,7 +47,7 @@ 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 + // Allow any user with CREATE_EMOJIS permission at Team level to create emojis at system level memberships, err := c.App.GetTeamMembersForUser(c.App.Session.UserId) if err != nil { @@ -55,16 +55,16 @@ func createEmoji(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_EMOJIS) { + if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_CREATE_EMOJIS) { hasPermission := false for _, membership := range memberships { - if c.App.SessionHasPermissionToTeam(c.App.Session, membership.TeamId, model.PERMISSION_MANAGE_EMOJIS) { + if c.App.SessionHasPermissionToTeam(c.App.Session, membership.TeamId, model.PERMISSION_CREATE_EMOJIS) { hasPermission = true break } } if !hasPermission { - c.SetPermissionError(model.PERMISSION_MANAGE_EMOJIS) + c.SetPermissionError(model.PERMISSION_CREATE_EMOJIS) return } } @@ -125,7 +125,7 @@ func deleteEmoji(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 + // Allow any user with DELETE_EMOJIS permission at Team level to delete emojis at system level memberships, err := c.App.GetTeamMembersForUser(c.App.Session.UserId) if err != nil { @@ -133,32 +133,32 @@ func deleteEmoji(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_EMOJIS) { + if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_DELETE_EMOJIS) { hasPermission := false for _, membership := range memberships { - if c.App.SessionHasPermissionToTeam(c.App.Session, membership.TeamId, model.PERMISSION_MANAGE_EMOJIS) { + if c.App.SessionHasPermissionToTeam(c.App.Session, membership.TeamId, model.PERMISSION_DELETE_EMOJIS) { hasPermission = true break } } if !hasPermission { - c.SetPermissionError(model.PERMISSION_MANAGE_EMOJIS) + c.SetPermissionError(model.PERMISSION_DELETE_EMOJIS) return } } if c.App.Session.UserId != emoji.CreatorId { - if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_OTHERS_EMOJIS) { + if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_DELETE_OTHERS_EMOJIS) { hasPermission := false for _, membership := range memberships { - if c.App.SessionHasPermissionToTeam(c.App.Session, membership.TeamId, model.PERMISSION_MANAGE_OTHERS_EMOJIS) { + if c.App.SessionHasPermissionToTeam(c.App.Session, membership.TeamId, model.PERMISSION_DELETE_OTHERS_EMOJIS) { hasPermission = true break } } if !hasPermission { - c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_EMOJIS) + c.SetPermissionError(model.PERMISSION_DELETE_OTHERS_EMOJIS) return } } diff --git a/api4/emoji_test.go b/api4/emoji_test.go index 30b0d8f2f1..031f6d50a3 100644 --- a/api4/emoji_test.go +++ b/api4/emoji_test.go @@ -159,7 +159,7 @@ func TestCreateEmoji(t *testing.T) { CheckForbiddenStatus(t, resp) // try to create an emoji without permissions - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_CREATE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) emoji = &model.Emoji{ CreatorId: th.BasicUser.Id, @@ -170,7 +170,7 @@ func TestCreateEmoji(t *testing.T) { CheckForbiddenStatus(t, resp) // create an emoji with permissions in one team - th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_CREATE_EMOJIS.Id, model.TEAM_USER_ROLE_ID) emoji = &model.Emoji{ CreatorId: th.BasicUser.Id, @@ -324,12 +324,12 @@ func TestDeleteEmoji(t *testing.T) { 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_DELETE_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) + th.AddPermissionToRole(model.PERMISSION_DELETE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) - //Try to delete other user's custom emoji without MANAGE_EMOJIS permissions + //Try to delete other user's custom emoji without DELETE_EMOJIS permissions emoji = &model.Emoji{ CreatorId: th.BasicUser.Id, Name: model.NewId(), @@ -338,8 +338,8 @@ func TestDeleteEmoji(t *testing.T) { 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) + th.RemovePermissionFromRole(model.PERMISSION_DELETE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_DELETE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) Client.Logout() th.LoginBasic2() @@ -347,13 +347,13 @@ func TestDeleteEmoji(t *testing.T) { _, resp = Client.DeleteEmoji(newEmoji.Id) 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) + th.RemovePermissionFromRole(model.PERMISSION_DELETE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_DELETE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) Client.Logout() th.LoginBasic() - //Try to delete other user's custom emoji without MANAGE_OTHERS_EMOJIS permissions + //Try to delete other user's custom emoji without DELETE_OTHERS_EMOJIS permissions emoji = &model.Emoji{ CreatorId: th.BasicUser.Id, Name: model.NewId(), @@ -380,8 +380,8 @@ func TestDeleteEmoji(t *testing.T) { 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) + th.AddPermissionToRole(model.PERMISSION_DELETE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_DELETE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) Client.Logout() th.LoginBasic2() @@ -396,12 +396,12 @@ func TestDeleteEmoji(t *testing.T) { 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) + th.RemovePermissionFromRole(model.PERMISSION_DELETE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_DELETE_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) + th.AddPermissionToRole(model.PERMISSION_DELETE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_DELETE_EMOJIS.Id, model.TEAM_USER_ROLE_ID) //Try to delete other user's custom emoji with permissions at team level emoji = &model.Emoji{ @@ -412,11 +412,11 @@ func TestDeleteEmoji(t *testing.T) { 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.RemovePermissionFromRole(model.PERMISSION_DELETE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_DELETE_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) + th.AddPermissionToRole(model.PERMISSION_DELETE_EMOJIS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_DELETE_OTHERS_EMOJIS.Id, model.TEAM_USER_ROLE_ID) Client.Logout() th.LoginBasic2() diff --git a/api4/role.go b/api4/role.go index 5efcb30db3..cb2c10b6d9 100644 --- a/api4/role.go +++ b/api4/role.go @@ -99,11 +99,13 @@ func patchRole(c *Context, w http.ResponseWriter, r *http.Request) { if c.App.License() == nil && patch.Permissions != nil { allowedPermissions := []string{ model.PERMISSION_CREATE_TEAM.Id, - model.PERMISSION_MANAGE_WEBHOOKS.Id, + model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, model.PERMISSION_MANAGE_OAUTH.Id, model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id, - model.PERMISSION_MANAGE_EMOJIS.Id, + model.PERMISSION_CREATE_EMOJIS.Id, + model.PERMISSION_DELETE_EMOJIS.Id, model.PERMISSION_EDIT_OTHERS_POSTS.Id, } diff --git a/api4/role_test.go b/api4/role_test.go index 3d0caa0201..d26969c94d 100644 --- a/api4/role_test.go +++ b/api4/role_test.go @@ -164,7 +164,7 @@ func TestPatchRole(t *testing.T) { defer th.App.Srv.Store.Job().Delete(role.Id) patch := &model.RolePatch{ - Permissions: &[]string{"manage_system", "create_public_channel", "manage_webhooks"}, + Permissions: &[]string{"manage_system", "create_public_channel", "manage_incoming_webhooks", "manage_outgoing_webhooks"}, } received, resp := th.SystemAdminClient.PatchRole(role.Id, patch) @@ -174,7 +174,7 @@ func TestPatchRole(t *testing.T) { assert.Equal(t, received.Name, role.Name) assert.Equal(t, received.DisplayName, role.DisplayName) assert.Equal(t, received.Description, role.Description) - assert.EqualValues(t, received.Permissions, []string{"manage_system", "create_public_channel", "manage_webhooks"}) + assert.EqualValues(t, received.Permissions, []string{"manage_system", "create_public_channel", "manage_incoming_webhooks", "manage_outgoing_webhooks"}) assert.Equal(t, received.SchemeManaged, role.SchemeManaged) // Check a no-op patch succeeds. @@ -192,7 +192,7 @@ func TestPatchRole(t *testing.T) { // Check a change that the license would not allow. patch = &model.RolePatch{ - Permissions: &[]string{"manage_system", "manage_webhooks"}, + Permissions: &[]string{"manage_system", "manage_incoming_webhooks", "manage_outgoing_webhooks"}, } _, resp = th.SystemAdminClient.PatchRole(role.Id, patch) @@ -209,6 +209,6 @@ func TestPatchRole(t *testing.T) { assert.Equal(t, received.Name, role.Name) assert.Equal(t, received.DisplayName, role.DisplayName) assert.Equal(t, received.Description, role.Description) - assert.EqualValues(t, received.Permissions, []string{"manage_system", "manage_webhooks"}) + assert.EqualValues(t, received.Permissions, []string{"manage_system", "manage_incoming_webhooks", "manage_outgoing_webhooks"}) assert.Equal(t, received.SchemeManaged, role.SchemeManaged) } diff --git a/api4/webhook.go b/api4/webhook.go index 5d0ac2282e..33a7b39797 100644 --- a/api4/webhook.go +++ b/api4/webhook.go @@ -39,8 +39,8 @@ func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("attempt") - if !c.App.SessionHasPermissionToTeam(c.App.Session, channel.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, channel.TeamId, model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) return } @@ -96,14 +96,14 @@ func updateIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionToTeam(c.App.Session, updatedHook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, updatedHook.TeamId, model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) return } - if c.App.Session.UserId != oldHook.UserId && !c.App.SessionHasPermissionToTeam(c.App.Session, updatedHook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) { + if c.App.Session.UserId != oldHook.UserId && !c.App.SessionHasPermissionToTeam(c.App.Session, updatedHook.TeamId, model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS) { c.LogAudit("fail - inappropriate permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS) return } @@ -137,15 +137,15 @@ func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) { var err *model.AppError if len(teamId) > 0 { - if !c.App.SessionHasPermissionToTeam(c.App.Session, teamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, teamId, model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) return } hooks, err = c.App.GetIncomingWebhooksForTeamPage(teamId, c.Params.Page, c.Params.PerPage) } else { - if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) return } @@ -184,16 +184,16 @@ func getIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) || + if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) || (channel.Type != model.CHANNEL_OPEN && !c.App.SessionHasPermissionToChannel(c.App.Session, hook.ChannelId, model.PERMISSION_READ_CHANNEL)) { c.LogAudit("fail - bad permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) return } - if c.App.Session.UserId != hook.UserId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) { + if c.App.Session.UserId != hook.UserId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS) { c.LogAudit("fail - inappropriate permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS) return } @@ -224,16 +224,16 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) || + if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) || (channel.Type != model.CHANNEL_OPEN && !c.App.SessionHasPermissionToChannel(c.App.Session, hook.ChannelId, model.PERMISSION_READ_CHANNEL)) { c.LogAudit("fail - bad permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS) return } - if c.App.Session.UserId != hook.UserId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) { + if c.App.Session.UserId != hook.UserId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS) { c.LogAudit("fail - inappropriate permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS) return } @@ -280,14 +280,14 @@ func updateOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionToTeam(c.App.Session, updatedHook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, updatedHook.TeamId, model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) return } - if c.App.Session.UserId != oldHook.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, updatedHook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) { + if c.App.Session.UserId != oldHook.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, updatedHook.TeamId, model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS) { c.LogAudit("fail - inappropriate permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS) return } @@ -314,8 +314,8 @@ func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { hook.CreatorId = c.App.Session.UserId - if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) return } @@ -339,22 +339,22 @@ func getOutgoingHooks(c *Context, w http.ResponseWriter, r *http.Request) { var err *model.AppError if len(channelId) > 0 { - if !c.App.SessionHasPermissionToChannel(c.App.Session, channelId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToChannel(c.App.Session, channelId, model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) return } hooks, err = c.App.GetOutgoingWebhooksForChannelPage(channelId, c.Params.Page, c.Params.PerPage) } else if len(teamId) > 0 { - if !c.App.SessionHasPermissionToTeam(c.App.Session, teamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, teamId, model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) return } hooks, err = c.App.GetOutgoingWebhooksForTeamPage(teamId, c.Params.Page, c.Params.PerPage) } else { - if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) return } @@ -383,14 +383,14 @@ func getOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("attempt") - if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) return } - if c.App.Session.UserId != hook.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) { + if c.App.Session.UserId != hook.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS) { c.LogAudit("fail - inappropriate permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS) return } @@ -412,14 +412,14 @@ func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request) c.LogAudit("attempt") - if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) return } - if c.App.Session.UserId != hook.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) { + if c.App.Session.UserId != hook.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS) { c.LogAudit("fail - inappropriate permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS) return } @@ -446,14 +446,14 @@ func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("attempt") - if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) { - c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + if !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) { + c.SetPermissionError(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS) return } - if c.App.Session.UserId != hook.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) { + if c.App.Session.UserId != hook.CreatorId && !c.App.SessionHasPermissionToTeam(c.App.Session, hook.TeamId, model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS) { c.LogAudit("fail - inappropriate permissions") - c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_WEBHOOKS) + c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS) return } diff --git a/api4/webhook_test.go b/api4/webhook_test.go index 215c78302a..b6a78e09db 100644 --- a/api4/webhook_test.go +++ b/api4/webhook_test.go @@ -25,8 +25,8 @@ func TestCreateIncomingWebhook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) hook := &model.IncomingWebhook{ChannelId: th.BasicChannel.Id} @@ -58,7 +58,7 @@ func TestCreateIncomingWebhook(t *testing.T) { _, resp = Client.CreateIncomingWebhook(hook) CheckForbiddenStatus(t, resp) - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) _, resp = Client.CreateIncomingWebhook(hook) CheckNoError(t, resp) @@ -85,8 +85,8 @@ func TestGetIncomingWebhooks(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) hook := &model.IncomingWebhook{ChannelId: th.BasicChannel.Id} rhook, resp := th.SystemAdminClient.CreateIncomingWebhook(hook) @@ -137,7 +137,7 @@ func TestGetIncomingWebhooks(t *testing.T) { _, resp = Client.GetIncomingWebhooks(0, 1000, "") CheckForbiddenStatus(t, resp) - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) _, resp = Client.GetIncomingWebhooksForTeam(th.BasicTeam.Id, 0, 1000, "") CheckNoError(t, resp) @@ -254,8 +254,8 @@ func TestCreateOutgoingWebhook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) hook := &model.OutgoingWebhook{ChannelId: th.BasicChannel.Id, TeamId: th.BasicChannel.TeamId, CallbackURLs: []string{"http://nowhere.com"}, Username: "some-user-name", IconURL: "http://some-icon-url/"} @@ -283,7 +283,7 @@ func TestCreateOutgoingWebhook(t *testing.T) { _, resp = Client.CreateOutgoingWebhook(hook) CheckForbiddenStatus(t, resp) - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) _, resp = Client.CreateOutgoingWebhook(hook) CheckNoError(t, resp) @@ -303,8 +303,8 @@ func TestGetOutgoingWebhooks(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) hook := &model.OutgoingWebhook{ChannelId: th.BasicChannel.Id, TeamId: th.BasicChannel.TeamId, CallbackURLs: []string{"http://nowhere.com"}} rhook, resp := th.SystemAdminClient.CreateOutgoingWebhook(hook) @@ -372,7 +372,7 @@ func TestGetOutgoingWebhooks(t *testing.T) { _, resp = Client.GetOutgoingWebhooks(0, 1000, "") CheckForbiddenStatus(t, resp) - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) _, resp = Client.GetOutgoingWebhooksForTeam(th.BasicTeam.Id, 0, 1000, "") CheckNoError(t, resp) @@ -435,8 +435,8 @@ func TestUpdateIncomingHook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) hook1 := &model.IncomingWebhook{ChannelId: th.BasicChannel.Id} @@ -567,11 +567,11 @@ func TestUpdateIncomingHook(t *testing.T) { CheckForbiddenStatus(t, resp) }) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) t.Run("OnlyAdminIntegrationsDisabled", func(t *testing.T) { - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) t.Run("UpdateHookOfSameUser", func(t *testing.T) { sameUserHook := &model.IncomingWebhook{ChannelId: th.BasicChannel.Id, UserId: th.BasicUser2.Id} @@ -589,8 +589,8 @@ func TestUpdateIncomingHook(t *testing.T) { }) }) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) Client.Logout() th.UpdateUserToTeamAdmin(th.BasicUser2, th.BasicTeam) @@ -681,8 +681,8 @@ func TestUpdateOutgoingHook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) createdHook := &model.OutgoingWebhook{ChannelId: th.BasicChannel.Id, TeamId: th.BasicChannel.TeamId, CallbackURLs: []string{"http://nowhere.com"}, TriggerWords: []string{"cats"}} @@ -755,7 +755,7 @@ func TestUpdateOutgoingHook(t *testing.T) { CheckForbiddenStatus(t, resp) }) - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) hook2 := &model.OutgoingWebhook{ChannelId: th.BasicChannel.Id, TeamId: th.BasicChannel.TeamId, CallbackURLs: []string{"http://nowhere.com"}, TriggerWords: []string{"rats2"}} @@ -765,8 +765,8 @@ func TestUpdateOutgoingHook(t *testing.T) { _, resp = Client.UpdateOutgoingWebhook(createdHook2) CheckForbiddenStatus(t, resp) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) Client.Logout() th.UpdateUserToTeamAdmin(th.BasicUser2, th.BasicTeam) diff --git a/app/app_test.go b/app/app_test.go index 1dad5baa71..023f847fea 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -5,6 +5,7 @@ package app import ( "fmt" + "sort" "testing" "github.com/stretchr/testify/assert" @@ -110,10 +111,12 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { 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_OTHERS_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_WEBHOOKS.Id, + model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.PERMISSION_DELETE_POST.Id, model.PERMISSION_DELETE_OTHERS_POSTS.Id, }, @@ -147,7 +150,8 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { 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_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, model.PERMISSION_EDIT_OTHER_USERS.Id, model.PERMISSION_EDIT_OTHERS_POSTS.Id, model.PERMISSION_MANAGE_OAUTH.Id, @@ -187,7 +191,8 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { 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_MANAGE_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.PERMISSION_EDIT_POST.Id, }, } @@ -281,10 +286,12 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { 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_OTHERS_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_WEBHOOKS.Id, + model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, model.PERMISSION_DELETE_POST.Id, @@ -320,7 +327,8 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { 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_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, model.PERMISSION_EDIT_OTHER_USERS.Id, model.PERMISSION_EDIT_OTHERS_POSTS.Id, model.PERMISSION_MANAGE_OAUTH.Id, @@ -360,7 +368,8 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { 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_MANAGE_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.PERMISSION_EDIT_POST.Id, }, } @@ -459,7 +468,8 @@ func TestDoEmojisPermissionsMigration(t *testing.T) { 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_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, model.PERMISSION_EDIT_OTHER_USERS.Id, model.PERMISSION_EDIT_OTHERS_POSTS.Id, model.PERMISSION_MANAGE_OAUTH.Id, @@ -499,14 +509,18 @@ func TestDoEmojisPermissionsMigration(t *testing.T) { 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_MANAGE_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.PERMISSION_EDIT_POST.Id, - model.PERMISSION_MANAGE_EMOJIS.Id, - model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, + model.PERMISSION_CREATE_EMOJIS.Id, + model.PERMISSION_DELETE_EMOJIS.Id, + model.PERMISSION_DELETE_OTHERS_EMOJIS.Id, } + sort.Strings(expectedSystemAdmin) role1, err1 := th.App.GetRoleByName(model.SYSTEM_ADMIN_ROLE_ID) assert.Nil(t, err1) + sort.Strings(role1.Permissions) 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) { @@ -524,18 +538,24 @@ func TestDoEmojisPermissionsMigration(t *testing.T) { 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_OTHERS_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_WEBHOOKS.Id, + model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.PERMISSION_DELETE_POST.Id, model.PERMISSION_DELETE_OTHERS_POSTS.Id, - model.PERMISSION_MANAGE_EMOJIS.Id, + model.PERMISSION_CREATE_EMOJIS.Id, + model.PERMISSION_DELETE_EMOJIS.Id, } + sort.Strings(expected2) + sort.Strings(role2.Permissions) 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) + sort.Strings(systemAdmin1.Permissions) 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) { @@ -552,11 +572,15 @@ func TestDoEmojisPermissionsMigration(t *testing.T) { model.PERMISSION_CREATE_GROUP_CHANNEL.Id, model.PERMISSION_PERMANENT_DELETE_USER.Id, model.PERMISSION_CREATE_TEAM.Id, - model.PERMISSION_MANAGE_EMOJIS.Id, + model.PERMISSION_CREATE_EMOJIS.Id, + model.PERMISSION_DELETE_EMOJIS.Id, } + sort.Strings(expected3) + sort.Strings(role3.Permissions) 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) + sort.Strings(systemAdmin2.Permissions) assert.Equal(t, expectedSystemAdmin, systemAdmin2.Permissions, fmt.Sprintf("'%v' did not have expected permissions", model.SYSTEM_ADMIN_ROLE_ID)) } diff --git a/app/helper_test.go b/app/helper_test.go index 96ce10238c..fe5d400e5d 100644 --- a/app/helper_test.go +++ b/app/helper_test.go @@ -429,7 +429,15 @@ func (me *TestHelper) ResetRoleMigration() { func (me *TestHelper) ResetEmojisMigration() { sqlSupplier := mainHelper.GetSqlSupplier() - if _, err := sqlSupplier.GetMaster().Exec("UPDATE Roles SET Permissions=REPLACE(Permissions, ', manage_emojis', '') WHERE builtin=True"); err != nil { + if _, err := sqlSupplier.GetMaster().Exec("UPDATE Roles SET Permissions=REPLACE(Permissions, ' create_emojis', '') WHERE builtin=True"); err != nil { + panic(err) + } + + if _, err := sqlSupplier.GetMaster().Exec("UPDATE Roles SET Permissions=REPLACE(Permissions, ' delete_emojis', '') WHERE builtin=True"); err != nil { + panic(err) + } + + if _, err := sqlSupplier.GetMaster().Exec("UPDATE Roles SET Permissions=REPLACE(Permissions, ' delete_others_emojis', '') WHERE builtin=True"); err != nil { panic(err) } diff --git a/app/migrations.go b/app/migrations.go index 03423e9bbd..2d668f101f 100644 --- a/app/migrations.go +++ b/app/migrations.go @@ -123,7 +123,7 @@ func (a *App) DoEmojisPermissionsMigration() { } if role != nil { - role.Permissions = append(role.Permissions, model.PERMISSION_MANAGE_EMOJIS.Id) + role.Permissions = append(role.Permissions, model.PERMISSION_CREATE_EMOJIS.Id, model.PERMISSION_DELETE_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()) @@ -138,8 +138,8 @@ func (a *App) DoEmojisPermissionsMigration() { return } - systemAdminRole.Permissions = append(systemAdminRole.Permissions, model.PERMISSION_MANAGE_EMOJIS.Id) - systemAdminRole.Permissions = append(systemAdminRole.Permissions, model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id) + systemAdminRole.Permissions = append(systemAdminRole.Permissions, model.PERMISSION_CREATE_EMOJIS.Id, model.PERMISSION_DELETE_EMOJIS.Id) + systemAdminRole.Permissions = append(systemAdminRole.Permissions, model.PERMISSION_DELETE_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()) diff --git a/app/permissions.go b/app/permissions.go index ca5c8a165e..a05a81a10c 100644 --- a/app/permissions.go +++ b/app/permissions.go @@ -60,6 +60,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() + a.DoPermissionsMigrations() return nil } diff --git a/app/permissions_migrations.go b/app/permissions_migrations.go new file mode 100644 index 0000000000..5f6cf00cfb --- /dev/null +++ b/app/permissions_migrations.go @@ -0,0 +1,163 @@ +// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import "github.com/mattermost/mattermost-server/model" + +type permissionTransformation struct { + On func(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" + + 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" +) + +func permissionExists(permission string) func(map[string]bool) bool { + return func(permissions map[string]bool) bool { + val, ok := permissions[permission] + return ok && val + } +} + +func permissionNotExists(permission string) func(map[string]bool) bool { + return func(permissions map[string]bool) bool { + val, ok := permissions[permission] + return !(ok && val) + } +} + +func permissionOr(funcs ...func(map[string]bool) bool) func(map[string]bool) bool { + return func(permissions map[string]bool) bool { + for _, f := range funcs { + if f(permissions) { + return true + } + } + return false + } +} + +func permissionAnd(funcs ...func(map[string]bool) bool) func(map[string]bool) bool { + return func(permissions map[string]bool) bool { + for _, f := range funcs { + if !f(permissions) { + return false + } + } + return true + } +} + +func applyPermissionsMap(permissions []string, migrationMap permissionsMap) []string { + finalMap := make(map[string]bool) + var result []string + for _, permission := range permissions { + finalMap[permission] = true + } + + for _, transformation := range migrationMap { + if transformation.On(finalMap) { + for _, add := range transformation.Add { + finalMap[add] = true + } + for _, remove := range transformation.Remove { + finalMap[remove] = false + } + } + } + + for key, active := range finalMap { + if active { + result = append(result, key) + } + } + return result +} + +func (a *App) doPermissionsMigration(key string, migrationMap permissionsMap) *model.AppError { + if result := <-a.Srv.Store.System().GetByName(key); result.Err == nil { + return nil + } + + roles, err := a.GetAllRoles() + if err != nil { + return err + } + + for _, role := range roles { + role.Permissions = applyPermissionsMap(role.Permissions, migrationMap) + if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { + return result.Err + } + } + + if result := <-a.Srv.Store.System().Save(&model.System{Name: key, Value: "true"}); result.Err != nil { + return result.Err + } + return nil +} + +func getEmojisPermissionsSplitMigration() permissionsMap { + return permissionsMap{ + permissionTransformation{ + On: permissionExists(PERMISSION_MANAGE_EMOJIS), + Add: []string{PERMISSION_CREATE_EMOJIS, PERMISSION_DELETE_EMOJIS}, + Remove: []string{PERMISSION_MANAGE_EMOJIS}, + }, + permissionTransformation{ + On: permissionExists(PERMISSION_MANAGE_OTHERS_EMOJIS), + Add: []string{PERMISSION_DELETE_OTHERS_EMOJIS}, + Remove: []string{PERMISSION_MANAGE_OTHERS_EMOJIS}, + }, + } +} + +func getWebhooksPermissionsSplitMigration() permissionsMap { + return permissionsMap{ + permissionTransformation{ + On: permissionExists(PERMISSION_MANAGE_WEBHOOKS), + Add: []string{PERMISSION_MANAGE_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OUTGOING_WEBHOOKS}, + Remove: []string{PERMISSION_MANAGE_WEBHOOKS}, + }, + permissionTransformation{ + On: permissionExists(PERMISSION_MANAGE_OTHERS_WEBHOOKS), + Add: []string{PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS}, + Remove: []string{PERMISSION_MANAGE_OTHERS_WEBHOOKS}, + }, + } +} + +// DoPermissionsMigrations execute all the permissions migrations need by the current version. +func (a *App) DoPermissionsMigrations() *model.AppError { + PermissionsMigrations := []struct { + Key string + Migration func() permissionsMap + }{ + {Key: MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT, Migration: getEmojisPermissionsSplitMigration}, + {Key: MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT, Migration: getWebhooksPermissionsSplitMigration}, + } + + for _, migration := range PermissionsMigrations { + if err := a.doPermissionsMigration(migration.Key, migration.Migration()); err != nil { + return err + } + } + return nil +} diff --git a/app/permissions_migrations_test.go b/app/permissions_migrations_test.go new file mode 100644 index 0000000000..d7ece4df3c --- /dev/null +++ b/app/permissions_migrations_test.go @@ -0,0 +1,89 @@ +// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "sort" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestApplyPermissionsMap(t *testing.T) { + tt := []struct { + Name string + Permissions []string + TranslationMap permissionsMap + ExpectedResult []string + }{ + { + "Split existing", + []string{"test1", "test2", "test3"}, + permissionsMap{permissionTransformation{On: permissionExists("test2"), Add: []string{"test4", "test5"}}}, + []string{"test1", "test2", "test3", "test4", "test5"}, + }, + { + "Remove existing", + []string{"test1", "test2", "test3"}, + permissionsMap{permissionTransformation{On: permissionExists("test2"), Remove: []string{"test2"}}}, + []string{"test1", "test3"}, + }, + { + "Rename existing", + []string{"test1", "test2", "test3"}, + permissionsMap{permissionTransformation{On: permissionExists("test2"), Add: []string{"test5"}, Remove: []string{"test2"}}}, + []string{"test1", "test3", "test5"}, + }, + { + "Remove when other not exists", + []string{"test1", "test2", "test3"}, + permissionsMap{permissionTransformation{On: permissionNotExists("test5"), Remove: []string{"test2"}}}, + []string{"test1", "test3"}, + }, + { + "Add when at least one exists", + []string{"test1", "test2", "test3"}, + permissionsMap{permissionTransformation{ + On: permissionOr(permissionExists("test5"), permissionExists("test3")), + Add: []string{"test4"}, + }}, + []string{"test1", "test2", "test3", "test4"}, + }, + { + "Add when all exists", + []string{"test1", "test2", "test3"}, + permissionsMap{permissionTransformation{ + On: permissionAnd(permissionExists("test1"), permissionExists("test2")), + Add: []string{"test4"}, + }}, + []string{"test1", "test2", "test3", "test4"}, + }, + { + "Not add when one in the and not exists", + []string{"test1", "test2", "test3"}, + permissionsMap{permissionTransformation{ + On: permissionAnd(permissionExists("test1"), permissionExists("test5")), + Add: []string{"test4"}, + }}, + []string{"test1", "test2", "test3"}, + }, + { + "Not Add when none on the or exists", + []string{"test1", "test2", "test3"}, + permissionsMap{permissionTransformation{ + On: permissionOr(permissionExists("test7"), permissionExists("test9")), + Add: []string{"test4"}, + }}, + []string{"test1", "test2", "test3"}, + }, + } + + for _, tc := range tt { + t.Run(tc.Name, func(t *testing.T) { + result := applyPermissionsMap(tc.Permissions, tc.TranslationMap) + sort.Strings(result) + assert.Equal(t, tc.ExpectedResult, result) + }) + } +} diff --git a/app/role.go b/app/role.go index 8141575076..8c48775433 100644 --- a/app/role.go +++ b/app/role.go @@ -17,7 +17,14 @@ func (a *App) GetRole(id string) (*model.Role, *model.AppError) { return nil, result.Err } return result.Data.(*model.Role), nil +} +func (a *App) GetAllRoles() ([]*model.Role, *model.AppError) { + result := <-a.Srv.Store.Role().GetAll() + if result.Err != nil { + return nil, result.Err + } + return result.Data.([]*model.Role), nil } func (a *App) GetRoleByName(name string) (*model.Role, *model.AppError) { diff --git a/app/server_app_adapters.go b/app/server_app_adapters.go index dcf9639afb..c721f3bc8d 100644 --- a/app/server_app_adapters.go +++ b/app/server_app_adapters.go @@ -137,6 +137,7 @@ func (s *Server) RunOldAppInitalization() error { s.FakeApp().DoAdvancedPermissionsMigration() s.FakeApp().DoEmojisPermissionsMigration() + s.FakeApp().DoPermissionsMigrations() s.FakeApp().InitPostMetadata() diff --git a/cmd/mattermost/commands/webhook_test.go b/cmd/mattermost/commands/webhook_test.go index 2bd67d11f2..15b791265c 100644 --- a/cmd/mattermost/commands/webhook_test.go +++ b/cmd/mattermost/commands/webhook_test.go @@ -36,8 +36,10 @@ func TestListWebhooks(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) dispName := "myhookinc" hook := &model.IncomingWebhook{DisplayName: dispName, ChannelId: th.BasicChannel.Id, TeamId: th.BasicChannel.TeamId} @@ -83,8 +85,10 @@ func TestShowWebhook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) dispName := "incominghook" hook := &model.IncomingWebhook{ @@ -154,8 +158,8 @@ func TestCreateIncomingWebhook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) // should fail because you need to specify valid channel require.Error(t, th.RunCommand(t, "webhook", "create-incoming")) @@ -206,8 +210,8 @@ func TestModifyIncomingWebhook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) description := "myhookincdesc" displayName := "myhookincname" @@ -269,8 +273,8 @@ func TestCreateOutgoingWebhook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) // team, user, display name, trigger words, callback urls are required team := th.BasicTeam.Id @@ -329,8 +333,8 @@ func TestModifyOutgoingWebhook(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) description := "myhookoutdesc" displayName := "myhookoutname" @@ -438,8 +442,10 @@ func TestDeleteWebhooks(t *testing.T) { defer func() { th.RestoreDefaultRolePermissions(defaultRolePermissions) }() - th.AddPermissionToRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) - th.RemovePermissionFromRole(model.PERMISSION_MANAGE_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) + th.AddPermissionToRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_ADMIN_ROLE_ID) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.TEAM_USER_ROLE_ID) dispName := "myhookinc" inHookStruct := &model.IncomingWebhook{DisplayName: dispName, ChannelId: th.BasicChannel.Id, TeamId: th.BasicChannel.TeamId} diff --git a/model/permission.go b/model/permission.go index 1af25daad1..2c66f33cdd 100644 --- a/model/permission.go +++ b/model/permission.go @@ -46,12 +46,15 @@ var PERMISSION_REMOVE_OTHERS_REACTIONS *Permission var PERMISSION_PERMANENT_DELETE_USER *Permission var PERMISSION_UPLOAD_FILE *Permission var PERMISSION_GET_PUBLIC_LINK *Permission -var PERMISSION_MANAGE_WEBHOOKS *Permission -var PERMISSION_MANAGE_OTHERS_WEBHOOKS *Permission +var PERMISSION_MANAGE_INCOMING_WEBHOOKS *Permission +var PERMISSION_MANAGE_OUTGOING_WEBHOOKS *Permission +var PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS *Permission +var PERMISSION_MANAGE_OTHERS_OUTGOING_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_EMOJIS *Permission +var PERMISSION_DELETE_EMOJIS *Permission +var PERMISSION_DELETE_OTHERS_EMOJIS *Permission var PERMISSION_CREATE_POST *Permission var PERMISSION_CREATE_POST_PUBLIC *Permission var PERMISSION_CREATE_POST_EPHEMERAL *Permission @@ -269,16 +272,28 @@ func initializePermissions() { "authentication.permissions.get_public_link.description", PERMISSION_SCOPE_SYSTEM, } - PERMISSION_MANAGE_WEBHOOKS = &Permission{ - "manage_webhooks", - "authentication.permissions.manage_webhooks.name", - "authentication.permissions.manage_webhooks.description", + PERMISSION_MANAGE_INCOMING_WEBHOOKS = &Permission{ + "manage_incoming_webhooks", + "authentication.permissions.manage_incoming_webhooks.name", + "authentication.permissions.manage_incoming_webhooks.description", PERMISSION_SCOPE_TEAM, } - PERMISSION_MANAGE_OTHERS_WEBHOOKS = &Permission{ - "manage_others_webhooks", - "authentication.permissions.manage_others_webhooks.name", - "authentication.permissions.manage_others_webhooks.description", + PERMISSION_MANAGE_OUTGOING_WEBHOOKS = &Permission{ + "manage_outgoing_webhooks", + "authentication.permissions.manage_outgoing_webhooks.name", + "authentication.permissions.manage_outgoing_webhooks.description", + PERMISSION_SCOPE_TEAM, + } + PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = &Permission{ + "manage_others_incoming_webhooks", + "authentication.permissions.manage_others_incoming_webhooks.name", + "authentication.permissions.manage_others_incoming_webhooks.description", + PERMISSION_SCOPE_TEAM, + } + PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = &Permission{ + "manage_others_outgoing_webhooks", + "authentication.permissions.manage_others_outgoing_webhooks.name", + "authentication.permissions.manage_others_outgoing_webhooks.description", PERMISSION_SCOPE_TEAM, } PERMISSION_MANAGE_OAUTH = &Permission{ @@ -293,16 +308,22 @@ 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_CREATE_EMOJIS = &Permission{ + "create_emojis", + "authentication.permissions.create_emojis.name", + "authentication.permissions.create_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_DELETE_EMOJIS = &Permission{ + "delete_emojis", + "authentication.permissions.delete_emojis.name", + "authentication.permissions.delete_emojis.description", + PERMISSION_SCOPE_TEAM, + } + PERMISSION_DELETE_OTHERS_EMOJIS = &Permission{ + "delete_others_emojis", + "authentication.permissions.delete_others_emojis.name", + "authentication.permissions.delete_others_emojis.description", PERMISSION_SCOPE_TEAM, } PERMISSION_CREATE_POST = &Permission{ @@ -469,12 +490,15 @@ func initializePermissions() { PERMISSION_PERMANENT_DELETE_USER, PERMISSION_UPLOAD_FILE, PERMISSION_GET_PUBLIC_LINK, - PERMISSION_MANAGE_WEBHOOKS, - PERMISSION_MANAGE_OTHERS_WEBHOOKS, + PERMISSION_MANAGE_INCOMING_WEBHOOKS, + PERMISSION_MANAGE_OUTGOING_WEBHOOKS, + PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS, + PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS, PERMISSION_MANAGE_OAUTH, PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH, - PERMISSION_MANAGE_EMOJIS, - PERMISSION_MANAGE_OTHERS_EMOJIS, + PERMISSION_CREATE_EMOJIS, + PERMISSION_DELETE_EMOJIS, + PERMISSION_DELETE_OTHERS_EMOJIS, PERMISSION_CREATE_POST, PERMISSION_CREATE_POST_PUBLIC, PERMISSION_CREATE_POST_EPHEMERAL, diff --git a/model/role.go b/model/role.go index 8fa7c81942..df0eec3e3f 100644 --- a/model/role.go +++ b/model/role.go @@ -248,10 +248,12 @@ func MakeDefaultRoles() map[string]*Role { PERMISSION_IMPORT_TEAM.Id, PERMISSION_MANAGE_TEAM_ROLES.Id, PERMISSION_MANAGE_CHANNEL_ROLES.Id, - PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id, + PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, + PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, PERMISSION_MANAGE_SLASH_COMMANDS.Id, PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, - PERMISSION_MANAGE_WEBHOOKS.Id, + PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, + PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, }, SchemeManaged: true, BuiltIn: true, @@ -329,7 +331,8 @@ func MakeDefaultRoles() map[string]*Role { PERMISSION_DELETE_PRIVATE_CHANNEL.Id, PERMISSION_CREATE_PRIVATE_CHANNEL.Id, PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id, - PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id, + PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, + PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, PERMISSION_EDIT_OTHER_USERS.Id, PERMISSION_EDIT_OTHERS_POSTS.Id, PERMISSION_MANAGE_OAUTH.Id, diff --git a/store/layered_store.go b/store/layered_store.go index 273358612d..d8d2753c1f 100644 --- a/store/layered_store.go +++ b/store/layered_store.go @@ -284,6 +284,12 @@ func (s *LayeredRoleStore) Get(roleId string) StoreChannel { }) } +func (s *LayeredRoleStore) GetAll() StoreChannel { + return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { + return supplier.RoleGetAll(s.TmpContext) + }) +} + func (s *LayeredRoleStore) GetByName(name string) StoreChannel { return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { return supplier.RoleGetByName(s.TmpContext, name) diff --git a/store/layered_store_supplier.go b/store/layered_store_supplier.go index 72ff0bea38..b1b075b5b9 100644 --- a/store/layered_store_supplier.go +++ b/store/layered_store_supplier.go @@ -34,6 +34,7 @@ type LayeredStoreSupplier interface { // Roles RoleSave(ctx context.Context, role *model.Role, hints ...LayeredStoreHint) *LayeredStoreSupplierResult RoleGet(ctx context.Context, roleId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult + RoleGetAll(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult RoleGetByName(ctx context.Context, name string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult RoleGetByNames(ctx context.Context, names []string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult RoleDelete(ctx context.Context, roldId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult diff --git a/store/local_cache_supplier_roles.go b/store/local_cache_supplier_roles.go index 6d8c61a5df..b9a96a8f90 100644 --- a/store/local_cache_supplier_roles.go +++ b/store/local_cache_supplier_roles.go @@ -30,6 +30,12 @@ func (s *LocalCacheSupplier) RoleGet(ctx context.Context, roleId string, hints . return s.Next().RoleGet(ctx, roleId, hints...) } +func (s *LocalCacheSupplier) RoleGetAll(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + // Roles are cached by name, as that is most commonly how they are looked up. + // This means that no caching is supported on roles being listed. + return s.Next().RoleGetAll(ctx, hints...) +} + func (s *LocalCacheSupplier) RoleGetByName(ctx context.Context, name string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { if result := s.doStandardReadCache(ctx, s.roleCache, name, hints...); result != nil { return result diff --git a/store/redis_supplier_roles.go b/store/redis_supplier_roles.go index a445c38a9f..43501f8131 100644 --- a/store/redis_supplier_roles.go +++ b/store/redis_supplier_roles.go @@ -29,6 +29,12 @@ func (s *RedisSupplier) RoleGet(ctx context.Context, roleId string, hints ...Lay return s.Next().RoleGet(ctx, roleId, hints...) } +func (s *RedisSupplier) RoleGetAll(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + // Roles are cached by name, as that is most commonly how they are looked up. + // This means that no caching is supported on roles being listed. + return s.Next().RoleGetAll(ctx, hints...) +} + func (s *RedisSupplier) RoleGetByName(ctx context.Context, name string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { key := buildRedisKeyForRoleName(name) diff --git a/store/sqlstore/role_supplier.go b/store/sqlstore/role_supplier.go index f5ba2a35d3..a3f4f89036 100644 --- a/store/sqlstore/role_supplier.go +++ b/store/sqlstore/role_supplier.go @@ -160,6 +160,28 @@ func (s *SqlSupplier) RoleGet(ctx context.Context, roleId string, hints ...store return result } +func (s *SqlSupplier) RoleGetAll(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + result := store.NewSupplierResult() + + var dbRoles []Role + + if _, err := s.GetReplica().Select(&dbRoles, "SELECT * from Roles", map[string]interface{}{}); err != nil { + if err == sql.ErrNoRows { + result.Err = model.NewAppError("SqlRoleStore.GetAll", "store.sql_role.get_all.app_error", nil, err.Error(), http.StatusNotFound) + } else { + result.Err = model.NewAppError("SqlRoleStore.GetAll", "store.sql_role.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) + } + } + + var roles []*model.Role + for _, dbRole := range dbRoles { + roles = append(roles, dbRole.ToModel()) + } + result.Data = roles + + return result +} + func (s *SqlSupplier) RoleGetByName(ctx context.Context, name string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { result := store.NewSupplierResult() diff --git a/store/store.go b/store/store.go index 306a370066..d24bbacb7b 100644 --- a/store/store.go +++ b/store/store.go @@ -523,6 +523,7 @@ type PluginStore interface { type RoleStore interface { Save(role *model.Role) StoreChannel Get(roleId string) StoreChannel + GetAll() StoreChannel GetByName(name string) StoreChannel GetByNames(names []string) StoreChannel Delete(roldId string) StoreChannel diff --git a/store/storetest/mocks/LayeredStoreDatabaseLayer.go b/store/storetest/mocks/LayeredStoreDatabaseLayer.go index e1fbea7b4b..cb39241e64 100644 --- a/store/storetest/mocks/LayeredStoreDatabaseLayer.go +++ b/store/storetest/mocks/LayeredStoreDatabaseLayer.go @@ -968,6 +968,29 @@ func (_m *LayeredStoreDatabaseLayer) RoleGet(ctx context.Context, roleId string, return r0 } +// RoleGetAll provides a mock function with given fields: ctx, hints +func (_m *LayeredStoreDatabaseLayer) RoleGetAll(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + // RoleGetByName provides a mock function with given fields: ctx, name, hints func (_m *LayeredStoreDatabaseLayer) RoleGetByName(ctx context.Context, name string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) diff --git a/store/storetest/mocks/LayeredStoreSupplier.go b/store/storetest/mocks/LayeredStoreSupplier.go index efcb1dbdb3..e6cec590f7 100644 --- a/store/storetest/mocks/LayeredStoreSupplier.go +++ b/store/storetest/mocks/LayeredStoreSupplier.go @@ -628,6 +628,29 @@ func (_m *LayeredStoreSupplier) RoleGet(ctx context.Context, roleId string, hint return r0 } +// RoleGetAll provides a mock function with given fields: ctx, hints +func (_m *LayeredStoreSupplier) RoleGetAll(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + // RoleGetByName provides a mock function with given fields: ctx, name, hints func (_m *LayeredStoreSupplier) RoleGetByName(ctx context.Context, name string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) diff --git a/store/storetest/mocks/RoleStore.go b/store/storetest/mocks/RoleStore.go index 95e1914e03..c835e40f55 100644 --- a/store/storetest/mocks/RoleStore.go +++ b/store/storetest/mocks/RoleStore.go @@ -45,6 +45,22 @@ func (_m *RoleStore) Get(roleId string) store.StoreChannel { return r0 } +// GetAll provides a mock function with given fields: +func (_m *RoleStore) GetAll() store.StoreChannel { + ret := _m.Called() + + var r0 store.StoreChannel + if rf, ok := ret.Get(0).(func() store.StoreChannel); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(store.StoreChannel) + } + } + + return r0 +} + // GetByName provides a mock function with given fields: name func (_m *RoleStore) GetByName(name string) store.StoreChannel { ret := _m.Called(name) diff --git a/store/storetest/role_store.go b/store/storetest/role_store.go index 1618b6c6d5..d95a3697cd 100644 --- a/store/storetest/role_store.go +++ b/store/storetest/role_store.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/store" @@ -15,6 +16,7 @@ import ( func TestRoleStore(t *testing.T, ss store.Store) { t.Run("Save", func(t *testing.T) { testRoleStoreSave(t, ss) }) t.Run("Get", func(t *testing.T) { testRoleStoreGet(t, ss) }) + t.Run("GetAll", func(t *testing.T) { testRoleStoreGetAll(t, ss) }) t.Run("GetByName", func(t *testing.T) { testRoleStoreGetByName(t, ss) }) t.Run("GetNames", func(t *testing.T) { testRoleStoreGetByNames(t, ss) }) t.Run("Delete", func(t *testing.T) { testRoleStoreDelete(t, ss) }) @@ -96,6 +98,47 @@ func testRoleStoreSave(t *testing.T, ss store.Store) { assert.NotNil(t, res4.Err) } +func testRoleStoreGetAll(t *testing.T, ss store.Store) { + prev := <-ss.Role().GetAll() + require.Nil(t, prev.Err) + prevCount := len(prev.Data.([]*model.Role)) + + // Save a role to test with. + r1 := &model.Role{ + Name: model.NewId(), + DisplayName: model.NewId(), + Description: model.NewId(), + Permissions: []string{ + "invite_user", + "create_public_channel", + "add_user_to_team", + }, + SchemeManaged: false, + } + + res1 := <-ss.Role().Save(r1) + require.Nil(t, res1.Err) + + r2 := &model.Role{ + Name: model.NewId(), + DisplayName: model.NewId(), + Description: model.NewId(), + Permissions: []string{ + "invite_user", + "create_public_channel", + "add_user_to_team", + }, + SchemeManaged: false, + } + res2 := <-ss.Role().Save(r2) + require.Nil(t, res2.Err) + + res3 := <-ss.Role().GetAll() + require.Nil(t, res3.Err) + data := res3.Data.([]*model.Role) + assert.Len(t, data, prevCount+2) +} + func testRoleStoreGet(t *testing.T, ss store.Store) { // Save a role to test with. r1 := &model.Role{ diff --git a/utils/authorization.go b/utils/authorization.go index 45efc4d124..d08f885bc3 100644 --- a/utils/authorization.go +++ b/utils/authorization.go @@ -197,7 +197,8 @@ func SetRolePermissionsFromConfig(roles map[string]*model.Role, cfg *model.Confi if !*cfg.ServiceSettings.DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations { roles[model.TEAM_USER_ROLE_ID].Permissions = append( roles[model.TEAM_USER_ROLE_ID].Permissions, - model.PERMISSION_MANAGE_WEBHOOKS.Id, + model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, + model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, ) roles[model.SYSTEM_USER_ROLE_ID].Permissions = append( diff --git a/utils/policies-roles-mapping.json b/utils/policies-roles-mapping.json index 6b09c6c727..f2c99d8f1b 100644 --- a/utils/policies-roles-mapping.json +++ b/utils/policies-roles-mapping.json @@ -497,7 +497,12 @@ "true": [ { "roleName": "team_user", - "permission": "manage_webhooks", + "permission": "manage_incoming_webhooks", + "shouldHave": false + }, + { + "roleName": "team_user", + "permission": "manage_outgoing_webhooks", "shouldHave": false }, { @@ -514,7 +519,12 @@ "false": [ { "roleName": "team_user", - "permission": "manage_webhooks", + "permission": "manage_incoming_webhooks", + "shouldHave": true + }, + { + "roleName": "team_user", + "permission": "manage_outgoing_webhooks", "shouldHave": true }, {