You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
matrix-spec-proposals/proposals/4293-redact-on-ban.md

16 KiB

MSC4293: Redact on kick/ban

MSC2244 (accepted)-style mass redactions are incredibly helpful for cleaning up large volumes of spam, especially because they reduce the total number of events a server needs to process in order to clean up a room. However, they have a few issues:

  1. To populate the target events, the sender needs to know which event IDs to target. Events may be soft failed by the moderator's local homeserver, which may prevent the sender's client from seeing them. Further, there may be timeline gaps which limit the sender's visibility on the events to target.

    This may be fixed by adding a "sugar API" like /room/:roomId/redact/:userId which causes the server to calculate event ID targets and send out one or more mass redactions, though this would only be effective if the server had all of the user's events at the time of the call. If an event came in late for any reason, the sent redactions might not target it, allowing the likely spam through to the room.

    Proposals such as MSC4194 explore this solution.

  2. Dedicated events must still be sent in order to perform the redaction, many of which might not be small if there's lots of events being targeted. This can impact bandwidth and data storage, though not as badly as trying to redact large volumes of spam without mass redactions.

  3. MSC2244 mass redactions are breaking for clients which perform redaction locally due to changing the type of redacts on m.room.redaction events from a string (single event ID) to an array. This is in part mitigated by MSC2244 through a new room version, though clients are currently unable to opt out of incompatible room versions.

    It's also possible to mitigate this concern by using a new event type for mass redactions instead. This alternative is explored in MSC4343.

  4. Due to changes in event authorization, MSC2244 requires a new room version in order to function. This limits the feature to new rooms or those which upgrade to a new enough version. Theoretically, it's possible to allow mass redactions in existing room versions anyway, though the redactions may get rejected due to the very authorization rules MSC2244 changes. This may cause senders to target a small number of events per mass redaction to avoid the possibility of spam being left visible due to a single event target not being present on the receiving homeserver.

To work around these issues, this proposal suggests adding a new flag to membership events to indicate to clients and servers that all of that user's events should be redacted in addition to being kicked or banned. There are still drawbacks for existing room versions with this approach, namely that the new flag isn't protected from redaction itself and may cause problems, but it does allow moderators to take an action they were going to anyway: ban & redact everything the user ever sent, without needing to wait for a new room version to roll out.

By applying the flag to a user ID instead of an event ID (or set of event IDs), the consumer's local view is considered instead of the sender's: a redaction for "all of @alice:example.org's events" when applied by a client removes all events visible to that client. Similarly, that redaction applied by a server to their local database will redact whatever events the server has already seen, or will see in the future.

Though this MSC isn't breaking for clients in the same way that MSC2244 is, clients (and to a degree, servers) may not support the MSC right away. This means that senders may still have to send "fallback redactions" to ensure the room is cleaned up, though those senders can begin to treat those redactions as best effort (currently, moderation bots in particular work incredibly hard to ensure they get every event redacted, but can run into delivery, reliability, and completeness issues with 1:1 redactions).

It's also important to note that this proposal intends to complement mass redactions and coexist in whatever room version mass redactions land in. This proposal has narrow scope and is fairly blunt as a measure, which may not be desirable in all situations. For example, only a user's last dozen or so messages may be worth redacting rather than the hundreds they sent prior to the ones which got them banned. This proposal does not support such a use case, but mass redactions do.

Proposal

