Spec MSC2285: Private read receipts (#1216)
* Convert `m.receipt.yaml` to traditional YAML * Spec MSC2285 (private read receipts) * Add some obvious copyright headers * Add changelog entries * Appease the linter Apparently it hates it when you do this. * Allow m.fully_read on /receipts * Apply suggestions from code review Co-authored-by: Matthew Hodgson <matthew@matrix.org> Co-authored-by: Matthew Hodgson <matthew@matrix.org>
This commit is contained in:
parent
a6990ff27c
commit
e406bd94f6
10 changed files with 146 additions and 66 deletions
1
changelogs/client_server/newsfragments/1216.feature.1
Normal file
1
changelogs/client_server/newsfragments/1216.feature.1
Normal file
|
@ -0,0 +1 @@
|
|||
Add `m.read.private` receipts, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
1
changelogs/client_server/newsfragments/1216.feature.2
Normal file
1
changelogs/client_server/newsfragments/1216.feature.2
Normal file
|
@ -0,0 +1 @@
|
|||
Make `m.fully_read` optional on `/read_markers`, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
1
changelogs/client_server/newsfragments/1216.feature.3
Normal file
1
changelogs/client_server/newsfragments/1216.feature.3
Normal file
|
@ -0,0 +1 @@
|
|||
Allow `m.fully_read` markers to be set from `/receipts`, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
|
@ -107,7 +107,19 @@ determined by the push rules which apply to an event.
|
|||
|
||||
When the user updates their read receipt (either by using the API or by
|
||||
sending an event), notifications prior to and including that event MUST
|
||||
be marked as read.
|
||||
be marked as read. Note that users can send both an `m.read` and
|
||||
`m.read.private` receipt, both of which are capable of clearing notifications.
|
||||
|
||||
If the user has both `m.read` and `m.read.private` set in the room then
|
||||
the receipt which is more recent/ahead must be used to determine where
|
||||
the user has read up to. For example, given an oldest-first set of events A,
|
||||
B, C, and D the `m.read` receipt could be at event C and `m.read.private`
|
||||
at event A - the user is considered to have read up to event C. If the
|
||||
`m.read.private` receipt is then updated to point to B or C, the user's
|
||||
notification state doesn't change (the `m.read` receipt is still more
|
||||
ahead), however if the `m.read.private` receipt were to be updated to
|
||||
event D then the user has read up to D (the `m.read` receipt is now
|
||||
behind the `m.read.private` receipt).
|
||||
|
||||
##### Push Rules
|
||||
|
||||
|
|
|
@ -31,12 +31,16 @@ The client cannot update fully read markers by directly modifying the
|
|||
`m.fully_read` account data event. Instead, the client must make use of
|
||||
the read markers API to change the values.
|
||||
|
||||
{{< changed-in v="1.4" >}} `m.read.private` receipts can now be sent from
|
||||
`/read_markers`.
|
||||
|
||||
The read markers API can additionally update the user's read receipt
|
||||
(`m.read`) location in the same operation as setting the fully read
|
||||
marker location. This is because read receipts and read markers are
|
||||
commonly updated at the same time, and therefore the client might wish
|
||||
to save an extra HTTP call. Providing an `m.read` location performs the
|
||||
same task as a request to `/receipt/m.read/$event:example.org`.
|
||||
(`m.read` or `m.read.private`) location in the same operation as setting
|
||||
the fully read marker location. This is because read receipts and read
|
||||
markers are commonly updated at the same time, and therefore the client
|
||||
might wish to save an extra HTTP call. Providing `m.read` and/or
|
||||
`m.read.private` performs the same task as a request to
|
||||
[`/receipt/{receiptType}/{eventId}`](#post_matrixclientv3roomsroomidreceiptreceipttypeeventid).
|
||||
|
||||
{{% http-api spec="client-server" api="read_markers" %}}
|
||||
|
||||
|
@ -44,8 +48,9 @@ same task as a request to `/receipt/m.read/$event:example.org`.
|
|||
|
||||
The server MUST prevent clients from setting `m.fully_read` directly in
|
||||
room account data. The server must additionally ensure that it treats
|
||||
the presence of `m.read` in the `/read_markers` request the same as how
|
||||
it would for a request to `/receipt/m.read/$event:example.org`.
|
||||
the presence of `m.read` and `m.read.private` in the `/read_markers`
|
||||
request the same as how it would for a request to
|
||||
[`/receipt/{receiptType}/{eventId}`](#post_matrixclientv3roomsroomidreceiptreceipttypeeventid).
|
||||
|
||||
Upon updating the `m.fully_read` event due to a request to
|
||||
`/read_markers`, the server MUST send the updated account data event
|
||||
|
|
|
@ -4,10 +4,14 @@ type: module
|
|||
|
||||
### Receipts
|
||||
|
||||
{{< changed-in v="1.4" >}} Added private read receipts.
|
||||
|
||||
This module adds in support for receipts. These receipts are a form of
|
||||
acknowledgement of an event. This module defines a single
|
||||
acknowledgement: `m.read` which indicates that the user has read up to a
|
||||
given event.
|
||||
acknowledgement of an event. This module defines the `m.read` receipt
|
||||
for indicating that the user has read up to a given event, and `m.read.private`
|
||||
to achieve the same purpose without any other user being aware. Primarily,
|
||||
`m.read.private` is intended to clear [notifications](#receiving-notifications)
|
||||
without advertising read-up-to status to others.
|
||||
|
||||
Sending a receipt for each event can result in sending large amounts of
|
||||
traffic to a homeserver. To prevent this from becoming a problem,
|
||||
|
@ -59,12 +63,36 @@ following HTTP APIs.
|
|||
|
||||
{{% http-api spec="client-server" api="receipts" %}}
|
||||
|
||||
##### Private read receipts
|
||||
|
||||
{{% added-in v="1.4" %}}
|
||||
|
||||
Some users would like to mark a room as read, clearing their [notification counts](#receiving-notifications),
|
||||
but not give away the fact that they've read a particular message yet. To
|
||||
achieve this, clients can send `m.read.private` receipts instead of `m.read`
|
||||
to do exactly that: clear notifications and not broadcast the receipt to
|
||||
other users.
|
||||
|
||||
Servers MUST NOT send the `m.read.private` receipt to any other user than the
|
||||
one which originally sent it.
|
||||
|
||||
Between `m.read` and `m.read.private`, the receipt which is more "ahead" or
|
||||
"recent" is used when determining the highest read-up-to mark. See the
|
||||
[notifications](#receiving-notifications) section for more information on
|
||||
how this affects notification counts.
|
||||
|
||||
If a client sends an `m.read` receipt which is "behind" the `m.read.private`
|
||||
receipt, other users will see that change happen but the sending user will
|
||||
not have their notification counts rewound to that point in time. While
|
||||
uncommon, it is considered valid to have an `m.read` (public) receipt lag
|
||||
several messages behind the `m.read.private` receipt, for example.
|
||||
|
||||
#### Server behaviour
|
||||
|
||||
For efficiency, receipts SHOULD be batched into one event per room
|
||||
before delivering them to clients.
|
||||
|
||||
Receipts are sent across federation as EDUs with type `m.receipt`. The
|
||||
Some receipts are sent across federation as EDUs with type `m.receipt`. The
|
||||
format of the EDUs are:
|
||||
|
||||
```
|
||||
|
@ -80,7 +108,8 @@ format of the EDUs are:
|
|||
```
|
||||
|
||||
These are always sent as deltas to previously sent receipts. Currently
|
||||
only a single `<receipt_type>` should be used: `m.read`.
|
||||
only a single `<receipt_type>` should be used: `m.read`. `m.read.private`
|
||||
MUST NOT appear in this federated `m.receipt` EDU.
|
||||
|
||||
#### Security considerations
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright 2018 New Vector Ltd
|
||||
# Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -56,6 +57,9 @@ paths:
|
|||
The event ID the read marker should be located at. The
|
||||
event MUST belong to the room.
|
||||
example: "$somewhere:example.org"
|
||||
x-changedInMatrixVersion:
|
||||
1.4: |
|
||||
This property is no longer required.
|
||||
"m.read":
|
||||
type: string
|
||||
description: |-
|
||||
|
@ -63,11 +67,18 @@ paths:
|
|||
equivalent to calling `/receipt/m.read/$elsewhere:example.org`
|
||||
and is provided here to save that extra call.
|
||||
example: "$elsewhere:example.org"
|
||||
required: ['m.fully_read']
|
||||
"m.read.private":
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
type: string
|
||||
description: |-
|
||||
The event ID to set the *private* read receipt location at. This
|
||||
equivalent to calling `/receipt/m.read.private/$elsewhere:example.org`
|
||||
and is provided here to save that extra call.
|
||||
example: "$elsewhere:example.org"
|
||||
responses:
|
||||
200:
|
||||
description: |-
|
||||
The read marker, and read receipt if provided, have been updated.
|
||||
The read marker, and read receipt(s) if provided, have been updated.
|
||||
schema:
|
||||
type: object
|
||||
properties: {}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright 2016 OpenMarket Ltd
|
||||
# Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -46,10 +47,19 @@ paths:
|
|||
- in: path
|
||||
type: string
|
||||
name: receiptType
|
||||
description: The type of receipt to send.
|
||||
description: |-
|
||||
The type of receipt to send. This can also be `m.fully_read` as an
|
||||
alternative to [`/read_makers`](/client-server-api/#post_matrixclientv3roomsroomidread_markers).
|
||||
|
||||
Note that `m.fully_read` does not appear under `m.receipt`: this endpoint
|
||||
effectively calls `/read_markers` internally when presented with a receipt
|
||||
type of `m.fully_read`.
|
||||
required: true
|
||||
x-example: "m.read"
|
||||
enum: ["m.read"]
|
||||
x-changedInMatrixVersion:
|
||||
1.4: |
|
||||
Allow `m.read.private` receipts and `m.fully_read` markers to be set.
|
||||
enum: ["m.read", "m.read.private", "m.fully_read"]
|
||||
- in: path
|
||||
type: string
|
||||
name: eventId
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
"@rikj:jki.re": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
},
|
||||
"m.read.private": {
|
||||
"@self:example.org": {
|
||||
"ts": 1661384801651
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,54 @@
|
|||
{
|
||||
"type": "object",
|
||||
"title": "Receipt Event",
|
||||
"description": "Informs the client of new receipts.",
|
||||
"allOf": [{
|
||||
"$ref": "core-event-schema/event.yaml"
|
||||
}],
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^\\$": {
|
||||
"type": "object",
|
||||
"x-pattern": "$EVENT_ID",
|
||||
"title": "Receipts",
|
||||
"description": "The mapping of event ID to a collection of receipts for this event ID. The event ID is the ID of the event being acknowledged and *not* an ID for the receipt itself.",
|
||||
"properties": {
|
||||
"m.read": {
|
||||
"type": "object",
|
||||
"title": "Users",
|
||||
"description": "A collection of users who have sent `m.read` receipts for this event.",
|
||||
"patternProperties": {
|
||||
"^@": {
|
||||
"type": "object",
|
||||
"title": "Receipt",
|
||||
"description": "The mapping of user ID to receipt. The user ID is the entity who sent this receipt.",
|
||||
"x-pattern": "$USER_ID",
|
||||
"properties": {
|
||||
"ts": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "The timestamp the receipt was sent at."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["m.receipt"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "content"]
|
||||
}
|
||||
type: object
|
||||
title: Receipt Event
|
||||
description: Informs the client of new receipts.
|
||||
x-changedInMatrixVersion:
|
||||
1.4: |
|
||||
Added `m.read.private` receipts to the event's `content`.
|
||||
allOf:
|
||||
- $ref: "core-event-schema/event.yaml"
|
||||
properties:
|
||||
content:
|
||||
type: object
|
||||
patternProperties:
|
||||
"^\\$":
|
||||
type: object
|
||||
x-pattern: "$EVENT_ID"
|
||||
title: Receipts
|
||||
description: |-
|
||||
The mapping of event ID to a collection of receipts for this
|
||||
event ID. The event ID is the ID of the event being acknowledged
|
||||
and *not* an ID for the receipt itself.
|
||||
properties:
|
||||
"m.read":
|
||||
type: object
|
||||
title: Users
|
||||
description: |-
|
||||
A collection of users who have sent `m.read` receipts for
|
||||
this event.
|
||||
patternProperties:
|
||||
"^@": &receiptUserMap
|
||||
type: object
|
||||
title: Receipt
|
||||
description: |-
|
||||
The mapping of user ID to receipt. The user ID is the
|
||||
entity who sent this receipt.
|
||||
x-pattern: "$USER_ID"
|
||||
properties:
|
||||
ts:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The timestamp the receipt was sent at.
|
||||
"m.read.private":
|
||||
type: object
|
||||
title: Own User
|
||||
description: |-
|
||||
Similar to `m.read`, the users who have sent `m.read.private`
|
||||
receipts for this event. Due to the nature of private read
|
||||
receipts, this should only ever have the current user's ID.
|
||||
patternProperties:
|
||||
"^@": *receiptUserMap
|
||||
additionalProperties: false
|
||||
type:
|
||||
type: string
|
||||
enum: ["m.receipt", "m.receipt.private"]
|
||||
required: ["type", "content"]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue