Skip to content
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

MSC2285: Private read receipts #2285

Merged
merged 30 commits into from
Jul 17, 2022
Merged
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
97c3c03
What if we let people hide their read receipts?
turt2live Sep 6, 2019
a4e5b45
Add unstable prefix
turt2live May 25, 2021
40d2aa2
Update proposals/2285-hidden-read-receipts.md
turt2live Aug 10, 2021
4a77139
Use a separate `receiptType` for hidden read receipts (#3750)
SimonBrandner Mar 3, 2022
94fdb2a
Clarify notification behaviour and other things
SimonBrandner May 4, 2022
2cc2ed9
Mention adding `m.fully_read` to `/receipt`
SimonBrandner May 4, 2022
c895850
Rename MSC to `Private read receipts`
SimonBrandner May 5, 2022
84d18d0
Apply suggestions from review
SimonBrandner Jun 28, 2022
55e2060
Apply suggestions from review
SimonBrandner Jun 28, 2022
de850aa
Remove trailing comma
SimonBrandner Jun 28, 2022
f551a77
Apply suggestions from review
SimonBrandner Jun 28, 2022
927b622
Apply suggestions from review
SimonBrandner Jun 28, 2022
18f49eb
`r0` -> `v3`
SimonBrandner Jun 28, 2022
904582f
Describe how to determine server support while stable
SimonBrandner Jul 1, 2022
287c503
Be more precise about the failure mode
SimonBrandner Jul 1, 2022
37f1d53
Improve wording
SimonBrandner Jul 1, 2022
f5c2659
Improve wording
SimonBrandner Jul 1, 2022
887cc0a
Improve wording
SimonBrandner Jul 1, 2022
e8ba93f
Be more explicit
SimonBrandner Jul 1, 2022
9eedb28
Be more explicit around server support
SimonBrandner Jul 2, 2022
8b1b73a
Simplify text
SimonBrandner Jul 4, 2022
4ad1c10
Be more explicit about detecting server support
SimonBrandner Jul 12, 2022
714695c
Add note about consistency
SimonBrandner Jul 12, 2022
aa41d84
Clarify how exactly to detect support
turt2live Jul 12, 2022
5c891d0
Try to fix clarity around precedence
turt2live Jul 12, 2022
252474a
Be clearer about alternatives
SimonBrandner Jul 13, 2022
33ba33c
Add sentence about `/receipt` federation
SimonBrandner Jul 13, 2022
dfd4c9f
Merge remote-tracking branch 'upstream/travis/msc/hidden-read-receipt…
SimonBrandner Jul 13, 2022
23f4a2a
Be more explicit about adding `m.read.private` to `/receipt`
SimonBrandner Jul 13, 2022
839c198
Fix wrong RR type
SimonBrandner Jul 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions proposals/2285-hidden-read-receipts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# MSC2285: Private read receipts
SimonBrandner marked this conversation as resolved.
Show resolved Hide resolved
turt2live marked this conversation as resolved.
Show resolved Hide resolved

Currently users must send read receipts in order to affect their notification
counts, which alerts other people that the user has read their message. For
primarily privacy reasons, it may be desirable to users to not advertise to
others that they've read a message.

## Proposal
turt2live marked this conversation as resolved.
Show resolved Hide resolved

This MSC proposes adding a new `receiptType` (see [the receipts
spec](https://spec.matrix.org/v1.3/client-server-api/#receipts)) of
`m.read.private`. This `receiptType` is used when the user wants to affect their
notification count but doesn't want other users to see their read receipt.

To move the user's private read receipt to `$123` the client can make a POST
request to the [`/receipt`
endpoint](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3roomsroomidreceiptreceipttypeeventid).
For example:

```HTTP
POST /_matrix/client/v3/rooms/!a:example.org/receipt/m.read.private/$123
{}
```

SimonBrandner marked this conversation as resolved.
Show resolved Hide resolved
The MSC also proposes adding `m.fully_read` as a possible `receiptType` for
`/receipt` to make this endpoint consistent with `/read_markers`. (we have two
endpoints that do essentially the same thing, so it would make sense for them to
be consistent)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't quite agree they do the same thing.

There's a notable difference between m.fully_read and m.read in that m.fully_read is private to the user and m.read is open to the world. Receipts, generally, are assumed to be federated, see the respective subsection of "Receipts" section in the client-server API spec. Even though only m.read is defined as of now, the text applies to all receipts. I see two ways out of it:

  1. The proposal to add m.read.private and m.fully_read to /receipt is retracted; the MSC only sticks to read_markers for its purpose (I personally think this is more prudent).
  2. The MSC should explicitly indicate it's no more a given that anything sent over /receipt is federated, and homeservers have to distinguish between federated and non-federated receipts. I wouldn't want to be the one defining the rules of that distinction: note that there's an MSC for user-defined generic EDUs, and even though it doesn't deal with /receipt directly I believe it's a matter of time for the question about adding receipt types to /receipt if that MSC goes through.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read markers are deliberately not able to control notifications, hence the need for a new receipt type in this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can send /read_markers with a sole {"m.read": "$evt" } and it will achieve the same effect as /receipt/m.read (including notifications), no?

Copy link
Contributor

@SimonBrandner SimonBrandner Jul 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't - the m.fully_read field is required (at least in the current spec - this MSC changes this). Though what @turt2live means by read markers in this case is m.fully_read itself, not the /read_markers endpoint, I think

Copy link
Member

@KitsuneRal KitsuneRal Jul 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, right, m.fully_read is mandatory in /read_markers... In that case I suggest to just add m.read.private alongside m.read here, and clarify that, notwithstanding what the spec says in general about receipts, m.read.private receipts are never federated. And I still don't think adding m.fully_read to /receipt would make things consistent because m.fully_read is not a receipt, it's a piece of room account data.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be updated

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't think m.fully_read should be added to /receipt - see above :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To at least comment on the history of this:

/receipt and /read_markers have always been very similar allowing the user to update their m.read and in the case of /read_markers m.fully_read. The idea was to make /receipt more "equal" to /read_markers to make things less confusing (why do these two do almost the same thing but not really?). Now things would be a little more straightforward

Though a new issue arises - /receipt is now rarely used as most of the time it's easier to use /read_markers; with m.read.private even more so. The solution was supposed to be to deprecate /receipt in favour of /read_markers. Then another step would probably be replacing /read_markers with a more flexible and extensible version of itself and deprecating the old version. (this would of course be a whole separate thing)


Alternatively, the client can move the user's `m.fully_read` marker and/or
`m.read` receipt at the same time as `m.read.private` by making a POST request
to the [`/read_markers`
endpoint](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3roomsroomidread_markers).
For example:

```HTTP
POST /_matrix/client/r0/rooms/!a:example.org/read_markers
{
"m.fully_read": "$123",
"m.read": "$123",
"m.read.private": "$123"
}
```

Both `m.read` and `m.read.private` clear notifications in the same way. If the
user sent two receipts into a room, the later one should be the one that decides
the notification count.

The receipt that is more "ahead" of the other takes precedence when considering
notifications and a client's rendering of read receipts. This means that given
an ordered set of events A, B, C, and D the public read receipt could be at
point C, private at point A. If the user moves the private receipt from A to B
then the user's notification count is still considered from point C as the public
receipt is further ahead, still. Other users would also see the user's public read
receipt as not having moved. The user can then move the private read receipt
to point D, hopping over the public receipt, to change their notification count.

For clarity, if the public receipt is "fast forwarded" to be at the same position
as the private receipt then the public receipt is broadcast to other users, even
if previously considered private.

Note that like regular read receipts today, neither receipt can cause a backwards
movement: both receipts can only move forwards, but do not have to be ahead of
each other. It's valid to, for example, update a public read receipt which lags
20 messages behind the private one.

The `m.read` property is now optional for the [`/read_markers`
SimonBrandner marked this conversation as resolved.
Show resolved Hide resolved
endpoint](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3roomsroomidread_markers)
as sometimes we only want to send `m.read.private`.

Servers MUST NOT send receipts of `receiptType` `m.read.private` to any other
user than the sender. Servers also MUST NOT send receipts of `receiptType`
`m.read.private` to any server over federation.

## Security considerations

Servers could act as if `m.read.private` is the same as `m.read` so the user
must already trust the homeserver to a degree however, and the methods of
notifying the user to the problem are difficult to implement. Users can always
run their own homeservers to ensure it behaves correctly.

## Potential issues

Clients which support read receipts would end up rendering the user's receipt as
jumping down when they send a message. This is no different from how IRC and
similarly bridged users are perceived today.

## Alternatives

It has been suggested to use account data to control this on a per-account
basis. While this might have some benefits, it is much less flexible and would
lead to us inventing a way to store per-account settings in account data which
should be handled in a separate MSC.
KitsuneRal marked this conversation as resolved.
Show resolved Hide resolved
turt2live marked this conversation as resolved.
Show resolved Hide resolved

Previous iterations of this MSC additionally suggested that having an `m.hidden`
flag on existing read receipts could work, however this feels like assigning too
much responsibility to an existing structure.
turt2live marked this conversation as resolved.
Show resolved Hide resolved

## Unstable prefix

While this MSC is not considered stable, implementations should use
`org.matrix.msc2285` as a namespace.

|Stable (post-FCP)|Unstable |
|-----------------|---------------------------------|
|`m.read.private` |`org.matrix.msc2285.read.private`|

Clients should check for server support before sending private read receipts:
if the server does not support them, then a private read receipt will not clear
any notifications for the user.

The presence of `org.matrix.msc2285` or `org.matrix.msc2285.stable` in
`unstable_features` is a reliable indication that a server supports private read
receipts; however the converse is not true: their absence does not necessarily
mean that the server does *not* support private read receipts. In particular,
the server may have been updated to a future spec version which includes
private read receipts, and hence removed the `unstable_features` entry.

Therefore, if a client has this feature enabled, but the server does not advertise
support for this MSC in `unstable_features`, the client should either keep sending
private read receipts with the risk that notifications will not be clearing, or it
should warn the user and start sending public read receipts instead.

To mitigate this problem, once this MSC gets merged and once it becomes a part of a
spec version, clients should update their implementations as fast as possible to
accommodate the fact that the way of detecting server support will change: clients
will now be looking for that spec version in `/versions`.

### While the MSC is unstable

During this period, to detect server support clients should check for the
presence of the `org.matrix.msc2285` flag in `unstable_features` on `/versions`.
Clients are also required to use the unstable prefixes (see [unstable
prefix](#unstable-prefix)) during this time.

### Once the MSC is merged but not in a spec version

Once this MSC is merged, but is not yet part of the spec, clients should rely on
the presence of the `org.matrix.msc2285.stable` flag in `unstable_features` to
determine server support. If the flag is present, clients are required to use
stable prefixes (see [unstable prefix](#unstable-prefix)).

### Once the MSC is in a spec version

Once this MSC becomes a part of a spec version, clients should rely on the
presence of the spec version, that supports the MSC, in `versions` on
`/versions`, to determine support. Servers are encouraged to keep the
`org.matrix.msc2285.stable` flag around for a reasonable amount of time
to help smooth over the transition for clients. "Reasonable" is intentionally
left as an implementation detail, however the MSC process currently recommends
*at most* 2 months from the date of spec release.