-
Notifications
You must be signed in to change notification settings - Fork 80
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
Add message redaction #524
Changes from all commits
6f44ee6
d6d45f6
b092e88
0e0f71c
323454d
4efeb02
4962974
4432a2d
15f353d
6328b52
6fe3a60
a70a629
4ba56db
6b2074b
4e0d316
d270474
d5edb9b
06d4c3c
0629dd4
9a97dc1
0258e52
eea9ec4
1680c6b
8ab12e9
dfc1d8b
89e6a3c
8fb0a99
16ccba5
2ef31eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,206 @@ | ||||||
--- | ||||||
title: Message redaction | ||||||
layout: spec | ||||||
work-in-progress: true | ||||||
copyrights: | ||||||
- | ||||||
name: "James Wheare" | ||||||
email: "[email protected]" | ||||||
period: "2020" | ||||||
- | ||||||
name: "Val Lorentz" | ||||||
email: "[email protected]" | ||||||
period: "2023" | ||||||
--- | ||||||
|
||||||
## Notes for implementing work-in-progress version | ||||||
|
||||||
This is a work-in-progress specification. | ||||||
|
||||||
Software implementing this work-in-progress specification MUST NOT use the | ||||||
unprefixed `message-redaction` capability name. | ||||||
Instead, implementations SHOULD use the `draft/message-redaction` capability | ||||||
name to be interoperable with other software implementing a compatible | ||||||
work-in-progress version. | ||||||
|
||||||
The final version of the specification will use an unprefixed capability name. | ||||||
|
||||||
## Introduction | ||||||
|
||||||
This specification enables messages to be deleted. | ||||||
Use cases include retracting accidentally sent messages, moderation, | ||||||
and removing a [`+draft/react` client tag][], amongst others. | ||||||
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. I definitely think that react needs a way to unreact that doesn't rely on this spec. We can maybe mention that reactions can be REDACTed and this should have the same result, but that probably belongs in the react spec, not this one. I would rather remove all references to react in this spec, but I can't think of another TAGMSG for the examples section. Original discussion here: https://github.com/ircv3/ircv3-specifications/pull/425/files#r602543189 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. I think it makes sense to have it both in the intro of this spec, and formally in the react spec |
||||||
These are cosmetic use cases and do not provide any operational security | ||||||
guarantees. | ||||||
|
||||||
## Architecture | ||||||
|
||||||
### Dependencies | ||||||
|
||||||
Clients wishing to use this capability MUST negotiate the [`message-tags`][] | ||||||
capability with the server. | ||||||
Clients SHOULD negotiate the [`echo-message`][] capability in order to receive | ||||||
message IDs for their own messages, so they can be redacted. | ||||||
|
||||||
|
||||||
### Capability | ||||||
|
||||||
This specification adds the `draft/message-redaction` capability. | ||||||
Clients MUST ignore this capability's value, if any. | ||||||
|
||||||
Implementations that negotiate this capability indicate that they are | ||||||
capable of handling the command described below. | ||||||
|
||||||
|
||||||
### Command | ||||||
|
||||||
To redact a message, a client MUST negotiate the `draft/message-redaction` | ||||||
capability and send a `REDACT` command to a target nickname or channel. | ||||||
The command is defined as follows: | ||||||
|
||||||
REDACT <target> <msgid> [<reason>] | ||||||
|
||||||
Where `<msgid>` is the id of the message to be redacted, which MUST be a | ||||||
`PRIVMSG`, `NOTICE`, or `TAGMSG`. | ||||||
|
||||||
An optional `<reason>` MAY be provided. As the last parameter, it MAY contain spaces. | ||||||
If the client is authorised to delete the message, the server: | ||||||
|
||||||
* SHOULD forward this `REDACT`, with an appropriate prefix, to the target | ||||||
recipients that have negotiated the `draft/message-redaction` capability, in the | ||||||
same way as PRIVMSG messages. | ||||||
* MUST not forward this `REDACT` to target recipients that have not negotiated | ||||||
this capability (see "Fallback" below) | ||||||
|
||||||
### Chat history | ||||||
|
||||||
After a message is redacted, [`chathistory`][] responses SHOULD either: | ||||||
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. It would be good to note that |
||||||
|
||||||
* exclude it entirely | ||||||
* replace its content and/or tags with a placeholder and | ||||||
add the `REDACT` message to the response (not counting toward message limits) | ||||||
jwheare marked this conversation as resolved.
Show resolved
Hide resolved
progval marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
after the redacted message | ||||||
* add the `REDACT` message to the response (not counting toward message limits) | ||||||
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. How does this interact with the 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. As in, redacting JOIN/PART/... messages? 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. My question is basically: are 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. I'd say yes. The motivation for 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. Right. I agree. 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. Does this need to be specified in this spec? 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.
This is at odds with #437 (comment). Clients have no way to differentiate between a Standalone
The server must return 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. Why do clients need to differentiate between the two? 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. Per the linked discussion above, my clients check whether there is more history to fetch by counting the number of messages. If it's less than the limit, no more messages. Hm, but now that I've written this, this would only cause the number of messages to exceed the limit, causing needless but harmless chathistory requests in the edge case where there are no more messages. So it should be all fine? Does a standalone 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. didn't the linked discussion settle on the empty batch to signify the end? 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. The discussion hasn't really settled AFAIU, and my clients are still doing the limit check. Please note, there is an interleaved discussion about what should happen when a channel has chathistory disabled, and this one has settled on empty batches instead of a 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. ugh, true 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. There are two ways to fix this issue that I see:
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. Does a resolution to this issue require changes to the redaction spec, or just to the chathistory spec? i.e. is this a blocker for merge/ratification? 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. only the chathistory spec IMO 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. Just spotted this other comment from @emersion that appears unaddressed https://github.com/ircv3/ircv3-specifications/pull/524/files#r1213547049 This PR has become a bit of a nightmare to review lol. |
||||||
after the redacted message | ||||||
|
||||||
### Errors | ||||||
|
||||||
This specification defines `FAIL` messages using the [standard replies][] | ||||||
framework for notifying clients of errors with message editing and deletion. | ||||||
The following codes are defined, with sample plain text descriptions. | ||||||
|
||||||
* `FAIL REDACT INVALID_TARGET <target> :You cannot delete messages from <target>` | ||||||
* `FAIL REDACT REDACT_FORBIDDEN <target> <target-msgid> :You are not authorised to delete this message` | ||||||
* `FAIL REDACT REDACT_WINDOW_EXPIRED <target> <target-msgid> <window> :You can no longer edit this message` | ||||||
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. How is the window communicated to clients? 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. For now, it's not. It could be an informational mode though. 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. It's an easy thing to add later if needed. I don't believe it's worth blocking this PR because of this. |
||||||
* `FAIL REDACT UNKNOWN_MSGID <target> <target-msgid> :This message does not exist or is too old` | ||||||
|
||||||
## Client implementation considerations | ||||||
|
||||||
It is strongly RECOMMENDED that clients provide visible redaction history to users. | ||||||
This helps ensure accountability, and mitigates abuse through malicious or | ||||||
surreptitious redaction. This could be done via a tool tip, or a separate log. | ||||||
Redacted messages MAY be hidden entirely from the primary message log, | ||||||
but a deletion log SHOULD be made available. | ||||||
|
||||||
For the purposes of user interface, clients MAY assume that their own messages | ||||||
are redactable. | ||||||
However, this will not always be the case, and there could be other messages | ||||||
that they have permission to act on. | ||||||
Pending a mechanism for discovering redaction permissions, clients SHOULD | ||||||
allow users to attempt to delete any message via some mechanism. | ||||||
|
||||||
Clients SHOULD NOT provide a default reason if users do not provide one. | ||||||
|
||||||
When a `REDACT` command's `msgid` parameter references a known message not in | ||||||
the `target`'s history, clients MUST ignore it. | ||||||
This allows servers to safely relay `REDACT` commands targeting messages which they | ||||||
did not keep in their history. | ||||||
|
||||||
## Server implementation considerations | ||||||
|
||||||
This section is non-normative. | ||||||
|
||||||
A key motivation for specifying this capability as a server tag, rather than | ||||||
a client-only message tag, is to enable more granular redaction permissions. | ||||||
Clients might be able to determine which messages are their own, but other | ||||||
use cases would not be feasible without server validation. | ||||||
|
||||||
Such use cases might include: | ||||||
|
||||||
* Allowing channel moderators or server admins to delete unwelcome messages from others | ||||||
* Specifying a cut-off time after which message edits are no longer allowed | ||||||
|
||||||
jwheare marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
If a message is redacted while a client is not present in a channel, servers may send the `REDACT` command in a `chathistory` batch when it re-joins the channel. | ||||||
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.
Suggested change
Removes the implication that servers are tracking whether clients are present in a channel or not. Should this section be in the normative part of the spec? 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. The implication was intentional. And the normative already says 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. The spec talks about the chathistory spec, not chathistory batches. 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. ugh. I guess I meant all chathistory batches rather than just chathistory responses 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. I'm still not sure why this implication is necessary. Which servers keep track of past membership when determining whether to send REDACTs in chathistory? 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. none of them, but they could if they wanted to 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. That could apply to a lot of things, what's the motivation for the special case here. Are you thinking of this in the context of e.g. the server can send a REDACT and omit the original PRIVMSG? 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. yes, so that clients end up showing the same things as if they were in the channel the whole time |
||||||
|
||||||
If servers use predictable or guessable `msgid`s, they should consider whether errors | ||||||
returned on `REDACT` may leak a message's existence to users who did not receive it | ||||||
(in a channel they are/were not in or in private messages). | ||||||
|
||||||
### Message validation | ||||||
|
||||||
To implement validation, servers require a mechanism for determining the permissions of | ||||||
a particular edit or delete action. | ||||||
The user requesting the action would need to be compared against properties of | ||||||
the message, given only the message ID and target. | ||||||
|
||||||
Servers with message history storage could look up the message properties from the ID, | ||||||
but this might not be possible or desirable in all cases. | ||||||
Another mechanism could involve encoding any required properties within the message ID | ||||||
itself, e.g. the account ID, timestamp, etc. Servers might choose to encrypt this | ||||||
information if it isn't usually public facing. Any information encoded in a message ID | ||||||
is still opaque and not intended to be parsed by clients. | ||||||
|
||||||
### Fallback | ||||||
|
||||||
Server implementations might choose to inform clients that haven't negotiated | ||||||
the capability that a deletion has taken place. | ||||||
The fallback method used (if any) is left up to server implementations, but | ||||||
could take the form of a standard NOTICE or PRIVMSG with information about the | ||||||
action. | ||||||
It might be preferable to use relative time descriptions if referring to | ||||||
messages in the past, for example: | ||||||
|
||||||
:irc.example.com NOTICE #channel :nickname redacted a message from othernick from 5 seconds ago: spam | ||||||
|
||||||
Implementations might also choose not to send a fallback, if this behaviour | ||||||
is considered too noisy for users. | ||||||
|
||||||
## Security considerations | ||||||
|
||||||
The ability to delete messages does not offer any information or operational | ||||||
security guarantees. | ||||||
Once a message has been sent, assume that it will remain visible to any | ||||||
recipients or servers, whether or not it is subsequently redacted. | ||||||
Above all else, clients that do not support this specification will not see | ||||||
any changes to the original message. | ||||||
|
||||||
## Examples | ||||||
|
||||||
Deleting a PRIVMSG: | ||||||
|
||||||
C: PRIVMSG #channel :an example | ||||||
S: @msgid=123 :nick!u@h PRIVMSG #channel :an example | ||||||
C: REDACT #channel 123 :bad example | ||||||
S: :nick!u@h REDACT #channel 123 :bad example | ||||||
|
||||||
Deleting a TAGMSG: | ||||||
|
||||||
C: @draft/react=🤞TAGMSG #channel | ||||||
S: @msgid=123;draft/react=🤞TAGMSG #channel | ||||||
C: REDACT #channel 123 | ||||||
S: :nick@u@h REDACT #channel 123 | ||||||
|
||||||
Deleting someone else's PRIVMSG: | ||||||
|
||||||
C1: PRIVMSG #channel :join my network for cold hard chats | ||||||
S: @msgid=123 :nick!u@h PRIVMSG #channel :join my network for cold hard chats | ||||||
C2: REDACT #channel 123 spam | ||||||
S: :chanop!u@h REDACT #channel 123 spam | ||||||
|
||||||
|
||||||
[`echo-message`]: ../extensions/echo-message.html | ||||||
[`+draft/react` client tag]: ../client-tags/react.html | ||||||
[standard replies]: ../extensions/standard-replies.html | ||||||
[`message-tags`]: ../extensions/message-tags.html | ||||||
[`msgid`]: ../extensions/message-ids.html | ||||||
[`chathistory`]: ../extensions/chathistory.html |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should happen to existing reactions to the redacted message? And what should happen to attempts to redact such reacts later?