[MM-64686] Expose audit logging functionality via plugin API (#31204)

This commit exposes audit logging functionality to plugins via the plugin API, allowing plugins to create and log audit records. Additionally, it addresses a gob encoding issue that could cause plugin crashes when audit data contains nil pointers or unregistered types.
Этот коммит содержится в:
David Krauser
2025-06-25 20:37:32 -04:00
коммит произвёл GitHub
родитель efb960a160
Коммит aaa62a40ae
68 изменённых файлов: 878 добавлений и 750 удалений

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

@@ -13,7 +13,6 @@ import (
"github.com/mattermost/mattermost/server/public/shared/i18n"
"github.com/mattermost/mattermost/server/public/shared/mlog"
"github.com/mattermost/mattermost/server/v8/channels/app"
"github.com/mattermost/mattermost/server/v8/channels/audit"
)
const maxListSize = 1000
@@ -103,9 +102,9 @@ func createChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("createChannel", audit.Fail)
auditRec := c.MakeAuditRecord("createChannel", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameterAuditable(auditRec, "channel", channel)
model.AddEventParameterAuditableToAuditRec(auditRec, "channel", channel)
if channel.Type == model.ChannelTypeOpen && !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), channel.TeamId, model.PermissionCreatePublicChannel) {
c.SetPermissionError(model.PermissionCreatePublicChannel)
@@ -153,8 +152,8 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("updateChannel", audit.Fail)
audit.AddEventParameterAuditable(auditRec, "channel", channel)
auditRec := c.MakeAuditRecord("updateChannel", model.AuditStatusFail)
model.AddEventParameterAuditableToAuditRec(auditRec, "channel", channel)
defer c.LogAuditRec(auditRec)
originalOldChannel, appErr := c.App.GetChannel(c.AppContext, channel.Id)
@@ -223,7 +222,7 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) {
if channel.Name != "" {
oldChannel.Name = channel.Name
audit.AddEventParameter(auditRec, "new_channel_name", oldChannel.Name)
model.AddEventParameterToAuditRec(auditRec, "new_channel_name", oldChannel.Name)
}
if channel.GroupConstrained != nil {
@@ -258,8 +257,8 @@ func updateChannelPrivacy(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("updateChannelPrivacy", audit.Fail)
audit.AddEventParameter(auditRec, "channel_id", c.Params.ChannelId)
auditRec := c.MakeAuditRecord("updateChannelPrivacy", model.AuditStatusFail)
model.AddEventParameterToAuditRec(auditRec, "channel_id", c.Params.ChannelId)
defer c.LogAuditRec(auditRec)
props := model.StringInterfaceFromJSON(r.Body)
@@ -269,7 +268,7 @@ func updateChannelPrivacy(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
audit.AddEventParameter(auditRec, "privacy", privacy)
model.AddEventParameterToAuditRec(auditRec, "privacy", privacy)
channel, err := c.App.GetChannel(c.AppContext, c.Params.ChannelId)
if err != nil {
@@ -337,9 +336,9 @@ func patchChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
oldChannel := originalOldChannel.DeepCopy()
auditRec := c.MakeAuditRecord("patchChannel", audit.Fail)
auditRec := c.MakeAuditRecord("patchChannel", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameterAuditable(auditRec, "channel", patch)
model.AddEventParameterAuditableToAuditRec(auditRec, "channel", patch)
auditRec.AddEventPriorState(oldChannel)
switch oldChannel.Type {
@@ -429,7 +428,7 @@ func restoreChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
teamId := channel.TeamId
auditRec := c.MakeAuditRecord("restoreChannel", audit.Fail)
auditRec := c.MakeAuditRecord("restoreChannel", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
auditRec.AddEventPriorState(channel)
@@ -483,8 +482,8 @@ func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
auditRec := c.MakeAuditRecord("createDirectChannel", audit.Fail)
audit.AddEventParameter(auditRec, "user_ids", userIds)
auditRec := c.MakeAuditRecord("createDirectChannel", model.AuditStatusFail)
model.AddEventParameterToAuditRec(auditRec, "user_ids", userIds)
defer c.LogAuditRec(auditRec)
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionCreateDirectChannel) {
@@ -502,7 +501,7 @@ func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) {
otherUserId = userIds[1]
}
audit.AddEventParameter(auditRec, "user_id", otherUserId)
model.AddEventParameterToAuditRec(auditRec, "user_id", otherUserId)
canSee, appErr := c.App.UserCanSeeOtherUser(c.AppContext, c.AppContext.Session().UserId, otherUserId)
if appErr != nil {
@@ -575,8 +574,8 @@ func createGroupChannel(c *Context, w http.ResponseWriter, r *http.Request) {
userIds = append(userIds, c.AppContext.Session().UserId)
}
auditRec := c.MakeAuditRecord("createGroupChannel", audit.Fail)
audit.AddEventParameter(auditRec, "user_ids", userIds)
auditRec := c.MakeAuditRecord("createGroupChannel", model.AuditStatusFail)
model.AddEventParameterToAuditRec(auditRec, "user_ids", userIds)
defer c.LogAuditRec(auditRec)
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionCreateGroupChannel) {
@@ -1374,8 +1373,8 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("deleteChannel", audit.Fail)
audit.AddEventParameter(auditRec, "id", c.Params.ChannelId)
auditRec := c.MakeAuditRecord("deleteChannel", model.AuditStatusFail)
model.AddEventParameterToAuditRec(auditRec, "id", c.Params.ChannelId)
auditRec.AddEventPriorState(channel)
defer c.LogAuditRec(auditRec)
@@ -1711,10 +1710,10 @@ func updateChannelMemberRoles(c *Context, w http.ResponseWriter, r *http.Request
return
}
auditRec := c.MakeAuditRecord("updateChannelMemberRoles", audit.Fail)
auditRec := c.MakeAuditRecord("updateChannelMemberRoles", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameter(auditRec, "props", props)
audit.AddEventParameter(auditRec, "channel_id", c.Params.ChannelId)
model.AddEventParameterToAuditRec(auditRec, "props", props)
model.AddEventParameterToAuditRec(auditRec, "channel_id", c.Params.ChannelId)
if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionManageChannelRoles) {
c.SetPermissionError(model.PermissionManageChannelRoles)
@@ -1743,10 +1742,10 @@ func updateChannelMemberSchemeRoles(c *Context, w http.ResponseWriter, r *http.R
return
}
auditRec := c.MakeAuditRecord("updateChannelMemberSchemeRoles", audit.Fail)
auditRec := c.MakeAuditRecord("updateChannelMemberSchemeRoles", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameter(auditRec, "channel_id", c.Params.ChannelId)
audit.AddEventParameterAuditable(auditRec, "roles", &schemeRoles)
model.AddEventParameterToAuditRec(auditRec, "channel_id", c.Params.ChannelId)
model.AddEventParameterAuditableToAuditRec(auditRec, "roles", &schemeRoles)
if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionManageChannelRoles) {
c.SetPermissionError(model.PermissionManageChannelRoles)
@@ -1775,10 +1774,10 @@ func updateChannelMemberNotifyProps(c *Context, w http.ResponseWriter, r *http.R
return
}
auditRec := c.MakeAuditRecord("updateChannelMemberNotifyProps", audit.Fail)
auditRec := c.MakeAuditRecord("updateChannelMemberNotifyProps", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameter(auditRec, "channel_id", c.Params.ChannelId)
audit.AddEventParameter(auditRec, "props", props)
model.AddEventParameterToAuditRec(auditRec, "channel_id", c.Params.ChannelId)
model.AddEventParameterToAuditRec(auditRec, "props", props)
if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
c.SetPermissionError(model.PermissionEditOtherUsers)
@@ -1912,11 +1911,11 @@ func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
continue
}
auditRec := c.MakeAuditRecord("addChannelMember", audit.Fail)
auditRec := c.MakeAuditRecord("addChannelMember", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameter(auditRec, "user_id", userId)
audit.AddEventParameter(auditRec, "channel_id", c.Params.ChannelId)
audit.AddEventParameter(auditRec, "post_root_id", postRootId)
model.AddEventParameterToAuditRec(auditRec, "user_id", userId)
model.AddEventParameterToAuditRec(auditRec, "channel_id", c.Params.ChannelId)
model.AddEventParameterToAuditRec(auditRec, "post_root_id", postRootId)
member := &model.ChannelMember{
ChannelId: c.Params.ChannelId,
@@ -2003,10 +2002,10 @@ func removeChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("removeChannelMember", audit.Fail)
auditRec := c.MakeAuditRecord("removeChannelMember", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameter(auditRec, "channel_id", c.Params.ChannelId)
audit.AddEventParameter(auditRec, "user_id", c.Params.UserId)
model.AddEventParameterToAuditRec(auditRec, "channel_id", c.Params.ChannelId)
model.AddEventParameterToAuditRec(auditRec, "user_id", c.Params.UserId)
channel, err := c.App.GetChannel(c.AppContext, c.Params.ChannelId)
if err != nil {
@@ -2059,8 +2058,8 @@ func updateChannelScheme(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("updateChannelScheme", audit.Fail)
audit.AddEventParameter(auditRec, "channel_id", c.Params.ChannelId)
auditRec := c.MakeAuditRecord("updateChannelScheme", model.AuditStatusFail)
model.AddEventParameterToAuditRec(auditRec, "channel_id", c.Params.ChannelId)
defer c.LogAuditRec(auditRec)
var p model.SchemeIDPatch
@@ -2070,7 +2069,7 @@ func updateChannelScheme(c *Context, w http.ResponseWriter, r *http.Request) {
}
schemeID := p.SchemeID
audit.AddEventParameter(auditRec, "scheme_id", *schemeID)
model.AddEventParameterToAuditRec(auditRec, "scheme_id", *schemeID)
if c.App.Channels().License() == nil {
c.Err = model.NewAppError("Api4.UpdateChannelScheme", "api.channel.update_channel_scheme.license.error", nil, "", http.StatusForbidden)
@@ -2254,7 +2253,7 @@ func patchChannelModerations(c *Context, w http.ResponseWriter, r *http.Request)
return
}
auditRec := c.MakeAuditRecord("patchChannelModerations", audit.Fail)
auditRec := c.MakeAuditRecord("patchChannelModerations", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleWriteUserManagementChannels) {
@@ -2267,7 +2266,7 @@ func patchChannelModerations(c *Context, w http.ResponseWriter, r *http.Request)
c.Err = appErr
return
}
audit.AddEventParameterAuditable(auditRec, "channel", channel)
model.AddEventParameterAuditableToAuditRec(auditRec, "channel", channel)
var channelModerationsPatch []*model.ChannelModerationPatch
err := json.NewDecoder(r.Body).Decode(&channelModerationsPatch)
@@ -2281,7 +2280,7 @@ func patchChannelModerations(c *Context, w http.ResponseWriter, r *http.Request)
c.Err = appErr
return
}
audit.AddEventParameterAuditableArray(auditRec, "channel_moderations_patch", channelModerationsPatch)
model.AddEventParameterAuditableArrayToAuditRec(auditRec, "channel_moderations_patch", channelModerationsPatch)
b, err := json.Marshal(channelModerations)
if err != nil {
@@ -2326,11 +2325,11 @@ func moveChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
auditRec := c.MakeAuditRecord("moveChannel", audit.Fail)
auditRec := c.MakeAuditRecord("moveChannel", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameter(auditRec, "channel_id", c.Params.ChannelId)
audit.AddEventParameter(auditRec, "team_id", teamId)
audit.AddEventParameter(auditRec, "force", force)
model.AddEventParameterToAuditRec(auditRec, "channel_id", c.Params.ChannelId)
model.AddEventParameterToAuditRec(auditRec, "team_id", teamId)
model.AddEventParameterToAuditRec(auditRec, "force", force)
auditRec.AddEventPriorState(channel)
// TODO check and verify if the below three things are parameters or prior state if any
@@ -2451,11 +2450,11 @@ func convertGroupMessageToChannel(c *Context, w http.ResponseWriter, r *http.Req
return
}
auditRec := c.MakeAuditRecord("convertGroupMessageToChannel", audit.Fail)
auditRec := c.MakeAuditRecord("convertGroupMessageToChannel", model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
audit.AddEventParameter(auditRec, "channel_id", gmConversionRequest.ChannelID)
audit.AddEventParameter(auditRec, "team_id", gmConversionRequest.TeamID)
audit.AddEventParameter(auditRec, "user_id", user.Id)
model.AddEventParameterToAuditRec(auditRec, "channel_id", gmConversionRequest.ChannelID)
model.AddEventParameterToAuditRec(auditRec, "team_id", gmConversionRequest.TeamID)
model.AddEventParameterToAuditRec(auditRec, "user_id", user.Id)
updatedChannel, appErr := c.App.ConvertGroupMessageToChannel(c.AppContext, c.AppContext.Session().UserId, gmConversionRequest)
if appErr != nil {