MM-60240 Sanitize Channels based on user permissions (#28086)
* initial commit * add unit tests * update tests, self review * update tests to verify something returned. * update app-layer * update unit tests * fix tests * add check for PermissionSysconsoleReadComplianceDataRetentionPolicy * revert package-lock * review suggestions --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d99961f106
Коммит
c12e6d9e9c
@@ -793,8 +793,9 @@ func getPinnedPosts(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func getAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
permissions := []*model.Permission{
|
permissions := []*model.Permission{
|
||||||
model.PermissionSysconsoleReadUserManagementGroups,
|
model.PermissionSysconsoleWriteUserManagementGroups,
|
||||||
model.PermissionSysconsoleReadUserManagementChannels,
|
model.PermissionSysconsoleReadUserManagementChannels,
|
||||||
|
model.PermissionSysconsoleReadComplianceDataRetentionPolicy,
|
||||||
}
|
}
|
||||||
if !c.App.SessionHasPermissionToAny(*c.AppContext.Session(), permissions) {
|
if !c.App.SessionHasPermissionToAny(*c.AppContext.Session(), permissions) {
|
||||||
c.SetPermissionError(permissions...)
|
c.SetPermissionError(permissions...)
|
||||||
@@ -822,6 +823,8 @@ func getAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channels = sanitizeAllChannelsResponse(c, channels)
|
||||||
|
|
||||||
if c.Params.IncludeTotalCount {
|
if c.Params.IncludeTotalCount {
|
||||||
totalCount, err := c.App.GetAllChannelsCount(c.AppContext, opts)
|
totalCount, err := c.App.GetAllChannelsCount(c.AppContext, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -843,6 +846,18 @@ func getAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sanitizeAllChannelsResponse(c *Context, channels model.ChannelListWithTeamData) model.ChannelListWithTeamData {
|
||||||
|
if !c.App.SessionHasPermissionToAny(*c.AppContext.Session(), []*model.Permission{
|
||||||
|
model.PermissionSysconsoleReadComplianceDataRetentionPolicy,
|
||||||
|
model.PermissionSysconsoleReadUserManagementChannels,
|
||||||
|
}) {
|
||||||
|
for _, channel := range channels {
|
||||||
|
channel.Channel = channel.Channel.Sanitize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return channels
|
||||||
|
}
|
||||||
|
|
||||||
func getPublicChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getPublicChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
c.RequireTeamId()
|
c.RequireTeamId()
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
@@ -1256,7 +1271,12 @@ func searchAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadUserManagementChannels) {
|
if !c.App.SessionHasPermissionToAny(*c.AppContext.Session(),
|
||||||
|
[]*model.Permission{
|
||||||
|
model.PermissionSysconsoleWriteUserManagementGroups,
|
||||||
|
model.PermissionSysconsoleReadUserManagementChannels,
|
||||||
|
model.PermissionSysconsoleReadComplianceDataRetentionPolicy,
|
||||||
|
}) {
|
||||||
c.SetPermissionError(model.PermissionSysconsoleReadUserManagementChannels)
|
c.SetPermissionError(model.PermissionSysconsoleReadUserManagementChannels)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1288,6 +1308,8 @@ func searchAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channels = sanitizeAllChannelsResponse(c, channels)
|
||||||
|
|
||||||
// Don't fill in channels props, since unused by client and potentially expensive.
|
// Don't fill in channels props, since unused by client and potentially expensive.
|
||||||
if props.Page != nil && props.PerPage != nil {
|
if props.Page != nil && props.PerPage != nil {
|
||||||
data := model.ChannelsWithCount{Channels: channels, TotalCount: totalCount}
|
data := model.ChannelsWithCount{Channels: channels, TotalCount: totalCount}
|
||||||
|
|||||||
@@ -1404,6 +1404,40 @@ func TestGetAllChannels(t *testing.T) {
|
|||||||
}
|
}
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("verify correct sanitization", func(t *testing.T) {
|
||||||
|
channels, resp, err := th.SystemAdminClient.GetAllChannels(context.Background(), 0, 10000, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
require.True(t, len(channels) > 0)
|
||||||
|
for _, channel := range channels {
|
||||||
|
if channel.DisplayName != "Off-Topic" && channel.DisplayName != "Town Square" {
|
||||||
|
require.NotEqual(t, "", channel.CreatorId)
|
||||||
|
require.NotEqual(t, "", channel.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
channels, resp, err = th.SystemManagerClient.GetAllChannels(context.Background(), 0, 10000, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
require.True(t, len(channels) > 0)
|
||||||
|
for _, channel := range channels {
|
||||||
|
if channel.DisplayName != "Off-Topic" && channel.DisplayName != "Town Square" {
|
||||||
|
require.NotEqual(t, "", channel.CreatorId)
|
||||||
|
require.NotEqual(t, "", channel.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th.RemovePermissionFromRole(model.PermissionSysconsoleReadUserManagementChannels.Id, model.SystemManagerRoleId)
|
||||||
|
channels, resp, err = th.SystemManagerClient.GetAllChannels(context.Background(), 0, 10000, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
require.True(t, len(channels) > 0)
|
||||||
|
for _, channel := range channels {
|
||||||
|
require.Equal(t, "", channel.CreatorId)
|
||||||
|
require.Equal(t, "", channel.Name)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAllChannelsWithCount(t *testing.T) {
|
func TestGetAllChannelsWithCount(t *testing.T) {
|
||||||
@@ -1887,6 +1921,40 @@ func TestSearchAllChannels(t *testing.T) {
|
|||||||
}
|
}
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("verify correct sanitization", func(t *testing.T) {
|
||||||
|
channels, resp, err := th.SystemAdminClient.SearchAllChannels(context.Background(), &model.ChannelSearch{Term: ""})
|
||||||
|
require.NoError(t, err)
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
require.True(t, len(channels) > 0)
|
||||||
|
for _, channel := range channels {
|
||||||
|
if channel.DisplayName != "Off-Topic" && channel.DisplayName != "Town Square" {
|
||||||
|
require.NotEqual(t, "", channel.CreatorId)
|
||||||
|
require.NotEqual(t, "", channel.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
channels, resp, err = th.SystemManagerClient.SearchAllChannels(context.Background(), &model.ChannelSearch{Term: ""})
|
||||||
|
require.NoError(t, err)
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
require.True(t, len(channels) > 0)
|
||||||
|
for _, channel := range channels {
|
||||||
|
if channel.DisplayName != "Off-Topic" && channel.DisplayName != "Town Square" {
|
||||||
|
require.NotEqual(t, "", channel.CreatorId)
|
||||||
|
require.NotEqual(t, "", channel.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th.RemovePermissionFromRole(model.PermissionSysconsoleReadUserManagementChannels.Id, model.SystemManagerRoleId)
|
||||||
|
channels, resp, err = th.SystemManagerClient.SearchAllChannels(context.Background(), &model.ChannelSearch{Term: ""})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, len(channels) > 0)
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
for _, channel := range channels {
|
||||||
|
require.Equal(t, "", channel.CreatorId)
|
||||||
|
require.Equal(t, "", channel.Name)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSearchAllChannelsPaged(t *testing.T) {
|
func TestSearchAllChannelsPaged(t *testing.T) {
|
||||||
|
|||||||
@@ -356,6 +356,15 @@ func (o *Channel) GetOtherUserIdForDM(userId string) string {
|
|||||||
return otherUserId
|
return otherUserId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Channel) Sanitize() Channel {
|
||||||
|
return Channel{
|
||||||
|
Id: o.Id,
|
||||||
|
TeamId: o.TeamId,
|
||||||
|
Type: o.Type,
|
||||||
|
DisplayName: o.DisplayName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t ChannelType) MarshalJSON() ([]byte, error) {
|
func (t ChannelType) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(string(t))
|
return json.Marshal(string(t))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,3 +114,49 @@ func TestGetGroupNameFromUserIds(t *testing.T) {
|
|||||||
|
|
||||||
require.LessOrEqual(t, len(name), ChannelNameMaxLength)
|
require.LessOrEqual(t, len(name), ChannelNameMaxLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSanitize(t *testing.T) {
|
||||||
|
schemaId := NewId()
|
||||||
|
o := Channel{
|
||||||
|
Id: NewId(),
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 1,
|
||||||
|
DeleteAt: 1,
|
||||||
|
Name: NewId(),
|
||||||
|
DisplayName: NewId(),
|
||||||
|
Header: NewId(),
|
||||||
|
Purpose: NewId(),
|
||||||
|
LastPostAt: 1,
|
||||||
|
TotalMsgCount: 1,
|
||||||
|
ExtraUpdateAt: 1,
|
||||||
|
CreatorId: NewId(),
|
||||||
|
SchemeId: &schemaId,
|
||||||
|
Props: make(map[string]any),
|
||||||
|
GroupConstrained: NewPointer(true),
|
||||||
|
Shared: NewPointer(true),
|
||||||
|
TotalMsgCountRoot: 1,
|
||||||
|
PolicyID: &schemaId,
|
||||||
|
LastRootPostAt: 1,
|
||||||
|
}
|
||||||
|
s := o.Sanitize()
|
||||||
|
|
||||||
|
require.NotEqual(t, "", s.Id)
|
||||||
|
require.Equal(t, int64(0), s.CreateAt)
|
||||||
|
require.Equal(t, int64(0), s.UpdateAt)
|
||||||
|
require.Equal(t, int64(0), s.DeleteAt)
|
||||||
|
require.Equal(t, "", s.Name)
|
||||||
|
require.NotEqual(t, "", s.DisplayName)
|
||||||
|
require.Equal(t, "", s.Header)
|
||||||
|
require.Equal(t, "", s.Purpose)
|
||||||
|
require.Equal(t, int64(0), s.LastPostAt)
|
||||||
|
require.Equal(t, int64(0), s.TotalMsgCount)
|
||||||
|
require.Equal(t, int64(0), s.ExtraUpdateAt)
|
||||||
|
require.Equal(t, "", s.CreatorId)
|
||||||
|
require.Nil(t, s.SchemeId)
|
||||||
|
require.Nil(t, s.Props)
|
||||||
|
require.Nil(t, s.GroupConstrained)
|
||||||
|
require.Nil(t, s.Shared)
|
||||||
|
require.Equal(t, int64(0), s.TotalMsgCountRoot)
|
||||||
|
require.Nil(t, s.PolicyID)
|
||||||
|
require.Equal(t, int64(0), s.LastRootPostAt)
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user