Channel metadata visible in archived channels despite configuration setting
Description
Mattermost versions 10.5.x <= 10.5.1, 10.4.x <= 10.4.3, 9.11.x <= 9.11.9 fail to check the "Allow Users to View Archived Channels" configuration when fetching channel metadata of a post from archived channels, which allows authenticated users to access such information when a channel is archived.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/mattermost/mattermost/server/v8Go | >= 10.5.0, < 10.5.2 | 10.5.2 |
github.com/mattermost/mattermost/server/v8Go | >= 10.4.0, < 10.4.4 | 10.4.4 |
github.com/mattermost/mattermost/server/v8Go | >= 9.11.0, < 9.11.10 | 9.11.10 |
github.com/mattermost/mattermost/server/v8Go | < 8.0.0-20250314142426-c049748b8863 | 8.0.0-20250314142426-c049748b8863 |
Affected products
1- Range: 10.5.0
Patches
5c6f6b6648117[MM-62798][MM-63193] Restrict channel permissions on archived channels when viewing archived channels is disabled (#30314) (#30376)
2 files changed · +126 −17
server/channels/app/authorization.go+36 −17 modified@@ -82,6 +82,19 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session return false } + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil && appErr.StatusCode == http.StatusNotFound { + return false + } + + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + + if a.isChannelArchivedAndHidden(channel) { + return false + } + ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(c, session.UserId, true, true) var channelRoles []string if err == nil { @@ -93,15 +106,6 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session } } - channel, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { - return false - } - - if session.IsUnrestricted() { - return true - } - if appErr == nil && channel.TeamId != "" { return a.SessionHasPermissionToTeam(session, channel.TeamId, permission) } @@ -115,22 +119,32 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio return true } + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + for _, channelID := range channelIDs { if channelID == "" { return false } - } - // if System Roles (ie. Admin, TeamAdmin) allow permissions - // if so, no reason to check team - if a.SessionHasPermissionTo(session, permission) { // make sure all channels exist, otherwise return false. for _, channelID := range channelIDs { - _, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil { + return false + } + + // if any channel is archived and the user doesn't have permission to view archived channels, return false + if a.isChannelArchivedAndHidden(channel) { return false } } + } + + // if System Roles (ie. Admin, TeamAdmin) allow permissions + // if so, no reason to check team + if a.SessionHasPermissionTo(session, permission) { return true } @@ -148,6 +162,7 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio } return false } + return true } @@ -389,7 +404,7 @@ func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Ses } func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -404,7 +419,7 @@ func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel * } func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -417,3 +432,7 @@ func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, ch return false } + +func (a *App) isChannelArchivedAndHidden(channel *model.Channel) bool { + return !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 +}
server/channels/app/authorization_test.go+90 −0 modified@@ -140,6 +140,24 @@ func TestSessionHasPermissionToChannel(t *testing.T) { assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionAddReaction)) }) + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + t.Run("does not panic if fetching channel causes an error", func(t *testing.T) { // Regression test for MM-29812 // Mock the channel store so getting the channel returns with an error, as per the bug report. @@ -203,6 +221,78 @@ func TestSessionHasPermissionToChannels(t *testing.T) { assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, allChannels, model.PermissionReadChannel)) }) + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access mixed archived and non-archived channels if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + + t.Run("basic user can access mixed archived and non-archived channels if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + t.Run("System Admins can access basic channels", func(t *testing.T) { session := model.Session{ UserId: th.SystemAdminUser.Id,
ae8a952bcaaa[MM-62798][MM-63193] Restrict channel permissions on archived channels when viewing archived channels is disabled (#30314) (#30375)
2 files changed · +126 −17
server/channels/app/authorization.go+36 −17 modified@@ -82,6 +82,19 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session return false } + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil && appErr.StatusCode == http.StatusNotFound { + return false + } + + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + + if a.isChannelArchivedAndHidden(channel) { + return false + } + ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(c, session.UserId, true, true) var channelRoles []string if err == nil { @@ -93,15 +106,6 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session } } - channel, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { - return false - } - - if session.IsUnrestricted() { - return true - } - if appErr == nil && channel.TeamId != "" { return a.SessionHasPermissionToTeam(session, channel.TeamId, permission) } @@ -115,22 +119,32 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio return true } + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + for _, channelID := range channelIDs { if channelID == "" { return false } - } - // if System Roles (ie. Admin, TeamAdmin) allow permissions - // if so, no reason to check team - if a.SessionHasPermissionTo(session, permission) { // make sure all channels exist, otherwise return false. for _, channelID := range channelIDs { - _, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil { + return false + } + + // if any channel is archived and the user doesn't have permission to view archived channels, return false + if a.isChannelArchivedAndHidden(channel) { return false } } + } + + // if System Roles (ie. Admin, TeamAdmin) allow permissions + // if so, no reason to check team + if a.SessionHasPermissionTo(session, permission) { return true } @@ -148,6 +162,7 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio } return false } + return true } @@ -389,7 +404,7 @@ func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Ses } func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -404,7 +419,7 @@ func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel * } func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -417,3 +432,7 @@ func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, ch return false } + +func (a *App) isChannelArchivedAndHidden(channel *model.Channel) bool { + return !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 +}
server/channels/app/authorization_test.go+90 −0 modified@@ -140,6 +140,24 @@ func TestSessionHasPermissionToChannel(t *testing.T) { assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionAddReaction)) }) + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + t.Run("does not panic if fetching channel causes an error", func(t *testing.T) { // Regression test for MM-29812 // Mock the channel store so getting the channel returns with an error, as per the bug report. @@ -203,6 +221,78 @@ func TestSessionHasPermissionToChannels(t *testing.T) { assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, allChannels, model.PermissionReadChannel)) }) + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access mixed archived and non-archived channels if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + + t.Run("basic user can access mixed archived and non-archived channels if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + t.Run("System Admins can access basic channels", func(t *testing.T) { session := model.Session{ UserId: th.SystemAdminUser.Id,
8e82d8df6106[MM-62798][MM-63193] Restrict channel permissions on archived channels when viewing archived channels is disabled (#30314) (#30374)
2 files changed · +126 −17
server/channels/app/authorization.go+36 −17 modified@@ -82,6 +82,19 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session return false } + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil && appErr.StatusCode == http.StatusNotFound { + return false + } + + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + + if a.isChannelArchivedAndHidden(channel) { + return false + } + ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(c, session.UserId, true, true) var channelRoles []string if err == nil { @@ -93,15 +106,6 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session } } - channel, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { - return false - } - - if session.IsUnrestricted() { - return true - } - if appErr == nil && channel.TeamId != "" { return a.SessionHasPermissionToTeam(session, channel.TeamId, permission) } @@ -115,22 +119,32 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio return true } + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + for _, channelID := range channelIDs { if channelID == "" { return false } - } - // if System Roles (ie. Admin, TeamAdmin) allow permissions - // if so, no reason to check team - if a.SessionHasPermissionTo(session, permission) { // make sure all channels exist, otherwise return false. for _, channelID := range channelIDs { - _, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil { + return false + } + + // if any channel is archived and the user doesn't have permission to view archived channels, return false + if a.isChannelArchivedAndHidden(channel) { return false } } + } + + // if System Roles (ie. Admin, TeamAdmin) allow permissions + // if so, no reason to check team + if a.SessionHasPermissionTo(session, permission) { return true } @@ -148,6 +162,7 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio } return false } + return true } @@ -389,7 +404,7 @@ func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Ses } func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -404,7 +419,7 @@ func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel * } func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -417,3 +432,7 @@ func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, ch return false } + +func (a *App) isChannelArchivedAndHidden(channel *model.Channel) bool { + return !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 +}
server/channels/app/authorization_test.go+90 −0 modified@@ -140,6 +140,24 @@ func TestSessionHasPermissionToChannel(t *testing.T) { assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionAddReaction)) }) + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + t.Run("does not panic if fetching channel causes an error", func(t *testing.T) { // Regression test for MM-29812 // Mock the channel store so getting the channel returns with an error, as per the bug report. @@ -203,6 +221,78 @@ func TestSessionHasPermissionToChannels(t *testing.T) { assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, allChannels, model.PermissionReadChannel)) }) + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access mixed archived and non-archived channels if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + + t.Run("basic user can access mixed archived and non-archived channels if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + t.Run("System Admins can access basic channels", func(t *testing.T) { session := model.Session{ UserId: th.SystemAdminUser.Id,
629f68a85dd6[MM-62798][MM-63193] Restrict channel permissions on archived channels when viewing archived channels is disabled (#30314) (#30378)
2 files changed · +126 −17
server/channels/app/authorization.go+36 −17 modified@@ -82,6 +82,19 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session return false } + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil && appErr.StatusCode == http.StatusNotFound { + return false + } + + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + + if a.isChannelArchivedAndHidden(channel) { + return false + } + ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(c, session.UserId, true, true) var channelRoles []string if err == nil { @@ -93,15 +106,6 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session } } - channel, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { - return false - } - - if session.IsUnrestricted() { - return true - } - if appErr == nil && channel.TeamId != "" { return a.SessionHasPermissionToTeam(session, channel.TeamId, permission) } @@ -115,22 +119,32 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio return true } + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + for _, channelID := range channelIDs { if channelID == "" { return false } - } - // if System Roles (ie. Admin, TeamAdmin) allow permissions - // if so, no reason to check team - if a.SessionHasPermissionTo(session, permission) { // make sure all channels exist, otherwise return false. for _, channelID := range channelIDs { - _, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil { + return false + } + + // if any channel is archived and the user doesn't have permission to view archived channels, return false + if a.isChannelArchivedAndHidden(channel) { return false } } + } + + // if System Roles (ie. Admin, TeamAdmin) allow permissions + // if so, no reason to check team + if a.SessionHasPermissionTo(session, permission) { return true } @@ -148,6 +162,7 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio } return false } + return true } @@ -389,7 +404,7 @@ func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Ses } func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -404,7 +419,7 @@ func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel * } func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -417,3 +432,7 @@ func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, ch return false } + +func (a *App) isChannelArchivedAndHidden(channel *model.Channel) bool { + return !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 +}
server/channels/app/authorization_test.go+90 −0 modified@@ -140,6 +140,24 @@ func TestSessionHasPermissionToChannel(t *testing.T) { assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionAddReaction)) }) + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + t.Run("does not panic if fetching channel causes an error", func(t *testing.T) { // Regression test for MM-29812 // Mock the channel store so getting the channel returns with an error, as per the bug report. @@ -200,6 +218,78 @@ func TestSessionHasPermissionToChannels(t *testing.T) { assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, allChannels, model.PermissionReadChannel)) }) + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access mixed archived and non-archived channels if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + + t.Run("basic user can access mixed archived and non-archived channels if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + t.Run("System Admins can access basic channels", func(t *testing.T) { session := model.Session{ UserId: th.SystemAdminUser.Id,
341186355d98[MM-62798][MM-63193] Restrict channel permissions on archived channels when viewing archived channels is disabled (#30314)
2 files changed · +126 −17
server/channels/app/authorization.go+36 −17 modified@@ -82,6 +82,19 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session return false } + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil && appErr.StatusCode == http.StatusNotFound { + return false + } + + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + + if a.isChannelArchivedAndHidden(channel) { + return false + } + ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(c, session.UserId, true, true) var channelRoles []string if err == nil { @@ -93,15 +106,6 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session } } - channel, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { - return false - } - - if session.IsUnrestricted() { - return true - } - if appErr == nil && channel.TeamId != "" { return a.SessionHasPermissionToTeam(session, channel.TeamId, permission) } @@ -115,22 +119,32 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio return true } + if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) { + return true + } + for _, channelID := range channelIDs { if channelID == "" { return false } - } - // if System Roles (i.e. Admin, TeamAdmin) allow permissions - // if so, no reason to check team - if a.SessionHasPermissionTo(session, permission) { // make sure all channels exist, otherwise return false. for _, channelID := range channelIDs { - _, appErr := a.GetChannel(c, channelID) - if appErr != nil && appErr.StatusCode == http.StatusNotFound { + channel, appErr := a.GetChannel(c, channelID) + if appErr != nil { + return false + } + + // if any channel is archived and the user doesn't have permission to view archived channels, return false + if a.isChannelArchivedAndHidden(channel) { return false } } + } + + // if System Roles (i.e. Admin, TeamAdmin) allow permissions + // if so, no reason to check team + if a.SessionHasPermissionTo(session, permission) { return true } @@ -148,6 +162,7 @@ func (a *App) SessionHasPermissionToChannels(c request.CTX, session model.Sessio } return false } + return true } @@ -389,7 +404,7 @@ func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Ses } func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -404,7 +419,7 @@ func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel * } func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, channel *model.Channel) bool { - if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 { + if a.isChannelArchivedAndHidden(channel) { return false } if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) { @@ -417,3 +432,7 @@ func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, ch return false } + +func (a *App) isChannelArchivedAndHidden(channel *model.Channel) bool { + return !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 +}
server/channels/app/authorization_test.go+90 −0 modified@@ -140,6 +140,24 @@ func TestSessionHasPermissionToChannel(t *testing.T) { assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionAddReaction)) }) + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + err := th.App.DeleteChannel(th.Context, th.BasicChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, th.BasicChannel.Id, model.PermissionReadChannel)) + }) + t.Run("does not panic if fetching channel causes an error", func(t *testing.T) { // Regression test for MM-29812 // Mock the channel store so getting the channel returns with an error, as per the bug report. @@ -203,6 +221,78 @@ func TestSessionHasPermissionToChannels(t *testing.T) { assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, allChannels, model.PermissionReadChannel)) }) + t.Run("basic user can access archived channel if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access archived channel if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + newChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, newChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, newChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, []string{newChannel.Id}, model.PermissionReadChannel)) + }) + + t.Run("basic user cannot access mixed archived and non-archived channels if setting is off", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = false + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.False(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + + t.Run("basic user can access mixed archived and non-archived channels if setting is on", func(t *testing.T) { + session := model.Session{ + UserId: th.BasicUser.Id, + } + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.TeamSettings.ExperimentalViewArchivedChannels = true + }) + + archivedChannel := th.CreateChannel(th.Context, th.BasicTeam) + _, appErr := th.App.AddUserToChannel(th.Context, th.BasicUser, archivedChannel, false) + assert.Nil(t, appErr) + + err := th.App.DeleteChannel(th.Context, archivedChannel, th.SystemAdminUser.Id) + require.Nil(t, err) + + mixedChannels := []string{th.BasicChannel.Id, archivedChannel.Id} + assert.True(t, th.App.SessionHasPermissionToChannels(th.Context, session, mixedChannels, model.PermissionReadChannel)) + }) + t.Run("System Admins can access basic channels", func(t *testing.T) { session := model.Session{ UserId: th.SystemAdminUser.Id,
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
9- github.com/advisories/GHSA-h4rr-f37j-4hh7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-27571ghsaADVISORY
- github.com/mattermost/mattermost/commit/341186355d982ac4cbe37668d7cdb0cf6275fe44ghsaWEB
- github.com/mattermost/mattermost/commit/629f68a85dd6ed5ba0c51a9356c3a3200f50657fghsaWEB
- github.com/mattermost/mattermost/commit/8e82d8df61068fc56b0f3e51ef1cc947bc87cec1ghsaWEB
- github.com/mattermost/mattermost/commit/ae8a952bcaaa5f77a92043e2538f625eac72e927ghsaWEB
- github.com/mattermost/mattermost/commit/c6f6b664811795f36b9cf05b0e2b537c44c65bc1ghsaWEB
- mattermost.com/security-updatesghsaWEB
- pkg.go.dev/vuln/GO-2025-3619ghsaWEB
News mentions
0No linked articles in our index yet.