Sanitize post for audit with preview links (#23745)
* sanitize post for audit with preview links * add unit test --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
@@ -2817,3 +2817,55 @@ func TestSanitizePostMetadataForUserAndChannel(t *testing.T) {
|
|||||||
actual = th.App.sanitizePostMetadataForUserAndChannel(th.Context, post, previewedPost, directChannel, guest.Id)
|
actual = th.App.sanitizePostMetadataForUserAndChannel(th.Context, post, previewedPost, directChannel, guest.Id)
|
||||||
assert.Nil(t, actual.Metadata.Embeds[0].Data)
|
assert.Nil(t, actual.Metadata.Embeds[0].Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSanitizePostMetaDataForAudit(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||||
|
*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
|
||||||
|
})
|
||||||
|
|
||||||
|
th.Context.Session().UserId = th.BasicUser.Id
|
||||||
|
|
||||||
|
referencedPost, err := th.App.CreatePost(th.Context, &model.Post{
|
||||||
|
UserId: th.BasicUser.Id,
|
||||||
|
ChannelId: th.BasicChannel.Id,
|
||||||
|
Message: "hello world",
|
||||||
|
}, th.BasicChannel, false, true)
|
||||||
|
require.Nil(t, err)
|
||||||
|
referencedPost.Metadata.Embeds = nil
|
||||||
|
|
||||||
|
link := fmt.Sprintf("%s/%s/pl/%s", *th.App.Config().ServiceSettings.SiteURL, th.BasicTeam.Name, referencedPost.Id)
|
||||||
|
|
||||||
|
previewPost, err := th.App.CreatePost(th.Context, &model.Post{
|
||||||
|
UserId: th.BasicUser.Id,
|
||||||
|
ChannelId: th.BasicChannel.Id,
|
||||||
|
Message: link,
|
||||||
|
}, th.BasicChannel, false, true)
|
||||||
|
require.Nil(t, err)
|
||||||
|
previewPost.Metadata.Embeds = nil
|
||||||
|
clientPost := th.App.PreparePostForClientWithEmbedsAndImages(th.Context, previewPost, false, false, false)
|
||||||
|
firstEmbed := clientPost.Metadata.Embeds[0]
|
||||||
|
preview := firstEmbed.Data.(*model.PreviewPost)
|
||||||
|
require.Equal(t, referencedPost.Id, preview.PostID)
|
||||||
|
|
||||||
|
// ensure the permalink metadata is sanitized for audit logging
|
||||||
|
m := clientPost.Auditable()
|
||||||
|
metaDataI, ok := m["metadata"]
|
||||||
|
require.True(t, ok)
|
||||||
|
metaData, ok := metaDataI.(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
embedsI, ok := metaData["embeds"]
|
||||||
|
require.True(t, ok)
|
||||||
|
embeds, ok := embedsI.([]map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
for _, pe := range embeds {
|
||||||
|
// ensure all the PostEmbed maps only contain `type` and `url`
|
||||||
|
for k := range pe {
|
||||||
|
if k != "type" && k != "url" {
|
||||||
|
require.Fail(t, "PostEmbed should only contain 'type' and 'url fields'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -120,6 +120,11 @@ type Post struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) Auditable() map[string]interface{} {
|
func (o *Post) Auditable() map[string]interface{} {
|
||||||
|
var metaData map[string]any
|
||||||
|
if o.Metadata != nil {
|
||||||
|
metaData = o.Metadata.Auditable()
|
||||||
|
}
|
||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"id": o.Id,
|
"id": o.Id,
|
||||||
"create_at": o.CreateAt,
|
"create_at": o.CreateAt,
|
||||||
@@ -139,7 +144,7 @@ func (o *Post) Auditable() map[string]interface{} {
|
|||||||
"reply_count": o.ReplyCount,
|
"reply_count": o.ReplyCount,
|
||||||
"last_reply_at": o.LastReplyAt,
|
"last_reply_at": o.LastReplyAt,
|
||||||
"is_following": o.IsFollowing,
|
"is_following": o.IsFollowing,
|
||||||
"metadata": o.Metadata,
|
"metadata": metaData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,11 @@ type PostEmbed struct {
|
|||||||
// Any additional data for the embedded content. Only used for OpenGraph embeds.
|
// Any additional data for the embedded content. Only used for OpenGraph embeds.
|
||||||
Data any `json:"data,omitempty"`
|
Data any `json:"data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pe *PostEmbed) Auditable() map[string]any {
|
||||||
|
// filter out embedded content.
|
||||||
|
return map[string]any{
|
||||||
|
"type": pe.Type,
|
||||||
|
"url": pe.URL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,26 @@ type PostMetadata struct {
|
|||||||
Acknowledgements []*PostAcknowledgement `json:"acknowledgements,omitempty"`
|
Acknowledgements []*PostAcknowledgement `json:"acknowledgements,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pm *PostMetadata) Auditable() map[string]any {
|
||||||
|
embeds := make([]map[string]any, 0, len(pm.Embeds))
|
||||||
|
for _, pe := range pm.Embeds {
|
||||||
|
embeds = append(embeds, pe.Auditable())
|
||||||
|
}
|
||||||
|
if len(embeds) == 0 {
|
||||||
|
embeds = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]any{
|
||||||
|
"embeds": embeds,
|
||||||
|
"emojis": pm.Emojis,
|
||||||
|
"files": pm.Files,
|
||||||
|
"images": pm.Images,
|
||||||
|
"reactions": pm.Reactions,
|
||||||
|
"priority": pm.Priority,
|
||||||
|
"acknowledgements": pm.Acknowledgements,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type PostImage struct {
|
type PostImage struct {
|
||||||
Width int `json:"width"`
|
Width int `json:"width"`
|
||||||
Height int `json:"height"`
|
Height int `json:"height"`
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user