A new flag is added to m.room.member events where the target user is kicked or banned: redact_events. Discussed later, this new flag has no effect when applied to self-leaves or other membership states. This flag is a boolean and has two effects when true:

  1. Clients apply the redaction algorithm to events sent by that user which are cached locally, up to the point of the user's previous membership event. No m.room.redaction events are sent by the client, but the user's events are redacted as though there was such an event.

  2. Servers perform the same function as clients, also not actually sending any m.room.redaction events. Instead, the user's events are redacted locally by the server. When serving events redacted in this way, the redacted_because field is populated using the membership event, like so:

    {
     // irrelevant fields not shown
    
     "type": "m.room.message",
     "sender": "@banned:example.org",
     "content": {}, // because the event is redacted, `content` is empty
     "unsigned": {
       "redacted_because": {
         // irrelevant fields also not shown here
    
         "type": "m.room.member",
         "sender": "@moderator:example.org",
         "state_key": "@banned:example.org",
         "content": {
           "membership": "ban",
           "reason": "spam",
           "redact_events": true
         }
       }
     }
    }
    

    Note that because m.room.redaction supports a reason field in the same place as m.room.member, clients which look up that reason by going event["unsigned"]["content"]["reason"] will still get a renderable, human-readable, string for their UI regardless of how the event was actually redacted.

When redact_events is false, it acts as though it was not specified: no redactions are applied, exactly like how bans work prior to this proposal.

Prior to applying the effects of redaction above, clients and servers MUST ensure that the sender of the kick or ban has power level to redact the target user's events. This means having a power level higher than or equal to redact and events["m.room.redaction"] (if set). We maintain the events check despite not actually sending events of that type to keep the same expectations within rooms. If the sender doesn't have permission to redact an event normally, the redact_events flag is ignored (and therefore no redaction effect is applied).

Events which are delivered after the kick or ban are likely soft failed and are still redacted by servers if the user's current membership event has redact_events: true.

The redact_events flag has no effect when present on any other membership state, such as joins, knocks, invites, and voluntary leaves (non-kicks).

Note: Due to this proposal being enabled in existing room versions, the redact_events flag may become redacted when a user's m.room.member event is redacted too. When this happens, the redactions already applied up to that point are not undone, though clients/servers which purge the events and re-fetch them might receive unredacted copies if they originate from a server which didn't apply this proposal's effects. Future proposals like MSC4298 protect the flag from redaction, avoiding the awkward state where events might be redacted for no discernible reason after the membership event itself is redacted.

redact_events is also added to the /kick and /ban endpoints and is proxied to the resulting event just like reason is. It is optional on these endpoints.

An example ban event is:

{
  // Irrelevant fields excluded

  "type": "m.room.member",
  "state_key": "@spam:example.org",
  "sender": "@mod:example.org",
  "content": {
    "membership": "ban",
    "reason": "flooding", // this is copied to `redacted_because`, leading to clients showing it
    "redact_events": true
  }
}

An example scenario would be:

  1. Alice joins the room.
  2. Alice sends events A, B, and C.
  3. Alice leaves the room.
  4. For whatever reason, Alice rejoins the room.
  5. Alice sends events D, E, and F.
  6. Bob bans Alice with redact_events: true.
  7. Clients and servers apply redactions to events D, E, and F, but not A, B, or C. No actual m.room.redaction events are sent in this example.
  8. Alice's event F arrive's late to Bob's server.
  9. Bob's server soft fails F because it fails current auth state (Alice is banned), and redacts it because redact_events: true is set on Alice's ban. There are still no actual m.room.redaction events sent here.

Events A, B, and C are not redacted because Alice's leave event at step 3 has an implied redact_events: false.

Moderation bots and similar MAY still wish to issue (mass) redactions upon kick/ban to protect users on servers or clients which don't have this feature.

Fallback behaviour

Servers which don't support this feature may be served redacted events over federation when attempting to fill gaps or backfill. This is considered expected behaviour.

Clients which don't support this feature may see events remain unredacted until they clear their local cache. Upon clearing or invalidating their cache, they will either receive redacted events if their server supports the feature, or unredacted events otherwise. This is also considered expected behaviour.

Though this proposal makes it clear that m.room.redaction events aren't actually sent, senders of kicks/bans MAY still send actual redactions in addition to redact_events: true to ensure that older clients and servers have the best possible chance of redacting the event. These redactions SHOULD be considered "best effort" by the sender as they may encounter delivery issues, especially when using 1:1 redactions instead of mass redactions. "Best effort" might mean using endpoints like MSC4194's batch redaction, or using the less reliable /messages endpoint to locate target event IDs to redact. Senders SHOULD note that this fallback behaviour will only target events they can see (or be made to see via MSC4194) and might not be the same events that a receiving client or server sees.

