Merge branch 'master' into travis/spec/MSC2320-identity-versions

pull/977/head
Travis Ralston 3 years ago committed by Richard van der Hoff
commit fc6aa30000

@ -89,8 +89,8 @@ To create a changelog entry, create a file named in the format ``prNumber.type``
the ``newsfragments`` directory. The ``type`` can be one of the following:
* ``new`` - Used when adding new endpoints. Please have the file contents be the
method and route being added, surrounded in RST code tags. For example: ``POST
/accounts/whoami``
method and route being added, surrounded in markdown code tags. For example: \`POST
/accounts/whoami\`.
* ``feature`` - Used when adding backwards-compatible changes to the API.
@ -103,7 +103,7 @@ the ``newsfragments`` directory. The ``type`` can be one of the following:
All news fragments must have a brief summary explaining the change in the
contents of the file. The summary must end in a full stop to be in line with
the style guide and and formatting must be done using Markdown.
the style guide and formatting must be done using Markdown.
Changes that do not change the spec, such as changes to the build script, formatting,
CSS, etc should not get a news fragment.

@ -2,10 +2,11 @@
This repository contains the Matrix Specification, rendered at [spec.matrix.org](http://spec.matrix.org/).
Developers looking to use Matrix should join [#matrix-dev:matrix.org](http://matrix.to/#/#matrix-dev:matrix.org)
Developers looking to use Matrix should join [#matrix-dev:matrix.org](https://matrix.to/#/#matrix-dev:matrix.org)
on Matrix for help.
Spec authors and proposal writers are welcome to join [#matrix-spec:matrix.org](http://matrix.to/#/#matrix-spec:matrix.org). We welcome contributions! See [CONTRIBUTING.rst](./CONTRIBUTING.rst) for details.
Spec authors and proposal writers are welcome to join [#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org).
We welcome contributions! See [CONTRIBUTING.rst](./CONTRIBUTING.rst) for details.
## Structure
@ -21,7 +22,7 @@ The Matrix spec is compiled with [Hugo](https://gohugo.io/) (a static site gener
* `/data`: this can contain TOML, YAML, or JSON files. Files kept here are directly available to template code as
[data objects](https://gohugo.io/templates/data-templates/), so templates don't need to load them from a file and
parse them. This is also where our
parse them. This is also where our Swagger/OpenAPI definitions and schemas are.
* `/layouts`: this contains [Hugo templates](https://gohugo.io/templates/). Some templates define the overall layout of
a page: for example, whether it has header, footer, sidebar, and so on.
@ -35,8 +36,8 @@ The Matrix spec is compiled with [Hugo](https://gohugo.io/) (a static site gener
* `/themes`: you can use just Hugo or use it with a theme. Themes primarily provide additional templates, which are
supplied in a `/themes/$theme_name/layouts` directory. You can use a theme but customise it by providing your own
versions of any of the them layouts in the base `/layouts` directory. That is, if a theme provides
`/themes/$theme_name/layouts/sidebar.html` and you provide `/layouts/sidebar.html`, then your version of this
versions of any of the theme layouts in the base `/layouts` directory. That is, if a theme provides
`/themes/$theme_name/layouts/sidebar.html` and you provide `/layouts/sidebar.html`, then your version of the
template will be used.
It also has the following top-level file:
@ -48,10 +49,9 @@ Additionally, the following directories may be of interest:
* `/attic`: Here contains historical sections of specification and legacy drafts for the specification.
* `/changelogs`: Various bits of changelog for the specification areas.
* `/event-schemas`: [JSON Schema](http://json-schema.org/) definitions for the spec.
* `/data-definitions`: Bits of structured data consumable by Matrix implementations.
* `/meta`: Documentation relating to the spec's processes that are otherwise untracked (release instructions, etc).
* `/scripts`: Various scripts for generating the spec.
* `/scripts`: Various scripts for generating the spec and validating its contents.
* `/proposals`: Matrix Spec Change (MSC) proposals. See <https://spec.matrix.org/unstable/proposals/>.
## Authoring changes to the spec
@ -62,7 +62,8 @@ place after an MSC has been accepted, not as part of a proposal itself.
1. Install the extended version (often the OS default) of Hugo: <https://gohugo.io/getting-started/installing>
2. Run `git submodule update --init --recursive` for good measure.
3. Run `npm i` to install the dependencies. Note that this will require NodeJS to be installed.
4. Run `npm run get-proposals` to seed the proposals data. This is not required.
4. Run `npm run get-proposals` to seed proposal data. This is merely for populating the content of the "Spec Change Proposals"
page and is not required.
5. Run `hugo serve` to run a local webserver which builds whenever a file change is detected. If watching doesn't appear
to be working for you, try `hugo serve --disableFastRender` instead.
6. Edit the specification 🙂
@ -73,18 +74,18 @@ Awesome. If you're looking at making design-related changes to the spec site, pl
## Building the specification
If for some reason you're not a CI/CD system and want to render the spec yourself, follow the above steps for authoring
changes to the specification and instead of `hugo serve` run `hugo -d "spec"` - this will generate the spec to `/spec`.
If you'd like to serve the spec off a path instead of a domain root (eg: `/unstable`), add `--baseURL "/unstable"` to
the `hugo -d "spec"` command.
If for some reason you're not a CI/CD system and want to render a static version of the spec for yourself, follow the above
steps for authoring changes to the specification and instead of `hugo serve` run `hugo -d "spec"` - this will generate the
spec to `/spec`. If you'd like to serve the spec off a path instead of a domain root (eg: `/unstable`), add `--baseURL "/unstable"`
to the `hugo -d "spec"` command.
For building the swagger definitions, create a python3 virtualenv and activate it. Then run `pip install -r ./scripts/requirements.txt` and finally `python ./scripts/dump-swagger.py` to generate it to `./scripts/swagger/api-docs.json`.
To make use of the generated file, there are a number of options:
For building the swagger definitions, create a python3 virtualenv and activate it. Then run `pip install -r ./scripts/requirements.txt`
and finally `python ./scripts/dump-swagger.py` to generate it to `./scripts/swagger/api-docs.json`. To make use of the generated file,
there are a number of options:
* It can be uploaded from your filesystem to an online editor/viewer such as
http://editor.swagger.io/
* It can be uploaded from your filesystem to an online editor/viewer such as [on the swagger website](http://editor.swagger.io/).
* You can run a local HTTP server by running `./scripts/swagger-http-server.py`, and then view the documentation via an
online viewer; for example, at <http://petstore.swagger.io/?url=http://localhost:8000/api-docs.json>
online viewer; for example, at <http://petstore.swagger.io/?url=http://localhost:8000/api-docs.json>.
* You can host the swagger UI yourself. See <https://github.com/swagger-api/swagger-ui#how-to-run> for advice on how to
do so.

@ -0,0 +1 @@
Add support for spoilers ([MSC2010](https://github.com/matrix-org/matrix-doc/pull/2010) and [MSC2557](https://github.com/matrix-org/matrix-doc/pull/2557)), and `color` attribute ([MSC2422](https://github.com/matrix-org/matrix-doc/pull/2422)).

@ -0,0 +1 @@
Clarify that event bodies are untrusted, as per [MSC2801](https://github.com/matrix-org/matrix-doc/pull/2801).

@ -0,0 +1 @@
Add `<details>` and `<summary>` to the suggested HTML subset as per [MSC2184](https://github.com/matrix-org/matrix-doc/pull/2184).

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1 @@
Fix the maximum event size restriction (65535 bytes -> 65536).

@ -0,0 +1 @@
Add `m.key.verification.ready` and `m.key.verification.done` to key verification framework as per [MSC2366](https://github.com/matrix-org/matrix-doc/pull/2366).

@ -0,0 +1 @@
Add key verification using in-room messages as per [MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241).

@ -0,0 +1 @@
Add information about using SSSS for cross-signing and key backup.

@ -0,0 +1 @@
Add key verification method using QR codes ([MSC1544](https://github.com/matrix-org/matrix-doc/pull/1544)).

@ -0,0 +1 @@
Add key verification using in-room messages as per [MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241).

@ -0,0 +1 @@
Document how clients can simplify usage of Secure Secret Storage ([MSC2874](https://github.com/uhoreg/matrix-doc/pull/new/single_ssss_spec)).

@ -0,0 +1 @@
Add support for knocking, as per [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403).

@ -0,0 +1 @@
Add `/knock` endpoint as per [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403).

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1 @@
Add support for knocking, as per [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403).

@ -0,0 +1 @@
Add `/make_knock` and `/send_knock` endpoints as per [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403).

@ -232,6 +232,18 @@ reserved for events defined in the Matrix specification - for instance
`m.room.message` is the event type for instant messages. Events are
usually sent in the context of a "Room".
{{% boxes/warning %}}
Event bodies are considered untrusted data. This means that any application using
Matrix must validate that the event body is of the expected shape/schema
before using the contents verbatim.
**It is not safe to assume that an event body will have all the expected
fields of the expected types.**
See [MSC2801](https://github.com/matrix-org/matrix-doc/pull/2801) for more
detail on why this assumption is unsafe.
{{% /boxes/warning %}}
### Event Graphs
Events exchanged in the context of a room are stored in a directed
@ -315,12 +327,12 @@ sent to the room `!qporfwt:matrix.org`:
Federation maintains *shared data structures* per-room between multiple
homeservers. The data is split into `message events` and `state events`.
Message events:
Message events:
These describe transient 'once-off' activity in a room such as an
instant messages, VoIP call setups, file transfers, etc. They generally
describe communication activity.
State events:
State events:
These describe updates to a given piece of persistent information
('state') related to a room, such as the room's name, topic, membership,
participating servers, etc. State is modelled as a lookup table of
@ -493,7 +505,7 @@ stable and unstable periodically for a variety of reasons, including
discovered security vulnerabilities and age.
Clients should not ask room administrators to upgrade their rooms if the
room is running a stable version. Servers SHOULD use room version 6 as
room is running a stable version. Servers SHOULD use **room version 6** as
the default room version when creating new rooms.
The available room versions are:
@ -510,10 +522,11 @@ The available room versions are:
signing key validity periods.
- [Version 6](/rooms/v6) - **Stable**. Alters several
authorization rules for events.
- [Version 7](/rooms/v7) - **Stable**. Introduces knocking.
## Specification Versions
The specification for each API is versioned in the form `rX.Y.Z`.
The specification for each API is versioned in the form `rX.Y.Z`.
- A change to `X` reflects a breaking change: a client implemented
against `r1.0.0` may need changes to work with a server which
supports (only) `r2.0.0`.

@ -68,118 +68,118 @@ request being made was invalid.
The common error codes are:
`M_FORBIDDEN`
`M_FORBIDDEN`
Forbidden access, e.g. joining a room without permission, failed login.
`M_UNKNOWN_TOKEN`
`M_UNKNOWN_TOKEN`
The access token specified was not recognised.
An additional response parameter, `soft_logout`, might be present on the
response for 401 HTTP status codes. See [the soft logout
section](#soft-logout) for more information.
`M_MISSING_TOKEN`
`M_MISSING_TOKEN`
No access token was specified for the request.
`M_BAD_JSON`
`M_BAD_JSON`
Request contained valid JSON, but it was malformed in some way, e.g.
missing required keys, invalid values for keys.
`M_NOT_JSON`
`M_NOT_JSON`
Request did not contain valid JSON.
`M_NOT_FOUND`
`M_NOT_FOUND`
No resource was found for this request.
`M_LIMIT_EXCEEDED`
`M_LIMIT_EXCEEDED`
Too many requests have been sent in a short period of time. Wait a while
then try again.
`M_UNKNOWN`
`M_UNKNOWN`
An unknown error has occurred.
Other error codes the client might encounter are:
`M_UNRECOGNIZED`
`M_UNRECOGNIZED`
The server did not understand the request.
`M_UNAUTHORIZED`
`M_UNAUTHORIZED`
The request was not correctly authorized. Usually due to login failures.
`M_USER_DEACTIVATED`
`M_USER_DEACTIVATED`
The user ID associated with the request has been deactivated. Typically
for endpoints that prove authentication, such as `/login`.
`M_USER_IN_USE`
`M_USER_IN_USE`
Encountered when trying to register a user ID which has been taken.
`M_INVALID_USERNAME`
`M_INVALID_USERNAME`
Encountered when trying to register a user ID which is not valid.
`M_ROOM_IN_USE`
`M_ROOM_IN_USE`
Sent when the room alias given to the `createRoom` API is already in
use.
`M_INVALID_ROOM_STATE`
`M_INVALID_ROOM_STATE`
Sent when the initial state given to the `createRoom` API is invalid.
`M_THREEPID_IN_USE`
`M_THREEPID_IN_USE`
Sent when a threepid given to an API cannot be used because the same
threepid is already in use.
`M_THREEPID_NOT_FOUND`
`M_THREEPID_NOT_FOUND`
Sent when a threepid given to an API cannot be used because no record
matching the threepid was found.
`M_THREEPID_AUTH_FAILED`
`M_THREEPID_AUTH_FAILED`
Authentication could not be performed on the third party identifier.
`M_THREEPID_DENIED`
`M_THREEPID_DENIED`
The server does not permit this third party identifier. This may happen
if the server only permits, for example, email addresses from a
particular domain.
`M_SERVER_NOT_TRUSTED`
`M_SERVER_NOT_TRUSTED`
The client's request used a third party server, e.g. identity server,
that this server does not trust.
`M_UNSUPPORTED_ROOM_VERSION`
`M_UNSUPPORTED_ROOM_VERSION`
The client's request to create a room used a room version that the
server does not support.
`M_INCOMPATIBLE_ROOM_VERSION`
`M_INCOMPATIBLE_ROOM_VERSION`
The client attempted to join a room that has a version the server does
not support. Inspect the `room_version` property of the error response
for the room's version.
`M_BAD_STATE`
`M_BAD_STATE`
The state change requested cannot be performed, such as attempting to
unban a user who is not banned.
`M_GUEST_ACCESS_FORBIDDEN`
`M_GUEST_ACCESS_FORBIDDEN`
The room or resource does not permit guests to access it.
`M_CAPTCHA_NEEDED`
`M_CAPTCHA_NEEDED`
A Captcha is required to complete the request.
`M_CAPTCHA_INVALID`
`M_CAPTCHA_INVALID`
The Captcha provided did not match what was expected.
`M_MISSING_PARAM`
`M_MISSING_PARAM`
A required parameter was missing from the request.
`M_INVALID_PARAM`
`M_INVALID_PARAM`
A parameter that was specified has the wrong value. For example, the
server expected an integer and instead received a string.
`M_TOO_LARGE`
`M_TOO_LARGE`
The request or entity was too large.
`M_EXCLUSIVE`
`M_EXCLUSIVE`
The resource being requested is reserved by an application service, or
the application service making the request has not created the resource.
`M_RESOURCE_LIMIT_EXCEEDED`
`M_RESOURCE_LIMIT_EXCEEDED`
The request cannot be completed because the homeserver has reached a
resource limit imposed on it. For example, a homeserver held in a shared
hosting environment may reach a resource limit if it starts using too
@ -189,7 +189,7 @@ Typically, this error will appear on routes which attempt to modify
state (e.g.: sending messages, account data, etc) and not routes which
only read state (e.g.: `/sync`, get account data, etc).
`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
The user is unable to reject an invite to join the server notices room.
See the [Server Notices](#server-notices) module for more information.
@ -238,23 +238,23 @@ time.
In this section, the following terms are used with specific meanings:
`PROMPT`
`PROMPT`
Retrieve the specific piece of information from the user in a way which
fits within the existing client user experience, if the client is
inclined to do so. Failure can take place instead if no good user
experience for this is possible at this point.
`IGNORE`
`IGNORE`
Stop the current auto-discovery mechanism. If no more auto-discovery
mechanisms are available, then the client may use other methods of
determining the required parameters, such as prompting the user, or
using default values.
`FAIL_PROMPT`
`FAIL_PROMPT`
Inform the user that auto-discovery failed due to invalid/empty data and
`PROMPT` for the parameter.
`FAIL_ERROR`
`FAIL_ERROR`
Inform the user that auto-discovery did not return any usable URLs. Do
not continue further with the current login process. At this point,
valid data was obtained, but no server is available to serve the client.
@ -606,7 +606,7 @@ flow with three stages will resemble the following diagram:
#### Authentication types
This specification defines the following auth types:
This specification defines the following auth types:
- `m.login.password`
- `m.login.recaptcha`
- `m.login.sso`
@ -893,7 +893,7 @@ type of identifier being used, and depending on the type, has other
fields giving the information required to identify the user as described
below.
This specification defines the following identifier types:
This specification defines the following identifier types:
- `m.id.user`
- `m.id.thirdparty`
- `m.id.phone`
@ -1381,6 +1381,18 @@ opaque string. No changes should be required to support the currently
available room versions.
{{% /boxes/warning %}}
{{% boxes/warning %}}
Event bodies are considered untrusted data. This means that any application using
Matrix must validate that the event body is of the expected shape/schema
before using the contents verbatim.
**It is not safe to assume that an event body will have all the expected
fields of the expected types.**
See [MSC2801](https://github.com/matrix-org/matrix-doc/pull/2801) for more
detail on why this assumption is unsafe.
{{% /boxes/warning %}}
### Types of room events
Room events are split into two categories:
@ -1435,7 +1447,7 @@ following fields.
### Size limits
The complete event MUST NOT be larger than 65535 bytes, when formatted
The complete event MUST NOT be larger than 65536 bytes, when formatted
as a [PDU for the Server-Server
protocol](/server-server-api/#pdus), including any
signatures, and encoded as [Canonical
@ -1451,7 +1463,7 @@ There are additional restrictions on sizes per key:
Some event types have additional size restrictions which are specified
in the description of the event. Additional keys have no limit other
than that implied by the total 65 KB limit on events.
than that implied by the total 64 KiB limit on events.
### Room Events
@ -1700,7 +1712,7 @@ event also has a `creator` key which contains the user ID of the room
creator. It will also generate several other events in order to manage
permissions in this room. This includes:
- `m.room.power_levels` : Sets the power levels of users and required power
- `m.room.power_levels` : Sets the power levels of users and required power
levels for various actions within the room such as sending events.
- `m.room.join_rules` : Whether the room is "invite-only" or not.
@ -1766,57 +1778,44 @@ in that room. There are several states in which a user may be, in
relation to a room:
- Unrelated (the user cannot send or receive events in the room)
- Knocking (the user has requested to participate in the room, but has
not yet been allowed to)
- Invited (the user has been invited to participate in the room, but
is not yet participating)
- Joined (the user can send and receive events in the room)
- Banned (the user is not allowed to join the room)
There is an exception to the requirement that a user join a room before
sending events to it: users may send an `m.room.member` event to a room
with `content.membership` set to `leave` to reject an invitation if they
have currently been invited to a room but have not joined it.
There are a few notable exceptions which allow non-joined members of the
room to send events in the room:
- Users wishing to reject an invite would send `m.room.member` events with
`content.membership` of `leave`. They must have been invited first.
- If the room allows, users can send `m.room.member` events with `content.membership`
of `knock` to knock on the room. This is a request for an invite by the user.
- To retract a previous knock, a user would send a `leave` event similar to
rejecting an invite.
Some rooms require that users be invited to it before they can join;
others allow anyone to join. Whether a given room is an "invite-only"
room is determined by the room config key `m.room.join_rules`. It can
have one of the following values:
`public`
`public`
This room is free for anyone to join without an invite.
`invite`
`invite`
This room can only be joined if you were invited.
`knock`
This room can only be joined if you were invited, and allows anyone to
request an invite to the room. Note that this join rule is only available
to rooms based upon [room version 7](/rooms/v7).
The allowable state transitions of membership are:
```
/ban
+------------------------------------------------------+
| |
| +----------------+ +----------------+ |
| | /leave | | | |
| | v v | |
/invite +--------+ +-------+ | |
------------>| invite |<----------| leave |----+ | |
+--------+ /invite +-------+ | | |
| | ^ | | |
| | | | | |
/join | +---------------+ | | | |
| | /join if | | | |
| | join_rules | | /ban | /unban |
| | public /leave | | | |
v v or | | | |
+------+ /kick | | | |
------------>| join |-------------------+ | | |
/join +------+ v | |
if | +-----+ | |
join_rules +-------------------------->| ban |-----+ |
public /ban +-----+ |
^ ^ |
| | |
----------------------------------------------+ +----------------------+
/ban
```
![membership-flow-diagram](/diagrams/membership.png)
{{% http-api spec="client-server" api="list_joined_rooms" %}}
@ -1826,14 +1825,51 @@ The allowable state transitions of membership are:
{{% http-api spec="client-server" api="joining" %}}
##### Knocking on rooms
<!--
This section is here because it's most similar to being invited/joining a
room, though has added complexity which needs to be explained. Otherwise
this will have been just the API definition and nothing more (like invites).
-->
If the join rules allow, external users to the room can `/knock` on it to
request permission to join. Users with appropriate permissions within the
room can then approve (`/invite`) or deny (`/kick`, `/ban`, or otherwise
set membership to `leave`) the knock. Knocks can be retracted by calling
`/leave` or otherwise setting membership to `leave`.
Users who are currently in the room, already invited, or banned cannot
knock on the room.
To accept another user's knock, the user must have permission to invite
users to the room. To reject another user's knock, the user must have
permission to either kick or ban users (whichever is being performed).
Note that setting another user's membership to `leave` is kicking them.
The knocking homeserver should assume that an invite to the room means
that the knock was accepted, even if the invite is not explicitly related
to the knock.
Homeservers are permitted to automatically accept invites as a result of
knocks as they should be aware of the user's intent to join the room. If
the homeserver is not auto-accepting invites (or there was an unrecoverable
problem with accepting it), the invite is expected to be passed down normally
to the client to handle. Clients can expect to see the join event if the
server chose to auto-accept.
{{% http-api spec="client-server" api="knocking" %}}
#### Leaving rooms
A user can leave a room to stop receiving events for that room. A user
must have been invited to or have joined the room before they are
eligible to leave the room. Leaving a room to which the user has been
invited rejects the invite. Once a user leaves a room, it will no longer
appear in the response to the [`/sync`](/client-server-api/#get_matrixclientr0sync) API unless it is explicitly
requested via a filter with the `include_leave` field set to `true`.
invited rejects the invite, and can retract a knock. Once a user leaves
a room, it will no longer appear in the response to the
[`/sync`](/client-server-api/#get_matrixclientr0sync) API unless it is
explicitly requested via a filter with the `include_leave` field set
to `true`.
Whether or not they actually joined the room, if the room is an
"invite-only" room the user will need to be re-invited before they can
@ -1841,7 +1877,7 @@ re-join the room.
A user can also forget a room which they have left. Rooms which have
been forgotten will never appear the response to the [`/sync`](/client-server-api/#get_matrixclientr0sync) API,
until the user re-joins or is re-invited.
until the user re-joins, is re-invited, or knocks.
A user may wish to force another user to leave a room. This can be done
by 'kicking' the other user. To do so, the user performing the kick MUST

@ -247,8 +247,7 @@ file type. The key is sent using the [JSON Web
Key](https://tools.ietf.org/html/rfc7517#appendix-A.3) format, with a
[W3C extension](https://w3c.github.io/webcrypto/#iana-section-jwk).
Extensions to `m.room.message` msgtypes
&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;
###### Extensions to `m.room.message` msgtypes
This module adds `file` and `thumbnail_file` properties, of type
`EncryptedFile`, to `m.room.message` msgtypes that reference files, such
@ -357,8 +356,8 @@ out-of-band channel: there is no way to do it within Matrix without
trusting the administrators of the homeservers.
In Matrix, verification works by Alice meeting Bob in person, or
contacting him via some other trusted medium, and use [SAS
Verification](#SAS Verification) to interactively verify Bob's devices.
contacting him via some other trusted medium, and using one of the
verification methods defined below to interactively verify Bob's devices.
Alice and Bob may also read aloud their unpadded base64 encoded Ed25519
public key, as returned by `/keys/query`.
@ -390,60 +389,70 @@ decrypted by such a device. For the Olm protocol, this is documented at
Verifying keys manually by reading out the Ed25519 key is not very
user-friendly, and can lead to errors. In order to help mitigate errors,
and to make the process easier for users, some verification methods are
supported by the specification. The methods all use a common framework
supported by the specification and use messages exchanged by the user's devices
to assist in the verification. The methods all use a common framework
for negotiating the key verification.
To use this framework, Alice's client would send
`m.key.verification.request` events to Bob's devices. All of the
`to_device` messages sent to Bob MUST have the same `transaction_id` to
indicate they are part of the same request. This allows Bob to reject
the request on one device, and have it apply to all of his devices.
Similarly, it allows Bob to process the verification on one device
without having to involve all of his devices.
When Bob's device receives an `m.key.verification.request`, it should
prompt Bob to verify keys with Alice using one of the supported methods
in the request. If Bob's device does not understand any of the methods,
it should not cancel the request as one of his other devices may support
the request. Instead, Bob's device should tell Bob that an unsupported
method was used for starting key verification. The prompt for Bob to
accept/reject Alice's request (or the unsupported method prompt) should
be automatically dismissed 10 minutes after the `timestamp` field or 2
minutes after Bob's client receives the message, whichever comes first,
if Bob does not interact with the prompt. The prompt should additionally
be hidden if an appropriate `m.key.verification.cancel` message is
received.
If Bob rejects the request, Bob's client must send an
`m.key.verification.cancel` message to Alice's device. Upon receipt,
Alice's device should tell her that Bob does not want to verify her
device and send `m.key.verification.cancel` messages to all of Bob's
devices to notify them that the request was rejected.
If Bob accepts the request, Bob's device starts the key verification
process by sending an `m.key.verification.start` message to Alice's
device. Upon receipt of this message, Alice's device should send an
`m.key.verification.cancel` message to all of Bob's other devices to
indicate the process has been started. The start message must use the
same `transaction_id` from the original key verification request if it
is in response to the request. The start message can be sent
independently of any request.
Individual verification methods may add additional steps, events, and
properties to the verification messages. Event types for methods defined
in this specification must be under the `m.key.verification` namespace
and any other event types must be namespaced according to the Java
package naming convention.
Any of Alice's or Bob's devices can cancel the key verification request
or process at any time with an `m.key.verification.cancel` message to
all applicable devices.
This framework yields the following handshake, assuming both Alice and
Bob each have 2 devices, Bob's first device accepts the key verification
request, and Alice's second device initiates the request. Note how
Alice's first device is not involved in the request or verification
process.
Verification messages can be sent either in a room shared by the two parties,
which should be a [direct messaging](#direct-messaging) room between the two
parties, or by using [to-device](#send-to-device-messaging) messages sent
directly between the two devices involved. In both cases, the messages
exchanged are similar, with minor differences as detailed below. Verifying
between two different users should be performed using in-room messages, whereas
verifying two devices belonging to the same user should be performed using
to-device messages.
A key verification session is identified by an ID that is established by the
first message sent in that session. For verifications using in-room messages,
the ID is the event ID of the initial message, and for verifications using
to-device messages, the first message contains a `transaction_id` field that is
shared by the other messages of that session.
In general, verification operates as follows:
- Alice requests a key verification with Bob by sending an
`m.key.verification.request` event. This event indicates the verification
methods that Alice's client supports. (Note that "Alice" and "Bob" may in
fact be the same user, in the case where a user is verifying their own
devices.)
- Bob's client prompts Bob to accept the key verification. When Bob accepts
the verification, Bob's client sends an `m.key.verification.ready` event.
This event indicates the verification methods, corresponding to the
verification methods supported by Alice's client, that Bob's client supports.
- Alice's or Bob's devices allow their users to select one of the verification
methods supported by both devices to use for verification. When Alice or Bob
selects a verification method, their device begins the verification by
sending an `m.key.verification.start` event, indicating the selected
verification method. Note that if there is only one verification method in
common between the devices then the receiver's device (Bob) can auto-select
it.
- Alice and Bob complete the verification as defined by the selected
verification method. This could involve their clients exchanging messages,
Alice and Bob exchanging information out-of-band, and/or Alice and Bob
interacting with their devices.
- Alice's and Bob's clients send `m.key.verification.done` events to indicate
that the verification was successful.
Verifications can be cancelled by either device at any time by sending an
`m.key.verification.cancel` event with a `code` field that indicates the reason
it was cancelled.
When using to-device messages, Alice may not know which of Bob's devices to
verify, or may not want to choose a specific device. In this case, Alice will
send `m.key.verification.request` events to all of Bob's devices. All of these
events will use the same transaction ID. When Bob accepts or declines the
verification on one of his devices (sending either an
`m.key.verification.ready` or `m.key.verification.cancel` event), Alice will
send an `m.key.verification.cancel` event to Bob's other devices with a `code`
of `m.accepted` in the case where Bob accepted the verification, or `m.user` in
the case where Bob rejected the verification. This yields the following
handshake when using to-device messages, assuming both Alice and Bob each have
2 devices, Bob's first device accepts the key verification request, and Alice's
second device initiates the request. Note how Alice's first device is not
involved in the request or verification process. Also note that, although in
this example, Bob's device sends the `m.key.verification.start`, Alice's device
could also send that message. As well, the order of the
`m.key.verification.done` messages could be reversed.
```
+---------------+ +---------------+ +-------------+ +-------------+
@ -456,20 +465,85 @@ process.
| | m.key.verification.request | |
| |-------------------------------------------------->|
| | | |
| | m.key.verification.start | |
| | m.key.verification.ready | |
| |<----------------------------------| |
| | | |
| | m.key.verification.cancel | |
| |-------------------------------------------------->|
| | | |
| | m.key.verification.start | |
| |<----------------------------------| |
| | | |
.
. (verification messages)
.
| | | |
| | m.key.verification.done | |
| |<----------------------------------| |
| | | |
| | m.key.verification.done | |
| |---------------------------------->| |
| | | |
```
After the handshake, the verification process begins.
When using in-room messages and the room has encryption enabled, clients should
ensure that encryption does not hinder the verification. For example, if the
verification messages are encrypted, clients must ensure that all the
recipient's unverified devices receive the keys necessary to decrypt the
messages, even if they would normally not be given the keys to decrypt messages
in the room. Alternatively, verification messages may be sent unencrypted,
though this is not encouraged.
Upon receipt of Alice's `m.key.verification.request` message, if Bob's device
does not understand any of the methods, it should not cancel the request as one
of his other devices may support the request. Instead, Bob's device should tell
Bob that no supported method was found, and allow him to manually reject the
request.
The prompt for Bob to accept/reject Alice's request (or the unsupported method
prompt) should be automatically dismissed 10 minutes after the `timestamp` (in
the case of to-device messages) or `origin_ts` (in the case of in-room
messages) field or 2 minutes after Bob's client receives the message, whichever
comes first, if Bob does not interact with the prompt. The prompt should
additionally be hidden if an appropriate `m.key.verification.cancel` message is
received.
If Bob rejects the request, Bob's client must send an
`m.key.verification.cancel` event with `code` set to `m.user`. Upon receipt,
Alice's device should tell her that Bob does not want to verify her device and,
if the request was sent as a to-device message, send
`m.key.verification.cancel` messages to all of Bob's devices to notify them
that the request was rejected.
If Alice's and Bob's clients both send an `m.key.verification.start` message,
and both specify the same verification method, then the
`m.key.verification.start` message sent by the user whose ID is the
lexicographically largest user ID should be ignored, and the situation should
be treated the same as if only the user with the lexicographically smallest
user ID had sent the `m.key.verification.start` message. In the case where the
user IDs are the same (that is, when a user is verifying their own device),
then the device IDs should be compared instead. If the two
`m.key.verification.start` messages do not specify the same verification
method, then the verification should be cancelled with a `code` of
`m.unexpected_message`.
An `m.key.verification.start` message can also be sent independently of any
request, specifying the verification method to use.
Individual verification methods may add additional steps, events, and
properties to the verification messages. Event types for methods defined
in this specification must be under the `m.key.verification` namespace
and any other event types must be namespaced according to the Java
package naming convention.
{{% event event="m.key.verification.request" %}}
{{% event event="m.key.verification.ready" %}}
{{% event event="m.key.verification.start" %}}
{{% event event="m.key.verification.done" %}}
{{% event event="m.key.verification.cancel" %}}
##### Short Authentication String (SAS) verification
@ -493,8 +567,11 @@ example, if we verify 40 bits, then an attacker has a 1 in
success. A failed attack would result in a mismatched Short
Authentication String, alerting users to the attack.
The verification process takes place over [to-device](#send-to-device-messaging) messages in two
phases:
To advertise support for this method, clients use the name `m.sas.v1` in the
`methods` fields of the `m.key.verification.request` and
`m.key.verification.ready` events.
The verification process takes place in two phases:
1. Key agreement phase (based on [ZRTP key
agreement](https://tools.ietf.org/html/rfc6189#section-4.4.1)).
@ -505,63 +582,62 @@ The process between Alice and Bob verifying each other would be:
1. Alice and Bob establish a secure out-of-band connection, such as
meeting in-person or a video call. "Secure" here means that either
party cannot be impersonated, not explicit secrecy.
2. Alice and Bob communicate which devices they'd like to verify with
each other.
3. Alice selects Bob's device from the device list and begins
verification.
4. Alice's client ensures it has a copy of Bob's device key.
5. Alice's device sends Bob's device an `m.key.verification.start`
message.
6. Bob's device receives the message and selects a key agreement
2. Alice and Bob begin a key verification using the key verification
framework as described above.
3. Alice's device sends Bob's device an `m.key.verification.start`
message. Alice's device ensures it has a copy of Bob's device key.
4. Bob's device receives the message and selects a key agreement
protocol, hash algorithm, message authentication code, and SAS
method supported by Alice's device.
7. Bob's device ensures it has a copy of Alice's device key.
8. Bob's device creates an ephemeral Curve25519 key pair
5. Bob's device ensures it has a copy of Alice's device key.
6. Bob's device creates an ephemeral Curve25519 key pair
(*K<sub>B</sub><sup>private</sup>*,*K<sub>B</sub><sup>public</sup>*),
and calculates the hash (using the chosen algorithm) of the public
key *K<sub>B</sub><sup>public</sup>*.
9. Bob's device replies to Alice's device with an
7. Bob's device replies to Alice's device with an
`m.key.verification.accept` message.
10. Alice's device receives Bob's message and stores the commitment hash
8. Alice's device receives Bob's message and stores the commitment hash
for later use.
11. Alice's device creates an ephemeral Curve25519 key pair
9. Alice's device creates an ephemeral Curve25519 key pair
(*K<sub>A</sub><sup>private</sup>*,*K<sub>A</sub><sup>public</sup>*)
and replies to Bob's device with an `m.key.verification.key`,
sending only the public key
*K<sub>A</sub><sup>public</sup>*.
12. Bob's device receives Alice's message and replies with its own
10. Bob's device receives Alice's message and replies with its own
`m.key.verification.key` message containing its public key
*K<sub>B</sub><sup>public</sup>*.
13. Alice's device receives Bob's message and verifies the commitment
11. Alice's device receives Bob's message and verifies the commitment
hash from earlier matches the hash of the key Bob's device just sent
and the content of Alice's `m.key.verification.start` message.
14. Both Alice and Bob's devices perform an Elliptic-curve
12. Both Alice and Bob's devices perform an Elliptic-curve
Diffie-Hellman
(*ECDH(K<sub>A</sub><sup>private</sup>*,*K<sub>B</sub><sup>public</sup>*)),
using the result as the shared secret.
15. Both Alice and Bob's devices display a SAS to their users, which is
13. Both Alice and Bob's devices display a SAS to their users, which is
derived from the shared key using one of the methods in this
section. If multiple SAS methods are available, clients should allow
the users to select a method.
16. Alice and Bob compare the strings shown by their devices, and tell
14. Alice and Bob compare the strings shown by their devices, and tell
their devices if they match or not.
17. Assuming they match, Alice and Bob's devices calculate the HMAC of
15. Assuming they match, Alice and Bob's devices calculate the HMAC of
their own device keys and a comma-separated sorted list of the key
IDs that they wish the other user to verify, using SHA-256 as the
hash function. HMAC is defined in [RFC
2104](https://tools.ietf.org/html/rfc2104). The key for the HMAC is
different for each item and is calculated by generating 32 bytes
(256 bits) using [the key verification HKDF](#hkdf-calculation).
18. Alice's device sends Bob's device an `m.key.verification.mac`
16. Alice's device sends Bob's device an `m.key.verification.mac`
message containing the MAC of Alice's device keys and the MAC of her
key IDs to be verified. Bob's device does the same for Bob's device
keys and key IDs concurrently with Alice.
19. When the other device receives the `m.key.verification.mac` message,
17. When the other device receives the `m.key.verification.mac` message,
the device calculates the HMAC of its copies of the other device's
keys given in the message, as well as the HMAC of the
comma-separated, sorted, list of key IDs in the message. The device
compares these with the HMAC values given in the message, and if
everything matches then the device keys are verified.
18. Alice and Bob's devices send `m.key.verification.done` messages to complete
the verification.
The wire protocol looks like the following between Alice and Bob's
devices:
@ -865,6 +941,13 @@ example, if Alice and Bob verify each other using SAS, Alice's
`mac` property. Servers therefore must ensure that device IDs will not
collide with cross-signing public keys.
The cross-signing private keys can be stored on the server or shared with other
devices using the [Secrets](#secrets) module. When doing so, the master,
user-signing, and self-signing keys are identified using the names
`m.cross_signing.master`, `m.cross_signing.user_signing`, and
`m.cross_signing.self_signing`, respectively, and the keys are base64-encoded
before being encrypted.
###### Key and signature security
A user's master key could allow an attacker to impersonate that user to
@ -907,6 +990,135 @@ user-signing keys.
{{% http-api spec="client-server" api="cross_signing" %}}
##### QR codes
Verifying by QR codes provides a quick way to verify when one of the parties
has a device capable of scanning a QR code. The QR code encodes both parties'
master signing keys as well as a random shared secret that is used to allow
bi-directional verification from a single scan.
To advertise the ability to show a QR code, clients use the names
`m.qr_code.show.v1` and `m.reciprocate.v1` in the `methods` fields of the
`m.key.verification.request` and `m.key.verification.ready` events. To
advertise the ability to scan a QR code, clients use the names
`m.qr_code.scan.v1` and `m.reciprocate.v1` in the `methods` fields of the
`m.key.verification.request` and `m.key.verification.ready` events.
Clients that support both showing and scanning QR codes would advertise
`m.qr_code.show.v1`, `m.qr_code.scan.v1`, and `m.reciprocate.v1` as
methods.
The process between Alice and Bob verifying each other would be:
1. Alice and Bob meet in person, and want to verify each other's keys.
2. Alice and Bob begin a key verification using the key verification
framework as described above.
3. Alice's client displays a QR code that Bob is able to scan if Bob's client
indicated the ability to scan, an option to scan Bob's QR code if her client
is able to scan. Bob's client prompts displays a QR code that Alice can
scan if Alice's client indicated the ability to scan, and an option to scan
Alice's QR code if his client is able to scan. The format for the QR code
is described below. Other options, like starting SAS Emoji verification,
can be presented alongside the QR code if the devices have appropriate
support.
5. Alice scans Bob's QR code.
6. Alice's device ensures that the keys encoded in the QR code match the
expected values for the keys. If not, Alice's device displays an error
message indicating that the code is incorrect, and sends a
`m.key.verification.cancel` message to Bob's device.
Otherwise, at this point:
- Alice's device has now verified Bob's key, and
- Alice's device knows that Bob has the correct key for her.
Thus for Bob to verify Alice's key, Alice needs to tell Bob that he has the
right key.
7. Alice's device displays a message saying that the verification was
successful because the QR code's keys will have matched the keys
expected for Bob. Bob's device hasn't had a chance to verify Alice's
keys yet so wouldn't show the same message. Bob will know that
he has the right key for Alice because Alice's device will have shown
this message, as otherwise the verification would be cancelled.
8. Alice's device sends an `m.key.verification.start` message with `method` set
to `m.reciprocate.v1` to Bob (see below). The message includes the shared
secret from the QR code. This signals to Bob's device that Alice has
scanned Bob's QR code.
This message is merely a signal for Bob's device to proceed to the next
step, and is not used for verification purposes.
9. Upon receipt of the `m.key.verification.start` message, Bob's device ensures
that the shared secret matches.
If the shared secret does not match, it should display an error message
indicating that an attack was attempted. (This does not affect Alice's
verification of Bob's keys.)
If the shared secret does match, it asks Bob to confirm that Alice
has scanned the QR code.
10. Bob sees Alice's device confirm that the key matches, and presses the button
on his device to indicate that Alice's key is verified.
Bob's verification of Alice's key hinges on Alice telling Bob the result of
her scan. Since the QR code includes what Bob thinks Alice's key is,
Alice's device can check whether Bob has the right key for her. Alice has
no motivation to lie about the result, as getting Bob to trust an incorrect
key would only affect communications between herself and Bob. Thus Alice
telling Bob that the code was scanned successfully is sufficient for Bob to
trust Alice's key, under the assumption that this communication is done
over a trusted medium (such as in-person).
11. Both devices send an `m.key.verification.done` message.
###### QR code format
The QR codes to be displayed and scanned using this format will encode binary
strings in the general form:
- the ASCII string `MATRIX`
- one byte indicating the QR code version (must be `0x02`)
- one byte indicating the QR code verification mode. Should be one of the
following values:
- `0x00` verifying another user with cross-signing
- `0x01` self-verifying in which the current device does trust the master key
- `0x02` self-verifying in which the current device does not yet trust the
master key
- the event ID or `transaction_id` of the associated verification
request event, encoded as:
- two bytes in network byte order (big-endian) indicating the length in
bytes of the ID as a UTF-8 string
- the ID as a UTF-8 string
- the first key, as 32 bytes. The key to use depends on the mode field:
- if `0x00` or `0x01`, then the current user's own master cross-signing public key
- if `0x02`, then the current device's device key
- the second key, as 32 bytes. The key to use depends on the mode field:
- if `0x00`, then what the device thinks the other user's master
cross-signing key is
- if `0x01`, then what the device thinks the other device's device key is
- if `0x02`, then what the device thinks the user's master cross-signing key
is
- a random shared secret, as a byte string. It is suggested to use a secret
that is about 8 bytes long. Note: as we do not share the length of the
secret, and it is not a fixed size, clients will just use the remainder of
binary string as the shared secret.
For example, if Alice displays a QR code encoding the following binary string:
```
"MATRIX" |ver|mode| len | event ID
4D 41 54 52 49 58 02 00 00 2D 21 41 42 43 44 ...
| user's cross-signing key | other user's cross-signing key | shared secret
00 01 02 03 04 05 06 07 ... 10 11 12 13 14 15 16 17 ... 20 21 22 23 24 25 26 27
```
this indicates that Alice is verifying another user (say Bob), in response to
the request from event "$ABCD...", her cross-signing key is
`0001020304050607...` (which is "AAECAwQFBg..." in base64), she thinks that
Bob's cross-signing key is `1011121314151617...` (which is "EBESExQVFh..." in
base64), and the shared secret is `2021222324252627` (which is "ICEiIyQlJic" in
base64).
###### Verification messages specific to QR codes
{{% event event="m.key.verification.start$m.reciprocate.v1" %}}
#### Sharing keys between devices
If Bob has an encrypted conversation with Alice on his computer, and
@ -1004,6 +1216,11 @@ as follows:
When reading in a recovery key, clients must disregard whitespace, and
perform the reverse of steps 1 through 3.
The recovery key can also be stored on the server or shared with other devices
using the [Secrets](#secrets) module. When doing so, it is identified using the
name `m.megolm_backup.v1`, and the key is base64-encoded before being
encrypted.
###### Backup algorithm: `m.megolm_backup.v1.curve25519-aes-sha2`
When a backup is created with the `algorithm` set to

@ -53,7 +53,7 @@ tags to permit, denying the use and rendering of anything else, is:
`font`, `del`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `blockquote`, `p`,
`a`, `ul`, `ol`, `sup`, `sub`, `li`, `b`, `i`, `u`, `strong`, `em`,
`strike`, `code`, `hr`, `br`, `div`, `table`, `thead`, `tbody`, `tr`,
`th`, `td`, `caption`, `pre`, `span`, `img`.
`th`, `td`, `caption`, `pre`, `span`, `img`, `details`, `summary`.
Not all attributes on those tags should be permitted as they may be
avenues for other disruption attempts, such as adding `onclick` handlers
@ -63,10 +63,11 @@ are listed, clients should translate the value (a 6-character hex color
code) to the appropriate CSS/attributes for the tag.
`font`
`data-mx-bg-color`, `data-mx-color`
`data-mx-bg-color`, `data-mx-color`, `color`
`span`
`data-mx-bg-color`, `data-mx-color`
`data-mx-bg-color`, `data-mx-color`, `data-mx-spoiler` (see
[spoiler messages](#spoiler-messages))
`a`
`name`, `target`, `href` (provided the value is not relative and has a
@ -461,6 +462,52 @@ For `m.image`, the text should be `"sent an image."`. For `m.video`, the
text should be `"sent a video."`. For `m.audio`, the text should be
`"sent an audio file"`.
##### Spoiler messages
Parts of a message can be hidden visually from the user through use of spoilers.
This does not affect the server's representation of the event content - it
is simply a visual cue to the user that the message may reveal important
information about something, spoiling any relevant surprise.
To send spoilers clients MUST use the `formatted_body` and therefore the
`org.matrix.custom.html` format, described above. This makes spoilers valid on
any `msgtype` which can support this format appropriately.
Spoilers themselves are contained with `span` tags, with the reason (optionally)
being in the `data-mx-spoiler` attribute. Spoilers without a reason must at least
specify the attribute, though the value may be empty/undefined.
An example of a spoiler is:
```json
{
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"body": "Alice [Spoiler](mxc://example.org/abc123) in the movie.",
"formatted_body": "Alice <span data-mx-spoiler>lived happily ever after</span> in the movie."
}
```
If a reason were to be supplied, it would look like:
```json
{
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"body": "Alice [Spoiler for health of Alice](mxc://example.org/abc123) in the movie.",
"formatted_body": "Alice <span data-mx-spoiler='health of alice'>lived happily ever after</span> in the movie."
}
```
When sending a spoiler, clients SHOULD provide the plain text fallback in the `body`
as shown above (including the reason). The fallback SHOULD omit the spoiler text verbatim
since `body` might show up in text-only clients or in notifications. To prevent spoilers
showing up in such situations, clients are strongly encouraged to first upload the plaintext
to the media repository then reference the MXC URI in a markdown-style link, as shown above.
Clients SHOULD render spoilers differently with some sort of disclosure. For example, the
client could blur the actual text and ask the user to click on it for it to be revealed.
#### Server behaviour
Homeservers SHOULD reject `m.room.message` events which don't have a

@ -42,7 +42,7 @@ passphrases](#deriving-keys-from-passphrases).
| Parameter | Type | Description
|------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------|
| name | string | **Required.** The name of the key. |
| name | string | Optional. The name of the key. If not given, the client may use a generic name such as "Unnamed key", or "Default key" if the key is marked as the default key (see below). |
| algorithm | string | **Required.** The encryption algorithm to be used for this key. Currently, only `m.secret_storage.v1.aes-hmac-sha2` is supported. |
| passphrase | string | See [deriving keys from passphrases](#deriving-keys-from-passphrases) section for a description of this property. |
@ -56,6 +56,18 @@ will be used to encrypt all secrets that the user would expect to be
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
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.
`DefaultKey`
| Parameter | Type | Description
|------------|-----------|------------------------------------------|
| key | string | **Required.** The ID of the default key. |
##### Secret storage
Encrypted data is stored in the user's account\_data using the event
@ -118,6 +130,16 @@ and the key descriptions for the keys would be:
}
```
If `key_id_1` is the default key, then we also have:
`m.secret_storage.default_key`:
```
{
"key": "key_id_1"
}
```
###### `m.secret_storage.v1.aes-hmac-sha2`
Secrets encrypted using the `m.secret_storage.v1.aes-hmac-sha2`

@ -10,3 +10,4 @@ weight: 60
* [Room Version 4](v4)
* [Room Version 5](v5)
* [Room Version 6](v6)
* [Room Version 7](v7)

@ -0,0 +1,52 @@
---
title: Room Version 7
type: docs
weight: 60
---
This room version builds on [version 6](/rooms/v6) to introduce knocking
as a possible join rule and membership state.
## Client considerations
This is the first room version to support knocking completely. As such,
users will not be able to knock on rooms which are not based off v7.
## Server implementation components
{{% boxes/warning %}}
The information contained in this section is strictly for server
implementors. Applications which use the Client-Server API are generally
unaffected by the intricacies contained here. The section above
regarding client considerations is the resource that Client-Server API
use cases should reference.
{{% /boxes/warning %}}
Room version 7 adds new authorization rules for events to support knocking.
[Room version 6](/rooms/v6) has details of other authorization rule changes,
as do the versions v6 is based upon.
For checks perfomed upon `m.room.member` events, the following conditions
are added in context:
If type is `m.room.member`:
...
* If `membership` is `ban`:
...
* If `membership` is `knock`:
i. If the `join_rule` is anything other than `knock`, reject.
ii. If `sender` does not match `state_key`, reject.
iii. If the `sender`'s current membership is not `ban`, `invite`, or `join`, allow.
iv. Otherwise, reject.
...
The remaining rules are the same as in [room version 6](/rooms/v6#authorization-rules-for-events).

@ -18,7 +18,7 @@ signatures in HTTP Authorization headers at the HTTP layer.
There are three main kinds of communication that occur between
homeservers:
Persisted Data Units (PDUs):
Persisted Data Units (PDUs):
These events are broadcast from one homeserver to any others that have
joined the same room (identified by Room ID). They are persisted in
long-term storage and record the history of messages and state for a
@ -29,12 +29,12 @@ to deliver that event to its recipient servers. However PDUs are signed
using the originating server's private key so that it is possible to
deliver them through third-party servers.
Ephemeral Data Units (EDUs):
Ephemeral Data Units (EDUs):
These events are pushed between pairs of homeservers. They are not
persisted and are not part of the history of a room, nor does the
receiving homeserver have to reply to them.
Queries:
Queries:
These are single request/response interactions between a given pair of
servers, initiated by one side sending an HTTPS GET request to obtain
some information, and responded by the other. They are not persisted and
@ -365,19 +365,19 @@ them.
#### Definitions
Required Power Level
Required Power Level
A given event type has an associated *required power level*. This is
given by the current `m.room.power_levels` event. The event type is
either listed explicitly in the `events` section or given by either
`state_default` or `events_default` depending on if the event is a state
event or not.
Invite Level, Kick Level, Ban Level, Redact Level
Invite Level, Kick Level, Ban Level, Redact Level
The levels given by the `invite`, `kick`, `ban`, and `redact` properties
in the current `m.room.power_levels` state. Each defaults to 50 if
unspecified.
Target User
Target User
For an `m.room.member` state event, the user given by the `state_key` of
the event.
@ -720,6 +720,24 @@ other servers participating in the room.
{{% http-api spec="server-server" api="joins-v2" %}}
## Knocking upon a room
Rooms can permit knocking through the join rules, and if permitted this
gives users a way to request to join (be invited) to the room. Users who
knock on a room where the server is already a resident of the room can
just send the knock event directly without using this process, however
much like [joining rooms](/server-server-api/#joining-rooms) the server
must handshake their way into having the knock sent on its behalf.
The handshake is largely the same as the joining rooms handshake, where
instead of a "joining server" there is a "knocking server", and the APIs
to be called are different (`/make_knock` and `/send_knock`).
Servers can retract knocks over federation by leaving the room, as described
below for rejecting invites.
{{% http-api spec="server-server" api="knocks" %}}
## Inviting to a room
When a user on a given homeserver invites another user on the same
@ -728,6 +746,10 @@ the process defined here. However, when a user invites another user on a
different homeserver, a request to that homeserver to have the event
signed and verified must be made.
Note that invites are used to indicate that knocks were accepted. As such,
receiving servers should be prepared to manually link up a previous knock
to an invite if the invite event does not directly reference the knock.
{{% http-api spec="server-server" api="invites-v1" %}}
{{% http-api spec="server-server" api="invites-v2" %}}
@ -735,10 +757,10 @@ signed and verified must be made.
## Leaving Rooms (Rejecting Invites)
Normally homeservers can send appropriate `m.room.member` events to have
users leave the room, or to reject local invites. Remote invites from
other homeservers do not involve the server in the graph and therefore
need another approach to reject the invite. Joining the room and
promptly leaving is not recommended as clients and servers will
users leave the room, to reject local invites, or to retract a knock.
Remote invites/knocks from other homeservers do not involve the server in the
graph and therefore need another approach to reject the invite. Joining
the room and promptly leaving is not recommended as clients and servers will
interpret that as accepting the invite, then leaving the room rather
than rejecting the invite.
@ -1009,6 +1031,8 @@ The following endpoint prefixes MUST be protected:
- `/_matrix/federation/v2/send_leave`
- `/_matrix/federation/v1/invite`
- `/_matrix/federation/v2/invite`
- `/_matrix/federation/v1/make_knock`
- `/_matrix/federation/v1/send_knock`
- `/_matrix/federation/v1/state`
- `/_matrix/federation/v1/state_ids`
- `/_matrix/federation/v1/backfill`

@ -18,7 +18,7 @@
"Pizza": "Pizza",
"Cake": "Gâteau",
"Heart": "Cœur",
"Hat": "Châpeau",
"Hat": "Chapeau",
"Glasses": "Lunettes",
"Hourglass": "Sablier",
"Book": "Livre",
@ -41,7 +41,7 @@
"Robot": "Robot",
"Spanner": "Clé à molette",
"Santa": "Père Noël",
"Thumbs Up": "Pouce en l'air",
"Thumbs Up": "Pouce en lair",
"Umbrella": "Parapluie",
"Clock": "Réveil",
"Gift": "Cadeau",

@ -0,0 +1,28 @@
{
"Folder": "Asdaw",
"Guitar": "Agiṭaṛ",
"Ball": "Tcama",
"Flag": "Acenyal",
"Telephone": "Atilifun",
"Key": "Tasarut",
"Book": "Adlis",
"Hat": "Taraza",
"Robot": "Aṛubu",
"Heart": "Ul",
"Apple": "Tadeffuyt",
"Banana": "Tabanant",
"Fire": "Timessi",
"Moon": "Ayyur",
"Mushroom": "Agursel",
"Tree": "Aseklu",
"Fish": "Aselm",
"Turtle": "Ifker",
"Rooster": "Ayaẓiḍ",
"Rabbit": "Agnin",
"Elephant": "Ilu",
"Pig": "Ilef",
"Horse": "Ayyis",
"Lion": "Izem",
"Cat": "Amuc",
"Dog": "Aydi"
}

@ -27,6 +27,7 @@
"sr": "пас",
"sv": "Hund",
"szl": null,
"tzm": "Aydi",
"uk": "Пес",
"zh_Hans": "狗"
}
@ -59,6 +60,7 @@
"sr": "мачка",
"sv": "Katt",
"szl": null,
"tzm": "Amuc",
"uk": "Кіт",
"zh_Hans": "猫"
}
@ -91,6 +93,7 @@
"sr": "лав",
"sv": "Lejon",
"szl": null,
"tzm": "Izem",
"uk": "Лев",
"zh_Hans": "狮子"
}
@ -123,6 +126,7 @@
"sr": "коњ",
"sv": "Häst",
"szl": null,
"tzm": "Ayyis",
"uk": "Кінь",
"zh_Hans": "马"
}
@ -155,6 +159,7 @@
"sr": "једнорог",
"sv": "Enhörning",
"szl": null,
"tzm": null,
"uk": "Єдиноріг",
"zh_Hans": "独角兽"
}
@ -187,6 +192,7 @@
"sr": "прасе",
"sv": "Gris",
"szl": null,
"tzm": "Ilef",
"uk": "Свиня",
"zh_Hans": "猪"
}
@ -219,6 +225,7 @@
"sr": "слон",
"sv": "Elefant",
"szl": null,
"tzm": "Ilu",
"uk": "Слон",
"zh_Hans": "大象"
}
@ -251,6 +258,7 @@
"sr": "зец",
"sv": "Kanin",
"szl": null,
"tzm": "Agnin",
"uk": "Кріль",
"zh_Hans": "兔子"
}
@ -283,6 +291,7 @@
"sr": "панда",
"sv": "Panda",
"szl": null,
"tzm": null,
"uk": "Панда",
"zh_Hans": "熊猫"
}
@ -315,6 +324,7 @@
"sr": "петао",
"sv": "Tupp",
"szl": null,
"tzm": "Ayaẓiḍ",
"uk": "Когут",
"zh_Hans": "公鸡"
}
@ -347,6 +357,7 @@
"sr": "пингвин",
"sv": "Pingvin",
"szl": null,
"tzm": null,
"uk": "Пінгвін",
"zh_Hans": "企鹅"
}
@ -379,6 +390,7 @@
"sr": "корњача",
"sv": "Sköldpadda",
"szl": null,
"tzm": "Ifker",
"uk": "Черепаха",
"zh_Hans": "乌龟"
}
@ -411,6 +423,7 @@
"sr": "риба",
"sv": "Fisk",
"szl": null,
"tzm": "Aselm",
"uk": "Риба",
"zh_Hans": "鱼"
}
@ -443,6 +456,7 @@
"sr": "октопод",
"sv": "Bläckfisk",
"szl": null,
"tzm": null,
"uk": "Восьминіг",
"zh_Hans": "章鱼"
}
@ -475,6 +489,7 @@
"sr": "лептир",
"sv": "Fjäril",
"szl": null,
"tzm": null,
"uk": "Метелик",
"zh_Hans": "蝴蝶"
}
@ -507,6 +522,7 @@
"sr": "цвет",
"sv": "Blomma",
"szl": null,
"tzm": null,
"uk": "Квітка",
"zh_Hans": "花"
}
@ -539,6 +555,7 @@
"sr": "дрво",
"sv": "Träd",
"szl": null,
"tzm": "Aseklu",
"uk": "Дерево",
"zh_Hans": "树"
}
@ -571,6 +588,7 @@
"sr": "кактус",
"sv": "Kaktus",
"szl": null,
"tzm": null,
"uk": "Кактус",
"zh_Hans": "仙人掌"
}
@ -603,6 +621,7 @@
"sr": "печурка",
"sv": "Svamp",
"szl": null,
"tzm": "Agursel",
"uk": "Гриб",
"zh_Hans": "蘑菇"
}
@ -635,6 +654,7 @@
"sr": "глобус",
"sv": "Jordklot",
"szl": null,
"tzm": null,
"uk": "Глобус",
"zh_Hans": "地球"
}
@ -667,6 +687,7 @@
"sr": "месец",
"sv": "Måne",
"szl": null,
"tzm": "Ayyur",
"uk": "Місяць",
"zh_Hans": "月亮"
}
@ -699,6 +720,7 @@
"sr": "облак",
"sv": "Moln",
"szl": null,
"tzm": null,
"uk": "Хмара",
"zh_Hans": "云"
}
@ -731,6 +753,7 @@
"sr": "ватра",
"sv": "Eld",
"szl": null,
"tzm": "Timessi",
"uk": "Вогонь",
"zh_Hans": "火"
}
@ -763,6 +786,7 @@
"sr": "банана",
"sv": "Banan",
"szl": null,
"tzm": "Tabanant",
"uk": "Банан",
"zh_Hans": "香蕉"
}
@ -795,6 +819,7 @@
"sr": "јабука",
"sv": "Äpple",
"szl": null,
"tzm": "Tadeffuyt",
"uk": "Яблуко",
"zh_Hans": "苹果"
}
@ -827,6 +852,7 @@
"sr": "јагода",
"sv": "Jordgubbe",
"szl": null,
"tzm": null,
"uk": "Полуниця",
"zh_Hans": "草莓"
}
@ -859,6 +885,7 @@
"sr": "кукуруз",
"sv": "Majs",
"szl": null,
"tzm": null,
"uk": "Кукурудза",
"zh_Hans": "玉米"
}
@ -891,6 +918,7 @@
"sr": "пица",
"sv": "Pizza",
"szl": null,
"tzm": null,
"uk": "Піца",
"zh_Hans": "披萨"
}
@ -923,6 +951,7 @@
"sr": "торта",
"sv": "Tårta",
"szl": null,
"tzm": null,
"uk": "Пиріг",
"zh_Hans": "蛋糕"
}
@ -955,6 +984,7 @@
"sr": "срце",
"sv": "Hjärta",
"szl": null,
"tzm": "Ul",
"uk": "Серце",
"zh_Hans": "心"
}
@ -987,6 +1017,7 @@
"sr": "смајли",
"sv": "Smiley",
"szl": null,
"tzm": null,
"uk": "Посмішка",
"zh_Hans": "笑脸"
}
@ -1019,6 +1050,7 @@
"sr": "робот",
"sv": "Robot",
"szl": null,
"tzm": "Aṛubu",
"uk": "Робот",
"zh_Hans": "机器人"
}
@ -1038,7 +1070,7 @@
"es": "Sombrero",
"et": "Kübar",
"fi": "Hattu",
"fr": "Châpeau",
"fr": "Chapeau",
"hr": "kapa",
"it": "Cappello",
"ja": "帽子",
@ -1051,6 +1083,7 @@
"sr": "шешир",
"sv": "Hatt",
"szl": null,
"tzm": "Taraza",
"uk": "Капелюх",
"zh_Hans": "帽子"
}
@ -1083,6 +1116,7 @@
"sr": "наочаре",
"sv": "Glasögon",
"szl": null,
"tzm": null,
"uk": "Окуляри",
"zh_Hans": "眼镜"
}
@ -1115,6 +1149,7 @@
"sr": "кључ",
"sv": "Skruvnyckel",
"szl": null,
"tzm": null,
"uk": "Гайковий ключ",
"zh_Hans": "扳手"
}
@ -1147,6 +1182,7 @@
"sr": "деда Мраз",
"sv": "Tomte",
"szl": null,
"tzm": null,
"uk": "Санта Клаус",
"zh_Hans": "圣诞老人"
}
@ -1166,7 +1202,7 @@
"es": "Pulgar arriba",
"et": "Pöidlad püsti",
"fi": "Peukalo ylös",
"fr": "Pouce en l'air",
"fr": "Pouce en lair",
"hr": "palac gore",
"it": "Pollice alzato",
"ja": "いいね",
@ -1179,6 +1215,7 @@
"sr": "палчић горе",
"sv": "Tummen upp",
"szl": null,
"tzm": null,
"uk": "Великий палець вгору",
"zh_Hans": "赞"
}
@ -1211,6 +1248,7 @@
"sr": "кишобран",
"sv": "Paraply",
"szl": null,
"tzm": null,
"uk": "Парасолька",
"zh_Hans": "伞"
}
@ -1243,6 +1281,7 @@
"sr": "пешчаник",
"sv": "Timglas",
"szl": null,
"tzm": null,
"uk": "Пісковий годинник",
"zh_Hans": "沙漏"
}
@ -1275,6 +1314,7 @@
"sr": "сат",
"sv": "Klocka",
"szl": null,
"tzm": null,
"uk": "Годинник",
"zh_Hans": "时钟"
}
@ -1307,6 +1347,7 @@
"sr": "поклон",
"sv": "Present",
"szl": null,
"tzm": null,
"uk": "Подарунок",
"zh_Hans": "礼物"
}
@ -1339,6 +1380,7 @@
"sr": "сијалица",
"sv": "Lampa",
"szl": null,
"tzm": null,
"uk": "Лампочка",
"zh_Hans": "灯泡"
}
@ -1371,6 +1413,7 @@
"sr": "књига",
"sv": "Bok",
"szl": null,
"tzm": "Adlis",
"uk": "Книга",
"zh_Hans": "书"
}
@ -1403,6 +1446,7 @@
"sr": "оловка",
"sv": "Penna",
"szl": null,
"tzm": null,
"uk": "Олівець",
"zh_Hans": "铅笔"
}
@ -1435,6 +1479,7 @@
"sr": "спајалица",
"sv": "Gem",
"szl": null,
"tzm": null,
"uk": "Спиначка",
"zh_Hans": "回形针"
}
@ -1467,6 +1512,7 @@
"sr": "маказе",
"sv": "Sax",
"szl": null,
"tzm": null,
"uk": "Ножиці",
"zh_Hans": "剪刀"
}
@ -1499,6 +1545,7 @@
"sr": "катанац",
"sv": "Lås",
"szl": null,
"tzm": null,
"uk": "Замок",
"zh_Hans": "锁"
}
@ -1531,6 +1578,7 @@
"sr": "кључ",
"sv": "Nyckel",
"szl": null,
"tzm": "Tasarut",
"uk": "Ключ",
"zh_Hans": "钥匙"
}
@ -1563,6 +1611,7 @@
"sr": "чекић",
"sv": "Hammare",
"szl": null,
"tzm": null,
"uk": "Молоток",
"zh_Hans": "锤子"
}
@ -1595,6 +1644,7 @@
"sr": "телефон",
"sv": "Telefon",
"szl": null,
"tzm": "Atilifun",
"uk": "Телефон",
"zh_Hans": "电话"
}
@ -1627,6 +1677,7 @@
"sr": "застава",
"sv": "Flagga",
"szl": null,
"tzm": "Acenyal",
"uk": "Прапор",
"zh_Hans": "旗帜"
}
@ -1659,6 +1710,7 @@
"sr": "воз",
"sv": "Tåg",
"szl": null,
"tzm": null,
"uk": "Потяг",
"zh_Hans": "火车"
}
@ -1691,6 +1743,7 @@
"sr": "бицикл",
"sv": "Cykel",
"szl": null,
"tzm": null,
"uk": "Велосипед",
"zh_Hans": "自行车"
}
@ -1723,6 +1776,7 @@
"sr": "авион",
"sv": "Flygplan",
"szl": null,
"tzm": null,
"uk": "Літак",
"zh_Hans": "飞机"
}
@ -1755,6 +1809,7 @@
"sr": "ракета",
"sv": "Raket",
"szl": null,
"tzm": null,
"uk": "Ракета",
"zh_Hans": "火箭"
}
@ -1787,6 +1842,7 @@
"sr": "пехар",
"sv": "Trofé",
"szl": null,
"tzm": null,
"uk": "Приз",
"zh_Hans": "奖杯"
}
@ -1819,6 +1875,7 @@
"sr": "лопта",
"sv": "Boll",
"szl": null,
"tzm": "Tcama",
"uk": "М'яч",
"zh_Hans": "球"
}
@ -1851,6 +1908,7 @@
"sr": "гитара",
"sv": "Gitarr",
"szl": null,
"tzm": "Agiṭaṛ",
"uk": "Гітара",
"zh_Hans": "吉他"
}
@ -1883,6 +1941,7 @@
"sr": "труба",
"sv": "Trumpet",
"szl": null,
"tzm": null,
"uk": "Труба",
"zh_Hans": "喇叭"
}
@ -1915,6 +1974,7 @@
"sr": "звоно",
"sv": "Bjällra",
"szl": null,
"tzm": null,
"uk": "Дзвін",
"zh_Hans": "铃铛"
}
@ -1947,6 +2007,7 @@
"sr": "сидро",
"sv": "Ankare",
"szl": null,
"tzm": null,
"uk": "Якір",
"zh_Hans": "锚"
}
@ -1979,6 +2040,7 @@
"sr": "слушалице",
"sv": "Hörlurar",
"szl": null,
"tzm": null,
"uk": "Навушники",
"zh_Hans": "耳机"
}
@ -2011,6 +2073,7 @@
"sr": "фасцикла",
"sv": "Mapp",
"szl": null,
"tzm": "Asdaw",
"uk": "Тека",
"zh_Hans": "文件夹"
}
@ -2043,6 +2106,7 @@
"sr": "чиода",
"sv": "Häftstift",
"szl": null,
"tzm": null,
"uk": "Кнопка",
"zh_Hans": "图钉"
}

@ -1,4 +1,4 @@
# Copyright 2018 New Vector Ltd
# Copyright 2018, 2021 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -69,6 +69,13 @@ properties:
avatar_url:
type: string
description: The URL for the room's avatar, if one is set.
join_rule:
type: string
description: |-
The room's join rule. When not present, the room is assumed to
be `public`. Note that rooms with `invite` join rules are not
expected here, but rooms with `knock` rules are given their
near-public nature.
next_batch:
type: string
description: |-
@ -90,13 +97,14 @@ example: {
"chunk": [
{
"aliases": ["#murrays:cheese.bar"],
"avatar_url": "mxc://bleeker.street/CHEDDARandBRIE",
"avatar_url": "mxc://bleecker.street/CHEDDARandBRIE",
"guest_can_join": false,
"name": "CHEESE",
"num_joined_members": 37,
"room_id": "!ol19s:bleecker.street",
"topic": "Tasty tasty cheese",
"world_readable": true
"world_readable": true,
"join_rule": "public"
}
],
"next_batch": "p190q",

@ -0,0 +1,124 @@
# Copyright 2021 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
swagger: '2.0'
info:
title: "Matrix Client-Server Room Knocking API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
$ref: definitions/security.yaml
paths:
"/knock/{roomIdOrAlias}":
post:
summary: Knock on a room, requesting permission to join.
description: |-
*Note that this API takes either a room ID or alias, unlike other membership APIs.*
This API "knocks" on the room to ask for permission to join, if the user
is allowed to knock on the room. Acceptance of the knock happens out of
band from this API, meaning that the client will have to watch for updates
regarding the acceptance/rejection of the knock.
If the room history settings allow, the user will still be able to see
history of the room while being in the "knock" state. The user will have
to accept the invitation to join the room (acceptance of knock) to see
messages reliably. See the `/join` endpoints for more information about
history visibility to the user.
The knock will appear as an entry in the response of the
[`/sync`](/client-server-api/#get_matrixclientr0sync) API.
operationId: knockRoom
security:
- accessToken: []
parameters:
- in: path
type: string
name: roomIdOrAlias
description: The room identifier or alias to knock upon.
required: true
x-example: "#monkeys:matrix.org"
- in: query
type: array
items:
type: string
name: server_name
description: |-
The servers to attempt to knock on the room through. One of the servers
must be participating in the room.
x-example: ["matrix.org", "elsewhere.ca"]
- in: body
name: body
required: true
schema:
type: object
properties:
reason:
type: string
description: |-
Optional reason to be included as the `reason` on the subsequent
membership event.
example: "Looking for support"
responses:
200:
description: |-
The room has been knocked upon.
The knocked room ID must be returned in the `room_id` field.
examples:
application/json: {
"room_id": "!d41d8cd:matrix.org"
}
schema:
type: object
properties:
room_id:
type: string
description: The knocked room ID.
required: ["room_id"]
403:
description: |-
You do not have permission to knock on the room. A meaningful `errcode`
and description error text will be returned. Example reasons for rejection are:
- The room is not set up for knocking.
- The user has been banned from the room.
examples:
application/json: {
"errcode": "M_FORBIDDEN", "error": "You are not allowed to knock on this room."
}
schema:
"$ref": "definitions/errors/error.yaml"
404:
description: |-
The room could not be found or resolved to a room ID.
examples:
application/json: {
"errcode": "M_NOT_FOUND", "error": "That room does not appear to exist."
}
schema:
"$ref": "definitions/errors/error.yaml"
429:
description: This request was rate-limited.
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- Room membership

@ -1,4 +1,4 @@
# Copyright 2016 OpenMarket Ltd
# Copyright 2016, 2021 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -281,6 +281,28 @@ paths:
items:
$ref: "../../event-schemas/schema/stripped_state.yaml"
type: array
knock:
title: Knocked rooms
type: object
description: |-
The rooms that the user has knocked upon, mapped as room ID to room information.
additionalProperties:
title: Knocked Room
type: object
properties:
knock_state:
title: KnockState
type: object
description: |-
The state of a room that the user has knocked upon. The state
events contained here have the same restrictions as `InviteState`
above.
properties:
events:
description: The StrippedState events that form the knock state.
items:
$ref: "../../event-schemas/schema/stripped_state.yaml"
type: array
leave:
title: Left rooms
type: object
@ -436,6 +458,26 @@ paths:
}
}
},
"knock": {
"!223asd456:example.com": {
"invite_state": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.room.name",
"state_key": "",
"content": {"name": "My Room Name"}
},
{
"sender": "@bob:example.com",
"type": "m.room.member",
"state_key": "@bob:example.com",
"content": {"membership": "knock"}
}
]
}
}
},
"leave": {}
}
}

@ -35,7 +35,7 @@ allOf:
sender:
type: string
description: User ID of the sender.
example: "john@example.com"
example: "@john:example.com"
type:
type: string
description: Event type for the message.
@ -59,7 +59,7 @@ allOf:
title: Device Message Contents
properties: {}
example: {
"alice@example.org": {
"@alice:example.org": {
"IWHQUZUIAH": {
"algorithm": "m.megolm.v1.aes-sha2",
"room_id": "!Cuyf34gef24t:localhost",

@ -0,0 +1,322 @@
# Copyright 2021 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
swagger: '2.0'
info:
title: "Matrix Federation Knock Room API"
version: "1.0.0"
host: localhost:8448
schemes:
- https
basePath: /_matrix/federation/v1
consumes:
- application/json
produces:
- application/json
securityDefinitions:
$ref: definitions/security.yaml
paths:
"/make_knock/{roomId}/{userId}":
get:
summary: Get information required to make a knock event for a room.
description: |-
Asks the receiving server to return information that the sending
server will need to prepare a knock event for the room.
operationId: makeKnock
security:
- signedRequest: []
parameters:
- in: path
name: roomId
type: string
description: The room ID that is about to be knocked.
required: true
x-example: "!abc123:example.org"
- in: path
name: userId
type: string
description: The user ID the knock event will be for.
required: true
x-example: "@someone:example.org"
- in: query
type: array
items:
type: string
name: ver
description: |-
The room versions the sending server has support for.
required: true # knocking was supported in v7
x-example: ["1", "7"]
responses:
200:
description: |-
A template to be used for the rest of the [Knocking Rooms](/server-server-api/#knocking-rooms)
handshake. Note that events have a different format depending on room version - check the
[room version specification](/#room-versions) for precise event formats. **The response body
here describes the common event fields in more detail and may be missing other
required fields for a PDU.**
schema:
type: object
properties:
room_version:
type: string
description: |-
The version of the room where the server is trying to knock.
example: "7"
event:
description: |-
An unsigned template event. Note that events have a different format
depending on the room version - check the [room version specification](/#room-versions)
for precise event formats.
type: object
title: Event Template
properties:
sender:
type: string
description: The user ID of the knocking member.
example: "@someone:example.org"
origin:
type: string
description: The name of the resident homeserver.
example: "matrix.org"
origin_server_ts:
type: integer
format: int64
description: A timestamp added by the resident homeserver.
example: 1234567890
type:
type: string
description: The value `m.room.member`.
example: "m.room.member"
state_key:
type: string
description: The user ID of the knocking member.
example: "@someone:example.org"
content:
type: object
title: Membership Event Content
description: The content of the event.
example: {"membership": "knock"}
properties:
membership:
type: string
description: The value `knock`.
example: "knock"
required: ['membership']
required:
- state_key
- origin
- origin_server_ts
- type
- content
- sender
required:
- room_version # knocking was added in v7
- event
examples:
application/json: {
"room_version": "7",
"event": {
"$ref": "examples/minimal_pdu.json",
"type": "m.room.member",
"state_key": "@someone:example.org",
"origin": "example.org",
"origin_server_ts": 1549041175876,
"sender": "@someone:example.org",
"content": {
"membership": "knock"
}
}
}
400:
description: |-
The request is invalid or the room the server is attempting
to knock upon has a version that is not listed in the `ver`
parameters.
The error should be passed through to clients so that they
may give better feedback to users.
schema:
allOf:
- $ref: "../client-server/definitions/errors/error.yaml"
- type: object
properties:
room_version:
type: string
description: |-
The version of the room. Required if the `errcode`
is `M_INCOMPATIBLE_ROOM_VERSION`.
examples:
application/json: {
"errcode": "M_INCOMPATIBLE_ROOM_VERSION",
"error": "Your homeserver does not support the features required to knock on this room",
"room_version": "7"
}
404:
description: |-
The room that the knocking server is attempting to knock upon is unknown
to the receiving server.
schema:
allOf:
- $ref: "../client-server/definitions/errors/error.yaml"
examples:
application/json: {
"errcode": "M_NOT_FOUND",
"error": "Unknown room",
}
403:
description: |-
The knocking server or user is not permitted to knock on the room, such as when the
server/user is banned or the room is not set up for receiving knocks.
schema:
allOf:
- $ref: "../client-server/definitions/errors/error.yaml"
examples:
application/json: {
"errcode": "M_FORBIDDEN",
"error": "You are not permitted to knock on this room",
}
"/send_knock/{roomId}/{eventId}":
put:
summary: Submit a signed knock event to a resident server.
description: |-
Submits a signed knock event to the resident server for it to
accept into the room's graph. Note that events have
a different format depending on the room version - check
the [room version specification](/#room-versions) for precise event formats.
**The request and response body here describe the common
event fields in more detail and may be missing other required
fields for a PDU.**
operationId: sendKnock
security:
- signedRequest: []
parameters:
- in: path
name: roomId
type: string
description: The room ID that is about to be knocked upon.
required: true
x-example: "!abc123:example.org"
- in: path
name: eventId
type: string
description: The event ID for the knock event.
required: true
x-example: "$abc123:example.org"
- in: body
name: body
type: object
required: true
schema:
type: object
properties:
sender:
type: string
description: The user ID of the knocking member.
example: "@someone:example.org"
origin:
type: string
description: The name of the knocking homeserver.
example: "matrix.org"
origin_server_ts:
type: integer
format: int64
description: A timestamp added by the knocking homeserver.
example: 1234567890
type:
type: string
description: The value `m.room.member`.
example: "m.room.member"
state_key:
type: string
description: The user ID of the knocking member.
example: "@someone:example.org"
content:
type: object
title: Membership Event Content
description: The content of the event.
example: {"membership": "knock"}
properties:
membership:
type: string
description: The value `knock`.
example: "knock"
required: ['membership']
required:
- state_key
- sender
- origin
- origin_server_ts
- type
- content
example: {
"$ref": "examples/minimal_pdu.json",
"type": "m.room.member",
"state_key": "@someone:example.org",
"origin": "example.org",
"origin_server_ts": 1549041175876,
"sender": "@someone:example.org",
"content": {
"membership": "knock"
}
}
responses:
200:
description: |-
Information about the room to pass along to clients regarding the
knock.
schema:
type: object
properties:
knock_room_state:
type: array
items:
$ref: "../../event-schemas/schema/stripped_state.yaml"
description: |-
A list of simplified events to help the initiator of the knock identify
the room. The recommended events to include are the join rules, canonical
alias, avatar, name, and encryption state of the room.
example:
$ref: "../../event-schemas/examples/knock_room_state.json"
required: ['knock_room_state']
examples:
application/json: {
"knock_room_state": {"$ref": "../../event-schemas/examples/knock_room_state.json"}
}
404:
description: |-
The room that the knocking server is attempting to knock upon is unknown
to the receiving server.
schema:
allOf:
- $ref: "../client-server/definitions/errors/error.yaml"
examples:
application/json: {
"errcode": "M_NOT_FOUND",
"error": "Unknown room",
}
403:
description: |-
The knocking server or user is not permitted to knock on the room, such as when the
server/user is banned or the room is not set up for receiving knocks.
schema:
allOf:
- $ref: "../client-server/definitions/errors/error.yaml"
examples:
application/json: {
"errcode": "M_FORBIDDEN",
"error": "You are not permitted to knock on this room",
}

@ -1,4 +1,4 @@
# Copyright 2018 New Vector Ltd
# Copyright 2018, 2021 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -193,6 +193,13 @@ paths:
avatar_url:
type: string
description: The URL for the room's avatar, if one is set.
join_rule:
type: string
description: |-
The room's join rule. When not present, the room is assumed to
be `public`. Note that rooms with `invite` join rules are not
expected here, but rooms with `knock` rules are given their
near-public nature.
next_batch:
type: string
description: |-
@ -215,13 +222,14 @@ paths:
"chunk": [
{
"aliases": ["#murrays:cheese.bar"],
"avatar_url": "mxc://bleeker.street/CHEDDARandBRIE",
"avatar_url": "mxc://bleecker.street/CHEDDARandBRIE",
"guest_can_join": false,
"name": "CHEESE",
"num_joined_members": 37,
"room_id": "!ol19s:bleecker.street",
"topic": "Tasty tasty cheese",
"world_readable": true
"world_readable": true,
"join_rule": "public"
}
],
"next_batch": "p190q",

@ -0,0 +1,18 @@
[
{
"type": "m.room.name",
"sender": "@bob:example.org",
"state_key": "",
"content": {
"name": "Example Room"
}
},
{
"type": "m.room.join_rules",
"sender": "@bob:example.org",
"state_key": "",
"content": {
"join_rule": "knock"
}
}
]

@ -0,0 +1,6 @@
{
"type": "m.key.verification.done",
"content": {
"transaction_id": "S0meUniqueAndOpaqueString"
}
}

@ -0,0 +1,10 @@
{
"type": "m.key.verification.ready",
"content": {
"from_device": "BobDevice1",
"transaction_id": "S0meUniqueAndOpaqueString",
"methods": [
"m.sas.v1"
]
}
}

@ -0,0 +1,15 @@
{
"$ref": "m.room.member.yaml",
"content": {
"membership": "knock",
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"reason": "Looking for support"
},
"unsigned": {
"age": 1234,
"knock_room_state": {
"$ref": "knock_room_state.json"
}
}
}

@ -3,16 +3,16 @@ allOf:
- $ref: core-event-schema/event.yaml
description: |-
Accepts a previously sent `m.key.verification.start` message. Typically sent as a
[to-device](/client-server-api/#send-to-device-messaging) event.
Accepts a previously sent `m.key.verification.start` message.
properties:
content:
properties:
transaction_id:
type: string
description: |-
An opaque identifier for the verification process. Must be the same as
the one used for the `m.key.verification.start` message.
Required when sent as a to-device message. An opaque identifier for
the verification process. Must be the same as the one used for the
`m.key.verification.start` message.
key_agreement_protocol:
type: string
description: |-
@ -43,8 +43,10 @@ properties:
The hash (encoded as unpadded base64) of the concatenation of the device's
ephemeral public key (encoded as unpadded base64) and the canonical JSON
representation of the `m.key.verification.start` message.
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
required:
- transaction_id
- method
- key_agreement_protocol
- hash

@ -3,14 +3,15 @@ allOf:
- $ref: core-event-schema/event.yaml
description: |-
Cancels a key verification process/request. Typically sent as a [to-device](/client-server-api/#send-to-device-messaging) event.
Cancels a key verification process/request.
properties:
content:
properties:
transaction_id:
type: string
description: |-
The opaque identifier for the verification process/request.
Required when sent as a to-device message. The opaque identifier for
the verification process/request.
reason:
type: string
description: |-
@ -56,8 +57,10 @@ properties:
gets an unexpected response with `m.unexpected_message`, the client should not
respond again with `m.unexpected_message` to avoid the other device potentially
sending another error response.
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
required:
- transaction_id
- code
- reason
type: object

@ -0,0 +1,23 @@
---
allOf:
- $ref: core-event-schema/event.yaml
description: |-
Indicates that a verification process/request has completed successfully.
properties:
content:
properties:
transaction_id:
type: string
description: |-
Required when sent as a to-device message. The opaque identifier for
the verification process/request.
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
type: object
type:
enum:
- m.key.verification.done
type: string
type: object

@ -3,22 +3,24 @@ allOf:
- $ref: core-event-schema/event.yaml
description: |-
Sends the ephemeral public key for a device to the partner device. Typically sent as a
[to-device](/client-server-api/#send-to-device-messaging) event.
Sends the ephemeral public key for a device to the partner device.
properties:
content:
properties:
transaction_id:
type: string
description: |-
An opaque identifier for the verification process. Must be the same as
the one used for the `m.key.verification.start` message.
Required when sent as a to-device message. An opaque identifier for
the verification process. Must be the same as the one used for the
`m.key.verification.start` message.
key:
type: string
description: |-
The device's ephemeral public key, encoded as unpadded base64.
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
required:
- transaction_id
- key
type: object
type:

@ -0,0 +1,21 @@
---
description: |-
Required when sent as an in-room message. Indicates the
`m.key.verification.request` that this message is related to. Note that for
encrypted messages, this property should be in the unencrypted portion of the
event.
properties:
rel_type:
type: string
enum:
- m.reference
description: |-
The relationship type.
event_id:
type: string
description: |-
The event ID of the `m.key.verification.request` that this message is
related to.
type: object
type: object
title: VerificationRelatesTo

@ -3,16 +3,16 @@ allOf:
- $ref: core-event-schema/event.yaml
description: |-
Sends the MAC of a device's key to the partner device. Typically sent as a
[to-device](/client-server-api/#send-to-device-messaging) event.
Sends the MAC of a device's key to the partner device.
properties:
content:
properties:
transaction_id:
type: string
description: |-
An opaque identifier for the verification process. Must be the same as
the one used for the `m.key.verification.start` message.
Required when sent as a to-device message. An opaque identifier for
the verification process. Must be the same as the one used for the
`m.key.verification.start` message.
mac:
type: object
description: |-
@ -26,8 +26,10 @@ properties:
description: |-
The MAC of the comma-separated, sorted, list of key IDs given in the `mac`
property, encoded as unpadded base64.
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
required:
- transaction_id
- mac
- keys
type: object

@ -0,0 +1,40 @@
---
allOf:
- $ref: core-event-schema/event.yaml
description: |-
Accepts a key verification request. Sent in response to an
`m.key.verification.request` event.
properties:
content:
properties:
from_device:
type: string
description: |-
The device ID which is accepting the request.
transaction_id:
type: string
description: |-
Required when sent as a to-device message. The transaction ID of the
verification request, as given in the `m.key.verification.request`
message.
methods:
type: array
description: |-
The verification methods supported by the sender, corresponding to
the verification methods indicated in the
`m.key.verification.request` message.
items:
type: string
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
required:
- from_device
- methods
type: object
type:
enum:
- m.key.verification.ready
type: string
type: object

@ -3,8 +3,7 @@ allOf:
- $ref: core-event-schema/event.yaml
description: |-
Requests a key verification with another user's devices. Typically sent as a
[to-device](/client-server-api/#send-to-device-messaging) event.
Requests a key verification with another user's devices.
properties:
content:
properties:
@ -15,8 +14,9 @@ properties:
transaction_id:
type: string
description: |-
An opaque identifier for the verification request. Must be unique
with respect to the devices involved.
Required when sent as a to-device message. An opaque identifier for
the verification request. Must be unique with respect to the devices
involved.
methods:
type: array
description: |-
@ -27,14 +27,13 @@ properties:
type: integer
format: int64
description: |-
The POSIX timestamp in milliseconds for when the request was made. If
the request is in the future by more than 5 minutes or more than 10
minutes in the past, the message should be ignored by the receiver.
Required when sent as a to-device message. The POSIX timestamp in
milliseconds for when the request was made. If the request is in the
future by more than 5 minutes or more than 10 minutes in the past,
the message should be ignored by the receiver.
required:
- from_device
- transaction_id
- methods
- timestamp
type: object
type:
enum:

@ -0,0 +1,44 @@
---
allOf:
- $ref: core-event-schema/event.yaml
description: |-
Begins a key verification process using the `m.reciprocate.v1` method, after
scanning a QR code.
properties:
content:
properties:
from_device:
type: string
description: |-
The device ID which is initiating the process.
transaction_id:
type: string
description: |-
Required when sent as a to-device message. An opaque identifier for
the verification process. Must be unique with respect to the devices
involved. Must be the same as the `transaction_id` given in the
`m.key.verification.request` if this process is originating from a
request.
method:
type: string
enum: ["m.reciprocate.v1"]
description: |-
The verification method to use.
secret:
type: string
description: |-
The shared secret from the QR code, encoded using unpadded base64.
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
required:
- from_device
- method
- secret
type: object
type:
enum:
- m.key.verification.start
type: string
type: object

@ -3,7 +3,7 @@ allOf:
- $ref: core-event-schema/event.yaml
description: |-
Begins a SAS key verification process using the `m.sas.v1` method. Typically sent as a [to-device](/client-server-api/#send-to-device-messaging) event.
Begins a SAS key verification process using the `m.sas.v1` method.
properties:
content:
properties:
@ -14,10 +14,11 @@ properties:
transaction_id:
type: string
description: |-
An opaque identifier for the verification process. Must be unique
with respect to the devices involved. Must be the same as the
`transaction_id` given in the `m.key.verification.request`
if this process is originating from a request.
Required when sent as a to-device message. An opaque identifier for
the verification process. Must be unique with respect to the devices
involved. Must be the same as the `transaction_id` given in the
`m.key.verification.request` if this process is originating from a
request.
method:
type: string
enum: ["m.sas.v1"]
@ -53,9 +54,11 @@ properties:
items:
type: string
enum: ["decimal", "emoji"]
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
required:
- from_device
- transaction_id
- method
- key_agreement_protocols
- hashes

@ -16,10 +16,11 @@ properties:
transaction_id:
type: string
description: |-
An opaque identifier for the verification process. Must be unique
with respect to the devices involved. Must be the same as the
`transaction_id` given in the `m.key.verification.request`
if this process is originating from a request.
Required when sent as a to-device message. An opaque identifier for
the verification process. Must be unique with respect to the devices
involved. Must be the same as the `transaction_id` given in the
`m.key.verification.request` if this process is originating from a
request.
method:
type: string
description: |-
@ -30,9 +31,11 @@ properties:
Optional method to use to verify the other user's key with. Applicable
when the `method` chosen only verifies one user's key. This field will
never be present if the `method` verifies keys both ways.
m.relates_to:
allOf:
- $ref: m.key.verification.m.relates_to.yaml
required:
- from_device
- transaction_id
- method
type: object
type:

@ -1,7 +1,16 @@
---
allOf:
- $ref: core-event-schema/state_event.yaml
description: 'A room may be `public` meaning anyone can join the room without any prior action. Alternatively, it can be `invite` meaning that a user who wishes to join the room must first receive an invite to the room from someone already inside of the room. Currently, `knock` and `private` are reserved keywords which are not implemented.'
description: |
A room may be `public` meaning anyone can join the room without any prior action.
Alternatively, it can be `invite` meaning that a user who wishes to join the room
must first receive an invite to the room from someone already inside of the room.
`knock` means that users are able to ask for permission to join the room, where
they are either allowed (invited) or denied (kicked/banned) access. Join rules
of `knock` are otherwise the same as `invite`: the user needs an explicit invite
to join the room.
Currently, `private` is a reserved keyword which is not implemented.
properties:
content:
properties:

@ -14,7 +14,7 @@ description: |-
- `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` - This is a reserved word, which currently has no meaning.
- `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.
@ -31,13 +31,13 @@ description: |-
from the `prev_content` object on an event. If not present, the user's previous membership must be assumed
as `leave`.
| | to `invite` | to `join` | to `leave` | to `ban` | to `knock` |
|-------------------|---------------------|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|------------------|
| **from `invite`** | No change. | User joined the room. | If the `state_key` is the same as the `sender`, the user rejected the invite. Otherwise, the `state_key` user had their invite revoked. | User was banned. | Not implemented. |
| **from `join`** |Must never happen. | `displayname` or `avatar_url` changed. | If the `state_key` is the same as the `sender`, the user left. Otherwise, the `state_key` user was kicked. | User was kicked and banned. | Not implemented. |
| **from `leave`** |New invitation sent. | User joined. | No change. | User was banned. | Not implemented. |
| **from `ban`** |Must never happen. | Must never happen. | User was unbanned. | No change. | Not implemented. |
| **from `knock`** |Not implemented. | Not implemented. | Not implemented. | Not implemented. | Not implemented. |
| | to `invite` | to `join` | to `leave` | to `ban` | to `knock` |
|-------------------|----------------------|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|--------------------|
| **from `invite`** | No change. | User joined the room. | If the `state_key` is the same as the `sender`, the user rejected the invite. Otherwise, the `state_key` user had their invite revoked. | User was banned. | Must never happen. |
| **from `join`** | Must never happen. | `displayname` or `avatar_url` changed. | If the `state_key` is the same as the `sender`, the user left. Otherwise, the `state_key` user was kicked. | User was kicked and banned. | Must never happen. |
| **from `leave`** | New invitation sent. | User joined. | No change. | User was banned. | User is knocking. |
| **from `ban`** | Must never happen. | Must never happen. | User was unbanned. | No change. | Must never happen. |
| **from `knock`** | Knock accepted. | Must never happen. | If the `state_key` is the same as the `sender`, the user retracted the knock. Otherwise, the `state_key` user had their knock denied. | User was banned. | No change. |
properties:
content:
@ -124,7 +124,24 @@ properties:
- type: object
properties:
invite_room_state:
description: 'A subset of the state of the room at the time of the invite, if `membership` is `invite`. Note that this state is informational, and SHOULD NOT be trusted; once the client has joined the room, it SHOULD fetch the live state from the server and discard the invite_room_state. Also, clients must not rely on any particular state being present here; they SHOULD behave properly (with possibly a degraded but not a broken experience) in the absence of any particular events here. If they are set on the room, at least the state for `m.room.avatar`, `m.room.canonical_alias`, `m.room.join_rules`, and `m.room.name` SHOULD be included.'
description: |-
A subset of the state of the room at the time of the invite, if `membership` is `invite`.
Note that this state is informational, and SHOULD NOT be trusted; once the client has
joined the room, it SHOULD fetch the live state from the server and discard the
invite_room_state. Also, clients must not rely on any particular state being present here;
they SHOULD behave properly (with possibly a degraded but not a broken experience) in
the absence of any particular events here. If they are set on the room, at least the
state for `m.room.avatar`, `m.room.canonical_alias`, `m.room.join_rules`, and `m.room.name`
SHOULD be included.
items:
$ref: "stripped_state.yaml"
type: array
knock_room_state:
description: |-
A subset of the state of the room at the time of the knock, if `membership` is `knock`.
This has the same restrictions as `invite_room_state`. If they are set on the room, at least
the state for `m.room.avatar`, `m.room.canonical_alias`, `m.room.join_rules`, `m.room.name`,
and `m.room.encryption` SHOULD be included.
items:
$ref: "stripped_state.yaml"
type: array

@ -8,7 +8,7 @@ in.
Format
------
Documentation is written either in github-flavored markdown.
Documentation is written in github-flavored markdown.
Sections
--------

@ -0,0 +1,314 @@
# Key verification in DMs
Currently, key verification is done using `to_device` messages. However, since
`to_device` messages are not part of a timeline, there is no user-visible
record of the key verification.
As well, the current key verification framework does not provide any feedback
when interacting with clients that do not support it; if a client does not
support the key verification framework, there is no way for users to discover
this other than waiting for a while and noticing that nothing is happening.
This proposal will solve both problems.
## Proposal
The current [key verification
framework](https://matrix.org/docs/spec/client_server/r0.5.0#key-verification-framework)
will be replaced by a new framework that uses room messages rather than
`to_device` messages. Key verification messages will be sent in a [Direct
Messaging](https://matrix.org/docs/spec/client_server/r0.5.0#id185) room. If
there is no Direct Messaging room between the two users involved, the client
that initiates the key verification will create one.
In this proposal, we use "Alice" to denote the user who initiates the key
verification, and "Bob" to denote the other user involved in the key
verification.
### General framework
#### Requesting a key verification
To request a key verification, Alice will send an `m.room.message` event with the
following properties in its contents:
- `body`: a fallback message to alert users that their client does not support
the key verification framework, and that they should use a different method
to verify keys. For example, "Alice is requesting to verify keys with you.
However, your client does not support this method, so you will need to use
the legacy method of key verification."
Clients that do support the key verification framework should hide the body
and instead present the user with an interface to accept or reject the key
verification.
The event may also contain `format` and `formatted_body` properties as
described in the [m.room.message
msgtypes](https://matrix.org/docs/spec/client_server/r0.5.0#m-room-message-msgtypes)
section of the spec. Clients that support the key verification should
similarly hide these from the user.
- `msgtype`: `m.key.verification.request`
- `methods`: the verification methods supported by Alice's client
- `to`: Bob's Matrix ID. Users should only respond to verification requests if
they are named in this field. Users who are not named in this field and who
did not send this event should ignore all other events that have a
`m.reference` relationship with this event.
- `from_device`: Alice's device ID. This is required since some verification
methods may use the device IDs as part of the verification process.
Key verifications will be identified by the event ID of the key verification
request event.
Clients should ignore verification requests that have been accepted or
cancelled, or if they do not belong to the sending or target users.
The way that clients display this event can depend on which user and device the
client belongs to, and what state the verification is in. For example:
- If the verification has been completed (there is an `m.key.verification.done`
or `m.key.verification.cancel` event), the client can indicate that the
verification was successful or had an error.
- If the verification has been accepted (there is an `m.key.verification.start`
event) but has not been completed, the two devices involved can indicate that
the verification is in progress and can use this event as a place in the
room's timeline to display progress of the key verification and to interact
with the user as necessary. Other devices can indicate that the verification
is in progress on other devices.
- If the verification has not been accepted, clients for the target user can
indicate that a verification has been requested and allow the user to accept
the verification on that device. The sending client can indicate that it is
waiting for the request to be accepted, and the sending user's other clients
can indicate the that a request was initiated on a different device.
Clients may choose to display or not to display events of any other type that
reference the original request event; but it must not have any effect on the
verification itself.
#### Accepting a key verification
To accept a key verification, Bob will send an `m.key.verification.ready` event
with the following properties in its contents:
- `m.relates_to`: an object with the properties:
- `rel_type`: `m.reference`
- `event_id`: the event ID of the key verification request that is being
accepted
- `methods`: an array of verification methods that the device supports
- `from_device`: Bob's device ID. This is required since some verification
methods may use the device IDs as part of the verification process.
(Note: the form of the `m.relates_to` property is based on the current state of
[MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674), but is
independent from it since this MSC does not rely on any aggregations features.)
Clients should ignore `m.key.verification.ready` events that correspond to
verification requests that they did not send.
After this, either Alice or Bob may start the verification by sending an
`m.key.verification.start` event with the following properties in its contents:
- `m.relates_to`: an object with the properties:
- `rel_type`: `m.reference`
- `event_id`: the event ID of the key verification request that is being
started
- `method`: the key verification method that is being used. This should be a
method that both Alice's and Bob's devices support.
- `from_device`: The user's device ID.
If both Alice and Bob send an `m.key.verification.start` message, and they both
specify the same verification method, then the event sent by the user whose
user ID is the smallest is used, and the other event is ignored. If they both
send an `m.key.verification.start` message and the method is different, then
the verification should be cancelled with a `code` of `m.unexpected_message`.
After the `m.key.verification.start` event is sent, the devices may exchange
messages (if any) according to the verification method in use.
#### Rejecting a key verification
To reject a key verification, Alice or Bob will send an
`m.key.verification.cancel` event with the following properties in its
contents:
- `m.relates_to`: an object with the properties:
- `rel_type`: `m.reference`
- `event_id`: the event ID of the key verification that is being cancelled
- `reason`: A human readable description of the `code`. The client should only
rely on this string if it does not understand the `code`.
- `code`: The error code for why the process/request was cancelled by the
user. The contents are the same as the `code` property of the currently
defined [`m.key.verification.cancel` to-device
event](https://matrix.org/docs/spec/client_server/r0.5.0#m-key-verification-cancel),
or as defined for specific key verification methods.
This message may be sent at any point in the key verification process. Any
subsequent key verification messages relating to the same request are ignored.
However, this does not undo any verifications that have already been done.
#### Concluding a key verification
When the other user's key is verified and no more messages are expected, each
party will send an `m.key.verification.done` event with the following
properties in its contents:
- `m.relates_to`: an object with the properties:
- `rel_type`: `m.reference`
- `event_id`: the event ID of the key verification that is being concluded
This provides a record within the room of the result of the verification.
Any subsequent key verification messages relating to the same request are
ignored.
Although a client may have successfully completed its side of the verification,
it may wait until receiving an `m.key.verification.done` (or
`m.key.verification.cancel`) event from the other device before informing the
user that the verification was successful or unsuccessful.
#### Other events
Key verification methods may define their own event types, or extensions to the
above event types. All events sent as part of a key verification process
should have an `m.relates_to` property as defined for
`m.key.verification.accept` or `m.key.verification.cancel` events.
Clients should ignore events with an `m.relates_to` that have a `rel_type` of
`m.reference` that refer to a verification where it is neither the requester
nor the accepter.
Clients should not redact or edit verification messages. A client may ignore
redactions or edits of key verification messages, or may cancel the
verification with a `code` of `m.unexpected_message` when it receives a
redaction or edit.
### SAS verification
The messages used in SAS verification are the same as those currently defined,
except that instead of the `transaction_id` property, an `m.relates_to`
property, as defined above, is used instead.
If the key verification messages are encrypted, the hash commitment sent in the
`m.key.verification.accept` message MUST be based on the decrypted
`m.key.verification.start` message contents, and include the `m.relates_to`
field, even if the decrypted message contents do not include that field. For
example, if Alice sends a message to start the SAS verification:
```json
{
"content": {
"algorithm": "m.megolm.v1.aes-sha2",
"ciphertext": "ABCDEFG...",
"device_id": "Dynabook",
"sender_key": "alice+sender+key",
"session_id": "session+id",
"m.relates_to": {
"rel_type": "m.reference",
"event_id": "$verification_request_event"
}
},
"event_id": "$event_id",
"origin_server_ts": 1234567890,
"sender": "@alice:example.org",
"type": "m.room.encrypted",
"room_id": "!room_id:example.org"
}
```
which, when decrypted, yields:
```json
{
"room_id": "!room_id:example.org",
"type": "m.key.verification.start",
"content": {
"from_device": "Dynabook",
"hashes": [
"sha256"
],
"key_agreement_protocols": [
"curve25519"
],
"message_authentication_codes": [
"hkdf-hmac-sha256"
],
"method": "m.sas.v1",
"short_authentication_string": [
"decimal",
"emoji"
]
}
}
```
then the hash commitment will be based on the message contents:
```json
{
"from_device": "Dynabook",
"hashes": [
"sha256"
],
"key_agreement_protocols": [
"curve25519"
],
"message_authentication_codes": [
"hkdf-hmac-sha256"
],
"method": "m.sas.v1",
"short_authentication_string": [
"decimal",
"emoji"
],
"m.relates_to": {
"rel_type": "m.reference",
"event_id": "$verification_request_event"
}
}
```
## Alternatives
Messages sent by the verification methods, after the initial key verification
request message, could be sent as to-device messages. The
`m.key.verification.ready`, `m.key.verification.cancel`, and
`m.key.verification.done` messages must be still be sent in the room, as the
`m.key.verification.ready` notifies the sender's other devices that the request
has been acknowledged, and the `m.key.verification.cancel` and
`m.key.verification.done` provide a record of the status of the key
verification.
However, it seems more natural to have all messages sent via the same
mechanism.
## Potential issues
If a user wants to verify their own device, this will require the creation of a
Direct Messaging room with themselves. Instead, clients may use the current
`to_device` messages for verifying the user's other devices.
Direct Messaging rooms could have end-to-end encryption enabled, and some
clients can be configured to only send decryption keys to verified devices.
Key verification messages should be granted an exception to this (so that
decryption keys are sent to all of the target user's devices), or should be
sent unencrypted, so that unverified devices will be able to be verified.
Users might have multiple Direct Messaging rooms with other users. In this
case, clients could need to prompt the user to select the room in which they
want to perform the verification, or could select a room.
## Security considerations
Key verification is subject to the room's visibility settings, and may be
visible to other users in the room. However, key verification does not rely on
secrecy, so this will no affect the security of the key verification. This may
reveal to others in the room that Alice and Bob know each other, but this is
already revealed by the fact that they share a Direct Messaging room.
This framework allows users to see what key verifications they have performed
in the past. However, since key verification messages are not secured, this
should not be considered as authoritative.
## Conclusion
By using room messages to perform key verification rather than `to_device`
messages, the user experience of key verification can be improved.

@ -199,7 +199,7 @@ contain this information:
"aliases": [
"#murrays:cheese.bar"
],
"avatar_url": "mxc://bleeker.street/CHEDDARandBRIE",
"avatar_url": "mxc://bleecker.street/CHEDDARandBRIE",
"guest_can_join": false,
"name": "CHEESE",
"num_joined_members": 37,

@ -0,0 +1,26 @@
# MSC2713: Remove deprecated Identity Service endpoints
Implementations will have had plenty of time to adopt the new v2 API for Identity Servers, so
we should clean out the old endpoints.
All deprecated endpoints in the r0.3.0 Identity Service API specification are to be removed.
For completeness, this includes:
* `GET /_matrix/identity/api/v1`
* `GET /_matrix/identity/api/v1/pubkey/{keyId}`
* `GET /_matrix/identity/api/v1/pubkey/isvalid`
* `GET /_matrix/identity/api/v1/pubkey/ephemeral/isvalid`
* `GET /_matrix/identity/api/v1/lookup`
* `POST /_matrix/identity/api/v1/bulk_lookup`
* `POST /_matrix/identity/api/v1/validate/email/requestToken`
* `POST /_matrix/identity/api/v1/validate/email/submitToken`
* `GET /_matrix/identity/api/v1/validate/email/submitToken`
* `POST /_matrix/identity/api/v1/validate/msisdn/requestToken`
* `POST /_matrix/identity/api/v1/validate/msisdn/submitToken`
* `GET /_matrix/identity/api/v1/validate/msisdn/submitToken`
* `GET /_matrix/identity/api/v1/3pid/getValidated3pid`
* `POST /_matrix/identity/api/v1/3pid/bind`
* `POST /_matrix/identity/api/v1/3pid/unbind`
* `POST /_matrix/identity/api/v1/store-invite`
* `POST /_matrix/identity/api/v1/sign-ed25519`

@ -1,9 +1,5 @@
[ tool.gilesbot ]
[ tool.gilesbot.circleci_artifacts.legacydocs ]
url = "gen/index.html"
message = "Click details to preview the legacy HTML documentation."
[ tool.gilesbot.circleci_artifacts.docs ]
url = "public/index.html"
message = "Click details to preview the HTML documentation."

@ -337,7 +337,7 @@ func (s *server) serveSpec(w http.ResponseWriter, req *http.Request) {
log.Printf("Serving pr %s (%s)\n", branchName, sha)
} else if strings.ToLower(branchName) == "head" ||
branchName == "master" ||
strings.HasPrefix(branchName, "drafts/") {
strings.HasPrefix(branchName, "attic/drafts/") {
branchSHA, err := s.lookupBranch(branchName)
if err != nil {
writeError(w, 400, err)

@ -0,0 +1,17 @@
# Spec diagrams
Non-ascii diagrams for the spec can be placed here for reference in the actual spec.
Please include source material so the diagram can be recreated by a future editor.
https://www.diagrams.net/ is a great ([open source](https://github.com/jgraph/drawio))
tool for these sorts of things - include your `.drawio` file next to your diagram.
Suggested settings for diagrams.net:
* Export as PNG.
* 100% size.
* `20` for a border width.
* No transparent background, shadow, or grid.
* Include a copy of the diagram.
To reference a diagram, use the absolute path when compiled. For example,
`![membership-flow-diagram](/diagrams/membership.png)`

@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2021-04-28T19:35:50.494Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36" etag="-IOh23FjJiPnGlGWLseU" version="14.6.6" type="device"><diagram id="4a_pTli-mcEMNPq0ciXK" name="Page-1">3Vvdb6M4EP9rIt09NMIGA3ncZtvbh73TSn243X1ZOYmT0BIcOaZJ9q8/E0z4cggEgulVqoqHsbHHv/nwjDsyp5vDXwxv13/TBfFH0FgcRubnEYTAAa74E1GOMWViopiwYt5CMqWEF+83kURDUkNvQXY5Rk6pz71tnjinQUDmPEfDjNF9nm1J/fxXt3hFSoSXOfbL1H+9BV/HVBc6Kf0L8Vbr5MvAnsRvNjhhlivZrfGC7jMk82lkThmlPH7aHKbEj4SXyCXu93zh7XlijAS8TodvBvr96euj/xL83G+Dn2gaTvgDkMO8Yz+UKxYjvFIvkJPmx0QSZCEEI5uU8TVd0QD7Tyn1kdEwWJDoc4ZopTxfKd0KIhDEV8L5Ue4yDjkVpDXf+PJt/M3oQxfXKEk7GrI5qVqYxApmK8Ir+OB5JwSECd0Qzo6iHyM+5t57fh5YYml15pNdPzGGjxmGrZAf32VG/hYRBINUCziRmJBKYdqFrWvGLx7iGSStzFJS0gkOTaBhqaDhEyykogEb5ODx75nnH9FQY4hk8/NBDn1qHJNGIGTwPcMZtX9kX6b9Tq2kY4dIhKgmFC01FCUGjDEwHDMeqhk6S3Cy3DycoDUZ25kfx8qPGM9cDpLCrinqLVD4rG1Wot4CqIo/j/q0dzIdulzuCC/06EYzSorhBe8eL6tFHvT7teB52eITWvbCXaqM3zthnByqQXcRI9ApSBjJ9j51XcCQtHXGbSV8KgzlpNdYVHaFETEoG0VO6/nNm799cH8DO1JysRduOyW/P/4hVG3qDGuJGRK/YIxRxjOA29wC6NEt1ASMWQmYB2NsI6ulW+gBMSXAKEPMRvZySQP+jDeeH23OVIjbI5E5+Yfs72NMLUu7MXVVehcGujUvF5HVDMhAVu1kr34Uz2xnqWsrWautNks7rdrkQekLQoVDiqldX5R+KrY8hreMVhfOfG8+grYv5vI4E/KwV9FTxPOLhT7Z6XVp8Caf5ug66lg1VavtobsdKsq6Jca5EMH3sduXNq7HYKT2xqFr0QgaeigCnEEGr05W0426mq4tqVEXMBei1340vZzAUmevBuVGzWKuT7sbVUadGu1lO53RFnfCSWdG1rVdq52dPddnCgkjB+WHiFdVSv31arCNjx3F5RPW1ccjLXBraaLrIcuy6yGrs4yDsrCly82nHrtRhHdLbksHhK7mqFxogrsYLGTVg1XTWgUo1CqQWV2hs41Kfn21CqhMwA/Ae9+SNGp6tM3Fal+I/064N8cdK0lHZycRzN+iIU2BbVr5ohqYoIEAVXkuG0qlqGWV4eOitrpeJUy7A4ZffjAHFQzcEBf+L6B0NUpwEGoZJfRgpspJhbeAKozSoJMK5zBKW1IhuRXT8SWKvouC+m9YJEF6RpBPB06YMEknl1k8FP8R0JOmiN8N2cwI+7NC4qChxMsmpl1JqXCGVKXCoELY9r2EbSpzEdIAxMmIU+MBz4QwB5qQKJSVaiebu/E8r+Fmmyw0oAFJSPGsHV1JkKtxjuvCm3JuTQP0wt08YFUfPM+3EtT8Gi/Jle2S/pjrVug3O3ZmIY7ZvGNI171OejXcmvRy4ISTwoETXcmkwEr+ewBaNNNr+DF7+s8M5tN/</diagram></mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Loading…
Cancel
Save