-
Notifications
You must be signed in to change notification settings - Fork 434
MSC3531: Letting moderators hide messages pending moderation #3531
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Yoric
wants to merge
9
commits into
matrix-org:main
Choose a base branch
from
Yoric:yoric/undo-redact
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+227
−0
Open
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
8f3e726
MSC3531: Letting moderators hide messages
Yoric 9db1e0a
wrapping lines
Yoric a0205ed
WIP
Yoric 69fdd50
MSC3531: Applying feedback
Yoric 43a2e09
MSC3531: Applying feedback: reason
Yoric 9d6f372
MSC3531: Minor fixes
Yoric 412d62f
FIXUP: Letting users hide their own messages
Yoric 726bf18
FIXUP: Applying feedback + experience from implementing prototype
Yoric 86b32d6
FIXUP: Visibility is part of the content, not the relation
Yoric File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,132 @@ | ||||||
|
|
||||||
| # **MSCXXXX: Letting moderators hide messages pending review** | ||||||
|
|
||||||
| Matrix supports **redacting** messages as a mechanism to remove unwanted content. At present, there is no manner of **undoing** these redactions. | ||||||
|
|
||||||
| After attempting to come up with a mechanism to undo redactions, we came to the conclusion that | ||||||
| this cannot be robustly and simply implemented at Matrix-level. Rather, we propose a spec to let moderators *hide messages pending review*. This spec can then be used by clients or bots such as Mjölnir | ||||||
|
Yoric marked this conversation as resolved.
Outdated
|
||||||
| to implement two phase redaction: | ||||||
| 1. a first phase during which messages are flagged for moderation (either by a bot or manually) and hidden from general consumption; | ||||||
| 1. a second phase during which moderators may either restore the message or `redact` it entirely. | ||||||
|
|
||||||
|
|
||||||
| ## **Proposal** | ||||||
|
|
||||||
| ### **Introduction** | ||||||
|
Yoric marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| **Redacting** events, as defined in the Matrix spec, is a mechanism that entirely removes the content of an event. Users can redact their own events, and room moderators can redact unwanted events, including illegal content. | ||||||
|
|
||||||
| The Matrix spec does not offer a mechanism to **undo** a redaction. This means that if a user or moderator makes a mistake, there is no way to restore the original message. Tolerance for mistakes supports innovation, as well as reducing the risks of proposals such as MSC3215, which aims to decentralize moderation. | ||||||
|
|
||||||
| Reversing a redaction is tricky, as we cover in the **Alternatives** section. However, if we allow moderators to flag a message as hidden, a moderator can easily restore the content of a message that has been flagged. In particular, if a moderator uses a bot such as Mjölnir, the bot may implement a room of "messages pending review by moderators", letting moderators review flagged messages leisurely while being certain that inappropriate messages are not visible by users on compliant clients. | ||||||
|
|
||||||
| In this proposal, the bulk of the work of hiding is *performed by clients*. Messages marked as "hidden" are distributed to all clients by should be visible only to their author and moderators. This keeps the proposal minimal and simple to implement. | ||||||
|
|
||||||
| ### **Proposal** | ||||||
| We introduce a new type of relation: `m.visibility`, with the following syntax: | ||||||
|
|
||||||
| ```jsonc | ||||||
| "m.relates_to": { | ||||||
| "rel_type": "m.visibility", | ||||||
| "event_id": "$event_id", | ||||||
| "visibility": "hidden"// or "visible" | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| Only moderators may send events with relation `m.visibility`. This relation controls whether *clients* should display an event or hide it. | ||||||
|
|
||||||
| #### Server behavior | ||||||
|
|
||||||
| When a homeserver receives an event with `rel_type` `m.visibility` sent by user U in room R: | ||||||
| 1. if the powerlevel of U in R is greater or equal to `m.visibility` | ||||||
| 1. accept the event | ||||||
| 1. otherwise | ||||||
| 1. respond with error code M_FORBIDDEN | ||||||
|
|
||||||
| #### Client behavior | ||||||
|
Yoric marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| 1. When a client receives an event with `rel_type` `m.visibility` and visibility V sent by user U in room R and relating to an existing event E in room R: | ||||||
| 1. If the powerlevel of U in R is greater or equal to `m.visibility` (note: we add this check to ensure that the proposal works to a large extent even without support from the homeserver) | ||||||
| 1. If V is "hidden", mark E as hidden | ||||||
| 1. In every display of E, either by itself or in a reaction | ||||||
| 1. If the current user is the sender of E | ||||||
| 1. Label the display of E with a label such as `(pending moderation)` | ||||||
| 1. Otherwise, if the current user has a powerlevel greater or equal to `m.visibility` | ||||||
| 1. Display E as a spoiler. | ||||||
| 1. Label the display of E with a label such as `(pending moderation)` | ||||||
| 1. Otherwise | ||||||
| 1. Instead of displaying E, display a message such as `Message is pending moderation` | ||||||
|
uhoreg marked this conversation as resolved.
Outdated
|
||||||
| 1. Otherwise, if V is "visible", mark E as visible | ||||||
| 1. Display E exactly as it would be displayed without this MSC | ||||||
| 1. Otherwise, ignore | ||||||
| 1. Otherwise, ignore | ||||||
| 1. When a client prepares to display a message E with visibility "hidden", whether by itself or in a reaction | ||||||
| 1. (see 1.1.1.1.1. for details on how to display E) | ||||||
|
|
||||||
| If several reactions race against each other to mark a message as visible or hidden, we consider the most recent one (by order of origin_server_ts) the source of truth. | ||||||
|
|
||||||
| #### Example use | ||||||
|
|
||||||
| A moderation bot such as Mjölnir may implement two-phase redaction as follows: | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. language nitpick for clarity:
Suggested change
|
||||||
| 1. When a room protection rule or a moderator requires Mjölnir to redact a message E in room R | ||||||
| 1. Copy E to a "moderation pending" room as message E', with some UX to decide whether E should be PASS or REJECT. | ||||||
| 1. Mark E in R as hidden, using the current MSC. | ||||||
| 1. When a moderator marks clone E' as PASS | ||||||
| 1. Mark E in R as visible, using the current MSC. | ||||||
| 1. Remove E' from the "moderation pending" room. | ||||||
| 1. When a moderator marks clone E' as REJECT | ||||||
| 1. Send a message `m.room.redaction` to R to fully redact message E. | ||||||
| 1. Remove E' from the "moderation pending" room. | ||||||
| 1. If, after <some retention duration, e.g. one week>, a clone E' has been marked neither PASS nor REJECT | ||||||
| 1. Behave as if E' had been marked REJECT | ||||||
|
|
||||||
| ### Potential issues | ||||||
| #### Abuse by moderators | ||||||
| This proposal does not give substantial new powers to moderators, so we don't think that there is cause for concern here. | ||||||
|
|
||||||
| #### Race conditions | ||||||
| There may be race conditions between e.g. an edition (MSC2767) and marking a message visible/hidden. We do not think that this can cause any real issue. | ||||||
|
|
||||||
| #### Hidden channel | ||||||
| As messages are hidden but still distributed to all clients in the room, it is entirely possible to write a client/bot that ignores hiding and one could imagine using hidden messages to semi-covertly exchange messages in a room. | ||||||
|
|
||||||
| As there are already countless ways to implement this, we don't foresee this to cause any problem. | ||||||
|
|
||||||
| #### Liabilities | ||||||
|
|
||||||
| It is possible that, in some countries, if moderators decide to mark content as hidden but fail to redact it, this could make the homeserver owner legally responsible for illegal content being exchanged through this covert channel. | ||||||
|
|
||||||
| We believe that using a bot that expunges automatically hidden messages after a retention period would avoid such liabilities. | ||||||
|
|
||||||
| ### Alternatives | ||||||
| #### A message to undo a redaction | ||||||
|
|
||||||
| As the original objective of this proposal is to undo redactions, one could imagine a message `m.room.undo_redaction` with the following behavior: | ||||||
|
|
||||||
| * The ability to send a `m.room.undo_redaction` is controlled by a powerlevel, just as `m.room.redaction`. | ||||||
| * When a server receives a `m.room.undo_redaction` for event E, event E loses its "redacted" status, in particular in any future `sync` or `/room/.../event/...` or other, the original event E is returned, rather than its redacted status. | ||||||
| * When a client receives a `m.room.undo_redaction` for an event E, they need to refetch event E from the homeserver. | ||||||
|
|
||||||
| This proposal would have the benefit of removing the hidden channel. | ||||||
|
|
||||||
| However, servers typically purge redacted events after a while, both to save space and to comply with regulations. Unfortunately, if two servers receive a `m.room.undo_redaction` for the same event E, one of the servers may have purged E already. Both servers could make different choices (one server keeping E redacted, the other one making it unredacted). In turn, these choices would end up having different consequences if E subsequently receives a reaction. These consequences would cause divergence between the room views, which is not desirable. | ||||||
|
|
||||||
| We could solve this by requiring that homeservers backup any redacted event, at least for some time, but this might contradict legal requirements in some countries, as well as the privacy preferences of individual administrators. | ||||||
|
|
||||||
| Furthermore, this proposal opens different abuse vectors, through which a malicious moderator could undo a self-redaction by a user, e.g. after accidentally revealing private information. | ||||||
|
|
||||||
| This could be mitigated by not allowing moderators to undo self redactions. | ||||||
|
|
||||||
| #### Injecting content in redacted messages | ||||||
| An alternative mechanism to undo redactions would be to let moderators un-redact a message by injecting new content in it. This would let clients or moderation bots such as Mjölnir implement undoing redactions by first backing up redacted messages (in a manner similar to what we discuss in "Example use"), then if a redaction is canceled, reinjecting content. | ||||||
| We decided not to pursue this mechanism as it is more complicated and it opens abuse vectors by malicious moderators de facto modifying the content of other user's messages (even if this could be mitigated by clients displaying who has modified a user's messages). | ||||||
|
|
||||||
| ### Security considerations | ||||||
| We do not think that this proposal could cause any security issue. | ||||||
|
uhoreg marked this conversation as resolved.
Outdated
|
||||||
|
|
||||||
| ### Unstable prefix | ||||||
|
|
||||||
| During the prototyping phase: | ||||||
|
|
||||||
| - `rel_type` `m.visibility` should be prefixed into `org.matrix.mscXXXX.visibility`; | ||||||
| - field `visibility` should also be prefixed into `org.matrix.mscXXXX.visibility`. | ||||||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.