From 817ec5380f57aecc392db19e8f2c12361a12249c Mon Sep 17 00:00:00 2001 From: Kim Brose <2803622+HarHarLinks@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:19:23 +0100 Subject: [PATCH 01/19] Create funding-manifest-urls (#2115) * Create funding-manifest-urls * update funding-manifest-urls location, add news Signed-off-by: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> --------- Signed-off-by: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> --- changelogs/internal/newsfragments/2115.clarification | 1 + static/.well-known/funding-manifest-urls | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelogs/internal/newsfragments/2115.clarification create mode 100644 static/.well-known/funding-manifest-urls diff --git a/changelogs/internal/newsfragments/2115.clarification b/changelogs/internal/newsfragments/2115.clarification new file mode 100644 index 00000000..3deaf8c8 --- /dev/null +++ b/changelogs/internal/newsfragments/2115.clarification @@ -0,0 +1 @@ +Add [well-known funding manifest urls](https://floss.fund/funding-manifest/) to spec to authorise https://matrix.org/funding.json. Contributed by @HarHarLinks. diff --git a/static/.well-known/funding-manifest-urls b/static/.well-known/funding-manifest-urls new file mode 100644 index 00000000..1b14b420 --- /dev/null +++ b/static/.well-known/funding-manifest-urls @@ -0,0 +1 @@ +https://matrix.org/funding.json From 8a2c58b1b17b26f742be2e1b0aeafdd41bb5f9fc Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 28 Mar 2025 14:13:17 +0000 Subject: [PATCH 02/19] Typo "not" -> "no" (#2121) * Typo "not" -> "no" Signed-off-by: Andy Balaam --------- Signed-off-by: Andy Balaam --- changelogs/client_server/newsfragments/2121.clarification | 1 + content/client-server-api/modules/secrets.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelogs/client_server/newsfragments/2121.clarification diff --git a/changelogs/client_server/newsfragments/2121.clarification b/changelogs/client_server/newsfragments/2121.clarification new file mode 100644 index 00000000..3ccb2333 --- /dev/null +++ b/changelogs/client_server/newsfragments/2121.clarification @@ -0,0 +1 @@ +Fix various typos throughout the specification. diff --git a/content/client-server-api/modules/secrets.md b/content/client-server-api/modules/secrets.md index 3e586bc4..fb997992 100644 --- a/content/client-server-api/modules/secrets.md +++ b/content/client-server-api/modules/secrets.md @@ -58,7 +58,7 @@ available on all their clients. Unless the user specifies otherwise, clients will try to use the default key to decrypt secrets. Clients that want to present a simplified interface to users by not supporting -multiple keys should use the default key if one is specified. If not default +multiple keys should use the default key if one is specified. If no default key is specified, the client may behave as if there is no key is present at all. When such a client creates a key, it should mark that key as being the default key. From 23ff7f1343ef00c61d148e84b3a26ec7826810b2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 7 Apr 2025 14:28:00 -0600 Subject: [PATCH 03/19] Fix minor typo in content hash calculations (#2128) * Fix minor typo in content hash calculations * Changelog --- changelogs/server_server/newsfragments/2128.clarification | 1 + content/server-server-api.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelogs/server_server/newsfragments/2128.clarification diff --git a/changelogs/server_server/newsfragments/2128.clarification b/changelogs/server_server/newsfragments/2128.clarification new file mode 100644 index 00000000..3ccb2333 --- /dev/null +++ b/changelogs/server_server/newsfragments/2128.clarification @@ -0,0 +1 @@ +Fix various typos throughout the specification. diff --git a/content/server-server-api.md b/content/server-server-api.md index 65494f80..d93aa51f 100644 --- a/content/server-server-api.md +++ b/content/server-server-api.md @@ -1337,7 +1337,7 @@ calculated as follows. The *content hash* of an event covers the complete event including the *unredacted* contents. It is calculated as follows. -First, any existing `unsigned`, `signature`, and `hashes` members are +First, any existing `unsigned`, `signatures`, and `hashes` properties are removed. The resulting object is then encoded as [Canonical JSON](/appendices#canonical-json), and the JSON is hashed using SHA-256. From c39c7d06807d933c9584c59b9a9f9ba5b096409e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Tue, 15 Apr 2025 15:47:21 +0200 Subject: [PATCH 04/19] Fix `/sync` example (#2077) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix sync example The same event should not appear in `state` and in the `timeline` so we cannot use the same event twice. To provide a `state` example we assume that with lazy-loading the user did not get the state event for `@example:example.org`, so we add one since they sent a message in the timeline. The events that are referenced include a `room_id`, which doesn't appear on this endpoint, so we copy them without it. Finally, the `join` event of `@alice:example.org` is wrong because the sender does not match the state key, which wouldn't pass the authorization rules. Signed-off-by: Kévin Commaille * Fix the `m.room.member.yaml` example This is a `join` event, and the `sender` doesn't match the `state_key`, so the event couldn't pass the authorization rules. Signed-off-by: Kévin Commaille * Add changelog Signed-off-by: Kévin Commaille --------- Signed-off-by: Kévin Commaille --- .../newsfragments/2077.clarification | 1 + data/api/client-server/sync.yaml | 46 +++++++++++++++++-- .../event-schemas/examples/m.room.member.yaml | 1 + 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2077.clarification diff --git a/changelogs/client_server/newsfragments/2077.clarification b/changelogs/client_server/newsfragments/2077.clarification new file mode 100644 index 00000000..2077d47f --- /dev/null +++ b/changelogs/client_server/newsfragments/2077.clarification @@ -0,0 +1 @@ +Fix the example of the `GET /sync` endpoint and the `m.room.member` example used in several places. \ No newline at end of file diff --git a/data/api/client-server/sync.yaml b/data/api/client-server/sync.yaml index 9d9a807d..e6fd7883 100644 --- a/data/api/client-server/sync.yaml +++ b/data/api/client-server/sync.yaml @@ -441,17 +441,57 @@ paths: "state": { "events": [ { - "$ref": "../../event-schemas/examples/m.room.member.yaml" + "content": { + "avatar_url": "mxc://example.org/SFHyPlCeYUSFFxlgbQYZmoEoe", + "displayname": "Example user", + "membership": "join" + }, + "event_id": "$143273976499sgjks:example.org", + "origin_server_ts": 1432735824653, + "sender": "@example:example.org", + "state_key": "@example:example.org", + "type": "m.room.member", + "unsigned": { + "age": 45603, + "membership": "join" + } } ] }, "timeline": { "events": [ { - "$ref": "../../event-schemas/examples/m.room.member.yaml" + "content": { + "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", + "displayname": "Alice Margatroid", + "membership": "join", + "reason": "Looking for support" + }, + "event_id": "$143273582443PhrSn:example.org", + "origin_server_ts": 1432735824653, + "sender": "@alice:example.org", + "state_key": "@alice:example.org", + "type": "m.room.member", + "unsigned": { + "age": 1234, + "membership": "join" + } }, { - "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml" + "content": { + "body": "This is an example text message", + "format": "org.matrix.custom.html", + "formatted_body": "This is an example text message", + "msgtype": "m.text" + }, + "event_id": "$143273582443PhrSn:example.org", + "origin_server_ts": 1432735824653, + "sender": "@example:example.org", + "type": "m.room.message", + "unsigned": { + "age": 1234, + "membership": "join" + } } ], "limited": true, diff --git a/data/event-schemas/examples/m.room.member.yaml b/data/event-schemas/examples/m.room.member.yaml index 5147b258..85e9a9eb 100644 --- a/data/event-schemas/examples/m.room.member.yaml +++ b/data/event-schemas/examples/m.room.member.yaml @@ -1,6 +1,7 @@ { "$ref": "core/state_event.json", "state_key": "@alice:example.org", + "sender": "@alice:example.org", "type": "m.room.member", "content": { "membership": "join", From 65b1db721d1269936b4c9b3d4a8f0fc4250c9f94 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 15 Apr 2025 18:24:22 +0100 Subject: [PATCH 05/19] Describe behaviour when the `topic` key is falsey in a `m.room.topic` event. (#2068) We seem to have [updated this for m.room.name](https://github.com/matrix-org/matrix-spec/pull/1639) some years back but omitted it for topic. --- .../client_server/newsfragments/2068.clarification | 1 + data/event-schemas/schema/m.room.topic.yaml | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 changelogs/client_server/newsfragments/2068.clarification diff --git a/changelogs/client_server/newsfragments/2068.clarification b/changelogs/client_server/newsfragments/2068.clarification new file mode 100644 index 00000000..1b3c13e8 --- /dev/null +++ b/changelogs/client_server/newsfragments/2068.clarification @@ -0,0 +1 @@ +Clarify behaviour when the `topic` key of a `m.room.topic` event is absent, null, or empty. diff --git a/data/event-schemas/schema/m.room.topic.yaml b/data/event-schemas/schema/m.room.topic.yaml index 78a3d878..56f0caf9 100644 --- a/data/event-schemas/schema/m.room.topic.yaml +++ b/data/event-schemas/schema/m.room.topic.yaml @@ -1,7 +1,14 @@ --- allOf: - $ref: core-event-schema/state_event.yaml -description: 'A topic is a short message detailing what is currently being discussed in the room. It can also be used as a way to display extra information about the room, which may not be suitable for the room name. The room topic can also be set when creating a room using `/createRoom` with the `topic` key.' +description: |- + A topic is a short message detailing what is currently being discussed in the room. + It can also be used as a way to display extra information about the room, which may not + be suitable for the room name. + The room topic can also be set when creating a room using `/createRoom` with the `topic` key.' + + If the `topic` property is absent, null, or empty then the topic is unset. In other words, + an empty `topic` property effectively resets the room to having no topic. properties: content: properties: From 81273df88ee79e2819733ef70dfae9d715954ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Tue, 15 Apr 2025 19:35:27 +0200 Subject: [PATCH 06/19] Adjust margins in rendered endpoints (#2081) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use consistent spacing between tables and code blocks Tables used `4 rem` which is more than the margin above a h2 title, which seems excessive. We change it to `2 rem` which matches the margin of code blocks and info boxes. We also remove the margin on the last item of a `.rendered-data` block because this is just wasted space. Signed-off-by: Kévin Commaille * Adjust spacing around h2 and h3 titles in `.rendered-data` Given that h2 titles are always preceded by an horizontal rule, we don't need a lot of space to separate them from the previous section. We also reduce the spacing when a h2 title is followed directly by a h3 title. Finally, we add a little spacing below both so that tables are less close to the title. Signed-off-by: Kévin Commaille * Add changelog Signed-off-by: Kévin Commaille --------- Signed-off-by: Kévin Commaille Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- assets/scss/_styles_project.scss | 26 ++++++++++++++----- .../internal/newsfragments/2081.clarification | 1 + 2 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 changelogs/internal/newsfragments/2081.clarification diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss index 9b020715..772b8412 100644 --- a/assets/scss/_styles_project.scss +++ b/assets/scss/_styles_project.scss @@ -316,13 +316,19 @@ Custom SCSS for the Matrix spec h2 { font-weight: $font-weight-bold; font-size: 1.3rem; - margin: 3rem 0 .5rem 0; + margin: 1.5rem 0 1rem 0; } h3 { font-weight: $font-weight-bold; font-size: 1.1rem; - margin: 1.5rem 0 .75rem 0; + margin: 1.5rem 0 1rem 0; + + } + + /* Reduce top margin of h3 if previous sibling is a h2 */ + h2 + h3 { + margin-top: 1rem; } hr { @@ -367,11 +373,6 @@ Custom SCSS for the Matrix spec } } - // add some space between two tables when they are right next to each other - & + table { - margin-top: 4rem; - } - caption { caption-side: top; color: $dark; @@ -443,6 +444,17 @@ Custom SCSS for the Matrix spec } } + /* Have consistent spacing around tables and examples */ + table, .highlight { + margin-top: 0; + margin-bottom: 2rem; + + /* We don't need the margin on the last child of the .rendered-data block */ + &:last-child { + margin-bottom: 0; + } + } + pre { border: 0; border-left: solid 5px $secondary; diff --git a/changelogs/internal/newsfragments/2081.clarification b/changelogs/internal/newsfragments/2081.clarification new file mode 100644 index 00000000..a4923694 --- /dev/null +++ b/changelogs/internal/newsfragments/2081.clarification @@ -0,0 +1 @@ +Adjust margins in rendered endpoints. From fca171427f11233cb1b82982ac541dd206ebbff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Tue, 22 Apr 2025 16:48:50 +0200 Subject: [PATCH 07/19] Clarifications around third-party invites (#2083) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- .../newsfragments/2083.clarification | 2 + .../newsfragments/2083.clarification | 1 + .../newsfragments/2083.clarification | 2 + .../modules/third_party_invites.md | 46 ++++---- content/server-server-api.md | 44 ++++---- .../client-server/third_party_membership.yaml | 9 +- data/api/identity/v2_pubkey.yaml | 15 ++- data/api/identity/v2_store_invite.yaml | 14 ++- .../api/server-server/third_party_invite.yaml | 100 ++++-------------- .../components/signed_third_party_invite.yaml | 45 ++++++++ data/event-schemas/schema/m.room.member.yaml | 91 ++++++++-------- .../schema/m.room.third_party_invite.yaml | 48 +++++++-- data/string-formats.yaml | 5 + 13 files changed, 237 insertions(+), 185 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2083.clarification create mode 100644 changelogs/identity_service/newsfragments/2083.clarification create mode 100644 changelogs/server_server/newsfragments/2083.clarification create mode 100644 data/event-schemas/schema/components/signed_third_party_invite.yaml diff --git a/changelogs/client_server/newsfragments/2083.clarification b/changelogs/client_server/newsfragments/2083.clarification new file mode 100644 index 00000000..cc3dc3c7 --- /dev/null +++ b/changelogs/client_server/newsfragments/2083.clarification @@ -0,0 +1,2 @@ +Clarify the format of third-party invites, including the fact that identity +server public keys can be encoded using standard or URL-safe base64. diff --git a/changelogs/identity_service/newsfragments/2083.clarification b/changelogs/identity_service/newsfragments/2083.clarification new file mode 100644 index 00000000..7e5575c9 --- /dev/null +++ b/changelogs/identity_service/newsfragments/2083.clarification @@ -0,0 +1 @@ +Clarify that public keys can be encoded using standard or URL-safe base64. diff --git a/changelogs/server_server/newsfragments/2083.clarification b/changelogs/server_server/newsfragments/2083.clarification new file mode 100644 index 00000000..cc3dc3c7 --- /dev/null +++ b/changelogs/server_server/newsfragments/2083.clarification @@ -0,0 +1,2 @@ +Clarify the format of third-party invites, including the fact that identity +server public keys can be encoded using standard or URL-safe base64. diff --git a/content/client-server-api/modules/third_party_invites.md b/content/client-server-api/modules/third_party_invites.md index 9ac55f57..2fc8b82e 100644 --- a/content/client-server-api/modules/third_party_invites.md +++ b/content/client-server-api/modules/third_party_invites.md @@ -5,8 +5,8 @@ This module adds in support for inviting new members to a room where their Matrix user ID is not known, instead addressing them by a third-party identifier such as an email address. There are two flows here; one if a Matrix user ID is known for the third-party identifier, and one if -not. Either way, the client calls [`/invite`](#post_matrixclientv3roomsroomidinvite) with the details of the -third-party identifier. +not. Either way, the client calls [`/invite`](#thirdparty_post_matrixclientv3roomsroomidinvite) +with the details of the third-party identifier. The homeserver asks the identity server whether a Matrix user ID is known for that identifier: @@ -37,10 +37,12 @@ A client asks a server to invite a user by their third-party identifier. #### Server behaviour -Upon receipt of an [`/invite`](#post_matrixclientv3roomsroomidinvite), the server is expected to look up the -third-party identifier with the provided identity server. If the lookup -yields a result for a Matrix User ID then the normal invite process can -be initiated. This process ends up looking like this: +Upon receipt of an [`/invite`](#thirdparty_post_matrixclientv3roomsroomidinvite), +the server is expected to look up the third-party identifier with the provided +identity server by making a call to [`/_matrix/identity/v2/lookup`](/identity-service-api/#post_matrixidentityv2lookup). +If the lookup yields a result for a Matrix User ID then the normal [invite +process](/server-server-api/#inviting-to-a-room) can be initiated. This process +ends up looking like this: ``` +---------+ +-------------+ +-----------------+ @@ -66,10 +68,11 @@ be initiated. This process ends up looking like this: | | | ``` -However, if the lookup does not yield a bound User ID, the homeserver -must store the invite on the identity server and emit a valid -`m.room.third_party_invite` event to the room. This process ends up -looking like this: +However, if the lookup does not yield a bound User ID, the homeserver must store +the invite on the identity server with a call to +[`/_matrix/identity/v2/store-invite`](/identity-service-api/#post_matrixidentityv2store-invite) +and emit a valid [`m.room.third_party_invite`](#mroomthird_party_invite) event +to the room. This process ends up looking like this: ``` +---------+ +-------------+ +-----------------+ @@ -101,15 +104,18 @@ looking like this: | | | ``` -All homeservers MUST verify the signature in the event's -`content.third_party_invite.signed` object. +The third-party user will then need to verify their identity, which results in a +request to [`/_matrix/federation/v1/3pid/onbind`](/server-server-api/#put_matrixfederationv13pidonbind) +from the identity server to the homeserver that bound the third-party identifier +to a user. The homeserver then exchanges the `m.room.third_party_invite` event +in the room for a complete [`m.room.member`](#mroommember) event with +`content.membership: invite` and a `content.third_party_invite` property for the +user that has bound the third-party identifier. If the invitee is on a different +homeserver than the inviting user, the invitee's homeserver makes a request to +[`/_matrix/federation/v1/exchange_third_party_invite/{roomId}`](/server-server-api/#put_matrixfederationv1exchange_third_party_inviteroomid). -The third-party user will then need to verify their identity, which -results in a call from the identity server to the homeserver that bound -the third-party identifier to a user. The homeserver then exchanges the -`m.room.third_party_invite` event in the room for a complete -`m.room.member` event for `membership: invite` for the user that has -bound the third-party identifier. +All homeservers MUST verify the signature in the `m.room.member` event's +`content.third_party_invite.signed` object. If a homeserver is joining a room for the first time because of an `m.room.third_party_invite`, the server which is already participating @@ -193,8 +199,8 @@ at any time - the completion is not shown in the diagram. H1 MUST verify the request from H3 to ensure the `signed` property is correct as well as the `key_validity_url` as still being valid. This is -done by making a request to the [identity server -/isvalid](/identity-service-api/#get_matrixidentityv2pubkeyisvalid) +done by making a request to the identity server's +[`/pubkey/isvalid`](/identity-service-api/#get_matrixidentityv2pubkeyisvalid) endpoint, using the provided URL rather than constructing a new one. The query string and response for the provided URL must match the Identity Service Specification. diff --git a/content/server-server-api.md b/content/server-server-api.md index d93aa51f..c82e3bee 100644 --- a/content/server-server-api.md +++ b/content/server-server-api.md @@ -970,9 +970,8 @@ the event to other servers in the room. ## Third-party invites {{% boxes/note %}} -More information about third-party invites is available in the -[Client-Server API](/client-server-api) under -the Third-party Invites module. +More information about third-party invites is available in the Client-Server API +under the [Third-party invites](/client-server-api/#third-party-invites) module. {{% /boxes/note %}} When a user wants to invite another user in a room but doesn't know the @@ -985,38 +984,41 @@ API](/identity-service-api). ### Cases where an association exists for a third-party identifier -If the third-party identifier is already bound to a Matrix ID, a lookup -request on the identity server will return it. The invite is then -processed by the inviting homeserver as a standard `m.room.member` -invite event. This is the simplest case. +If the third-party identifier is already bound to a Matrix ID, a [lookup +request](/identity-service-api/#post_matrixidentityv2lookup) on the identity +server will return it. The invite is then processed by the inviting homeserver +as a [standard `m.room.member` invite event](#inviting-to-a-room). This is the +simplest case. ### Cases where an association doesn't exist for a third-party identifier If the third-party identifier isn't bound to any Matrix ID, the inviting -homeserver will request the identity server to store an invite for this -identifier and to deliver it to whoever binds it to its Matrix ID. It -will also send an `m.room.third_party_invite` event in the room to -specify a display name, a token and public keys the identity server -provided as a response to the invite storage request. +homeserver will request the identity server to [store an invite](/identity-service-api/#invitation-storage) +for this identifier and to deliver it to whoever binds it to its Matrix ID. It +will also send an [`m.room.third_party_invite`](/client-server-api/#mroomthird_party_invite) +event in the room to specify a display name, a token and public keys the +identity server provided as a response to the invite storage request. -When a third-party identifier with pending invites gets bound to a -Matrix ID, the identity server will send a POST request to the ID's -homeserver as described in the [Invitation -Storage](/identity-service-api#invitation-storage) -section of the Identity Service API. +When a third-party identifier with pending invites gets bound to a Matrix ID, +the identity server will send a request to the [`/3pid/onbind`](#put_matrixfederationv13pidonbind) +endpoint of the the ID's homeserver as described in the [Invitation +Storage](/identity-service-api#invitation-storage) section of the Identity +Service API. The following process applies for each invite sent by the identity server: -The invited homeserver will create an `m.room.member` invite event -containing a special `third_party_invite` section containing the token -and a signed object, both provided by the identity server. +The invited homeserver will create an [`m.room.member`](/client-server-api/#mroommember) +invite event containing a special `third_party_invite` section containing the +token and a `signed` object, both provided by the identity server. If the invited homeserver is in the room the invite came from, it can auth the event and send it. However, if the invited homeserver isn't in the room the invite came -from, it will need to request the room's homeserver to auth the event. +from, it will need to request the inviting homeserver to auth the event +at the [`/exchange_third_party_invite`](#put_matrixfederationv1exchange_third_party_inviteroomid) +endpoint. {{% http-api spec="server-server" api="third_party_invite" %}} diff --git a/data/api/client-server/third_party_membership.yaml b/data/api/client-server/third_party_membership.yaml index 65148ee0..67caa387 100644 --- a/data/api/client-server/third_party_membership.yaml +++ b/data/api/client-server/third_party_membership.yaml @@ -57,9 +57,6 @@ paths: - A signature of the token, signed with the identity server's private key - The matrix user ID who invited them to the room - - If a token is requested from the identity server, the homeserver will - append a `m.room.third_party_invite` event to the room. operationId: inviteBy3PID security: - accessTokenQuery: [] @@ -72,6 +69,8 @@ paths: example: "!d41d8cd:matrix.org" schema: type: string + format: mx-room-id + pattern: "^!" requestBody: content: application/json: @@ -90,7 +89,9 @@ paths: value: {} "403": description: |- - You do not have permission to invite the user to the room. A meaningful `errcode` and description error text will be returned. Example reasons for rejections are: + You do not have permission to invite the user to the room. A + meaningful `errcode` and description error text will be returned. + Example reasons for rejections are: - The invitee has been banned from the room. - The invitee is already a member of the room. diff --git a/data/api/identity/v2_pubkey.yaml b/data/api/identity/v2_pubkey.yaml index 2aaf5f8e..68e383a8 100644 --- a/data/api/identity/v2_pubkey.yaml +++ b/data/api/identity/v2_pubkey.yaml @@ -43,7 +43,8 @@ paths: properties: public_key: type: string - description: Unpadded Base64 encoded public key. + description: |- + [Unpadded Base64](/appendices/#unpadded-base64)-encoded public key. required: - public_key examples: @@ -74,7 +75,8 @@ paths: - in: query name: public_key required: true - description: The unpadded base64-encoded public key to check. + description: |- + The [unpadded Base64](/appendices/#unpadded-base64)-encoded public key to check. example: VXuGitF39UH5iRfvbIknlvlAVKgD1BsLDMvBf0pmp7c schema: type: string @@ -105,7 +107,14 @@ paths: - in: query name: public_key required: true - description: The unpadded base64-encoded public key to check. + description: |- + The [unpadded Base64](/appendices/#unpadded-base64)-encoded public + key to check. + + This MUST be the exact same encoded string returned in the response + of the [`/store-invite`](/identity-service-api/#post_matrixidentityv2store-invite) + endpoint, or found in the corresponding [`m.room.third_party_invite`](/client-server-api/#mroomthird_party_invite) + event, so it may use the standard or URL-safe alphabets. example: VXuGitF39UH5iRfvbIknlvlAVKgD1BsLDMvBf0pmp7c schema: type: string diff --git a/data/api/identity/v2_store_invite.yaml b/data/api/identity/v2_store_invite.yaml index 5dcd9a78..98e7e7f4 100644 --- a/data/api/identity/v2_store_invite.yaml +++ b/data/api/identity/v2_store_invite.yaml @@ -42,7 +42,7 @@ paths: (if present) from the request here. Also, the generated ephemeral public key will be listed as valid on - requests to `/_matrix/identity/v2/pubkey/ephemeral/isvalid`. + requests to [`/_matrix/identity/v2/pubkey/ephemeral/isvalid`](/identity-service-api/#get_matrixidentityv2pubkeyephemeralisvalid). Currently, invites may only be issued for 3pids of the `email` medium. @@ -70,10 +70,14 @@ paths: room_id: type: string description: The Matrix room ID to which the user is invited + format: mx-room-id + pattern: "^!" example: "!something:example.org" sender: type: string description: The Matrix user ID of the inviting user + format: mx-user-id + pattern: "^@" example: "@bob:example.com" room_alias: type: string @@ -81,12 +85,16 @@ paths: The Matrix room alias for the room to which the user is invited. This should be retrieved from the `m.room.canonical_alias` state event. + format: mx-room-alias + pattern: "^#" example: "#somewhere:example.org" room_avatar_url: type: string description: |- The Content URI for the room to which the user is invited. This should be retrieved from the `m.room.avatar` state event. + format: mx-mxc-uri + pattern: "^mxc:\\/\\/" example: mxc://example.org/s0meM3dia room_join_rules: type: string @@ -108,6 +116,8 @@ paths: type: string description: The Content URI for the avatar of the user ID initiating the invite. + format: mx-mxc-uri + pattern: "^mxc:\\/\\/" example: mxc://example.org/an0th3rM3dia room_type: type: string @@ -146,7 +156,7 @@ paths: public_key: type: string description: | - The public key, encoded using [unpadded Base64](/appendices/#unpadded-base64). + The public key, encoded using standard or URL-safe [unpadded Base64](/appendices/#unpadded-base64). key_validity_url: type: string description: | diff --git a/data/api/server-server/third_party_invite.yaml b/data/api/server-server/third_party_invite.yaml index 76a7d2ff..019aa2d4 100644 --- a/data/api/server-server/third_party_invite.yaml +++ b/data/api/server-server/third_party_invite.yaml @@ -35,6 +35,8 @@ paths: example: "!abc123:matrix.org" schema: type: string + format: mx-room-id + pattern: "^!" requestBody: content: application/json: @@ -50,16 +52,22 @@ paths: description: |- The room ID the event is for. Must match the ID given in the path. + format: mx-room-id + pattern: "^!" example: "!abc123:matrix.org" sender: type: string description: |- The user ID of the user who sent the original `m.room.third_party_invite` event. + format: mx-user-id + pattern: "^@" example: "@joe:matrix.org" state_key: type: string description: The user ID of the invited user + format: mx-user-id + pattern: "^@" example: "@someone:example.org" content: type: object @@ -82,45 +90,7 @@ paths: third-party identifier. example: alice signed: - type: object - description: |- - A block of content which has been signed, which servers can use to - verify the event. - title: Invite Signatures - properties: - signatures: - type: object - title: Signatures - additionalProperties: - type: object - additionalProperties: - type: string - description: |- - The server signatures for this event. - - The signature is calculated using the process - described at [Signing JSON](/appendices/#signing-json). - example: - magic.forest: - ed25519:3: fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg - mxid: - type: string - description: The invited matrix user ID - example: "@alice:localhost" - token: - type: string - description: The token used to verify the event - example: abc123 - required: - - signatures - - mxid - - token - example: - mxid: "@alice:localhost" - token: abc123 - signatures: - magic.forest: - ed25519:3: fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg + $ref: ../../event-schemas/schema/components/signed_third_party_invite.yaml required: - display_name - signed @@ -215,6 +185,8 @@ paths: mxid: type: string description: The user that is now bound to the third-party identifier. + format: mx-user-id + pattern: "^@" example: "@alice:matrix.org" invites: type: array @@ -237,59 +209,23 @@ paths: mxid: type: string description: The now-bound user ID that received the invite. + format: mx-user-id + pattern: "^@" example: "@alice:matrix.org" room_id: type: string description: The room ID the invite is valid for. + format: mx-room-id + pattern: "^!" example: "!somewhere:example.org" sender: type: string description: The user ID that sent the invite. + format: mx-user-id + pattern: "^@" example: "@bob:matrix.org" - # TODO (TravisR): Make this reusable when doing IS spec changes - # also make sure it isn't lying about anything, like the key version signed: - type: object - title: Identity Server Signatures - description: |- - Signature from the identity server using a long-term private - key. - properties: - mxid: - type: string - description: |- - The user ID that has been bound to the third-party - identifier. - example: "@alice:matrix.org" - token: - type: string - # TODO: What is this actually? - description: A token. - example: Hello World - signatures: - type: object - title: Identity Server Signature - description: |- - The signature from the identity server. The `string` key - is the identity server's domain name, such as vector.im - additionalProperties: - type: object - title: Identity Server Domain Signature - description: The signature for the identity server. - properties: - ed25519:0: - type: string - description: The signature. - example: SomeSignatureGoesHere - required: - - ed25519:0 - example: - vector.im: - ed25519:0: SomeSignatureGoesHere - required: - - mxid - - token - - signatures + $ref: ../../event-schemas/schema/components/signed_third_party_invite.yaml required: - medium - address diff --git a/data/event-schemas/schema/components/signed_third_party_invite.yaml b/data/event-schemas/schema/components/signed_third_party_invite.yaml new file mode 100644 index 00000000..b231c978 --- /dev/null +++ b/data/event-schemas/schema/components/signed_third_party_invite.yaml @@ -0,0 +1,45 @@ +title: SignedThirdPartyInvite +description: |- + A block of content which has been signed by the identity server, which + homeservers can use to verify the event. Clients should ignore this. +type: object +properties: + mxid: + description: |- + The user ID that has been bound to the third-party identifier. + type: string + format: mx-user-id + pattern: "^@" + example: "@alice:example.org" + signatures: + title: IdentityServerSignatures + description: |- + The identity server signatures for this block. This is a map of identity + server name to signing key identifier to base64-encoded signature. + + The signatures are calculated using the process described at + [Signing JSON](/appendices/#signing-json). + type: object + additionalProperties: + type: object + additionalProperties: + type: string + example: { + "magic.forest": { + "ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg" + } + } + token: + description: |- + The token generated by the identity server at the + [`/store_invite`](/identity-service-api/#post_matrixidentityv2store-invite) + endpoint. + + It matches the `state_key` of the corresponding [`m.room.third_party_invite`](/client-server-api/#mroomthird_party_invite) + event. + type: string + example: "abc123" +required: + - mxid + - signatures + - token diff --git a/data/event-schemas/schema/m.room.member.yaml b/data/event-schemas/schema/m.room.member.yaml index 8d212687..436c0145 100644 --- a/data/event-schemas/schema/m.room.member.yaml +++ b/data/event-schemas/schema/m.room.member.yaml @@ -2,17 +2,27 @@ allOf: - $ref: core-event-schema/state_event.yaml description: |- - Adjusts the membership state for a user in a room. It is preferable to use the membership APIs (`/rooms//invite` etc) when performing membership actions rather than adjusting the state directly as there are a restricted set of valid transformations. For example, user A cannot force user B to join a room, and trying to force this state change directly will fail. + Adjusts the membership state for a user in a room. It is preferable to use the membership APIs + (`/rooms//invite` etc) when performing membership actions rather than adjusting the + state directly as there are a restricted set of valid transformations. For example, user A cannot + force user B to join a room, and trying to force this state change directly will fail. The following membership states are specified: - - `invite` - The user has been invited to join a room, but has not yet joined it. They may not participate in the room until they join. - - `join` - The user has joined the room (possibly after accepting an invite), and may participate in it. - - `leave` - The user was once joined to the room, but has since left (possibly by choice, or possibly by being kicked). - - `ban` - The user has been banned from the room, and is no longer allowed to join it until they are un-banned from the room (by having their membership state set to a value other than `ban`). - - `knock` - The user has knocked on the room, requesting permission to participate. They may not participate in the room until they join. + - `invite` - The user has been invited to join a room, but has not yet joined it. They may not + participate in the room until they join. + - `join` - The user has joined the room (possibly after accepting an invite), and may participate + in it. + - `leave` - The user was once joined to the room, but has since left (possibly by choice, or + possibly by being kicked). + - `ban` - The user has been banned from the room, and is no longer allowed to join it until they + are un-banned from the room (by having their membership state set to a value other than `ban`). + - `knock` - The user has knocked on the room, requesting permission to participate. They may not + participate in the room until they join. - The `third_party_invite` property will be set if this invite is an `invite` event and is the successor of an `m.room.third_party_invite` event, and absent otherwise. + The `third_party_invite` property will be set if this invite is an `invite` event and is the + successor of an [`m.room.third_party_invite`](/client-server-api/#mroomthird_party_invite) event, + and absent otherwise. This event may also include an `invite_room_state` key inside the event's `unsigned` data. If present, this contains an array of [stripped state events](/client-server-api/#stripped-state) @@ -57,63 +67,54 @@ properties: - ban type: string is_direct: - description: Flag indicating if the room containing this event was created with the intention of being a direct chat. See [Direct Messaging](/client-server-api/#direct-messaging). + description: |- + Flag indicating if the room containing this event was created with the intention of being + a direct chat. See [Direct Messaging](/client-server-api/#direct-messaging). type: boolean join_authorised_via_users_server: x-addedInMatrixVersion: "1.2" type: string description: |- - Usually found on `join` events, this field is used to denote which homeserver (through representation of a user with sufficient power level) - authorised the user's join. More information about this field can be found in the [Restricted Rooms Specification](/client-server-api/#restricted-rooms). + Usually found on `join` events, this field is used to denote which homeserver (through + representation of a user with sufficient power level) authorised the user's join. More + information about this field can be found in the [Restricted Rooms Specification](/client-server-api/#restricted-rooms). - Client and server implementations should be aware of the [signing implications](/rooms/v8/#authorization-rules) of including this - field in further events: in particular, the event must be signed by the server which - owns the user ID in the field. When copying the membership event's `content` - (for profile updates and similar) it is therefore encouraged to exclude this - field in the copy, as otherwise the event might fail event authorization. + Client and server implementations should be aware of the [signing implications](/rooms/v8/#authorization-rules) + of including this field in further events: in particular, the event must be signed by the + server which owns the user ID in the field. When copying the membership event's `content` + (for profile updates and similar) it is therefore encouraged to exclude this field in the + copy, as otherwise the event might fail event authorization. reason: x-addedInMatrixVersion: "1.1" type: string description: |- - Optional user-supplied text for why their membership has changed. For kicks and bans, this is typically the reason for the kick or ban. - For other membership changes, this is a way for the user to communicate their intent without having to send a message to the room, such - as in a case where Bob rejects an invite from Alice about an upcoming concert, but can't make it that day. + Optional user-supplied text for why their membership has changed. For kicks and bans, + this is typically the reason for the kick or ban. For other membership changes, this is a + way for the user to communicate their intent without having to send a message to the + room, such as in a case where Bob rejects an invite from Alice about an upcoming concert, + but can't make it that day. - Clients are not recommended to show this reason to users when receiving an invite due to the potential for spam and abuse. Hiding the - reason behind a button or other component is recommended. + Clients are not recommended to show this reason to users when receiving an invite due to + the potential for spam and abuse. Hiding the reason behind a button or other component is + recommended. third_party_invite: + title: ThirdPartyInvite + description: |- + A third-party invite, if this `m.room.member` is the successor to an + [`m.room.third_party_invite`](/client-server-api/#mroomthird_party_invite) + event. + type: object properties: display_name: - description: A name which can be displayed to represent the user instead of their third-party identifier + description: |- + A name which can be displayed to represent the user instead of their + third-party identifier type: string signed: - description: 'A block of content which has been signed, which servers can use to verify the event. Clients should ignore this.' - properties: - mxid: - description: The invited matrix user ID. Must be equal to the user_id property of the event. - type: string - signatures: - description: 'A single signature from the verifying server, in the format specified by the Signing Events section of the server-server API.' - title: Signatures - type: object - additionalProperties: - type: object - additionalProperties: - type: string - token: - description: The token property of the containing third_party_invite object. - type: string - required: - - mxid - - signatures - - token - title: signed - type: object + $ref: components/signed_third_party_invite.yaml required: - display_name - signed - title: Invite - type: object required: - membership title: EventContent diff --git a/data/event-schemas/schema/m.room.third_party_invite.yaml b/data/event-schemas/schema/m.room.third_party_invite.yaml index bb4883f5..704669d2 100644 --- a/data/event-schemas/schema/m.room.third_party_invite.yaml +++ b/data/event-schemas/schema/m.room.third_party_invite.yaml @@ -1,28 +1,56 @@ --- allOf: - $ref: core-event-schema/state_event.yaml -description: "Acts as an `m.room.member` invite event, where there isn't a target user_id to invite. This event contains a token and a public key whose private key must be used to sign the token. Any user who can present that signature may use this invitation to join the target room." +description: |- + Acts as an `m.room.member` invite event, where there isn't a target user_id to + invite. This event contains a token and a public key whose private key must be + used to sign the token. Any user who can present that signature may use this + invitation to join the target room. properties: content: properties: display_name: - description: "A user-readable string which represents the user who has been invited. This should not contain the user's third-party ID, as otherwise when the invite is accepted it would leak the association between the matrix ID and the third-party ID." + description: |- + A user-readable string which represents the user who has been invited. + This should not contain the user's third-party ID, as otherwise when + the invite is accepted it would leak the association between the + matrix ID and the third-party ID. type: string key_validity_url: - description: "A URL which can be fetched, with querystring public_key=public_key, to validate whether the key has been revoked. The URL must return a JSON object containing a boolean property named 'valid'." + description: |- + A URL which can be fetched, with querystring public_key=public_key, to + validate whether the key has been revoked. The URL must return a JSON + object containing a boolean property named 'valid'. type: string + format: uri public_key: - description: A base64-encoded ed25519 key with which token must be signed (though a signature from any entry in public_keys is also sufficient). This exists for backwards compatibility. + description: |- + An Ed25519 key with which the token must be signed (though a signature + from any entry in `public_keys` is also sufficient). + + The key is encoded using [Unpadded Base64](/appendices/#unpadded-base64), + using the standard or URL-safe alphabets. + + This exists for backwards compatibility. type: string public_keys: description: Keys with which the token may be signed. items: properties: key_validity_url: - description: "An optional URL which can be fetched, with querystring public_key=public_key, to validate whether the key has been revoked. The URL must return a JSON object containing a boolean property named 'valid'. If this URL is absent, the key must be considered valid indefinitely." + description: |- + An optional URL which can be fetched, with querystring + `public_key=`, to validate whether the key has been + revoked. The URL must return a JSON object containing a boolean + property named `valid`. If this URL is absent, the key must be + considered valid indefinitely. type: string public_key: - description: A base-64 encoded ed25519 key with which token may be signed. + description: |- + An Ed25519 key with which the token may be signed. + + The key is encoded using [Unpadded Base64](/appendices/#unpadded-base64), + using the standard or URL-safe alphabets. type: string required: - public_key @@ -35,11 +63,15 @@ properties: - public_key type: object state_key: - description: 'The token, of which a signature must be produced in order to join the room.' + description: |- + The token, of which a signature must be produced in order to join the + room. type: string type: enum: - m.room.third_party_invite type: string -title: 'An invitation to a room issued to a third-party identifier, rather than a matrix user ID.' +title: |- + An invitation to a room issued to a third-party identifier, rather than a + matrix user ID. type: object diff --git a/data/string-formats.yaml b/data/string-formats.yaml index 352d21fc..fca325b9 100644 --- a/data/string-formats.yaml +++ b/data/string-formats.yaml @@ -51,6 +51,11 @@ mx-room-id: url: appendices#room-ids # regex: "^!" +mx-room-alias: + title: Room Alias + url: appendices#room-aliases + # regex: "^#" + mx-server-name: title: Server Name url: appendices#server-name From a8c326962a773f5234a08f755512d7cbae40ca30 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Thu, 8 May 2025 10:09:45 +0100 Subject: [PATCH 08/19] Add a note to the federation invite endpoints that invites can be sent twice (#2067) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... as this may be non-obvious when implementing behaviour that is triggered by an incoming invite event. See https://github.com/matrix-org/matrix-spec/issues/2062 for more context. Co-authored-by: Kévin Commaille <76261501+zecakeh@users.noreply.github.com> --- changelogs/server_server/newsfragments/2067.clarification | 1 + data/api/server-server/invites-v1.yaml | 6 +++++- data/api/server-server/invites-v2.yaml | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 changelogs/server_server/newsfragments/2067.clarification diff --git a/changelogs/server_server/newsfragments/2067.clarification b/changelogs/server_server/newsfragments/2067.clarification new file mode 100644 index 00000000..4bd8176b --- /dev/null +++ b/changelogs/server_server/newsfragments/2067.clarification @@ -0,0 +1 @@ +Add a note to the invite endpoints that invites to local users may be received twice over federation if the homeserver is already in the room. \ No newline at end of file diff --git a/data/api/server-server/invites-v1.yaml b/data/api/server-server/invites-v1.yaml index 7d241c37..b1771018 100644 --- a/data/api/server-server/invites-v1.yaml +++ b/data/api/server-server/invites-v1.yaml @@ -20,7 +20,7 @@ paths: put: summary: Invites a remote user to a room description: |- - Invites a remote user to a room. Once the event has been signed by both the inviting + Invites a remote user to a room. Once the event has been signed by both the inviting homeserver and the invited homeserver, it can be sent to all of the servers in the room by the inviting homeserver. @@ -32,6 +32,10 @@ paths: [room version specification](/rooms) for precise event formats. **The request and response bodies here describe the common event fields in more detail and may be missing other required fields for a PDU.** + + Also note that if the remote homeserver is already in the room, it will receive the + invite event twice; once through this endpoint, and again through a [federation + transaction](/server-server-api/#transactions). operationId: sendInviteV1 security: - signedRequest: [] diff --git a/data/api/server-server/invites-v2.yaml b/data/api/server-server/invites-v2.yaml index f42c8eea..6ac8bb3e 100644 --- a/data/api/server-server/invites-v2.yaml +++ b/data/api/server-server/invites-v2.yaml @@ -24,7 +24,7 @@ paths: This API is nearly identical to the v1 API with the exception of the request body being different, and the response format fixed. - Invites a remote user to a room. Once the event has been signed by both the inviting + Invites a remote user to a room. Once the event has been signed by both the inviting homeserver and the invited homeserver, it can be sent to all of the servers in the room by the inviting homeserver. @@ -36,6 +36,10 @@ paths: [room version specification](/rooms) for precise event formats. **The request and response bodies here describe the common event fields in more detail and may be missing other required fields for a PDU.** + + Also note that if the remote homeserver is already in the room, it will receive the + invite event twice; once through this endpoint, and again through a [federation + transaction](/server-server-api/#transactions). operationId: sendInviteV2 security: - signedRequest: [] From fe46e0c363cc285125f9a83be29f96aeb4945dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Thu, 8 May 2025 11:29:32 +0200 Subject: [PATCH 09/19] Replace Hugo shortcodes in OpenAPI output (#2088) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- .github/workflows/main.yml | 11 +- .../internal/newsfragments/2088.clarification | 1 + scripts/dump-openapi.py | 112 +++++++++++++++++- 3 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 changelogs/internal/newsfragments/2088.clarification diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 25a2fb68..daa8fb67 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,6 +2,7 @@ name: "Spec" env: HUGO_VERSION: 0.139.0 + PYTHON_VERSION: 3.13 on: push: @@ -40,7 +41,7 @@ jobs: - name: "➕ Setup Python" uses: actions/setup-python@v5 with: - python-version: '3.9' + python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' cache-dependency-path: scripts/requirements.txt - name: "➕ Install dependencies" @@ -59,7 +60,7 @@ jobs: - name: "➕ Setup Python" uses: actions/setup-python@v5 with: - python-version: '3.9' + python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' cache-dependency-path: scripts/requirements.txt - name: "➕ Install dependencies" @@ -78,7 +79,7 @@ jobs: - name: "➕ Setup Python" uses: actions/setup-python@v5 with: - python-version: '3.9' + python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' cache-dependency-path: scripts/requirements.txt - name: "➕ Install dependencies" @@ -120,7 +121,7 @@ jobs: - name: "➕ Setup Python" uses: actions/setup-python@v5 with: - python-version: '3.9' + python-version: ${{ env.PYTHON_VERSION }} cache: 'pip' cache-dependency-path: scripts/requirements.txt - name: "➕ Install dependencies" @@ -172,7 +173,7 @@ jobs: - name: "➕ Setup Python" uses: actions/setup-python@v5 with: - python-version: '3.9' + python-version: ${{ env.PYTHON_VERSION }} - name: "➕ Install towncrier" run: "pip install 'towncrier'" - name: "Generate changelog" diff --git a/changelogs/internal/newsfragments/2088.clarification b/changelogs/internal/newsfragments/2088.clarification new file mode 100644 index 00000000..a0e53726 --- /dev/null +++ b/changelogs/internal/newsfragments/2088.clarification @@ -0,0 +1 @@ +Replace Hugo shortcodes in OpenAPI output. diff --git a/scripts/dump-openapi.py b/scripts/dump-openapi.py index 490ac9bf..49ad9147 100755 --- a/scripts/dump-openapi.py +++ b/scripts/dump-openapi.py @@ -32,6 +32,35 @@ import yaml scripts_dir = os.path.dirname(os.path.abspath(__file__)) api_dir = os.path.join(os.path.dirname(scripts_dir), "data", "api") +# Finds a Hugo shortcode in a string. +# +# A shortcode is defined as (newlines and whitespaces for presentation purpose): +# +# {{% +# +# +# (optional ) +# +# %}} +# +# With: +# +# * : any word character and `-` and `/`. `re.ASCII` is used to only match +# ASCII characters in the name. +# * : any character except `}`, must not start or end with a +# whitespace. +shortcode_regex = re.compile(r"""\{\{\% # {{% + \s* # zero or more whitespaces + (?P[\w/-]+) # name of shortcode + (?:\s+(?P[^\s\}][^\}]+[^\s\}]))? # optional list of parameters + \s* # zero or more whitespaces + \%\}\} # %}}""", re.ASCII | re.VERBOSE) + +# Parses the parameters of a Hugo shortcode. +# +# For simplicity, this currently only supports the `key="value"` format. +shortcode_params_regex = re.compile(r"(?P\w+)=\"(?P[^\"]+)\"", re.ASCII) + def prefix_absolute_path_references(text, base_url): """Adds base_url to absolute-path references. @@ -44,17 +73,90 @@ def prefix_absolute_path_references(text, base_url): """ return text.replace("](/", "]({}/".format(base_url)) -def edit_links(node, base_url): - """Finds description nodes and makes any links in them absolute.""" +def replace_match(match, replacement): + """Replaces the regex match by the replacement in the text.""" + return match.string[:match.start()] + replacement + match.string[match.end():] + +def replace_shortcode(shortcode): + """Replaces the shortcode by a Markdown fallback in the text. + + The supported shortcodes are: + + * boxes/note, boxes/rationale, boxes/warning + * added-in, changed-in + + All closing tags (`{{ /shortcode }}`) are replaced with the empty string. + """ + + if shortcode['name'].startswith("/"): + # This is the end of the shortcode, just remove it. + return replace_match(shortcode, "") + + # Parse the parameters of the shortcode + params = {} + if shortcode['params']: + for param in shortcode_params_regex.finditer(shortcode['params']): + if param['key']: + params[param['key']] = param['value'] + + match shortcode['name']: + case "boxes/note": + return replace_match(shortcode, "**NOTE:** ") + case "boxes/rationale": + return replace_match(shortcode, "**RATIONALE:** ") + case "boxes/warning": + return replace_match(shortcode, "**WARNING:** ") + case "added-in": + version = params['v'] + if not version: + raise ValueError("Missing parameter `v` for `added-in` shortcode") + + return replace_match(shortcode, f"**[Added in `v{version}`]** ") + case "changed-in": + version = params['v'] + if not version: + raise ValueError("Missing parameter `v` for `changed-in` shortcode") + + return replace_match(shortcode, f"**[Changed in `v{version}`]** ") + case _: + raise ValueError("Unknown shortcode", shortcode['name']) + + +def find_and_replace_shortcodes(text): + """Finds Hugo shortcodes and replaces them by a Markdown fallback. + + The supported shortcodes are: + + * boxes/note, boxes/rationale, boxes/warning + * added-in, changed-in + """ + # We use a `while` loop with `search` instead of a `for` loop with + # `finditer`, because as soon as we start replacing text, the + # indices of the match are invalid. + while shortcode := shortcode_regex.search(text): + text = replace_shortcode(shortcode) + + return text + +def edit_descriptions(node, base_url): + """Finds description nodes and apply fixes to them. + + The fixes that are applied are: + + * Make links absolute + * Replace Hugo shortcodes + """ if isinstance(node, dict): for key in node: if isinstance(node[key], str): node[key] = prefix_absolute_path_references(node[key], base_url) + node[key] = find_and_replace_shortcodes(node[key]) else: - edit_links(node[key], base_url) + edit_descriptions(node[key], base_url) elif isinstance(node, list): for item in node: - edit_links(item, base_url) + edit_descriptions(item, base_url) + parser = argparse.ArgumentParser( "dump-openapi.py - assemble the OpenAPI specs into a single JSON file" @@ -164,7 +266,7 @@ for filename in os.listdir(selected_api_dir): if untagged != 0: print("{} untagged operations, you may want to look into fixing that.".format(untagged)) -edit_links(output, base_url) +edit_descriptions(output, base_url) print("Generating %s" % output_file) From ca9c376076b1e142c94277c741984f70283c24a1 Mon Sep 17 00:00:00 2001 From: Kim Brose <2803622+HarHarLinks@users.noreply.github.com> Date: Thu, 8 May 2025 11:55:51 +0000 Subject: [PATCH 10/19] Clarify Well-Known URIs (#2140) * Clarify Well-Known URIs Signed-off-by: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> * Fix section link --------- Signed-off-by: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> --- .../newsfragments/2140.clarification | 1 + .../newsfragments/2140.clarification | 1 + content/client-server-api/_index.md | 25 +++++++++++++++---- content/server-server-api.md | 3 ++- data/api/client-server/support.yaml | 7 ++++-- data/api/client-server/wellknown.yaml | 6 +++++ data/api/server-server/wellknown.yaml | 6 +++++ 7 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2140.clarification create mode 100644 changelogs/server_server/newsfragments/2140.clarification diff --git a/changelogs/client_server/newsfragments/2140.clarification b/changelogs/client_server/newsfragments/2140.clarification new file mode 100644 index 00000000..4a151fe8 --- /dev/null +++ b/changelogs/client_server/newsfragments/2140.clarification @@ -0,0 +1 @@ +Clarify that Well-Known URIs are available on the server name's hostname. Contributed by @HarHarLinks. diff --git a/changelogs/server_server/newsfragments/2140.clarification b/changelogs/server_server/newsfragments/2140.clarification new file mode 100644 index 00000000..4a151fe8 --- /dev/null +++ b/changelogs/server_server/newsfragments/2140.clarification @@ -0,0 +1 @@ +Clarify that Well-Known URIs are available on the server name's hostname. Contributed by @HarHarLinks. diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 94dfe35f..f2de85de 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -371,15 +371,23 @@ valid data was obtained, but no server is available to serve the client. No further guess should be attempted and the user should make a conscientious decision what to do next. -### Well-known URI +### Well-known URIs + +Matrix facilitates automatic discovery for the Client-Server API base URL and more via the +[RFC 8615](https://datatracker.ietf.org/doc/html/rfc8615) "Well-Known URI" method. +This method uses JSON files at a predetermined location on the root path `/.well-known/` to +specify parameter values. {{% boxes/note %}} +Diverging from the rest of the endpoints in the Client-Server spec, these files can not be provided +on the base URL that the Client-Server API is reachable on, as it is yet to be discovered. +Instead, they can be reached via HTTPS on the [server name](/appendices/#server-name)'s hostname as domain. + Servers hosting the `.well-known` JSON file SHOULD offer CORS headers, as per the [CORS](#web-browser-clients) section in this specification. {{% /boxes/note %}} -The `.well-known` method uses a JSON file at a predetermined location to -specify parameter values. The flow for this method is as follows: +The flow for auto-discovery is as follows: 1. Extract the [server name](/appendices/#server-name) from the user's Matrix ID by splitting the Matrix ID at the first colon. @@ -415,10 +423,17 @@ specify parameter values. The flow for this method is as follows: {{% http-api spec="client-server" api="wellknown" %}} -{{% http-api spec="client-server" api="versions" %}} - {{% http-api spec="client-server" api="support" %}} +### API Versions + +Upon connecting, the Matrix client and server need to negotiate which version of the specification +they commonly support, as the API evolves over time. The server advertises its supported versions +and optionally unstable features to the client, which can then go on to make requests to the +endpoints it supports. + +{{% http-api spec="client-server" api="versions" %}} + ## Client Authentication Most API endpoints require the user to identify themselves by presenting diff --git a/content/server-server-api.md b/content/server-server-api.md index c82e3bee..10d91468 100644 --- a/content/server-server-api.md +++ b/content/server-server-api.md @@ -119,7 +119,8 @@ to send. The process overall is as follows: server must present a valid certificate for the hostname. 3. If the hostname is not an IP literal, a regular HTTPS request is - made to `https:///.well-known/matrix/server`, expecting + made to `https:///.well-known/matrix/server` (according to + [RFC 8615](https://datatracker.ietf.org/doc/html/rfc8615)), expecting the schema defined later in this section. 30x redirects should be followed, however redirection loops should be avoided. Responses (successful or otherwise) to the `/.well-known` endpoint should be diff --git a/data/api/client-server/support.yaml b/data/api/client-server/support.yaml index b9ca062e..154afbe7 100644 --- a/data/api/client-server/support.yaml +++ b/data/api/client-server/support.yaml @@ -22,9 +22,12 @@ paths: description: |- Gets server admin contact and support page of the domain. - Like the [well-known discovery URI](/client-server-api/#well-known-uri), - this should be accessed with the hostname of the homeserver by making a + {{% boxes/note %}} + Like the [well-known discovery URI](/client-server-api/#well-known-uris), + this endpoint should be accessed with the hostname of the homeserver's + [server name](/appendices/#server-name) by making a GET request to `https://hostname/.well-known/matrix/support`. + {{% /boxes/note %}} Note that this endpoint is not necessarily handled by the homeserver. It may be served by another webserver, used for discovering support diff --git a/data/api/client-server/wellknown.yaml b/data/api/client-server/wellknown.yaml index 72de3598..4e2383bf 100644 --- a/data/api/client-server/wellknown.yaml +++ b/data/api/client-server/wellknown.yaml @@ -26,6 +26,12 @@ paths: suitably namespaced for each application and reduces the risk of clashes. + {{% boxes/note %}} + This endpoint should be accessed with the hostname of the homeserver's + [server name](/appendices/#server-name) by making a + GET request to `https://hostname/.well-known/matrix/client`. + {{% /boxes/note %}} + Note that this endpoint is not necessarily handled by the homeserver, but by another webserver, to be used for discovering the homeserver URL. operationId: getWellknown diff --git a/data/api/server-server/wellknown.yaml b/data/api/server-server/wellknown.yaml index 717462f9..920bc356 100644 --- a/data/api/server-server/wellknown.yaml +++ b/data/api/server-server/wellknown.yaml @@ -24,6 +24,12 @@ paths: Gets information about the delegated server for server-server communication between Matrix homeservers. Servers should follow 30x redirects, carefully avoiding redirect loops, and use normal X.509 certificate validation. + + {{% boxes/note %}} + This endpoint should be accessed with the hostname of the homeserver's + [server name](/appendices/#server-name) by making a + GET request to `https://hostname/.well-known/matrix/server`. + {{% /boxes/note %}} operationId: getWellKnown responses: "200": From c74befd111aeb245c72cc98f854d04cd58aa1ab9 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 13 May 2025 15:34:39 +0200 Subject: [PATCH 11/19] Clarify the meaning of "public rooms" for profile look-ups (#2101) --- .../client_server/newsfragments/2101.clarification | 1 + content/client-server-api/_index.md | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2101.clarification diff --git a/changelogs/client_server/newsfragments/2101.clarification b/changelogs/client_server/newsfragments/2101.clarification new file mode 100644 index 00000000..fa84c41c --- /dev/null +++ b/changelogs/client_server/newsfragments/2101.clarification @@ -0,0 +1 @@ +"Public" rooms in profile look-ups are defined through their join rule and history visibility. diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index f2de85de..0b2a8346 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -2862,10 +2862,15 @@ re-invited. #### Server behaviour -Homeservers MUST at a minimum allow profile look-up for: +Homeservers MUST at a minimum allow profile look-up for users who are +visible to the requester based on their membership in rooms known to the +homeserver. This means: - users that share a room with the requesting user -- users that reside in public rooms known to the homeserver +- users who are joined to rooms known to the homeserver that have a + `public` [join rule](#mroomjoin_rules) +- users who are joined to rooms known to the homeserver that have a + `world_readable` [history visibility](#room-history-visibility) In all other cases, homeservers MAY deny profile look-up by responding with 403 and an error code of `M_FORBIDDEN`. From fc811710816e855ac3d996f42841de57008929b2 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 13 May 2025 15:37:31 +0200 Subject: [PATCH 12/19] Clarify the meaning of "public rooms" for user directory queries (#2102) --- .../newsfragments/2102.clarification | 1 + data/api/client-server/users.yaml | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2102.clarification diff --git a/changelogs/client_server/newsfragments/2102.clarification b/changelogs/client_server/newsfragments/2102.clarification new file mode 100644 index 00000000..df9eab58 --- /dev/null +++ b/changelogs/client_server/newsfragments/2102.clarification @@ -0,0 +1 @@ +"Public" rooms in user directory queries are defined through their join rule and history visibility. diff --git a/data/api/client-server/users.yaml b/data/api/client-server/users.yaml index 3a7f2bfa..c1f3c6c8 100644 --- a/data/api/client-server/users.yaml +++ b/data/api/client-server/users.yaml @@ -20,10 +20,17 @@ paths: post: summary: Searches the user directory. description: |- - Performs a search for users. The homeserver may - determine which subset of users are searched, however the homeserver - MUST at a minimum consider the users the requesting user shares a - room with and those who reside in public rooms (known to the homeserver). + Performs a search for users. The homeserver may determine which + subset of users are searched. However, the homeserver MUST at a + minimum consider users who are visible to the requester based + on their membership in rooms known to the homeserver. This means: + + - users that share a room with the requesting user + - users who are joined to rooms known to the homeserver that have a + `public` [join rule](#mroomjoin_rules) + - users who are joined to rooms known to the homeserver that have a + `world_readable` [history visibility](#room-history-visibility) + The search MUST consider local users to the homeserver, and SHOULD query remote users as part of the search. From 2c6ddafb43cc92595cc24e307a95b1ed9d3ab8d8 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 13 May 2025 16:09:12 +0200 Subject: [PATCH 13/19] Clarify the meaning of "public rooms" for call invites (#2106) --- .../client_server/newsfragments/2106.clarification | 1 + content/client-server-api/modules/voip_events.md | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2106.clarification diff --git a/changelogs/client_server/newsfragments/2106.clarification b/changelogs/client_server/newsfragments/2106.clarification new file mode 100644 index 00000000..8a0dd00a --- /dev/null +++ b/changelogs/client_server/newsfragments/2106.clarification @@ -0,0 +1 @@ +"Public" rooms with respect to call invites are defined through their join rule. diff --git a/content/client-server-api/modules/voip_events.md b/content/client-server-api/modules/voip_events.md index 14b7d796..1c0bfd28 100644 --- a/content/client-server-api/modules/voip_events.md +++ b/content/client-server-api/modules/voip_events.md @@ -202,11 +202,13 @@ specific user, and should be set to the Matrix user ID of that user. Invites without an `invitee` field are defined to be intended for any member of the room other than the sender of the event. -Clients should consider an incoming call if they see a non-expired invite event where the `invitee` field is either -absent or equal to their user's Matrix ID, however they should evaluate whether or not to ring based on their -user's trust relationship with the callers and/or where the call was placed. As a starting point, it is -suggested that clients ignore call invites from users in public rooms. It is strongly recommended that -when clients do not ring for an incoming call invite, they still display the call invite in the room and +Clients should consider an incoming call if they see a non-expired invite event +where the `invitee` field is either absent or equal to their user's Matrix ID. +They should, however, evaluate whether or not to ring based on their user's trust +relationship with the callers and/or where the call was placed. As a starting +point, it is RECOMMENDED that clients ignore call invites in rooms with a +[join rule](#mroomjoin_rules) of `public`. When clients suppress ringing for an +incoming call invite, they SHOULD still display the call invite in the room and annotate that it was ignored. ##### Glare From 0a1efd8c9ceebe700e7bc786bd2de3cb7a524613 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 13 May 2025 16:10:08 +0200 Subject: [PATCH 14/19] Clarify the meaning of "public rooms" for policy lists (#2107) --- changelogs/client_server/newsfragments/2107.clarification | 1 + content/client-server-api/modules/moderation_policies.md | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2107.clarification diff --git a/changelogs/client_server/newsfragments/2107.clarification b/changelogs/client_server/newsfragments/2107.clarification new file mode 100644 index 00000000..0474010e --- /dev/null +++ b/changelogs/client_server/newsfragments/2107.clarification @@ -0,0 +1 @@ +"Public" rooms have no specific meaning with respect to moderation policy lists. diff --git a/content/client-server-api/modules/moderation_policies.md b/content/client-server-api/modules/moderation_policies.md index 2912d164..15a3a377 100644 --- a/content/client-server-api/modules/moderation_policies.md +++ b/content/client-server-api/modules/moderation_policies.md @@ -18,8 +18,9 @@ the entity making the decisions on filtering is best positioned to interpret the rules how it sees fit. Moderation policy lists are stored as room state events. There are no -restrictions on how the rooms can be configured (they could be public, -private, encrypted, etc). +restrictions on how the rooms can be configured in terms of +[join rules](#mroomjoin_rules), [history visibility](#room-history-visibility), +encryption, etc. There are currently 3 kinds of entities which can be affected by rules: `user`, `server`, and `room`. All 3 are described with From 73fcf366a0da5fb4e408a0e845e705277fdccea9 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 13 May 2025 16:11:50 +0200 Subject: [PATCH 15/19] Clarify the meaning of "public rooms" for presence (#2108) --- changelogs/client_server/newsfragments/2108.clarification | 1 + content/client-server-api/modules/presence.md | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2108.clarification diff --git a/changelogs/client_server/newsfragments/2108.clarification b/changelogs/client_server/newsfragments/2108.clarification new file mode 100644 index 00000000..2e8c4e59 --- /dev/null +++ b/changelogs/client_server/newsfragments/2108.clarification @@ -0,0 +1 @@ +"Public" rooms with respect to presence are defined through their join rule. diff --git a/content/client-server-api/modules/presence.md b/content/client-server-api/modules/presence.md index ba46b327..4bbd43eb 100644 --- a/content/client-server-api/modules/presence.md +++ b/content/client-server-api/modules/presence.md @@ -68,5 +68,7 @@ will cause the server to automatically set their presence to `online`. #### Security considerations -Presence information is shared with all users who share a room with the -target user. In large public rooms this could be undesirable. +Presence information is published to all users who share a room with the +target user. If the target user is a member of a room with a `public` +[join rule](#mroomjoin_rules), any other user in the federation is +able to gain access to the target user's presence. This could be undesirable. From f4e6e6dea96c549bfe7b51d9eeab86e316fe321a Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 13 May 2025 16:13:40 +0200 Subject: [PATCH 16/19] Clarify the meaning of "public rooms" for presence (#2108) From 04397076248040937783101d12c86010cbb08f93 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 13 May 2025 17:01:25 +0200 Subject: [PATCH 17/19] Spec PR - MSC3765: Rich text in room topics (#2095) Signed-off-by: Johannes Marbach --- .../client_server/newsfragments/2095.feature | 1 + .../server_server/newsfragments/2095.feature | 1 + content/client-server-api/modules/search.md | 7 ++-- data/api/client-server/create_room.yaml | 14 ++++---- .../definitions/public_rooms_chunk.yaml | 4 ++- data/event-schemas/examples/m.room.topic.yaml | 10 +++++- .../components/m_text_content_block.yaml | 28 +++++++++++++++ data/event-schemas/schema/m.room.topic.yaml | 35 +++++++++++++++---- 8 files changed, 82 insertions(+), 18 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2095.feature create mode 100644 changelogs/server_server/newsfragments/2095.feature create mode 100644 data/event-schemas/schema/components/m_text_content_block.yaml diff --git a/changelogs/client_server/newsfragments/2095.feature b/changelogs/client_server/newsfragments/2095.feature new file mode 100644 index 00000000..0a993bbb --- /dev/null +++ b/changelogs/client_server/newsfragments/2095.feature @@ -0,0 +1 @@ +Add `m.topic` content block to enable rich text in `m.room.topic` events as per [MSC3765](https://github.com/matrix-org/matrix-spec-proposals/pull/3765). diff --git a/changelogs/server_server/newsfragments/2095.feature b/changelogs/server_server/newsfragments/2095.feature new file mode 100644 index 00000000..0a993bbb --- /dev/null +++ b/changelogs/server_server/newsfragments/2095.feature @@ -0,0 +1 @@ +Add `m.topic` content block to enable rich text in `m.room.topic` events as per [MSC3765](https://github.com/matrix-org/matrix-spec-proposals/pull/3765). diff --git a/content/client-server-api/modules/search.md b/content/client-server-api/modules/search.md index 8115d5be..2705aa66 100644 --- a/content/client-server-api/modules/search.md +++ b/content/client-server-api/modules/search.md @@ -26,9 +26,10 @@ on certain keys of certain event types. The supported keys to search over are: -- `content.body` in `m.room.message` -- `content.name` in `m.room.name` -- `content.topic` in `m.room.topic` +- `content.body` in [`m.room.message`](/client-server-api/#mroommessage) +- `content.name` in [`m.room.name`](/client-server-api/#mroomname) +- In [`m.room.topic`](/client-server-api/#mroomtopic), `content.topic` + as well as the `body` of the `text/plain` representation in `content['m.topic']`. The search will *not* include rooms that are end to end encrypted. diff --git a/data/api/client-server/create_room.yaml b/data/api/client-server/create_room.yaml index 3992fdfe..03a85443 100644 --- a/data/api/client-server/create_room.yaml +++ b/data/api/client-server/create_room.yaml @@ -109,15 +109,17 @@ paths: name: type: string description: |- - If this is included, an `m.room.name` event will be sent - into the room to indicate the name of the room. See Room - Events for more information on `m.room.name`. + If this is included, an [`m.room.name`](/client-server-api/#mroomname) event + will be sent into the room to indicate the name for the room. + This overwrites any [`m.room.name`](/client-server-api/#mroomname) + event in `initial_state`. topic: type: string description: |- - If this is included, an `m.room.topic` event will be sent - into the room to indicate the topic for the room. See Room - Events for more information on `m.room.topic`. + If this is included, an [`m.room.topic`](/client-server-api/#mroomtopic) + event with a `text/plain` mimetype will be sent into the room + to indicate the topic for the room. This overwrites any + [`m.room.topic`](/client-server-api/#mroomtopic) event in `initial_state`. invite: type: array description: |- diff --git a/data/api/client-server/definitions/public_rooms_chunk.yaml b/data/api/client-server/definitions/public_rooms_chunk.yaml index 9c6ae6fc..64786432 100644 --- a/data/api/client-server/definitions/public_rooms_chunk.yaml +++ b/data/api/client-server/definitions/public_rooms_chunk.yaml @@ -33,7 +33,9 @@ properties: example: "!abcdefg:example.org" topic: type: string - description: The topic of the room, if any. + description: |- + The plain text topic of the room. Omitted if no `text/plain` mimetype + exists in [`m.room.topic`](/client-server-api/#mroomtopic). example: "All things general" world_readable: type: boolean diff --git a/data/event-schemas/examples/m.room.topic.yaml b/data/event-schemas/examples/m.room.topic.yaml index 69e5d4f1..993145a6 100644 --- a/data/event-schemas/examples/m.room.topic.yaml +++ b/data/event-schemas/examples/m.room.topic.yaml @@ -3,6 +3,14 @@ "type": "m.room.topic", "state_key": "", "content": { - "topic": "A room topic" + "m.topic": { + "m.text": [ { + "mimetype": "text/html", + "body": "An interesting room topic" + }, { + "body": "An interesting room topic" + }] + }, + "topic": "An interesting room topic" } } diff --git a/data/event-schemas/schema/components/m_text_content_block.yaml b/data/event-schemas/schema/components/m_text_content_block.yaml new file mode 100644 index 00000000..29c8d148 --- /dev/null +++ b/data/event-schemas/schema/components/m_text_content_block.yaml @@ -0,0 +1,28 @@ +type: array +description: |- + An ordered array of textual representations in different mimetypes. + + Senders SHOULD specify at least one representation and SHOULD always + include a plaintext representation. + + Receivers SHOULD use the first representation in the array that + they understand. +title: TextContentBlock +items: + type: object + title: TextualRepresentation + properties: + mimetype: + type: string + description: The mimetype. Defaults to `text/plain` if omitted. + example: "text/html" + body: + type: string + description: |- + The string content. + + Clients SHOULD validate and sanitize the content as they do + for rich content associated with [`msgtype`](/client-server-api/#mroommessage-msgtypes) + of [`m.room.message`](/client-server-api/#mroommessage). + required: + - body diff --git a/data/event-schemas/schema/m.room.topic.yaml b/data/event-schemas/schema/m.room.topic.yaml index 56f0caf9..580566d2 100644 --- a/data/event-schemas/schema/m.room.topic.yaml +++ b/data/event-schemas/schema/m.room.topic.yaml @@ -1,20 +1,41 @@ --- allOf: - $ref: core-event-schema/state_event.yaml -description: |- - A topic is a short message detailing what is currently being discussed in the room. - It can also be used as a way to display extra information about the room, which may not - be suitable for the room name. - The room topic can also be set when creating a room using `/createRoom` with the `topic` key.' - +description: |- + A topic is a short message detailing what is currently being discussed + in the room. It can also be used as a way to display extra information + about the room, which may not be suitable for the room name. The room + topic can also be set when creating a room using + [`/createRoom`](client-server-api/#post_matrixclientv3createroom), either + with the `topic` key or by specifying a full event in `initial_state`. + If the `topic` property is absent, null, or empty then the topic is unset. In other words, an empty `topic` property effectively resets the room to having no topic. + + In order to prevent formatting abuse in room topics, clients SHOULD + limit the length of topics during both entry and display, for instance, + by capping the number of displayed lines. Additionally, clients SHOULD + ignore things like headings and enumerations (or format them as regular + text). properties: content: properties: topic: - description: The topic text. + description: |- + The topic in plain text. + + This SHOULD duplicate the content of the `text/plain` + representation in `m.topic` if any exists. type: string + m.topic: + type: object + title: TopicContentBlock + x-addedInMatrixVersion: "1.15" + description: |- + Textual representation of the room topic in different mimetypes. + properties: + m.text: + $ref: components/m_text_content_block.yaml required: - topic type: object From 338047ec7bb628a1215a730611b9d87739012600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Tue, 13 May 2025 17:03:10 +0200 Subject: [PATCH 18/19] Clarify that `join_authorised_via_users_server` auth event is only necessary for `join`s (#2100) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- changelogs/server_server/newsfragments/2100.clarification | 1 + content/server-server-api.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelogs/server_server/newsfragments/2100.clarification diff --git a/changelogs/server_server/newsfragments/2100.clarification b/changelogs/server_server/newsfragments/2100.clarification new file mode 100644 index 00000000..a488b392 --- /dev/null +++ b/changelogs/server_server/newsfragments/2100.clarification @@ -0,0 +1 @@ +Clarify that auth event of `content.join_authorised_via_users_server` is only necessary for `m.room.member` with a `membership` of `join`. diff --git a/content/server-server-api.md b/content/server-server-api.md index 10d91468..2745bff6 100644 --- a/content/server-server-api.md +++ b/content/server-server-api.md @@ -544,8 +544,8 @@ the following subset of the room state: `third_party_invite` property, the current `m.room.third_party_invite` event with `state_key` matching `content.third_party_invite.signed.token`, if any. - - If `content.join_authorised_via_users_server` is present, - and the [room version supports restricted rooms](/rooms/#feature-matrix), + - If `membership` is `join`, `content.join_authorised_via_users_server` + is present, and the [room version supports restricted rooms](/rooms/#feature-matrix), then the `m.room.member` event with `state_key` matching `content.join_authorised_via_users_server`. From 67743d5715071afa4a2b8553321dccf5339a330d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Tue, 13 May 2025 17:09:18 +0200 Subject: [PATCH 19/19] Fix generation of historical spec (#2123) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the move of the config file, the command in CI did not work as expected anymore. I am unsure why Hugo actually ignored the missing config file in the command… To avoid this problem in the future and simplify the job, we use the default config and add an environment variable for the status which will always take precedence over the config. Signed-off-by: Kévin Commaille --- .github/workflows/main.yml | 5 +++-- changelogs/internal/newsfragments/2123.clarification | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 changelogs/internal/newsfragments/2123.clarification diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index daa8fb67..446aca9c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -284,10 +284,11 @@ jobs: npm i npm run get-proposals - name: "⚙️ hugo" + env: + HUGO_PARAMS_VERSION_STATUS: "historical" # Create a baseURL like `/v1.2` out of the `v1.2` tag run: | - echo -e '[params.version]\nstatus="historical"' > historical.toml - hugo --config config.toml,historical.toml --baseURL "/${GITHUB_REF/refs\/tags\//}" -d "spec" + hugo --baseURL "/${GITHUB_REF/refs\/tags\//}" -d "spec" - name: "📥 Spec definition download" uses: actions/download-artifact@v4 diff --git a/changelogs/internal/newsfragments/2123.clarification b/changelogs/internal/newsfragments/2123.clarification new file mode 100644 index 00000000..af26abaf --- /dev/null +++ b/changelogs/internal/newsfragments/2123.clarification @@ -0,0 +1 @@ +Fix the historical info box when generating the historical spec in CI.