Merge branch 'master' into travis/msc/widgets-send-receive-events

pull/4237/head
Travis Ralston 4 years ago
commit b67124622b

@ -5,44 +5,44 @@ This repository contains the Matrix Specification, rendered at [spec.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](https://matrix.to/#/#matrix-spec:matrix.org).
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
The Matrix spec is compiled with [Hugo](https://gohugo.io/) (a static site generator) with the following structure:
* `/assets`: assets that need postprocessing using [Hugo Pipes](https://gohugo.io/hugo-pipes/introduction/).
* `/assets`: assets that need postprocessing using [Hugo Pipes](https://gohugo.io/hugo-pipes/introduction/).
For example, Sass files would go here.
* `/content`: files that will become pages in the site go here. Typically these are Markdown files with some YAML front
matter indicating, [among other things](https://gohugo.io/content-management/front-matter/), what layout should be
applied to this page. The organization of files under `/content` determines the organization of pages in the built
* `/content`: files that will become pages in the site go here. Typically these are Markdown files with some YAML front
matter indicating, [among other things](https://gohugo.io/content-management/front-matter/), what layout should be
applied to this page. The organization of files under `/content` determines the organization of pages in the built
site.
* `/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
* `/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 Swagger/OpenAPI definitions and schemas are.
* `/layouts`: this contains [Hugo templates](https://gohugo.io/templates/). Some templates define the overall layout of
* `/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.
* `/layouts/partials`: these templates can be called from other templates, so they can be used to factor out
template code that's used in more than one template. An obvious example here is something like a sidebar, where
several different page layouts might all include the sidebar. But also, partial templates can return values: this
* `/layouts/partials`: these templates can be called from other templates, so they can be used to factor out
template code that's used in more than one template. An obvious example here is something like a sidebar, where
several different page layouts might all include the sidebar. But also, partial templates can return values: this
means they can be used like functions, that can be called by multiple templates to do some common processing.
* `/layouts/shortcodes`: these templates can be called directly from files in `/content`.
* `/static`: static files which don't need preprocessing. JS or CSS files could live here.
* `/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 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
* `/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 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:
* `config.toml`: site-wide configuration settings. Some of these are built-in and you can add your own. Config settings
* `config.toml`: site-wide configuration settings. Some of these are built-in and you can add your own. Config settings
defined here are available in templates. All these directories above are configurable via `config.toml` settings.
Additionally, the following directories may be of interest:
@ -59,34 +59,40 @@ Additionally, the following directories may be of interest:
Please read [CONTRIBUTING.rst](./CONTRIBUTING.rst) before authoring a change to the spec. Note that spec authoring takes
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>
1. Install the extended version (often the OS default) of Hugo:
<https://gohugo.io/getting-started/installing>. Note that at least Hugo
v0.74 is required.
Alternatively, use the Docker image at https://hub.docker.com/r/klakegg/hugo/.
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 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.
5. Run `hugo serve` (or `docker run --rm -it -v $(pwd):/src -p 1313:1313
klakegg/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
adding `--disableFastRender` to the commandline.
6. Edit the specification 🙂
We use a highly customized [Docsy](https://www.docsy.dev/) theme for our generated site, which uses Bootstrap and Font
Awesome. If you're looking at making design-related changes to the spec site, please coordinate with us in
We use a highly customized [Docsy](https://www.docsy.dev/) theme for our generated site, which uses Bootstrap and Font
Awesome. If you're looking at making design-related changes to the spec site, please coordinate with us in
[#matrix-docs:matrix.org](https://matrix.to/#/#matrix-docs:matrix.org) before opening a PR.
## Building the specification
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"`
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,
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 [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>.
* You can host the swagger UI yourself. See <https://github.com/swagger-api/swagger-ui#how-to-run> for advice on how to
* 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.
## Issue tracking

@ -45,9 +45,6 @@ Custom SCSS for the Matrix spec
scroll-behavior: smooth;
overscroll-behavior: contain;
/* This overrides calc(100vh - 10rem);, which gives us a blank space at the bottom of the sidebar */
max-height: calc(100vh - 6rem);
&>.td-sidebar-nav__section {
margin-top: 1rem;
}
@ -92,6 +89,15 @@ Custom SCSS for the Matrix spec
}
}
@media (min-width: 768px) {
@supports (position: sticky) {
.td-sidebar-nav {
/* This overrides calc(100vh - 10rem);, which gives us a blank space at the bottom of the sidebar */
max-height: calc(100vh - 6rem);
}
}
}
/* Customise footer */
footer {
box-shadow: 0px 0px 8px rgba(179, 179, 179, 0.25);

@ -0,0 +1 @@
Deprecate starting verifications that don't start with `m.key.verification.request` as per [MSC3122](https://github.com/matrix-org/matrix-doc/pull/3122).

@ -0,0 +1 @@
Update `Access-Control-Allow-Headers` recommendation to fit CORS specification.

@ -0,0 +1 @@
Explicitly state that `replacment_room` is a room ID in `m.room.tombstone` events.

@ -0,0 +1 @@
Clarify that all request bodies are required.

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

@ -0,0 +1 @@
Fix key_backup operation IDs in OpenAPI spec.

@ -0,0 +1 @@
Add auth property to UIA endpoint uploadCrossSigningKeys.

@ -0,0 +1 @@
Clarify that all request bodies are required.

@ -0,0 +1 @@
Disambiguate getEvents and peekEvents, and include both in swagger.

@ -0,0 +1 @@
Mention that a canonical alias event should be added when a room is created with an alias.

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

@ -0,0 +1 @@
Add an 'API conventions' section to the Appendices.

@ -1 +1 @@
Clarify that some identifiers may be lowercase prior to processing, as per [MSC2265](https://github.com/matrix-org/matrix-doc/pull/2265).
Clarify that some identifiers must be case folded prior to processing, as per [MSC2265](https://github.com/matrix-org/matrix-doc/pull/2265).

@ -0,0 +1 @@
Clarify that some identifiers must be case folded prior to processing, as per [MSC2265](https://github.com/matrix-org/matrix-doc/pull/2265).

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

@ -0,0 +1 @@
Correct the `/_matrix/federation/v1/user/devices/{userId}` response which actually returns `"self_signing_key"` instead of `"self_signing_keys"`.

@ -0,0 +1 @@
Explain the reasons why `<hostname>` TLS certificate is needed rather than `<delegated_hostname>` for SRV delegation.

@ -43,7 +43,13 @@ privacy_policy = "https://matrix.org/legal/privacy-notice"
# must be one of "unstable", "current", "historical"
# this is used to decide whether to show a banner pointing to the current release
status = "unstable"
# A URL pointing to the latest, stable release of the spec. To be shown in the unstable version warning banner.
current_version_url = "https://matrix.org/docs/spec/"
# The following is used when status = "stable", and is displayed in various UI elements on a released version
# of the spec. CI will set these values here automatically when a release git tag (i.e `v1.5`) is created.
#major = "1"
#minor = "0"
#release_date = "April 01, 2021"
# User interface configuration
[params.ui]

@ -328,7 +328,7 @@ Federation maintains *shared data structures* per-room between multiple
homeservers. The data is split into `message events` and `state events`.
Message events:
These describe transient 'once-off' activity in a room such as an
These describe transient 'one-off' activity in a room such as an
instant messages, VoIP call setups, file transfers, etc. They generally
describe communication activity.

@ -756,11 +756,11 @@ Represents E-Mail addresses. The `address` is the raw email address in
other text such as real name, angle brackets or a mailto: prefix.
In addition to lowercasing the domain component of an email address,
implementations are expected to lowercase the localpart as described
in [the unicode mapping file](https://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt)
prior to any processing. For example, `Strauß@Example.com` must be
considered to be `strauss@example.com` while processing the email
address.
implementations are expected to apply the unicode case-folding algorithm
as described under "Caseless Matching" in
[chapter 5 of the unicode standard](https://www.unicode.org/versions/Unicode13.0.0/ch05.pdf#G21790).
For example, `Strauß@Example.com` must be considered to be `strauss@example.com`
while processing the email address.
### PSTN Phone numbers
@ -1039,3 +1039,22 @@ The event signing algorithm should emit the following signed event:
}
}
```
## Conventions for Matrix APIs
This section is intended primarily to guide API designers when adding to Matrix,
setting guidelines to follow for how those APIs should work. This is important to
maintain consistency with the Matrix protocol, and thus improve developer
experience.
### HTTP endpoint and JSON property naming
The names of the API endpoints for the HTTP transport follow a convention of
using underscores to separate words (for example `/delete_devices`).
The key names in JSON objects passed over the API also follow this convention.
{{% boxes/note %}}
There are a few historical exceptions to this rule, such as `/createRoom`.
These inconsistencies may be addressed in future versions of this specification.
{{% /boxes/note %}}

@ -4,7 +4,7 @@ weight: 10
type: docs
---
The client-server API provides a simple lightweight API to let clients
The client-server API allows clients to
send messages, control rooms and synchronise conversation history. It is
designed to support both lightweight clients which store no state and
lazy-load data from the server as required - as well as heavyweight
@ -20,20 +20,15 @@ supported as optional extensions - e.g. a packed binary encoding over
stream-cipher encrypted TCP socket for low-bandwidth/low-roundtrip
mobile usage. For the default HTTP transport, all API calls use a
Content-Type of `application/json`. In addition, all strings MUST be
encoded as UTF-8. Clients are authenticated using opaque `access_token`
strings (see [Client Authentication](#client-authentication) for
details), passed as a query string parameter on all requests.
encoded as UTF-8.
The names of the API endpoints for the HTTP transport follow a
convention of using underscores to separate words (for example
`/delete_devices`). The key names in JSON objects passed over the API
also follow this convention.
Clients are authenticated using opaque `access_token` strings (see [Client
Authentication](#client-authentication) for details).
{{% boxes/note %}}
There are a few historical exceptions to this rule, such as
`/createRoom`. A future version of this specification will address the
inconsistency.
{{% /boxes/note %}}
See also [Conventions for Matrix APIs](/appendices#conventions-for-matrix-apis)
in the Appendices for conventions which all Matrix APIs are expected to follow.
### Standard error response
Any errors which occur at the Matrix API level MUST return a "standard
error response". This is a JSON object which looks like:
@ -46,15 +41,17 @@ error response". This is a JSON object which looks like:
```
The `error` string will be a human-readable error message, usually a
sentence explaining what went wrong. The `errcode` string will be a
unique string which can be used to handle an error message e.g.
`M_FORBIDDEN`. These error codes should have their namespace first in
ALL CAPS, followed by a single \_ to ease separating the namespace from
the error code. For example, if there was a custom namespace
`com.mydomain.here`, and a `FORBIDDEN` code, the error code should look
like `COM.MYDOMAIN.HERE_FORBIDDEN`. There may be additional keys
depending on the error, but the keys `error` and `errcode` MUST always
be present.
sentence explaining what went wrong.
The `errcode` string will be a unique string which can be used to handle an
error message e.g. `M_FORBIDDEN`. Error codes should have their namespace
first in ALL CAPS, followed by a single `_`. For example, if there was a custom
namespace `com.mydomain.here`, and a `FORBIDDEN` code, the error code should
look like `COM.MYDOMAIN.HERE_FORBIDDEN`. Error codes defined by this
specification should start `M_`.
Some `errcode`s define additional keys which should be present in the error
response object, but the keys `error` and `errcode` MUST always be present.
Errors are generally best expressed by their error code rather than the
HTTP status code returned. When encountering the error code `M_UNKNOWN`,
@ -66,7 +63,9 @@ found. However, if the client were to receive an error code of
`M_UNKNOWN` with a 400 Bad Request, the client should assume that the
request being made was invalid.
The common error codes are:
#### Common error codes
These error codes can be returned by any API endpoint:
`M_FORBIDDEN`
Forbidden access, e.g. joining a room without permission, failed login.
@ -98,7 +97,11 @@ then try again.
`M_UNKNOWN`
An unknown error has occurred.
Other error codes the client might encounter are:
#### Other error codes
The following error codes are specific to certain endpoints.
<!-- TODO: move them to the endpoints that return them -->.
`M_UNRECOGNIZED`
The server did not understand the request.
@ -226,7 +229,7 @@ headers to be returned by servers on all requests are:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization
## Server Discovery

@ -528,7 +528,9 @@ 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.
request, specifying the verification method to use. This behaviour is
deprecated, and new clients should not begin verifications in this way.
However, clients should handle such verifications started by other clients.
Individual verification methods may add additional steps, events, and
properties to the verification messages. Event types for methods defined

@ -134,6 +134,15 @@ to send. The process overall is as follows:
8448 and a `Host` header containing the `<hostname>`. The target
server must present a valid certificate for `<hostname>`.
{{% boxes/note %}}
The reasons we require `<hostname>` rather than `<delegated_hostname>` for SRV
delegation are:
1. DNS is insecure (not all domains have DNSSEC), so the target of the delegation
must prove that it is a valid delegate for `<hostname>` via TLS.
2. Consistency with the recommendations in [RFC6125](https://datatracker.ietf.org/doc/html/rfc6125#section-6.2.1)
and other applications using SRV records such [XMPP](https://datatracker.ietf.org/doc/html/rfc6120#section-13.7.2.1).
{{% /boxes/note %}}
The TLS certificate provided by the target server must be signed by a
known Certificate Authority. Servers are ultimately responsible for
determining the trusted Certificate Authorities, however are strongly
@ -500,15 +509,15 @@ Example
As an example consider the event graph:
A
/
A
/
B
where `B` is a ban of a user `X`. If the user `X` tries to set the topic
by sending an event `C` while evading the ban:
A
/ \
A
/ \
B C
servers that receive `C` after `B` should soft fail event `C`, and so
@ -518,11 +527,11 @@ will neither relay `C` to its clients nor send any events referencing
If later another server sends an event `D` that references both `B` and
`C` (this can happen if it received `C` before `B`):
A
/ \
A
/ \
B C
\ /
D
\ /
D
then servers will handle `D` as normal. `D` is sent to the servers'
clients (assuming `D` passes auth checks). The state at `D` may resolve
@ -539,18 +548,18 @@ state of the `C` branch.
Let's go back to the graph before `D` was sent:
A
/ \
A
/ \
B C
If all the servers in the room saw `B` before `C` and so soft fail `C`,
then any new event `D'` will not reference `C`:
A
/ \
A
/ \
B C
|
D
D'
#### Retrieving event authorization information
@ -584,15 +593,15 @@ state.
For example, consider the following event graph (where the oldest event,
E0, is at the top):
E0
|
E1
/ \
E0
|
E1
/ \
E2 E4
| |
E3 |
\ /
E5
\ /
E5
Suppose E3 and E4 are both `m.room.name` events which set the name of
the room. What should the name of the room be at E5?

@ -87,7 +87,7 @@ paths:
associated the third party identifier with the user.
required: ['medium', 'address', 'validated_at', 'added_at']
tags:
- User data
- Account management
post:
summary: Adds contact information to the user's account.
description: |-
@ -154,6 +154,7 @@ paths:
properties:
submit_url:
type: string
format: uri
description: |-
An optional field containing a URL where the client must
submit the validation token to, with identical parameters
@ -178,7 +179,7 @@ paths:
schema:
"$ref": "definitions/errors/error.yaml"
tags:
- User data
- Account management
"/account/3pid/add":
post:
summary: Adds contact information to the user's account.
@ -234,7 +235,7 @@ paths:
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- User data
- Account management
"/account/3pid/bind":
post:
summary: Binds a 3PID to the user's account through an Identity Service.
@ -288,7 +289,7 @@ paths:
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- User data
- Account management
"/account/3pid/delete":
post:
summary: Deletes a third party identifier from the user's account
@ -345,7 +346,7 @@ paths:
description: |-
An indicator as to whether or not the homeserver was able to unbind
the 3PID from the identity server. `success` indicates that the
indentity server has unbound the identifier whereas `no-support`
identity server has unbound the identifier whereas `no-support`
indicates that the identity server refuses to support the request
or the homeserver was not able to determine an identity server to
unbind from.
@ -353,7 +354,7 @@ paths:
required:
- id_server_unbind_result
tags:
- User data
- Account management
"/account/3pid/unbind":
post:
summary: Removes a user's third party identifier from an identity server.
@ -417,7 +418,7 @@ paths:
required:
- id_server_unbind_result
tags:
- User data
- Account management
"/account/3pid/email/requestToken":
post:
summary: Begins the validation process for an email address for association with the user's account.
@ -469,6 +470,8 @@ paths:
"errcode": "M_THREEPID_IN_USE",
"error": "Third party identifier already in use"
}
tags:
- Account management
"/account/3pid/msisdn/requestToken":
post:
summary: Begins the validation process for a phone number for association with the user's account.
@ -517,3 +520,5 @@ paths:
"errcode": "M_THREEPID_IN_USE",
"error": "Third party identifier already in use"
}
tags:
- Account management

@ -66,6 +66,7 @@ paths:
properties:
content_uri:
type: string
format: uri
description: "The [MXC URI](/client-server-api/#matrix-content-mxc-uris) to the uploaded content."
examples:
application/json: {
@ -360,6 +361,7 @@ paths:
parameters:
- in: query
type: string
format: uri
x-example: "https://matrix.org"
name: url
description: "The URL to get a preview of."
@ -389,6 +391,7 @@ paths:
The byte-size of the image. Omitted if there is no image attached.
"og:image":
type: string
format: uri
description: |-
An [MXC URI](/client-server-api/#matrix-content-mxc-uris) to the image. Omitted if there is no image.
examples:

@ -48,16 +48,18 @@ paths:
(and not other members) permission to send state events. Overridden
by the `power_level_content_override` parameter.
4. Events set by the `preset`. Currently these are the `m.room.join_rules`,
4. An `m.room.canonical_alias` event if `room_alias_name` is given.
5. Events set by the `preset`. Currently these are the `m.room.join_rules`,
`m.room.history_visibility`, and `m.room.guest_access` state events.
5. Events listed in `initial_state`, in the order that they are
6. Events listed in `initial_state`, in the order that they are
listed.
6. Events implied by `name` and `topic` (`m.room.name` and `m.room.topic`
7. Events implied by `name` and `topic` (`m.room.name` and `m.room.topic`
state events).
7. Invite events implied by `invite` and `invite_3pid` (`m.room.member` with
8. Invite events implied by `invite` and `invite_3pid` (`m.room.member` with
`membership: invite` and `m.room.third_party_invite`).
The available presets do the following with respect to room state:
@ -112,7 +114,8 @@ paths:
would be `#foo:example.com`.
The complete room alias will become the canonical alias for
the room.
the room and an `m.room.canonical_alias` event will be sent
into the room.
name:
type: string
description: |-

@ -42,6 +42,7 @@ paths:
name: keys
description: |-
The keys to be published.
required: true
schema:
type: object
properties:
@ -66,6 +67,12 @@ paths:
request.
allOf:
- $ref: definitions/cross_signing_key.yaml
auth:
description: |-
Additional authentication information for the
user-interactive authentication API.
allOf:
- $ref: "definitions/auth_data.yaml"
example: {
"master_key": {
"user_id": "@alice:example.com",
@ -129,6 +136,8 @@ paths:
"errcode": "M_FORBIDDEN",
"error": "Key ID in use"
}
tags:
- End-to-end encryption
"/keys/signatures/upload":
post:
summary: Upload cross-signing signatures.
@ -143,6 +152,7 @@ paths:
name: signatures
description: |-
The signatures to be published.
required: true
schema:
type: object
title: Signatures
@ -222,3 +232,5 @@ paths:
}
}
}
tags:
- End-to-end encryption

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
type: object
title: Error
description: A Matrix-level Error
properties:
errcode:
@ -22,4 +23,4 @@ properties:
type: string
description: A human-readable error message.
example: An unknown error occurred
required: ["errcode"]
required: ["errcode"]

@ -13,6 +13,7 @@
# limitations under the License.
$ref: error.yaml
type: object
title: RateLimitError
description: The rate limit was reached for this request
properties:
errcode:
@ -29,4 +30,4 @@ properties:
The amount of time in milliseconds the client should wait
before trying the request again.
example: 2000
required: ["errcode"]
required: ["errcode"]

@ -21,3 +21,4 @@ properties:
type: object
type: array
type: object
title: EventBatch

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
type: object
title: OpenIdCredentials
properties:
access_token:
type: string

@ -68,6 +68,7 @@ properties:
rules like any other user.
avatar_url:
type: string
format: uri
description: The URL for the room's avatar, if one is set.
join_rule:
type: string
@ -110,4 +111,4 @@ example: {
"next_batch": "p190q",
"prev_batch": "p1902",
"total_room_count_estimate": 115
}
}

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
type: object
title: RequestTokenResponse
properties:
sid:
type: string
@ -22,6 +23,7 @@ properties:
example: "123abc"
submit_url:
type: string
format: uri
description: |-
An optional field containing a URL where the client must submit the
validation token to, with identical parameters to the Identity Service

@ -25,3 +25,4 @@ properties:
- origin_server_ts
type: array
type: object
title: RoomEventBatch

@ -26,3 +26,4 @@ properties:
- state_key
type: array
type: object
title: StateEventBatch

@ -24,3 +24,4 @@ properties:
rooms/{roomId}/messages endpoint.
type: string
type: object
title: TimelineBatch

@ -18,6 +18,7 @@ type: object
properties:
base_url:
type: string
format: uri
description: The base URL for the homeserver for client-server connections.
example: https://matrix.example.com
required:

@ -18,6 +18,7 @@ type: object
properties:
base_url:
type: string
format: uri
description: The base URL for the identity server for client-server connections.
example: https://identity.example.com
required:

@ -375,7 +375,7 @@ paths:
summary: Store a key in the backup.
description: |-
Store a key in the backup.
operationId: postRoomKeysKeyRoomIdSessionId
operationId: putRoomKeysBySessionId
security:
- accessToken: []
parameters:
@ -409,6 +409,7 @@ paths:
description: The update succeeded.
schema:
type: object
title: RoomKeysUpdateResponse
properties:
etag:
description: |-
@ -443,10 +444,10 @@ paths:
tags:
- End-to-end encryption
get:
summary: Retrieve a key from the backup
summary: Retrieve a key from the backup.
description: |-
Retrieve a key from the backup.
operationId: getRoomKeysKeyRoomIdSessionId
operationId: getRoomKeysBySessionId
security:
- accessToken: []
parameters:
@ -487,11 +488,13 @@ paths:
description: This request was rate-limited.
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- End-to-end encryption
delete:
summary: Delete a key from the backup
summary: Delete a key from the backup.
description: |-
Delete a key from the backup.
operationId: deleteRoomKeysKeyRoomIdSessionId
operationId: deleteRoomKeysBySessionId
security:
- accessToken: []
parameters:
@ -519,6 +522,7 @@ paths:
description: The update succeeded
schema:
type: object
title: RoomKeysUpdateResponse
properties:
etag:
description: |-
@ -547,12 +551,14 @@ paths:
description: This request was rate-limited.
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- End-to-end encryption
"/room_keys/keys/{roomId}":
put:
summary: Store several keys in the backup for a given room.
description: |-
Store a key in the backup.
operationId: postRoomKeysKeyRoomId
Store several keys in the backup for a given room.
operationId: putRoomKeysByRoomId
security:
- accessToken: []
parameters:
@ -580,6 +586,7 @@ paths:
description: The update succeeded
schema:
type: object
title: RoomKeysUpdateResponse
properties:
etag:
description: |-
@ -624,10 +631,10 @@ paths:
tags:
- End-to-end encryption
get:
summary: Retrieve the keys from the backup for a given room
summary: Retrieve the keys from the backup for a given room.
description: |-
Retrieve the keys from the backup for a given room
operationId: getRoomKeysKeyRoomId
Retrieve the keys from the backup for a given room.
operationId: getRoomKeysByRoomId
security:
- accessToken: []
parameters:
@ -666,11 +673,13 @@ paths:
description: This request was rate-limited.
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- End-to-end encryption
delete:
summary: Delete a key from the backup
summary: Delete the keys from the backup for a given room.
description: |-
Delete a key from the backup.
operationId: deleteRoomKeysKeyRoomId
Delete the keys from the backup for a given room.
operationId: deleteRoomKeysByRoomId
security:
- accessToken: []
parameters:
@ -692,6 +701,7 @@ paths:
description: The update succeeded
schema:
type: object
title: RoomKeysUpdateResponse
properties:
etag:
description: |-
@ -720,12 +730,14 @@ paths:
description: This request was rate-limited.
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- End-to-end encryption
"/room_keys/keys":
put:
summary: Store several keys in the backup.
description: |-
Store several keys in the backup.
operationId: postRoomKeysKey
operationId: putRoomKeys
security:
- accessToken: []
parameters:
@ -773,6 +785,7 @@ paths:
description: The update succeeded
schema:
type: object
title: RoomKeysUpdateResponse
properties:
etag:
description: |-
@ -817,10 +830,10 @@ paths:
tags:
- End-to-end encryption
get:
summary: Retrieve the keys from the backup for a given room
summary: Retrieve the keys from the backup.
description: |-
Retrieve the keys from the backup for a given room
operationId: getRoomKeysKeyRoomId
Retrieve the keys from the backup.
operationId: getRoomKeys
security:
- accessToken: []
parameters:
@ -875,11 +888,13 @@ paths:
description: This request was rate-limited.
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- End-to-end encryption
delete:
summary: Delete a key from the backup
summary: Delete the keys from the backup.
description: |-
Delete a key from the backup.
operationId: deleteRoomKeysKeyRoomId
Delete the keys from the backup.
operationId: deleteRoomKeys
security:
- accessToken: []
parameters:
@ -895,6 +910,7 @@ paths:
description: The update succeeded
schema:
type: object
title: RoomKeysUpdateResponse
properties:
etag:
description: |-
@ -923,3 +939,5 @@ paths:
description: This request was rate-limited.
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- End-to-end encryption

@ -61,6 +61,8 @@ paths:
}
schema:
"$ref": "definitions/errors/error.yaml"
tags:
- Room discovery
put:
summary: Sets the visibility of a room in the room directory
description: |-
@ -111,6 +113,8 @@ paths:
}
schema:
"$ref": "definitions/errors/error.yaml"
tags:
- Room discovery
"/publicRooms":
get:
summary: Lists the public rooms on the server.

@ -27,9 +27,11 @@ produces:
securityDefinitions:
$ref: definitions/security.yaml
paths:
"/events":
# With an extra " " to disambiguate from the getEvents endpoint
# The extra space makes it sort first for what I'm sure is a good reason.
"/events ":
get:
summary: Listen on the event stream.
summary: Listen on the event stream of a particular room.
description: |-
This will listen for new events related to a particular room and return
them to the caller. This will block until an event is received, or until
@ -103,4 +105,5 @@ paths:
- "$ref": "../../event-schemas/schema/core-event-schema/room_event.yaml"
400:
description: "Bad pagination `from` parameter."
# No tags to exclude this from the swagger UI - use the normal version instead.
tags:
- Room participation

@ -129,6 +129,7 @@ paths:
properties:
avatar_url:
type: string
format: uri
description: The new avatar URL for this user.
responses:
200:
@ -170,6 +171,7 @@ paths:
properties:
avatar_url:
type: string
format: uri
description: The user's avatar URL if they have set one, otherwise not present.
404:
description: There is no avatar URL for this user or this user does not exist.
@ -204,6 +206,7 @@ paths:
properties:
avatar_url:
type: string
format: uri
description: The user's avatar URL if they have set one, otherwise not present.
displayname:
type: string

@ -113,6 +113,7 @@ paths:
properties:
url:
type: string
format: uri
description: |-
Required if `kind` is `http`. The URL to use to send
notifications to.
@ -220,6 +221,7 @@ paths:
properties:
url:
type: string
format: uri
description: |-
Required if `kind` is `http`. The URL to use to send
notifications to. MUST be an HTTPS URL with a path of

@ -61,6 +61,7 @@ paths:
description: |-
Extra receipt information to attach to `content` if any. The
server will automatically set the `ts` field.
required: true
schema:
type: object
example: {

@ -214,7 +214,7 @@ paths:
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- User data
- Account management
"/register/email/requestToken":
post:
summary: Begins the validation process for an email to be used during registration.
@ -265,6 +265,8 @@ paths:
}
schema:
"$ref": "definitions/errors/error.yaml"
tags:
- Account management
"/register/msisdn/requestToken":
post:
summary: Requests a validation token be sent to the given phone number for the purpose of registering an account
@ -315,6 +317,8 @@ paths:
}
schema:
"$ref": "definitions/errors/error.yaml"
tags:
- Account management
"/account/password":
post:
summary: "Changes a user's password."
@ -378,7 +382,7 @@ paths:
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- User data
- Account management
"/account/password/email/requestToken":
post:
summary: Requests a validation token be sent to the given email address for the purpose of resetting a user's password
@ -434,6 +438,8 @@ paths:
"errcode": "M_THREEPID_NOT_FOUND",
"error": "Email not found"
}
tags:
- Account management
"/account/password/msisdn/requestToken":
post:
summary: Requests a validation token be sent to the given phone number for the purpose of resetting a user's password.
@ -489,6 +495,8 @@ paths:
"errcode": "M_THREEPID_NOT_FOUND",
"error": "Phone number not found"
}
tags:
- Account management
"/account/deactivate":
post:
summary: "Deactivate a user's account."
@ -565,7 +573,7 @@ paths:
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- User data
- Account management
"/register/available":
get:
summary: Checks to see if a username is available on the server.
@ -627,4 +635,4 @@ paths:
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- User data
- Account management

@ -49,6 +49,7 @@ paths:
x-example: "$something:example.org"
- in: body
name: body
required: true
schema:
type: object
example: {

@ -65,6 +65,7 @@ paths:
x-example: "35"
- in: body
name: body
required: true
schema:
type: object
example: {

@ -74,6 +74,7 @@ paths:
x-example: "@alice:example.com"
- in: body
name: body
required: true
schema:
type: object
example: {

@ -206,6 +206,7 @@ paths:
enum:
- join
- invite
- knock
- leave
- ban
description: |-
@ -220,6 +221,7 @@ paths:
enum:
- join
- invite
- knock
- leave
- ban
description: |-
@ -301,6 +303,7 @@ paths:
description: The display name of the user this object is representing.
avatar_url:
type: string
format: uri
description: The mxc avatar url of the user this object is representing.
description: A map from user ID to a RoomMember object.
type: object

@ -238,6 +238,7 @@ paths:
title: Display name
avatar_url:
type: string
format: uri
title: Avatar Url
events_before:
type: array

@ -46,6 +46,8 @@ paths:
headers:
Location:
type: "string"
tags:
- Session management
"/login/sso/redirect/{idpId}":
get:
summary: Redirect the user's browser to the SSO interface for an IdP.
@ -56,7 +58,7 @@ paths:
The server MUST respond with an HTTP redirect to the SSO interface
for that IdP.
operationId: redirectToSSO
operationId: redirectToIdP
parameters:
- in: path
type: string
@ -83,3 +85,5 @@ paths:
The IdP ID was not recognized by the server. The server is encouraged
to provide a user-friendly page explaining the error given the user
will be navigated to it.
tags:
- Session management

@ -42,6 +42,8 @@ paths:
description: The protocols supported by the homeserver.
schema:
$ref: ../application-service/definitions/protocol_metadata.yaml
tags:
- Third Party Lookup
"/thirdparty/protocol/{protocol}":
get:
summary: Retrieve metadata about a specific protocol that the homeserver supports.
@ -71,6 +73,8 @@ paths:
}
schema:
$ref: definitions/errors/error.yaml
tags:
- Third Party Lookup
"/thirdparty/location/{protocol}":
get:
summary: Retrieve Matrix-side portals rooms leading to a third party location.
@ -112,6 +116,8 @@ paths:
}
schema:
$ref: definitions/errors/error.yaml
tags:
- Third Party Lookup
"/thirdparty/user/{protocol}":
get:
summary: Retrieve the Matrix User ID of a corresponding third party user.
@ -147,6 +153,8 @@ paths:
}
schema:
$ref: definitions/errors/error.yaml
tags:
- Third Party Lookup
"/thirdparty/location":
get:
summary: Reverse-lookup third party locations given a Matrix room alias.
@ -177,6 +185,8 @@ paths:
}
schema:
$ref: definitions/errors/error.yaml
tags:
- Third Party Lookup
"/thirdparty/user":
get:
summary: Reverse-lookup third party users given a Matrix User ID.
@ -206,3 +216,5 @@ paths:
}
schema:
$ref: definitions/errors/error.yaml
tags:
- Third Party Lookup

@ -47,6 +47,7 @@ paths:
parameters:
- in: body
name: body
required: true
schema:
type: object
properties:
@ -95,6 +96,7 @@ paths:
description: The display name of the user, if one exists.
avatar_url:
type: string
format: uri
example: "mxc://bar.com/foo"
description: The avatar url, as an MXC, if one exists.
limited:
@ -105,4 +107,4 @@ paths:
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- User data
- User directory

@ -89,4 +89,4 @@ paths:
schema:
"$ref": "definitions/errors/rate_limited.yaml"
tags:
- User data
- Session management

@ -96,7 +96,7 @@ paths:
"ed25519:base64+master+public+key": "base64+master+public+key",
}
}
self_signing_keys:
self_signing_key:
type: object
description: |-
The user\'s self-signing key.

@ -45,6 +45,7 @@ properties:
avatar_url:
description: 'The avatar URL for this user, if any.'
type: string
format: uri
displayname:
description: 'The display name for this user, if any.'
type:

@ -10,7 +10,7 @@ properties:
description: A server-defined message.
replacement_room:
type: string
description: The new room the client should be visiting.
description: The room ID of the new room the client should be visiting.
required:
- replacement_room
- body

@ -45,8 +45,10 @@
{{ $status := .Site.Params.version.status }}
{{ if ne $status "unstable"}}
{{ $ret = .Site.Params.version.number }}
{{ $ret = delimit (slice "version" $ret) " " }}
{{ $path := path.Join "changelogs" }}
{{/* produces a string similar to "version v1.5" */}}
{{ $ret = delimit (slice "version v" .Site.Params.version.major "." .Site.Params.version.minor) "" }}
{{ end }}
{{ return $ret }}

@ -7,22 +7,26 @@
it expects to find newsfragments describing changes to that API.
If the `version.status` setting in config.toml is anything other than
"unstable", then it also expects to find a "release.yaml" file in /changelogs,
which contains:
- `tag`: Git tag for this release
- `date`: date of this release
It then renders this info a table, before the list of changes.
"unstable", then it also expects to find additional settings under
`version` in config.toml:
- `major`: the major version number of the release
- `minor`: the minor version number of the release
- `release_date`: the date of the release
The release tag is calculated as `v<major>.<minor>`; for example `v1.5`.
It then renders this into a table displayed before the list of changes.
*/}}
{{ $path := path.Join "changelogs" }}
{{ $status := .Site.Params.version.status }}
{{ $release_tag := delimit (slice "v" .Site.Params.version.major "." .Site.Params.version.minor) "" }}
{{ if ne $status "unstable" }}
{{ $release_info := readFile (path.Join $path "release.yaml") | transform.Unmarshal }}
<table class="release-info">
<tr><th>Git commit</th><td><a href="https://github.com/matrix-org/matrix-doc/tree/{{ $release_info.tag }}">https://github.com/matrix-org/matrix-doc/tree/{{ $release_info.tag }}</a></td>
<tr><th>Release date</th><td>{{ $release_info.date }}</td>
<tr><th>Git commit</th><td><a href="https://github.com/matrix-org/matrix-doc/tree/{{ $release_tag }}">https://github.com/matrix-org/matrix-doc/tree/{{ $release_tag }}</a></td>
<tr><th>Release date</th><td>{{ .Site.Params.version.release_date }}</td>
</table>
{{ end }}

@ -8,8 +8,12 @@
{{ $status := .Site.Params.version.status }}
{{ if eq $status "unstable"}}
<p>This is the <strong>unstable</strong> version of the Matrix specification.</p>
<p>This changelog lists changes made since the last release of the specification.</p>
{{ else }}
<p>This is version <strong>{{ .Site.Params.version.number }}</strong> of the Matrix specification.</p>
<p>This is version <strong>v{{ .Site.Params.version.major }}.{{ .Site.Params.version.minor }}</strong> of the Matrix specification.</p>
{{ end }}

@ -8,7 +8,7 @@ in.
Format
------
Documentation is written in github-flavored markdown.
Documentation is written in Commonmark markdown.
Sections
--------
@ -66,6 +66,12 @@ Lists should:
* Be used where they provide clarity.
* Contain entries which start with a capital and end with a full stop.
When talking about properties in JSON objects, prefer the word "property" to "field",
"member", or various other alternatives. For example: "this property will be set to
X if ...". Also avoid the term "key" unless you are specifically talking about the
*name* of a property - and be mindful of the scope for confusion with cryptographic
keys.
OpenAPI
~~~~~~~

92
package-lock.json generated

@ -97,22 +97,10 @@
"postcss-value-parser": "^4.1.0"
},
"dependencies": {
"postcss": {
"version": "7.0.32",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
"integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
@ -135,15 +123,48 @@
}
},
"browserslist": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.0.tgz",
"integrity": "sha512-pUsXKAF2lVwhmtpeA3LJrZ76jXuusrNyhduuQs7CDFf9foT4Y38aQOserd2lMe5DSSrjf3fx34oHwryuvxAUgQ==",
"version": "4.16.6",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
"integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30001111",
"electron-to-chromium": "^1.3.523",
"escalade": "^3.0.2",
"node-releases": "^1.1.60"
"caniuse-lite": "^1.0.30001219",
"colorette": "^1.2.2",
"electron-to-chromium": "^1.3.723",
"escalade": "^3.1.1",
"node-releases": "^1.1.71"
},
"dependencies": {
"caniuse-lite": {
"version": "1.0.30001230",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz",
"integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==",
"dev": true
},
"colorette": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
"integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
"dev": true
},
"electron-to-chromium": {
"version": "1.3.739",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.739.tgz",
"integrity": "sha512-+LPJVRsN7hGZ9EIUUiWCpO7l4E3qBYHNadazlucBfsXBbccDFNKUBAgzE68FnkWGJPwD/AfKhSzL+G+Iqb8A4A==",
"dev": true
},
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"dev": true
},
"node-releases": {
"version": "1.1.72",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz",
"integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==",
"dev": true
}
}
},
"caller-callsite": {
@ -274,12 +295,6 @@
"path-type": "^4.0.0"
}
},
"electron-to-chromium": {
"version": "1.3.534",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.534.tgz",
"integrity": "sha512-7x2S3yUrspNHQOoPk+Eo+iHViSiJiEGPI6BpmLy1eT2KRNGCkBt/NUYqjfXLd1DpDCQp7n3+LfA1RkbG+LqTZQ==",
"dev": true
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@ -295,12 +310,6 @@
"is-arrayish": "^0.2.1"
}
},
"escalade": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz",
"integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@ -387,9 +396,9 @@
"dev": true
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
@ -418,8 +427,7 @@
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"ignore": {
"version": "5.1.8",
@ -575,12 +583,6 @@
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
"dev": true
},
"node-releases": {
"version": "1.1.60",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz",
"integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==",
"dev": true
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -658,9 +660,9 @@
"dev": true
},
"postcss": {
"version": "7.0.32",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
"integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
"version": "7.0.36",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
"dev": true,
"requires": {
"chalk": "^2.4.2",

@ -126,7 +126,7 @@ relationship can be expressed in one of two ways:
`origin_server_ts` of their `m.room.create` events, or ascending
lexicographic order of their `room_id`s in case of equal
`origin_server_ts`. `order`s which are not strings, or do not consist
solely of ascii characters in the range `\x20` (space) to `\x7F` (`~`), or
solely of ascii characters in the range `\x20` (space) to `\x7E` (`~`), or
consist of more than 50 characters, are forbidden and the field should be
ignored if received.)

@ -23,8 +23,8 @@ Sydent.
This proposal suggests changing the specification of the e-mail 3PID type in
[the Matrix spec appendices](https://matrix.org/docs/spec/appendices#pid-types)
to mandate that, before any processing, e-mail addresses must go through a full
case folding based on [the unicode mapping
file](https://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt), on top of
case folding as described under "Caseless Matching" in
[chapter 5 of the unicode standard](https://www.unicode.org/versions/Unicode13.0.0/ch05.pdf#G21790), on top of
having their domain lowercased.
This means that `Strauß@Example.com` must be considered as being the same e-mail

@ -0,0 +1,97 @@
# MSC2732: Olm fallback keys
Olm uses a set of one-time keys when initializing a session between two
devices: Alice uploads one-time keys to her homeserver, and Bob claims one of
them to perform a Diffie-Hellman to generate a shared key. As implied by the
name, a one-time key is only to be used once. However, if all of Alice's
one-time keys are claimed, Bob will not be able to create a session with Alice.
This can be addressed by Alice uploading a fallback key that is used in place
of a one-time key when no one-time keys are available.
## Proposal
A new request parameter, `fallback_keys`, is added to the body of the
[`/keys/upload` client-server API](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-upload), which is in the same format as the
`one_time_keys` parameter with the exception that there must be at most one key
per key algorithm. If the user had previously uploaded a fallback key for a
given algorithm, it is replaced -- the server will only keep one fallback key
per algorithm for each user.
When uploading fallback keys for algorithms whose key format is a signed JSON
object, client should include a property named `fallback` with a value of
`true`.
Example:
`POST /keys/upload`
```json
{
"fallback_keys": {
"signed_curve25519:AAAAAA": {
"key": "base64+public+key",
"fallback": true,
"signatures": {
"@alice:example.org": {
"ed25519:DEVICEID": "base64+signature"
}
}
}
}
}
```
When Bob calls `/keys/claim` to claim one of Alice's one-time keys, but Alice
has no one-time keys left, the homeserver will return the fallback key instead,
if Alice had previously uploaded one. Unlike with one-time keys, fallback keys
are not deleted when they are returned by `/keys/claim`. However, the server
marks that they have been used.
A new response parameter, `device_unused_fallback_key_types`, is added to
`/sync`. This is an array listing the key algorithms for which the server has
an unused fallback key for the device. If the client wants the server to have a
fallback key for a given key algorithm, but that algorithm is not listed in
`device_unused_fallback_key_types`, the client will upload a new key as above.
The `device_unused_fallback_key_types` parameter must be present if the server
supports fallback keys. Clients can thus treat this field as an indication
that the server supports fallback keys, and so only upload fallback keys to
servers that support them.
Example:
`GET /sync`
Response:
```jsonc
{
// other fields...
"device_unused_fallback_key_types": ["signed_curve25519"]
}
```
## Security considerations
Using a fallback key rather than a one-time key has security implications. An
attacker can replay a message that was originally sent with a fallback key, and
the receiving client will accept it as a new message if the fallback key is
still active. Also, an attacker that compromises a client may be able to
retrieve the private part of the fallback key to decrypt past messages if the
client has still retained the private part of the fallback key.
For this reason, clients should not store the private part of the fallback key
indefinitely. For example, client should only store at most two fallback keys:
the current fallback key (that it has not yet received any messages for) and
the previous fallback key, and should remove the previous fallback key once it
is reasonably certain that it has received all the messages that use it (for
example, one hour after receiving the first message that used it).
For addressing replay attacks, clients can also keep track of inbound sessions
to detect replays.
## Unstable prefix
The `fallback_keys` request parameter and the `device_unused_fallback_key_types`
response parameter will be prefixed by `org.matrix.msc2732.`.

@ -0,0 +1,135 @@
# MSC2778: Providing authentication method for appservice users
Appservices within Matrix are increasingly attempting to support End-to-End Encryption. As such, they
need a way to generate devices for their users so that they can participate in E2E rooms. In order to
do so, this proposal suggests implementing an appservice extension to the
[`POST /login` endpoint](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-login).
Appservice users do not usually need to log in as they do not need their own access token, and do not
traditionally need a "device". However, E2E encryption demands that at least one user in a room has a
Matrix device which means bridge users need to be able to generate a device on demand. In the past,
bridge developers have used the bridge bot's device for all bridge users in the room, but this causes
problems should the bridge wish to only join ghosts to a room (e.g. for DMs).
Another advantage this provides is that an appservice can now be used to generate access tokens for
any user in its namespace without having to set a password for that user, which may be useful where
maintaining password(s) in the configuration is undesirable.
## Proposal
A new `type` is to be added to `POST /login`: `m.login.application_service`
The `/login` endpoint may now take an `access_token` in the same way that other
authenticated endpoints do. No additional parameters should be specified in the request body.
Example request
```json
{
"type": "m.login.application_service",
"identifier": {
"type": "m.id.user",
"user": "_bridge_alice"
}
}
```
Note: Implementations MUST use the `identifier.type`=`m.id.user` method of specifying the
localpart. The deprecated top-level `user` field **cannot** use this login flow type. This
is deliberate so as to coax developers into using the new identifier format when implementing
new flows.
The response body should be unchanged from the existing `/login` specification.
If one of the following conditions are true:
- The access token is not provided
- The access token does not correspond to an appservice
- Or the user has not previously been registered
Then the servers MUST reject with HTTP 403, with an `errcode` of `"M_FORBIDDEN"`.
If the access token DOES correspond to an appservice but the user is not inside its namespace,
then the `errcode` must be `"M_EXCLUSIVE"`.
Homeservers should ignore the `access_token` parameter if a type other than
`m.login.application_service` has been provided.
Appservices creating **new** users can still use the `/register` endpoint to generate an `access_token` / `device_id`
but for existing users, the `/login` endpoint can be used instead.
## Potential issues
This proposal means that there will be more calls to make when setting up a appservice user, when
using encryption. While this could be done during the registration step, this would prohibit creating
new devices should the appservice intentionally or inadvertently have lost the client-side device data.
## Alternatives
### 1. Include the token in the `/login` request body
One minor tweak to the current proposal could be to include the token as part of the auth data, rather than
being part of the header/params to the request. An argument could be made for either, but since the specification
expects the appservice to pass the token this way in all requests, including `/register`, it seems wise to keep
it that way.
### 2. Use implementation specific "shared secret" authentication
Some community members have used homeserver implementation details such as a "shared secret" authentication method to
log into the accounts without having to use the /login process at all. Synapse provides such a function,
but also means the appservice can now authenticate as any user on the homeserver. This is undesirable from a
security standpoint.
### 3. Keep using `/register` solely
A third option could be to create a new endpoint that simply creates a new device for an appservice user on demand.
Given the rest of the matrix eco-system does this with /login, and /login is already extensible with `type`, it would
create more work for all parties involved for little benefit.
Finally, `POST /register` does already return a `device_id` and `access_token` so appservices
could store this information rather than calling `POST /login` at all. This does however present a few problems:
- Quite a few appservices which only support unencrypted messaging do not use/store the `device_id`/`access_token` from a register call.
In the event that an appservice eventually gains the ability to support encryption, they would be unable to fetch a new `device_id`/
`access_token` for any existing users (as `/register` would fail for an existing user).
- If user tokens were lost or exposed, there is no way to programattically create new access tokens for these users.
- Finally, if a user was registered externally and the appservice would like to masquerade as it, it would be unable to fetch
an access token for that user.
While `POST /register` does work, it is impactical as the sole method of fetching an access token.
## Security considerations
Appservices could use this new functionality to generate devices for any userId that are within its namespace e.g. setting the
user namespace regex to `@.*:example.com` would allow appservice to control anyone on the homeserver. While this sounds scary, in practice
this is not a problem because:
- Appservice namespaces are maintained by the homeserver admin. If the namespace were to change, then it's reasonable
to assume that the server admin is aware. There is no defense mechanism to stop a malicious server admin from creating new
devices for a given user's account as they could also do so by simply modifying the database.
- While an appservice *could* try to masquerade as a user maliciously without the server admin expecting it, it would still
be bound by the restrictions of the namespace. Server admins are expected to be aware of the implications of adding new
appservices to their server so the burden of responsibility lies with the server admin.
- Appservices already can /sync as any user using the `as_token` and send any messages as any user in the namespace, the only
difference is that without a dedicated access token they are unable to receive device messages. While in theory this
does make them unable to see encrypted messages, this is not designed to be a security mechanism.
In conclusion this MSC only automates the creation of new devices for users inside an AS namespace, which is something
a server admin could already do. Appservices should always be treated with care and so with these facts in mind the MSC should
be considered secure.
## Unstable prefix
Implementations should use `uk.half-shot.msc2778.login.application_service` for `type` given in the
`POST /login` until this lands in a released version of the specification.
## Implementations
The proposal has been implemented by a homeserver, a bridge SDK and two bridges:
- [synapse](https://github.com/matrix-org/synapse/pull/8320)
- [mautrix-python](https://github.com/tulir/mautrix-python/commit/12d7c48ca7c15fd3ff61608369af1cf69e289aeb)
- [mautrix-whatsapp](https://github.com/tulir/mautrix-whatsapp/commit/ead8a869c84d07fadc7cfcf3d522452c99faaa36)
- [matrix-appservice-bridge](https://github.com/matrix-org/matrix-appservice-bridge/pull/231/files#diff-5e93f1b51d50a44fcf0ca46ea1793c1cR851-R864)

@ -0,0 +1,291 @@
# Restricting room membership based on membership in other rooms
A desirable feature is to give room admins the power to restrict membership of
their room based on the membership of one or more rooms.
Potential usecases include:
* Private spaces (allowing any member of a [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772)
space to join child rooms in that space), for example:
> members of the #doglovers:example.com space can join this room without an invitation<sup id="a1">[1](#f1)</sup>
* Room upgrades for private rooms (instead of issuing invites to each user).
* Allowing all users in a private room to be able to join a private breakout room.
This does not preclude members from being directly invited to the room, which is
still a useful discovery feature.
## Proposal
In a future room version a new `join_rule` (`restricted`) will be used to reflect
a cross between `invite` and `public` join rules. The content of the join rules
would include the rooms to trust for membership. For example:
```json
{
"type": "m.room.join_rules",
"state_key": "",
"content": {
"join_rule": "restricted",
"allow": [
{
"type": "m.room_membership",
"room_id": "!mods:example.org"
},
{
"type": "m.room_membership",
"room_id": "!users:example.org"
}
]
}
}
```
This means that a user must be a member of the `!mods:example.org` room or
`!users:example.org` room in order to join without an invite<sup id="a2">[2](#f2)</sup>.
Membership in a single allowed room is enough.
If the `allow` key is an empty list (or not a list at all), then no users are
allowed to join without an invite. Each entry is expected to be an object with the
following keys:
* `type`: `"m.room_membership"` to describe that we are allowing access via room
membership. Future MSCs may define other types.
* `room_id`: The room ID to check the membership of.
Any entries in the list which do not match the expected format are ignored. Thus,
if all entries are invalid, the list behaves as if empty and all users without
an invite are rejected.
The `allow` key is to be protected when redacting an event.
When a homeserver receives a `/join` request from a client or a `/make_join` /
`/send_join` request from another homeserver, the request should only be permitted
if the user is invited to this room, or is joined to one of the listed rooms. If
the user is not a member of at least one of the rooms, the homeserver should return
an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`.
It is possible for a resident homeserver (one which receives a `/make_join` /
`/send_join` request) to not know if the user is in some of the allowed rooms (due
to not participating in them). If the user is not in any of the allowed rooms that
are known to the homeserver, and the homeserver is not participating in all listed
rooms, then it should return an error response with HTTP status code of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should
attempt to join via another resident homeserver. If the resident homeserver knows
that the user is not in *any* of the allowed rooms it should return an error response
with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a
configuration error if there are allowed rooms with no participating authorised
servers.
A chosen resident homeserver might also be unable to issue invites (which, as below,
is a pre-requisite for generating a correctly-signed join event). In this case
it should return an error response with HTTP status code of 400 and an `errcode`
of `M_UNABLE_TO_GRANT_JOIN`. The joining server should attempt to join via another
resident homeserver.
From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules),
the `restricted` join rule has the same behavior as `public`, with the additional
caveat that servers must ensure that, for `m.room.member` events with a `membership` of `join`:
* The user's previous membership was `invite` or `join`, or
* The join event has a valid signature from a homeserver whose users have the
power to issue invites.
When generating a join event for `/join` or `/make_join`, the server should
include the MXID of a local user who could issue an invite in the content with
the key `join_authorised_via_users_server`. The actual user chosen is arbitrary.
The changes to the auth rules imply that:
* A join event issued via `/send_join` is signed by not just the requesting
server, but also the resident server.<sup id="a3">[3](#f3)</sup>
In order for the joining server to receive the proper signatures the join
event will be returned via `/send_join` in the `event` field.
* The auth chain of the join event needs to include events which prove
the homeserver can be issuing the join. This can be done by including:
* The `m.room.power_levels` event.
* The join event of the user specified in `join_authorised_via_users_server`.
It should be confirmed that the authorising user is in the room. (This
prevents situations where any homeserver could process the join, even if
they weren't in the room, under certain power level conditions.)
The above creates a new restriction on the relationship between the resident
servers used for `/make_join` and `/send_join` -- they must now both go to
the same server (since the `join_authorised_via_users_server` is added in
the call to `/make_join`, while the final signature is added during
the call to `/send_join`). If a request to `/send_join` is received that includes
an event from a different resident server it should return an error response with
HTTP status code of 400.
Note that the homeservers whose users can issue invites are trusted to confirm
that the `allow` rules were properly checked (since this cannot easily be
enforced over federation by event authorisation).<sup id="a4">[4](#f4)</sup>
To better cope with joining via aliases, homeservers should use the list of
authorised servers (not the list of candidate servers) when a user attempts to
join a room.
## Summary of the behaviour of join rules
See the [join rules](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-join-rules)
specification for full details; the summary below is meant to highlight the differences
between `public`, `invite`, and `restricted` from a user perspective. Note that
all join rules are subject to `ban` and `server_acls`.
* `public`: anyone can join, as today.
* `invite`: only people with membership `invite` can join, as today.
* `knock`: the same as `invite`, except anyone can knock. See
[MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403).
* `private`: This is reserved, but unspecified.
* `restricted`: the same as `invite`, except users may also join if they are a
member of a room listed in the `allow` rules.
## Security considerations
Increased trust to enforce the join rules during calls to `/join`, `/make_join`,
and `/send_join` is placed in the homeservers whose users can issue invites.
Although it is possible for those homeservers to issue a join event in bad faith,
there is no real-world benefit to doing this as those homeservers could easily
side-step the restriction by issuing an invite first anyway.
## Unstable prefix
The `restricted` join rule will be included in a future room version to allow
servers and clients to opt-into the new functionality.
During development, an unstable room version of `org.matrix.msc3083.v2` will be used.
Since the room version namespaces the behaviour, the `allow` key and value, as well
as the `restricted` join rule value do not need unstable prefixes.
An unstable key of `org.matrix.msc3083.v2.event` will be used in the response
from `/send_join` in place of `event` during development.
## Alternatives
It may seem that just having the `allow` key with `public` join rules is enough
(as originally suggested in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962)),
but there are concerns that changing the behaviour of a pre-existing `public`
join rule may cause security issues in older implementations (that do not yet
understand the new behaviour). This could be solved by introducing a new room
version, thus it seems clearer to introduce a new join rule -- `restricted`.
Using an `allow` key with the `invite` join rules to broaden who can join was rejected
as an option since it requires weakening the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules).
From the perspective of the auth rules, the `restricted` join rule is identical
to `public` with additional checks on the signature of the event.
## Future extensions
### Checking room membership over federation
If a homeserver is not in an allowed room (and thus doesn't know the
membership of it) then the server cannot enforce the membership checks while
generating a join event. Peeking over federation, as described in
[MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444),
could be used to establish if the user is in any of the proper rooms.
This would then delegate power out to a (potentially) untrusted server, giving that
peek server significant power. For example, a poorly chosen peek
server could lie about the room membership and add an `@evil_user:example.org`
to an allowed room to gain membership to a room.
As iterated above, this MSC recommends rejecting the join, potentially allowing
the requesting homeserver to retry via another homeserver.
### Kicking users out when they leave the allowed room
In the above example, suppose `@bob:server.example` leaves `!users:example.org`:
should they be removed from the room? Likely not, by analogy with what happens
when you switch the join rules from `public` to `invite`. Join rules currently govern
joins, not existing room membership.
It is left to a future MSC to consider this, but some potential thoughts are
given below.
If you assume that a user *should* be removed in this case, one option is to
leave the departure up to Bob's server `server.example`, but this places a
relatively high level of trust in that server. Additionally, if `server.example`
were offline, other users in the room would still see Bob in the room (and their
servers would attempt to send message traffic to it).
Another consideration is that users may have joined via a direct invite, not via
access through a room.
Fixing this is thorny. Some sort of annotation on the membership events might
help, but it's unclear what the desired semantics are:
* Assuming that users in an allowed room are *not* kicked when that room is
removed from `allow`, are those users then given a pass to remain
in the room indefinitely? What happens if the room is added back to
`allow` and *then* the user leaves it?
* Suppose a user joins a room via an allowed room (RoomA). Later, RoomB is added
to the `allow` list and RoomA is removed. What should happen when the
user leaves RoomB? Are they exempt from the kick?
It is possible that completely different state should be kept, or a different
`m.room.member` state could be used in a more reasonable way to track this.
### Inheriting join rules
If an allowed room is a space and you make a parent space invite-only, should that
(optionally?) cascade into child rooms? This would have some of the same problems
as inheriting power levels, as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962).
### Additional allow types
Future MSCs may wish to define additional values for the `type` argument, potentially
restricting access via:
* MXIDs or servers.
* A shared secret (room password).
These are just examples and are not fully thought through for this MSC, but it should
be possible to add these behaviors in the future.
### Client considerations
[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) defines a `via`
key in the content of `m.space.child` events:
> the content must contain a via `key` which gives a list of candidate servers
> that can be used to join the room.
It is possible for the list of candidate servers and the list of authorised
servers to diverge. It may not be possible for a user to join a room if there's
no overlap between these lists.
If there is some overlap between the lists of servers the join request should
complete successfully.
Clients should also consider the authorised servers when generating candidate
servers to embed in links to the room, e.g. via matrix.to.
A future MSC may define a way to override or update the `via` key in a coherent
manner.
## Footnotes
<a id="f1"/>[1]: The converse restriction, "anybody can join, provided they are not members
of the #catlovers:example.com space" is less useful since:
1. Users in the banned room could simply leave it at any time
2. This functionality is already partially provided by
[Moderation policy lists](https://matrix.org/docs/spec/client_server/r0.6.1#moderation-policy-lists). [](#a1)
<a id="f2"/>[2]: Note that there is nothing stopping users sending and
receiving invites in `public` rooms today, and they work as you might expect.
The only difference is that you are not *required* to hold an invite when
joining the room. [](#a2)
<a id="f3"/>[3]: This seems like an improvement regardless since the resident server
is accepting the event on behalf of the joining server and ideally this should be
verifiable after the fact, even for current room versions. Requiring all events
to be signed and verified in this way is left to a future MSC. [](#a3)
<a id="f4"/>[4]: This has the downside of increased centralisation, as some
homeservers that are already in the room may not issue a join event for another
user on that server. (It must go through the `/make_join` / `/send_join` flow of
a server whose users may issue invites.) This is considered a reasonable
trade-off. [](#a4)

@ -0,0 +1,195 @@
# MSC3173: Expose stripped state events to any potential joiner
It can be useful to view the partial state of a room before joining to allow a user
to know *what* they're joining. For example, it improves the user experience to
show the user the room name and avatar before joining.
It is already allowed to partially view the room state without being joined to
the room in some situations:
* If the room has `history_visibility: world_readable`, then anyone can inspect
it (by calling `/state` on it).
* Rooms in the [room directory](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-publicrooms)
expose some of their state publicly.
* [Invited users](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid)
and [knocking users](https://github.com/matrix-org/matrix-doc/pull/2403)
receive stripped state events to display metadata to users.
This MSC proposes formalizing that the stripped state that is currently available
to invited and knocking users is available to any user who could potentially join
a room. It also defines "stripped state" and consolidates the recommendation on
which events to include in the stripped state.
## Background
When creating an invite it is [currently recommended](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid)
to include stripped state events which are useful for displaying the invite to a user:
> An optional list of simplified events to help the receiver of the invite identify
> the room. The recommended events to include are the join rules, canonical alias,
> avatar, and name of the room.
The invited user receives these [stripped state events](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0sync)
as part of the `/sync` response:
> The state of a room that the user has been invited to. These state events may
> only have the `sender`, `type`, `state_key` and `content` keys present. These
> events do not replace any state that the client already has for the room, for
> example if the client has archived the room.
These are sent as part of the [`unsigned` content of the `m.room.member` event](https://spec.matrix.org/unstable/client-server-api/#mroommember)
containing the invite.
[MSC2403: Add "knock" feature](https://github.com/matrix-org/matrix-doc/pull/2403)
extends this concept to also include the stripped state events in the `/sync` response
for knocking users:
> It is proposed to add a fourth possible key to rooms, called `knock`. Its value
> is a mapping from room ID to room information. The room information is a mapping
> from a key `knock_state` to another mapping with key events being a list of
> `StrippedStateEvent`.
It is also provides an extended rationale of why this is useful:
> These stripped state events contain information about the room, most notably the
> room's name and avatar. A client will need this information to show a nice
> representation of pending knocked rooms. The recommended events to include are the
> join rules, canonical alias, avatar, name and encryption state of the room, rather
> than all room state. This behaviour matches the information sent to remote
> homeservers when remote users are invited to a room.
[MSC1772: Spaces](https://github.com/matrix-org/matrix-doc/pull/1772) additionally
recommends including the `m.room.create` event as one of the stripped state events:
> Join rules, invites and 3PID invites work as for a normal room, with the exception
> that `invite_state` sent along with invites should be amended to include the
> `m.room.create` event, to allow clients to discern whether an invite is to a
> space-room or not.
## Proposal
The specification does not currently define what "stripped state" is or formally
describe who can access it, instead it is specified that certain situations (e.g.
an invite or knock) provide a potential joiner with the stripped state of a room.
This MSC clarifies what "stripped state" is and formalizes who can access the
stripped state of a room in future cases.
Potential ways that a user might be able to join a room include, but are not
limited to, the following mechanisms:
* A room that has `join_rules` set to `public` or `knock`.
* A room that the user is in possession of an invite to (regardless of the `join_rules`).
This MSC proposes a formal definition for the stripped state of a room<sup id="a1">[1](#f1)</sup>:
> The stripped state of a room is a list of simplified state events to help a
> potential joiner identify the room. These state events may only have the
> `sender`, `type`, `state_key` and `content` keys present.
### Client behavior
These events do not replace any state that the client already has for the room,
for example if the client has archived the room. Instead the client should keep
two separate copies of the state: the one from the stripped state and one from the
archived state. If the client joins the room then the current state will be given
as a delta against the archived state not the stripped state.
### Server behavior
It is recommended (although not required<sup id="a2">[2](#f2)</sup>) that
homeserver implementations include the following events as part of the stripped
state of a room:
* Create event (`m.room.create`)<sup id="a3">[3](#f3)</sup>
* Join rules (`m.room.join_rules`)
* Canonical alias (`m.room.canonical_alias`)
* Room avatar (`m.room.avatar`)
* Room name (`m.room.name`)
* Encryption information (`m.room.encryption`)<sup id="a4">[4](#f4)</sup>
* Room topic (`m.room.topic`)<sup id="a5">[5](#f5)</sup>
## Potential issues
This is a formalization of current behavior and should not introduce new issues.
## Alternatives
A different approach would be to continue with what is done today for invites,
knocking, the room directory: separately specify that a user is allowed to see
the stripped state (and what events the stripped state should contain).
## Security considerations
This would allow for invisibly accessing the stripped state of a room with `public`
or `knock` join rules.
In the case of a public room, if the room has `history_visibility` set to `world_readable`
then this is no change. Additionally, this information is already provided by the
room directory (if the room is listed there). Otherwise, it is trivial to access
the state of the room by joining, but currently users in the room would know
that the join occurred.
Similarly, in the case of knocking, a user is able to trivially access the
stripped state of the room by knocking, but users in the room would know that
the knock occurred.
This does not seem to weaken the security expectations of either join rule.
## Future extensions
### Revisions to the room directory
A future MSC could include additional information from the stripped state events
in the [room directory](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-publicrooms).
The main missing piece seems to be the encryption information, but there may also
be other pieces of information to include.
### Additional ways to access the stripped state
[MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946) proposes including
the stripped state in the spaces summary. Not needing to rationalize what state
can be included for a potential joiner would simplify this (and future) MSCs.
### Additional ways to join a room
[MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083) proposes a new
join rule due to membership in a space. This MSC would clarify that the stripped
state of a room is available to those joiners.
### Dedicated API for accessing the stripped state
Dedicated client-server and server-server APIs could be added to request the
stripped state events, but that is considered out-of-scope for the current
proposal.
This API would allow any potential joiner to query for the stripped state. If
the server does not know the room's state it would need to query other servers
for it.
## Unstable prefix
N/A
## Footnotes
<a id="f1"/>[1]: No changes are proposed to
[the definition of `history_visibility`](https://matrix.org/docs/spec/client_server/latest#room-history-visibility).
The state of a room which is `world_readable` is available to anyone. This somewhat
implies that the stripped state is also available to anyone, regardless of the join
rules, but having a `world_readable`, `invite` room does not seem valuable. [](#a1)
<a id="f2"/>[2]: Privacy conscious deployments may wish to limit the metadata
available to users who are not in a room as the trade-off against user experience.
There seems to be no reason to not allow this. [](#a2)
<a id="f3"/>[3]: As updated in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772). [](#a3)
<a id="f4"/>[4]: The encryption information (`m.room.encryption`) is already sent
from Synapse and generally seems useful for a user to know before joining a room.
[](#a4)
<a id="f5"/>[5]: The room topic (`m.room.topic`) is included as part of the
[room directory](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-publicrooms)
response for public rooms. It is also planned to be included as part of [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946)
in the spaces summary response. [](#a5)

@ -0,0 +1,15 @@
# MSC3289: Room Version 8
A new room version, `8`, is proposed using [room version 7](https://spec.matrix.org/unstable/rooms/v7/)
as a base and incorporating the following MSCs:
* [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083) - Restricting room
membership based on membership in other rooms
Though other MSCs are capable of being included in this version, they do not have
sufficient implementation to be considered for this room version. A future room
version may include them.
Room version `8` upon being added to the specification shall be considered stable.
No other room versions are affected by this MSC. Before room version `8` can enter
the specification, MSC3083 needs to complete its final comment period.
Loading…
Cancel
Save