Senders are encouraged to evaluate when they can cease sending fallback redactions like those described above to minimize the event traffic involved in a ban. For moderation bots this may mean waiting for sufficiently high client implementations existing in their communities.

Potential issues

  1. It's a little annoying that the flag is redacted when the membership event is redacted, however it's extremely rare for a moderator/admin to redact a kick or ban event. This can be fixed in a future room version, like what is proposed by MSC4298.

  2. Though extremely rare, if an existing server in the room didn't apply the redactions and a sender's ban was redacted, a new server to the room may backfill through that existing server and see unredacted events without knowing it's supposed to redact them due to the ban having lost the redact_events field. This is fixed for future room versions by implementing something like MSC4298.

  3. Clients may miss the membership event if they are using lazy loading, though servers should already be tracking which membership events the client has received and needs to render events in the timeline. This should mean that those clients will still receive the event.

    Servers which miss the event will eventually receive or retrieve it, just like they would with any other event.

  4. Moderation bots/clients which attempt to reduce the amount of duplicate work they do may need to inspect redacted_because's type instead of checking for its presence to determine which kind of redaction was applied to a given event. This is especially true if the moderation bot/client is providing the fallback support described above.

  5. If a user is banned using redact_events: true, unbanned, rejoins, sends more events, and is banned again using redact_events: true, the user's events between bans will be subsequently redacted. The events redacted by the first ban may also be re-redacted by servers/clients depending on implementation. This is considered expected behaviour, and implementations can internally track which events they've already auto-redacted to avoid duplicate work.

  6. With respect to the fallback behaviour, it's not great that implementations, and in particular moderation bots, need to maintain their "find all events sent by this user and redact them" behaviour. MSC4194 should help with this, though has the limitations discussed throughout this MSC when applied to this proposal's use case.

  7. If a user is banned without the flag then banned again with the flag, their events sent before the first ban won't be redacted. This is already the case with moderation bots which support autoredaction when certain ban reasons are used: if there's a typo/problem with the reason, the bot's operator may need to issue more commands/requests to reach the intended result.

    Clients and moderation bots are encouraged to implement UX which reduces the chances of this sort of thing happening. Moderation teams are also encouraged to develop operating procedures which limit the opportunity for accidentally encountering this case.

  8. A spammer may attempt to work around this MSC's effects by joining and leaving the room during their spam. This has relatively high cost (the impact of spam is lesser when they aren't joined to the room, and re-joining will hit a more restrictive rate limit on most servers).

    Moderation bots and similar community safety tools are encouraged to add restrictions to the number of join+leave cycles a user may perform in a short window. This will further reduce the effectiveness of such an attack. Issue 7 above also applies here.

Alternatives

Alternatives are discussed inline on this proposal and in the introduction.

Future considerations

It may be desirable to place this behaviour on self-leaves too, allowing for faster removal of one's own messages/events. This proposal doesn't suggest adding this functionality here to maintain narrow scope on T&S functionality. A future proposal may introduce this, or rely on regular mass redactions instead.

Security considerations

As the room moderator/administrator would already send redactions, and may still for full protection, it's not deemed any more risk than today. This may change if self-leaves are permitted to also carry the field.

There may also be implementation or reliability bugs which inhibit the "stop redacting now" point from working as intended. Server implementations in particular should ensure that an event received after a membership event which asks for redaction is really affected by that redaction. ie: whether it's just a late delivery, or if there's a join waiting for state res to make a determination.

Unstable prefix

While this proposal is not considered stable, implementations should use org.matrix.msc4293.redact_events instead of redact_events.

Dependencies

This MSC has no direct dependencies.

Credits

Credit goes to Erik of the Spec Core Team for the suggestion to look into this.