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/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/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/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" %}} 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. 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" + } + } +} +``` 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 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. 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. 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) 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`. 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). 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. 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. 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) 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.