From f9d654f127f111aec653224d79fce7f8f13bef1f Mon Sep 17 00:00:00 2001 From: kegsay Date: Sun, 31 Oct 2021 19:10:44 +0000 Subject: [PATCH 01/13] MSC2946: Spaces Summary (#2946) * Spaces Summary * MSC2946 * Clarity * More clarity * Clarify what no room data means for clients * Federation API * Update 2946-spaces-summary.md * auto_join filter * Blurb on auth for fed api * Update to reflect MSC1772 changes * Mention auth chain on federation api * Add 'version' field * Stripped state; remove room versions * Update 2946-spaces-summary.md * Update proposals/2946-spaces-summary.md Co-authored-by: Patrick Cloke * Replace with link to draft doc. * Add a preamble and copy the current draft API. * Switch to using stable identifiers (and add an unstable identifiers section). * Updates / clarifications. * Fix typo. * Clean-ups. * Update proposals/2946-spaces-summary.md Co-authored-by: Travis Ralston * Drop unstable identifiers from MSC1772. * Various updates and clarifications. * Include the origin_server_ts in the response, as needed by MSC1772. * Rename a parameter for clarity. * Fix typo. Co-authored-by: David Baker * Various clarifications based on feedback. * Add auth / rate-limiting info. * Combine some double spaces. * Use only GET endpoints. * Add notes about DoS potential. * Tweaks from review. * Add context about why stripped events are returned. * Remove some implementation details. * Add notes on ordering. * Remove unnecessary data. * Clarify the server-server API. * More clarifications. * Remove obsolete note. * Some clarifications to what accessible means. * Update notes about sorting to include the origin_server_ts of the m.space.child event. This reverts commit af8c7b04d9f87bb2c4292a549b7db36ae6ef2324. * Only consider `m.space` rooms and do not return links to nowhere. * Updates based on MSC3173 merging and updates to MSC3083. * Updates per MSC2403. * Remove field which is not part of the C-S API. * Rewrite the proposal. * Handle todo comments. * Update URLs. * Rename field. * Updates based on implementation. * Clarify the state which is persisted. * Expand notes about errors. * Update MSC with pagination parameter. * Fix wrong endpoint. Co-authored-by: Matthew Hodgson * Clarifications based on implementation. * Remove empty section. * Fix typo. Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Rename field in example. * Clarify error code. * Clarify ordering changes. * Clarify wording. Co-authored-by: Travis Ralston * Fix typos. Co-authored-by: Hubert Chathi * Clarify that rooms do not belong to servers. Co-authored-by: Hubert Chathi * Fix example to use correct URL. Co-authored-by: Hubert Chathi * Clarify using local vs. remote data. Co-authored-by: Hubert Chathi * Clarify bits aboud stripped state. * Clarify access control of federation responses. * Clarify error code. Co-authored-by: Hubert Chathi * Be less prescriptive about expiring data. * Limit must be non-zero. Co-authored-by: Travis Ralston * Rate limiting. Co-authored-by: Travis Ralston * Add a note about room upgrades. * Update stable URLs per MSC2844. * Clarify federation return values. * Clarify `origin_server_ts`. Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> * Tweak wording around `inaccessible_children`. Co-authored-by: Patrick Cloke Co-authored-by: Richard van der Hoff Co-authored-by: Patrick Cloke Co-authored-by: Matthew Hodgson Co-authored-by: Travis Ralston Co-authored-by: David Baker Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Travis Ralston Co-authored-by: Hubert Chathi Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- proposals/2946-spaces-summary.md | 389 +++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 proposals/2946-spaces-summary.md diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md new file mode 100644 index 000000000..fc0c136b8 --- /dev/null +++ b/proposals/2946-spaces-summary.md @@ -0,0 +1,389 @@ +# MSC2946: Spaces Summary + +This MSC depends on [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772), which +describes why a Space is useful: + +> Collecting rooms together into groups is useful for a number of purposes. Examples include: +> +> * Allowing users to discover different rooms related to a particular topic: for example "official matrix.org rooms". +> * Allowing administrators to manage permissions across a number of rooms: for example "a new employee has joined my company and needs access to all of our rooms". +> * Letting users classify their rooms: for example, separating "work" from "personal" rooms. +> +> We refer to such collections of rooms as "spaces". + +This MSC attempts to solve how a member of a space discovers rooms in that space. This +is useful for quickly exposing a user to many aspects of an entire community, using the +examples above, joining the "official matrix.org rooms" space might suggest joining a few +rooms: + +* A room to discuss development of the Matrix Spec. +* An announcements room for news related to matrix.org. +* An off-topic room for members of the space. + +## Proposal + +A new client-server API (and corresponding server-server API) is added which allows +for querying for the rooms and spaces contained within a space. This allows a client +to efficiently display a hierarchy of rooms to a user (i.e. without having +to walk the full state of each room). + +### Client-server API + +An endpoint is provided to walk the space tree, starting at the provided room ID +("the root room"), and visiting other rooms/spaces found via `m.space.child` +events. It recurses into the children and into their children, etc. + +Any child room that the user is joined or is potentially joinable (per +[MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173)) is included in +the response. When a room with a `type` of `m.space` is found, it is searched +for valid `m.space.child` events to recurse into. + +In order to provide a consistent experience, the space tree should be walked in +a depth-first manner, e.g. whenever a space is found it should be recursed into +by sorting the children rooms and iterating through them. + +There could be loops in the returned child events; clients and servers should +handle this gracefully. Similarly, note that a child room might appear multiple +times (e.g. also be a grandchild). Clients and servers should handle this +appropriately. + +This endpoint requires authentication and is subject to rate-limiting. + +#### Request format + +```text +GET /_matrix/client/v1/rooms/{roomID}/hierarchy +``` + +Query Parameters: + +* **`suggested_only`**: Optional. If `true`, return only child events and rooms + where the `m.space.child` event has `suggested: true`. Must be a boolean, + defaults to `false`. + + This applies transitively, i.e. if a `suggested_only` is `true` and a space is + not suggested then it should not be searched for children. The inverse is also + true, if a space is suggested, but a child of that space is not then the child + should not be included. +* **`limit`**: Optional: a client-defined limit to the maximum + number of rooms to return per page. Must an integer greater than zero. + + Server implementations should impose a maximum value to avoid resource + exhaustion. +* **`max_depth`**: Optional: The maximum depth in the tree (from the root room) + to return. The deepest depth returned will not include children events. Defaults + to no-limit. Must be a non-negative integer. + + Server implementations may wish to impose a maximum value to avoid resource + exhaustion. +* **`from`**: Optional. Pagination token given to retrieve the next set of rooms. + + Note that if a pagination token is provided, then the parameters given for + `suggested_only` and `max_depth` must be the same. + +#### Response Format + +* **`rooms`**: `[object]` For each room/space, starting with the root room, a + summary of that room. The fields are the same as those returned by + `/publicRooms` (see + [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), + with the addition of: + * **`room_type`**: the value of the `m.type` field from the room's + `m.room.create` event, if any. + * **`children_state`**: The stripped state of the `m.space.child` events of + the room per [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173). + In addition to the standard stripped state fields, the following is included: + * **`origin_server_ts`**: `integer`. The `origin_server_ts` field from the + room's `m.space.child` event. This is required for sorting of rooms as + specified below. +* **`next_batch`**: Optional `string`. The token to supply in the `from` param + of the next `/hierarchy` request in order to request more rooms. If this is absent, + there are no more results. + +#### Example request: + +```text +GET /_matrix/client/v1/rooms/%21ol19s%3Ableecker.street/hierarchy? + limit=30& + suggested_only=true& + max_depth=4 +``` + +#### Example response: + +```jsonc +{ + "rooms": [ + { + "room_id": "!ol19s:bleecker.street", + "avatar_url": "mxc://bleecker.street/CHEDDARandBRIE", + "guest_can_join": false, + "name": "CHEESE", + "num_joined_members": 37, + "topic": "Tasty tasty cheese", + "world_readable": true, + "join_rules": "public", + "room_type": "m.space", + "children_state": [ + { + "type": "m.space.child", + "state_key": "!efgh:example.com", + "content": { + "via": ["example.com"], + "suggested": true + }, + "room_id": "!ol19s:bleecker.street", + "sender": "@alice:bleecker.street", + "origin_server_ts": 1432735824653 + }, + { ... } + ] + }, + { ... } + ], + "next_batch": "abcdef" +} +``` + +#### Errors: + +An HTTP response with a status code of 403 and an error code of `M_FORBIDDEN` +should be returned if the user doesn't have permission to view/peek the root room. +This should also be returned if that room does not exist, which matches the +behavior of other room endpoints (e.g. +[`/_matrix/client/r0/rooms/{roomID}/aliases`](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-rooms-roomid-aliases)) +to not divulge that a room exists which the user doesn't have permission to view. + +An HTTP response with a status code of 400 and an error code of `M_INVALID_PARAM` +should be returned if the `from` token provided is unknown to the server or if +the `suggested_only` or `max_depth` parameters are modified during pagination. + +#### Server behaviour + +The server should generate the response as discussed above, by doing a depth-first +search (starting at the "root" room) for any `m.space.child` events. Any +`m.space.child` with an invalid `via` are discarded (invalid is defined as in +[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772): missing, not an +array or an empty array). + +In the case of the homeserver not having access to the state of a room, the +server-server API (see below) can be used to query for this information over +federation from one of the servers provided in the `via` key of the +`m.space.child` event. It is recommended to cache the federation response for a +period of time. The federation results may contain information on a room +that the requesting server is already participating in; the requesting server +should use its local data for such rooms rather than the data returned over +federation. + +When the current response page is full, the current state should be persisted +and a pagination token should be generated (if there is more data to return). +To prevent resource exhaustion, the server may expire persisted data that it +deems to be stale. + +The persisted state will include: + +* The processed rooms. +* Rooms to process (in depth-first order with rooms at the same depth + ordered [according to MSC1772, as updated to below](#msc1772-ordering)). +* Room information from federation responses for rooms which have yet to be + processed. + +### Server-server API + +The Server-Server API has a similar interface to the Client-Server API, but a +simplified response. It is used when a homeserver is not participating in a room +(and cannot summarize room due to not having the state). + +The main difference is that it does *not* recurse into spaces and does not support +pagination. This is somewhat equivalent to a Client-Server request with a `max_depth=1`. + +Additional federation requests are made to recurse into sub-spaces. This allows +for trivially caching responses for a short period of time (since it is not +easily known the room summary might have changed). + +Since the server-server API does not know the requesting user, the response should +divulge information based on if any member of the requesting server could join +the room. The requesting server is trusted to properly filter this information +using the `world_readable`, `join_rules`, and `allowed_room_ids` fields from the +response. + +If the target server is not a member of some children rooms (so would have to send +another request over federation to inspect them), no attempt is made to recurse +into them. They are simply omitted from the `children` key of the response. +(Although they will still appear in the `children_state`key of the `room`.) + +Similarly, if a server-set limit on the size of the response is reached, additional +rooms are not added to the response and can be queried individually. + +#### Request format + +```text +GET /_matrix/federation/v1/hierarchy/{roomID} +``` + +Query Parameters: + +* **`suggested_only`**: The same as the Client-Server API. + +#### Response format + +The response format is similar to the Client-Server API: + +* **`room`**: `object` The summary of the requested room, see below for details. +* **`children`**: `[object]` For each room/space, a summary of that room, see + below for details. +* **`inaccessible_children`**: Optional `[string]`. A list of room IDs which are + children of the requested room, but are inaccessible to the requesting server. + Assuming the target server is non-malicious and well-behaved, then other + non-malicious servers should respond with the same set of inaccessible rooms. + Thus the requesting server can consider the rooms inaccessible from everywhere. + + This is used to differentiate between rooms which the requesting server does + not have access to from those that the target server cannot include in the + response (which will simply be missing in the response). + +For both the `room` and `children` fields the summary of the room/space includes +the fields returned by `/publicRooms` (see [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), +with the addition of: + +* **`room_type`**: the value of the `m.type` field from the room's `m.room.create` + event, if any. +* **`allowed_room_ids`**: A list of room IDs which give access to this room per + [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[1](#f1) + +#### Example request: + +```jsonc +GET /_matrix/federation/v1/hierarchy/{roomID}? + suggested_only=true +``` + +#### Errors: + +An HTTP response with a status code of 404 and an error code of `M_NOT_FOUND` is +returned if the target server is not a member of the requested room or the +requesting server is not allowed to access the room. + +### MSC1772 Ordering + +[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) defines the ordering +of "default ordering of siblings in the room list" using the `order` key: + +> Rooms are sorted based on a lexicographic ordering of the Unicode codepoints +> of the characters in `order` values. Rooms with no `order` come last, in +> ascending numeric order of the `origin_server_ts` of their `m.room.create` +> events, or ascending lexicographic order of their `room_id`s in case of equal +> `origin_server_ts`. `order`s which are not strings, or do not consist solely +> of ascii characters in the range `\x20` (space) to `\x7F` (~), or consist of +> more than 50 characters, are forbidden and the field should be ignored if +> received. + +Unfortunately there are situations when a homeserver comes across a reference to +a child room that is unknown to it and must decide the ordering. Without being +able to see the `m.room.create` event (which it might not have permission to see) +no proper ordering can be given. + +Consider the following case of a space with 3 child rooms: + +``` + Space A + | + +--------+--------+ + | | | +Room B Room C Room D +``` + +HS1 has users in Space A, Room B, and Room C, while HS2 has users in Room D. HS1 has no users +in Room D (and thus has no state from it). Room B, C, and D do not have an +`order` field set (and default to using the ordering rules above). + +When a user asks HS1 for the space summary with a `limit` equal to `2` it cannot +fulfill this request since it is unsure how to order Room B, Room C, and Room D, +but it can only return 2 of them. It *can* reach out over federation to HS2 and +request a space summary for Room D, but this is undesirable: + +* HS1 might not have the permissions to know any of the state of Room D, so might + receive a 404 error. +* If we expand the example above to many rooms than this becomes expensive to + query a remote server simply for ordering. + +This proposes changing the ordering rules from MSC1772 to the following: + +> Rooms are sorted based on a lexicographic ordering of the Unicode codepoints +> of the characters in `order` values. Rooms with no `order` come last, in +> ascending numeric order of the `origin_server_ts` of their `m.space.child` +> events, or ascending lexicographic order of their `room_id`s in case of equal +> `origin_server_ts`. `order`s which are not strings, or do not consist solely +> of ascii characters in the range `\x20` (space) to `\x7E` (~), or consist of +> more than 50 characters, are forbidden and the field should be ignored if +> received. + +This modifies the clause for calculating the order to use the `origin_server_ts` +of the `m.space.child` event instead of the `m.room.create` event. This allows +for a defined sorting of siblings based purely on the information available in +the state of the space while still allowing for a natural ordering due to the +age of the relationship. + +## Potential issues + +A large flat space (a single room with many `m.space.child` events) could cause +a large federation response. + +Room version upgrades of rooms in a space are unsolved and left to a future MSC. +When upgrading a room it is unclear if the old room should be removed (in which +case users who have not yet joined the new room will no longer see it in the space) +or leave the old room (in which case users who have joined the new room will see +both). The current recommendation is for clients de-duplicate rooms which are +known old versions of rooms in the space. + +## Alternatives + +Peeking to explore the room state could be used to build the tree of rooms/spaces, +but this would be significantly more expensive for both clients and servers. It +would also require peeking over federation (which is explored in +[MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444)). + +## Security considerations + +A space with many sub-spaces and rooms on different homeservers could cause +a large number of federation requests. A carefully crafted space with inadequate +server enforced limits could be used in a denial of service attack. Generally +this is mitigated by enforcing server limits and caching of responses. + +The requesting server over federation is trusted to filter the response for the +requesting user. The alternative, where the requesting server sends the requesting +`user_id`, and the target server does the filtering, is unattractive because it +rules out a caching of the result. This does not decrease security since a server +could lie and make a request on behalf of a user in the proper space to see the +given information. I.e. the calling server must be trusted anyway. + +## Unstable prefix + +During development of this feature it will be available at unstable endpoints. + +The client-server API will be: +`/_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/hierarchy` + +The server-server API will be: +`/_matrix/federation/unstable/org.matrix.msc2946/hierarchy/{roomID}` + +## Footnotes + +[1]: As a worked example, in the context of +[MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083), consider that Alice +and Bob share a server; Alice is a member of a space, but Bob is not. A remote +server will not know whether the request is on behalf of Alice or Bob (and hence +whether it should share details of restricted rooms within that space). + +Consider if the space is modified to include a restricted room on a different server +which allows access from the space. When summarizing the space, the homeserver must make +a request over federation for information on the room. The response should include +the room (since Alice is able to join it). Without additional information the +calling server does not know *why* they received the room and cannot properly +filter the returned results. + +Note that there are still potential situations where each server individually +doesn't have enough information to properly return the full summary, but these +do not seem reasonable in what is considered a normal structure of spaces. (E.g. +in the above example, if the remote server is not in the space and does not know +whether the server is in the space or not it cannot return the room.)[↩](#a1) From c06b32448cc7a9e031ede0889da74fe297e95757 Mon Sep 17 00:00:00 2001 From: Jonas Kress Date: Wed, 17 Nov 2021 16:45:14 +0100 Subject: [PATCH 02/13] MSC3283: Expose capabilities for profile actions (#3283) * Create 3278-enable_set_displayname-capabilities.md * Apply suggestions from code review Co-authored-by: Alexey Rusakov * Apply suggestions from code review Co-authored-by: Alexey Rusakov * Update and rename 3278-enable_set_displayname-capabilities.md to 3279-enable_set_displayname-capabilities.md * Update and rename 3279-enable_set_displayname-capabilities.md to 3282-enable_set_displayname-capabilities.md * Update and rename 3282-enable_set_displayname-capabilities.md to 3283-enable_set_displayname-capabilities.md * Update proposals/3283-enable_set_displayname-capabilities.md Co-authored-by: Alexey Rusakov * Update proposals/3283-enable_set_displayname-capabilities.md Co-authored-by: Will Hunt * Update proposals/3283-enable_set_displayname-capabilities.md Co-authored-by: Will Hunt * Update 3283-enable_set_displayname-capabilities.md * Update 3283-enable_set_displayname-capabilities.md * Update proposals/3283-enable_set_displayname-capabilities.md Co-authored-by: Dirk Klimpel <5740567+dklimpel@users.noreply.github.com> * Update proposals/3283-enable_set_displayname-capabilities.md Co-authored-by: Dirk Klimpel <5740567+dklimpel@users.noreply.github.com> * Update 3283-enable_set_displayname-capabilities.md * Update 3283-enable_set_displayname-capabilities.md * Update 3283-enable_set_displayname-capabilities.md * Update 3283-enable_set_displayname-capabilities.md Co-authored-by: Alexey Rusakov Co-authored-by: Will Hunt Co-authored-by: Dirk Klimpel <5740567+dklimpel@users.noreply.github.com> --- ...283-enable_set_displayname-capabilities.md | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 proposals/3283-enable_set_displayname-capabilities.md diff --git a/proposals/3283-enable_set_displayname-capabilities.md b/proposals/3283-enable_set_displayname-capabilities.md new file mode 100644 index 000000000..e59746d8b --- /dev/null +++ b/proposals/3283-enable_set_displayname-capabilities.md @@ -0,0 +1,46 @@ +# MSC3283: Expose enable_set_displayname, enable_set_avatar_url and enable_3pid_changes in capabilities response + +Some home servers like [Synapse](https://github.com/matrix-org/synapse/blob/756fd513dfaebddd28bf783eafa95b4505ce8745/docs/sample_config.yaml#L1207) +can be configured to `enable_set_displayname: false`, `enable_set_avatar_url: false` or `enable_3pid_changes: false`. +To enable clients to handle that gracefully in the UI this setting should be exposed. + +## Proposal + +The `/_matrix/client/r0/capabilities` endpoint should be decorated to provide more information on capabilities. +```jsonc +{ + "capabilities": { + "m.set_displayname": { "enabled": false }, + "m.set_avatar_url": { "enabled": false }, + "m.3pid_changes": { "enabled": false }, + "m.room_versions": {...}, + } +} +``` +As part of this MSC, a capability for each setting will be added that exposes the server setting: +- `m.set_displayname` + +Whether users are allowed to change their displayname after it has been initially set. +Useful when provisioning users based on the contents of a third-party directory. + +- `m.set_avatar_url` + +Whether users are allowed to change their avatar after it has been initially set. +Useful when provisioning users based on the contents of a third-party directory. + +- `m.3pid_changes` + +Whether users can change the 3PIDs associated with their accounts +(email address and msisdn). +Useful when provisioning users based on the contents of a third-party directory. + +## Client recommendations +When presenting profile settings, clients should use capabilities in order to display the correct UI. + +Capability should always be present. +Servers should always send these capabilities. If they aren't (because the server does not support +a new enough spec version or for any other reason), clients should behave as if they were present and set to true. + +## Unstable prefix + +While this MSC is not considered stable, implementations should use `org.matrix.msc3283.` in place of `m.` throughout this proposal. From c8e8b75c83fedc2afd4f2a6e18049a81f6fa4d64 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 23 Nov 2021 13:49:46 -0500 Subject: [PATCH 03/13] MSC2674: Event Relationships (#2674) * initial version of event relationship MSC * fix MSC numbers * clarifications * mention multiple relations per event might be useful, but postpone for a future MSC * mention MSC 3051 for proposed multiple relations * remove send_relation endpoint * move e2ee section under sending relations * mention limitation of leaving server-side aggregations out for now * remove mentions of m.reference, we'll sort that out in another MSC * whitespace * argument why m.relates_to should be preserved by redactions more general but still give example of redacted edits * deal with this in the comments * clarify the conditions to meet for a relation * mention specifically that this does not replace replies (yet) * clarify how general rel_types should be * clarify that gaps may cause clients to be unaware of some relations * Update proposals/2674-event-relationships.md Co-authored-by: DeepBlueV7.X * Update proposals/2674-event-relationships.md Co-authored-by: DeepBlueV7.X * make wording clearer and move to bottom of section * remove this as references are not defined here anymore * clearer wording * move edge cases to other relevant mscs * clarify that a goal of sticking to this format is backwards compat. * mention MSC 3267, to which m.reference has been extracted * Update proposals/2674-event-relationships.md Co-authored-by: Hubert Chathi * Update proposals/2674-event-relationships.md Co-authored-by: Hubert Chathi * Update proposals/2674-event-relationships.md Co-authored-by: Matthew Hodgson * Update proposals/2674-event-relationships.md Co-authored-by: Matthew Hodgson * Update proposals/2674-event-relationships.md Co-authored-by: Travis Ralston * wrap lines * better wording * this is singular, really * add example of event shape * specify how invalid relations should be treated by the redaction algorithm * fix typo * split up redactions changes in separate MSC * also add new msc to introduction * reword why not adopt m.in_reply_to * remove guidelines how to pick rel_type * mention that the target event must exist in the same room * spell out the conscious (subject, object, verb) triple idea. * Spelling Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * remove paragraph saying what server should accept * Revert "remove paragraph saying what server should accept" This reverts commit e0271331b2e7dee236349aa63eec3cec7369e361. * further specify that a server should reject invalid relations through the cs api * linebreak Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Bruno Windels Co-authored-by: DeepBlueV7.X Co-authored-by: Matthew Hodgson Co-authored-by: Travis Ralston Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/2674-event-relationships.md | 250 ++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 proposals/2674-event-relationships.md diff --git a/proposals/2674-event-relationships.md b/proposals/2674-event-relationships.md new file mode 100644 index 000000000..95f077bad --- /dev/null +++ b/proposals/2674-event-relationships.md @@ -0,0 +1,250 @@ +# MSC2674: Event relationships + +It's common to want to send events in Matrix which relate to existing events - +for instance, reactions, edits and even replies/threads. + +This proposal is one in a series of proposals that defines a mechanism for +events to relate to each other. Together, these proposals replace +[MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849). + +* This proposal defines a standard shape for indicating events which relate to + other events. +* [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675) defines APIs to + let the server calculate the aggregations on behalf of the client, and so + bundle the related events with the original event where appropriate. +* [MSC2676](https://github.com/matrix-org/matrix-doc/pull/2676) defines how + users can edit messages using this mechanism. +* [MSC2677](https://github.com/matrix-org/matrix-doc/pull/2677) defines how + users can annotate events, such as reacting to events with emoji, using this + mechanism. +* [MSC3267](https://github.com/matrix-org/matrix-doc/pull/3267) defines how events + can make a reference to other events. +* [MSC3389](https://github.com/matrix-org/matrix-doc/pull/3389) defines changes to + the redaction algorithm, to preserve the type and target id of a relation. + + +## Proposal + +This proposal introduces the concept of relations, which can be used to +associate new information with an existing event. + +A relationship is an object with a field `rel_type`, which is a string describing the type of relation, +and a field `event_id`, which is a string that represents the event_id of the target event of this relation. +The target event must exist in the same room as the relating event is sent. +Both of those fields are required. An event is said to contain a relationship if its `content` contains +a relationship with all the required fields under the `m.relates_to` key. If any of these conditions is not met, +clients and servers should treat the event as if it does not contain a relationship. +Servers should reject events not meeting these conditions with an HTTP 400 error when +they are received via the client-server API. + +Here's a (partial) example of an event relating to another event: + +```json +{ + "content": { + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$abc:server.tld" + } + } +} +``` + +All the information about the relationship lives under the `m.relates_to` key. + +If it helps, you can think of relations as a "subject verb object" triple, +where the subject is the relation event itself; the verb is the `rel_type` +field of the `m.relates_to` and the object is the `event_id` field. + +We consciously do not support multiple different relations within a single event, +in order to keep the API simple. This means that if event A relates to event B +in two different ways you would send two events to describe the two relations, +rather than bundling them into a single event. Another MSC, +like [MSC 3051](https://github.com/matrix-org/matrix-doc/pull/3051), +can propose a change to add support for multiple relations if it turns out that +this would facilitate certain use cases. + +Relations do not yet replace the +[reply mechanism currently defined in the spec](https://matrix.org/docs/spec/client_server/r0.6.1#rich-replies). + +### Relation types + +Any values for `rel_type` should abide the +[general guidelines for identifiers](https://github.com/matrix-org/matrix-doc/pull/3171). + +The `rel_type` property determines how an event relates to another and can be used +by clients to determine how and in what context a relation should be displayed. + +[MSC 2675](https://github.com/matrix-org/matrix-doc/pull/2675) proposes to also interpret the `rel_type` server-side. + +It is left up to the discretion of other MSCs building on this one whether they introduce +`rel_type`s that are specific to their use case or that can serve a broad range +of use cases. MSCs may define additional properties on the relation object for a given `rel_type`. + +Currently, a few `rel_type`s are already proposed. Here's a non-exhaustive list: + + - `m.replace` in [MSC 2676](https://github.com/matrix-org/matrix-doc/pull/2676). + - `m.annotation` in [MSC 2677](https://github.com/matrix-org/matrix-doc/pull/2677). + - `m.reference` in [MSC 3267](https://github.com/matrix-org/matrix-doc/pull/3267). + - `m.thread` in [MSC 3440](https://github.com/matrix-org/matrix-doc/pull/3440). + + +### Sending relations + +Related events are normal Matrix events, and can be sent by the normal `/send` +API. + +The server should postprocess relations if needed before sending them into a +room, as defined by the relationship type. For example, a relationship type +might only allow a user to send one related message to a given event. + +### Receiving relations + +Relations are received like other non-state events, with `/sync`, +`/messages` and `/context`, as normal discrete Matrix events. As explained +in the limitations, clients may be unaware of some relations using just these endpoints. + +[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675) defines ways in +which the server may aid clients in processing relations by aggregating the +events. + +### Redactions + +Events with a relation may be redacted like any other event. + +[MSC3389](https://github.com/matrix-org/matrix-doc/pull/3389) proposes that +the redaction algorithm should preserve the type and target id of a relation. + +However, event relationships can still be used in existing room versions, but +the user experience may be worse if redactions are performed. + +## Potential issues + +### Federation considerations + +We have a problem with resynchronising relations after a gap in federation: +We have no way of knowing that an edit happened in the gap to one of the events +we already have. So, we'll show inconsistent data until we backfill the gap. + * We could write this off as a limitation. + * Or we could make *ALL* relations a DAG, so we can spot holes at the next + relation, and go walk the DAG to pull in the missing relations? Then, the + next relation for an event could pull in any of the missing relations. + Socially this probably doesn't work as reactions will likely drop off over + time, so by the time your server comes back there won't be any more reactions + pulling the missing ones in. + * Could we also ask the server, after a gap, to provide all the relations which + happened during the gap to events whose root preceeded the gap. + * "Give me all relations which happened between this set of + forward-extremities when I lost sync, and the point i've rejoined the DAG, + for events which preceeded the gap"? + * Would be hard to auth all the relations which this api coughed up. + * We could auth them based only the auth events of the relation, except we + lose the context of the nearby DAG which we'd have if it was a normal + backfilled event. + * As a result it would be easier for a server to retrospectively lie about + events on behalf of its users. + * This probably isn't the end of the world, plus it's more likely to be + consistent than if we leave a gap. + * i.e. it's better to consistent with a small chance of being maliciously + wrong, than inconsistent with a guaranteed chance of being innocently + wrong. + * We'd need to worry about pagination. + * This is probably the best solution, but can also be added as a v2. + * In practice this seems to not be an issue, which is worth complicating + the s-s API over. Clients very rarely jump over the federation gap to an edit. + In most cases they scroll up, which backfills the server and we have all the + edits, when we reach the event before the gap. + +## Limitations + +Based solely on this MSC, relations are only received as discrete events in +the timeline, so clients may only have an incomplete image of all the relations +with an event if they do not fill gaps (syncs with a since token that have +`limited: true` set in the sync response for a room) in the timeline. + +In practice, this has proven not to be too big of a problem, as reactions +(as proposed in [MSC 2677](https://github.com/matrix-org/matrix-doc/pull/2677)) +tend to be posted close after the target event in the timeline. + +A more complete solution to this has been deferred to +[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675). + +## Tradeoffs + +### Event shape + +Shape of + +```json +"content": { + "m.relates_to": { + "m.reference": { + "event_id": "$another:event.com" + } + } +} +``` +versus + +```json +"content": { + "m.relates_to": { + "rel_type": "m.reference", + "event_id": "$another:event.com" + } +} +``` + +The reasons to go with `rel_type` is: + * This format is now in use in the wider matrix ecosystem without a prefix, + in spite of the original MSC 1849 not being merged. This situation is not ideal + but we still don't want to break compatibility with several clients. + * We don't need the extra indirection to let multiple relations apply to a given pair of + events, as that should be expressed as separate relation events. + * If we want 'adverbs' to apply to 'verbs' in the subject-verb-object triples which + relations form, then we apply it as mixins to the relation data itself rather than trying + to construct subject-verb-verb-object sentences. + * We decided to not adopt the format used by `m.in_reply_to` as it allows for multiple relations + and is hence overly flexible. Also, the relation type of `m.in_reply_to` is also overly specific + judged by the guidelines for `rel_type`s laid out in this MSC. Having replies use the same + format as relations is postponed to a later MSC, but it would likely involve replies + adopting the relation format with a more broadly useful `rel_type` (possibly the `m.reference` + type proposed in [MSC3267](https://github.com/matrix-org/matrix-doc/pull/3267)), + rather than relations adopting the replies format. + +## Historical context + +pik's MSC441 has: + +Define the JSON schema for the aggregation event, so the server can work out +which fields should be aggregated. + +```json +"type": "m.room._aggregation.emoticon", +"content": { + "emoticon": "::smile::", + "msgtype": "?", + "target_id": "$another:event.com" +} +``` + +These would then be aggregated, based on target_id, and returned as annotations on +the source event in an `aggregation_data` field: + +```json +"content": { + ... + "aggregation_data": { + "m.room._aggregation.emoticon": { + "aggregation_data": [ + { + "emoticon": "::smile::", + "event_id": "$14796538949JTYis:pik-test", + "sender": "@pik:pik-test" + } + ], + "latest_event_id": "$14796538949JTYis:pik-test" + } + } +} +``` From acf44d7d2888e23299938674232861b2cc19bc23 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 28 Dec 2021 21:16:33 +0000 Subject: [PATCH 04/13] Add m.login.appservice to the spec (#3324) Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Hubert Chathi Co-authored-by: Travis Ralston --- .../client_server/newsfragments/3324.feature | 1 + content/application-service-api.md | 27 +++++++++++--- content/client-server-api/_index.md | 35 +++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 changelogs/client_server/newsfragments/3324.feature diff --git a/changelogs/client_server/newsfragments/3324.feature b/changelogs/client_server/newsfragments/3324.feature new file mode 100644 index 000000000..346de35df --- /dev/null +++ b/changelogs/client_server/newsfragments/3324.feature @@ -0,0 +1 @@ +Extend `/_matrix/client/r0/login` to accept a `m.login.appservice`, as per [MSC2778](https://github.com/matrix-org/matrix-doc/pull/2778). \ No newline at end of file diff --git a/content/application-service-api.md b/content/application-service-api.md index e324bba05..02d7ed6fa 100644 --- a/content/application-service-api.md +++ b/content/application-service-api.md @@ -312,10 +312,11 @@ information. The homeserver needs to give the application service *full control* over its namespace, both for users and for room aliases. This means that the -AS should be able to create/edit/delete any room alias in its namespace, -as well as create/delete any user in its namespace. No additional API +AS should be able to manage any users and room alias in its namespace. No additional API changes need to be made in order for control of room aliases to be -granted to the AS. Creation of users needs API changes in order to: +granted to the AS. + +Creation of users needs API changes in order to: - Work around captchas. - Have a 'passwordless' user. @@ -334,8 +335,26 @@ user ID without a password. username: "_irc_example" } +Similarly, logging in as users needs API changes in order to allow the AS to +log in without needing the user's password. This is achieved by including the +`as_token` on a `/login` request, along with a login type of +`m.login.application_service`. + + POST /_matrix/client/%CLIENT_MAJOR_VERSION%/login + Authorization: Bearer YourApplicationServiceTokenHere + + Content: + { + type: "m.login.application_service", + "identifier": { + "type": "m.id.user", + "user": "_irc_example" + } + } + Application services which attempt to create users or aliases *outside* -of their defined namespaces will receive an error code `M_EXCLUSIVE`. +of their defined namespaces, or log in as users outside of their defined +namespaces will receive an error code `M_EXCLUSIVE`. Similarly, normal users who attempt to create users or aliases *inside* an application service-defined namespace will receive the same `M_EXCLUSIVE` error code, but only if the application service has diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 1f50ae7a4..f9ef60632 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -1024,6 +1024,41 @@ client supports it, the client should redirect the user to the is complete, the client will need to submit a `/login` request matching `m.login.token`. +#### Appservice Login + +An appservice can log in by providing a valid appservice token and a user within the appservice's +namespace. + +{{% boxes/note %}} +Appservices do not need to log in as individual users in all cases, as they +can perform [Identity Assertion](/application-service-api#identity-assertion) +using the appservice token. However, if the appservice needs a scoped token +for a single user then they can use this API instead. +{{% /boxes/note %}} + +This request must be authenticated by the [appservice `as_token`](/application-service-api#registration) +(see [Client Authentication](#client-authentication) on how to provide the token). + +To use this login type, clients should submit a `/login` request as follows: + +```json +{ + "type": "m.login.appservice", + "identifier": { + "type": "m.id.user", + "user": "" + } +} +``` + +If the access token is not valid, does not correspond to an appservice +or the user has not previously been registered then the homeserver will +respond with an errcode of `M_FORBIDDEN`. + +If the access token does correspond to an appservice, but the user id does +not lie within its namespace then the homeserver will respond with an +errcode of `M_EXCLUSIVE`. + {{% http-api spec="client-server" api="login" %}} {{% http-api spec="client-server" api="logout" %}} From a07780dbabcc2cdf8f41c9b00d1e0b03bb492f40 Mon Sep 17 00:00:00 2001 From: Lukas Lihotzki Date: Tue, 4 Jan 2022 19:31:09 +0100 Subject: [PATCH 05/13] dump-swagger.py: include untagged operations (#3326) --- scripts/dump-swagger.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/dump-swagger.py b/scripts/dump-swagger.py index 4b4922fff..68a9356aa 100755 --- a/scripts/dump-swagger.py +++ b/scripts/dump-swagger.py @@ -98,10 +98,9 @@ for filename in os.listdir(cs_api_dir): path = (basePath + path).replace('%CLIENT_MAJOR_VERSION%', major_version) for method, spec in methods.items(): - if "tags" in spec.keys(): - if path not in output["paths"]: - output["paths"][path] = {} - output["paths"][path][method] = spec + if path not in output["paths"]: + output["paths"][path] = {} + output["paths"][path][method] = spec print("Generating %s" % output_file) From a786fa980d56ab24a31cb394ff606ea0693576e8 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Thu, 6 Jan 2022 10:34:56 +0000 Subject: [PATCH 06/13] Rename assets-hugo directory to assets (#3259) Now that we've dropped the old build pipeline (and an assets directory does not exist in the repo any longer, we can rename the hugo version of the assets (assets-hugo) created during the build tools migration back to simply assets. --- .gitignore | 3 +-- {assets-hugo => assets}/icons/logo.svg | 0 {assets-hugo => assets}/scss/_variables_project.scss | 0 {assets-hugo => assets}/scss/custom.scss | 0 config.toml | 4 ---- static/css/fonts/README.md | 4 ++-- 6 files changed, 3 insertions(+), 8 deletions(-) rename {assets-hugo => assets}/icons/logo.svg (100%) rename {assets-hugo => assets}/scss/_variables_project.scss (100%) rename {assets-hugo => assets}/scss/custom.scss (100%) diff --git a/.gitignore b/.gitignore index cce5848fa..a0c5cef07 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ /api/node_modules -/assets /assets.tar.gz /data/msc /env* @@ -18,4 +17,4 @@ _rendered.rst /.vscode/ /.idea/ -/spec/ \ No newline at end of file +/spec/ diff --git a/assets-hugo/icons/logo.svg b/assets/icons/logo.svg similarity index 100% rename from assets-hugo/icons/logo.svg rename to assets/icons/logo.svg diff --git a/assets-hugo/scss/_variables_project.scss b/assets/scss/_variables_project.scss similarity index 100% rename from assets-hugo/scss/_variables_project.scss rename to assets/scss/_variables_project.scss diff --git a/assets-hugo/scss/custom.scss b/assets/scss/custom.scss similarity index 100% rename from assets-hugo/scss/custom.scss rename to assets/scss/custom.scss diff --git a/config.toml b/config.toml index c18c024eb..21108fb84 100644 --- a/config.toml +++ b/config.toml @@ -12,10 +12,6 @@ theme = ["docsy"] disableKinds = ["taxonomy", "taxonomyTerm"] -# Change the default for assets, because the old Python toolchain uses "assets" for build output. -# When the old toolchain is retired we can switch back to the default here. -assetDir = "assets-hugo" - [languages] [languages.en] title = "Matrix Specification" diff --git a/static/css/fonts/README.md b/static/css/fonts/README.md index e6eb74eb2..aca333042 100644 --- a/static/css/fonts/README.md +++ b/static/css/fonts/README.md @@ -22,9 +22,9 @@ python3 download_google_fonts_css.py \ Which would pop out a `Inter.css` file that should be `@import url("Inter.css")`d somewhere in the site's SCSS (currently in -[/assets-hugo/scss/_variables_project.scss](/assets-hugo/scss/_variables_project.scss)). +[/assets/scss/_variables_project.scss](/assets/scss/_variables_project.scss)). Re-running the script and committing any new files is only necessary when a desired font updates (not very often), or we want to change the font we're using. In that case, remove the existing font files at `/static/fonts/*.woff2` and re-run the script with a -different URL. \ No newline at end of file +different URL. From aa0350ae330da697ba877e2e8cf0ebcfa94ae4fe Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Sat, 15 Jan 2022 17:07:08 -0500 Subject: [PATCH 07/13] MSC2675: Serverside aggregations of message relationships (#2675) * initial version of serverside aggregations proposal * fix MSC numbers * clarification * add e2ee section from 2674 here, as it is only needed for server-side aggregations * move edge case wrt to calling /context on a relation here from 2674 * fix typo * clarify which APIs should bundle relations * move stale_events over to future extensions section * summarize stale_events and make tone conditional to mark that is not part of the MSC * casing and wording * clarify in summary an API for requesting relations is also proposed * remove proposal for batch get event api as is unused and unimplemented * attempt to clarify relations vs aggregations * clarify pagination and align it with synapse impl already in the wild * conciseness * better headers * clarify that relations are always returned, contrary to aggregations * document the limitation of the event type not being known in e2ee rooms * specify that redacted relations are not aggregated * remove type in (non-binding) example as synapse doesn't do this * mention that these are just examples * clarify that this is a non-normative example * Update proposals/2675-aggregations-server.md Co-authored-by: David Baker * add http method for endpoint list * line break * remove "unbundled relations" term, it's just confusing instead use relation events, with the bundled form now called aggregation also restructure the headings so we have on section about aggregations and another one about querying relation events * some more restructuring of text after changing doc structure * mention original_event for m.replace relations * remove dir param as it is unused and unimplemented * clarify that relating pending events should happen by transaction_id * remove unimplemented /aggregations/{eventID}//{eventType}/{key} endpoint * Update proposals/2675-aggregations-server.md Co-authored-by: Patrick Cloke * mention that the server might not be aware of all the relations * clarify that redacted events should still return their relations and aggregations respectively * remove /context edge case, it should not be special-cased * Update proposals/2675-aggregations-server.md Co-authored-by: Patrick Cloke * Update proposals/2675-aggregations-server.md Co-authored-by: Patrick Cloke * Update proposals/2675-aggregations-server.md Co-authored-by: Patrick Cloke * bad example, replies doesn't use relations * clarify that we dont bundle discrete events * clarify that we dont bundle discrete events, again * improve example * clarify this MSC does not use a prefix * better english * clarify pagination in example * better english * remove contradication: m.reference doesn't support pagination but example mentions it * double punctuation * clarify that only the bundled aggregation limit for truncation can't be set by the client, /aggregations does have a limit param * move e2ee limitation to limitations section * clarify prefixes * mention that state events never bundle aggregations * Update proposals/2675-aggregations-server.md Co-authored-by: Patrick Cloke * add that the visibility of relations can derive from that of the target * typsos * be more explicit * moar rewording * keep related parts together * don't make a relation invisible because the target event isn't also clarify what to do with relations for which the target is invisible * Update proposals/2675-aggregations-server.md Co-authored-by: David Baker * better words * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * be more precise when clients should ensure the key is shared * mention that ignored users can cause different aggregations for users * move visibility rule changes to MSC3570 * don't overspecify visibility limitation, allow for unspecified behaviour as synapse includes the invisible events in the aggregation * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * move non-normative note to below example * make rel_type mandatory as the response structure doesn't allow for mixing types * fix typo/thinko * make pagination forward only as there is no use case for backwards * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * add non-normative aggregation examples * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * use relation type rather than rel_type the former is already define as the latter in MSC 2674 * change trailing slashes remark to event_type, rel_type is mandatory now * reword and split out client-side aggregation section * rename parent event to target event, the term used elsewhere * apply suggestion * apply suggestion * remove pagination * remove mentions of /aggregations endpoint after removing pagination * add note about not bundling into state events * restructure headers so more of the aggregations stuff is under section * make rel_type mandatory for /relations and better wording * remove confusion that aggregations contain more info than relations * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/2675-aggregations-server.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * mention that tokens from /sync, /messages can be used on /relations * try not to be overly prescriptive * remove edge case of ignoring events without target event, as ignoring is not always safe * clarify limitation for encrypted rooms * make rel_type optional again for /relations * Update proposals/2675-aggregations-server.md Co-authored-by: Hubert Chathi * Update proposals/2675-aggregations-server.md Co-authored-by: Hubert Chathi * Update proposals/2675-aggregations-server.md Co-authored-by: Hubert Chathi * Update proposals/2675-aggregations-server.md Co-authored-by: Hubert Chathi * Update proposals/2675-aggregations-server.md Co-authored-by: Matthew Hodgson * mention requires auth and rate-limited on /relations * replace hypothetical examples for bundled aggregations with non-normative ones * move to MSC 2676 as it's specific to edits * dont repeat how local echo using transaction_id works Co-authored-by: Bruno Windels Co-authored-by: David Baker Co-authored-by: Patrick Cloke Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Matthew Hodgson --- proposals/2675-aggregations-server.md | 320 ++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 proposals/2675-aggregations-server.md diff --git a/proposals/2675-aggregations-server.md b/proposals/2675-aggregations-server.md new file mode 100644 index 000000000..5808dbec0 --- /dev/null +++ b/proposals/2675-aggregations-server.md @@ -0,0 +1,320 @@ +# MSC2675: Serverside aggregations of message relationships + +It's common to want to send events in Matrix which relate to existing events - +for instance, reactions, edits and even replies/threads. + +Clients typically need to track the related events alongside the original +event they relate to, in order to correctly display them. For instance, +reaction events need to be aggregated together by summing and be shown next to +the event they react to; edits need to be aggregated together by replacing the +original event and subsequent edits, etc. + +It is possible to treat relations as normal events and aggregate them +clientside, but to do so comprehensively could be very resource intensive, as +the client would need to spider all possible events in a room to find +relationships and maintain a correct view. + +Instead, this proposal seeks to solve this problem by defining APIs to let the +server calculate the aggregations on behalf of the client, and so bundle the +aggregated data with the original event where appropriate. It also proposes an +API to let clients paginate through all relations of an event. + +This proposal is one in a series of proposals that defines a mechanism for +events to relate to each other. Together, these proposals replace +[MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849). + +* [MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674) defines a + standard shape for indicating events which relate to other events. +* This proposal defines APIs to let the server calculate the aggregations on + behalf of the client, and so bundle the aggregated data with the original + event where appropriate. +* [MSC2676](https://github.com/matrix-org/matrix-doc/pull/2676) defines how + users can edit messages using this mechanism. +* [MSC2677](https://github.com/matrix-org/matrix-doc/pull/2677) defines how + users can annotate events, such as reacting to events with emoji, using this + mechanism. + +## Proposal + +### Aggregations + +Relation events can be aggregated per relation type by the server. +The format of the aggregated value (hereafter called "aggregation") +depends on the relation type. + +Some relation types might group the aggregations by the `key` property +in the relation and aggregate to an array, while +others might aggregate to a single object or any other value really. + +Here are some non-normative examples of what aggregations can look like: + +Example aggregation for [`m.thread`](https://github.com/matrix-org/matrix-doc/pull/3440) (which +aggregates all relations into a single object): +``` +{ + "latest_event": { + "content": { ... }, + ... + }, + "count": 7, + "current_user_participated": true +} +``` + +Example aggregation for [`m.annotation`](https://github.com/matrix-org/matrix-doc/pull/2677) (which +aggregates relations into a list of objects, grouped by `key`). +``` +[ + { + "key": "👍", + "origin_server_ts": 1562763768320, + "count": 3 + }, + { + "key": "👎", + "origin_server_ts": 1562763768320, + "count": 2 + } +] +``` + +#### Bundling + +Other than during non-gappy incremental syncs, timeline events that have other +events relate to them should include the aggregation of those related events +in the `m.relations` property of their unsigned data. This process is +referred to as "bundling", and the aggregated relations included via +this mechanism are called "bundled aggregations". + +By sending a summary of the relations, bundling +avoids us having to always send lots of individual relation events +to the client. + +Aggregations are never bundled into state events. This is a current +implementation detail that could be revisited later, +rather than a specific design decision. + +The following client-server APIs should bundle aggregations +with events they return: + + - `GET /rooms/{roomId}/messages` + - `GET /rooms/{roomId}/context/{eventId}` + - `GET /rooms/{roomId}/event/{eventId}` + - `GET /sync`, only for room sections in the response where `limited` field + is `true`; this amounts to all rooms in the response if + the `since` request parameter was not passed, also known as an initial sync. + - `GET /relations`, as proposed in this MSC. + +Deprecated APIs like `/initialSync` and `/events/{eventId}` are *not* required +to bundle aggregations. + +The bundled aggregations are grouped according to their relation type. +The format of `m.relations` (here with *non-normative* examples of +the [`m.replace`](https://github.com/matrix-org/matrix-doc/pull/2676) and +[`m.annotation`](https://github.com/matrix-org/matrix-doc/pull/2677) relation +types) is as follows: + +```json +{ + "event_id": "abc", + "unsigned": { + "m.relations": { + "m.annotation": { + "key": "👍", + "origin_server_ts": 1562763768320, + "count": 3 + }, + "m.replace": { + "event_id": "$edit_event_id", + "origin_server_ts": 1562763768320, + "sender": "@alice:localhost" + }, + } + } +} +``` + +#### Client-side aggregation + +Bundled aggregations on an event give a snapshot of what relations were known +at the time the event was received. When relations are received through `/sync`, +clients should locally aggregate (as they might have done already before +supporting this MSC) the relation on top of any bundled aggregation the server +might have sent along previously with the target event, to get an up to date +view of the aggregations for the target event. The aggregation algorithm is the +same as the one described here for the server. + +### Querying relations + +A single event can have lots of associated relations, and we do not want to +overload the client by, for example, including them all bundled with the +related-to event. Instead, we also provide a new `/relations` API in +order to paginate over the relations, which behaves in a similar way to +`/messages`, except using `next_batch` and `prev_batch` names +(in line with `/sync` API). Tokens from `/sync` or `/messages` can be +passed to `/relations` to only get relating events from a section of +the timeline. + +The `/relations` API returns the discrete relation events +associated with an event that the server is aware of +in standard topological order. Note that events may be missing, +see [limitations](#servers-might-not-be-aware-of-all-relations-of-an-event). +You can optionally filter by a given relation type and the event type of the +relating event: + +``` +GET /_matrix/client/v1/rooms/{roomID}/relations/{event_id}[/{rel_type}[/{event_type}]][?from=token][&to=token][&limit=amount] +``` + +``` +{ + "chunk": [ + { + "type": "m.reaction", + "sender": "...", + "content": { + "m.relates_to": { + "rel_type": "m.annotation", + ... + } + } + } + ], + "prev_batch": "some_token", + "next_batch": "some_token", +} +``` + +The endpoint does not have any trailing slashes. It requires authentication +and is not rate-limited. + +The `from` and `limit` query parameters are used for pagination, and work +just like described for the `/messages` endpoint. + +Note that [MSC2676](https://github.com/matrix-org/matrix-doc/pull/2676) +adds the related-to event in `original_event` property of the response. +This way the full history (e.g. also the first, original event) of the event +is obtained without further requests. See that MSC for further details. + +### End to end encryption + +Since the server has to be able to aggregate relation events, structural +information about relations must be visible to the server, and so the +`m.relates_to` field must be included in the plaintext. + +A future MSC may define a method for encrypting certain parts of the +`m.relates_to` field that may contain sensitive information. + +### Redactions + +Redacted relations should not be taken into consideration in +bundled aggregations, nor should they be returned from `/relations`. + +Requesting `/relations` on a redacted event should +still return any existing relation events. +This is in line with other APIs like `/context` and `/messages`. + +### Local echo + +For the best possible user experience, clients should also include unsent +relations into the client-side aggregation. When adding a relation to the send +queue, clients should locally aggregate it into the relations of the target +event, ideally regardless of the target event having received an `event_id` +already or still being pending. If the client gives up on sending the relation +for some reason, the relation should be de-aggregated from the relations of +the target event. If the client offers the user a possibility of manually +retrying to send the relation, it should be re-aggregated when the user does so. + +De-aggregating a relation refers to rerunning the aggregation for a given +target event while not considering the de-aggregated event any more. + +Upon receiving the remote echo for any relations, a client is likely to remove +the pending event from the send queue. Here, it should also de-aggregate the +pending event from the target event's relations, and re-aggregate the received +remote event from `/sync` to make sure the client-side aggregation happens with +the same event data as on the server. + +When adding a redaction for a relation to the send queue, the relation +referred to should be de-aggregated from the relations of the target of the +relation. Similar to a relation, when the sending of the redaction fails or +is cancelled, the relation should be aggregated again. + +If the target event is still pending and hasn't received its `event_id` yet, +clients can locally relate relation events to their target by using +`transaction_id` like they already do for detecting remote echos when sending +events. + +## Edge cases + +### How do you handle ignored users? + + * Information about relations sent from ignored users must never be sent to + the client, either in aggregations or discrete relation events. + This is to let you block someone from harassing you with emoji reactions + (or using edits as a side-channel to harass you). Therefore, it is possible + that different users will see different aggregations (a different last edit, + or a different reaction count) on an event. + +## Limitations + +### Relations can be missed while not being in the room + +Relation events behave no different from other events in terms of room history visibility, +which means that some relations might not be visible to a user while they are not invited +or have not joined the room. This can cause a user to see an incomplete edit history or reaction count +based on discrete relation events upon (re)joining a room. + +Ideally the server would not include these events in aggregations, as it would mean breaking +the room history visibility rules, but this MSC defers addressing this limitation and +specifying the exact server behaviour to [MSC3570](https://github.com/matrix-org/matrix-doc/pull/3570). + +### Servers might not be aware of all relations of an event + +The response of `/relations` might be incomplete because the homeserver +potentially doesn't have the full DAG of the room. The federation API doens't +have an equivalent of the `/relations` API, so has no way but to fetch the +full DAG over federation to assure itself that it is aware of all relations. + +[MSC2836](https://github.com/matrix-org/matrix-doc/pull/2836) provided a proposal for following relationships over federation in the "Querying relationships over federation" section via a `/_matrix/federation/v1/event_relationships` API + +### Event type based aggregation and filtering won't work well in encrypted rooms + +The `/relations` endpoint allows filtering by event type, +which for encrypted rooms will be `m.room.encrypted`, rendering this filtering +less useful for encrypted rooms. Aggregation algorithms that take the type of +the relating events they aggregate into account will suffer from the same +limitation. + +## Future extensions + +### Handling limited (gappy) syncs + +For the special case of a gappy incremental sync, many relations (particularly +reactions) may have occurred during the gap. It would be inefficient to send +each one individually to the client, but it would also be inefficient to send +all possible bundled aggregations to the client. + +The server could tell the client the event IDs of events which +predate the gap which received relations during the gap. This means that the +client could invalidate its copy of those events (if any) and then requery them +(including their bundled relations) from the server if/when needed, +for example using an extension of the `/event` API for batch requests. + +The server could do this with a new `stale_events` field of each room object +in the sync response. The `stale_events` field would list all the event IDs +prior to the gap which had updated relations during the gap. The event IDs +would be grouped by relation type, +and paginated as per the normal Matrix pagination model. + +This was originally part of this MSC but left out to limit the scope +to what is implemented at the time of writing. + +## Prefix + +While this MSC is not considered stable, the endpoints become: + + - `GET /_matrix/client/unstable/rooms/{roomID}/relations/{eventID}[/{relationType}[/{eventType}]]` + +None of the newly introduced identifiers should use a prefix though, as this MSC +tries to document relation support already being used in +the wider matrix ecosystem. \ No newline at end of file From e979b3b9bb2b84d213d23a22bea611d78c9c87f1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 6 Mar 2022 23:01:12 +0200 Subject: [PATCH 08/13] MSC3316: Add timestamp massaging to the spec (#3316) * Proposal to add timestamp massaging to the spec Signed-off-by: Tulir Asokan * Update unstable prefix Signed-off-by: Tulir Asokan --- .../3316-appservice-timestamp-massaging.md | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 proposals/3316-appservice-timestamp-massaging.md diff --git a/proposals/3316-appservice-timestamp-massaging.md b/proposals/3316-appservice-timestamp-massaging.md new file mode 100644 index 000000000..b954e59a1 --- /dev/null +++ b/proposals/3316-appservice-timestamp-massaging.md @@ -0,0 +1,51 @@ +# Proposal to add timestamp massaging to the spec +Bridges often want to override message timestamps to preserve the timestamps from +the remote network. The spec used to have a concept of [timestamp massaging], but +it was excluded from the release due to not being properly specified. Synapse +still implements it and it is widely used in bridges. + +[MSC2716] was originally going to add timestamp massaging to the spec, but it +pivoted to focusing solely on batch sending history. This MSC simply copies the +proposed `ts` query param from the [original MSC2716]. + +[timestamp massaging]: https://matrix.org/docs/spec/application_service/r0.1.2#timestamp-massaging +[MSC2716]: https://github.com/matrix-org/matrix-doc/pull/2716 +[original MSC2716]: https://github.com/matrix-org/matrix-doc/blob/94514392b118dfae8ee6840b13b83d2f8ce8fcfc/proposals/2716-importing-history-into-existing-rooms.md + +## Proposal +As per the original version of MSC2716: + +> We let the AS API override ('massage') the `origin_server_ts` timestamp +> applied to sent events. We do this by adding a `ts` querystring parameter on +> the `PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}` +> and `PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}` +> endpoints, specifying the value to apply to `origin_server_ts` on the event +> (UNIX epoch milliseconds). +> +> We consciously don't support the `ts` parameter on the various helper +> syntactic-sugar APIs like /kick and /ban. If a bridge/bot is smart enough to +> be faking history, it is already in the business of dealing with raw events, +> and should not be using the syntactic sugar APIs. + +The spec should also make it clear that the `ts` query param won't affect DAG +ordering, and MSC2716's batch sending should be used when the intention is to +insert history somewhere else than the end of the room. + +## Potential issues +None. + +## Alternatives +The new MSC2716 could technically be considered an alternative, but it can only +be used for history, while this proposal also supports overriding timestamps of +new messages. In practice, bridges will likely use both: Batch sending for +filling history and timestamp massaging for new messages. + +## Security considerations +Timestamps should already be considered untrusted over federation, and +application services are trusted server components, so allowing appservices +to override timestamps does not create any new security considerations. + +## Unstable prefix +`org.matrix.msc3316.ts` may be used as the query parameter. However, the `ts` +parameter is already used in production for the `/send` endpoint, which means +the unstable prefix should only be used for the `/state` endpoint. From 3f0ba9c749c86be8772e79b25cb37755832a1218 Mon Sep 17 00:00:00 2001 From: Bruno Windels <274386+bwindels@users.noreply.github.com> Date: Sun, 17 Jul 2022 18:47:24 +0000 Subject: [PATCH 09/13] MSC3267: Reference relations (#3267) * initial draft of reference relations msc * change MSC number * Apply formatting * Convert to point at present rather than ideal * Clarify that multiple relations is a thing we don't have and won't fix here * Fix wording to match reality, again * fix a typo Co-authored-by: Travis Ralston Co-authored-by: Andrew Morgan --- proposals/3267-reference-relations.md | 92 +++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 proposals/3267-reference-relations.md diff --git a/proposals/3267-reference-relations.md b/proposals/3267-reference-relations.md new file mode 100644 index 000000000..7b11d649f --- /dev/null +++ b/proposals/3267-reference-relations.md @@ -0,0 +1,92 @@ +# MSC3267: reference relationships + +## Proposal + +This proposal defines a relation type (using +[MSC2674 relations](https://github.com/matrix-org/matrix-doc/pull/2674)) +for events to make a reference to another event. + +A `rel_type` of `m.reference` is defined as a generic way to associate an +event with another event. As a bundle, `m.reference` relations appear as +an object with a single `chunk` field. The `chunk` is an array of objects +with a single `event_id` field for all the child events which `m.reference` +the parent. + +There are no implied semantics by a reference relation: the feature or event +type which makes use of the `rel_type` should specify what sort of semantic +behaviour there is, if any. For example, describing that a poll response event +*references* the poll start event, or that a location update *references* a +previous location update. + +Reference relations are used by [MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241) +to tie all events together for the same verification request. + +For instance, an `m.room.message` which references an existing event +would look like: + +```json5 +{ + // Unimportant fields omitted + "type": "m.room.message", + "content": { + "msgtype": "m.text", + "body": "i <3 shelties", + "m.relates_to": { + "rel_type": "m.reference", + "event_id": "$another_event_id" + } + } +} +``` + +## Server aggregation + +[MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674) states +that values for `rel_type` should define how the server should aggregate the +`rel_type`. For `m.reference`, child events are bundled to appear as follows +under `m.relations`: + +```json5 +{ + "m.reference": { + "chunk": [ + {"event_id": "$one"}, + {"event_id": "$two"}, + {"event_id": "$three"} + ] + } +} +``` + +Note that currently only the `event_id` is noted in the chunk, however a future +MSC might add more fields. + +## Limitations + +Different subtypes of references could be defined through additional fields on +the `m.relates_to` object, to distinguish between other forms of semantic behaviour +independent of type (hypothetical threads, replies, etc if we didn't have a system +for them already). This MSC doesn't attempt to define these subtypes. + +This relation cannot be used in conjunction with another relation due to `rel_type` +being a single value. This is known and unfortunately not resolved by this MSC. +A future MSC might address the concern. + +## Edge Cases + +Can you reference an event which doesn't have logical meaning? Eg to a [reaction](https://github.com/matrix-org/matrix-doc/pull/2677)? + * Yes, at the protocol level. But you shouldn't expect clients to do anything + useful with it. + * The relationship is effectively pointless, so the event would appear as though + there was no reference relationship. + +Do we need to support retrospective references? + * For something like "m.duplicate" to retrospectively declare that one event + dupes another, we might need to bundle two-levels deep (subject+ref and then + ref+target). We can cross this bridge when we get there though, as another + aggregation type + +## Unstable prefix + +Unfortunately not applicable - this MSC was used in production and appears in the +specified version of the [key verification framework](https://spec.matrix.org/v1.2/client-server-api/#key-verification-framework). From 3297d37770c5d103ae1118d2100b8b8ed38fb766 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 17 Jul 2022 21:47:50 +0300 Subject: [PATCH 10/13] MSC2832: HS -> AS authorization header (#2832) * Proposal to fix homeserver -> appservice authorization Signed-off-by: Tulir Asokan * Remove query parameter entirely instead of deprecating it Signed-off-by: Tulir Asokan * Update title Co-authored-by: Jonathan de Jong Co-authored-by: Jonathan de Jong --- proposals/2832-appservice-auth-fix.md | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 proposals/2832-appservice-auth-fix.md diff --git a/proposals/2832-appservice-auth-fix.md b/proposals/2832-appservice-auth-fix.md new file mode 100644 index 000000000..412b4d036 --- /dev/null +++ b/proposals/2832-appservice-auth-fix.md @@ -0,0 +1,28 @@ +# MSC2832: Homeserver -> Application Service authorization header +Most of the auth tokens in the spec are passed in the `Authorization` header, +with the `access_token` query parameter supported for backwards-compatibility. +For some reason, the application service spec was not updated in the same way +and it still requires using the archaic query parameter when the homeserver +pushes transactions to the appservice. + +## Proposal +The `access_token` query parameter is removed from all requests made by the +homeserver to appservice and is replaced with the `Authorization` header with +`Bearer ` as the value. + +### Backwards-compatibility +Homeservers which want to support old spec versions in the appservice API may +send both the query parameter and header. Similarly, appservices may accept the +token from either source. + +## Security considerations +Not fixing this causes access tokens to be logged in many bridges. + +## Alternatives +We could add a way for appservices to explicitly specify which spec version +they want in order to implement backwards-compatibility without sending both +tokens. + +## Unstable prefix +The authorization header is already used in the client-server spec, and an +unstable prefix would just unnecessarily complicate things. From 5a75c7a308121a6379490b4c984dde1a157cc3f2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sun, 17 Jul 2022 13:06:08 -0600 Subject: [PATCH 11/13] MSC2285: Private read receipts (#2285) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * What if we let people hide their read receipts? * Add unstable prefix * Update proposals/2285-hidden-read-receipts.md Co-authored-by: Šimon Brandner * Use a separate `receiptType` for hidden read receipts (#3750) * Update the way MSC2285 works Signed-off-by: Šimon Brandner * Update proposals/2285-hidden-read-receipts.md Co-authored-by: Travis Ralston * Clarify notification behaviour and other things Co-authored-by: Patrick Cloke * Mention adding `m.fully_read` to `/receipt` * Rename MSC to `Private read receipts` Signed-off-by: Šimon Brandner * Apply suggestions from review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Apply suggestions from review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Remove trailing comma Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Apply suggestions from review Signed-off-by: Šimon Brandner * Apply suggestions from review Signed-off-by: Šimon Brandner * `r0` -> `v3` Signed-off-by: Šimon Brandner * Describe how to determine server support while stable Signed-off-by: Šimon Brandner * Be more precise about the failure mode Signed-off-by: Šimon Brandner * Improve wording Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Improve wording Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Improve wording Signed-off-by: Šimon Brandner * Be more explicit Signed-off-by: Šimon Brandner * Be more explicit around server support Signed-off-by: Šimon Brandner * Simplify text Signed-off-by: Šimon Brandner * Be more explicit about detecting server support Signed-off-by: Šimon Brandner * Add note about consistency Signed-off-by: Šimon Brandner * Clarify how exactly to detect support * Try to fix clarity around precedence * Be clearer about alternatives Signed-off-by: Šimon Brandner * Add sentence about `/receipt` federation Signed-off-by: Šimon Brandner * Be more explicit about adding `m.read.private` to `/receipt` Signed-off-by: Šimon Brandner * Fix wrong RR type Co-authored-by: Kévin Commaille <76261501+zecakeh@users.noreply.github.com> Co-authored-by: Šimon Brandner Co-authored-by: Patrick Cloke Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Kévin Commaille <76261501+zecakeh@users.noreply.github.com> --- proposals/2285-hidden-read-receipts.md | 151 +++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 proposals/2285-hidden-read-receipts.md diff --git a/proposals/2285-hidden-read-receipts.md b/proposals/2285-hidden-read-receipts.md new file mode 100644 index 000000000..7c3ed9eeb --- /dev/null +++ b/proposals/2285-hidden-read-receipts.md @@ -0,0 +1,151 @@ +# MSC2285: Private read receipts + +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 + +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 +{} +``` + +The MSC also proposes adding `m.fully_read` and `m.read.private` 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) + +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.fully_read` property is now optional for the [`/read_markers` +endpoint](https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3roomsroomidread_markers) +as sometimes we only want to send `m.read.private`. + +The MSC proposes that from now on, not all things sent over `/receipt` are +federated. 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 store the setting that controls +whether read receipts should be private on a per-account/per-room basis. While +this might have some benefits, it is much less flexible. + +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. + +## 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. From a47591bb9cd2f041eca3c42d69d98410bb02ac2b Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Sun, 17 Jul 2022 23:00:43 -0400 Subject: [PATCH 12/13] MSC2676: Message editing (#2676) * initial version of message editing proposal * fix MSC numbers * Fix JSON in example Co-authored-by: Alexandre Morignot * clarifications * remove obsolete "XXX:", and fix a typo * Initial cleanup and restructuring * Clarify algorithm for replacing content * background * More clarifications on applying edits * Clarify behaviour of redactions * Minor grammar fixes * Move the section on `msgtype` down It clutters up the initial description - let's move it down into a more detailed section. * Clarify how edits are ordered - we use event_id as a tiebreaker. We also have a section in "Future considerations" about this, so I don't think we need the braindump in "Edge cases". * Spec the behaviour for encrypted events * Requirements for an edit event to be considered valid * Collect "client behaviour" and "sever behaviour" together ... and clarify these sections. * Clarify permalinks section * Notes on edits of replies * Clarify that `m.relates_to` within `m.new_content` is ignored * Clarifications from review * event ids are sorted lexicographically * Clarify aggregation section * minor clarifications * Clarify which endpoints support edits * move definition of latest edit * Apply suggestions from code review Co-authored-by: Hubert Chathi * fix typo * Attempt to clarify encrypted events Co-authored-by: Alexandre Morignot Co-authored-by: Richard van der Hoff Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/2676-message-editing.md | 407 ++++++++++++++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 proposals/2676-message-editing.md diff --git a/proposals/2676-message-editing.md b/proposals/2676-message-editing.md new file mode 100644 index 000000000..680563b50 --- /dev/null +++ b/proposals/2676-message-editing.md @@ -0,0 +1,407 @@ +# MSC2676: Message editing + +Users may wish to edit previously sent messages, for example to correct typos. +This can be done by sending a new message with an indication that it replaces +the previously sent message. + +This proposal is one in a series of proposals that defines a mechanism for +events to relate to each other. Together, these proposals replace +[MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849). + +* [MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674) defines a + standard shape for indicating events which relate to other events. +* [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675) defines APIs to + let the server calculate the aggregations on behalf of the client, and so + bundle the related events with the original event where appropriate. +* This proposal defines how users can edit messages using this mechanism. +* [MSC2677](https://github.com/matrix-org/matrix-doc/pull/2677) defines how + users can annotate events, such as reacting to events with emoji, using this + mechanism. + +## Background + +Element-Web (then Riot-Web) and Synapse both implemented initial support for +message editing, following the proposals of MSC1849, in May 2019 +([matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk/pull/2952), +[synapse](https://github.com/matrix-org/synapse/pull/5209)). Element-Android +and Element-iOS also added implementations around that time. Unfortunately, +those implementations presented the feature as "production-ready", despite it +not yet having been adopted into the Matrix specification. + +The current situation is therefore that client or server implementations hoping +to interact with Element users must simply follow the examples of that +implementation. In other words, message edits form part of the *de-facto* spec +despite not being formalised in the written spec. This is clearly a regrettable +situation. Hopefully, processes have improved over the last three years so that +this situation will not arise again. Nevertheless there is little we can do +now other than formalise the status quo. + +This MSC, along with the others mentioned above, therefore seeks primarily to +do that. Although there is plenty of scope for improvement, we consider that +better done in *future* MSCs, based on a shared understanding of the *current* +implementation. + +In short, this MSC prefers fidelity to the current implementations over +elegance of design. + +## Proposal + +### `m.replace` event relationship type + +A new `rel_type` of `m.replace` is defined for use with the `m.relates_to` +field as defined in +[MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674). This is +intended primarily for handling edits, and lets you define an event which +replaces an existing event. + +Such an event, with `rel_type: m.replace`, is referred to as a "message edit event". + +### `m.new_content` property + +The `content` of a message edit event must contain a `m.new_content` property +which defines the replacement content. (This allows the normal `body` fields to +be used for a fallback for clients who do not understand replacement events.) + +For instance, an `m.room.message` which replaces an existing event might look like: + +```json +{ + "type": "m.room.message", + "content": { + "body": "* Hello! My name is bar", + "msgtype": "m.text", + "m.new_content": { + "body": "Hello! My name is bar", + "msgtype": "m.text" + }, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$some_event_id" + } + } +} +``` + +The `m.new_content` can include any properties that would normally be found in +an event's `content` property, such as `formatted_body`. + +#### Encrypted events + +If the original event was encrypted, the replacement should be too. In that +case, `m.new_content` is placed in the `content` of the encrypted payload. The +`m.relates_to` property remains unencrypted, as required by the +[relationships](https://spec.matrix.org/v1.3/client-server-api/#forming-relationships-between-events) +section of the Client-Server API specification. + +For example, an encrypted replacement event might look like this: + +```json +{ + "type": "m.room.encrypted", + "content": { + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$some_event_id" + }, + "algorithm": "m.megolm.v1.aes-sha2", + "sender_key": "", + "device_id": "", + "session_id": "", + "ciphertext": "" + } +} +``` + +... and, once decrypted, the payload might look like this: + + +```json +{ + "type": "m.room.", + "room_id": "!some_room_id", + "content": { + "body": "* Hello! My name is bar", + "msgtype": "m.text", + "m.new_content": { + "body": "Hello! My name is bar", + "msgtype": "m.text" + } + } +} +``` + +Note that: + * There is no `m.relates_to` property in the encrypted payload. (Any such + property would be ignored.) + * There is no `m.new_content` property in the cleartext `content` of the + `m.room.encrypted` event. (Again, any such property would be ignored.) + +For clarity: the payload must be encrypted as normal, ratcheting the Megolm session +as normal. The original Megolm ratchet entry should **not** be re-used. + +#### Applying `m.new_content` + +When applying a replacement, the `content` property of the original event is +replaced entirely by the `m.new_content`, with the exception of `m.relates_to`, +which is left *unchanged*. Any `m.relates_to` property within `m.new_content` +is ignored. + +For example, given a pair of events: + +```json +{ + "event_id": "$original_event", + "type": "m.room.message", + "content": { + "body": "I *really* like cake", + "msgtype": "m.text", + "formatted_body": "I really like cake", + } +} +``` + +```json +{ + "event_id": "$edit_event", + "type": "m.room.message", + "content": { + "body": "* I *really* like *chocolate* cake", + "msgtype": "m.text", + "m.new_content": { + "body": "I *really* like *chocolate* cake", + "msgtype": "m.text", + "com.example.extension_property": "chocolate" + }, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$original_event_id" + } + } +} +``` + +... then the end result is an event as shown below. Note that `formatted_body` +is now absent, because it was absent in the replacement event, but +`m.relates_to` remains unchanged (ie, absent). + +```json +{ + "event_id": "$original_event", + "type": "m.room.message", + "content": { + "body": "I *really* like *chocolate* cake", + "msgtype": "m.text", + "com.example.extension_property": "chocolate" + } +} +``` + +Note that the `msgtype` property of `m.room.message` events need not be the +same as in the original event. For example, if a user intended to send a +message beginning with "/me", but their client sends an `m.emote` event +instead, they could edit the message to send be an `m.text` event as they had +originally intended. + +### Validity of message edit events + +Some message edit events are defined to be invalid. To be considered valid, all +of the following criteria must be satisfied: + + * The replacement and original events must have the same `type`. + * Neither the replacement nor original events can be state events (ie, neither + may have a `state_key`). + * The original event must not, itself, have a `rel_type` of `m.replace`. + * The original event and replacement event must have the same `sender`. + * The replacement event (once decrypted, if appropriate) must have an + `m.new_content` property. + +The original event and replacement event must also have the same `room_id`, as +required by the +[relationships](https://spec.matrix.org/v1.3/client-server-api/#forming-relationships-between-events) +section of the Client-Server API specification. + +If any of these criteria are not satisfied, implementations should ignore the +replacement event (the content of the original should not be replaced, and the +edit should not be included in the server-side aggregation). + +### Server behaviour + +#### Server-side aggregation of `m.replace` relationships + +Note that there can be multiple events with an `m.replace` relationship to a +given event (for example, if an event is edited multiple times). These should +be [aggregated](https://spec.matrix.org/v1.3/client-server-api/#aggregations) +by the homeserver. + +The format of the aggregation for `m.replace` simply gives gives the +`event_id`, `origin_server_ts`, and `sender` of the most recent replacement +event (as determined by `origin_server_ts`, falling back to a lexicographic +ordering of `event_id`). + +This aggregation is bundled into the `unsigned/m.relations` property of any +event that is the target of an `m.replace` relationship. For example: + +```json5 + +{ + "event_id": "$original_event_id", + // ... + "unsigned": { + "m.relations": { + "m.replace": { + "event_id": "$latest_edit_event_id", + "origin_server_ts": 1649772304313, + "sender": "@editing_user:localhost" + } + } + } +} +``` + +If the original event is redacted, any `m.replace` relationship should **not** +be bundled with it (whether or not any subsequent edits are themselves +redacted). Note that this behaviour is specific to the `m.replace` +relationship. + +#### Server-side replacement of content + +Whenever an `m.replace` is to be bundled with an event as above, the server should +also modify the `content` of the original event according +to the `m.new_content` of the most recent edit (determined as above). + +An exception applies to [`GET +/_matrix/client/v3/rooms/{roomId}/event/{eventId}`](https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3roomsroomideventeventid), +which should return the *unmodified* event (though the relationship should +still be bundled, as described above). + +The endpoints where this behaviour takes place is the same as those where +aggregations are bundled, with the exception of +`/room/{roomId}/event/{eventId}`. This includes: + + * `GET /rooms/{roomId}/messages` + * `GET /rooms/{roomId}/context/{eventId}` + * `GET /rooms/{roomId}/relations/{eventId}` + * `GET /rooms/{roomId}/relations/{eventId}/{relType}` + * `GET /rooms/{roomId}/relations/{eventId}/{relType}/{eventType}` + * `GET /sync` when the relevant section has a `limited` value of `true` + * `POST /search` for any matching events under `room_events`. + +### Client behaviour + +Clients can often ignore message edit events, since any events the server +returns via the C-S API will be updated by the server to account for subsequent +edits. + +However, clients should apply the replacement themselves when the server is +unable to do so. This happens in the following situations: + +1. The client has already received and stored the original event before the message + edit event arrives. + +2. The original event (and hence its replacement) are encrypted. + +Client authors are reminded to take note of the requirements for [Validity of +message edit events](#validity-of-message-edit-events), and to ignore any +invalid edit events that may be received. + +### Permalinks + +Permalinks to edited events should capture the event ID that the creator of the +permalink is viewing at that point (which might be a message edit event). + +The client viewing the permalink should resolve this ID to the original event +ID, and then display the most recent version of that event. + +### Redactions + +When a message using a `rel_type` of `m.replace` is redacted, it removes that +edit revision. This has little effect if there were subsequent edits, however +if it was the most recent edit, the event is in effect reverted to its content +before the redacted edit. + +Redacting the original message in effect removes the message, including all +subsequent edits, from the visible timeline. In this situation, homeservers +will return an empty `content` for the original event as with any other +redacted event. It must be noted that, although they are not immediately +visible in Element, subsequent edits remain unredacted and can be seen via API +calls. See [Future considerations](#future-considerations). + +### Edits of replies + +Some particular constraints apply to events which replace a +[reply](https://spec.matrix.org/v1.3/client-server-api/#rich-replies). In +particular: + + * There should be no `m.in_reply_to` property in the the `m.relates_to` + object, since it would be redundant (see [Applying + `m.new_content`](#applying-mnew_content) above, which notes that the original + event's `m.relates_to` is preserved), as well as being contrary to the + spirit of + [MSC2674](https://github.com/matrix-org/matrix-spec-proposals/pull/2674) + which expects only one relationship per event. + + * `m.new_content` should **not** contain any ["reply + fallback"](https://spec.matrix.org/v1.3/client-server-api/#fallbacks-for-rich-replies), + since it is assumed that any client which can handle edits can also + display replies natively. + +An example of an edit to a reply is as follows: + +```json +{ + "type": "m.room.message", + "content": { + "body": "> <@richvdh:sw1v.org> ab\n\n * ef", + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "formatted_body": "
In reply to @richvdh:sw1v.org
ab
* ef", + "m.new_content": { + "body": "ef", + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "formatted_body": "ef" + }, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": "$original_reply_event" + } + } +} +``` + + +## Future considerations + +### Ordering of edits + +In future we may wish to consider ordering replacements (or relations in +general) via a DAG rather than using `origin_server_ts` to determine ordering - +particularly to mitigate potential abuse of edits applied by moderators. +Whatever, care must be taken by the server to ensure that if there are multiple +replacement events, the server must consistently choose the same one as all +other servers. + +### Redaction of edits + +It is highly unintuitive that redacting the original event leaves subsequent +edits visible to curious eyes even though they are hidden from the +timeline. This is considered a bug which this MSC makes no attempt to +resolve. See also +[element-web#11978](https://github.com/vector-im/element-web/issues/11978) and +[synapse#5594](https://github.com/matrix-org/synapse/issues/5594). + +### Edits to state events + +There are various issues which would need to be resolved before edits to state +events could be supported. In particular, we would need to consider how the +semantically-meaningful fields of the content of a state event relate to +`m.new_content`. Variation between implementations could easily lead to +security problems (See +[element-web#21851](https://github.com/vector-im/element-web/issues/21851) for +example.) + +### Editing other users' events + +There is a usecase for users with sufficient power-level to edit other peoples' +events. For now, no attempt is made to support this. If it is supported in the +future, we would need to find a way to make it clear in the timeline. From a96b752a4b666ace80402321a4732fcad143fca6 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sun, 6 Nov 2022 06:21:11 -0600 Subject: [PATCH 13/13] MSC3030: Jump to date API endpoint (#3030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial MSC draft for jump to date * Update with alternate /timestamp_to_event endpoint * Add origin_server_ts for quick remote to local comparison As discussed at https://github.com/matrix-org/synapse/pull/9445#discussion_r757098009 * Add origin_server_ts to client endpoint * Wrap lines * Use stable when discussing MSC and document unstable * Describe the direction parameter * Add server support detection * Fix typos * Explain what happens when an event can't be found Fix https://github.com/matrix-org/matrix-doc/pull/3030#discussion_r787002549 * Add context behind why we chose /timestamp_to_event vs alternatives Fix https://github.com/matrix-org/matrix-doc/pull/3030#discussion_r785425438 * Add comments about authentication and rate-limiting Fix https://github.com/matrix-org/matrix-doc/pull/3030#discussion_r786351083 * Return pagination token directly in future iteration See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r787297190 * Abuse /timestamp_to_event to get create event As suggested by @turt2live, https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r846444317 * Unrenderable events As proposed by @turt2live, https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r846447351 * Add some complication thoughts around alternatives Context: https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r846449709 * Backfill event so we can get pagination token See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r846578171 * Heuristic for which server to try first See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r967574944 * Give a suggestion on where to backfill from See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r967574843 * Add alternative suggestion from @alphapapa See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r868478333 * Better wording and fix typo Co-authored-by: Travis Ralston * No difference in homeservers See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r992858188 * Fix typos Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Fix extra word typo * Summarizing discussion around why `dir` instead of closest See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r849310414 * Adjust to just suggest the right way See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r999099294 * Great simplification with the same meaning 🌟 Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Perfect is the enemy of good See https://github.com/matrix-org/matrix-spec-proposals/pull/3030#discussion_r1004651959 Co-authored-by: Travis Ralston Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/3030-jump-to-date.md | 286 +++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 proposals/3030-jump-to-date.md diff --git a/proposals/3030-jump-to-date.md b/proposals/3030-jump-to-date.md new file mode 100644 index 000000000..e19ce415b --- /dev/null +++ b/proposals/3030-jump-to-date.md @@ -0,0 +1,286 @@ +# MSC3030: Jump to date API endpoint + +Add an API that makes it easy to find the closest messages for a given +timestamp. + +The goal of this change is to have clients be able to implement a jump to date +feature in order to see messages back at a given point in time. Pick a date from +a calender, heatmap, or paginate next/previous between days and view all of the +messages that were sent on that date. + +Alongside the [roadmap of feature parity with +Gitter](https://github.com/vector-im/roadmap/issues/26), we're also interested +in using this for a new better static Matrix archive. Our idea is to server-side +render [Hydrogen](https://github.com/vector-im/hydrogen-web) and this new +endpoint would allow us to jump back on the fly without having to paginate and +keep track of everything in order to display the selected date. + +Also useful for archiving and backup use cases. This new endpoint can be used to +slice the messages by day and persist to file. + +Related issue: [*URL for an arbitrary day of history and navigation for next and +previous days* +(vector-im/element-web#7677)](https://github.com/vector-im/element-web/issues/7677) + + +## Problem + +These types of use cases are not supported by the current Matrix API because it +has no way to fetch or filter older messages besides a manual brute force +pagination from the most recent event in the room. Paginating is time-consuming +and expensive to process every event as you go (not practical for clients). +Imagine wanting to get a message from 3 years ago 😫 + + +## Proposal + +Add new client API endpoint `GET +/_matrix/client/v1/rooms/{roomId}/timestamp_to_event?ts=&dir=[f|b]` +which fetches the closest `event_id` to the given timestamp `ts` query parameter +in the direction specified by the `dir` query parameter. The direction `dir` +query parameter accepts `f` for forward-in-time from the timestamp and `b` for +backward-in-time from the timestamp. This endpoint also returns +`origin_server_ts` to make it easy to do a quick comparison to see if the +`event_id` fetched is too far out of range to be useful for your use case. + +When an event can't be found in the given direction, the endpoint throws a 404 +`"errcode":"M_NOT_FOUND",` (example error message `"error":"Unable to find event +from 1672531200000 in direction f"`). + +In order to solve the problem where a homeserver does not have all of the history in a +room and no suitably close event, we also add a server API endpoint `GET +/_matrix/federation/v1/timestamp_to_event/{roomId}?ts=?dir=[f|b]` which other +homeservers can use to ask about their closest `event_id` to the timestamp. This +endpoint also returns `origin_server_ts` to make it easy to do a quick comparison to see +if the remote `event_id` fetched is closer than the local one. After the local +homeserver receives a response from the federation endpoint, it probably should +try to backfill this event via the federation `/event/` endpoint so that it's +available to query with `/context` from a client in order to get a pagination token. + +The heuristics for deciding when to ask another homeserver for a closer event if +your homeserver doesn't have something close, are left up to the homeserver +implementation, although the heuristics will probably be based on whether the +closest event is a forward/backward extremity indicating it's next to a gap of +events which are potentially closer. + +A good heuristic for which servers to try first is to sort by servers that have +been in the room the longest because they're most likely to have anything we ask +about. + +These endpoints are authenticated and should be rate-limited like similar client +and federation endpoints to prevent resource exhaustion abuse. + +``` +GET /_matrix/client/v1/rooms//timestamp_to_event?ts=&dir= +{ + "event_id": ... + "origin_server_ts": ... +} +``` + +Federation API endpoint: +``` +GET /_matrix/federation/v1/timestamp_to_event/?ts=&dir= +{ + "event_id": ... + "origin_server_ts": ... +} +``` + +--- + +In order to paginate `/messages`, we need a pagination token which we can get +using `GET /_matrix/client/r0/rooms/{roomId}/context/{eventId}?limit=0` for the +`event_id` returned by `/timestamp_to_event`. + +We can always iterate on `/timestamp_to_event` later and return a pagination +token directly in another MSC ⏩ + + +## Potential issues + +### Receiving a rogue random delayed event ID + +Since `origin_server_ts` is not enforcably accurate, we can only hope that an event's +`origin_server_ts` is relevant enough to its `prev_events` and descendants. + +If you ask for "the message with `origin_server_ts` closest to Jan 1st 2018" you +might actually get a rogue random delayed one that was backfilled from a +federated server, but the human can figure that out by trying again with a +slight variation on the date or something. + +Since there isn't a good or fool-proof way to combat this, it's probably best to just go +with `origin_server_ts` and not let perfect be the enemy of good. + + +### Receiving an unrenderable event ID + +Another issue is that clients could land on an event they can't/won't render, +such as a reaction, then they'll be forced to desperately seek around the +timeline until they find an event they can do something with. + +Eg: + - Client wants to jump to January 1st, 2022 + - Server says there's an event on January 2nd, 2022 that is close enough + - Client finds out there's a ton of unrenderable events like memberships, poll responses, reactions, etc at that time + - Client starts paginating forwards, finally finding an event on January 27th it can render + - Client wasn't aware that the actual nearest neighbouring event was backwards on December 28th, 2021 because it didn't paginate in that direction + - User is confused that they are a month past the target date when the message is *right there*. + +Clients can be smarter here though. Clients can see when events were sent as +they paginate and if they see they're going more than a couple days out, they +can also try the other direction before going further and further away. + +Clients can also just explain to the user what happened with a little toast: "We +were unable to find an event to display on January 1st, 2022. The closest event +after that date is on January 27th." + + +### Abusing the `/timestamp_to_event` API to get the `m.room.create` event + +Although it's possible to jump to the start of the room and get the first event in the +room (`m.room.create`) with `/timestamp_to_event?dir=f&ts=0`, clients should still use +`GET /_matrix/client/v3/rooms/{roomId}/state/m.room.create/` to get the room creation +event. + +In the future, with things like importing history via +[MSC2716](https://github.com/matrix-org/matrix-spec-proposals/pull/2716), the first +event you encounter with `/timestamp_to_event?dir=f&ts=0` could be an imported event before +the room was created. + + +## Alternatives + +We chose the current `/timestamp_to_event` route because it sounded like the +easist path forward to bring it to fruition and get some real-world experience. +And was on our mind during the [initial discussion](https://docs.google.com/document/d/1KCEmpnGr4J-I8EeaVQ8QJZKBDu53ViI7V62y5BzfXr0/edit#bookmark=id.qu9k9wje9pxm) because there was some prior art with a [WIP +implementation](https://github.com/matrix-org/synapse/pull/9445/commits/91b1b3606c9fb9eede0a6963bc42dfb70635449f) +from @erikjohnston. The alternatives haven't been thrown out for a particular +reason and we could still go down those routes depending on how people like the +current design. + + +### Paginate `/messages?around=` from timestamp + +Add the `?around=` query parameter to the `GET +/_matrix/client/r0/rooms/{roomId}/messages` endpoint. This will start the +response at the message with `origin_server_ts` closest to the provided `around` +timestamp. The direction is determined by the existing `?dir` query parameter. + +Use topological ordering, just as Element would use if you follow a permalink. + +This alternative could be confusing to the end-user around how this plays with +the existing query parameters +`/messages?from={paginationToken}&to={paginationToken}` which also determine +what part of the timeline to query. Those parameters could be extended to accept +timestamps in addition to pagination tokens but then could get confusing again +when you start mixing timestamps and pagination tokens. The homeserver also has +to disambiguate what a pagination token looks like vs a unix timestamp. Since +pagination tokens don't follow a certain convention, some homeserver +implementations may already be using arbitrary number tokens already which would +be impossible to distinguish from a timestamp. + +A related alternative is to use `/messages` with a `from_time`/`to_time` (or +`from_ts`/`to_ts`) query parameters that only accept timestamps which solves the +confusion and disambigution problem of trying to re-use the existing `from`/`to` +query paramters. Re-using `/messages` would reduce the number of round-trips and +potentially client-side implementations for the use case where you want to fetch +a window of messages from a given time. But has the same round-trip problem if +you want to use the returned `event_id` with `/context` or another endpoint +instead. + + +### Filter by date in `RoomEventFilter` + +Extend `RoomEventFilter` to be able to specify a timestamp or a date range. The +`RoomEventFilter` can be passed via the `?filter` query param on the `/messages` +endpoint. + +This suffers from the same confusion to the end-user of how it plays with how +this plays with `/messages?from={paginationToken}&to={paginationToken}` which +also determines what part of the timeline to query. + + +### Return the closest event in any direction + +We considered omitting the `dir` parameter (or allowing `dir=c`) to have the server +return the closest event to the timestamp, regardless of direction. However, this seems +to offer little benefit. + +Firstly, for some usecases (such as archive viewing, where we want to show all the +messages that happened on a particular day), an explicit direction is important, so this +would have to be optional behaviour. + +For a regular messaging client, "directionless" search also offers little benefit: it is +easy for the client to repeat the request in the other direction if the returned event +is "too far away", and in any case it needs to manage an iterative search to handle +unrenderable events, as discussed above. + +Implementing a directionless search on the server carries a performance overhead, since +it must search both forwards and backwards on every request. In short, there is little +reason to expect that a single `dir=c` request would be any more efficient than a pair of +requests with `dir=b` and `dir=f`. + +### New `destination_server_ts` field + +Add a new field and index on messages called `destination_server_ts` which +indicates when the message was received from federation. This gives a more +"real" time for how someone would actually consume those messages. + +The contract of the API is "show me messages my server received at time T" +rather than the messy confusion of showing a delayed message which happened to +originally be sent at time T. + +We've decided against this approach because the backfill from federated servers +could be horribly late. + +--- + +Related issue around `/sync` vs `/messages`, +https://github.com/matrix-org/synapse/issues/7164 + +> Sync returns things in the order they arrive at the server; backfill returns +> them in the order determined by the event graph. +> +> *-- @richvdh, https://github.com/matrix-org/synapse/issues/7164#issuecomment-605877176* + +> The general idea is that, if you're following a room in real-time (ie, +> `/sync`), you probably want to see the messages as they arrive at your server, +> rather than skipping any that arrived late; whereas if you're looking at a +> historical section of timeline (ie, `/messages`), you want to see the best +> representation of the state of the room as others were seeing it at the time. +> +> *-- @richvdh , https://github.com/matrix-org/synapse/issues/7164#issuecomment-605953296* + + +## Security considerations + +We're only going to expose messages according to the existing message history +setting in the room (`m.room.history_visibility`). No extra data is exposed, +just a new way to sort through it all. + + + +## Unstable prefix + +While this MSC is not considered stable, the endpoints are available at `/unstable/org.matrix.msc3030` instead of their `/v1` description from above. + +``` +GET /_matrix/client/unstable/org.matrix.msc3030/rooms//timestamp_to_event?ts=&dir= +{ + "event_id": ... + "origin_server_ts": ... +} +``` + +``` +GET /_matrix/federation/unstable/org.matrix.msc3030/timestamp_to_event/?ts=&dir= +{ + "event_id": ... + "origin_server_ts": ... +} +``` + +Servers will indicate support for the new endpoint via a non-empty value for feature flag +`org.matrix.msc3030` in `unstable_features` in the response to `GET +/_matrix/client/versions`.