Skip to content

Commit e51a61a

Browse files
uhoregbwindelsrichvdhdbkr
authored andcommitted
MSC2677: Annotations and reactions (#2677)
* initial version of reactions proposal * fix MSC numbers * add security consideration * remove event type from aggregation grouping criteria because of e2ee * Apply suggestions from code review Co-authored-by: David Baker <dbkr@users.noreply.github.com> * Update intro and add background * Corrections and clarifications to the main text In particular: we *do* aggregate based on event `type` as well as key. * Clarify counting rules and interactions with edits * Error code for deduplicating annotations * Clarify eligible target events * Notes on encryption * Clarify variation-16 * Update 2677-reactions.md * No server-side aggregation for reactions --------- Co-authored-by: Bruno Windels <bruno@windels.cloud> Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: David Baker <dbkr@users.noreply.github.com> Co-authored-by: Richard van der Hoff <richard@matrix.org>
1 parent 5a310fb commit e51a61a

File tree

1 file changed

+294
-0
lines changed

1 file changed

+294
-0
lines changed

proposals/2677-reactions.md

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
# MSC2677: Annotations and Reactions
2+
3+
Users sometimes wish to respond to a message using emojis. When such responses
4+
are grouped visually below the message being reacted to, this provides a
5+
(visually) light-weight way for users to react to messages.
6+
7+
This proposal was originally part of [MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849).
8+
9+
## Background
10+
11+
As with [message
12+
edits](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2676-message-editing.md#background),
13+
support for reactions were landed in the Element clients and Synapse in May
14+
2019, following the proposals of
15+
[MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849) and then
16+
presented as being "production-ready", despite them not yet having been adopted
17+
into the Matrix specification.
18+
19+
Again as with edits, the current situation is therefore that client or server
20+
implementations hoping to interact with Element users must simply follow the
21+
examples of that implementation.
22+
23+
To rectify the situation, this MSC therefore seeks primarily to formalise the
24+
status quo. Although there is plenty of scope for improvement, we consider
25+
that better done in *future* MSCs, based on a shared understanding of the
26+
*current* implementation.
27+
28+
In short, this MSC prefers fidelity to the current implementations over
29+
elegance of design.
30+
31+
On the positive side: this MSC is the last part of the former MSC1849 to be
32+
formalised, and is by far the most significant feature implemented by the
33+
Element clients which has yet to be specified.
34+
35+
## Proposal
36+
37+
### `m.annotation` event relationship type
38+
39+
A new [event relationship type](https://spec.matrix.org/v1.6/client-server-api/#relationship-types)
40+
with a `rel_type` of `m.annotation`.
41+
42+
This relationship type is intended primarily for handling emoji reactions, allowing clients to
43+
send an event which annotates an existing event.
44+
45+
Another potential usage of annotations is for bots, which could use them to
46+
report the success/failure or progress of a command.
47+
48+
Along with the normal properties `event_id` and `rel_type`, the
49+
[`m.relates_to`](https://spec.matrix.org/v1.6/client-server-api/#definition-mrelates_to)
50+
property should contains a `key` that indicates the annotation being
51+
applied. For example, when reacting with emojis, the `key` contains the emoji
52+
being used.
53+
54+
An event annotating another with the thumbs-up emoji would therefore have the following `m.relates_to` propperty:
55+
56+
```json
57+
"m.relates_to": {
58+
"rel_type": "m.annotation",
59+
"event_id": "$some_event_id",
60+
"key": "👍"
61+
}
62+
```
63+
64+
When sending emoji reactions, the `key` property should include the unicode
65+
[emoji presentation
66+
selector](https://www.unicode.org/reports/tr51/#def_emoji_presentation_selector)
67+
(`\uFE0F`) for codepoints which allow it (see the [emoji variation sequences
68+
list](https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-variation-sequences.txt)).
69+
70+
Any `type` of event is eligible for an annotation, including state events.
71+
72+
### `m.reaction` event type
73+
74+
A new message type `m.reaction` is proposed to indicate that a user is reacting
75+
to a message. No `content` properties are defined for this event type: it serves
76+
only to hold a relationship to another event.
77+
78+
For example, an `m.reaction` event which annotates an existing event with a 👍
79+
looks like:
80+
81+
```json
82+
{
83+
"type": "m.reaction",
84+
"content": {
85+
"m.relates_to": {
86+
"rel_type": "m.annotation",
87+
"event_id": "$some_event_id",
88+
"key": "👍"
89+
}
90+
}
91+
}
92+
```
93+
94+
Since they contain no `content` other than `m.relates_to`, `m.reaction` events
95+
are normally not encrypted, as there would be no benefit in doing so. (However,
96+
see [Encrypted reactions](#encrypted-reactions) below.)
97+
98+
### Interation with edited events
99+
100+
It is not considered valid to send an annotation for a [replacement
101+
event](https://spec.matrix.org/v1.6/client-server-api/#event-replacements)
102+
(i.e., a message edit event): any reactions should refer to the original
103+
event. Annotations of replacement events will be ignored according to the rules
104+
for [counting annotations](#counting-annotations).
105+
106+
As an aside, note that it is not possible to edit a reaction, since replacement
107+
events do not change `m.relates_to` (see [Applying
108+
`m.new_content`](https://spec.matrix.org/v1.6/client-server-api/#applying-mnew_content)),
109+
and there is no other meaningful content within `m.reaction`. If a user wishes
110+
to change their reaction, the original reaction should be redacted and a new
111+
one sent in its place.
112+
113+
### Counting annotations
114+
115+
The intention of annotations is that they are counted up, rather than being displayed individually.
116+
117+
Clients must keep count of the number of annotations with a given event `type`
118+
and annotation `key` they observe for each event; these counts are typically
119+
presented alongside the event in the timeline.
120+
121+
When performing this count:
122+
123+
* Each event `type` and annotation `key` should normally be counted separately,
124+
though whether to actually do so is an implementation decision.
125+
126+
* Annotation events sent by [ignored users](https://spec.matrix.org/v1.6/client-server-api/#ignoring-users)
127+
should be excluded from the count.
128+
129+
* Multiple identical annotations (i.e., with the same event `type` and
130+
annotation `key`) from the same user (i.e., events with the same `sender`) should
131+
be treated as a single annotation.
132+
133+
* It is not considered valid to annotate an event which itself has an
134+
`m.relates_to` with `rel_type: m.annotation` or `rel_type:
135+
m.replace`. Implementations should ignore any such annotation events.
136+
137+
* When an annotation is redacted, it is removed from the count.
138+
139+
### Push rules
140+
141+
Since reactions are considered "metadata" that annotate an existing event, they
142+
should not by default trigger notifications. Thus a new [default override
143+
rule](https://spec.matrix.org/v1.6/client-server-api/#default-override-rules)
144+
is to be added that ignores reaction events:
145+
146+
```json
147+
{
148+
"rule_id": ".m.rule.reaction",
149+
"default": true,
150+
"enabled": true,
151+
"conditions": [
152+
{
153+
"kind": "event_match",
154+
"key": "type",
155+
"pattern": "m.reaction"
156+
}
157+
],
158+
"actions": []
159+
}
160+
```
161+
162+
The rule is added between `.m.rule.tombstone` and `.m.rule.room.server_acl`.
163+
164+
(Synapse implementation: [base_rules.rs](https://github.com/matrix-org/synapse/blob/157c571f3e9d3d09cd763405b6a9eb967f2807e7/rust/src/push/base_rules.rs#L216-L229))
165+
166+
### Server support
167+
168+
#### Avoiding duplicate annotations
169+
170+
Homeservers should prevent users from sending a second annotation for a given
171+
event with identical event `type` and annotation `key` (unless the first event
172+
has been redacted).
173+
174+
Attempts to send such an annotation should be rejected with a 400 error and an
175+
error code of `M_DUPLICATE_ANNOTATION`.
176+
177+
Note that this does not guarantee that duplicate annotations will not arrive
178+
over federation. Clients and servers are responsible for deduplicating received
179+
annotations when [counting annotations](#counting-annotations).
180+
181+
#### Server-side aggregation of `m.annotation` relationships
182+
183+
`m.annotation` relationships are *not* [aggregated](https://spec.matrix.org/v1.6/client-server-api/#aggregations)
184+
by the server. In other words, `m.annotation` is not included in the `m.relations` property.
185+
186+
## Alternatives
187+
188+
### Encrypted reactions
189+
190+
[matrix-spec#660](https://github.com/matrix-org/matrix-spec/issues/660)
191+
discusses the possibility of encrypting message relationships in general.
192+
193+
Given that reactions do not rely on server-side aggregation support, an easier
194+
solution to encrypting reactions might be not to use the relationships
195+
framework at all and instead just use a keys within `m.reaction` events, which
196+
could then be encrypted. For example, a reaction could instead be formatted as:
197+
198+
```json5
199+
{
200+
"type": "m.reaction",
201+
"content": {
202+
"event_id": "$some_event_id",
203+
"key": "👍"
204+
}
205+
}
206+
```
207+
208+
### Extended annotation use case
209+
210+
In future it might be useful to be able to annotate events with more
211+
information, some examples include:
212+
213+
* Annotate commit/PR notification messages with their associated CI state, e.g.
214+
pending/passed/failed.
215+
* If a user issues a command to a bot, e.g. `!deploy-site` the bot could
216+
annotate that event with current state, like "acknowledged",
217+
"redeploying...", "success", "failed", etc.
218+
* Other use cases...?
219+
220+
However, this doesn't really work with the proposed grouping, as the aggregation
221+
key wouldn't contain the right information needed to display it (unlike for
222+
reactions).
223+
224+
One way to potentially support this is to include the events (or a subset of the
225+
event) when grouping, so that clients have enough information to render them.
226+
However this dramatically inceases the size of the parent event if we bundle the
227+
full events inside, even if limit the number we bundle in. To reduce the
228+
overhead the annotation event could include a `m.result` field which gets
229+
included.
230+
231+
This would look something like the following, where the annotation is:
232+
233+
```json
234+
{
235+
"type": "m.bot_command_response",
236+
"content": {
237+
"m.result": {
238+
"state": "success",
239+
},
240+
"m.relates_to": {
241+
"type": "m.annotation",
242+
"key": ""
243+
}
244+
}
245+
}
246+
```
247+
248+
and gets bundled into an event like:
249+
250+
```json
251+
{
252+
"unsigned": {
253+
"m.relations": {
254+
"m.annotation": [
255+
{
256+
"type": "m.bot_command_response",
257+
"key": "",
258+
"count": 1,
259+
"chunk": [
260+
{
261+
"m.result": {
262+
"state": "success",
263+
},
264+
}
265+
],
266+
"limited": false,
267+
}
268+
]
269+
}
270+
}
271+
}
272+
```
273+
274+
This is something that could be added later on. A few issues with this are:
275+
276+
* How does this work with E2EE? How do we encrypt the `m.result`?
277+
* We would end up including old annotations that had been superceded, should
278+
these be done via edits instead?
279+
280+
## Security considerations
281+
282+
Clients should render reactions that have a long `key` field in a sensible
283+
manner. For example, clients can elide overly-long reactions.
284+
285+
If using reactions for upvoting/downvoting purposes we would almost certainly want to anonymise the
286+
reactor, at least from other users if not server admins, to avoid retribution problems.
287+
This gives an unfair advantage to people who run their own servers however and
288+
can cheat and deanonymise (and publish) reactor details. In practice, reactions may
289+
not be best used for upvote/downvote as at the unbundled level they are intrinsically
290+
private data.
291+
292+
Or in a MSC1228 world... we could let users join the room under an anonymous
293+
persona from a big public server in order to vote? However, such anonymous personae
294+
would lack any reputation data.

0 commit comments

Comments
 (0)