Add support for modules

pull/977/head
Will 4 years ago
parent 74adbfc1ec
commit 228c737f56
No known key found for this signature in database
GPG Key ID: 385872BB265E8BF8

@ -1940,3 +1940,692 @@ never succeeds without auth. Homeservers may allow requests that don't
require auth by offering a stage with only the `m.login.dummy` auth require auth by offering a stage with only the `m.login.dummy` auth
type, but they must still give a 401 response to requests with no auth type, but they must still give a 401 response to requests with no auth
data. data.
## Modules
Modules are parts of the Client-Server API which are not universal to
all endpoints. Modules are strictly defined within this specification
and should not be mistaken for experimental extensions or optional
features. A compliant server implementation MUST support all modules and
supporting specification (unless the implementation only targets clients
of certain profiles, in which case only the required modules for those
feature profiles MUST be implemented). A compliant client implementation
MUST support all the required modules and supporting specification for
the [Feature Profile](#feature-profiles) it targets.
### Feature Profiles
Matrix supports many different kinds of clients: from embedded IoT
devices to desktop clients. Not all clients can provide the same feature
sets as other clients e.g. due to lack of physical hardware such as not
having a screen. Clients can fall into one of several profiles and each
profile contains a set of features that the client MUST support. This
section details a set of "feature profiles". Clients are expected to
implement a profile in its entirety in order for it to be classified as
that profile.
#### Summary
<table>
<thead>
<tr class="header">
<th>Module / Profile</th>
<th>Web</th>
<th>Mobile</th>
<th>Desktop</th>
<th>CLI</th>
<th>Embedded</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><blockquote>
<p><a href="">Instant Messaging</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Direct Messaging</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Mentions</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Presence</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Push Notifications</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Receipts</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Fully read markers</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Typing Notifications</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">VoIP</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Ignoring Users</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Reporting Content</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Content Repository</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Managing History Visibility</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Server Side Search</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Room Upgrades</a></p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Required</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Server Administration</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Event Context</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Third Party Networks</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Send-to-Device Messaging</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Device Management</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">End-to-End Encryption</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Guest Accounts</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Room Previews</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Client Config</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">SSO Login</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">OpenID</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Stickers</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Server ACLs</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="odd">
<td><blockquote>
<p><a href="">Server Notices</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
<tr class="even">
<td><blockquote>
<p><a href="">Moderation policies</a></p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
<td><blockquote>
<p>Optional</p>
</blockquote></td>
</tr>
</tbody>
</table>
*Please see each module for more details on what clients need to
implement.*
#### Clients
##### Stand-alone web (`Web`)
This is a web page which heavily uses Matrix for communication.
Single-page web apps would be classified as a stand-alone web client, as
would multi-page web apps which use Matrix on nearly every page.
##### Mobile (`Mobile`)
This is a Matrix client specifically designed for consumption on mobile
devices. This is typically a mobile app but need not be so provided the
feature set can be reached (e.g. if a mobile site could display push
notifications it could be classified as a mobile client).
##### Desktop (`Desktop`)
This is a native GUI application which can run in its own environment
outside a browser.
##### Command Line Interface (`CLI`)
This is a client which is used via a text-based terminal.
##### Embedded (`Embedded`)
This is a client which is embedded into another application or an
embedded device.
###### Application
This is a Matrix client which is embedded in another website, e.g. using
iframes. These embedded clients are typically for a single purpose
related to the website in question, and are not intended to be
fully-fledged communication apps.
###### Device
This is a client which is typically running on an embedded device such
as a kettle, fridge or car. These clients tend to perform a few
operations and run in a resource constrained environment. Like embedded
applications, they are not intended to be fully-fledged communication
systems.
{{% cs-modules %}}

@ -0,0 +1,32 @@
---
type: module
weight: 190
---
### Client Config
Clients can store custom config data for their account on their
homeserver. This account data will be synced between different devices
and can persist across installations on a particular device. Users may
only view the account data for their own account
The account\_data may be either global or scoped to a particular rooms.
#### Events
The client receives the account data as events in the `account_data`
sections of a `/sync`.
These events can also be received in a `/events` response or in the
`account_data` section of a room in `/sync`. `m.tag` events appearing in
`/events` will have a `room_id` with the room the tags are for.
#### Client Behaviour
{{account\_data\_cs\_http\_api}}
#### Server Behaviour
Servers MUST reject clients from setting account data for event types
that the server manages. Currently, this only includes
[m.fully\_read]().

@ -0,0 +1,13 @@
---
type: module
weight: 200
---
### Server Administration
This module adds capabilities for server administrators to inspect
server state and data.
#### Client Behaviour
{{admin\_cs\_http\_api}}

@ -0,0 +1,118 @@
---
type: module
weight: 70
---
### Content repository
The content repository (or "media repository") allows users to upload
files to their homeserver for later use. For example, files which the
user wants to send to a room would be uploaded here, as would an avatar
the user wants to use.
Uploads are POSTed to a resource on the user's local homeserver which
returns a MXC URI which can later be used to GET the download. Content
is downloaded from the recipient's local homeserver, which must first
transfer the content from the origin homeserver using the same API
(unless the origin and destination homeservers are the same).
When serving content, the server SHOULD provide a
`Content-Security-Policy` header. The recommended policy is
`sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; object-src 'self';`.
#### Matrix Content (MXC) URIs
Content locations are represented as Matrix Content (MXC) URIs. They
look like:
mxc://<server-name>/<media-id>
<server-name> : The name of the homeserver where this content originated, e.g. matrix.org
<media-id> : An opaque ID which identifies the content.
#### Client behaviour
Clients can upload and download content using the following HTTP APIs.
{{content\_repo\_cs\_http\_api}}
##### Thumbnails
The homeserver SHOULD be able to supply thumbnails for uploaded images
and videos. The exact file types which can be thumbnailed are not
currently specified - see [Issue
\#1938](https://github.com/matrix-org/matrix-doc/issues/1938) for more
information.
The thumbnail methods are "crop" and "scale". "scale" tries to return an
image where either the width or the height is smaller than the requested
size. The client should then scale and letterbox the image if it needs
to fit within a given rectangle. "crop" tries to return an image where
the width and height are close to the requested size and the aspect
matches the requested size. The client should scale the image if it
needs to fit within a given rectangle.
The dimensions given to the thumbnail API are the minimum size the
client would prefer. Servers must never return thumbnails smaller than
the client's requested dimensions, unless the content being thumbnailed
is smaller than the dimensions. When the content is smaller than the
requested dimensions, servers should return the original content rather
than thumbnail it.
Servers SHOULD produce thumbnails with the following dimensions and
methods:
- 32x32, crop
- 96x96, crop
- 320x240, scale
- 640x480, scale
- 800x600, scale
In summary:
- "scale" maintains the original aspect ratio of the image
- "crop" provides an image in the aspect ratio of the sizes given in
the request
- The server will return an image larger than or equal to the
dimensions requested where possible.
Servers MUST NOT upscale thumbnails under any circumstance. Servers MUST
NOT return a smaller thumbnail than requested, unless the original
content makes that impossible.
#### Security considerations
The HTTP GET endpoint does not require any authentication. Knowing the
URL of the content is sufficient to retrieve the content, even if the
entity isn't in the room.
MXC URIs are vulnerable to directory traversal attacks such as
`mxc://127.0.0.1/../../../some_service/etc/passwd`. This would cause the
target homeserver to try to access and return this file. As such,
homeservers MUST sanitise MXC URIs by allowing only alphanumeric
(`A-Za-z0-9`), `_` and `-` characters in the `server-name` and
`media-id` values. This set of whitelisted characters allows URL-safe
base64 encodings specified in RFC 4648. Applying this character
whitelist is preferable to blacklisting `.` and `/` as there are
techniques around blacklisted characters (percent-encoded characters,
UTF-8 encoded traversals, etc).
Homeservers have additional content-specific concerns:
- Clients may try to upload very large files. Homeservers should not
store files that are too large and should not serve them to clients,
returning a HTTP 413 error with the `M_TOO_LARGE` code.
- Clients may try to upload very large images. Homeservers should not
attempt to generate thumbnails for images that are too large,
returning a HTTP 413 error with the `M_TOO_LARGE` code.
- Remote homeservers may host very large files or images. Homeservers
should not proxy or thumbnail large files or images from remote
homeservers, returning a HTTP 502 error with the `M_TOO_LARGE` code.
- Clients may try to upload a large number of files. Homeservers
should limit the number and total size of media that can be uploaded
by clients, returning a HTTP 403 error with the `M_FORBIDDEN` code.
- Clients may try to access a large number of remote files through a
homeserver. Homeservers should restrict the number and size of
remote files that it caches.
- Clients or remote homeservers may try to upload malicious files
targeting vulnerabilities in either the homeserver thumbnailing or
the client decoders.

@ -0,0 +1,28 @@
---
type: module
weight: 90
---
### Device Management
This module provides a means for a user to manage their [devices]().
#### Client behaviour
Clients that implement this module should offer the user a list of
registered devices, as well as the means to update their display names.
Clients should also allow users to delete disused devices.
{{device\_management\_cs\_http\_api}}
#### Security considerations
Deleting devices has security implications: it invalidates the
access\_token assigned to the device, so an attacker could use it to log
out the real user (and do it repeatedly every time the real user tries
to log in to block the attacker). Servers should require additional
authentication beyond the access token when deleting devices (for
example, requiring that the user resubmit their password).
The display names of devices are publicly visible. Clients should
consider advising the user of this.

@ -0,0 +1,47 @@
---
type: module
weight: 230
---
### Direct Messaging
All communication over Matrix happens within a room. It is sometimes
desirable to offer users the concept of speaking directly to one
particular person. This module defines a way of marking certain rooms as
'direct chats' with a given person. This does not restrict the chat to
being between exactly two people since this would preclude the presence
of automated 'bot' users or even a 'personal assistant' who is able to
answer direct messages on behalf of the user in their absence.
A room may not necessarily be considered 'direct' by all members of the
room, but a signalling mechanism exists to propagate the information of
whether a chat is 'direct' to an invitee.
#### Events
{{m\_direct\_event}}
#### Client behaviour
To start a direct chat with another user, the inviting user's client
should set the `is_direct` flag to \_. The client should do this
whenever the flow the user has followed is one where their intention is
to speak directly with another person, as opposed to bringing that
person in to a shared room. For example, clicking on 'Start Chat' beside
a person's profile picture would imply the `is_direct` flag should be
set.
The invitee's client may use the `is_direct` flag in the
[m.room.member]() event to automatically mark the room as a direct chat
but this is not required: it may for example, prompt the user, or ignore
the flag altogether.
Both the inviting client and the invitee's client should record the fact
that the room is a direct chat by storing an `m.direct` event in the
account data using \_.
#### Server behaviour
When the `is_direct` flag is given to \_, the home server must set the
`is_direct` flag in the invite member event for any users invited in the
\_ call.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,21 @@
---
type: module
weight: 210
---
### Event Context
This API returns a number of events that happened just before and after
the specified event. This allows clients to get the context surrounding
an event.
#### Client behaviour
There is a single HTTP API for retrieving event context, documented
below.
{{event\_context\_cs\_http\_api}}
#### Security considerations
The server must only return results that the user has permission to see.

@ -0,0 +1,108 @@
---
type: module
weight: 160
---
### Guest Access
There are times when it is desirable for clients to be able to interact
with rooms without having to fully register for an account on a
homeserver or join the room. This module specifies how these clients
should interact with servers in order to participate in rooms as guests.
Guest users retrieve access tokens from a homeserver using the ordinary
[register
endpoint](#post-matrix-client-%CLIENT_MAJOR_VERSION%-register),
specifying the `kind` parameter as `guest`. They may then interact with
the client-server API as any other user would, but will only have access
to a subset of the API as described the Client behaviour subsection
below. Homeservers may choose not to allow this access at all to their
local users, but have no information about whether users on other
homeservers are guests or not.
Guest users can also upgrade their account by going through the ordinary
`register` flow, but specifying the additional POST parameter
`guest_access_token` containing the guest's access token. They are also
required to specify the `username` parameter to the value of the local
part of their username, which is otherwise optional.
This module does not fully factor in federation; it relies on individual
homeservers properly adhering to the rules set out in this module,
rather than allowing all homeservers to enforce the rules on each other.
#### Events
{{m\_room\_guest\_access\_event}}
#### Client behaviour
The following API endpoints are allowed to be accessed by guest accounts
for retrieving events:
- [GET
/rooms/:room\_id/state](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-state)
- [GET
/rooms/:room\_id/context/:event\_id](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-context-eventid)
- [GET
/rooms/:room\_id/event/:event\_id](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-event-eventid)
- [GET
/rooms/:room\_id/state/:event\_type/:state\_key](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-state-eventtype-statekey)
- [GET
/rooms/:room\_id/messages](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-messages)
- [GET
/rooms/:room\_id/members](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-members)
- [GET
/rooms/:room\_id/initialSync](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-initialsync)
- [GET /sync](#get-matrix-client-%CLIENT_MAJOR_VERSION%-sync)
- [GET /events]() as used for room previews.
The following API endpoints are allowed to be accessed by guest accounts
for sending events:
- [POST
/rooms/:room\_id/join](#post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-join)
- [POST
/rooms/:room\_id/leave](#post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-leave)
- [PUT
/rooms/:room\_id/send/m.room.message/:txn\_id](#put-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-send-eventtype-txnid)
- [PUT
/sendToDevice/{eventType}/{txnId}](#put-matrix-client-%CLIENT_MAJOR_VERSION%-sendtodevice-eventtype-txnid)
The following API endpoints are allowed to be accessed by guest accounts
for their own account maintenance:
- [PUT
/profile/:user\_id/displayname](#put-matrix-client-%CLIENT_MAJOR_VERSION%-profile-userid-displayname)
- [GET /devices](#get-matrix-client-%CLIENT_MAJOR_VERSION%-devices)
- [GET
/devices/{deviceId}](#get-matrix-client-%CLIENT_MAJOR_VERSION%-devices-deviceid)
- [PUT
/devices/{deviceId}](#put-matrix-client-%CLIENT_MAJOR_VERSION%-devices-deviceid)
The following API endpoints are allowed to be accessed by guest accounts
for end-to-end encryption:
- [POST
/keys/upload](#post-matrix-client-%CLIENT_MAJOR_VERSION%-keys-upload)
- [POST
/keys/query](#post-matrix-client-%CLIENT_MAJOR_VERSION%-keys-query)
- [POST
/keys/claim](#post-matrix-client-%CLIENT_MAJOR_VERSION%-keys-claim)
#### Server behaviour
Servers MUST only allow guest users to join rooms if the
`m.room.guest_access` state event is present on the room, and has the
`guest_access` value `can_join`. If the `m.room.guest_access` event is
changed to stop this from being the case, the server MUST set those
users' `m.room.member` state to `leave`.
#### Security considerations
Each homeserver manages its own guest accounts itself, and whether an
account is a guest account or not is not information passed from server
to server. Accordingly, any server participating in a room is trusted to
properly enforce the permissions outlined in this section.
Homeservers may want to enable protections such as captchas for guest
registration to prevent spam, denial of service, and similar attacks.

@ -0,0 +1,91 @@
---
type: module
weight: 120
---
### Room History Visibility
This module adds support for controlling the visibility of previous
events in a room.
In all cases except `world_readable`, a user needs to join a room to
view events in that room. Once they have joined a room, they will gain
access to a subset of events in the room. How this subset is chosen is
controlled by the `m.room.history_visibility` event outlined below.
After a user has left a room, they may see any events which they were
allowed to see before they left the room, but no events received after
they left.
The four options for the `m.room.history_visibility` event are:
- `world_readable` - All events while this is the
`m.room.history_visibility` value may be shared by any participating
homeserver with anyone, regardless of whether they have ever joined
the room.
- `shared` - Previous events are always accessible to newly joined
members. All events in the room are accessible, even those sent when
the member was not a part of the room.
- `invited` - Events are accessible to newly joined members from the
point they were invited onwards. Events stop being accessible when
the member's state changes to something other than `invite` or
`join`.
- `joined` - Events are accessible to newly joined members from the
point they joined the room onwards. Events stop being accessible
when the member's state changes to something other than `join`.
Warning
These options are applied at the point an event is *sent*. Checks are
performed with the state of the `m.room.history_visibility` event when
the event in question is added to the DAG. This means clients cannot
retrospectively choose to show or hide history to new users if the
setting at that time was more restrictive.
#### Events
{{m\_room\_history\_visibility\_event}}
#### Client behaviour
Clients that implement this module MUST present to the user the possible
options for setting history visibility when creating a room.
Clients may want to display a notice that their events may be read by
non-joined people if the value is set to `world_readable`.
#### Server behaviour
By default if no `history_visibility` is set, or if the value is not
understood, the visibility is assumed to be `shared`. The rules
governing whether a user is allowed to see an event depend on the state
of the room *at that event*.
1. If the `history_visibility` was set to `world_readable`, allow.
2. If the user's `membership` was `join`, allow.
3. If `history_visibility` was set to `shared`, and the user joined the
room at any point after the event was sent, allow.
4. If the user's `membership` was `invite`, and the
`history_visibility` was set to `invited`, allow.
5. Otherwise, deny.
For `m.room.history_visibility` events themselves, the user should be
allowed to see the event if the `history_visibility` before *or* after
the event would allow them to see it. (For example, a user should be
able to see `m.room.history_visibility` events which change the
`history_visibility` from `world_readable` to `joined` *or* from
`joined` to `world_readable`, even if that user was not a member of the
room.)
Likewise, for the user's own `m.room.member` events, the user should be
allowed to see the event if their `membership` before *or* after the
event would allow them to see it. (For example, a user can always see
`m.room.member` events which set their membership to `join`, or which
change their membership from `join` to any other value, even if
`history_visibility` is `joined`.)
#### Security considerations
The default value for `history_visibility` is `shared` for
backwards-compatibility reasons. Clients need to be aware that by not
setting this event they are exposing all of their room history to anyone
in the room.

@ -0,0 +1,50 @@
---
type: module
weight: 240
---
### Ignoring Users
With all the communication through Matrix it may be desirable to ignore
a particular user for whatever reason. This module defines how clients
and servers can implement the ignoring of users.
#### Events
{{m\_ignored\_user\_list\_event}}
#### Client behaviour
To ignore a user, effectively blocking them, the client should add the
target user to the `m.ignored_user_list` event in their account data
using \_. Once ignored, the client will no longer receive events sent by
that user, with the exception of state events. The client should either
hide previous content sent by the newly ignored user or perform a new
`/sync` with no previous token.
Invites to new rooms by ignored users will not be sent to the client.
The server may optionally reject the invite on behalf of the client.
State events will still be sent to the client, even if the user is
ignored. This is to ensure parts, such as the room name, do not appear
different to the user just because they ignored the sender.
To remove a user from the ignored users list, remove them from the
account data event. The server will resume sending events from the
previously ignored user, however it should not send events that were
missed while the user was ignored. To receive the events that were sent
while the user was ignored the client should perform a fresh sync. The
client may also un-hide any events it previously hid due to the user
becoming ignored.
#### Server behaviour
Following an update of the `m.ignored_user_list`, the sync API for all
clients should immediately start ignoring (or un-ignoring) the user.
Clients are responsible for determining if they should hide previously
sent events or to start a new sync stream.
Servers must still send state events sent by ignored users to clients.
Servers must not send room invites from ignored users to clients.
Servers may optionally decide to reject the invite, however.

@ -0,0 +1,482 @@
---
type: module
weight: 10
---
### Instant Messaging
This module adds support for sending human-readable messages to a room.
It also adds support for associating human-readable information with the
room itself such as a room name and topic.
#### Events
{{m\_room\_message\_event}}
{{m\_room\_message\_feedback\_event}}
Usage of this event is discouraged for several reasons:
- The number of feedback events will grow very quickly with the number
of users in the room. This event provides no way to "batch"
feedback, unlike the [receipts module]().
- Pairing feedback to messages gets complicated when paginating as
feedback arrives before the message it is acknowledging.
- There are no guarantees that the client has seen the event ID being
acknowledged.
{{m\_room\_name\_event}}
{{m\_room\_topic\_event}}
{{m\_room\_avatar\_event}}
{{m\_room\_pinned\_events\_event}}
##### m.room.message msgtypes
Each [m.room.message]() MUST have a `msgtype` key which identifies the
type of message being sent. Each type has their own required and
optional keys, as outlined below. If a client cannot display the given
`msgtype` then it SHOULD display the fallback plain text `body` key
instead.
Some message types support HTML in the event content that clients should
prefer to display if available. Currently `m.text`, `m.emote`, and
`m.notice` support an additional `format` parameter of
`org.matrix.custom.html`. When this field is present, a `formatted_body`
with the HTML must be provided. The plain text version of the HTML
should be provided in the `body`.
Clients should limit the HTML they render to avoid Cross-Site Scripting,
HTML injection, and similar attacks. The strongly suggested set of HTML
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`.
Not all attributes on those tags should be permitted as they may be
avenues for other disruption attempts, such as adding `onclick` handlers
or excessively large text. Clients should only permit the attributes
listed for the tags below. Where `data-mx-bg-color` and `data-mx-color`
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`
`span`
`data-mx-bg-color`, `data-mx-color`
`a`
`name`, `target`, `href` (provided the value is not relative and has a
scheme matching one of: `https`, `http`, `ftp`, `mailto`, `magnet`)
`img`
`width`, `height`, `alt`, `title`, `src` (provided it is a [Matrix
Content (MXC) URI]())
`ol`
`start`
`code`
`class` (only classes which start with `language-` for syntax
highlighting)
Additionally, web clients should ensure that *all* `a` tags get a
`rel="noopener"` to prevent the target page from referencing the
client's tab/window.
Tags must not be nested more than 100 levels deep. Clients should only
support the subset of tags they can render, falling back to other
representations of the tags where possible. For example, a client may
not be able to render tables correctly and instead could fall back to
rendering tab-delimited text.
In addition to not rendering unsafe HTML, clients should not emit unsafe
HTML in events. Likewise, clients should not generate HTML that is not
needed, such as extra paragraph tags surrounding text due to Rich Text
Editors. HTML included in events should otherwise be valid, such as
having appropriate closing tags, appropriate attributes (considering the
custom ones defined in this specification), and generally valid
structure.
A special tag, `mx-reply`, may appear on rich replies (described below)
and should be allowed if, and only if, the tag appears as the very first
tag in the `formatted_body`. The tag cannot be nested and cannot be
located after another tag in the tree. Because the tag contains HTML, an
`mx-reply` is expected to have a partner closing tag and should be
treated similar to a `div`. Clients that support rich replies will end
up stripping the tag and its contents and therefore may wish to exclude
the tag entirely.
Note
A future iteration of the specification will support more powerful and
extensible message formatting options, such as the proposal
[MSC1767](https://github.com/matrix-org/matrix-doc/pull/1767).
{{msgtype\_events}}
#### Client behaviour
Clients SHOULD verify the structure of incoming events to ensure that
the expected keys exist and that they are of the right type. Clients can
discard malformed events or display a placeholder message to the user.
Redacted `m.room.message` events MUST be removed from the client. This
can either be replaced with placeholder text (e.g. "\[REDACTED\]") or
the redacted message can be removed entirely from the messages view.
Events which have attachments (e.g. `m.image`, `m.file`) SHOULD be
uploaded using the [content repository module]() where available. The
resulting `mxc://` URI can then be used in the `url` key.
Clients MAY include a client generated thumbnail image for an attachment
under a `info.thumbnail_url` key. The thumbnail SHOULD also be a
`mxc://` URI. Clients displaying events with attachments can either use
the client generated thumbnail or ask its homeserver to generate a
thumbnail from the original attachment using the [content repository
module]().
##### Recommendations when sending messages
In the event of send failure, clients SHOULD retry requests using an
exponential-backoff algorithm for a certain amount of time T. It is
recommended that T is no longer than 5 minutes. After this time, the
client should stop retrying and mark the message as "unsent". Users
should be able to manually resend unsent messages.
Users may type several messages at once and send them all in quick
succession. Clients SHOULD preserve the order in which they were sent by
the user. This means that clients should wait for the response to the
previous request before sending the next request. This can lead to
head-of-line blocking. In order to reduce the impact of head-of-line
blocking, clients should use a queue per room rather than a global
queue, as ordering is only relevant within a single room rather than
between rooms.
##### Local echo
Messages SHOULD appear immediately in the message view when a user
presses the "send" button. This should occur even if the message is
still sending. This is referred to as "local echo". Clients SHOULD
implement "local echo" of messages. Clients MAY display messages in a
different format to indicate that the server has not processed the
message. This format should be removed when the server responds.
Clients need to be able to match the message they are sending with the
same message which they receive from the event stream. The echo of the
same message from the event stream is referred to as "remote echo". Both
echoes need to be identified as the same message in order to prevent
duplicate messages being displayed. Ideally this pairing would occur
transparently to the user: the UI would not flicker as it transitions
from local to remote. Flickering can be reduced through clients making
use of the transaction ID they used to send a particular event. The
transaction ID used will be included in the event's `unsigned` data as
`transaction_id` when it arrives through the event stream.
Clients unable to make use of the transaction ID are likely to
experience flickering when the remote echo arrives on the event stream
*before* the request to send the message completes. In that case the
event arrives before the client has obtained an event ID, making it
impossible to identify it as a remote echo. This results in the client
displaying the message twice for some time (depending on the server
responsiveness) before the original request to send the message
completes. Once it completes, the client can take remedial actions to
remove the duplicate event by looking for duplicate event IDs.
##### Calculating the display name for a user
Clients may wish to show the human-readable display name of a room
member as part of a membership list, or when they send a message.
However, different members may have conflicting display names. Display
names MUST be disambiguated before showing them to the user, in order to
prevent spoofing of other users.
To ensure this is done consistently across clients, clients SHOULD use
the following algorithm to calculate a disambiguated display name for a
given user:
1. Inspect the `m.room.member` state event for the relevant user id.
2. If the `m.room.member` state event has no `displayname` field, or if
that field has a `null` value, use the raw user id as the display
name. Otherwise:
3. If the `m.room.member` event has a `displayname` which is unique
among members of the room with `membership: join` or
`membership: invite`, use the given `displayname` as the
user-visible display name. Otherwise:
4. The `m.room.member` event has a non-unique `displayname`. This
should be disambiguated using the user id, for example "display name
(@id:homeserver.org)".
Developers should take note of the following when implementing the above
algorithm:
- The user-visible display name of one member can be affected by
changes in the state of another member. For example, if
`@user1:matrix.org` is present in a room, with `displayname: Alice`,
then when `@user2:example.com` joins the room, also with
`displayname: Alice`, *both* users must be given disambiguated
display names. Similarly, when one of the users then changes their
display name, there is no longer a clash, and *both* users can be
given their chosen display name. Clients should be alert to this
possibility and ensure that all affected users are correctly
renamed.
- The display name of a room may also be affected by changes in the
membership list. This is due to the room name sometimes being based
on user display names (see [Calculating the display name for a
room](#calculating-the-display-name-for-a-room)).
- If the entire membership list is searched for clashing display
names, this leads to an O(N^2) implementation for building the list
of room members. This will be very inefficient for rooms with large
numbers of members. It is recommended that client implementations
maintain a hash table mapping from `displayname` to a list of room
members using that name. Such a table can then be used for efficient
calculation of whether disambiguation is needed.
##### Displaying membership information with messages
Clients may wish to show the display name and avatar URL of the room
member who sent a message. This can be achieved by inspecting the
`m.room.member` state event for that user ID (see [Calculating the
display name for a user](#calculating-the-display-name-for-a-user)).
When a user paginates the message history, clients may wish to show the
**historical** display name and avatar URL for a room member. This is
possible because older `m.room.member` events are returned when
paginating. This can be implemented efficiently by keeping two sets of
room state: old and current. As new events arrive and/or the user
paginates back in time, these two sets of state diverge from each other.
New events update the current state and paginated events update the old
state. When paginated events are processed sequentially, the old state
represents the state of the room *at the time the event was sent*. This
can then be used to set the historical display name and avatar URL.
##### Calculating the display name for a room
Clients may wish to show a human-readable name for a room. There are a
number of possibilities for choosing a useful name. To ensure that rooms
are named consistently across clients, clients SHOULD use the following
algorithm to choose a name:
1. If the room has an [m.room.name]() state event with a non-empty
`name` field, use the name given by that field.
2. If the room has an [m.room.canonical\_alias]() state event with a
valid `alias` field, use the alias given by that field as the name.
Note that clients should avoid using `alt_aliases` when calculating
the room name.
3. If none of the above conditions are met, a name should be composed
based on the members of the room. Clients should consider
[m.room.member]() events for users other than the logged-in user, as
defined below.
1. If the number of `m.heroes` for the room are greater or equal to
`m.joined_member_count + m.invited_member_count - 1`, then use
the membership events for the heroes to calculate display names
for the users ([disambiguating them if
required](#calculating-the-display-name-for-a-user)) and
concatenating them. For example, the client may choose to show
"Alice, Bob, and Charlie (@charlie:example.org)" as the room
name. The client may optionally limit the number of users it
uses to generate a room name.
2. If there are fewer heroes than
`m.joined_member_count + m.invited_member_count - 1`, and
`m.joined_member_count + m.invited_member_count` is greater than
1, the client should use the heroes to calculate display names
for the users ([disambiguating them if
required](#calculating-the-display-name-for-a-user)) and
concatenating them alongside a count of the remaining users. For
example, "Alice, Bob, and 1234 others".
3. If `m.joined_member_count + m.invited_member_count` is less than
or equal to 1 (indicating the member is alone), the client
should use the rules above to indicate that the room was empty.
For example, "Empty Room (was Alice)", "Empty Room (was Alice
and 1234 others)", or "Empty Room" if there are no heroes.
Clients SHOULD internationalise the room name to the user's language
when using the `m.heroes` to calculate the name. Clients SHOULD use
minimum 5 heroes to calculate room names where possible, but may use
more or less to fit better with their user experience.
##### Forming relationships between events
In some cases, events may wish to reference other events. This could be
to form a thread of messages for the user to follow along with, or to
provide more context as to what a particular event is describing.
Currently, the only kind of relation defined is a "rich reply" where a
user may reference another message to create a thread-like conversation.
Relationships are defined under an `m.relates_to` key in the event's
`content`. If the event is of the type `m.room.encrypted`, the
`m.relates_to` key MUST NOT be covered by the encryption and instead be
put alongside the encryption information held in the `content`.
###### Rich replies
Users may wish to reference another message when forming their own
message, and clients may wish to better embed the referenced message for
the user to have a better context for the conversation being had. This
sort of embedding another message in a message is known as a "rich
reply", or occasionally just a "reply".
A rich reply is formed through use of an `m.relates_to` relation for
`m.in_reply_to` where a single key, `event_id`, is used to reference the
event being replied to. The referenced event ID SHOULD belong to the
same room where the reply is being sent. Clients should be cautious of
the event ID belonging to another room, or being invalid entirely. Rich
replies can only be constructed in the form of `m.room.message` events
with a `msgtype` of `m.text` or `m.notice`. Due to the fallback
requirements, rich replies cannot be constructed for types of `m.emote`,
`m.file`, etc. Rich replies may reference any other `m.room.message`
event, however. Rich replies may reference another event which also has
a rich reply, infinitely.
An `m.in_reply_to` relationship looks like the following:
{
...
"type": "m.room.message",
"content": {
"msgtype": "m.text",
"body": "<body including fallback>",
"format": "org.matrix.custom.html",
"formatted_body": "<HTML including fallback>",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$another:event.com"
}
}
}
}
####### Fallbacks and event representation
Some clients may not have support for rich replies and therefore need a
fallback to use instead. Clients that do not support rich replies should
render the event as if rich replies were not special.
Clients that do support rich replies MUST provide the fallback format on
replies, and MUST strip the fallback before rendering the reply. Rich
replies MUST have a `format` of `org.matrix.custom.html` and therefore a
`formatted_body` alongside the `body` and appropriate `msgtype`. The
specific fallback text is different for each `msgtype`, however the
general format for the `body` is:
> <@alice:example.org> This is the original body
This is where the reply goes
The `formatted_body` should use the following template:
<mx-reply>
<blockquote>
<a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a>
<a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
<br />
<!-- This is where the related event's HTML would be. -->
</blockquote>
</mx-reply>
This is where the reply goes.
If the related event does not have a `formatted_body`, the event's
`body` should be considered after encoding any HTML special characters.
Note that the `href` in both of the anchors use a [matrix.to
URI](../appendices.html#matrix-to-navigation).
######## Stripping the fallback
Clients which support rich replies MUST strip the fallback from the
event before rendering the event. This is because the text provided in
the fallback cannot be trusted to be an accurate representation of the
event. After removing the fallback, clients are recommended to represent
the event referenced by `m.in_reply_to` similar to the fallback's
representation, although clients do have creative freedom for their user
interface. Clients should prefer the `formatted_body` over the `body`,
just like with other `m.room.message` events.
To strip the fallback on the `body`, the client should iterate over each
line of the string, removing any lines that start with the fallback
prefix ("&gt; ", including the space, without quotes) and stopping when
a line is encountered without the prefix. This prefix is known as the
"fallback prefix sequence".
To strip the fallback on the `formatted_body`, the client should remove
the entirety of the `mx-reply` tag.
######## Fallback for `m.text`, `m.notice`, and unrecognised message types
Using the prefix sequence, the first line of the related event's `body`
should be prefixed with the user's ID, followed by each line being
prefixed with the fallback prefix sequence. For example:
> <@alice:example.org> This is the first line
> This is the second line
This is the reply
The `formatted_body` uses the template defined earlier in this section.
######## Fallback for `m.emote`
Similar to the fallback for `m.text`, each line gets prefixed with the
fallback prefix sequence. However an asterisk should be inserted before
the user's ID, like so:
> * <@alice:example.org> feels like today is going to be a great day
This is the reply
The `formatted_body` has a subtle difference for the template where the
asterisk is also inserted ahead of the user's ID:
<mx-reply>
<blockquote>
<a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a>
* <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
<br />
<!-- This is where the related event's HTML would be. -->
</blockquote>
</mx-reply>
This is where the reply goes.
######## Fallback for `m.image`, `m.video`, `m.audio`, and `m.file`
The related event's `body` would be a file name, which may not be very
descriptive. The related event should additionally not have a `format`
or `formatted_body` in the `content` - if the event does have a `format`
and/or `formatted_body`, those fields should be ignored. Because the
filename alone may not be descriptive, the related event's `body` should
be considered to be `"sent a file."` such that the output looks similar
to the following:
> <@alice:example.org> sent a file.
This is the reply
<mx-reply>
<blockquote>
<a href="https://matrix.to/#/!somewhere:example.org/$event:example.org">In reply to</a>
<a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
<br />
sent a file.
</blockquote>
</mx-reply>
This is where the reply goes.
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"`.
#### Server behaviour
Homeservers SHOULD reject `m.room.message` events which don't have a
`msgtype` key, or which don't have a textual `body` key, with an HTTP
status code of 400.
#### Security considerations
Messages sent using this module are not encrypted, although end to end
encryption is in development (see [E2E module]()).
Clients should sanitise **all displayed keys** for unsafe HTML to
prevent Cross-Site Scripting (XSS) attacks. This includes room names and
topics.

@ -0,0 +1,58 @@
---
type: module
weight: 300
---
### User, room, and group mentions
This module allows users to mention other users, rooms, and groups
within a room message. This is achieved by including a [matrix.to
URI](../appendices.html#matrix-to-navigation) in the HTML body of an
[m.room.message]() event. This module does not have any server-specific
behaviour to it.
Mentions apply only to [m.room.message]() events where the `msgtype` is
`m.text`, `m.emote`, or `m.notice`. The `format` for the event must be
`org.matrix.custom.html` and therefore requires a `formatted_body`.
To make a mention, reference the entity being mentioned in the
`formatted_body` using an anchor, like so:
{
"body": "Hello Alice!",
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"formatted_body": "Hello <a href='https://matrix.to/#/@alice:example.org'>Alice</a>!"
}
#### Client behaviour
In addition to using the appropriate `matrix.to URI` for the mention,
clients should use the following guidelines when making mentions in
events to be sent:
- When mentioning users, use the user's potentially ambiguous display
name for the anchor's text. If the user does not have a display
name, use the user's ID.
- When mentioning rooms, use the canonical alias for the room. If the
room does not have a canonical alias, prefer one of the aliases
listed on the room. If no alias can be found, fall back to the room
ID. In all cases, use the alias/room ID being linked to as the
anchor's text.
- When referencing groups, use the group ID as the anchor's text.
The text component of the anchor should be used in the event's `body`
where the mention would normally be represented, as shown in the example
above.
Clients should display mentions differently from other elements. For
example, this may be done by changing the background color of the
mention to indicate that it is different from a normal link.
If the current user is mentioned in a message (either by a mention as
defined in this module or by a push rule), the client should show that
mention differently from other mentions, such as by using a red
background color to signify to the user that they were mentioned.
When clicked, the mention should navigate the user to the appropriate
room, group, or user information.

@ -0,0 +1,126 @@
---
type: module
weight: 330
---
### Moderation policy lists
With Matrix being an open network where anyone can participate, a very
wide range of content exists and it is important that users are
empowered to select which content they wish to see, and which content
they wish to block. By extension, room moderators and server admins
should also be able to select which content they do not wish to host in
their rooms and servers.
The protocol's position on this is one of neutrality: it should not be
deciding what content is undesirable for any particular entity and
should instead be empowering those entities to make their own decisions.
As such, a generic framework for communicating "moderation policy lists"
or "moderation policy rooms" is described. Note that this module only
describes the data structures and not how they should be interpreting:
the entity making the decisions on filtering is best positioned to
interpret the rules how it sees fit.
Moderation policy lists are stored as room state events. There are no
restrictions on how the rooms can be configured (they could be public,
private, encrypted, etc).
There are currently 3 kinds of entities which can be affected by rules:
`user`, `server`, and `room`. All 3 are described with
`m.policy.rule.<kind>` state events. The `state_key` for a policy rule
is an arbitrary string decided by the sender of the rule.
Rules contain recommendations and reasons for the rule existing. The
`reason` is a human-readable string which describes the
`recommendation`. Currently only one recommendation, `m.ban`, is
specified.
#### `m.ban` recommendation
When this recommendation is used, the entities affected by the rule
should be banned from participation where possible. The enforcement of
this is deliberately left as an implementation detail to avoid the
protocol imposing its opinion on how the policy list is to be
interpreted. However, a suggestion for a simple implementation is as
follows:
- Is a `user` rule...
- Applied to a user: The user should be added to the subscriber's
ignore list.
- Applied to a room: The user should be banned from the room
(either on sight or immediately).
- Applied to a server: The user should not be allowed to send
invites to users on the server.
- Is a `room` rule...
- Applied to a user: The user should leave the room and not join
it
([MSC2270](https://github.com/matrix-org/matrix-doc/pull/2270)-style
ignore).
- Applied to a room: No-op because a room cannot ban itself.
- Applied to a server: The server should prevent users from
joining the room and from receiving invites to it.
- Is a `server` rule...
- Applied to a user: The user should not receive events or invites
from the server.
- Applied to a room: The server is added as a denied server in the
ACLs.
- Applied to a server: The subscriber should avoid federating with
the server as much as possible by blocking invites from the
server and not sending traffic unless strictly required (no
outbound invites).
#### Subscribing to policy lists
This is deliberately left as an implementation detail. For
implementations using the Client-Server API, this could be as easy as
joining or peeking the room. Joining or peeking is not required,
however: an implementation could poll for updates or use a different
technique for receiving updates to the policy's rules.
#### Sharing
In addition to sharing a direct reference to the room which contains the
policy's rules, plain http or https URLs can be used to share links to
the list. When the URL is approached with a `Accept: application/json`
header or has `.json` appended to the end of the URL, it should return a
JSON object containing a `room_uri` property which references the room.
Currently this would be a `matrix.to` URI, however in future it could be
a Matrix-schemed URI instead. When not approached with the intent of
JSON, the service could return a user-friendly page describing what is
included in the ban list.
#### Events
The `entity` described by the state events can contain `*` and `?` to
match zero or more and one or more characters respectively. Note that
rules against rooms can describe a room ID or room alias - the
subscriber is responsible for resolving the alias to a room ID if
desired.
{{m\_policy\_rule\_user\_event}}
{{m\_policy\_rule\_room\_event}}
{{m\_policy\_rule\_server\_event}}
#### Client behaviour
As described above, the client behaviour is deliberately left undefined.
#### Server behaviour
Servers have no additional requirements placed on them by this module.
#### Security considerations
This module could be used to build a system of shared blacklists, which
may create a divide within established communities if not carefully
deployed. This may well not be a suitable solution for all communities.
Depending on how implementations handle subscriptions, user IDs may be
linked to policy lists and therefore expose the views of that user. For
example, a client implementation which joins the user to the policy room
would expose the user's ID to observers of the policy room. In future,
[MSC1228](https://github.com/matrix-org/matrix-doc/pulls/1228) and
[MSC1777](https://github.com/matrix-org/matrix-doc/pulls/1777) (or
similar) could help solve this concern.

@ -0,0 +1,13 @@
---
type: module
weight: 280
---
### OpenID
This module allows users to verify their identity with a third party
service. The third party service does need to be matrix-aware in that it
will need to know to resolve matrix homeservers to exchange the user's
token for identity information.
{{openid\_cs\_http\_api}}

@ -0,0 +1,76 @@
---
type: module
weight: 60
---
### Presence
Each user has the concept of presence information. This encodes:
- Whether the user is currently online
- How recently the user was last active (as seen by the server)
- Whether a given client considers the user to be currently idle
- Arbitrary information about the user's current status (e.g. "in a
meeting").
This information is collated from both per-device (`online`, `idle`,
`last_active`) and per-user (status) data, aggregated by the user's
homeserver and transmitted as an `m.presence` event. Presence events are
sent to interested parties where users share a room membership.
User's presence state is represented by the `presence` key, which is an
enum of one of the following:
- `online` : The default state when the user is connected to an event
stream.
- `unavailable` : The user is not reachable at this time e.g. they are
idle.
- `offline` : The user is not connected to an event stream or is
explicitly suppressing their profile information from being sent.
#### Events
{{presence\_events}}
#### Client behaviour
Clients can manually set/get their presence using the HTTP APIs listed
below.
{{presence\_cs\_http\_api}}
##### Last active ago
The server maintains a timestamp of the last time it saw a pro-active
event from the user. A pro-active event may be sending a message to a
room or changing presence state to `online`. This timestamp is presented
via a key called `last_active_ago` which gives the relative number of
milliseconds since the pro-active event.
To reduce the number of presence updates sent to clients the server may
include a `currently_active` boolean field when the presence state is
`online`. When true, the server will not send further updates to the
last active time until an update is sent to the client with either a)
`currently_active` set to false or b) a presence state other than
`online`. During this period clients must consider the user to be
currently active, irrespective of the last active time.
The last active time must be up to date whenever the server gives a
presence event to the client. The `currently_active` mechanism should
purely be used by servers to stop sending continuous presence updates,
as opposed to disabling last active tracking entirely. Thus clients can
fetch up to date last active times by explicitly requesting the presence
for a given user.
##### Idle timeout
The server will automatically set a user's presence to `unavailable` if
their last active time was over a threshold value (e.g. 5 minutes).
Clients can manually set a user's presence to `unavailable`. Any
activity that bumps the last active time on any of the user's clients
will cause the server to automatically set their presence to `online`.
#### Security considerations
Presence information is shared with all users who share a room with the
target user. In large public rooms this could be undesirable.

@ -0,0 +1,721 @@
---
type: module
weight: 130
---
### Push Notifications
+--------------------+ +-------------------+
Matrix HTTP | | | |
Notification Protocol | App Developer | | Device Vendor |
| | | |
+-------------------+ | +----------------+ | | +---------------+ |
| | | | | | | | | |
| Matrix homeserver +-----> Push Gateway +------> Push Provider | |
| | | | | | | | | |
+-^-----------------+ | +----------------+ | | +----+----------+ |
| | | | | |
Matrix | | | | | |
Client/Server API + | | | | |
| | +--------------------+ +-------------------+
| +--+-+ |
| | <-------------------------------------------+
+---+ |
| | Provider Push Protocol
+----+
Mobile Device or Client
This module adds support for push notifications. Homeservers send
notifications of events to user-configured HTTP endpoints. Users may
also configure a number of rules that determine which events generate
notifications. These are all stored and managed by the user's
homeserver. This allows user-specific push settings to be reused between
client applications.
The above diagram shows the flow of push notifications being sent to a
handset where push notifications are submitted via the handset vendor,
such as Apple's APNS or Google's GCM. This happens as follows:
1. The client app signs in to a homeserver.
2. The client app registers with its vendor's Push Provider and obtains
a routing token of some kind.
3. The mobile app uses the Client/Server API to add a 'pusher',
providing the URL of a specific Push Gateway which is configured for
that application. It also provides the routing token it has acquired
from the Push Provider.
4. The homeserver starts sending HTTP requests to the Push Gateway
using the supplied URL. The Push Gateway relays this notification to
the Push Provider, passing the routing token along with any
necessary private credentials the provider requires to send push
notifications.
5. The Push Provider sends the notification to the device.
Definitions for terms used in this section are below:
Push Provider
A push provider is a service managed by the device vendor which can send
notifications directly to the device. Google Cloud Messaging (GCM) and
Apple Push Notification Service (APNS) are two examples of push
providers.
Push Gateway
A push gateway is a server that receives HTTP event notifications from
homeservers and passes them on to a different protocol such as APNS for
iOS devices or GCM for Android devices. Clients inform the homeserver
which Push Gateway to send notifications to when it sets up a Pusher.
Pusher
A pusher is a worker on the homeserver that manages the sending of HTTP
notifications for a user. A user can have multiple pushers: one per
device.
Push Rule
A push rule is a single rule that states under what *conditions* an
event should be passed onto a push gateway and *how* the notification
should be presented. These rules are stored on the user's homeserver.
They are manually configured by the user, who can create and view them
via the Client/Server API.
Push Ruleset
A push ruleset *scopes a set of rules according to some criteria*. For
example, some rules may only be applied for messages from a particular
sender, a particular room, or by default. The push ruleset contains the
entire set of scopes and rules.
#### Client behaviour
Clients MUST configure a Pusher before they will receive push
notifications. There is a single API endpoint for this, as described
below.
{{pusher\_cs\_http\_api}}
##### Listing Notifications
A client can retrieve a list of events that it has been notified about.
This may be useful so that users can see a summary of what important
messages they have received.
{{notifications\_cs\_http\_api}}
##### Receiving notifications
Servers MUST include the number of unread notifications in a client's
`/sync` stream, and MUST update it as it changes. Notifications are
determined by the push rules which apply to an event.
When the user updates their read receipt (either by using the API or by
sending an event), notifications prior to and including that event MUST
be marked as read.
##### Push Rules
A push rule is a single rule that states under what *conditions* an
event should be passed onto a push gateway and *how* the notification
should be presented. There are different "kinds" of push rules and each
rule has an associated priority. Every push rule MUST have a `kind` and
`rule_id`. The `rule_id` is a unique string within the kind of rule and
its' scope: `rule_ids` do not need to be unique between rules of the
same kind on different devices. Rules may have extra keys depending on
the value of `kind`.
The different `kind`s of rule, in the order that they are checked, are:
Override Rules `override`
The highest priority rules are user-configured overrides.
Content-specific Rules `content`
These configure behaviour for (unencrypted) messages that match certain
patterns. Content rules take one parameter: `pattern`, that gives the
glob pattern to match against. This is treated in the same way as
`pattern` for `event_match`.
Room-specific Rules `room`
These rules change the behaviour of all messages for a given room. The
`rule_id` of a room rule is always the ID of the room that it affects.
Sender-specific rules `sender`
These rules configure notification behaviour for messages from a
specific Matrix user ID. The `rule_id` of Sender rules is always the
Matrix user ID of the user whose messages they'd apply to.
Underride rules `underride`
These are identical to `override` rules, but have a lower priority than
`content`, `room` and `sender` rules.
Rules with the same `kind` can specify an ordering priority. This
determines which rule is selected in the event of multiple matches. For
example, a rule matching "tea" and a separate rule matching "time" would
both match the sentence "It's time for tea". The ordering of the rules
would then resolve the tiebreak to determine which rule is executed.
Only `actions` for highest priority rule will be sent to the Push
Gateway.
Each rule can be enabled or disabled. Disabled rules never match. If no
rules match an event, the homeserver MUST NOT notify the Push Gateway
for that event. Homeservers MUST NOT notify the Push Gateway for events
that the user has sent themselves.
###### Actions
All rules have an associated list of `actions`. An action affects if and
how a notification is delivered for a matching event. The following
actions are defined:
`notify`
This causes each matching event to generate a notification.
`dont_notify`
This prevents each matching event from generating a notification
`coalesce`
This enables notifications for matching events but activates homeserver
specific behaviour to intelligently coalesce multiple events into a
single notification. Not all homeservers may support this. Those that do
not support it should treat it as the `notify` action.
`set_tweak`
Sets an entry in the `tweaks` dictionary key that is sent in the
notification request to the Push Gateway. This takes the form of a
dictionary with a `set_tweak` key whose value is the name of the tweak
to set. It may also have a `value` key which is the value to which it
should be set.
Actions that have no parameters are represented as a string. Otherwise,
they are represented as a dictionary with a key equal to their name and
other keys as their parameters, e.g.
`{ "set_tweak": "sound", "value": "default" }`
####### Tweaks
The `set_tweak` action is used to add an entry to the 'tweaks'
dictionary that is sent in the notification request to the Push Gateway.
The following tweaks are defined:
`sound`
A string representing the sound to be played when this notification
arrives. A value of `default` means to play a default sound. A device
may choose to alert the user by some other means if appropriate, eg.
vibration.
`highlight`
A boolean representing whether or not this message should be highlighted
in the UI. This will normally take the form of presenting the message in
a different colour and/or style. The UI might also be adjusted to draw
particular attention to the room in which the event occurred. If a
`highlight` tweak is given with no value, its value is defined to be
`true`. If no highlight tweak is given at all then the value of
`highlight` is defined to be false.
Tweaks are passed transparently through the homeserver so client
applications and Push Gateways may agree on additional tweaks. For
example, a tweak may be added to specify how to flash the notification
light on a mobile device.
###### Conditions
`override` and `underride` rules MAY have a list of 'conditions'. All
conditions must hold true for an event in order for the rule to match. A
rule with no conditions always matches. The following conditions are
defined:
`event_match`
This is a glob pattern match on a field of the event. Parameters:
- `key`: The dot-separated field of the event to match, e.g.
`content.body`
- `pattern`: The glob-style pattern to match against. Patterns with no
special glob characters should be treated as having asterisks
prepended and appended when testing the condition.
`contains_display_name`
This matches unencrypted messages where `content.body` contains the
owner's display name in that room. This is a separate rule because
display names may change and as such it would be hard to maintain a rule
that matched the user's display name. This condition has no parameters.
`room_member_count`
This matches the current number of members in the room. Parameters:
- `is`: A decimal integer optionally prefixed by one of, `==`, `<`,
`>`, `>=` or `<=`. A prefix of `<` matches rooms where the member
count is strictly less than the given number and so forth. If no
prefix is present, this parameter defaults to `==`.
`sender_notification_permission`
This takes into account the current power levels in the room, ensuring
the sender of the event has high enough power to trigger the
notification.
Parameters:
- `key`: A string that determines the power level the sender must have
to trigger notifications of a given type, such as `room`. Refer to
the [m.room.power\_levels]() event schema for information about what
the defaults are and how to interpret the event. The `key` is used
to look up the power level required to send a notification type from
the `notifications` object in the power level event content.
Unrecognised conditions MUST NOT match any events, effectively making
the push rule disabled.
`room`, `sender` and `content` rules do not have conditions in the same
way, but instead have predefined conditions. In the cases of `room` and
`sender` rules, the `rule_id` of the rule determines its behaviour.
###### Predefined Rules
Homeservers can specify "server-default rules" which operate at a lower
priority than "user-defined rules". The `rule_id` for all server-default
rules MUST start with a dot (".") to identify them as "server-default".
The following server-default rules are specified:
####### Default Override Rules
######## `.m.rule.master`
Matches all events. This can be enabled to turn off all push
notifications other than those generated by override rules set by the
user. By default this rule is disabled.
Definition
{
"rule_id": ".m.rule.master",
"default": true,
"enabled": false,
"conditions": [],
"actions": [
"dont_notify"
]
}
######## `.m.rule.suppress_notices`
Matches messages with a `msgtype` of `notice`.
Definition:
{
"rule_id": ".m.rule.suppress_notices",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "content.msgtype",
"pattern": "m.notice",
}
],
"actions": [
"dont_notify",
]
}
######## `.m.rule.invite_for_me`
Matches any invites to a new room for this user.
Definition:
{
"rule_id": ".m.rule.invite_for_me",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
},
{
"key": "content.membership",
"kind": "event_match",
"pattern": "invite"
},
{
"key": "state_key",
"kind": "event_match",
"pattern": "[the user's Matrix ID]"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
}
######## `.m.rule.member_event`
Matches any `m.room.member_event`.
Definition:
{
"rule_id": ".m.rule.member_event",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
}
],
"actions": [
"dont_notify"
]
}
######## `.m.rule.contains_display_name`
Matches any message whose content is unencrypted and contains the user's
current display name in the room in which it was sent.
Definition:
{
"rule_id": ".m.rule.contains_display_name",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "contains_display_name"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
]
}
######## `.m.rule.tombstone`
Matches any state event whose type is `m.room.tombstone`. This is
intended to notify users of a room when it is upgraded, similar to what
an `@room` notification would accomplish.
Definition:
{
"rule_id": ".m.rule.tombstone",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.tombstone"
},
{
"kind": "event_match",
"key": "state_key",
"pattern": ""
}
],
"actions": [
"notify",
{
"set_tweak": "highlight"
}
]
}
######## `.m.rule.roomnotif`
Matches any message whose content is unencrypted and contains the text
`@room`, signifying the whole room should be notified of the event.
Definition:
{
"rule_id": ".m.rule.roomnotif",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "content.body",
"pattern": "@room"
},
{
"kind": "sender_notification_permission",
"key": "room"
}
],
"actions": [
"notify",
{
"set_tweak": "highlight"
}
]
}
####### Default Content Rules
######## `.m.rule.contains_user_name`
Matches any message whose content is unencrypted and contains the local
part of the user's Matrix ID, separated by word boundaries.
Definition (as a `content` rule):
{
"rule_id": ".m.rule.contains_user_name",
"default": true,
"enabled": true,
"pattern": "[the local part of the user's Matrix ID]",
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
]
}
####### Default Underride Rules
######## `.m.rule.call`
Matches any incoming VOIP call.
Definition:
{
"rule_id": ".m.rule.call",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.call.invite"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "ring"
}
]
}
######## `.m.rule.encrypted_room_one_to_one`
Matches any encrypted event sent in a room with exactly two members.
Unlike other push rules, this rule cannot be matched against the content
of the event by nature of it being encrypted. This causes the rule to be
an "all or nothing" match where it either matches *all* events that are
encrypted (in 1:1 rooms) or none.
Definition:
{
"rule_id": ".m.rule.encrypted_room_one_to_one",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "room_member_count",
"is": "2"
},
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.encrypted"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
}
######## `.m.rule.room_one_to_one`
Matches any message sent in a room with exactly two members.
Definition:
{
"rule_id": ".m.rule.room_one_to_one",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "room_member_count",
"is": "2"
},
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.message"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
}
######## `.m.rule.message`
Matches all chat messages.
Definition:
{
"rule_id": ".m.rule.message",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.message"
}
],
"actions": [
"notify"
]
}
######## `.m.rule.encrypted`
Matches all encrypted events. Unlike other push rules, this rule cannot
be matched against the content of the event by nature of it being
encrypted. This causes the rule to be an "all or nothing" match where it
either matches *all* events that are encrypted (in group rooms) or none.
Definition:
{
"rule_id": ".m.rule.encrypted",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.encrypted"
}
],
"actions": [
"notify"
]
}
##### Push Rules: API
Clients can retrieve, add, modify and remove push rules globally or
per-device using the APIs below.
{{pushrules\_cs\_http\_api}}
##### Push Rules: Events
When a user changes their push rules a `m.push_rules` event is sent to
all clients in the `account_data` section of their next `/sync` request.
The content of the event is the current push rules for the user.
{{m\_push\_rules\_event}}
###### Examples
To create a rule that suppresses notifications for the room with ID
`!dj234r78wl45Gh4D:matrix.org`:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \
'{
"actions" : ["dont_notify"]
}'
To suppress notifications for the user `@spambot:matrix.org`:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \
'{
"actions" : ["dont_notify"]
}'
To always notify for messages that contain the work 'cake' and set a
specific sound (with a rule\_id of `SSByZWFsbHkgbGlrZSBjYWtl`):
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \
'{
"pattern": "cake",
"actions" : ["notify", {"set_sound":"cakealarm.wav"}]
}'
To add a rule suppressing notifications for messages starting with
'cake' but ending with 'lie', superseding the previous rule:
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \
'{
"pattern": "cake*lie",
"actions" : ["notify"]
}'
To add a custom sound for notifications messages containing the word
'beer' in any rooms with 10 members or fewer (with greater importance
than the room, sender and content rules):
curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456" -d \
'{
"conditions": [
{"kind": "event_match", "key": "content.body", "pattern": "beer" },
{"kind": "room_member_count", "is": "<=10"}
],
"actions" : [
"notify",
{"set_sound":"beeroclock.wav"}
]
}'
#### Server behaviour
#### Push Gateway behaviour
##### Recommendations for APNS
The exact format for sending APNS notifications is flexible and up to
the client app and its' push gateway to agree on. As APNS requires that
the sender has a private key owned by the app developer, each app must
have its own push gateway. It is recommended that:
- The APNS token be base64 encoded and used as the pushkey.
- A different app\_id be used for apps on the production and sandbox
APS environments.
- APNS push gateways do not attempt to wait for errors from the APNS
gateway before returning and instead to store failures and return
'rejected' responses next time that pushkey is used.
#### Security considerations
Clients specify the Push Gateway URL to use to send event notifications
to. This URL should be over HTTPS and *never* over HTTP.
As push notifications will pass through a Push Provider, message content
shouldn't be sent in the push itself where possible. Instead, Push
Gateways should send a "sync" command to instruct the client to get new
events from the homeserver directly.

