Manual Cherrypick: Add audits for accessing posts without membership (#31266) (#35022)

Automatic Merge
Этот коммит содержится в:
Daniel Espino García
2026-01-26 11:23:28 +01:00
коммит произвёл GitHub
родитель 12dce033d6
Коммит 21a86506f9
79 изменённых файлов: 1707 добавлений и 1001 удалений

Просмотреть файл

@@ -91,42 +91,52 @@ func (a *App) SessionHasPermissionToTeams(c request.CTX, session model.Session,
return true
}
func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session, channelID string, permission *model.Permission) bool {
// SessionHasPermissionToChannel checks if the session has permission to the given channel.
//
// Returns:
//
// (hasPermission, isMember)
//
// hasPermission: true if the user has the specified permission for the channel, otherwise false.
// isMember: used for auditing access without membership. True if the user is a member of the channel, otherwise false.
func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session, channelID string, permission *model.Permission) (hasPermission bool, isMember bool) {
if channelID == "" {
return false
return false, false
}
channel, appErr := a.GetChannel(c, channelID)
if appErr != nil && appErr.StatusCode == http.StatusNotFound {
return false
return false, false
} else if appErr != nil {
c.Logger().Warn("Failed to get channel", mlog.String("channel_id", channelID), mlog.Err(appErr))
}
if session.IsUnrestricted() || a.RolesGrantPermission(session.GetUserRoles(), model.PermissionManageSystem.Id) {
return true
if session.IsUnrestricted() {
return true, false
}
if appErr == nil && a.isChannelArchivedAndHidden(channel) {
return false
return false, false
}
isMember = false
ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(c, session.UserId, true, true)
var channelRoles []string
if err == nil {
if roles, ok := ids[channelID]; ok {
isMember = true
channelRoles = strings.Fields(roles)
if a.RolesGrantPermission(channelRoles, permission.Id) {
return true
return true, isMember
}
}
}
if appErr == nil && channel.TeamId != "" {
return a.SessionHasPermissionToTeam(session, channel.TeamId, permission)
return a.SessionHasPermissionToTeam(session, channel.TeamId, permission), isMember
}
return a.SessionHasPermissionTo(session, permission)
return a.SessionHasPermissionTo(session, permission), isMember
}
// SessionHasPermissionToChannels returns true only if user has access to all channels.
@@ -221,6 +231,21 @@ func (a *App) SessionHasPermissionToChannelByPost(session model.Session, postID
return a.SessionHasPermissionTo(session, permission)
}
func (a *App) SessionHasPermissionToReadPost(rctx request.CTX, session model.Session, postID string) (hasPErmission bool, isMember bool) {
if postID == "" {
return false, false
}
channel, err := a.Srv().Store().Channel().GetForPost(postID)
if err != nil {
// Original implementation (SessionHasPermissionToChannelByPost) still checks for
// general permissions even if the channel is not found, and some tests rely on this behavior.
return a.SessionHasPermissionTo(session, model.PermissionReadChannelContent), false
}
return a.SessionHasPermissionToReadChannel(rctx, session, channel)
}
func (a *App) SessionHasPermissionToCategory(c request.CTX, session model.Session, userID, teamID, categoryId string) bool {
if a.SessionHasPermissionTo(session, model.PermissionEditOtherUsers) {
return true
@@ -298,11 +323,21 @@ func (a *App) HasPermissionToTeam(c request.CTX, askingUserId string, teamID str
return a.HasPermissionTo(askingUserId, permission)
}
func (a *App) HasPermissionToChannel(c request.CTX, askingUserId string, channelID string, permission *model.Permission) bool {
// HasPermissionToChannel determines if the specified user has the given permission on the provided channel.
//
// Returns:
//
// (hasPermission, isMember)
//
// hasPermission: true if the user has the specified permission for the channel, otherwise false.
// isMember: used for auditing access without membership. True if the user is a member of the channel, otherwise false.
func (a *App) HasPermissionToChannel(c request.CTX, askingUserId string, channelID string, permission *model.Permission) (hasPermission bool, isMember bool) {
if channelID == "" || askingUserId == "" {
return false
return false, false
}
isMember = false
// We call GetAllChannelMembersForUser instead of just getting
// a single member from the DB, because it's cache backed
// and this is a very frequent call.
@@ -310,19 +345,20 @@ func (a *App) HasPermissionToChannel(c request.CTX, askingUserId string, channel
var channelRoles []string
if err == nil {
if roles, ok := ids[channelID]; ok {
isMember = true
channelRoles = strings.Fields(roles)
if a.RolesGrantPermission(channelRoles, permission.Id) {
return true
return true, isMember
}
}
}
channel, appErr := a.GetChannel(c, channelID)
if appErr == nil && channel.TeamId != "" {
return a.HasPermissionToTeam(c, askingUserId, channel.TeamId, permission)
return a.HasPermissionToTeam(c, askingUserId, channel.TeamId, permission), isMember
}
return a.HasPermissionTo(askingUserId, permission)
return a.HasPermissionTo(askingUserId, permission), isMember
}
func (a *App) HasPermissionToChannelByPost(c request.CTX, askingUserId string, postID string, permission *model.Permission) bool {
@@ -411,34 +447,53 @@ func (a *App) SessionHasPermissionToManageBot(rctx request.CTX, session model.Se
return nil
}
func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Session, channel *model.Channel) bool {
// SessionHasPermissionToReadChannel checks whether the given session has permission
// to read the specified channel.
//
// Returns:
//
// (hasPermission, isMember)
//
// hasPermission: true if the user has permission to read the channel, false otherwise
// isMember: used for auditing access without membership. True if the user is a member of the channel, false otherwise
func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Session, channel *model.Channel) (hasPermission bool, isMember bool) {
if session.IsUnrestricted() {
return true
return true, false
}
return a.HasPermissionToReadChannel(c, session.UserId, channel)
}
func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool {
// HasPermissionToReadChannel determines if the specified user has permission to read the given channel.
//
// Returns:
//
// (hasPermission, isMember)
//
// hasPermission: true if the user has permission to read the channel, false otherwise
// isMember: used for auditing access without membership. True if the user is a member of the channel, false otherwise
func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) (hasPermission bool, isMember bool) {
if a.isChannelArchivedAndHidden(channel) {
return false
return false, false
}
if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) {
return true
if ok, member := a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent); ok {
return true, member
}
if channel.Type == model.ChannelTypeOpen && !*a.Config().ComplianceSettings.Enable {
return a.HasPermissionToTeam(c, userID, channel.TeamId, model.PermissionReadPublicChannel)
return a.HasPermissionToTeam(c, userID, channel.TeamId, model.PermissionReadPublicChannel), false
}
return false
return false, false
}
func (a *App) HasPermissionToChannelMemberCount(c request.CTX, userID string, channel *model.Channel) bool {
if a.isChannelArchivedAndHidden(channel) {
return false
}
if a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent) {
if ok, _ := a.HasPermissionToChannel(c, userID, channel.Id, model.PermissionReadChannelContent); ok {
return true
}