diff --git a/roomserver/api/output.go b/roomserver/api/output.go index b25353ae4..d6c09f9e8 100644 --- a/roomserver/api/output.go +++ b/roomserver/api/output.go @@ -29,6 +29,22 @@ const ( // OutputTypeRetireInviteEvent indicates that the event is an OutputRetireInviteEvent OutputTypeRetireInviteEvent OutputType = "retire_invite_event" // OutputTypeRedactedEvent indicates that the event is an OutputRedactedEvent + // + // This event is emitted when a redaction has been 'validated' (meaning both the redaction and the event to redact are known). + // Redaction validation happens when the roomserver receives either: + // - A redaction for which we have the event to redact. + // - Any event for which we have a redaction. + // When the roomserver receives an event, it will check against the redactions table to see if there is a matching redaction + // for the event. If there is, it will mark the redaction as validated and emit this event. In the common case of a redaction + // happening after receiving the event to redact, the roomserver will emit a OutputTypeNewRoomEvent of m.room.redaction + // immediately followed by a OutputTypeRedactedEvent. In the uncommon case of receiving the redaction BEFORE the event to redact, + // the roomserver will emit a OutputTypeNewRoomEvent of the event to redact immediately followed by a OutputTypeRedactedEvent. + // + // In order to honour redactions correctly, downstream components must ignore m.room.redaction events emitted via OutputTypeNewRoomEvent. + // When downstream components receive an OutputTypeRedactedEvent they must: + // - Pull out the event to redact from the database. They should have this because the redaction is validated. + // - Redact the event and set the corresponding `unsigned` fields to indicate it as redacted. + // - Replace the event in the database. OutputTypeRedactedEvent OutputType = "redacted_event" ) diff --git a/roomserver/storage/shared/storage.go b/roomserver/storage/shared/storage.go index a9cb57821..e2e5daf95 100644 --- a/roomserver/storage/shared/storage.go +++ b/roomserver/storage/shared/storage.go @@ -563,6 +563,10 @@ func (d *Database) handleRedactions( // we've seen this redaction before or there is nothing to redact return nil, "", nil } + if redactedEvent.RoomID() != redactionEvent.RoomID() { + // redactions across rooms aren't allowed + return nil, "", nil + } // mark the event as redacted err = redactedEvent.SetUnsignedField("redacted_because", redactionEvent) diff --git a/syncapi/consumers/roomserver.go b/syncapi/consumers/roomserver.go index ba2b2055b..c65027168 100644 --- a/syncapi/consumers/roomserver.go +++ b/syncapi/consumers/roomserver.go @@ -83,8 +83,13 @@ func (s *OutputRoomEventConsumer) onMessage(msg *sarama.ConsumerMessage) error { case api.OutputTypeNewRoomEvent: // Ignore redaction events. We will add them to the database when they are // validated (when we receive OutputTypeRedactedEvent) - if output.NewRoomEvent.Event.Type() == gomatrixserverlib.MRoomRedaction && output.NewRoomEvent.Event.StateKey() == nil { - return nil + event := output.NewRoomEvent.Event + if event.Type() == gomatrixserverlib.MRoomRedaction && event.StateKey() == nil { + // in the special case where the event redacts itself, just pass the message through because + // we will never see the other part of the pair + if event.Redacts() != event.EventID() { + return nil + } } return s.onNewRoomEvent(context.TODO(), *output.NewRoomEvent) case api.OutputTypeNewInviteEvent: diff --git a/sytest-whitelist b/sytest-whitelist index 30380af0e..0628ea26e 100644 --- a/sytest-whitelist +++ b/sytest-whitelist @@ -160,14 +160,6 @@ User can create and send/receive messages in a room with version 1 POST /createRoom ignores attempts to set the room version via creation_content Inbound federation rejects remote attempts to join local users to rooms Inbound federation rejects remote attempts to kick local users to rooms -# SyTest currently only implements the v1 endpoints for /send_join and /send_leave, -# whereas Dendrite only supports the v2 endpoints for those, so let's ignore this -# test for now. -#An event which redacts itself should be ignored -# SyTest currently only implements the v1 endpoints for /send_join and /send_leave, -# whereas Dendrite only supports the v2 endpoints for those, so let's ignore this -# test for now. -#A pair of events which redact each other should be ignored Full state sync includes joined rooms A message sent after an initial sync appears in the timeline of an incremental sync. Can add tag @@ -295,6 +287,14 @@ POST /rooms/:room_id/redact/:event_id as random user does not redact message POST /redact disallows redaction of event in different room An event which redacts itself should be ignored A pair of events which redact each other should be ignored +Redaction of a redaction redacts the redaction reason +An event which redacts an event in a different room should be ignored +Can receive redactions from regular users over federation in room version 1 +Can receive redactions from regular users over federation in room version 2 +Can receive redactions from regular users over federation in room version 3 +Can receive redactions from regular users over federation in room version 4 +Can receive redactions from regular users over federation in room version 5 +Can receive redactions from regular users over federation in room version 6 Outbound federation can backfill events Inbound federation can backfill events Backfill checks the events requested belong to the room