@ -0,0 +1,54 @@
---
type: module
weight: 50
---
### Fully read markers
The history for a given room may be split into three sections: messages
the user has read (or indicated they aren't interested in them),
messages the user might have read some but not others, and messages the
user hasn't seen yet. The "fully read marker" (also known as a "read
marker") marks the last event of the first section, whereas the user's
read receipt marks the last event of the second section.
#### Events
The user's fully read marker is kept as an event in the room's [account
data](#client-config). The event may be read to determine the user's
current fully read marker location in the room, and just like other
account data events the event will be pushed down the event stream when
updated.
The fully read marker is kept under an `m.fully_read` event. If the
event does not exist on the user's account data, the fully read marker
should be considered to be the user's read receipt location.
{{m\_fully\_read\_event}}
#### Client behaviour
The client cannot update fully read markers by directly modifying the
`m.fully_read` account data event. Instead, the client must make use of
the read markers API to change the values.
The read markers API can additionally update the user's read receipt
(`m.read`) location in the same operation as setting the fully read
marker location. This is because read receipts and read markers are
commonly updated at the same time, and therefore the client might wish
to save an extra HTTP call. Providing an `m.read` location performs the
same task as a request to `/receipt/m.read/$event:example.org`.
{{read\_markers\_cs\_http\_api}}
#### Server behaviour
The server MUST prevent clients from setting `m.fully_read` directly in
room account data. The server must additionally ensure that it treats
the presence of `m.read` in the `/read_markers` request the same as how
it would for a request to `/receipt/m.read/$event:example.org`.
Upon updating the `m.fully_read` event due to a request to
`/read_markers`, the server MUST send the updated account data event
through to the client via the event stream (eg: `/sync`), provided any
applicable filters are also satisfied.

@ -0,0 +1,87 @@
---
type: module
weight: 40
---
### Receipts
This module adds in support for receipts. These receipts are a form of
acknowledgement of an event. This module defines a single
acknowledgement: `m.read` which indicates that the user has read up to a
given event.
Sending a receipt for each event can result in sending large amounts of
traffic to a homeserver. To prevent this from becoming a problem,
receipts are implemented using "up to" markers. This marker indicates
that the acknowledgement applies to all events "up to and including" the
event specified. For example, marking an event as "read" would indicate
that the user had read all events *up to* the referenced event. See the
[Receiving notifications](#receiving-notifications) section for more
information on how read receipts affect notification counts.
#### Events
Each `user_id`, `receipt_type` pair must be associated with only a
single `event_id`.
{{m\_receipt\_event}}
#### Client behaviour
In `/sync`, receipts are listed under the `ephemeral` array of events
for a given room. New receipts that come down the event streams are
deltas which update existing mappings. Clients should replace older
receipt acknowledgements based on `user_id` and `receipt_type` pairs.
For example:
Client receives m.receipt:
user = @alice:example.com
receipt_type = m.read
event_id = $aaa:example.com
Client receives another m.receipt:
user = @alice:example.com
receipt_type = m.read
event_id = $bbb:example.com
The client should replace the older acknowledgement for $aaa:example.com with
this one for $bbb:example.com
Clients should send read receipts when there is some certainty that the
event in question has been **displayed** to the user. Simply receiving
an event does not provide enough certainty that the user has seen the
event. The user SHOULD need to *take some action* such as viewing the
room that the event was sent to or dismissing a notification in order
for the event to count as "read". Clients SHOULD NOT send read receipts
for events sent by their own user.
A client can update the markers for its user by interacting with the
following HTTP APIs.
{{receipts\_cs\_http\_api}}
#### Server behaviour
For efficiency, receipts SHOULD be batched into one event per room
before delivering them to clients.
Receipts are sent across federation as EDUs with type `m.receipt`. The
format of the EDUs are:
{
<room_id>: {
<receipt_type>: {
<user_id>: { <content> }
},
...
},
...
}
These are always sent as deltas to previously sent receipts. Currently
only a single `<receipt_type>` should be used: `m.read`.
#### Security considerations
As receipts are sent outside the context of the event graph, there are
no integrity checks performed on the contents of `m.receipt` events.

@ -0,0 +1,24 @@
---
type: module
weight: 260
---
### Reporting Content
Users may encounter content which they find inappropriate and should be
able to report it to the server administrators or room moderators for
review. This module defines a way for users to report content.
Content is reported based upon a negative score, where -100 is "most
offensive" and 0 is "inoffensive".
#### Client behaviour
{{report\_content\_cs\_http\_api}}
#### Server behaviour
Servers are free to handle the reported content however they desire.
This may be a dedicated room to alert server administrators to the
reported content or some other mechanism for notifying the appropriate
people.

@ -0,0 +1,42 @@
---
type: module
weight: 170
---
### Room Previews
It is sometimes desirable to offer a preview of a room, where a user can
"lurk" and read messages posted to the room, without joining the room.
This can be particularly effective when combined with [Guest Access]().
Previews are implemented via the `world_readable` [Room History
Visibility](). setting, along with a special version of the [GET
/events](#get-matrix-client-%CLIENT_MAJOR_VERSION%-events) endpoint.
#### Client behaviour
A client wishing to view a room without joining it should call [GET
/rooms/:room\_id/initialSync](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-initialsync),
followed by [GET /events](#peeking_events_api). Clients will need to do
this in parallel for each room they wish to view.
Clients can of course also call other endpoints such as [GET
/rooms/:room\_id/messages](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-messages)
and [GET /search](#get-matrix-client-%CLIENT_MAJOR_VERSION%-search) to
access events outside the `/events` stream.
{{peeking\_events\_cs\_http\_api}}
#### Server behaviour
For clients which have not joined a room, servers are required to only
return events where the room state at the event had the
`m.room.history_visibility` state event present with
`history_visibility` value `world_readable`.
#### Security considerations
Clients may wish to display to their users that rooms which are
`world_readable` *may* be showing messages to non-joined users. There is
no way using this module to find out whether any non-joined guest users
*do* see events in the room, or to list or count any lurking users.

@ -0,0 +1,73 @@
---
type: module
weight: 310
---
### Room Upgrades
From time to time, a room may need to be upgraded to a different room
version for a variety for reasons. This module defines a way for rooms
to upgrade to a different room version when needed.
#### Events
{{m\_room\_tombstone\_event}}
#### Client behaviour
Clients which understand `m.room.tombstone` events and the `predecessor`
field on `m.room.create` events should communicate to the user that the
room was upgraded. One way of accomplishing this would be hiding the old
room from the user's room list and showing banners linking between the
old and new room - ensuring that permalinks work when referencing the
old room. Another approach may be to virtually merge the rooms such that
the old room's timeline seamlessly continues into the new timeline
without the user having to jump between the rooms.
{{room\_upgrades\_cs\_http\_api}}
#### Server behaviour
When the client requests to upgrade a known room to a known version, the
server:
1. Checks that the user has permission to send `m.room.tombstone`
events in the room.
2. Creates a replacement room with a `m.room.create` event containing a
`predecessor` field and the applicable `room_version`.
3. Replicates transferable state events to the new room. The exact
details for what is transferred is left as an implementation detail,
however the recommended state events to transfer are:
- `m.room.server_acl`
- `m.room.encryption`
- `m.room.name`
- `m.room.avatar`
- `m.room.topic`
- `m.room.guest_access`
- `m.room.history_visibility`
- `m.room.join_rules`
- `m.room.power_levels`
Membership events should not be transferred to the new room due to
technical limitations of servers not being able to impersonate
people from other homeservers. Additionally, servers should not
transfer state events which are sensitive to who sent them, such as
events outside of the Matrix namespace where clients may rely on the
sender to match certain criteria.
4. Moves any local aliases to the new room.
5. Sends a `m.room.tombstone` event to the old room to indicate that it
is not intended to be used any further.
6. If possible, the power levels in the old room should also be
modified to prevent sending of events and inviting new users. For
example, setting `events_default` and `invite` to the greater of
`50` and `users_default + 1`.
When a user joins the new room, the server should automatically
transfer/replicate some of the user's personalized settings such as
notifications, tags, etc.

@ -0,0 +1,91 @@
---
type: module
weight: 150
---
### Server Side Search
The search API allows clients to perform full text search across events
in all rooms that the user has been in, including those that they have
left. Only events that the user is allowed to see will be searched, e.g.
it won't include events in rooms that happened after you left.
#### Client behaviour
There is a single HTTP API for performing server-side search, documented
below.
{{search\_cs\_http\_api}}
#### Search Categories
The search API allows clients to search in different categories of
items. Currently the only specified category is `room_events`.
##### `room_events`
This category covers all events that the user is allowed to see,
including events in rooms that they have left. The search is performed
on certain keys of certain event types.
The supported keys to search over are:
- `content.body` in `m.room.message`
- `content.name` in `m.room.name`
- `content.topic` in `m.room.topic`
The search will *not* include rooms that are end to end encrypted.
The results include a `rank` key that can be used to sort the results by
relevancy. The higher the `rank` the more relevant the result is.
The value of `count` gives an approximation of the total number of
results. Homeservers may give an estimate rather than an exact value for
this field.
#### Ordering
The client can specify the ordering that the server returns results in.
The two allowed orderings are:
- `rank`, which returns the most relevant results first.
- `recent`, which returns the most recent results first.
The default ordering is `rank`.
#### Groups
The client can request that the results are returned along with grouping
information, e.g. grouped by `room_id`. In this case the response will
contain a group entry for each distinct value of `room_id`. Each group
entry contains at least a list of the `event_ids` that are in that
group, as well as potentially other metadata about the group.
The current required supported groupings are:
- `room_id`
- `sender`
#### Pagination
The server may return a `next_batch` key at various places in the
response. These are used to paginate the results. To fetch more results,
the client should send the *same* request to the server with a
`next_batch` query parameter set to that of the token.
The scope of the pagination is defined depending on where the
`next_batch` token was returned. For example, using a token inside a
group will return more results from within that group.
The currently supported locations for the `next_batch` token are:
- `search_categories.<category>.next_batch`
- `search_categories.<category>.groups.<group_key>.<group_id>.next_batch`
A server need not support pagination, even if there are more matching
results. In that case, they must not return a `next_batch` token in the
response.
#### Security considerations
The server must only return results that the user has permission to see.

@ -0,0 +1,450 @@
---
type: module
weight: 110
---
### Secrets
Clients may have secret information that they wish to be made available
to other authorised clients, but that the server should not be able to
see, so the information must be encrypted as it passes through the
server. This can be done either asynchronously, by storing encrypted
data on the server for later retrieval, or synchronously, by sending
messages to each other.
Each secret has an identifier that is used by clients to refer to the
secret when storing, fetching, requesting, or sharing the secret.
Secrets are plain strings; structured data can be stored by encoding it
as a string.
#### Storage
When secrets are stored on the server, they are stored in the user's
[account-data](#module-account-data), using an event type equal to the
secret's identifier. The keys that secrets are encrypted with are
described by data that is also stored in the user's account-data. Users
can have multiple keys, allowing them to control what sets of secrets
clients can access, depending on what keys are given to them.
##### Key storage
Each key has an ID, and the description of the key is stored in the
user's account\_data using the event type
`m.secret_storage.key.[key ID]`. The contents of the account data for
the key will include an `algorithm` property, which indicates the
encryption algorithm used, as well as a `name` property, which is a
human-readable name. Key descriptions may also have a `passphrase`
property for generating the key from a user-entered passphrase, as
described in [deriving keys from
passphrases](#deriving-keys-from-passphrases).
`KeyDescription`
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>name</td>
<td>string</td>
<td><strong>Required.</strong> The name of the key.</td>
</tr>
<tr class="even">
<td><p>algorithm</p></td>
<td><p>string</p></td>
<td><p><strong>Required.</strong> The encryption algorithm to be used for this key. Currently, only <code>m.secret_storage.v1.aes-hmac-sha2</code> is supported.</p></td>
</tr>
<tr class="odd">
<td><p>passphrase</p></td>
<td><p>string</p></td>
<td><p>See <a href="#deriving-keys-from-passphrases">deriving keys from passphrases</a> section for a description of this property.</p></td>
</tr>
</tbody>
</table>
Other properties depend on the encryption algorithm, and are described
below.
A key can be marked as the "default" key by setting the user's
account\_data with event type `m.secret_storage.default_key` to an
object that has the ID of the key as its `key` property. The default key
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.
##### Secret storage
Encrypted data is stored in the user's account\_data using the event
type defined by the feature that uses the data. The account\_data will
have an `encrypted` property that is a map from key ID to an object. The
algorithm from the `m.secret_storage.key.[key ID]` data for the given
key defines how the other properties are interpreted, though it's
expected that most encryption schemes would have `ciphertext` and `mac`
properties, where the `ciphertext` property is the unpadded
base64-encoded ciphertext, and the `mac` is used to ensure the integrity
of the data.
`Secret`
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><p>encrypted</p></td>
<td><p>{string: object}</p></td>
<td><p><strong>Required.</strong> Map from key ID the encrypted data. The exact format for the encrypted data is dependent on the key algorithm. See the definition of <code>AesHmacSha2EncryptedData</code> in the <a href="#m.secret_storage.v1.aes-hmac-sha2">m.secret_storage.v1.aes-hmac-sha2</a> section.</p></td>
</tr>
</tbody>
</table>
Example:
Some secret is encrypted using keys with ID `key_id_1` and `key_id_2`:
`org.example.some.secret`:
{
"encrypted": {
"key_id_1": {
"ciphertext": "base64+encoded+encrypted+data",
"mac": "base64+encoded+mac",
// ... other properties according to algorithm property in
// m.secret_storage.key.key_id_1
},
"key_id_2": {
// ...
}
}
}
and the key descriptions for the keys would be:
`m.secret_storage.key.key_id_1`:
{
"name": "Some key",
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
// ... other properties according to algorithm
}
`m.secret_storage.key.key_id_2`:
{
"name": "Some other key",
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
// ... other properties according to algorithm
}
###### `m.secret_storage.v1.aes-hmac-sha2`
Secrets encrypted using the `m.secret_storage.v1.aes-hmac-sha2`
algorithm are encrypted using AES-CTR-256, and authenticated using
HMAC-SHA-256. The secret is encrypted as follows:
1. Given the secret storage key, generate 64 bytes by performing an
HKDF with SHA-256 as the hash, a salt of 32 bytes of 0, and with the
secret name as the info. The first 32 bytes are used as the AES key,
and the next 32 bytes are used as the MAC key
2. Generate 16 random bytes, set bit 63 to 0 (in order to work around
differences in AES-CTR implementations), and use this as the AES
initialization vector. This becomes the `iv` property, encoded using
base64.
3. Encrypt the data using AES-CTR-256 using the AES key generated
above. This encrypted data, encoded using base64, becomes the
`ciphertext` property.
4. Pass the raw encrypted data (prior to base64 encoding) through
HMAC-SHA-256 using the MAC key generated above. The resulting MAC is
base64-encoded and becomes the `mac` property.
`AesHmacSha2EncryptedData`
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><p>iv</p></td>
<td><p>string</p></td>
<td><p><strong>Required.</strong> The 16-byte initialization vector, encoded as base64.</p></td>
</tr>
<tr class="even">
<td><p>ciphertext</p></td>
<td><p>string</p></td>
<td><p><strong>Required.</strong> The AES-CTR-encrypted data, encoded as base64.</p></td>
</tr>
<tr class="odd">
<td>mac</td>
<td>string</td>
<td><strong>Required.</strong> The MAC, encoded as base64.</td>
</tr>
</tbody>
</table>
For the purposes of allowing clients to check whether a user has
correctly entered the key, clients should:
1. encrypt and MAC a message consisting of 32 bytes of 0 as described
above, using the empty string as the info parameter to the HKDF in
step 1.
2. store the `iv` and `mac` in the `m.secret_storage.key.[key ID]`
account-data.
`AesHmacSha2KeyDescription`
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>name</td>
<td>string</td>
<td><strong>Required.</strong> The name of the key.</td>
</tr>
<tr class="even">
<td><p>algorithm</p></td>
<td><p>string</p></td>
<td><p><strong>Required.</strong> The encryption algorithm to be used for this key. Currently, only <code>m.secret_storage.v1.aes-hmac-sha2</code> is supported.</p></td>
</tr>
<tr class="odd">
<td><p>passphrase</p></td>
<td><p>object</p></td>
<td><p>See <a href="#deriving-keys-from-passphrases">deriving keys from passphrases</a> section for a description of this property.</p></td>
</tr>
<tr class="even">
<td>iv</td>
<td>string</td>
<td>The 16-byte initialization vector, encoded as base64.</td>
</tr>
<tr class="odd">
<td><p>mac</p></td>
<td><p>string</p></td>
<td><p>The MAC of the result of encrypting 32 bytes of 0, encoded as base64.</p></td>
</tr>
</tbody>
</table>
For example, the `m.secret_storage.key.key_id` for a key using this
algorithm could look like:
{
"name": "m.default",
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
"iv": "random+data",
"mac": "mac+of+encrypted+zeros"
}
and data encrypted using this algorithm could look like this:
{
"encrypted": {
"key_id": {
"iv": "16+bytes+base64",
"ciphertext": "base64+encoded+encrypted+data",
"mac": "base64+encoded+mac"
}
}
}
###### Key representation
When a user is given a raw key for `m.secret_storage.v1.aes-hmac-sha2`,
it will be presented as a string constructed as follows:
1. The key is prepended by the two bytes `0x8b` and `0x01`
2. All the bytes in the string above, including the two header bytes,
are XORed together to form a parity byte. This parity byte is
appended to the byte string.
3. The byte string is encoded using base58, using the same [mapping as
is used for Bitcoin
addresses](https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart),
that is, using the alphabet
`123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`.
4. The string is formatted into groups of four characters separated by
spaces.
When decoding a raw key, the process should be reversed, with the
exception that whitespace is insignificant in the user's input.
###### Deriving keys from passphrases
A user may wish to use a chosen passphrase rather than a randomly
generated key. In this case, information on how to generate the key from
a passphrase will be stored in the `passphrase` property of the
`m.secret_storage.key.[key ID]` account-data. The `passphrase` property
has an `algorithm` property that indicates how to generate the key from
the passphrase. Other properties of the `passphrase` property are
defined by the `algorithm` specified.
####### `m.pbkdf2`
For the `m.pbkdf2` algorithm, the `passphrase` property has the
following properties:
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>algorithm</td>
<td>string</td>
<td><strong>Required.</strong> Must be <code>m.pbkdf2</code></td>
</tr>
<tr class="even">
<td>salt</td>
<td>string</td>
<td><strong>Required.</strong> The salt used in PBKDF2.</td>
</tr>
<tr class="odd">
<td>iterations</td>
<td>integer</td>
<td><strong>Required.</strong> The number of iterations to use in PBKDF2.</td>
</tr>
<tr class="even">
<td><p>bits</p></td>
<td><p>integer</p></td>
<td><p>Optional. The number of bits to generate for the key. Defaults to 256.</p></td>
</tr>
</tbody>
</table>
The key is generated using PBKDF2 with SHA-512 as the hash, using the
salt given in the `salt` parameter, and the number of iterations given
in the `iterations` parameter.
Example:
{
"passphrase": {
"algorithm": "m.pbkdf2",
"salt": "MmMsAlty",
"iterations": 100000,
"bits": 256
},
...
}
#### Sharing
To request a secret from other devices, a client sends an
`m.secret.requests` device event with `action` set to `request` and
`name` set to the identifier of the secret. A device that wishes to
share the secret will reply with an `m.secret.send` event, encrypted
using olm. When the original client obtains the secret, it sends an
`m.secret.request` event with `action` set to `request_cancellation` to
all devices other than the one that it received the secret from. Clients
should ignore `m.secret.send` events received from devices that it did
not send an `m.secret.request` event to.
Clients must ensure that they only share secrets with other devices that
are allowed to see them. For example, clients should only share secrets
with the users own devices that are verified and may prompt the user to
confirm sharing the secret.
##### Event definitions
###### `m.secret.request`
Sent by a client to request a secret from another device or to cancel a
previous request. It is sent as an unencrypted to-device event.
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><p>name</p></td>
<td><p>string</p></td>
<td><p>Required if <code>action</code> is <code>request</code>. The name of the secret that is being requested.</p></td>
</tr>
<tr class="even">
<td>action</td>
<td>enum</td>
<td><strong>Required.</strong> One of ["request", "request_cancellation"].</td>
</tr>
<tr class="odd">
<td>requesting_device_id</td>
<td>string</td>
<td><strong>Required.</strong> The ID of the device requesting the secret.</td>
</tr>
<tr class="even">
<td><p>request_id</p></td>
<td><p>string</p></td>
<td><p><strong>Required.</strong> A random string uniquely identifying (with respect to the requester and the target) the target for a secret. If the secret is requested from multiple devices at the same time, the same ID may be used for every target. The same ID is also used in order to cancel a previous request.</p></td>
</tr>
</tbody>
</table>
Example:
{
"name": "org.example.some.secret",
"action": "request",
"requesting_device_id": "ABCDEFG",
"request_id": "randomly_generated_id_9573"
}
###### `m.secret.send`
Sent by a client to share a secret with another device, in response to
an `m.secret.request` event. It must be encrypted as an
`m.room.encrypted` event, then sent as a to-device event.
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>request_id</td>
<td>string</td>
<td><strong>Required.</strong> The ID of the request that this a response to.</td>
</tr>
<tr class="even">
<td>secret</td>
<td>string</td>
<td><strong>Required.</strong> The contents of the secret.</td>
</tr>
</tbody>
</table>
Example:
{
"request_id": "randomly_generated_id_9573",
"secret": "ThisIsASecretDon'tTellAnyone"
}

@ -0,0 +1,143 @@
---
type: module
weight: 80
---
### Send-to-Device messaging<span id="module:to_device"></span>
This module provides a means by which clients can exchange signalling
messages without them being stored permanently as part of a shared
communication history. A message is delivered exactly once to each
client device.
The primary motivation for this API is exchanging data that is
meaningless or undesirable to persist in the room DAG - for example,
one-time authentication tokens or key data. It is not intended for
conversational data, which should be sent using the normal \_ API for
consistency throughout Matrix.
#### Client behaviour
To send a message to other devices, a client should call
`/sendToDevice`\_. Only one message can be sent to each device per
transaction, and they must all have the same event type. The device ID
in the request body can be set to `*` to request that the message be
sent to all known devices.
If there are send-to-device messages waiting for a client, they will be
returned by \_, as detailed in Extensions to /sync\_. Clients should
inspect the `type` of each returned event, and ignore any they do not
understand.
#### Server behaviour
Servers should store pending messages for local users until they are
successfully delivered to the destination device. When a client calls \_
with an access token which corresponds to a device with pending
messages, the server should list the pending messages, in order of
arrival, in the response body.
When the client calls `/sync` again with the `next_batch` token from the
first response, the server should infer that any send-to-device messages
in that response have been delivered successfully, and delete them from
the store.
If there is a large queue of send-to-device messages, the server should
limit the number sent in each `/sync` response. 100 messages is
recommended as a reasonable limit.
If the client sends messages to users on remote domains, those messages
should be sent on to the remote servers via
[federation](../server_server/%SERVER_RELEASE_LABEL%.html#send-to-device-messaging).
#### Protocol definitions
{{to\_device\_cs\_http\_api}}
##### Extensions to /sync
This module adds the following properties to the \_ response:
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><p>to_device</p></td>
<td><p>ToDevice</p></td>
<td><p>Optional. Information on the send-to-device messages for the client device.</p></td>
</tr>
</tbody>
</table>
`ToDevice`
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>events</td>
<td>[Event]</td>
<td>List of send-to-device messages.</td>
</tr>
</tbody>
</table>
`Event`
<table>
<thead>
<tr class="header">
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><p>content</p></td>
<td><p>EventContent</p></td>
<td><p>The content of this event. The fields in this object will vary depending on the type of event.</p></td>
</tr>
<tr class="even">
<td><p>sender</p></td>
<td><p>string</p></td>
<td><p>The Matrix user ID of the user who sent this event.</p></td>
</tr>
<tr class="odd">
<td>type</td>
<td>string</td>
<td>The type of event.</td>
</tr>
</tbody>
</table>
Example response:
{
"next_batch": "s72595_4483_1934",
"rooms": {"leave": {}, "join": {}, "invite": {}},
"to_device": {
"events": [
{
"sender": "@alice:example.com",
"type": "m.new_device",
"content": {
"device_id": "XYZABCDE",
"rooms": ["!726s6s6q:example.com"]
}
}
]
}
}

@ -0,0 +1,62 @@
---
type: module
weight: 290
---
### Server Access Control Lists (ACLs) for rooms
In some scenarios room operators may wish to prevent a malicious or
untrusted server from participating in their room. Sending an
[m.room.server\_acl]() state event into a room is an effective way to
prevent the server from participating in the room at the federation
level.
Server ACLs can also be used to make rooms only federate with a limited
set of servers, or retroactively make the room no longer federate with
any other server, similar to setting the `m.federate` value on the
[m.room.create]() event.
{{m\_room\_server\_acl\_event}}
Note
Port numbers are not supported because it is unclear to parsers whether
a port number should be matched or an IP address literal. Additionally,
it is unlikely that one would trust a server running on a particular
domain's port but not a different port, especially considering the
server host can easily change ports.
Note
CIDR notation is not supported for IP addresses because Matrix does not
encourage the use of IPs for identifying servers. Instead, a blanket
`allow_ip_literals` is provided to cover banning them.
#### Client behaviour
Clients are not expected to perform any additional duties beyond sending
the event. Clients should describe changes to the server ACLs to the
user in the user interface, such as in the timeline.
Clients may wish to kick affected users from the room prior to denying a
server access to the room to help prevent those servers from
participating and to provide feedback to the users that they have been
excluded from the room.
#### Server behaviour
Servers MUST prevent blacklisted servers from sending events or
participating in the room when an [m.room.server\_acl]() event is
present in the room state. Which APIs are specifically affected are
described in the Server-Server API specification.
Servers should still send events to denied servers if they are still
residents of the room.
#### Security considerations
Server ACLs are only effective if every server in the room honours them.
Servers that do not honour the ACLs may still permit events sent by
denied servers into the room, leaking them to other servers in the room.
To effectively enforce an ACL in a room, the servers that do not honour
the ACLs should be denied in the room as well.

@ -0,0 +1,68 @@
---
type: module
weight: 320
---
### Server Notices
Homeserver hosts often want to send messages to users in an official
capacity, or have resource limits which affect a user's ability to use
the homeserver. For example, the homeserver may be limited to a certain
number of active users per month and has exceeded that limit. To
communicate this failure to users, the homeserver would use the Server
Notices room.
The aesthetics of the room (name, topic, avatar, etc) are left as an
implementation detail. It is recommended that the homeserver decorate
the room such that it looks like an official room to users.
#### Events
Notices are sent to the client as normal `m.room.message` events with a
`msgtype` of `m.server_notice` in the server notices room. Events with a
`m.server_notice` `msgtype` outside of the server notice room must be
ignored by clients.
The specified values for `server_notice_type` are:
`m.server_notice.usage_limit_reached`
The server has exceeded some limit which requires the server
administrator to intervene. The `limit_type` describes the kind of limit
reached. The specified values for `limit_type` are:
`monthly_active_user`
The server's number of active users in the last 30 days has exceeded the
maximum. New connections are being refused by the server. What defines
"active" is left as an implementation detail, however servers are
encouraged to treat syncing users as "active".
{{m\_room\_message\_m\_server\_notice\_event}}
#### Client behaviour
Clients can identify the server notices room by the `m.server_notice`
tag on the room. Active notices are represented by the [pinned
events](#m-room-pinned-events) in the server notices room. Server notice
events pinned in that room should be shown to the user through special
UI and not through the normal pinned events interface in the client. For
example, clients may show warning banners or bring up dialogs to get the
user's attention. Events which are not server notice events and are
pinned in the server notices room should be shown just like any other
pinned event in a room.
The client must not expect to be able to reject an invite to join the
server notices room. Attempting to reject the invite must result in a
`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM` error. Servers should not prevent
the user leaving the room after joining the server notices room, however
the same error code must be used if the server will prevent leaving the
room.
#### Server behaviour
Servers should manage exactly 1 server notices room per user. Servers
must identify this room to clients with the `m.server_notice` tag.
Servers should invite the target user rather than automatically join
them to the server notice room.
How servers send notices to clients, and which user they use to send the
events, is left as an implementation detail for the server.

@ -0,0 +1,309 @@
---
type: module
weight: 220
---
### SSO client login/authentication
Single Sign-On (SSO) is a generic term which refers to protocols which
allow users to log into applications via a single web-based
authentication portal. Examples include OpenID Connect, "Central
Authentication Service" (CAS) and SAML.
This module allows a Matrix homeserver to delegate user authentication
to an external authentication server supporting one of these protocols.
In this process, there are three systems involved:
> - A Matrix client, using the APIs defined this specification, which
> is seeking to authenticate a user to a Matrix homeserver.
> - A Matrix homeserver, implementing the APIs defined in this
> specification, but which is delegating user authentication to the
> authentication server.
> - An "authentication server", which is responsible for
> authenticating the user.
This specification is concerned only with communication between the
Matrix client and the homeserver, and is independent of the SSO protocol
used to communicate with the authentication server. Different Matrix
homeserver implementations might support different SSO protocols.
Clients and homeservers implementing the SSO flow will need to consider
both [login]() and [user-interactive authentication](). The flow is
similar in both cases, but there are slight differences.
Typically, SSO systems require a single "callback" URI to be configured
at the authentication server. Once the user is authenticated, their
browser is redirected to that URI. It is up to the Matrix homeserver
implementation to implement a suitable endpoint. For example, for CAS
authentication the homeserver should provide a means for the
administrator to configure where the CAS server is and the REST
endpoints which consume the ticket.
#### Client login via SSO
An overview of the process is as follows:
1. The Matrix client calls `GET /login`\_ to find the supported login
types, and the homeserver includes a flow with
`"type": "m.login.sso"` in the response.
2. To initiate the `m.login.sso` login type, the Matrix client
instructs the user's browser to navigate to the
`/login/sso/redirect`\_ endpoint on the user's homeserver.
3. The homeserver responds with an HTTP redirect to the SSO user
interface, which the browser follows.
4. The authentication server and the homeserver interact to verify the
user's identity and other authentication information, potentially
using a number of redirects.
5. The browser is directed to the `redirectUrl` provided by the client
with a `loginToken` query parameter for the client to log in with.
6. The client exchanges the login token for an access token by calling
the `/login`\_ endpoint with a `type` of `m.login.token`.
For native applications, typically steps 1 to 4 are carried out by
opening an embedded web view.
These steps are illustrated as follows:
Matrix Client Matrix Homeserver Auth Server
| | |
|-------------(0) GET /login----------->| |
|<-------------login types--------------| |
| | |
| Webview | |
| | | |
|----->| | |
| |--(1) GET /login/sso/redirect-->| |
| |<---------(2) 302---------------| |
| | | |
| |<========(3) Authentication process================>|
| | | |
| |<--(4) redirect to redirectUrl--| |
|<-----| | |
| | |
|---(5) POST /login with login token--->| |
|<-------------access token-------------| |
Note
In the older [r0.4.0
version](https://matrix.org/docs/spec/client_server/r0.4.0.html#cas-based-client-login)
of this specification it was possible to authenticate via CAS when the
homeserver provides a `m.login.cas` login flow. This specification
deprecates the use of `m.login.cas` to instead prefer `m.login.sso`,
which is the same process with the only change being which redirect
endpoint to use: for `m.login.cas`, use `/cas/redirect` and for
`m.login.sso` use `/sso/redirect` (described below). The endpoints are
otherwise the same.
##### Client behaviour
The client starts the process by instructing the browser to navigate to
`/login/sso/redirect`\_ with an appropriate `redirectUrl`. Once
authentication is successful, the browser will be redirected to that
`redirectUrl`.
{{sso\_login\_redirect\_cs\_http\_api}}
###### Security considerations
1. CSRF attacks via manipulation of parameters on the `redirectUrl`
Clients should validate any requests to the `redirectUrl`. In
particular, it may be possible for attackers to falsify any query
parameters, leading to cross-site request forgery (CSRF) attacks.
For example, consider a web-based client at
`https://client.example.com`, which wants to initiate SSO login on
the homeserver at `server.example.org`. It does this by storing the
homeserver name in a query parameter for the `redirectUrl`: it
redirects to
`https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=server.example.org`.
An attacker could trick a victim into following a link to
`https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=evil.com`,
which would result in the client sending a login token for the
victim's account to the attacker-controlled site `evil.com`.
To guard against this, clients MUST NOT store state (such as the
address of the homeserver being logged into) anywhere it can be
modified by external processes.
Instead, the state could be stored in
[localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)
or in a cookie.
2. For added security, clients SHOULD include a unique identifier in
the `redirectUrl` and reject any callbacks that do not contain a
recognised identifier, to guard against unsolicited login attempts
and replay attacks.
##### Server behaviour
###### Redirecting to the Authentication server
The server should handle
`/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect` as follows:
1. It should build a suitable request for the SSO system.
2. It should store enough state that the flow can be securely resumed
after the SSO process completes. One way to do this is by storing a
cookie which is stored in the user's browser, by adding a
`Set-Cookie` header to the response.
3. It should redirect the user's browser to the SSO login page with the
appropriate parameters.
See also the "Security considerations" below.
###### Handling the callback from the Authentication server
Note that there will normally be a single callback URI which is used for
both login and user-interactive authentication: it is up to the
homeserver implementation to distinguish which is taking place.
The homeserver should validate the response from the SSO system: this
may require additional calls to the authentication server, and/or may
require checking a signature on the response.
The homeserver then proceeds as follows:
1. The homeserver MUST map the user details received from the
authentication server to a valid [Matrix user
identifier](../appendices.html#user-identifiers). The guidance in
[Mapping from other character
sets](../appendices.html#mapping-from-other-character-sets) may be
useful.
2. If the generated user identifier represents a new user, it should be
registered as a new user.
3. The homeserver should generate a short-term login token. This is an
opaque token, suitable for use with the `m.login.token` type of the
`/login`\_ API. The lifetime of this token SHOULD be limited to
around five seconds.
4. The homeserver adds a query parameter of `loginToken`, with the
value of the generated login token, to the `redirectUrl` given in
the `/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect`
request. (Note: `redirectURL` may or may not include existing query
parameters. If it already includes one or more `loginToken`
parameters, they should be removed before adding the new one.)
5. The homeserver redirects the user's browser to the URI thus built.
##### Security considerations
1. Homeservers should ensure that login tokens are not sent to
malicious clients.
For example, consider a homeserver at `server.example.org`. An
attacker tricks a victim into following a link to
`https://server.example.org/login/sso/redirect?redirectUrl=https://evil.com`,
resulting in a login token being sent to the attacker-controlled
site `evil.com`. This is a form of cross-site request forgery
(CSRF).
To mitigate this, Homeservers SHOULD confirm with the user that they
are happy to grant access to their matrix account to the site named
in the `redirectUrl`. This can be done either *before* redirecting
to the SSO login page when handling the
`/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect`
endpoint, or *after* login when handling the callback from the
authentication server. (If the check is performed before
redirecting, it is particularly important that the homeserver guards
against unsolicited authentication attempts as below).
It may be appropriate to whitelist a set of known-trusted client
URLs in this process. In particular, the homeserver's own [login
fallback]() implementation could be excluded.
2. For added security, homeservers SHOULD guard against unsolicited
authentication attempts by tracking pending requests. One way to do
this is to set a cookie when handling
`/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect`, which
is checked and cleared when handling the callback from the
authentication server.
#### SSO during User-Interactive Authentication
[User-interactive authentication]() is used by client-server endpoints
which require additional confirmation of the user's identity (beyond
holding an access token). Typically this means that the user must
re-enter their password, but for homeservers which delegate to an SSO
server, this means redirecting to the authentication server during
user-interactive auth.
The implemementation of this is based on the [Fallback]() mechanism for
user-interactive auth.
#### Client behaviour
Clients do not need to take any particular additional steps beyond
ensuring that the fallback mechanism has been implemented, and treating
the `m.login.sso` authentication type the same as any other unknown type
(i.e. they should open a browser window for
`/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/m.login.sso/fallback/web?session=<session_id>`.
Once the flow has completed, the client retries the request with the
session only.)
#### Server behaviour
##### Redirecting to the Authentication server
The server should handle
`/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/m.login.sso/fallback/web`
in much the same way as
`/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect`, which is to
say:
1. It should build a suitable request for the SSO system.
2. It should store enough state that the flow can be securely resumed
after the SSO process completes. One way to do this is by storing a
cookie which is stored in the user's browser, by adding a
`Set-Cookie` header to the response.
3. It should redirect the user's browser to the SSO login page with the
appropriate parameters.
See also the "Security considerations" below.
###### Handling the callback from the Authentication server
Note that there will normally be a single callback URI which is used for
both login and user-interactive authentication: it is up to the
homeserver implementation to distinguish which is taking place.
The homeserver should validate the response from the SSO system: this
may require additional calls to the authentication server, and/or may
require checking a signature on the response.
The homeserver then returns the [user-interactive authentication
fallback completion]() page to the user's browser.
###### Security considerations
1. Confirming the operation
The homeserver SHOULD confirm that the user is happy for the
operation to go ahead. The goal of the user-interactive
authentication operation is to guard against a compromised
`access_token` being used to take over the user's account. Simply
redirecting the user to the SSO system is insufficient, since they
may not realise what is being asked of them, or the SSO system may
even confirm the authentication automatically.
For example, the homeserver might serve a page with words to the
effect of:
> A client is trying to remove a device from your account. To
> confirm this action, re-authenticate with single sign-on. If you
> did not expect this, your account may be compromised!
This confirmation could take place before redirecting to the SSO
authentication page (when handling the
`/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/m.login.sso/fallback/web`
endpoint), or *after* authentication when handling the callback from
the authentication server. (If the check is performed before
redirecting, it is particularly important that the homeserver guards
against unsolicited authentication attempts as below).
2. For added security, homeservers SHOULD guard against unsolicited
authentication attempts by tracking pending requests. One way to do
this is to set a cookie when handling
`/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/m.login.sso/fallback/web`,
which is checked and cleared when handling the callback from the
authentication server.

@ -0,0 +1,40 @@
---
type: module
weight: 250
---
### Sticker Messages
This module allows users to send sticker messages in to rooms or direct
messaging sessions.
Sticker messages are specialised image messages that are displayed
without controls (e.g. no "download" link, or light-box view on click,
as would be displayed for for [m.image]() events).
Sticker messages are intended to provide simple "reaction" events in the
message timeline. The matrix client should provide some mechanism to
display the sticker "body" e.g. as a tooltip on hover, or in a modal
when the sticker image is clicked.
#### Events
Sticker events are received as a single `m.sticker` event in the
`timeline` section of a room, in a `/sync`.
{{m\_sticker\_event}}
#### Client behaviour
Clients supporting this message type should display the image content
from the event URL directly in the timeline.
A thumbnail image should be provided in the `info` object. This is
largely intended as a fallback for clients that do not fully support the
`m.sticker` event type. In most cases it is fine to set the thumbnail
URL to the same URL as the main event content.
It is recommended that sticker image content should be 512x512 pixels in
size or smaller. The dimensions of the image file should be twice the
intended display size specified in the `info` object in order to assist
rendering sharp images on higher DPI screens.

@ -0,0 +1,66 @@
---
type: module
weight: 180
---
### Room Tagging
Users can add tags to rooms. Tags are namespaced strings used to label
rooms. A room may have multiple tags. Tags are only visible to the user
that set them but are shared across all their devices.
#### Events
The tags on a room are received as single `m.tag` event in the
`account_data` section of a room. The content of the `m.tag` event is a
`tags` key whose value is an object mapping the name of each tag to
another object.
The JSON object associated with each tag gives information about the
tag, e.g how to order the rooms with a given tag.
Ordering information is given under the `order` key as a number between
0 and 1. The numbers are compared such that 0 is displayed first.
Therefore a room with an `order` of `0.2` would be displayed before a
room with an `order` of `0.7`. If a room has a tag without an `order`
key then it should appear after the rooms with that tag that have an
`order` key.
The name of a tag MUST NOT exceed 255 bytes.
The tag namespace is defined as follows:
- The namespace `m.*` is reserved for tags defined in the Matrix
specification. Clients must ignore any tags in this namespace they
don't understand.
- The namespace `u.*` is reserved for user-defined tags. The portion
of the string after the `u.` is defined to be the display name of
this tag. No other semantics should be inferred from tags in this
namespace.
- A client or app willing to use special tags for advanced
functionality should namespace them similarly to state keys:
`tld.name.*`
- Any tag in the `tld.name.*` form but not matching the namespace of
the current client should be ignored
- Any tag not matching the above rules should be interpreted as a user
tag from the `u.*` namespace, as if the name had already had `u.`
stripped from the start (ie. the name of the tag is used as the
display name directly). These non-namespaced tags are supported for
historical reasons. New tags should use one of the defined
namespaces above.
Several special names are listed in the specification: The following
tags are defined in the `m.*` namespace:
- `m.favourite`: The user's favourite rooms. These should be shown
with higher precedence than other rooms.
- `m.lowpriority`: These should be shown with lower precedence than
others.
- `m.server_notice`: Used to identify [Server Notice
Rooms](#module-server-notices).
{{m\_tag\_event}}
#### Client Behaviour
{{tags\_cs\_http\_api}}

@ -0,0 +1,235 @@
---
type: module
weight: 140
---
### Third party invites
This module adds in support for inviting new members to a room where
their Matrix user ID is not known, instead addressing them by a third
party identifier such as an email address. There are two flows here; one
if a Matrix user ID is known for the third party identifier, and one if
not. Either way, the client calls `/invite` with the details of the
third party identifier.
The homeserver asks the identity server whether a Matrix user ID is
known for that identifier:
- If it is, an invite is simply issued for that user.
- If it is not, the homeserver asks the identity server to record the
details of the invitation, and to notify the invitee's homeserver of
this pending invitation if it gets a binding for this identifier in
the future. The identity server returns a token and public key to
the inviting homeserver.
When the invitee's homeserver receives the notification of the binding,
it should insert an `m.room.member` event into the room's graph for that
user, with `content.membership` = `invite`, as well as a
`content.third_party_invite` property which contains proof that the
invitee does indeed own that third party identifier. See the
[m.room.member](#m-room-member) schema for more information.
#### Events
{{m\_room\_third\_party\_invite\_event}}
#### Client behaviour
A client asks a server to invite a user by their third party identifier.
{{third\_party\_membership\_cs\_http\_api}}
#### Server behaviour
Upon receipt of an `/invite`, the server is expected to look up the
third party identifier with the provided identity server. If the lookup
yields a result for a Matrix User ID then the normal invite process can
be initiated. This process ends up looking like this:
+---------+ +-------------+ +-----------------+
| Client | | Homeserver | | IdentityServer |
+---------+ +-------------+ +-----------------+
| | |
| POST /invite | |
|------------------------------------>| |
| | |
| | GET /lookup |
| |--------------------------------------------------->|
| | |
| | User ID result |
| |<---------------------------------------------------|
| | |
| | Invite process for the discovered User ID |
| |------------------------------------------ |
| | | |
| |<----------------------------------------- |
| | |
| Complete the /invite request | |
|<------------------------------------| |
| | |
However, if the lookup does not yield a bound User ID, the homeserver
must store the invite on the identity server and emit a valid
`m.room.third_party_invite` event to the room. This process ends up
looking like this:
+---------+ +-------------+ +-----------------+
| Client | | Homeserver | | IdentityServer |
+---------+ +-------------+ +-----------------+
| | |
| POST /invite | |
|------------------------------------>| |
| | |
| | GET /lookup |
| |-------------------------------------------------------------->|
| | |
| | "no users" result |
| |<--------------------------------------------------------------|
| | |
| | POST /store-invite |
| |-------------------------------------------------------------->|
| | |
| | Information needed for the m.room.third_party_invite |
| |<--------------------------------------------------------------|
| | |
| | Emit m.room.third_party_invite to the room |
| |------------------------------------------- |
| | | |
| |<------------------------------------------ |
| | |
| Complete the /invite request | |
|<------------------------------------| |
| | |
All homeservers MUST verify the signature in the event's
`content.third_party_invite.signed` object.
The third party user will then need to verify their identity, which
results in a call from the identity server to the homeserver that bound
the third party identifier to a user. The homeserver then exchanges the
`m.room.third_party_invite` event in the room for a complete
`m.room.member` event for `membership: invite` for the user that has
bound the third party identifier.
If a homeserver is joining a room for the first time because of an
`m.room.third_party_invite`, the server which is already participating
in the room (which is chosen as per the standard server-server
specification) MUST validate that the public key used for signing is
still valid, by checking `key_validity_url` in the above described way.
No other homeservers may reject the joining of the room on the basis of
`key_validity_url`, this is so that all homeservers have a consistent
view of the room. They may, however, indicate to their clients that a
member's membership is questionable.
For example, given H1, H2, and H3 as homeservers, UserA as a user of H1,
and an identity server IS, the full sequence for a third party invite
would look like the following. This diagram assumes H1 and H2 are
residents of the room while H3 is attempting to join.
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
| UserA | | ThirdPartyUser | | H1 | | H2 | | H3 | | IS |
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
| | | | | |
| POST /invite for ThirdPartyUser | | | |
|----------------------------------->| | | |
| | | | | |
| | | GET /lookup | | |
| | |---------------------------------------------------------------------------------------------->|
| | | | | |
| | | | Lookup results (empty object) |
| | |<----------------------------------------------------------------------------------------------|
| | | | | |
| | | POST /store-invite | | |
| | |---------------------------------------------------------------------------------------------->|
| | | | | |
| | | | Token, keys, etc for third party invite |
| | |<----------------------------------------------------------------------------------------------|
| | | | | |
| | | (Federation) Emit m.room.third_party_invite | | |
| | |----------------------------------------------->| | |
| | | | | |
| Complete /invite request | | | |
|<-----------------------------------| | | |
| | | | | |
| | Verify identity | | | |
| |-------------------------------------------------------------------------------------------------------------------->|
| | | | | |
| | | | | POST /3pid/onbind |
| | | | |<---------------------------|
| | | | | |
| | | PUT /exchange_third_party_invite/:roomId | |
| | |<-----------------------------------------------------------------| |
| | | | | |
| | | Verify the request | | |
| | |------------------- | | |
| | | | | | |
| | |<------------------ | | |
| | | | | |
| | | (Federation) Emit m.room.member for invite | | |
| | |----------------------------------------------->| | |
| | | | | |
| | | | | |
| | | (Federation) Emit the m.room.member event sent to H2 | |
| | |----------------------------------------------------------------->| |
| | | | | |
| | | Complete /exchange_third_party_invite/:roomId request | |
| | |----------------------------------------------------------------->| |
| | | | | |
| | | | | Participate in the room |
| | | | |------------------------ |
| | | | | | |
| | | | |<----------------------- |
| | | | | |
Note that when H1 sends the `m.room.member` event to H2 and H3 it does
not have to block on either server's receipt of the event. Likewise, H1
may complete the `/exchange_third_party_invite/:roomId` request at the
same time as sending the `m.room.member` event to H2 and H3.
Additionally, H3 may complete the `/3pid/onbind` request it got from IS
at any time - the completion is not shown in the diagram.
H1 MUST verify the request from H3 to ensure the `signed` property is
correct as well as the `key_validity_url` as still being valid. This is
done by making a request to the [identity server
/isvalid](../identity_service/%IDENTITY_RELEASE_LABEL%.html#get-matrix-identity-v2-pubkey-isvalid)
endpoint, using the provided URL rather than constructing a new one. The
query string and response for the provided URL must match the Identity
Service Specification.
The reason that no other homeserver may reject the event based on
checking `key_validity_url` is that we must ensure event acceptance is
deterministic. If some other participating server doesn't have a network
path to the keyserver, or if the keyserver were to go offline, or revoke
its keys, that other server would reject the event and cause the
participating servers' graphs to diverge. This relies on participating
servers trusting each other, but that trust is already implied by the
server-server protocol. Also, the public key signature verification must
still be performed, so the attack surface here is minimized.
#### Security considerations
There are a number of privacy and trust implications to this module.
It is important for user privacy that leaking the mapping between a
matrix user ID and a third party identifier is hard. In particular,
being able to look up all third party identifiers from a matrix user ID
(and accordingly, being able to link each third party identifier) should
be avoided wherever possible. To this end, the third party identifier is
not put in any event, rather an opaque display name provided by the
identity server is put into the events. Clients should not remember or
display third party identifiers from invites, other than for the use of
the inviter themself.
Homeservers are not required to trust any particular identity server(s).
It is generally a client's responsibility to decide which identity
servers it trusts, not a homeserver's. Accordingly, this API takes
identity servers as input from end users, and doesn't have any specific
trusted set. It is possible some homeservers may want to supply
defaults, or reject some identity servers for *its* users, but no
homeserver is allowed to dictate which identity servers *other*
homeservers' users trust.
There is some risk of denial of service attacks by flooding homeservers
or identity servers with many requests, or much state to store.
Defending against these is left to the implementer's discretion.

@ -0,0 +1,22 @@
---
type: module
weight: 270
---
### Third Party Networks
Application services can provide access to third party networks via
bridging. This allows Matrix users to communicate with users on other
communication platforms, with messages ferried back and forth by the
application service. A single application service may bridge multiple
third party networks, and many individual locations within those
networks. A single third party network location may be bridged to
multiple Matrix rooms.
#### Third Party Lookups
A client may wish to provide a rich interface for joining third party
locations and connecting with third party users. Information necessary
for such an interface is provided by third party lookups.
{{third\_party\_lookup\_cs\_http\_api}}

@ -0,0 +1,41 @@
---
type: module
weight: 30
---
### Typing Notifications
Users may wish to be informed when another user is typing in a room.
This can be achieved using typing notifications. These are ephemeral
events scoped to a `room_id`. This means they do not form part of the
[Event Graph](index.html#event-graphs) but still have a `room_id` key.
#### Events
{{m\_typing\_event}}
#### Client behaviour
When a client receives an `m.typing` event, it MUST use the user ID list
to **REPLACE** its knowledge of every user who is currently typing. The
reason for this is that the server *does not remember* users who are not
currently typing as that list gets big quickly. The client should mark
as not typing any user ID who is not in that list.
It is recommended that clients store a `boolean` indicating whether the
user is typing or not. Whilst this value is `true` a timer should fire
periodically every N seconds to send a typing HTTP request. The value of
N is recommended to be no more than 20-30 seconds. This request should
be re-sent by the client to continue informing the server the user is
still typing. As subsequent requests will replace older requests, a
safety margin of 5 seconds before the expected timeout runs out is
recommended. When the user stops typing, the state change of the
`boolean` to `false` should trigger another HTTP request to inform the
server that the user has stopped typing.
{{typing\_cs\_http\_api}}
#### Security considerations
Clients may not wish to inform everyone in a room that they are typing
and instead only specific users in the room.

@ -0,0 +1,87 @@
---
type: module
weight: 20
---
### Voice over IP
This module outlines how two users in a room can set up a Voice over IP
(VoIP) call to each other. Voice and video calls are built upon the
WebRTC 1.0 standard. Call signalling is achieved by sending [message
events]() to the room. In this version of the spec, only two-party
communication is supported (e.g. between two peers, or between a peer
and a multi-point conferencing unit). This means that clients MUST only
send call events to rooms with exactly two participants.
#### Events
{{voip\_events}}
#### Client behaviour
A call is set up with message events exchanged as follows:
Caller Callee
[Place Call]
m.call.invite ----------->
m.call.candidate -------->
[..candidates..] -------->
[Answers call]
<--------------- m.call.answer
[Call is active and ongoing]
<--------------- m.call.hangup
Or a rejected call:
Caller Callee
m.call.invite ------------>
m.call.candidate --------->
[..candidates..] --------->
[Rejects call]
<-------------- m.call.hangup
Calls are negotiated according to the WebRTC specification.
##### Glare
"Glare" is a problem which occurs when two users call each other at
roughly the same time. This results in the call failing to set up as
there already is an incoming/outgoing call. A glare resolution algorithm
can be used to determine which call to hangup and which call to answer.
If both clients implement the same algorithm then they will both select
the same call and the call will be successfully connected.
As calls are "placed" to rooms rather than users, the glare resolution
algorithm outlined below is only considered for calls which are to the
same room. The algorithm is as follows:
- If an `m.call.invite` to a room is received whilst the client is
**preparing to send** an `m.call.invite` to the same room:
- the client should cancel its outgoing call and instead
automatically accept the incoming call on behalf of the user.
- If an `m.call.invite` to a room is received **after the client has
sent** an `m.call.invite` to the same room and is waiting for a
response:
- the client should perform a lexicographical comparison of the
call IDs of the two calls and use the *lesser* of the two calls,
aborting the greater. If the incoming call is the lesser, the
client should accept this call on behalf of the user.
The call setup should appear seamless to the user as if they had simply
placed a call and the other party had accepted. This means any media
stream that had been setup for use on a call should be transferred and
used for the call that replaces it.
#### Server behaviour
The homeserver MAY provide a TURN server which clients can use to
contact the remote party. The following HTTP API endpoints will be used
by clients in order to get information about the TURN server.
{{voip\_cs\_http\_api}}
#### Security considerations
Calls should only be placed to rooms with one other user in them. If
they are placed to group chat rooms it is possible that another user
will intercept and answer the call.

@ -0,0 +1,14 @@
{{/*
This template is used to embed module documentation in the client-server API spec.
It searches the site for pages of type "module", sorts them by weight, and
emits the page's rendered content.
*/}}
{{ $modules := where site.Pages "Type" "module" }}
{{ range $modules.ByWeight }}
{{ .Content }}
{{ end }}
Loading…
Cancel
Save