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

MSC4140: Cancellable delayed events #4140

Open
wants to merge 85 commits into
base: main
Choose a base branch
from
Open
Changes from 4 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
480b00a
draft for expiring event PR
toger5 May 7, 2024
8839b8d
Add msc number
toger5 May 7, 2024
8bf6db7
add security consideration and alternatives
toger5 May 7, 2024
8ec6374
alternative name and alternative content
toger5 May 8, 2024
9f45cfa
review andrewF
toger5 May 8, 2024
54fff99
draft of iteration two (after meeting with the backend team)
toger5 May 10, 2024
abdfe1c
timeout_refresh_token is not a well description since the same token …
toger5 May 13, 2024
53f6186
rename msc, rephrase introduction
toger5 May 14, 2024
087c74e
Add usecase specific section.
toger5 May 20, 2024
538b853
add GET futures endpoint
toger5 May 20, 2024
f7a1aad
shorten introduction
toger5 May 21, 2024
f5f4b38
add alternative section to not include the `m.send_now` field
toger5 May 22, 2024
c16afbc
Update proposals/4140-delayed-events-futures.md
toger5 May 31, 2024
c52c80d
batch sending considerations
toger5 May 31, 2024
bf22260
Update proposals/4140-delayed-events-futures.md
toger5 Jun 3, 2024
7f0d80f
Update proposals/4140-delayed-events-futures.md
toger5 Jun 3, 2024
7b192ac
Update proposals/4140-delayed-events-futures.md
toger5 Jun 3, 2024
f3bf66d
review
toger5 Jun 3, 2024
2d7b27d
add background to usecase specific considerations
toger5 Jun 4, 2024
1140ce9
Simplify main proposal for widget api usage
toger5 Jun 5, 2024
0a7896e
make `future_group_id` server generated and small adjustments
toger5 Jun 6, 2024
8fa33d6
review
toger5 Jun 6, 2024
49d5294
user scoping details
toger5 Jun 13, 2024
7550d9b
Update proposals/4140-delayed-events-futures.md
toger5 Jun 13, 2024
a663bb4
add rate limiting section
toger5 Jun 14, 2024
99b3a20
rename `/futures` to `/future`
toger5 Jun 19, 2024
eb50a19
Update everything to v1
toger5 Jun 20, 2024
9ff051e
Update proposals/4140-delayed-events-futures.md
toger5 Jun 22, 2024
425b9bf
review
toger5 Jun 24, 2024
2e7be46
Swap the alternative of reusing the send and state request with the m…
toger5 Jun 24, 2024
5653fe1
add reference to MSC4143 (MatrixRTC)
toger5 Jul 2, 2024
af060cf
Meeting feedback:
toger5 Jul 15, 2024
bff704c
remove parent concept.
toger5 Jul 22, 2024
fa461e2
Refactor + unstable prefixes
hughns Jul 23, 2024
d195218
Update to GET /futures
hughns Jul 23, 2024
b5ac9b2
Standardise endpoint for interacting with futures
hughns Jul 23, 2024
c07dd9b
Make it clear that events can be cancelled
hughns Jul 24, 2024
b79e4e2
Make wording more authoritative
hughns Jul 24, 2024
e125901
Remove erroneous old example
hughns Jul 24, 2024
0443cd9
Take view that clients don't act on behalf of a user
hughns Jul 24, 2024
7df0919
Use name delay_id and delayed_events
hughns Jul 24, 2024
ff95144
Clean up more references to future
hughns Jul 24, 2024
93c932a
event_type => type
hughns Jul 24, 2024
6cce3bd
Tidying
hughns Jul 24, 2024
ac2d2c5
Pagination on GET endpoint
hughns Jul 24, 2024
84e20fd
Add alternative of M_INVALID_PARAM
hughns Jul 24, 2024
ac3bd9d
change order of manage <-> get sections
toger5 Jul 25, 2024
de77a90
Obey lint rules and more renames
toger5 Jul 25, 2024
677d6f3
TOC update
hughns Jul 25, 2024
4caecd1
Additional notes on security considerations
hughns Jul 25, 2024
c482d58
Add rate limiting requirements
hughns Jul 25, 2024
9098fea
Describe MatrixRTC use case in terms of heartbeats
hughns Jul 25, 2024
7e06e85
"leave" => "hangup" for consistency
hughns Jul 25, 2024
a1b8121
Wording clarification
hughns Jul 25, 2024
3a3a5b5
Additional reference to heartbeat
hughns Jul 25, 2024
97d4141
TOC update (use monospace and dont list msc title
toger5 Jul 25, 2024
99c9467
be consistent with "restart" wording (we used reset, refresh and rest…
toger5 Jul 25, 2024
6f2aa5e
Add compatibility with Cryptographic Identities to potenail issues
hughns Jul 25, 2024
5e43db0
Add placeholder for MSC3277
hughns Jul 25, 2024
84b8dc0
Add note about MSC2716 batch sending
hughns Jul 25, 2024
e7d0986
Add alternative of not providing a send action
hughns Jul 25, 2024
850bf9e
Add alternative of using DELETE HTTP method
hughns Jul 25, 2024
e1b460a
Add clarification about regular/non-state events not getting cancelled
hughns Jul 25, 2024
114da1e
Clarify contents of content field on GET response
hughns Jul 25, 2024
772590f
Expose transaction ID in GET response
hughns Jul 25, 2024
4a2ca48
Add context on MSC3277 alternative
hughns Jul 25, 2024
37979cd
Add more context to MQTT style alternative
hughns Jul 25, 2024
195ab6a
Add alternative of typing notifications
hughns Jul 25, 2024
0f8a2d1
Update TOC
hughns Jul 26, 2024
886f378
Fix TOC
hughns Aug 2, 2024
8523ed4
Note on alternative names for `running_since`
hughns Aug 2, 2024
883e6b5
Revert "Expose transaction ID in GET response"
AndrewFerr Sep 11, 2024
caece4d
Scope GET to only the requesting user's events
AndrewFerr Sep 11, 2024
28970ec
remove all references to future (except where we actually talk about …
toger5 Oct 1, 2024
2f57b0b
add terminated events section to GET endpoint
toger5 Oct 1, 2024
9d5c93a
use case specific considerations details
toger5 Oct 1, 2024
da3d75e
remove batch sending endpoint since that does not make sense in the s…
toger5 Oct 2, 2024
f7e4e9b
Clean up iteration with two significant changes:
toger5 Oct 4, 2024
b8e317f
terminated -> finalised
toger5 Oct 4, 2024
b499995
andrews changes
toger5 Oct 4, 2024
8dc05a4
requried -> required
AndrewFerr Oct 7, 2024
0a777f4
Change example of "canceled" outcome to "cancel"
AndrewFerr Oct 8, 2024
a09a883
Minor formatting changes
AndrewFerr Oct 9, 2024
72a808e
Allow servers to discard returned finalised events
AndrewFerr Oct 22, 2024
d1a37f0
Define finalised events for /sync & /transactions
AndrewFerr Oct 22, 2024
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
170 changes: 170 additions & 0 deletions proposals/4140-expiring-events-with-keep-alive-endpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# MSC4140: Expiring events with keep alive endpoint

Currently there is no mechanism for a client to provide a reliable way of
communicating that an event is still valid. The best expiration method is to post
another event that is stores that it is expired.
In some situations the client just looses connection or fails to sent the expired
version of the event.
A generic way is desired in which the event gets marked as expired by the homeserver.

Clients can then perform custom logic based on if the event is in valid or
expired state.

This is particularly interesting in the context of matrixRTC where we want
to ignore expired state events of users who left the call without sending a new
state empty `m.call.member` event.

We would like the homeserver to mark this event as expired in a reasonable
time window after a user disconnected.

## Proposal

Events can contain a `m.will_expire: "running" | "expired" | "ended"` field.
This is an enum marking the event as
expired `m.will_expire: "expired" | "ended"` or still alive `m.will_expire: "running"`.
This field lives outside the ciphertext content (hence it also works for encrypted
events) and is set via the usual `PUT` request if the content contains the additional
`m.will_expire: 10` field (similar how it is done with relations), with the desired
timeout duration in seconds.
AndrewFerr marked this conversation as resolved.
Show resolved Hide resolved

Request

```json
{
"m.will_expire": 10,
"body": "hello"
}
```

If the homeserver detects a `m.expired` field it will store and distribute the
toger5 marked this conversation as resolved.
Show resolved Hide resolved
event as hiding the timeout duration:

```json
{
"content":{
"m.will_expire": "running",
"body": "hello",
},
"other_fields":"sender, origin_server_ts ..."
}
```

The response to the client will be:

```json
{
"eventId": "hash_id",
"expire_refresh_token": "hash_refresh",
}
```

The default response is extended with the `expire_refresh_token` which
can be used to reset the expiration timeout (in this example 10 seconds).
A new unauthenticated endpoint is introduced:
`PUT /_matrix/client/v3/expiration/{refresh_method}`
where the `refresh_method` is either: `refresh`, `end`
toger5 marked this conversation as resolved.
Show resolved Hide resolved
The body contains the refresh token so the homeserver knows what to refresh.

```json
{
"expire_refresh_token": "hash_refresh",
}
```
toger5 marked this conversation as resolved.
Show resolved Hide resolved

The information required to call this endpoint is very limited so that almost
no metadata is leaked when. This allows to share a refresh link to a different
toger5 marked this conversation as resolved.
Show resolved Hide resolved
service (an SFU for instance) that can track the current client connection state,
and pings the HS to refresh and informs the HS about a disconnect.

The homeserver does the following when receiving an event with `m.expired`
toger5 marked this conversation as resolved.
Show resolved Hide resolved

- It generates a token and stores it alongside with the time of retrieval,
the eventId and the expire duration.
- Starts a counter for the stored expiation token.
toger5 marked this conversation as resolved.
Show resolved Hide resolved
- If a `PUT /_matrix/client/v3/expiration/refresh` is received, the
timer is restarted with the stored expire duration.
AndrewFerr marked this conversation as resolved.
Show resolved Hide resolved
- If a `PUT /_matrix/client/v3/expiration/end` is received, the
event _gets ended_.
- If the timer times out, the event _gets expired_.
- If the event is a state event only the latest/current state is considered. If
the homeserver receives a new state event without `m.expires` but with the same
toger5 marked this conversation as resolved.
Show resolved Hide resolved
state key, the expire_refresh_token gets invalidated and the associated timer is
stopped.

The event _gets expired_/_gets ended_ means:

- The homeserver **sends a new event** that is a copy of the previous event but:
- If it gets _expired_ the event will include: `"m.will_expire": "expired"`
- If it gets _ended_ the event will include: `"m.will_expire": "ended"`.
- Additionally it includes a relation to the original event with `rel_type: "m.expire.relationship"`

```json
"m.relates_to": {
"event_id": "$original_event",
"rel_type": "m.expire.relationship"
},
"m.will_expire": "ended" | "expired",
```

- The homeserver stops the associated timer and invalidates (deletes) the `expire_refresh_token`

So for each event that is sent with `m.will_expire: X` where X is duration in
seconds > 0. The homeserver will sent another event which can be used to trigger
logic on the client. This allows for any generic timeout logic.

Timed messages/reminders could also be implemented using this where clients ignore
the `"will_expire":"running"` events for a specific event type but render the
`"will_expire":"expired"` events.

## Potential issues

## Alternatives

[MSC4018](https://github.com/matrix-org/matrix-spec-proposals/pull/4018) also
proposes a way to make call memberships reliable. It uses the client sync loop as
an indicator to determine if the event is expired. Instead of letting the SFU
inform about the call termination or using the call app ping loop like we propose
here.

---
It might not be necessary to change the value of `"m.will_expire" = 10` to
`"m.will_expire" = "running"` it makes it easier to understand and also
hides more potential metadata but it is questionable if that bring any benefit.

---
The name `m.will_expire` has been chosen since it communicates that it becomes
invalid. And that it is an event that automatically changes state
(`will_expire` vs `expired`). But it does not imply what expired vs non expired
means, it is flexible in how can be used.
Alternatives could by:

- `m.alive`
- pro: communicates it might change (alive is always temporal)
- con: ver strong bias on how to use it `valid/invalid`
- `m.timeout`
- pro: very unbiased in how its used - timeout over can also mean the client
will show a reminder.
- pro: clear that it has something to do with time.
- con: not so clear the homeserver will automatically do sth.
- con: not so clear that this timeout can be refreshed?

## Security considerations

We are using unauthenticated endpoint to refresh the expirations. Since we use
the token it is hard to guess a correct endpoint and randomly end `will_expire`
events.

It is an intentional decision to not provide an endpoint like
`PUT /_matrix/client/v3/expiration/room/{roomId}/event/{eventId}`
where any client with access to the room could also `end` or `refresh`
the expiration. With the token the client sending the event has ownership
over the expiration and only intentional delegation of that ownership
(sharing the token) is possible.

On the other hand the token makes sure that the instance gets as little
information about the matrix metadata of the associated `will_expire` event.

## Unstable prefix

## Dependencies