commit
7fed40ad04
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,376 @@
|
|||||||
|
---
|
||||||
|
title: "Application Service API"
|
||||||
|
weight: 30
|
||||||
|
type: docs
|
||||||
|
---
|
||||||
|
|
||||||
|
The Matrix client-server API and server-server APIs provide the means to
|
||||||
|
implement a consistent self-contained federated messaging fabric.
|
||||||
|
However, they provide limited means of implementing custom server-side
|
||||||
|
behaviour in Matrix (e.g. gateways, filters, extensible hooks etc). The
|
||||||
|
Application Service API (AS API) defines a standard API to allow such
|
||||||
|
extensible functionality to be implemented irrespective of the
|
||||||
|
underlying homeserver implementation.
|
||||||
|
|
||||||
|
## Application Services
|
||||||
|
|
||||||
|
Application services are passive and can only observe events from
|
||||||
|
homeserver. They can inject events into rooms they are participating in.
|
||||||
|
They cannot prevent events from being sent, nor can they modify the
|
||||||
|
content of the event being sent. In order to observe events from a
|
||||||
|
homeserver, the homeserver needs to be configured to pass certain types
|
||||||
|
of traffic to the application service. This is achieved by manually
|
||||||
|
configuring the homeserver with information about the application
|
||||||
|
service.
|
||||||
|
|
||||||
|
### Registration
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
Previously, application services could register with a homeserver via
|
||||||
|
HTTP APIs. This was removed as it was seen as a security risk. A
|
||||||
|
compromised application service could re-register for a global `*` regex
|
||||||
|
and sniff *all* traffic on the homeserver. To protect against this,
|
||||||
|
application services now have to register via configuration files which
|
||||||
|
are linked to the homeserver configuration file. The addition of
|
||||||
|
configuration files allows homeserver admins to sanity check the
|
||||||
|
registration for suspicious regex strings.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
Application services register "namespaces" of user IDs, room aliases and
|
||||||
|
room IDs. These namespaces are represented as regular expressions. An
|
||||||
|
application service is said to be "interested" in a given event if one
|
||||||
|
of the IDs in the event match the regular expression provided by the
|
||||||
|
application service, such as the room having an alias or ID in the
|
||||||
|
relevant namespaces. Similarly, the application service is said to be
|
||||||
|
interested in a given event if one of the application service's
|
||||||
|
namespaced users is the target of the event, or is a joined member of
|
||||||
|
the room where the event occurred.
|
||||||
|
|
||||||
|
An application service can also state whether they should be the only
|
||||||
|
ones who can manage a specified namespace. This is referred to as an
|
||||||
|
"exclusive" namespace. An exclusive namespace prevents humans and other
|
||||||
|
application services from creating/deleting entities in that namespace.
|
||||||
|
Typically, exclusive namespaces are used when the rooms represent real
|
||||||
|
rooms on another service (e.g. IRC). Non-exclusive namespaces are used
|
||||||
|
when the application service is merely augmenting the room itself (e.g.
|
||||||
|
providing logging or searching facilities). Namespaces are represented
|
||||||
|
by POSIX extended regular expressions and look like:
|
||||||
|
|
||||||
|
users:
|
||||||
|
- exclusive: true
|
||||||
|
regex: "@_irc_bridge_.*"
|
||||||
|
|
||||||
|
Application services may define the following namespaces (with none
|
||||||
|
being explicitly required):
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
|----------|------------------------------------------------------------|
|
||||||
|
| users | Events which are sent from certain users. |
|
||||||
|
| aliases | Events which are sent in rooms with certain room aliases. |
|
||||||
|
| rooms | Events which are sent in rooms with certain room IDs. |
|
||||||
|
|
||||||
|
Each individual namespace MUST declare the following fields:
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
|------------|------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| exclusive | **Required** A true or false value stating whether this application service has exclusive access to events within this namespace. |
|
||||||
|
| regex | **Required** A regular expression defining which values this namespace includes. |
|
||||||
|
|
||||||
|
Exclusive user and alias namespaces should begin with an underscore
|
||||||
|
after the sigil to avoid collisions with other users on the homeserver.
|
||||||
|
Application services should additionally attempt to identify the service
|
||||||
|
they represent in the reserved namespace. For example, `@_irc_.*` would
|
||||||
|
be a good namespace to register for an application service which deals
|
||||||
|
with IRC.
|
||||||
|
|
||||||
|
The registration is represented by a series of key-value pairs, which
|
||||||
|
this specification will present as YAML. See below for the possible
|
||||||
|
options along with their explanation:
|
||||||
|
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| id | **Required** A unique, user-defined ID of the application service which will never change. |
|
||||||
|
| url | **Required** The URL for the application service. May include a path after the domain name. Optionally set to null if no traffic is required. |
|
||||||
|
| as_token | **Required** A unique token for application services to use to authenticate requests to Homeservers. |
|
||||||
|
| hs_token | **Required** A unique token for Homeservers to use to authenticate requests to application services. |
|
||||||
|
| sender_localpart | **Required** The localpart of the user associated with the application service. |
|
||||||
|
| namespaces | **Required** A list of `users`, `aliases` and `rooms` namespaces that the application service controls. |
|
||||||
|
| rate_limited | Whether requests from masqueraded users are rate-limited. The sender is excluded. |
|
||||||
|
| protocols | The external protocols which the application service provides (e.g. IRC). |
|
||||||
|
|
||||||
|
An example registration file for an IRC-bridging application service is
|
||||||
|
below:
|
||||||
|
|
||||||
|
id: "IRC Bridge"
|
||||||
|
url: "http://127.0.0.1:1234"
|
||||||
|
as_token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46"
|
||||||
|
hs_token: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e"
|
||||||
|
sender_localpart: "_irc_bot" # Will result in @_irc_bot:example.org
|
||||||
|
namespaces:
|
||||||
|
users:
|
||||||
|
- exclusive: true
|
||||||
|
regex: "@_irc_bridge_.*"
|
||||||
|
aliases:
|
||||||
|
- exclusive: false
|
||||||
|
regex: "#_irc_bridge_.*"
|
||||||
|
rooms: []
|
||||||
|
|
||||||
|
{{% boxes/warning %}}
|
||||||
|
If the homeserver in question has multiple application services, each
|
||||||
|
`as_token` and `id` MUST be unique per application service as these are
|
||||||
|
used to identify the application service. The homeserver MUST enforce
|
||||||
|
this.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
|
### Homeserver -> Application Service API
|
||||||
|
|
||||||
|
#### Authorization
|
||||||
|
|
||||||
|
Homeservers MUST include a query parameter named `access_token`
|
||||||
|
containing the `hs_token` from the application service's registration
|
||||||
|
when making requests to the application service. Application services
|
||||||
|
MUST verify the provided `access_token` matches their known `hs_token`,
|
||||||
|
failing the request with an `M_FORBIDDEN` error if it does not match.
|
||||||
|
|
||||||
|
#### Legacy routes
|
||||||
|
|
||||||
|
Previous drafts of the application service specification had a mix of
|
||||||
|
endpoints that have been used in the wild for a significant amount of
|
||||||
|
time. The application service specification now defines a version on all
|
||||||
|
endpoints to be more compatible with the rest of the Matrix
|
||||||
|
specification and the future.
|
||||||
|
|
||||||
|
Homeservers should attempt to use the specified endpoints first when
|
||||||
|
communicating with application services. However, if the application
|
||||||
|
service receives an HTTP status code that does not indicate success
|
||||||
|
(i.e.: 404, 500, 501, etc) then the homeserver should fall back to the
|
||||||
|
older endpoints for the application service.
|
||||||
|
|
||||||
|
The older endpoints have the exact same request body and response
|
||||||
|
format, they just belong at a different path. The equivalent path for
|
||||||
|
each is as follows:
|
||||||
|
|
||||||
|
- `/_matrix/app/v1/transactions/{txnId}` should fall back to
|
||||||
|
`/transactions/{txnId}`
|
||||||
|
- `/_matrix/app/v1/users/{userId}` should fall back to
|
||||||
|
`/users/{userId}`
|
||||||
|
- `/_matrix/app/v1/rooms/{roomAlias}` should fall back to
|
||||||
|
`/rooms/{roomAlias}`
|
||||||
|
- `/_matrix/app/v1/thirdparty/protocol/{protocol}` should fall back to
|
||||||
|
`/_matrix/app/unstable/thirdparty/protocol/{protocol}`
|
||||||
|
- `/_matrix/app/v1/thirdparty/user/{user}` should fall back to
|
||||||
|
`/_matrix/app/unstable/thirdparty/user/{user}`
|
||||||
|
- `/_matrix/app/v1/thirdparty/location/{location}` should fall back to
|
||||||
|
`/_matrix/app/unstable/thirdparty/location/{location}`
|
||||||
|
- `/_matrix/app/v1/thirdparty/user` should fall back to
|
||||||
|
`/_matrix/app/unstable/thirdparty/user`
|
||||||
|
- `/_matrix/app/v1/thirdparty/location` should fall back to
|
||||||
|
`/_matrix/app/unstable/thirdparty/location`
|
||||||
|
|
||||||
|
Homeservers should periodically try again for the newer endpoints
|
||||||
|
because the application service may have been updated.
|
||||||
|
|
||||||
|
#### Pushing events
|
||||||
|
|
||||||
|
The application service API provides a transaction API for sending a
|
||||||
|
list of events. Each list of events includes a transaction ID, which
|
||||||
|
works as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
Typical
|
||||||
|
HS ---> AS : Homeserver sends events with transaction ID T.
|
||||||
|
<--- : Application Service sends back 200 OK.
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
AS ACK Lost
|
||||||
|
HS ---> AS : Homeserver sends events with transaction ID T.
|
||||||
|
<-/- : AS 200 OK is lost.
|
||||||
|
HS ---> AS : Homeserver retries with the same transaction ID of T.
|
||||||
|
<--- : Application Service sends back 200 OK. If the AS had processed these
|
||||||
|
events already, it can NO-OP this request (and it knows if it is the
|
||||||
|
same events based on the transaction ID).
|
||||||
|
```
|
||||||
|
|
||||||
|
The events sent to the application service should be linearised, as if
|
||||||
|
they were from the event stream. The homeserver MUST maintain a queue of
|
||||||
|
transactions to send to the application service. If the application
|
||||||
|
service cannot be reached, the homeserver SHOULD backoff exponentially
|
||||||
|
until the application service is reachable again. As application
|
||||||
|
services cannot *modify* the events in any way, these requests can be
|
||||||
|
made without blocking other aspects of the homeserver. Homeservers MUST
|
||||||
|
NOT alter (e.g. add more) events they were going to send within that
|
||||||
|
transaction ID on retries, as the application service may have already
|
||||||
|
processed the events.
|
||||||
|
|
||||||
|
{{transactions\_as\_http\_api}}
|
||||||
|
|
||||||
|
#### Querying
|
||||||
|
|
||||||
|
The application service API includes two querying APIs: for room aliases
|
||||||
|
and for user IDs. The application service SHOULD create the queried
|
||||||
|
entity if it desires. During this process, the application service is
|
||||||
|
blocking the homeserver until the entity is created and configured. If
|
||||||
|
the homeserver does not receive a response to this request, the
|
||||||
|
homeserver should retry several times before timing out. This should
|
||||||
|
result in an HTTP status 408 "Request Timeout" on the client which
|
||||||
|
initiated this request (e.g. to join a room alias).
|
||||||
|
|
||||||
|
{{% boxes/rationale %}}
|
||||||
|
Blocking the homeserver and expecting the application service to create
|
||||||
|
the entity using the client-server API is simpler and more flexible than
|
||||||
|
alternative methods such as returning an initial sync style JSON blob
|
||||||
|
and get the HS to provision the room/user. This also meant that there
|
||||||
|
didn't need to be a "backchannel" to inform the application service
|
||||||
|
about information about the entity such as room ID to room alias
|
||||||
|
mappings.
|
||||||
|
{{% /boxes/rationale %}}
|
||||||
|
|
||||||
|
{{query\_user\_as\_http\_api}}
|
||||||
|
|
||||||
|
{{query\_room\_as\_http\_api}}
|
||||||
|
|
||||||
|
#### Third party networks
|
||||||
|
|
||||||
|
Application services may declare which protocols they support via their
|
||||||
|
registration configuration for the homeserver. These networks are
|
||||||
|
generally for third party services such as IRC that the application
|
||||||
|
service is managing. Application services may populate a Matrix room
|
||||||
|
directory for their registered protocols, as defined in the
|
||||||
|
Client-Server API Extensions.
|
||||||
|
|
||||||
|
Each protocol may have several "locations" (also known as "third party
|
||||||
|
locations" or "3PLs"). A location within a protocol is a place in the
|
||||||
|
third party network, such as an IRC channel. Users of the third party
|
||||||
|
network may also be represented by the application service.
|
||||||
|
|
||||||
|
Locations and users can be searched by fields defined by the application
|
||||||
|
service, such as by display name or other attribute. When clients
|
||||||
|
request the homeserver to search in a particular "network" (protocol),
|
||||||
|
the search fields will be passed along to the application service for
|
||||||
|
filtering.
|
||||||
|
|
||||||
|
{{protocols\_as\_http\_api}}
|
||||||
|
|
||||||
|
### Client-Server API Extensions
|
||||||
|
|
||||||
|
Application services can use a more powerful version of the
|
||||||
|
client-server API by identifying itself as an application service to the
|
||||||
|
homeserver.
|
||||||
|
|
||||||
|
Endpoints defined in this section MUST be supported by homeservers in
|
||||||
|
the client-server API as accessible only by application services.
|
||||||
|
|
||||||
|
#### Identity assertion
|
||||||
|
|
||||||
|
The client-server API infers the user ID from the `access_token`
|
||||||
|
provided in every request. To avoid the application service from having
|
||||||
|
to keep track of each user's access token, the application service
|
||||||
|
should identify itself to the Client-Server API by providing its
|
||||||
|
`as_token` for the `access_token` alongside the user the application
|
||||||
|
service would like to masquerade as.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- Application service token (`as_token`)
|
||||||
|
- User ID in the AS namespace to act as.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- This applies to all aspects of the Client-Server API, except for
|
||||||
|
Account Management.
|
||||||
|
- The `as_token` is inserted into `access_token` which is usually
|
||||||
|
where the client token is, such as via the query string or
|
||||||
|
`Authorization` header. This is done on purpose to allow application
|
||||||
|
services to reuse client SDKs.
|
||||||
|
- The `access_token` should be supplied through the `Authorization`
|
||||||
|
header where possible to prevent the token appearing in HTTP request
|
||||||
|
logs by accident.
|
||||||
|
|
||||||
|
The application service may specify the virtual user to act as through
|
||||||
|
use of a `user_id` query string parameter on the request. The user
|
||||||
|
specified in the query string must be covered by one of the application
|
||||||
|
service's `user` namespaces. If the parameter is missing, the homeserver
|
||||||
|
is to assume the application service intends to act as the user implied
|
||||||
|
by the `sender_localpart` property of the registration.
|
||||||
|
|
||||||
|
An example request would be:
|
||||||
|
|
||||||
|
GET /_matrix/client/%CLIENT_MAJOR_VERSION%/account/whoami?user_id=@_irc_user:example.org
|
||||||
|
Authorization: Bearer YourApplicationServiceTokenHere
|
||||||
|
|
||||||
|
#### Timestamp massaging
|
||||||
|
|
||||||
|
Previous drafts of the Application Service API permitted application
|
||||||
|
services to alter the timestamp of their sent events by providing a `ts`
|
||||||
|
query parameter when sending an event. This API has been excluded from
|
||||||
|
the first release due to design concerns, however some servers may still
|
||||||
|
support the feature. Please visit [issue
|
||||||
|
\#1585](https://github.com/matrix-org/matrix-doc/issues/1585) for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
#### Server admin style permissions
|
||||||
|
|
||||||
|
The homeserver needs to give the application service *full control* over
|
||||||
|
its namespace, both for users and for room aliases. This means that the
|
||||||
|
AS should be able to create/edit/delete any room alias in its namespace,
|
||||||
|
as well as create/delete any user in its namespace. No additional API
|
||||||
|
changes need to be made in order for control of room aliases to be
|
||||||
|
granted to the AS. Creation of users needs API changes in order to:
|
||||||
|
|
||||||
|
- Work around captchas.
|
||||||
|
- Have a 'passwordless' user.
|
||||||
|
|
||||||
|
This involves bypassing the registration flows entirely. This is
|
||||||
|
achieved by including the `as_token` on a `/register` request, along
|
||||||
|
with a login type of `m.login.application_service` to set the desired
|
||||||
|
user ID without a password.
|
||||||
|
|
||||||
|
POST /_matrix/client/%CLIENT_MAJOR_VERSION%/register
|
||||||
|
Authorization: Bearer YourApplicationServiceTokenHere
|
||||||
|
|
||||||
|
Content:
|
||||||
|
{
|
||||||
|
type: "m.login.application_service",
|
||||||
|
username: "_irc_example"
|
||||||
|
}
|
||||||
|
|
||||||
|
Application services which attempt to create users or aliases *outside*
|
||||||
|
of their defined namespaces will receive an error code `M_EXCLUSIVE`.
|
||||||
|
Similarly, normal users who attempt to create users or aliases *inside*
|
||||||
|
an application service-defined namespace will receive the same
|
||||||
|
`M_EXCLUSIVE` error code, but only if the application service has
|
||||||
|
defined the namespace as `exclusive`.
|
||||||
|
|
||||||
|
#### Using `/sync` and `/events`
|
||||||
|
|
||||||
|
Application services wishing to use `/sync` or `/events` from the
|
||||||
|
Client-Server API MUST do so with a virtual user (provide a `user_id`
|
||||||
|
via the query string). It is expected that the application service use
|
||||||
|
the transactions pushed to it to handle events rather than syncing with
|
||||||
|
the user implied by `sender_localpart`.
|
||||||
|
|
||||||
|
#### Application service room directories
|
||||||
|
|
||||||
|
Application services can maintain their own room directories for their
|
||||||
|
defined third party protocols. These room directories may be accessed by
|
||||||
|
clients through additional parameters on the `/publicRooms`
|
||||||
|
client-server endpoint.
|
||||||
|
|
||||||
|
{{appservice\_room\_directory\_cs\_http\_api}}
|
||||||
|
|
||||||
|
### Referencing messages from a third party network
|
||||||
|
|
||||||
|
Application services should include an `external_url` in the `content`
|
||||||
|
of events it emits to indicate where the message came from. This
|
||||||
|
typically applies to application services that bridge other networks
|
||||||
|
into Matrix, such as IRC, where an HTTP URL may be available to
|
||||||
|
reference.
|
||||||
|
|
||||||
|
Clients should provide users with a way to access the `external_url` if
|
||||||
|
it is present. Clients should additionally ensure the URL has a scheme
|
||||||
|
of `https` or `http` before making use of it.
|
||||||
|
|
||||||
|
The presence of an `external_url` on an event does not necessarily mean
|
||||||
|
the event was sent from an application service. Clients should be wary
|
||||||
|
of the URL contained within, as it may not be a legitimate reference to
|
||||||
|
the event's source.
|
File diff suppressed because it is too large
Load Diff
@ -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](#mfully_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](/#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](#mroommember) 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,91 @@
|
|||||||
|
---
|
||||||
|
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_matrixclientr0register),
|
||||||
|
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_matrixclientr0roomsroomidstate)
|
||||||
|
- [GET /rooms/:room\_id/context/:event\_id](#get_matrixclientr0roomsroomidcontexteventid)
|
||||||
|
- [GET /rooms/:room\_id/event/:event\_id](#get_matrixclientr0roomsroomideventeventid)
|
||||||
|
- [GET /rooms/:room\_id/state/:event\_type/:state\_key](#get_matrixclientr0roomsroomidstateeventtypestatekey)
|
||||||
|
- [GET /rooms/:room\_id/messages](#get_matrixclientr0roomsroomidmessages)
|
||||||
|
- [GET /rooms/:room\_id/members](#get_matrixclientr0roomsroomidmembers)
|
||||||
|
- [GET /rooms/:room\_id/initialSync](#get_matrixclientr0roomsroomidinitialsync)
|
||||||
|
- [GET /sync](#get_matrixclientr0sync)
|
||||||
|
- [GET /events](#get_matrixclientr0events) 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_matrixclientr0roomsroomidjoin)
|
||||||
|
- [POST /rooms/:room\_id/leave](#post_matrixclientr0roomsroomidleave)
|
||||||
|
- [PUT /rooms/:room\_id/send/m.room.message/:txn\_id](#put_matrixclientr0roomsroomidsendeventtypetxnid)
|
||||||
|
- [PUT /sendToDevice/{eventType}/{txnId}](#put_matrixclientr0sendtodeviceeventtypetxnid)
|
||||||
|
|
||||||
|
The following API endpoints are allowed to be accessed by guest accounts
|
||||||
|
for their own account maintenance:
|
||||||
|
|
||||||
|
- [PUT /profile/:user\_id/displayname](#put_matrixclientr0profileuseriddisplayname)
|
||||||
|
- [GET /devices](#get_matrixclientr0devices)
|
||||||
|
- [GET /devices/{deviceId}](#get_matrixclientr0devicesdeviceid)
|
||||||
|
- [PUT /devices/{deviceId}](#put_matrixclientr0devicesdeviceid)
|
||||||
|
|
||||||
|
The following API endpoints are allowed to be accessed by guest accounts
|
||||||
|
for end-to-end encryption:
|
||||||
|
|
||||||
|
- [POST /keys/upload](#post_matrixclientr0keysupload)
|
||||||
|
- [POST /keys/query](#post_matrixclientr0keysquery)
|
||||||
|
- [POST /keys/claim](#post_matrixclientr0keysclaim)
|
||||||
|
|
||||||
|
#### 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`.
|
||||||
|
|
||||||
|
{{% boxes/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.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
|
#### 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,485 @@
|
|||||||
|
---
|
||||||
|
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](#receipts).
|
||||||
|
- 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](#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](#matrix-content-mxc-uris))
|
||||||
|
|
||||||
|
`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.
|
||||||
|
|
||||||
|
{{% boxes/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).
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
{{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](#content-repository)
|
||||||
|
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](#content-repository).
|
||||||
|
|
||||||
|
##### 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](#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](#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](#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#matrixto-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 ("> ", 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](#end-to-end-encryption)).
|
||||||
|
|
||||||
|
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,60 @@
|
|||||||
|
---
|
||||||
|
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/#matrixto-navigation) in the HTML body of an
|
||||||
|
[m.room.message](#mroommessage) event. This module does not have any server-specific
|
||||||
|
behaviour to it.
|
||||||
|
|
||||||
|
Mentions apply only to [m.room.message](#mroommessage) 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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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,748 @@
|
|||||||
|
---
|
||||||
|
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](#mroompower_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
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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,89 @@
|
|||||||
|
---
|
||||||
|
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](#guest-access).
|
||||||
|
|
||||||
|
Previews are implemented via the `world_readable` [Room History
|
||||||
|
Visibility](#room-history-visibility). setting, along with a special version of the [GET
|
||||||
|
/events](#get_matrixclientr0events) endpoint.
|
||||||
|
|
||||||
|
#### Client behaviour
|
||||||
|
|
||||||
|
A client wishing to view a room without joining it should call [GET
|
||||||
|
/rooms/:room\_id/initialSync](#get_matrixclientr0roomsroomidinitialsync),
|
||||||
|
followed by [GET /events](#get_matrixclientr0events). 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_matrixclientr0roomsroomidmessages)
|
||||||
|
and [GET /search](#post_matrixclientr0search) 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,98 @@
|
|||||||
|
---
|
||||||
|
type: module
|
||||||
|
weight: 80
|
||||||
|
---
|
||||||
|
|
||||||
|
### Send-to-Device messaging
|
||||||
|
|
||||||
|
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-api#send-to-device-messaging).
|
||||||
|
|
||||||
|
#### Protocol definitions
|
||||||
|
|
||||||
|
{{to\_device\_cs\_http\_api}}
|
||||||
|
|
||||||
|
##### Extensions to /sync
|
||||||
|
|
||||||
|
This module adds the following properties to the \_ response:
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|-----------|-----------------------------------------------------------------------------|
|
||||||
|
| to_device | ToDevice | Optional. Information on the send-to-device messages for the client device. |
|
||||||
|
|
||||||
|
`ToDevice`
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-----------|-----------|----------------------------------|
|
||||||
|
| events | [Event] | List of send-to-device messages. |
|
||||||
|
|
||||||
|
`Event`
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|------------|--------------|-------------------------------------------------------------------------------------------------|
|
||||||
|
| content | EventContent | The content of this event. The fields in this object will vary depending on the type of event. |
|
||||||
|
| sender | string | The Matrix user ID of the user who sent this event. |
|
||||||
|
| type | string | The type of event. |
|
||||||
|
|
||||||
|
Example response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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](#mroomserver_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](#mroomcreate) event.
|
||||||
|
|
||||||
|
{{m\_room\_server\_acl\_event}}
|
||||||
|
|
||||||
|
{{% boxes/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.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
{{% boxes/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.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
#### 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](#mroomserver_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](#mroompinned_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,311 @@
|
|||||||
|
---
|
||||||
|
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](#login) and [user-interactive authentication](#user-interactive-authentication-api). 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-------------| |
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% boxes/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.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
##### 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#user-identifiers). The guidance in
|
||||||
|
[Mapping from other character
|
||||||
|
sets](/appendices#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](#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](#user-interactive-authentication-api) 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](#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](#fallback) 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](#mimage) 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](#server-notices).
|
||||||
|
|
||||||
|
{{m\_tag\_event}}
|
||||||
|
|
||||||
|
#### Client Behaviour
|
||||||
|
|
||||||
|
{{tags\_cs\_http\_api}}
|
@ -0,0 +1,241 @@
|
|||||||
|
---
|
||||||
|
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](#mroommember) 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-api/#get_matrixidentityv2pubkeyisvalid)
|
||||||
|
endpoint, using the provided URL rather than constructing a new one. The
|
||||||
|
query string and response for the provided URL must match the Identity
|
||||||
|
Service Specification.
|
||||||
|
|
||||||
|
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,91 @@
|
|||||||
|
---
|
||||||
|
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](#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,443 @@
|
|||||||
|
---
|
||||||
|
title: "Identity Service API"
|
||||||
|
weight: 40
|
||||||
|
type: docs
|
||||||
|
---
|
||||||
|
|
||||||
|
The Matrix client-server and server-server APIs are largely expressed in
|
||||||
|
Matrix user identifiers. From time to time, it is useful to refer to
|
||||||
|
users by other ("third-party") identifiers, or "3PID"s, e.g. their email
|
||||||
|
address or phone number. This Identity Service Specification describes
|
||||||
|
how mappings between third-party identifiers and Matrix user identifiers
|
||||||
|
can be established, validated, and used. This description technically
|
||||||
|
may apply to any 3PID, but in practice has only been applied
|
||||||
|
specifically to email addresses and phone numbers.
|
||||||
|
|
||||||
|
## General principles
|
||||||
|
|
||||||
|
The purpose of an identity server is to validate, store, and answer
|
||||||
|
questions about the identities of users. In particular, it stores
|
||||||
|
associations of the form "identifier X represents the same user as
|
||||||
|
identifier Y", where identities may exist on different systems (such as
|
||||||
|
email addresses, phone numbers, Matrix user IDs, etc).
|
||||||
|
|
||||||
|
The identity server has some private-public keypairs. When asked about
|
||||||
|
an association, it will sign details of the association with its private
|
||||||
|
key. Clients may validate the assertions about associations by verifying
|
||||||
|
the signature with the public key of the identity server.
|
||||||
|
|
||||||
|
In general, identity servers are treated as reliable oracles. They do
|
||||||
|
not necessarily provide evidence that they have validated associations,
|
||||||
|
but claim to have done so. Establishing the trustworthiness of an
|
||||||
|
individual identity server is left as an exercise for the client.
|
||||||
|
|
||||||
|
3PID types are described in [3PID Types](/appendices#pid-types)
|
||||||
|
Appendix.
|
||||||
|
|
||||||
|
## API standards
|
||||||
|
|
||||||
|
The mandatory baseline for identity server communication in Matrix is
|
||||||
|
exchanging JSON objects over HTTP APIs. HTTPS is required for
|
||||||
|
communication, and all API calls use a Content-Type of
|
||||||
|
`application/json`. In addition, strings MUST be encoded as UTF-8.
|
||||||
|
|
||||||
|
Any errors which occur at the Matrix API level MUST return a "standard
|
||||||
|
error response". This is a JSON object which looks like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"errcode": "<error code>",
|
||||||
|
"error": "<error message>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `error` string will be a human-readable error message, usually a
|
||||||
|
sentence explaining what went wrong. The `errcode` string will be a
|
||||||
|
unique string which can be used to handle an error message e.g.
|
||||||
|
`M_FORBIDDEN`. There may be additional keys depending on the error, but
|
||||||
|
the keys `error` and `errcode` MUST always be present.
|
||||||
|
|
||||||
|
Some standard error codes are below:
|
||||||
|
|
||||||
|
`M_NOT_FOUND`
|
||||||
|
The resource requested could not be located.
|
||||||
|
|
||||||
|
`M_MISSING_PARAMS`
|
||||||
|
The request was missing one or more parameters.
|
||||||
|
|
||||||
|
`M_INVALID_PARAM`
|
||||||
|
The request contained one or more invalid parameters.
|
||||||
|
|
||||||
|
`M_SESSION_NOT_VALIDATED`
|
||||||
|
The session has not been validated.
|
||||||
|
|
||||||
|
`M_NO_VALID_SESSION`
|
||||||
|
A session could not be located for the given parameters.
|
||||||
|
|
||||||
|
`M_SESSION_EXPIRED`
|
||||||
|
The session has expired and must be renewed.
|
||||||
|
|
||||||
|
`M_INVALID_EMAIL`
|
||||||
|
The email address provided was not valid.
|
||||||
|
|
||||||
|
`M_EMAIL_SEND_ERROR`
|
||||||
|
There was an error sending an email. Typically seen when attempting to
|
||||||
|
verify ownership of a given email address.
|
||||||
|
|
||||||
|
`M_INVALID_ADDRESS`
|
||||||
|
The provided third party address was not valid.
|
||||||
|
|
||||||
|
`M_SEND_ERROR`
|
||||||
|
There was an error sending a notification. Typically seen when
|
||||||
|
attempting to verify ownership of a given third party address.
|
||||||
|
|
||||||
|
`M_UNRECOGNIZED`
|
||||||
|
The request contained an unrecognised value, such as an unknown token or
|
||||||
|
medium.
|
||||||
|
|
||||||
|
`M_THREEPID_IN_USE`
|
||||||
|
The third party identifier is already in use by another user. Typically
|
||||||
|
this error will have an additional `mxid` property to indicate who owns
|
||||||
|
the third party identifier.
|
||||||
|
|
||||||
|
`M_UNKNOWN`
|
||||||
|
An unknown error has occurred.
|
||||||
|
|
||||||
|
## Privacy
|
||||||
|
|
||||||
|
Identity is a privacy-sensitive issue. While the identity server exists
|
||||||
|
to provide identity information, access should be restricted to avoid
|
||||||
|
leaking potentially sensitive data. In particular, being able to
|
||||||
|
construct large-scale connections between identities should be avoided.
|
||||||
|
To this end, in general APIs should allow a 3PID to be mapped to a
|
||||||
|
Matrix user identity, but not in the other direction (i.e. one should
|
||||||
|
not be able to get all 3PIDs associated with a Matrix user ID, or get
|
||||||
|
all 3PIDs associated with a 3PID).
|
||||||
|
|
||||||
|
## Version 1 API deprecation
|
||||||
|
|
||||||
|
As described on each of the version 1 endpoints, the v1 API is
|
||||||
|
deprecated in favour of the v2 API described here. The major difference,
|
||||||
|
with the exception of a few isolated cases, is that the v2 API requires
|
||||||
|
authentication to ensure the user has given permission for the identity
|
||||||
|
server to operate on their data.
|
||||||
|
|
||||||
|
The v1 API is planned to be removed from the specification in a future
|
||||||
|
version.
|
||||||
|
|
||||||
|
Clients SHOULD attempt the v2 endpoints first, and if they receive a
|
||||||
|
`404`, `400`, or similar error they should try the v1 endpoint or fail
|
||||||
|
the operation. Clients are strongly encouraged to warn the user of the
|
||||||
|
risks in using the v1 API, if they are planning on using it.
|
||||||
|
|
||||||
|
## Web browser clients
|
||||||
|
|
||||||
|
It is realistic to expect that some clients will be written to be run
|
||||||
|
within a web browser or similar environment. In these cases, the
|
||||||
|
identity server should respond to pre-flight requests and supply
|
||||||
|
Cross-Origin Resource Sharing (CORS) headers on all requests.
|
||||||
|
|
||||||
|
When a client approaches the server with a pre-flight (OPTIONS) request,
|
||||||
|
the server should respond with the CORS headers for that route. The
|
||||||
|
recommended CORS headers to be returned by servers on all requests are:
|
||||||
|
|
||||||
|
Access-Control-Allow-Origin: *
|
||||||
|
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
|
||||||
|
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Most `v2` endpoints in the Identity Service API require authentication
|
||||||
|
in order to ensure that the requesting user has accepted all relevant
|
||||||
|
policies and is otherwise permitted to make the request. The `v1` API
|
||||||
|
(currently deprecated) does not require this authentication, however
|
||||||
|
using `v1` is strongly discouraged as it will be removed in a future
|
||||||
|
release.
|
||||||
|
|
||||||
|
Identity Servers use a scheme similar to the Client-Server API's concept
|
||||||
|
of access tokens to authenticate users. The access tokens provided by an
|
||||||
|
Identity Server cannot be used to authenticate Client-Server API
|
||||||
|
requests.
|
||||||
|
|
||||||
|
An access token is provided to an endpoint in one of two ways:
|
||||||
|
|
||||||
|
1. Via a query string parameter, `access_token=TheTokenHere`.
|
||||||
|
2. Via a request header, `Authorization: Bearer TheTokenHere`.
|
||||||
|
|
||||||
|
Clients are encouraged to the use the `Authorization` header where
|
||||||
|
possible to prevent the access token being leaked in access/HTTP logs.
|
||||||
|
The query string should only be used in cases where the `Authorization`
|
||||||
|
header is inaccessible for the client.
|
||||||
|
|
||||||
|
When credentials are required but missing or invalid, the HTTP call will
|
||||||
|
return with a status of 401 and the error code `M_UNAUTHORIZED`.
|
||||||
|
|
||||||
|
{{v2\_auth\_is\_http\_api}}
|
||||||
|
|
||||||
|
## Terms of service
|
||||||
|
|
||||||
|
Identity Servers are encouraged to have terms of service (or similar
|
||||||
|
policies) to ensure that users have agreed to their data being processed
|
||||||
|
by the server. To facilitate this, an identity server can respond to
|
||||||
|
almost any authenticated API endpoint with an HTTP 403 and the error
|
||||||
|
code `M_TERMS_NOT_SIGNED`. The error code is used to indicate that the
|
||||||
|
user must accept new terms of service before being able to continue.
|
||||||
|
|
||||||
|
All endpoints which support authentication can return the
|
||||||
|
`M_TERMS_NOT_SIGNED` error. When clients receive the error, they are
|
||||||
|
expected to make a call to `GET /terms` to find out what terms the
|
||||||
|
server offers. The client compares this to the `m.accepted_terms`
|
||||||
|
account data for the user (described later) and presents the user with
|
||||||
|
option to accept the still-missing terms of service. After the user has
|
||||||
|
made their selection, if applicable, the client sends a request to
|
||||||
|
`POST /terms` to indicate the user's acceptance. The server cannot
|
||||||
|
expect that the client will send acceptance for all pending terms, and
|
||||||
|
the client should not expect that the server will not respond with
|
||||||
|
another `M_TERMS_NOT_SIGNED` on their next request. The terms the user
|
||||||
|
has just accepted are appended to `m.accepted_terms`.
|
||||||
|
|
||||||
|
{{m\_accepted\_terms\_event}}
|
||||||
|
|
||||||
|
{{v2\_terms\_is\_http\_api}}
|
||||||
|
|
||||||
|
## Status check
|
||||||
|
|
||||||
|
{{ping\_is\_http\_api}}
|
||||||
|
|
||||||
|
{{v2\_ping\_is\_http\_api}}
|
||||||
|
|
||||||
|
## Key management
|
||||||
|
|
||||||
|
An identity server has some long-term public-private keypairs. These are
|
||||||
|
named in a scheme `algorithm:identifier`, e.g. `ed25519:0`. When signing
|
||||||
|
an association, the standard [Signing
|
||||||
|
JSON](/appendices#signing-json) algorithm applies.
|
||||||
|
|
||||||
|
The identity server may also keep track of some short-term
|
||||||
|
public-private keypairs, which may have different usage and lifetime
|
||||||
|
characteristics than the service's long-term keys.
|
||||||
|
|
||||||
|
{{pubkey\_is\_http\_api}}
|
||||||
|
|
||||||
|
{{v2\_pubkey\_is\_http\_api}}
|
||||||
|
|
||||||
|
## Association lookup
|
||||||
|
|
||||||
|
{{lookup\_is\_http\_api}}
|
||||||
|
|
||||||
|
{{v2\_lookup\_is\_http\_api}}
|
||||||
|
|
||||||
|
### Client behaviour
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
This section only covers the v2 lookup endpoint. The v1 endpoint is
|
||||||
|
described in isolation above.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
Prior to performing a lookup clients SHOULD make a request to the
|
||||||
|
`/hash_details` endpoint to determine what algorithms the server
|
||||||
|
supports (described in more detail below). The client then uses this
|
||||||
|
information to form a `/lookup` request and receive known bindings from
|
||||||
|
the server.
|
||||||
|
|
||||||
|
Clients MUST support at least the `sha256` algorithm.
|
||||||
|
|
||||||
|
### Server behaviour
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
This section only covers the v2 lookup endpoint. The v1 endpoint is
|
||||||
|
described in isolation above.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
Servers, upon receipt of a `/lookup` request, will compare the query
|
||||||
|
against known bindings it has, hashing the identifiers it knows about as
|
||||||
|
needed to verify exact matches to the request.
|
||||||
|
|
||||||
|
Servers MUST support at least the `sha256` algorithm.
|
||||||
|
|
||||||
|
### Algorithms
|
||||||
|
|
||||||
|
Some algorithms are defined as part of the specification, however other
|
||||||
|
formats can be negotiated between the client and server using
|
||||||
|
`/hash_details`.
|
||||||
|
|
||||||
|
#### `sha256`
|
||||||
|
|
||||||
|
This algorithm MUST be supported by clients and servers at a minimum. It
|
||||||
|
is additionally the preferred algorithm for lookups.
|
||||||
|
|
||||||
|
When using this algorithm, the client converts the query first into
|
||||||
|
strings separated by spaces in the format `<address> <medium> <pepper>`.
|
||||||
|
The `<pepper>` is retrieved from `/hash_details`, the `<medium>` is
|
||||||
|
typically `email` or `msisdn` (both lowercase), and the `<address>` is
|
||||||
|
the 3PID to search for. For example, if the client wanted to know about
|
||||||
|
`alice@example.org`'s bindings, it would first format the query as
|
||||||
|
`alice@example.org email ThePepperGoesHere`.
|
||||||
|
|
||||||
|
{{% boxes/rationale %}}
|
||||||
|
Mediums and peppers are appended to the address to prevent a common
|
||||||
|
prefix for each 3PID, helping prevent attackers from pre-computing the
|
||||||
|
internal state of the hash function.
|
||||||
|
{{% /boxes/rationale %}}
|
||||||
|
|
||||||
|
After formatting each query, the string is run through SHA-256 as
|
||||||
|
defined by [RFC 4634](https://tools.ietf.org/html/rfc4634). The
|
||||||
|
resulting bytes are then encoded using URL-Safe [Unpadded
|
||||||
|
Base64](/appendices#unpadded-base64) (similar to [room version
|
||||||
|
4's event ID format](/rooms/v4#event-ids)).
|
||||||
|
|
||||||
|
An example set of queries when using the pepper `matrixrocks` would be:
|
||||||
|
|
||||||
|
"alice@example.com email matrixrocks" -> "4kenr7N9drpCJ4AfalmlGQVsOn3o2RHjkADUpXJWZUc"
|
||||||
|
"bob@example.com email matrixrocks" -> "LJwSazmv46n0hlMlsb_iYxI0_HXEqy_yj6Jm636cdT8"
|
||||||
|
"18005552067 msisdn matrixrocks" -> "nlo35_T5fzSGZzJApqu8lgIudJvmOQtDaHtr-I4rU7I"
|
||||||
|
|
||||||
|
The set of hashes is then given as the `addresses` array in `/lookup`.
|
||||||
|
Note that the pepper used MUST be supplied as `pepper` in the `/lookup`
|
||||||
|
request.
|
||||||
|
|
||||||
|
#### `none`
|
||||||
|
|
||||||
|
This algorithm performs plaintext lookups on the identity server.
|
||||||
|
Typically this algorithm should not be used due to the security concerns
|
||||||
|
of unhashed identifiers, however some scenarios (such as LDAP-backed
|
||||||
|
identity servers) prevent the use of hashed identifiers. Identity
|
||||||
|
servers (and optionally clients) can use this algorithm to perform those
|
||||||
|
kinds of lookups.
|
||||||
|
|
||||||
|
Similar to the `sha256` algorithm, the client converts the queries into
|
||||||
|
strings separated by spaces in the format `<address> <medium>` - note
|
||||||
|
the lack of `<pepper>`. For example, if the client wanted to know about
|
||||||
|
`alice@example.org`'s bindings, it would format the query as
|
||||||
|
`alice@example.org email`.
|
||||||
|
|
||||||
|
The formatted strings are then given as the `addresses` in `/lookup`.
|
||||||
|
Note that the `pepper` is still required, and must be provided to ensure
|
||||||
|
the client has made an appropriate request to `/hash_details` first.
|
||||||
|
|
||||||
|
### Security considerations
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
[MSC2134](https://github.com/matrix-org/matrix-doc/pull/2134) has much
|
||||||
|
more information about the security considerations made for this section
|
||||||
|
of the specification. This section covers the high-level details for why
|
||||||
|
the specification is the way it is.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
Typically the lookup endpoint is used when a client has an unknown 3PID
|
||||||
|
it wants to find a Matrix User ID for. Clients normally do this kind of
|
||||||
|
lookup when inviting new users to a room or searching a user's address
|
||||||
|
book to find any Matrix users they may not have discovered yet. Rogue or
|
||||||
|
malicious identity servers could harvest this unknown information and do
|
||||||
|
nefarious things with it if it were sent in plain text. In order to
|
||||||
|
protect the privacy of users who might not have a Matrix identifier
|
||||||
|
bound to their 3PID addresses, the specification attempts to make it
|
||||||
|
difficult to harvest 3PIDs.
|
||||||
|
|
||||||
|
{{% boxes/rationale %}}
|
||||||
|
Hashing identifiers, while not perfect, helps make the effort required
|
||||||
|
to harvest identifiers significantly higher. Phone numbers in particular
|
||||||
|
are still difficult to protect with hashing, however hashing is
|
||||||
|
objectively better than not.
|
||||||
|
|
||||||
|
An alternative to hashing would be using bcrypt or similar with many
|
||||||
|
rounds, however by nature of needing to serve mobile clients and clients
|
||||||
|
on limited hardware the solution needs be kept relatively lightweight.
|
||||||
|
{{% /boxes/rationale %}}
|
||||||
|
|
||||||
|
Clients should be cautious of servers not rotating their pepper very
|
||||||
|
often, and potentially of servers which use a weak pepper - these
|
||||||
|
servers may be attempting to brute force the identifiers or use rainbow
|
||||||
|
tables to mine the addresses. Similarly, clients which support the
|
||||||
|
`none` algorithm should consider at least warning the user of the risks
|
||||||
|
in sending identifiers in plain text to the identity server.
|
||||||
|
|
||||||
|
Addresses are still potentially reversable using a calculated rainbow
|
||||||
|
table given some identifiers, such as phone numbers, common email
|
||||||
|
address domains, and leaked addresses are easily calculated. For
|
||||||
|
example, phone numbers can have roughly 12 digits to them, making them
|
||||||
|
an easier target for attack than email addresses.
|
||||||
|
|
||||||
|
## Establishing associations
|
||||||
|
|
||||||
|
The flow for creating an association is session-based.
|
||||||
|
|
||||||
|
Within a session, one may prove that one has ownership of a 3PID. Once
|
||||||
|
this has been established, the user can form an association between that
|
||||||
|
3PID and a Matrix user ID. Note that this association is only proved one
|
||||||
|
way; a user can associate *any* Matrix user ID with a validated 3PID,
|
||||||
|
i.e. I can claim that any email address I own is associated with
|
||||||
|
@billg:microsoft.com.
|
||||||
|
|
||||||
|
Sessions are time-limited; a session is considered to have been modified
|
||||||
|
when it was created, and then when a validation is performed within it.
|
||||||
|
A session can only be checked for validation, and validation can only be
|
||||||
|
performed within a session, within a 24-hour period since its most
|
||||||
|
recent modification. Any attempts to perform these actions after the
|
||||||
|
expiry will be rejected, and a new session should be created and used
|
||||||
|
instead.
|
||||||
|
|
||||||
|
To start a session, the client makes a request to the appropriate
|
||||||
|
`/requestToken` endpoint. The identity server then sends a validation
|
||||||
|
token to the user, and the user provides the token to the client. The
|
||||||
|
client then provides the token to the appropriate `/submitToken`
|
||||||
|
endpoint, completing the session. At this point, the client should
|
||||||
|
`/bind` the third party identifier or leave it for another entity to
|
||||||
|
bind.
|
||||||
|
|
||||||
|
### Format of a validation token
|
||||||
|
|
||||||
|
The format of the validation token is left up to the identity server: it
|
||||||
|
should choose one appropriate to the 3PID type. (For example, it would
|
||||||
|
be inappropriate to expect a user to copy a long passphrase including
|
||||||
|
punctuation from an SMS message into a client.)
|
||||||
|
|
||||||
|
Whatever format the identity server uses, the validation token must
|
||||||
|
consist of at most 255 Unicode codepoints. Clients must pass the token
|
||||||
|
through without modification.
|
||||||
|
|
||||||
|
### Email associations
|
||||||
|
|
||||||
|
{{email\_associations\_is\_http\_api}}
|
||||||
|
|
||||||
|
{{v2\_email\_associations\_is\_http\_api}}
|
||||||
|
|
||||||
|
### Phone number associations
|
||||||
|
|
||||||
|
{{phone\_associations\_is\_http\_api}}
|
||||||
|
|
||||||
|
{{v2\_phone\_associations\_is\_http\_api}}
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
{{associations\_is\_http\_api}}
|
||||||
|
|
||||||
|
{{v2\_associations\_is\_http\_api}}
|
||||||
|
|
||||||
|
## Invitation storage
|
||||||
|
|
||||||
|
An identity server can store pending invitations to a user's 3PID, which
|
||||||
|
will be retrieved and can be either notified on or look up when the 3PID
|
||||||
|
is associated with a Matrix user ID.
|
||||||
|
|
||||||
|
At a later point, if the owner of that particular 3PID binds it with a
|
||||||
|
Matrix user ID, the identity server will attempt to make an HTTP POST to
|
||||||
|
the Matrix user's homeserver via the
|
||||||
|
[/3pid/onbind](/server-server-api#put_matrixfederationv13pidonbind)
|
||||||
|
endpoint. The request MUST be signed with a long-term private key for
|
||||||
|
the identity server.
|
||||||
|
|
||||||
|
{{store\_invite\_is\_http\_api}}
|
||||||
|
|
||||||
|
{{v2\_store\_invite\_is\_http\_api}}
|
||||||
|
|
||||||
|
## Ephemeral invitation signing
|
||||||
|
|
||||||
|
To aid clients who may not be able to perform crypto themselves, the
|
||||||
|
identity server offers some crypto functionality to help in accepting
|
||||||
|
invitations. This is less secure than the client doing it itself, but
|
||||||
|
may be useful where this isn't possible.
|
||||||
|
|
||||||
|
{{invitation\_signing\_is\_http\_api}}
|
||||||
|
|
||||||
|
{{v2\_invitation\_signing\_is\_http\_api}}
|
@ -0,0 +1,481 @@
|
|||||||
|
---
|
||||||
|
title: "Spec Change Proposals"
|
||||||
|
weight: 60
|
||||||
|
type: docs
|
||||||
|
---
|
||||||
|
|
||||||
|
If you are interested in submitting a change to the Matrix
|
||||||
|
Specification, please take note of the following guidelines.
|
||||||
|
|
||||||
|
Most changes to the Specification require a formal proposal. Bug fixes,
|
||||||
|
typos, and clarifications to existing behaviour do not need proposals -
|
||||||
|
see the [contributing
|
||||||
|
guide](https://github.com/matrix-org/matrix-doc/blob/master/CONTRIBUTING.rst)
|
||||||
|
for more information on what does and does not need a proposal.
|
||||||
|
|
||||||
|
The proposal process involves some technical writing, having it reviewed
|
||||||
|
by everyone, having the proposal being accepted, then actually having
|
||||||
|
your ideas implemented as committed changes to the [Specification
|
||||||
|
repository](https://github.com/matrix-org/matrix-doc).
|
||||||
|
|
||||||
|
Meet the [members of the Core Team](https://matrix.org/foundation), a
|
||||||
|
group of individuals tasked with ensuring the spec process is as smooth
|
||||||
|
and painless as possible. Members of the Spec Core Team will do their
|
||||||
|
best to participate in discussion, summarise when things become
|
||||||
|
long-winded, and generally try to act towards the benefit of everyone.
|
||||||
|
As a majority, team members have the ability to change the state of a
|
||||||
|
proposal, and individually have the final say in proposal discussion.
|
||||||
|
|
||||||
|
## Guiding Principles
|
||||||
|
|
||||||
|
Proposals **must** act to the greater benefit of the entire Matrix
|
||||||
|
ecosystem, rather than benefiting or privileging any single player or
|
||||||
|
subset of players -and must not contain any patent encumbered
|
||||||
|
intellectual property. Members of the Core Team pledge to act as a
|
||||||
|
neutral custodian for Matrix on behalf of the whole ecosystem.
|
||||||
|
|
||||||
|
For clarity: the Matrix ecosystem is anyone who uses the Matrix
|
||||||
|
protocol. That includes client users, server admins, client developers,
|
||||||
|
bot developers, bridge and application service developers, users and
|
||||||
|
admins who are indirectly using Matrix via 3rd party networks which
|
||||||
|
happen to be bridged, server developers, room moderators and admins,
|
||||||
|
companies/projects building products or services on Matrix, spec
|
||||||
|
contributors, translators, and those who created it in the first place.
|
||||||
|
|
||||||
|
"Greater benefit" could include maximising:
|
||||||
|
|
||||||
|
- the number of end-users reachable on the open Matrix network
|
||||||
|
- the number of regular users on the Matrix network (e.g. 30-day
|
||||||
|
retained federated users)
|
||||||
|
- the number of online servers in the open federation
|
||||||
|
- the number of developers building on Matrix
|
||||||
|
- the number of independent implementations which use Matrix
|
||||||
|
- the number of bridged end-users reachable on the open Matrix network
|
||||||
|
- the signal-to-noise ratio of the content on the open Matrix network
|
||||||
|
(i.e. minimising spam)
|
||||||
|
- the ability for users to discover content on their terms (empowering
|
||||||
|
them to select what to see and what not to see)
|
||||||
|
- the quality and utility of the Matrix spec (as defined by ease and
|
||||||
|
ability with which a developer can implement spec-compliant clients,
|
||||||
|
servers, bots, bridges, and other integrations without needing to
|
||||||
|
refer to any other external material)
|
||||||
|
|
||||||
|
In addition, proposal authors are expected to uphold the following
|
||||||
|
values in their proposed changes to the Matrix protocol:
|
||||||
|
|
||||||
|
- Supporting the whole long-term ecosystem rather than individual
|
||||||
|
stakeholder gain
|
||||||
|
- Openness rather than proprietary lock-in
|
||||||
|
- Interoperability rather than fragmentation
|
||||||
|
- Cross-platform rather than platform-specific
|
||||||
|
- Collaboration rather than competition
|
||||||
|
- Accessibility rather than elitism
|
||||||
|
- Transparency rather than stealth
|
||||||
|
- Empathy rather than contrariness
|
||||||
|
- Pragmatism rather than perfection
|
||||||
|
- Proof rather than conjecture
|
||||||
|
|
||||||
|
Please [see
|
||||||
|
MSC1779](https://github.com/matrix-org/matrix-doc/blob/master/proposals/1779-open-governance.md)
|
||||||
|
for full details of the project's Guiding Principles.
|
||||||
|
|
||||||
|
## Technical notes
|
||||||
|
|
||||||
|
Proposals **must** develop Matrix as a layered protocol: with new
|
||||||
|
features building on layers of shared abstractions rather than
|
||||||
|
introducing tight vertical coupling within the stack. This ensures that
|
||||||
|
new features can evolve rapidly by building on existing layers and
|
||||||
|
swapping out old features without impacting the rest of the stack or
|
||||||
|
requiring substantial upgrades to the whole ecosystem. This is critical
|
||||||
|
for Matrix to rapidly evolve and compete effectively with centralised
|
||||||
|
systems, despite being a federated protocol.
|
||||||
|
|
||||||
|
For instance, new features should be implemented using the highest layer
|
||||||
|
abstractions possible (e.g. new event types, which layer on top of the
|
||||||
|
existing room semantics, and so don't even require any API changes).
|
||||||
|
Failing that, the next recourse would be backwards-compatible changes to
|
||||||
|
the next layer down (e.g. room APIs); failing that, considering changes
|
||||||
|
to the format of events or the DAG; etc. It would be a very unusual
|
||||||
|
feature which doesn't build on the existing infrastructure provided by
|
||||||
|
the spec and instead created new primitives or low level APIs.
|
||||||
|
|
||||||
|
Backwards compatibility is very important for Matrix, but not at the
|
||||||
|
expense of hindering the protocol's evolution. Backwards incompatible
|
||||||
|
changes to endpoints are allowed when no other alternative exists, and
|
||||||
|
must be versioned under a new major release of the API. Backwards
|
||||||
|
incompatible changes to the room algorithm are also allowed when no
|
||||||
|
other alternative exists, and must be versioned under a new version of
|
||||||
|
the room algorithm.
|
||||||
|
|
||||||
|
There is sometimes a dilemma over where to include higher level
|
||||||
|
features: for instance, should video conferencing be formalised in the
|
||||||
|
spec, or should it be implemented via widgets? Should reputation systems
|
||||||
|
be specified? Should search engine behaviour be specified?
|
||||||
|
|
||||||
|
There is no universal answer to this, but the following guidelines
|
||||||
|
should be applied:
|
||||||
|
|
||||||
|
1. If the feature would benefit the whole Matrix ecosystem and is
|
||||||
|
aligned with the guiding principles above, then it should be
|
||||||
|
supported by the spec.
|
||||||
|
2. If the spec already makes the feature possible without changing any
|
||||||
|
of the implementations and spec, then it may not need to be added to
|
||||||
|
the spec.
|
||||||
|
3. However, if the best user experience for a feature does require
|
||||||
|
custom implementation behaviour then the behaviour should be defined
|
||||||
|
in the spec such that all implementations may implement it.
|
||||||
|
4. However, the spec must never add dependencies on
|
||||||
|
unspecified/nonstandardised 3rd party behaviour.
|
||||||
|
|
||||||
|
As a worked example:
|
||||||
|
|
||||||
|
1. Video conferencing is clearly a feature which would benefit the
|
||||||
|
whole ecosystem, and so the spec should find a way to make it
|
||||||
|
happen.
|
||||||
|
2. Video conferencing can be achieved by widgets without requiring any
|
||||||
|
compulsory changes to clients nor servers to work, and so could be
|
||||||
|
omitted from the spec.
|
||||||
|
3. A better experience could be achieved by embedding Jitsi natively
|
||||||
|
into clients rather than using a widget...
|
||||||
|
4. ...except that would add a dependency on unspecified/nonstandardised
|
||||||
|
3rd party behaviour, so must not be added to the spec.
|
||||||
|
|
||||||
|
Therefore, our two options in the specific case of video conferencing
|
||||||
|
are either to spec SFU conferencing semantics for WebRTC (or refer to an
|
||||||
|
existing spec for doing so), or to keep it as a widget-based approach
|
||||||
|
(optionally with widget extensions specific for more deeply integrating
|
||||||
|
video conferencing use cases).
|
||||||
|
|
||||||
|
As an alternative example: it's very unlikely that "how to visualise
|
||||||
|
Magnetic Resonance Imaging data over Matrix" would ever be added to the
|
||||||
|
Matrix spec (other than perhaps a custom event type in a wider
|
||||||
|
standardised Matrix event registry) given that the spec's existing
|
||||||
|
primitives of file transfer and extensible events (MSC1767) give
|
||||||
|
excellent tools for transferring and visualising arbitrary rich data.
|
||||||
|
|
||||||
|
Supporting public search engines are likely to not require custom spec
|
||||||
|
features (other than possibly better bulk access APIs), given they can
|
||||||
|
be implemented as clients using the existing CS API. An exception could
|
||||||
|
be API features required by decentralised search infrastructure
|
||||||
|
(avoiding centralisation of power by a centralised search engine).
|
||||||
|
|
||||||
|
Features such as reactions, threaded messages, editable messages,
|
||||||
|
spam/abuse/content filtering (and reputation systems), are all features
|
||||||
|
which would clearly benefit the whole Matrix ecosystem, and cannot be
|
||||||
|
implemented in an interoperable way using the current spec; so they
|
||||||
|
necessitate a spec change.
|
||||||
|
|
||||||
|
## Process
|
||||||
|
|
||||||
|
The process for submitting a Matrix Spec Change (MSC) Proposal in detail
|
||||||
|
is as follows:
|
||||||
|
|
||||||
|
- Create a first draft of your proposal using [GitHub-flavored
|
||||||
|
Markdown](https://help.github.com/articles/basic-writing-and-formatting-syntax/)
|
||||||
|
- In the document, clearly state the problem being solved, and the
|
||||||
|
possible solutions being proposed for solving it and their
|
||||||
|
respective trade-offs.
|
||||||
|
- Proposal documents are intended to be as lightweight and
|
||||||
|
flexible as the author desires; there is no formal template; the
|
||||||
|
intention is to iterate as quickly as possible to get to a good
|
||||||
|
design.
|
||||||
|
- However, a [template with suggested
|
||||||
|
headers](https://github.com/matrix-org/matrix-doc/blob/master/proposals/0000-proposal-template.md)
|
||||||
|
is available to get you started if necessary.
|
||||||
|
- Take care in creating your proposal. Specify your intended
|
||||||
|
changes, and give reasoning to back them up. Changes without
|
||||||
|
justification will likely be poorly received by the community.
|
||||||
|
- Fork and make a PR to the
|
||||||
|
[matrix-doc](https://github.com/matrix-org/matrix-doc) repository.
|
||||||
|
The ID of your PR will become the MSC ID for the lifetime of your
|
||||||
|
proposal.
|
||||||
|
- The proposal must live in the `proposals/` directory with a
|
||||||
|
filename that follows the format `1234-my-new-proposal.md` where
|
||||||
|
`1234` is the MSC ID.
|
||||||
|
- Your PR description must include a link to the rendered Markdown
|
||||||
|
document and a summary of the proposal.
|
||||||
|
- It is often very helpful to link any related MSCs or [matrix-doc
|
||||||
|
issues](https://github.com/matrix-org/matrix-doc/issues) to give
|
||||||
|
context for the proposal.
|
||||||
|
- Additionally, please be sure to sign off your proposal PR as per
|
||||||
|
the guidelines listed on
|
||||||
|
[CONTRIBUTING.rst](https://github.com/matrix-org/matrix-doc/blob/master/CONTRIBUTING.rst).
|
||||||
|
- Gather feedback as widely as possible.
|
||||||
|
- The aim is to get maximum consensus towards an optimal solution.
|
||||||
|
Sometimes trade-offs are required to meet this goal. Decisions
|
||||||
|
should be made to the benefit of all major use cases.
|
||||||
|
- A good place to ask for feedback on a specific proposal is
|
||||||
|
[\#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org).
|
||||||
|
If preferred, an alternative room can be created and advertised
|
||||||
|
in \#matrix-spec:matrix.org. Please also link to the room in
|
||||||
|
your PR description.
|
||||||
|
- For additional discussion areas, know that
|
||||||
|
\#matrix-dev:matrix.org is for developers using existing Matrix
|
||||||
|
APIs, \#matrix:matrix.org is for users trying to run Matrix apps
|
||||||
|
(clients & servers) and \#matrix-architecture:matrix.org is for
|
||||||
|
cross-cutting discussion of Matrix's architectural design.
|
||||||
|
- The point of the spec proposal process is to be collaborative
|
||||||
|
rather than competitive, and to try to solve the problem in
|
||||||
|
question with the optimal set of trade-offs. The author should
|
||||||
|
neutrally gather the various viewpoints and get consensus, but
|
||||||
|
this can sometimes be time-consuming (or the author may be
|
||||||
|
biased), in which case an impartial 'shepherd' can be assigned
|
||||||
|
to help guide the proposal through this process instead. A
|
||||||
|
shepherd is typically a neutral party from the Spec Core Team or
|
||||||
|
an experienced member of the community. There is no formal
|
||||||
|
process for assignment. Simply ask for a shepherd to help get
|
||||||
|
your proposal through and one will be assigned based on
|
||||||
|
availability. Having a shepherd is not a requirement for
|
||||||
|
proposal acceptance.
|
||||||
|
- Members of the Spec Core Team and community will review and discuss
|
||||||
|
the PR in the comments and in relevant rooms on Matrix. Discussion
|
||||||
|
outside of GitHub should be summarised in a comment on the PR.
|
||||||
|
- When a member of the Spec Core Team believes that no new discussion
|
||||||
|
points are being made, and the proposal has suitable evidence of
|
||||||
|
working (see [implementing a proposal](#implementing-a-proposal)
|
||||||
|
below), they will propose a motion for a final comment period (FCP),
|
||||||
|
along with a *disposition* of either merge, close or postpone. This
|
||||||
|
FCP is provided to allow a short period of time for any invested
|
||||||
|
party to provide a final objection before a major decision is made.
|
||||||
|
If sufficient reasoning is given, an FCP can be cancelled. It is
|
||||||
|
often preceded by a comment summarising the current state of the
|
||||||
|
discussion, along with reasoning for its occurrence.
|
||||||
|
- A concern can be raised by a Spec Core Team member at any time,
|
||||||
|
which will block an FCP from beginning. An FCP will only begin when
|
||||||
|
75% of the members of the Spec Core Team agree on its outcome, and
|
||||||
|
all existing concerns have been resolved.
|
||||||
|
- The FCP will then begin and last for 5 days, giving anyone else some
|
||||||
|
time to speak up before it concludes. On its conclusion, the
|
||||||
|
disposition of the FCP will be carried out. If sufficient reasoning
|
||||||
|
against the disposition is raised, the FCP can be cancelled and the
|
||||||
|
MSC will continue to evolve accordingly.
|
||||||
|
- Once the proposal has been accepted and merged, it is time to submit
|
||||||
|
the actual change to the Specification that your proposal reasoned
|
||||||
|
about. This is known as a spec PR. However in order for the spec PR
|
||||||
|
to be accepted, an implementation **must** be shown to prove that it
|
||||||
|
works well in practice. A link to the implementation should be
|
||||||
|
included in the PR description. In addition, any significant
|
||||||
|
unforeseen changes to the original idea found during this process
|
||||||
|
will warrant another MSC. Any minor, non-fundamental changes are
|
||||||
|
allowed but **must** be documented in the original proposal
|
||||||
|
document. This ensures that someone reading a proposal in the future
|
||||||
|
doesn't assume old information wasn't merged into the spec.
|
||||||
|
- Similar to the proposal PR, please sign off the spec PR as per
|
||||||
|
the guidelines on
|
||||||
|
[CONTRIBUTING.rst](https://github.com/matrix-org/matrix-doc/blob/master/CONTRIBUTING.rst).
|
||||||
|
- Your PR will then be reviewed and hopefully merged on the grounds it
|
||||||
|
is implemented sufficiently. If so, then give yourself a pat on the
|
||||||
|
back knowing you've contributed to the Matrix protocol for the
|
||||||
|
benefit of users and developers alike :)
|
||||||
|
|
||||||
|
The process for handling proposals is shown visually in the following
|
||||||
|
diagram. Note that the lifetime of a proposal is tracked through the
|
||||||
|
corresponding labels for each stage on the
|
||||||
|
[matrix-doc](https://github.com/matrix-org/matrix-doc) issue and pull
|
||||||
|
request trackers.
|
||||||
|
|
||||||
|
```
|
||||||
|
+ +
|
||||||
|
Proposals | Spec PRs | Additional States
|
||||||
|
+-------+ | +------+ | +---------------+
|
||||||
|
| |
|
||||||
|
+----------------------+ | +---------+ | +-----------+
|
||||||
|
| | | | | | | |
|
||||||
|
| Proposal | | +------= Spec PR | | | Postponed |
|
||||||
|
| Drafting and Initial | | | | Missing | | | |
|
||||||
|
| Feedback Gathering | | | | | | +-----------+
|
||||||
|
| | | | +----+----+ |
|
||||||
|
+----------+-----------+ | | | | +----------+
|
||||||
|
| | | v | | |
|
||||||
|
v | | +-----------------+ | | Closed |
|
||||||
|
+-------------------+ | | | | | | |
|
||||||
|
| | | | | Spec PR Created | | +----------+
|
||||||
|
| Proposal PR | | | | and In Review | |
|
||||||
|
| In Review | | | | | |
|
||||||
|
| | | | +--------+--------+ |
|
||||||
|
+---------+---------+ | | | |
|
||||||
|
| | | v |
|
||||||
|
v | | +-----------+ |
|
||||||
|
+----------------------+ | | | | |
|
||||||
|
| | | | | Spec PR | |
|
||||||
|
| Proposed Final | | | | Merged! | |
|
||||||
|
| Comment Period | | | | | |
|
||||||
|
| | | | +-----------+ |
|
||||||
|
+----------+-----------+ | | |
|
||||||
|
| | | |
|
||||||
|
v | | |
|
||||||
|
+----------------------+ | | |
|
||||||
|
| | | | |
|
||||||
|
| Final Comment Period | | | |
|
||||||
|
| | | | |
|
||||||
|
+----------+-----------+ | | |
|
||||||
|
| | | |
|
||||||
|
v | | |
|
||||||
|
+----------------------+ | | |
|
||||||
|
| | | | |
|
||||||
|
| Final Comment Period | | | |
|
||||||
|
| Complete | | | |
|
||||||
|
| | | | |
|
||||||
|
+----------+-----------+ | | |
|
||||||
|
| | | |
|
||||||
|
+-----------------+ |
|
||||||
|
| |
|
||||||
|
+ +
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lifetime States
|
||||||
|
|
||||||
|
**Note:** All labels are to be placed on the proposal PR.
|
||||||
|
|
||||||
|
| Name | GitHub Label | Description |
|
||||||
|
|---------------------------------|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| Proposal Drafting and Feedback | [No label](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+-label%3Aabandoned+-label%3Afinal-comment-period+-label%3Afinished-final-comment-period+-label%3Amerged+-label%3Aobsolete+-label%3Aproposal-postponed+-label%3Aproposed-final-comment-period+-label%3Aproposal-in-review+-label%3Aspec-pr-in-review+-label%3Aspec-pr-missing) | A proposal document which is still work-in-progress but is being shared to incorporate feedback. Please prefix your proposal's title with `[WIP]` to make it easier for reviewers to skim their notifications list. |
|
||||||
|
| Proposal In Review | [proposal-in-review](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Aproposal-in-review) | A proposal document which is now ready and waiting for review by the Spec Core Team and community |
|
||||||
|
| Proposed Final Comment Period | [proposed-final-comment-period](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Aproposed-final-comment-period+) | Currently awaiting signoff of a 75% majority of team members in order to enter the final comment period |
|
||||||
|
| Final Comment Period | [final-comment-period](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Afinal-comment-period+) | A proposal document which has reached final comment period either for merge, closure or postponement |
|
||||||
|
| Final Comment Period Complete | [finished-final-comment-period](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Afinished-final-comment-period+) | The final comment period has been completed. Waiting for a demonstration implementation |
|
||||||
|
| Spec PR Missing | [spec-pr-missing](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Aspec-pr-missing) | The proposal has been agreed, and proven with a demonstration implementation. Waiting for a PR against the Spec |
|
||||||
|
| Spec PR In Review | [spec-pr-in-review](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Aspec-pr-in-review+) | The spec PR has been written, and is currently under review |
|
||||||
|
| Spec PR Merged | [merged](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Amerged) | A proposal with a sufficient working implementation and whose Spec PR has been merged! |
|
||||||
|
| Postponed | [proposal-postponed](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Aproposal-postponed+) | A proposal that is temporarily blocked or a feature that may not be useful currently but perhaps sometime in the future |
|
||||||
|
| Abandoned | [proposal-closed](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Aabandoned) | A proposal where the author/shepherd is not responsive |
|
||||||
|
| Obsolete | [obsolete](https://github.com/matrix-org/matrix-doc/issues?q=label%3Aproposal+label%3Aobsolete+) | A proposal which has been made obsolete by another proposal or decision elsewhere. |
|
||||||
|
|
||||||
|
## Categories
|
||||||
|
|
||||||
|
We use category labels on MSCs to place them into a track of work. The
|
||||||
|
Spec Core Team decides which of the tracks they are focusing on for the
|
||||||
|
next while and generally makes an effort to pull MSCs out of that
|
||||||
|
category when possible.
|
||||||
|
|
||||||
|
The current categories are:
|
||||||
|
|
||||||
|
| Name | GitHub Label | Description |
|
||||||
|
|-------------|------------------|---------------------------------------|
|
||||||
|
| Core | kind:core | Important for the protocol's success. |
|
||||||
|
| Feature | kind:feature | Nice to have additions to the spec. |
|
||||||
|
| Maintenance | kind:maintenance | Fixes or clarifies existing spec. |
|
||||||
|
|
||||||
|
Some examples of core MSCs would be aggregations, cross-signing, and
|
||||||
|
groups/communities. These are the sorts of things that if not
|
||||||
|
implemented could cause the protocol to fail or become second-class.
|
||||||
|
Features would be areas like enhanced media APIs, new transports, and
|
||||||
|
bookmarks in comparison. Finally, maintenance MSCs would include
|
||||||
|
improving error codes, clarifying what is required of an API, and adding
|
||||||
|
properties to an API which makes it easier to use.
|
||||||
|
|
||||||
|
The Spec Core Team assigns a category to each MSC based on the
|
||||||
|
descriptions above. This can mean that new MSCs get categorized into an
|
||||||
|
area the team isn't focused on, though that can always change as
|
||||||
|
priorities evolve. We still encourage that MSCs be opened, even if not
|
||||||
|
the focus for the time being, as they can still make progress and even
|
||||||
|
be merged without the Spec Core Team focusing on them specifically.
|
||||||
|
|
||||||
|
## Implementing a proposal
|
||||||
|
|
||||||
|
As part of the proposal process the spec core team will require evidence
|
||||||
|
of the MSC working in order for it to move into FCP. This can usually be
|
||||||
|
a branch/pull request to whichever implementation of choice that proves
|
||||||
|
the MSC works in practice, though in some cases the MSC itself will be
|
||||||
|
small enough to be considered proven. Where it's unclear if an MSC will
|
||||||
|
require an implementation proof, ask in
|
||||||
|
[\#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org).
|
||||||
|
|
||||||
|
### Early release of an MSC/idea
|
||||||
|
|
||||||
|
To help facilitate early releases of software dependent on a spec
|
||||||
|
release, implementations are required to use the following process to
|
||||||
|
ensure that the official Matrix namespace is not cluttered with
|
||||||
|
development or testing data.
|
||||||
|
|
||||||
|
Note
|
||||||
|
|
||||||
|
Unreleased implementations (including proofs-of-concept demonstrating
|
||||||
|
that a particular MSC works) do not have to follow this process.
|
||||||
|
|
||||||
|
1. Have an idea for a feature.
|
||||||
|
2. Implement the feature using unstable endpoints, vendor prefixes, and
|
||||||
|
unstable feature flags as appropriate.
|
||||||
|
- When using unstable endpoints, they MUST include a vendor
|
||||||
|
prefix. For example:
|
||||||
|
`/_matrix/client/unstable/com.example/login`. Vendor prefixes
|
||||||
|
throughout Matrix always use the Java package naming convention.
|
||||||
|
The MSC for the feature should identify which preferred vendor
|
||||||
|
prefix is to be used by early adopters.
|
||||||
|
- Note that unstable namespaces do not automatically inherit
|
||||||
|
endpoints from stable namespaces: for example, the fact that
|
||||||
|
`/_matrix/client/r0/sync` exists does not imply that
|
||||||
|
`/_matrix/client/unstable/com.example/sync` exists.
|
||||||
|
- If the client needs to be sure the server supports the feature,
|
||||||
|
an unstable feature flag that MUST be vendor prefixed is to be
|
||||||
|
used. This kind of flag shows up in the `unstable_features`
|
||||||
|
section of `/versions` as, for example, `com.example.new_login`.
|
||||||
|
The MSC for the feature should identify which preferred feature
|
||||||
|
flag is to be used by early adopters.
|
||||||
|
- When using this approach correctly, the implementation can
|
||||||
|
ship/release the feature at any time, so long as the
|
||||||
|
implementation is able to accept the technical debt that results
|
||||||
|
from needing to provide adequate backwards and forwards
|
||||||
|
compatibility. The implementation MUST support the flag (and
|
||||||
|
server-side implementation) disappearing and be generally safe
|
||||||
|
for users. Note that implementations early in the MSC review
|
||||||
|
process may also be required to provide backwards compatibility
|
||||||
|
with earlier editions of the proposal.
|
||||||
|
- If the implementation cannot support the technical debt (or if
|
||||||
|
it's impossible to provide forwards/backwards compatibility -
|
||||||
|
e.g. a user authentication change which can't be safely rolled
|
||||||
|
back), the implementation should not attempt to implement the
|
||||||
|
feature and should instead wait for a spec release.
|
||||||
|
- If at any point after early release, the idea changes in a
|
||||||
|
backwards-incompatible way, the feature flag should also change
|
||||||
|
so that implementations can adapt as needed.
|
||||||
|
3. In parallel, or ahead of implementation, open an MSC and solicit
|
||||||
|
review per above.
|
||||||
|
4. Before FCP can be called, the Spec Core Team will require evidence
|
||||||
|
of the MSC working as proposed. A typical example of this is an
|
||||||
|
implementation of the MSC, though the implementation does not need
|
||||||
|
to be shipped anywhere and can therefore avoid the
|
||||||
|
forwards/backwards compatibility concerns mentioned here.
|
||||||
|
5. The FCP process is completed, and assuming nothing is flagged the
|
||||||
|
MSC lands.
|
||||||
|
6. A spec PR is written to incorporate the changes into Matrix.
|
||||||
|
7. A spec release happens.
|
||||||
|
8. Implementations switch to using stable prefixes (e.g.: `/r0`) if the
|
||||||
|
server supports the specification version released. If the server
|
||||||
|
doesn't advertise the specification version, but does have the
|
||||||
|
feature flag, unstable prefixes should still be used.
|
||||||
|
9. A transition period of about 2 months starts immediately after the
|
||||||
|
spec release, before implementations start to encourage other
|
||||||
|
implementations to switch to stable endpoints. For example, a server
|
||||||
|
implementation should start asking client implementations to support
|
||||||
|
the stable endpoints 2 months after the spec release, if they
|
||||||
|
haven't already. The same applies in the reverse: if clients cannot
|
||||||
|
switch to stable prefixes because server implementations haven't
|
||||||
|
started supporting the new spec release, some noise should be raised
|
||||||
|
in the general direction of the implementation.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
MSCs MUST still describe what the stable endpoints/feature looks like
|
||||||
|
with a note towards the bottom for what the unstable feature
|
||||||
|
flag/prefixes are. For example, an MSC would propose `/_matrix/client/r0/new/endpoint`, not `/_matrix/client/unstable/
|
||||||
|
com.example/new/endpoint`.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
In summary:
|
||||||
|
|
||||||
|
- Implementations MUST NOT use stable endpoints before the MSC is in
|
||||||
|
the spec. This includes NOT using stable endpoints in the period
|
||||||
|
between completion of FCP and release of the spec. passed.
|
||||||
|
- Implementations are able to ship features that are exposed to users
|
||||||
|
by default before an MSC has been merged to the spec, provided they
|
||||||
|
follow the process above.
|
||||||
|
- Implementations SHOULD be wary of the technical debt they are
|
||||||
|
incurring by moving faster than the spec.
|
||||||
|
- The vendor prefix is chosen by the developer of the feature, using
|
||||||
|
the Java package naming convention. The foundation's preferred
|
||||||
|
vendor prefix is `org.matrix`.
|
||||||
|
- The vendor prefixes, unstable feature flags, and unstable endpoints
|
||||||
|
should be included in the MSC, though the MSC MUST be written in a
|
||||||
|
way that proposes new stable endpoints. Typically this is solved by
|
||||||
|
a small table at the bottom mapping the various values from stable
|
||||||
|
to unstable.
|
@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
title: "Push Gateway API"
|
||||||
|
weight: 50
|
||||||
|
type: docs
|
||||||
|
---
|
||||||
|
|
||||||
|
Clients may want to receive push notifications when events are received
|
||||||
|
at the homeserver. This is managed by a distinct entity called the Push
|
||||||
|
Gateway.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
A client's homeserver forwards information about received events to the
|
||||||
|
push gateway. The gateway then submits a push notification to the push
|
||||||
|
notification provider (e.g. APNS, GCM).
|
||||||
|
|
||||||
|
```
|
||||||
|
+--------------------+ +-------------------+
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Homeserver behaviour
|
||||||
|
|
||||||
|
This describes the format used by "HTTP" pushers to send notifications
|
||||||
|
of events to Push Gateways. If the endpoint returns an HTTP error code,
|
||||||
|
the homeserver SHOULD retry for a reasonable amount of time using
|
||||||
|
exponential backoff.
|
||||||
|
|
||||||
|
When pushing notifications for events, the homeserver is expected to
|
||||||
|
include all of the event-related fields in the `/notify` request. When
|
||||||
|
the homeserver is performing a push where the `format` is
|
||||||
|
`"event_id_only"`, only the `event_id`, `room_id`, `counts`, and
|
||||||
|
`devices` are required to be populated.
|
||||||
|
|
||||||
|
Note that most of the values and behaviour of this endpoint is described
|
||||||
|
by the Client-Server API's [Push
|
||||||
|
Module](/client-server-api#push-notifications).
|
||||||
|
|
||||||
|
{{push\_notifier\_push\_http\_api}}
|
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: Room Versions
|
||||||
|
type: docs
|
||||||
|
weight: 60
|
||||||
|
---
|
||||||
|
|
||||||
|
* [Room Version 1](v1)
|
||||||
|
* [Room Version 2](v2)
|
||||||
|
* [Room Version 3](v3)
|
||||||
|
* [Room Version 4](v4)
|
||||||
|
* [Room Version 5](v5)
|
||||||
|
* [Room Version 6](v6)
|
@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
title: Room Version 3
|
||||||
|
type: docs
|
||||||
|
weight: 30
|
||||||
|
---
|
||||||
|
|
||||||
|
This room version builds on [version 2](/rooms/v2) with an improved event
|
||||||
|
format.
|
||||||
|
|
||||||
|
## Client considerations
|
||||||
|
|
||||||
|
This room version changes the format for event IDs sent to clients.
|
||||||
|
Clients should be aware that these event IDs may contain slashes and
|
||||||
|
other potentially problematic characters. Clients should be treating
|
||||||
|
event IDs as opaque identifiers and should not be attempting to parse
|
||||||
|
them into a usable form, just like with other room versions.
|
||||||
|
|
||||||
|
Clients should expect to see event IDs changed from the format of
|
||||||
|
`$randomstring:example.org` to something like
|
||||||
|
`$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk` (note the lack of domain
|
||||||
|
and the potentially problematic slash).
|
||||||
|
|
||||||
|
## Server implementation components
|
||||||
|
|
||||||
|
{{% boxes/warning %}}
|
||||||
|
The information contained in this section is strictly for server
|
||||||
|
implementors. Applications which use the Client-Server API are generally
|
||||||
|
unaffected by the intricacies contained here. The section above
|
||||||
|
regarding client considerations is the resource that Client-Server API
|
||||||
|
use cases should reference.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
|
Room version 3 uses the state resolution algorithm defined in [room
|
||||||
|
version 2](/rooms/v2), and the event format defined here.
|
||||||
|
|
||||||
|
### Event IDs
|
||||||
|
|
||||||
|
{{% boxes/rationale %}}
|
||||||
|
In other room versions (namely version 1 and 2) the event ID is a
|
||||||
|
distinct field from the remainder of the event, which must be tracked as
|
||||||
|
such. This leads to complications where servers receive multiple events
|
||||||
|
with the same ID in either the same or different rooms where the server
|
||||||
|
cannot easily keep track of which event it should be using. By removing
|
||||||
|
the use of a dedicated event ID, servers are required to track the
|
||||||
|
hashes on an event to determine its ID.
|
||||||
|
{{% /boxes/rationale %}}
|
||||||
|
|
||||||
|
The event ID is the [reference
|
||||||
|
hash](/server-server-api#calculating-the-reference-hash-for-an-event) of
|
||||||
|
the event encoded using [Unpadded
|
||||||
|
Base64](/appendices#unpadded-base64), prefixed with `$`. A
|
||||||
|
resulting event ID using this approach should look similar to
|
||||||
|
`$CD66HAED5npg6074c6pDtLKalHjVfYb2q4Q3LZgrW6o`.
|
||||||
|
|
||||||
|
Event IDs should not be sent over federation to servers when the room
|
||||||
|
uses this room version. On the receiving end of an event, the server
|
||||||
|
should compute the relevant event ID for itself.
|
||||||
|
|
||||||
|
Additionally, the `auth_events` and `prev_events` have had a format
|
||||||
|
change compared to other room versions to make it easier to handle.
|
||||||
|
Instead of a tuple of values, they are now plain lists of events.
|
||||||
|
|
||||||
|
{{definition\_ss\_pdu\_v3}}
|
||||||
|
|
||||||
|
### Changes to APIs
|
||||||
|
|
||||||
|
Due to the event ID being removed from the event, some APIs need to
|
||||||
|
change. All APIs which currently accept an event ID must do so with the
|
||||||
|
new format. Servers must append the calculated event ID to all events
|
||||||
|
sent to clients where an event ID would normally be expected.
|
||||||
|
|
||||||
|
Because the format of events has changed, servers must be aware of the
|
||||||
|
room version where the event resides so that the server may parse and
|
||||||
|
handle the event. The federation API has taken this concern into
|
||||||
|
consideration by ensuring that servers are aware of (or can find) the
|
||||||
|
room version during a request.
|
||||||
|
|
||||||
|
### Authorization rules for events
|
||||||
|
|
||||||
|
The authorization rules for a given event have changed in this room
|
||||||
|
version due to the change in event format:
|
||||||
|
|
||||||
|
- The event no longer needs to be signed by the domain of the event ID
|
||||||
|
(as there is no domain in the event ID), but still needs to be
|
||||||
|
signed by the sender's domain.
|
||||||
|
- In past room versions, redactions were only permitted to enter the
|
||||||
|
DAG if the sender's domain matched the domain in the event ID being
|
||||||
|
redacted, or the sender had appropriate permissions per the power
|
||||||
|
levels. Due to servers now not being able to determine where an
|
||||||
|
event came from during event authorization, redaction events are
|
||||||
|
always accepted (provided the event is allowed by `events` and
|
||||||
|
`events_default` in the power levels). However, servers should not
|
||||||
|
apply or send redactions to clients until both the redaction event
|
||||||
|
and original event have been seen, and are valid. Servers should
|
||||||
|
only apply redactions to events where the sender's domains match, or
|
||||||
|
the sender of the redaction has the appropriate permissions per the
|
||||||
|
power levels.
|
||||||
|
|
||||||
|
The remaining rules are the same as [room version
|
||||||
|
1](/rooms/v1#authorization-rules).
|
@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
title: Room Version 4
|
||||||
|
type: docs
|
||||||
|
weight: 40
|
||||||
|
---
|
||||||
|
|
||||||
|
This room version builds on [version 3](/rooms/v3) using a different
|
||||||
|
encoding for event IDs.
|
||||||
|
|
||||||
|
## Client considerations
|
||||||
|
|
||||||
|
This room version changes the format form event IDs sent to clients.
|
||||||
|
Clients should already be treating event IDs as opaque identifiers, and
|
||||||
|
should not be concerned with the format of them. Clients should still
|
||||||
|
encode the event ID when including it in a request path.
|
||||||
|
|
||||||
|
Clients should expect to see event IDs changed from the format of
|
||||||
|
`$randomstring:example.org` to something like
|
||||||
|
`$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg` (note the lack of
|
||||||
|
domain).
|
||||||
|
|
||||||
|
## Server implementation components
|
||||||
|
|
||||||
|
{{% boxes/warning %}}
|
||||||
|
The information contained in this section is strictly for server
|
||||||
|
implementors. Applications which use the Client-Server API are generally
|
||||||
|
unaffected by the intricacies contained here. The section above
|
||||||
|
regarding client considerations is the resource that Client-Server API
|
||||||
|
use cases should reference.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
|
Room version 4 uses the same algorithms defined in [room version
|
||||||
|
3](/rooms/v3), however using URL-safe base64 to generate the event ID.
|
||||||
|
|
||||||
|
### Event IDs
|
||||||
|
|
||||||
|
{{% boxes/rationale %}}
|
||||||
|
Room version 3 generated event IDs that were difficult for client
|
||||||
|
implementations which were not encoding the event ID to function in
|
||||||
|
those rooms. It additionally raised concern due to the `/` character
|
||||||
|
being interpretted differently by some reverse proxy software, and
|
||||||
|
generally made administration harder.
|
||||||
|
{{% /boxes/rationale %}}
|
||||||
|
|
||||||
|
The event ID is the [reference
|
||||||
|
hash](/server-server-api#calculating-the-reference-hash-for-an-event) of
|
||||||
|
the event encoded using a variation of [Unpadded
|
||||||
|
Base64](/appendices#unpadded-base64) which replaces the 62nd and
|
||||||
|
63rd characters with `-` and `_` instead of using `+` and `/`. This
|
||||||
|
matches [RFC4648's definition of URL-safe
|
||||||
|
base64](https://tools.ietf.org/html/rfc4648#section-5). Event IDs are
|
||||||
|
still prefixed with `$` and may result in looking like
|
||||||
|
`$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg`.
|
||||||
|
|
||||||
|
Just like in room version 3, event IDs should not be sent over
|
||||||
|
federation to servers when the room uses this room version. On the
|
||||||
|
receiving end of an event, the server should compute the relevant event
|
||||||
|
ID for itself. Room version 3 also changes the format of `auth_events`
|
||||||
|
and `prev_events` in a PDU.
|
||||||
|
|
||||||
|
{{definition\_ss\_pdu\_v4}}
|
@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
title: Room Version 5
|
||||||
|
type: docs
|
||||||
|
weight: 50
|
||||||
|
---
|
||||||
|
|
||||||
|
This room version builds on [version 4](/rooms/v4) while enforcing signing
|
||||||
|
key validity periods for events.
|
||||||
|
|
||||||
|
## Client considerations
|
||||||
|
|
||||||
|
There are no specific requirements for clients in this room version.
|
||||||
|
Clients should be aware of event ID changes in [room version
|
||||||
|
4](/rooms/v4), however.
|
||||||
|
|
||||||
|
## Server implementation components
|
||||||
|
|
||||||
|
{{% boxes/warning %}}
|
||||||
|
The information contained in this section is strictly for server
|
||||||
|
implementors. Applications which use the Client-Server API are generally
|
||||||
|
unaffected by the intricacies contained here. The section above
|
||||||
|
regarding client considerations is the resource that Client-Server API
|
||||||
|
use cases should reference.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
|
Room version 5 uses the same algorithms defined in [room version
|
||||||
|
4](/rooms/v4), ensuring that signing key validity is respected.
|
||||||
|
|
||||||
|
### Signing key validity period
|
||||||
|
|
||||||
|
When validating event signatures, servers MUST enforce the
|
||||||
|
`valid_until_ts` property from a key request is at least as large as the
|
||||||
|
`origin_server_ts` for the event being validated. Servers missing a copy
|
||||||
|
of the signing key MUST try to obtain one via the [GET
|
||||||
|
/\_matrix/key/v2/server](/server-server-api#get_matrixkeyv2serverkeyid)
|
||||||
|
or [POST
|
||||||
|
/\_matrix/key/v2/query](/server-server-api#post_matrixkeyv2query)
|
||||||
|
APIs. When using the `/query` endpoint, servers MUST set the
|
||||||
|
`minimum_valid_until_ts` property to prompt the notary server to attempt
|
||||||
|
to refresh the key if appropriate.
|
||||||
|
|
||||||
|
Servers MUST use the lesser of `valid_until_ts` and 7 days into the
|
||||||
|
future when determining if a key is valid. This is to avoid a situation
|
||||||
|
where an attacker publishes a key which is valid for a significant
|
||||||
|
amount of time without a way for the homeserver owner to revoke it.
|
@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
title: Room Version 6
|
||||||
|
type: docs
|
||||||
|
weight: 60
|
||||||
|
---
|
||||||
|
|
||||||
|
This room version builds on [version 5](/rooms/v5) while changing various
|
||||||
|
authorization rules performed on events.
|
||||||
|
|
||||||
|
## Client considerations
|
||||||
|
|
||||||
|
The redaction algorithm has changed from [room version 1](/rooms/v1) to
|
||||||
|
remove all rules against events of type `m.room.aliases`. Room versions
|
||||||
|
2, 3, 4, and 5 all use v1's redaction algorithm. The algorithm is
|
||||||
|
otherwise unchanged.
|
||||||
|
|
||||||
|
## Server implementation components
|
||||||
|
|
||||||
|
{{% boxes/warning %}}
|
||||||
|
The information contained in this section is strictly for server
|
||||||
|
implementors. Applications which use the Client-Server API are generally
|
||||||
|
unaffected by the intricacies contained here. The section above
|
||||||
|
regarding client considerations is the resource that Client-Server API
|
||||||
|
use cases should reference.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
|
Room version 6 makes the following alterations to algorithms described
|
||||||
|
in [room version 5](/rooms/v5).
|
||||||
|
|
||||||
|
### Redactions
|
||||||
|
|
||||||
|
As mentioned in the client considerations portion of this specification,
|
||||||
|
all special meaning has been removed for events of type
|
||||||
|
`m.room.aliases`. The algorithm is otherwise unchanged.
|
||||||
|
|
||||||
|
### Authorization rules for events
|
||||||
|
|
||||||
|
Like redactions, all rules relating specifically to events of type
|
||||||
|
`m.room.aliases` are removed. They must still pass authorization checks
|
||||||
|
relating to state events.
|
||||||
|
|
||||||
|
Additionally, the authorization rules for events of type
|
||||||
|
`m.room.power_levels` now include the content key `notifications`. This
|
||||||
|
new rule takes the place of the rule which checks the `events` and
|
||||||
|
`users` keys.
|
||||||
|
|
||||||
|
For completeness, the changes to the auth rules can be represented as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
-If type is `m.room.aliases`:
|
||||||
|
-
|
||||||
|
- a. If event has no `state_key`, reject.
|
||||||
|
- b. If sender's domain doesn't matches `state_key`, reject.
|
||||||
|
- c. Otherwise, allow.
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
If type is `m.room.power_levels`:
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
- * For each entry being added, changed or removed in both the `events` and `users` keys:
|
||||||
|
+ * For each entry being added, changed or removed in the `events`, `users`, and `notifications` keys:
|
||||||
|
|
||||||
|
i. If the current value is higher than the `sender`'s current power level, reject.
|
||||||
|
|
||||||
|
ii. If the new value is higher than the `sender`'s current power level, reject.
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
The remaining rules are the same as in [room version
|
||||||
|
3](/rooms/v3#authorization-rules-for-events) (the last inherited room
|
||||||
|
version to specify the authorization rules).
|
||||||
|
|
||||||
|
### Canonical JSON
|
||||||
|
|
||||||
|
Servers MUST strictly enforce the JSON format specified in the
|
||||||
|
[appendices](/appendices#canonical-json). This translates to a
|
||||||
|
400 `M_BAD_JSON` error on most endpoints, or discarding of events over
|
||||||
|
federation. For example, the Federation API's `/send` endpoint would
|
||||||
|
discard the event whereas the Client Server API's `/send/{eventType}`
|
||||||
|
endpoint would return a `M_BAD_JSON` error.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
|||||||
|
{{/*
|
||||||
|
|
||||||
|
Display an alert box of the given type, containing the given content.
|
||||||
|
|
||||||
|
Supported types are "warning", "info", and "rationale".
|
||||||
|
The type determines the colors used in the box and, by default,
|
||||||
|
the title for the box: WARNING, INFO, RATIONALE.
|
||||||
|
|
||||||
|
By passing "omit_title", a caller can suppress the title, and just get
|
||||||
|
a box using the colors and styles for the given type.
|
||||||
|
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{ $type := .type}}
|
||||||
|
{{ $content := .content}}
|
||||||
|
{{ $omit_title := .omit_title }}
|
||||||
|
|
||||||
|
<div class="alert {{ $type }} {{ if $omit_title }}omit-title{{end}}" role="alert">
|
||||||
|
{{ $content | markdownify }}
|
||||||
|
</div>
|
@ -0,0 +1 @@
|
|||||||
|
{{ partial "alert" (dict "type" "note" "content" .Inner) }}
|
@ -0,0 +1 @@
|
|||||||
|
{{ partial "alert" (dict "type" "rationale" "content" .Inner) }}
|
@ -0,0 +1 @@
|
|||||||
|
{{ partial "alert" (dict "type" "warning" "content" .Inner) }}
|
@ -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 }}
|
@ -0,0 +1,26 @@
|
|||||||
|
{{/*
|
||||||
|
|
||||||
|
This template is used to render the table of SAS emoji table.
|
||||||
|
|
||||||
|
It replaces the old {{sas_emoji_table}} template.
|
||||||
|
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{ $emoji_json := readFile "data-definitions/sas-emoji.json" | transform.Unmarshal }}
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Number</th>
|
||||||
|
<th>Emoji</th>
|
||||||
|
<th>Unicode</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
{{ range $emoji_json }}
|
||||||
|
<tr>
|
||||||
|
<td>{{ .number }}</td>
|
||||||
|
<td>{{ .emoji }}</td>
|
||||||
|
<td>{{ .unicode }}</td>
|
||||||
|
<td>{{ .description }}</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
</table>
|
Loading…
Reference in New Issue