Compare commits

...

8 commits

Author SHA1 Message Date
Kim Brose dfae09d761
Merge e0f02743bd into ca9c376076 2025-05-08 18:10:46 +02:00
Kim Brose ca9c376076
Clarify Well-Known URIs (#2140)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
* 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>
2025-05-08 13:55:51 +02:00
Kévin Commaille fe46e0c363
Replace Hugo shortcodes in OpenAPI output (#2088)
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-05-08 09:29:32 +00:00
Andrew Morgan a8c326962a
Add a note to the federation invite endpoints that invites can be sent twice (#2067)
... 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>
2025-05-08 10:09:45 +01:00
Kévin Commaille fca171427f
Clarifications around third-party invites (#2083)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-04-22 15:48:50 +01:00
Kévin Commaille 81273df88e
Adjust margins in rendered endpoints (#2081)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
* 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 <zecakeh@tedomum.fr>

* 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 <zecakeh@tedomum.fr>

* Add changelog

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>

---------

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2025-04-15 18:35:27 +01:00
Will Hunt 65b1db721d
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.
2025-04-15 18:24:22 +01:00
Kévin Commaille c39c7d0680
Fix /sync example (#2077)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
* 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 <zecakeh@tedomum.fr>

* 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 <zecakeh@tedomum.fr>

* Add changelog

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>

---------

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-04-15 14:47:21 +01:00
32 changed files with 477 additions and 216 deletions

View file

@ -2,6 +2,7 @@ name: "Spec"
env: env:
HUGO_VERSION: 0.139.0 HUGO_VERSION: 0.139.0
PYTHON_VERSION: 3.13
on: on:
push: push:
@ -40,7 +41,7 @@ jobs:
- name: " Setup Python" - name: " Setup Python"
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.9' python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip' cache: 'pip'
cache-dependency-path: scripts/requirements.txt cache-dependency-path: scripts/requirements.txt
- name: " Install dependencies" - name: " Install dependencies"
@ -59,7 +60,7 @@ jobs:
- name: " Setup Python" - name: " Setup Python"
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.9' python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip' cache: 'pip'
cache-dependency-path: scripts/requirements.txt cache-dependency-path: scripts/requirements.txt
- name: " Install dependencies" - name: " Install dependencies"
@ -78,7 +79,7 @@ jobs:
- name: " Setup Python" - name: " Setup Python"
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.9' python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip' cache: 'pip'
cache-dependency-path: scripts/requirements.txt cache-dependency-path: scripts/requirements.txt
- name: " Install dependencies" - name: " Install dependencies"
@ -120,7 +121,7 @@ jobs:
- name: " Setup Python" - name: " Setup Python"
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.9' python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip' cache: 'pip'
cache-dependency-path: scripts/requirements.txt cache-dependency-path: scripts/requirements.txt
- name: " Install dependencies" - name: " Install dependencies"
@ -172,7 +173,7 @@ jobs:
- name: " Setup Python" - name: " Setup Python"
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.9' python-version: ${{ env.PYTHON_VERSION }}
- name: " Install towncrier" - name: " Install towncrier"
run: "pip install 'towncrier'" run: "pip install 'towncrier'"
- name: "Generate changelog" - name: "Generate changelog"

View file

@ -316,13 +316,19 @@ Custom SCSS for the Matrix spec
h2 { h2 {
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
font-size: 1.3rem; font-size: 1.3rem;
margin: 3rem 0 .5rem 0; margin: 1.5rem 0 1rem 0;
} }
h3 { h3 {
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
font-size: 1.1rem; 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 { 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 {
caption-side: top; caption-side: top;
color: $dark; 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 { pre {
border: 0; border: 0;
border-left: solid 5px $secondary; border-left: solid 5px $secondary;

View file

@ -0,0 +1 @@
Clarify behaviour when the `topic` key of a `m.room.topic` event is absent, null, or empty.

View file

@ -0,0 +1 @@
Fix the example of the `GET /sync` endpoint and the `m.room.member` example used in several places.

View file

@ -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.

View file

@ -0,0 +1 @@
Clarify that Well-Known URIs are available on the server name's hostname. Contributed by @HarHarLinks.

View file

@ -0,0 +1 @@
Clarify that public keys can be encoded using standard or URL-safe base64.

View file

@ -0,0 +1 @@
Adjust margins in rendered endpoints.

View file

@ -0,0 +1 @@
Replace Hugo shortcodes in OpenAPI output.

View file

@ -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.

View file

@ -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.

View file

@ -0,0 +1 @@
Clarify that Well-Known URIs are available on the server name's hostname. Contributed by @HarHarLinks.

View file

@ -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 No further guess should be attempted and the user should make a
conscientious decision what to do next. 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 %}} {{% 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, Servers hosting the `.well-known` JSON file SHOULD offer CORS headers,
as per the [CORS](#web-browser-clients) section in this specification. as per the [CORS](#web-browser-clients) section in this specification.
{{% /boxes/note %}} {{% /boxes/note %}}
The `.well-known` method uses a JSON file at a predetermined location to The flow for auto-discovery is as follows:
specify parameter values. The flow for this method is as follows:
1. Extract the [server name](/appendices/#server-name) from the user's Matrix ID by splitting the 1. Extract the [server name](/appendices/#server-name) from the user's Matrix ID by splitting the
Matrix ID at the first colon. 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="wellknown" %}}
{{% http-api spec="client-server" api="versions" %}}
{{% http-api spec="client-server" api="support" %}} {{% 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 ## Client Authentication
Most API endpoints require the user to identify themselves by presenting Most API endpoints require the user to identify themselves by presenting

View file

@ -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 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 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 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 not. Either way, the client calls [`/invite`](#thirdparty_post_matrixclientv3roomsroomidinvite)
third-party identifier. with the details of the third-party identifier.
The homeserver asks the identity server whether a Matrix user ID is The homeserver asks the identity server whether a Matrix user ID is
known for that identifier: known for that identifier:
@ -37,10 +37,12 @@ A client asks a server to invite a user by their third-party identifier.
#### Server behaviour #### Server behaviour
Upon receipt of an [`/invite`](#post_matrixclientv3roomsroomidinvite), the server is expected to look up the Upon receipt of an [`/invite`](#thirdparty_post_matrixclientv3roomsroomidinvite),
third-party identifier with the provided identity server. If the lookup the server is expected to look up the third-party identifier with the provided
yields a result for a Matrix User ID then the normal invite process can identity server by making a call to [`/_matrix/identity/v2/lookup`](/identity-service-api/#post_matrixidentityv2lookup).
be initiated. This process ends up looking like this: 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 However, if the lookup does not yield a bound User ID, the homeserver must store
must store the invite on the identity server and emit a valid the invite on the identity server with a call to
`m.room.third_party_invite` event to the room. This process ends up [`/_matrix/identity/v2/store-invite`](/identity-service-api/#post_matrixidentityv2store-invite)
looking like this: 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 The third-party user will then need to verify their identity, which results in a
`content.third_party_invite.signed` object. 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 All homeservers MUST verify the signature in the `m.room.member` event's
results in a call from the identity server to the homeserver that bound `content.third_party_invite.signed` object.
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.
If a homeserver is joining a room for the first time because of an 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 `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 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 correct as well as the `key_validity_url` as still being valid. This is
done by making a request to the [identity server done by making a request to the identity server's
/isvalid](/identity-service-api/#get_matrixidentityv2pubkeyisvalid) [`/pubkey/isvalid`](/identity-service-api/#get_matrixidentityv2pubkeyisvalid)
endpoint, using the provided URL rather than constructing a new one. The endpoint, using the provided URL rather than constructing a new one. The
query string and response for the provided URL must match the Identity query string and response for the provided URL must match the Identity
Service Specification. Service Specification.

View file

@ -119,7 +119,8 @@ to send. The process overall is as follows:
server must present a valid certificate for the hostname. server must present a valid certificate for the hostname.
3. If the hostname is not an IP literal, a regular HTTPS request is 3. If the hostname is not an IP literal, a regular HTTPS request is
made to `https://<hostname>/.well-known/matrix/server`, expecting made to `https://<hostname>/.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 the schema defined later in this section. 30x redirects should be
followed, however redirection loops should be avoided. Responses followed, however redirection loops should be avoided. Responses
(successful or otherwise) to the `/.well-known` endpoint should be (successful or otherwise) to the `/.well-known` endpoint should be
@ -970,9 +971,8 @@ the event to other servers in the room.
## Third-party invites ## Third-party invites
{{% boxes/note %}} {{% boxes/note %}}
More information about third-party invites is available in the More information about third-party invites is available in the Client-Server API
[Client-Server API](/client-server-api) under under the [Third-party invites](/client-server-api/#third-party-invites) module.
the Third-party Invites module.
{{% /boxes/note %}} {{% /boxes/note %}}
When a user wants to invite another user in a room but doesn't know the When a user wants to invite another user in a room but doesn't know the
@ -985,38 +985,41 @@ API](/identity-service-api).
### Cases where an association exists for a third-party identifier ### Cases where an association exists for a third-party identifier
If the third-party identifier is already bound to a Matrix ID, a lookup 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 request](/identity-service-api/#post_matrixidentityv2lookup) on the identity
processed by the inviting homeserver as a standard `m.room.member` server will return it. The invite is then processed by the inviting homeserver
invite event. This is the simplest case. 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 ### 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 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 homeserver will request the identity server to [store an invite](/identity-service-api/#invitation-storage)
identifier and to deliver it to whoever binds it to its Matrix ID. It 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 will also send an [`m.room.third_party_invite`](/client-server-api/#mroomthird_party_invite)
specify a display name, a token and public keys the identity server event in the room to specify a display name, a token and public keys the
provided as a response to the invite storage request. identity server provided as a response to the invite storage request.
When a third-party identifier with pending invites gets bound to a When a third-party identifier with pending invites gets bound to a Matrix ID,
Matrix ID, the identity server will send a POST request to the ID's the identity server will send a request to the [`/3pid/onbind`](#put_matrixfederationv13pidonbind)
homeserver as described in the [Invitation endpoint of the the ID's homeserver as described in the [Invitation
Storage](/identity-service-api#invitation-storage) Storage](/identity-service-api#invitation-storage) section of the Identity
section of the Identity Service API. Service API.
The following process applies for each invite sent by the identity The following process applies for each invite sent by the identity
server: server:
The invited homeserver will create an `m.room.member` invite event The invited homeserver will create an [`m.room.member`](/client-server-api/#mroommember)
containing a special `third_party_invite` section containing the token invite event containing a special `third_party_invite` section containing the
and a signed object, both provided by the identity server. 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 If the invited homeserver is in the room the invite came from, it can
auth the event and send it. auth the event and send it.
However, if the invited homeserver isn't in the room the invite came 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" %}} {{% http-api spec="server-server" api="third_party_invite" %}}

View file

@ -22,9 +22,12 @@ paths:
description: |- description: |-
Gets server admin contact and support page of the domain. Gets server admin contact and support page of the domain.
Like the [well-known discovery URI](/client-server-api/#well-known-uri), {{% boxes/note %}}
this should be accessed with the hostname of the homeserver by making a 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`. GET request to `https://hostname/.well-known/matrix/support`.
{{% /boxes/note %}}
Note that this endpoint is not necessarily handled by the homeserver. Note that this endpoint is not necessarily handled by the homeserver.
It may be served by another webserver, used for discovering support It may be served by another webserver, used for discovering support

View file

@ -441,17 +441,57 @@ paths:
"state": { "state": {
"events": [ "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": { "timeline": {
"events": [ "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": "<b>This is an example text message</b>",
"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, "limited": true,

View file

@ -57,9 +57,6 @@ paths:
- A signature of the token, signed with the identity server's private key - A signature of the token, signed with the identity server's private key
- The matrix user ID who invited them to the room - 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 operationId: inviteBy3PID
security: security:
- accessTokenQuery: [] - accessTokenQuery: []
@ -72,6 +69,8 @@ paths:
example: "!d41d8cd:matrix.org" example: "!d41d8cd:matrix.org"
schema: schema:
type: string type: string
format: mx-room-id
pattern: "^!"
requestBody: requestBody:
content: content:
application/json: application/json:
@ -90,7 +89,9 @@ paths:
value: {} value: {}
"403": "403":
description: |- 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 has been banned from the room.
- The invitee is already a member of the room. - The invitee is already a member of the room.

View file

@ -26,6 +26,12 @@ paths:
suitably namespaced for each application and reduces the risk of suitably namespaced for each application and reduces the risk of
clashes. 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, Note that this endpoint is not necessarily handled by the homeserver,
but by another webserver, to be used for discovering the homeserver URL. but by another webserver, to be used for discovering the homeserver URL.
operationId: getWellknown operationId: getWellknown

View file

@ -43,7 +43,8 @@ paths:
properties: properties:
public_key: public_key:
type: string type: string
description: Unpadded Base64 encoded public key. description: |-
[Unpadded Base64](/appendices/#unpadded-base64)-encoded public key.
required: required:
- public_key - public_key
examples: examples:
@ -74,7 +75,8 @@ paths:
- in: query - in: query
name: public_key name: public_key
required: true 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 example: VXuGitF39UH5iRfvbIknlvlAVKgD1BsLDMvBf0pmp7c
schema: schema:
type: string type: string
@ -105,7 +107,14 @@ paths:
- in: query - in: query
name: public_key name: public_key
required: true 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 example: VXuGitF39UH5iRfvbIknlvlAVKgD1BsLDMvBf0pmp7c
schema: schema:
type: string type: string

View file

@ -42,7 +42,7 @@ paths:
(if present) from the request here. (if present) from the request here.
Also, the generated ephemeral public key will be listed as valid on 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. Currently, invites may only be issued for 3pids of the `email` medium.
@ -70,10 +70,14 @@ paths:
room_id: room_id:
type: string type: string
description: The Matrix room ID to which the user is invited description: The Matrix room ID to which the user is invited
format: mx-room-id
pattern: "^!"
example: "!something:example.org" example: "!something:example.org"
sender: sender:
type: string type: string
description: The Matrix user ID of the inviting user description: The Matrix user ID of the inviting user
format: mx-user-id
pattern: "^@"
example: "@bob:example.com" example: "@bob:example.com"
room_alias: room_alias:
type: string type: string
@ -81,12 +85,16 @@ paths:
The Matrix room alias for the room to which the user is The Matrix room alias for the room to which the user is
invited. This should be retrieved from the `m.room.canonical_alias` invited. This should be retrieved from the `m.room.canonical_alias`
state event. state event.
format: mx-room-alias
pattern: "^#"
example: "#somewhere:example.org" example: "#somewhere:example.org"
room_avatar_url: room_avatar_url:
type: string type: string
description: |- description: |-
The Content URI for the room to which the user is invited. This should The Content URI for the room to which the user is invited. This should
be retrieved from the `m.room.avatar` state event. be retrieved from the `m.room.avatar` state event.
format: mx-mxc-uri
pattern: "^mxc:\\/\\/"
example: mxc://example.org/s0meM3dia example: mxc://example.org/s0meM3dia
room_join_rules: room_join_rules:
type: string type: string
@ -108,6 +116,8 @@ paths:
type: string type: string
description: The Content URI for the avatar of the user ID initiating the description: The Content URI for the avatar of the user ID initiating the
invite. invite.
format: mx-mxc-uri
pattern: "^mxc:\\/\\/"
example: mxc://example.org/an0th3rM3dia example: mxc://example.org/an0th3rM3dia
room_type: room_type:
type: string type: string
@ -146,7 +156,7 @@ paths:
public_key: public_key:
type: string type: string
description: | 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: key_validity_url:
type: string type: string
description: | description: |

View file

@ -20,7 +20,7 @@ paths:
put: put:
summary: Invites a remote user to a room summary: Invites a remote user to a room
description: |- 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 homeserver and the invited homeserver, it can be sent to all of the servers in the
room by the inviting homeserver. room by the inviting homeserver.
@ -32,6 +32,10 @@ paths:
[room version specification](/rooms) for precise event formats. **The request and response [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 bodies here describe the common event fields in more detail and may be missing other
required fields for a PDU.** 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 operationId: sendInviteV1
security: security:
- signedRequest: [] - signedRequest: []

View file

@ -24,7 +24,7 @@ paths:
This API is nearly identical to the v1 API with the exception of the request This API is nearly identical to the v1 API with the exception of the request
body being different, and the response format fixed. 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 homeserver and the invited homeserver, it can be sent to all of the servers in the
room by the inviting homeserver. room by the inviting homeserver.
@ -36,6 +36,10 @@ paths:
[room version specification](/rooms) for precise event formats. **The request and response [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 bodies here describe the common event fields in more detail and may be missing other
required fields for a PDU.** 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 operationId: sendInviteV2
security: security:
- signedRequest: [] - signedRequest: []

View file

@ -35,6 +35,8 @@ paths:
example: "!abc123:matrix.org" example: "!abc123:matrix.org"
schema: schema:
type: string type: string
format: mx-room-id
pattern: "^!"
requestBody: requestBody:
content: content:
application/json: application/json:
@ -50,16 +52,22 @@ paths:
description: |- description: |-
The room ID the event is for. Must match the ID given in The room ID the event is for. Must match the ID given in
the path. the path.
format: mx-room-id
pattern: "^!"
example: "!abc123:matrix.org" example: "!abc123:matrix.org"
sender: sender:
type: string type: string
description: |- description: |-
The user ID of the user who sent the original `m.room.third_party_invite` The user ID of the user who sent the original `m.room.third_party_invite`
event. event.
format: mx-user-id
pattern: "^@"
example: "@joe:matrix.org" example: "@joe:matrix.org"
state_key: state_key:
type: string type: string
description: The user ID of the invited user description: The user ID of the invited user
format: mx-user-id
pattern: "^@"
example: "@someone:example.org" example: "@someone:example.org"
content: content:
type: object type: object
@ -82,45 +90,7 @@ paths:
third-party identifier. third-party identifier.
example: alice example: alice
signed: signed:
type: object $ref: ../../event-schemas/schema/components/signed_third_party_invite.yaml
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
required: required:
- display_name - display_name
- signed - signed
@ -215,6 +185,8 @@ paths:
mxid: mxid:
type: string type: string
description: The user that is now bound to the third-party identifier. description: The user that is now bound to the third-party identifier.
format: mx-user-id
pattern: "^@"
example: "@alice:matrix.org" example: "@alice:matrix.org"
invites: invites:
type: array type: array
@ -237,59 +209,23 @@ paths:
mxid: mxid:
type: string type: string
description: The now-bound user ID that received the invite. description: The now-bound user ID that received the invite.
format: mx-user-id
pattern: "^@"
example: "@alice:matrix.org" example: "@alice:matrix.org"
room_id: room_id:
type: string type: string
description: The room ID the invite is valid for. description: The room ID the invite is valid for.
format: mx-room-id
pattern: "^!"
example: "!somewhere:example.org" example: "!somewhere:example.org"
sender: sender:
type: string type: string
description: The user ID that sent the invite. description: The user ID that sent the invite.
format: mx-user-id
pattern: "^@"
example: "@bob:matrix.org" 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: signed:
type: object $ref: ../../event-schemas/schema/components/signed_third_party_invite.yaml
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
required: required:
- medium - medium
- address - address

View file

@ -24,6 +24,12 @@ paths:
Gets information about the delegated server for server-server communication Gets information about the delegated server for server-server communication
between Matrix homeservers. Servers should follow 30x redirects, carefully between Matrix homeservers. Servers should follow 30x redirects, carefully
avoiding redirect loops, and use normal X.509 certificate validation. 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 operationId: getWellKnown
responses: responses:
"200": "200":

View file

@ -1,6 +1,7 @@
{ {
"$ref": "core/state_event.json", "$ref": "core/state_event.json",
"state_key": "@alice:example.org", "state_key": "@alice:example.org",
"sender": "@alice:example.org",
"type": "m.room.member", "type": "m.room.member",
"content": { "content": {
"membership": "join", "membership": "join",

View file

@ -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

View file

@ -2,17 +2,27 @@
allOf: allOf:
- $ref: core-event-schema/state_event.yaml - $ref: core-event-schema/state_event.yaml
description: |- description: |-
Adjusts the membership state for a user in a room. It is preferable to use the membership APIs (`/rooms/<room id>/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/<room id>/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: 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. - `invite` - The user has been invited to join a room, but has not yet joined it. They may not
- `join` - The user has joined the room (possibly after accepting an invite), and may participate in it. participate in the room until they join.
- `leave` - The user was once joined to the room, but has since left (possibly by choice, or possibly by being kicked). - `join` - The user has joined the room (possibly after accepting an invite), and may participate
- `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`). in it.
- `knock` - The user has knocked on the room, requesting permission to participate. They may not participate in the room until they join. - `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. 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) If present, this contains an array of [stripped state events](/client-server-api/#stripped-state)
@ -57,63 +67,54 @@ properties:
- ban - ban
type: string type: string
is_direct: 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 type: boolean
join_authorised_via_users_server: join_authorised_via_users_server:
x-addedInMatrixVersion: "1.2" x-addedInMatrixVersion: "1.2"
type: string type: string
description: |- description: |-
Usually found on `join` events, this field is used to denote which homeserver (through representation of a user with sufficient power level) Usually found on `join` events, this field is used to denote which homeserver (through
authorised the user's join. More information about this field can be found in the [Restricted Rooms Specification](/client-server-api/#restricted-rooms). 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 Client and server implementations should be aware of the [signing implications](/rooms/v8/#authorization-rules)
field in further events: in particular, the event must be signed by the server which of including this field in further events: in particular, the event must be signed by the
owns the user ID in the field. When copying the membership event's `content` 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 (for profile updates and similar) it is therefore encouraged to exclude this field in the
field in the copy, as otherwise the event might fail event authorization. copy, as otherwise the event might fail event authorization.
reason: reason:
x-addedInMatrixVersion: "1.1" x-addedInMatrixVersion: "1.1"
type: string type: string
description: |- 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. Optional user-supplied text for why their membership has changed. For kicks and bans,
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 this is typically the reason for the kick or ban. For other membership changes, this is a
as in a case where Bob rejects an invite from Alice about an upcoming concert, but can't make it that day. 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 Clients are not recommended to show this reason to users when receiving an invite due to
reason behind a button or other component is recommended. the potential for spam and abuse. Hiding the reason behind a button or other component is
recommended.
third_party_invite: 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: properties:
display_name: 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 type: string
signed: signed:
description: 'A block of content which has been signed, which servers can use to verify the event. Clients should ignore this.' $ref: components/signed_third_party_invite.yaml
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
required: required:
- display_name - display_name
- signed - signed
title: Invite
type: object
required: required:
- membership - membership
title: EventContent title: EventContent

View file

@ -1,28 +1,56 @@
--- ---
allOf: allOf:
- $ref: core-event-schema/state_event.yaml - $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: properties:
content: content:
properties: properties:
display_name: 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 type: string
key_validity_url: 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 type: string
format: uri
public_key: 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 type: string
public_keys: public_keys:
description: Keys with which the token may be signed. description: Keys with which the token may be signed.
items: items:
properties: properties:
key_validity_url: 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=<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 type: string
public_key: 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 type: string
required: required:
- public_key - public_key
@ -35,11 +63,15 @@ properties:
- public_key - public_key
type: object type: object
state_key: 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: string
type: type:
enum: enum:
- m.room.third_party_invite - m.room.third_party_invite
type: string 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 type: object

View file

@ -1,7 +1,14 @@
--- ---
allOf: allOf:
- $ref: core-event-schema/state_event.yaml - $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: properties:
content: content:
properties: properties:

View file

@ -51,6 +51,11 @@ mx-room-id:
url: appendices#room-ids url: appendices#room-ids
# regex: "^!" # regex: "^!"
mx-room-alias:
title: Room Alias
url: appendices#room-aliases
# regex: "^#"
mx-server-name: mx-server-name:
title: Server Name title: Server Name
url: appendices#server-name url: appendices#server-name

View file

@ -32,6 +32,35 @@ import yaml
scripts_dir = os.path.dirname(os.path.abspath(__file__)) scripts_dir = os.path.dirname(os.path.abspath(__file__))
api_dir = os.path.join(os.path.dirname(scripts_dir), "data", "api") 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):
#
# {{%
# <zero or more whitespaces>
# <name of shortcode>
# (optional <one or more whitespaces><list of parameters>)
# <zero or more whitespaces>
# %}}
#
# With:
#
# * <name of shortcode>: any word character and `-` and `/`. `re.ASCII` is used to only match
# ASCII characters in the name.
# * <list of parameters>: any character except `}`, must not start or end with a
# whitespace.
shortcode_regex = re.compile(r"""\{\{\% # {{%
\s* # zero or more whitespaces
(?P<name>[\w/-]+) # name of shortcode
(?:\s+(?P<params>[^\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<key>\w+)=\"(?P<value>[^\"]+)\"", re.ASCII)
def prefix_absolute_path_references(text, base_url): def prefix_absolute_path_references(text, base_url):
"""Adds base_url to absolute-path references. """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)) return text.replace("](/", "]({}/".format(base_url))
def edit_links(node, base_url): def replace_match(match, replacement):
"""Finds description nodes and makes any links in them absolute.""" """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): if isinstance(node, dict):
for key in node: for key in node:
if isinstance(node[key], str): if isinstance(node[key], str):
node[key] = prefix_absolute_path_references(node[key], base_url) node[key] = prefix_absolute_path_references(node[key], base_url)
node[key] = find_and_replace_shortcodes(node[key])
else: else:
edit_links(node[key], base_url) edit_descriptions(node[key], base_url)
elif isinstance(node, list): elif isinstance(node, list):
for item in node: for item in node:
edit_links(item, base_url) edit_descriptions(item, base_url)
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
"dump-openapi.py - assemble the OpenAPI specs into a single JSON file" "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: if untagged != 0:
print("{} untagged operations, you may want to look into fixing that.".format(untagged)) 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) print("Generating %s" % output_file)