diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 0a302b8a..16b1820d 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -1940,3 +1940,692 @@ never succeeds without auth. Homeservers may allow requests that don't require auth by offering a stage with only the `m.login.dummy` auth type, but they must still give a 401 response to requests with no auth data. + +## Modules + +Modules are parts of the Client-Server API which are not universal to +all endpoints. Modules are strictly defined within this specification +and should not be mistaken for experimental extensions or optional +features. A compliant server implementation MUST support all modules and +supporting specification (unless the implementation only targets clients +of certain profiles, in which case only the required modules for those +feature profiles MUST be implemented). A compliant client implementation +MUST support all the required modules and supporting specification for +the [Feature Profile](#feature-profiles) it targets. + +### Feature Profiles + +Matrix supports many different kinds of clients: from embedded IoT +devices to desktop clients. Not all clients can provide the same feature +sets as other clients e.g. due to lack of physical hardware such as not +having a screen. Clients can fall into one of several profiles and each +profile contains a set of features that the client MUST support. This +section details a set of "feature profiles". Clients are expected to +implement a profile in its entirety in order for it to be classified as +that profile. + +#### Summary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Module / ProfileWebMobileDesktopCLIEmbedded
+

Instant Messaging

+
+

Required

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Direct Messaging

+
+

Required

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Mentions

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Optional

+
+

Presence

+
+

Required

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Push Notifications

+
+

Optional

+
+

Required

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Receipts

+
+

Required

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Fully read markers

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Typing Notifications

+
+

Required

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

VoIP

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Optional

+
+

Ignoring Users

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Optional

+
+

Reporting Content

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Content Repository

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Optional

+
+

Managing History Visibility

+
+

Required

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Server Side Search

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Room Upgrades

+
+

Required

+
+

Required

+
+

Required

+
+

Required

+
+

Optional

+
+

Server Administration

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Event Context

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Third Party Networks

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Send-to-Device Messaging

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Device Management

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

End-to-End Encryption

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Guest Accounts

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Room Previews

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Client Config

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

SSO Login

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

OpenID

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Stickers

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Server ACLs

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Server Notices

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Moderation policies

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+

Optional

+
+ +*Please see each module for more details on what clients need to +implement.* + +#### Clients + +##### Stand-alone web (`Web`) + +This is a web page which heavily uses Matrix for communication. +Single-page web apps would be classified as a stand-alone web client, as +would multi-page web apps which use Matrix on nearly every page. + +##### Mobile (`Mobile`) + +This is a Matrix client specifically designed for consumption on mobile +devices. This is typically a mobile app but need not be so provided the +feature set can be reached (e.g. if a mobile site could display push +notifications it could be classified as a mobile client). + +##### Desktop (`Desktop`) + +This is a native GUI application which can run in its own environment +outside a browser. + +##### Command Line Interface (`CLI`) + +This is a client which is used via a text-based terminal. + +##### Embedded (`Embedded`) + +This is a client which is embedded into another application or an +embedded device. + +###### Application + +This is a Matrix client which is embedded in another website, e.g. using +iframes. These embedded clients are typically for a single purpose +related to the website in question, and are not intended to be +fully-fledged communication apps. + +###### Device + +This is a client which is typically running on an embedded device such +as a kettle, fridge or car. These clients tend to perform a few +operations and run in a resource constrained environment. Like embedded +applications, they are not intended to be fully-fledged communication +systems. + +{{% cs-modules %}} diff --git a/content/client-server-api/modules/account_data.md b/content/client-server-api/modules/account_data.md new file mode 100644 index 00000000..1509555f --- /dev/null +++ b/content/client-server-api/modules/account_data.md @@ -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](). diff --git a/content/client-server-api/modules/admin.md b/content/client-server-api/modules/admin.md new file mode 100644 index 00000000..28176bd9 --- /dev/null +++ b/content/client-server-api/modules/admin.md @@ -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}} diff --git a/content/client-server-api/modules/content_repo.md b/content/client-server-api/modules/content_repo.md new file mode 100644 index 00000000..f615e7f7 --- /dev/null +++ b/content/client-server-api/modules/content_repo.md @@ -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:/// + + : The name of the homeserver where this content originated, e.g. matrix.org + : 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. diff --git a/content/client-server-api/modules/device_management.md b/content/client-server-api/modules/device_management.md new file mode 100644 index 00000000..3f49c0e7 --- /dev/null +++ b/content/client-server-api/modules/device_management.md @@ -0,0 +1,28 @@ +--- +type: module +weight: 90 +--- + +### Device Management + +This module provides a means for a user to manage their [devices](). + +#### Client behaviour + +Clients that implement this module should offer the user a list of +registered devices, as well as the means to update their display names. +Clients should also allow users to delete disused devices. + +{{device\_management\_cs\_http\_api}} + +#### Security considerations + +Deleting devices has security implications: it invalidates the +access\_token assigned to the device, so an attacker could use it to log +out the real user (and do it repeatedly every time the real user tries +to log in to block the attacker). Servers should require additional +authentication beyond the access token when deleting devices (for +example, requiring that the user resubmit their password). + +The display names of devices are publicly visible. Clients should +consider advising the user of this. diff --git a/content/client-server-api/modules/dm.md b/content/client-server-api/modules/dm.md new file mode 100644 index 00000000..7b8802ce --- /dev/null +++ b/content/client-server-api/modules/dm.md @@ -0,0 +1,47 @@ +--- +type: module +weight: 230 +--- + +### Direct Messaging + +All communication over Matrix happens within a room. It is sometimes +desirable to offer users the concept of speaking directly to one +particular person. This module defines a way of marking certain rooms as +'direct chats' with a given person. This does not restrict the chat to +being between exactly two people since this would preclude the presence +of automated 'bot' users or even a 'personal assistant' who is able to +answer direct messages on behalf of the user in their absence. + +A room may not necessarily be considered 'direct' by all members of the +room, but a signalling mechanism exists to propagate the information of +whether a chat is 'direct' to an invitee. + +#### Events + +{{m\_direct\_event}} + +#### Client behaviour + +To start a direct chat with another user, the inviting user's client +should set the `is_direct` flag to \_. The client should do this +whenever the flow the user has followed is one where their intention is +to speak directly with another person, as opposed to bringing that +person in to a shared room. For example, clicking on 'Start Chat' beside +a person's profile picture would imply the `is_direct` flag should be +set. + +The invitee's client may use the `is_direct` flag in the +[m.room.member]() event to automatically mark the room as a direct chat +but this is not required: it may for example, prompt the user, or ignore +the flag altogether. + +Both the inviting client and the invitee's client should record the fact +that the room is a direct chat by storing an `m.direct` event in the +account data using \_. + +#### Server behaviour + +When the `is_direct` flag is given to \_, the home server must set the +`is_direct` flag in the invite member event for any users invited in the +\_ call. diff --git a/content/client-server-api/modules/end_to_end_encryption.md b/content/client-server-api/modules/end_to_end_encryption.md new file mode 100644 index 00000000..598c5c9f --- /dev/null +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -0,0 +1,1584 @@ +--- +type: module +weight: 100 +--- + +### End-to-End Encryption + +Matrix optionally supports end-to-end encryption, allowing rooms to be +created whose conversation contents are not decryptable or interceptable +on any of the participating homeservers. + +#### Key Distribution + +Encryption and Authentication in Matrix is based around public-key +cryptography. The Matrix protocol provides a basic mechanism for +exchange of public keys, though an out-of-band channel is required to +exchange fingerprints between users to build a web of trust. + +##### Overview + + 1) Bob publishes the public keys and supported algorithms for his + device. This may include long-term identity keys, and/or one-time + keys. + + +----------+ +--------------+ + | Bob's HS | | Bob's Device | + +----------+ +--------------+ + | | + |<=============| + /keys/upload + + 2) Alice requests Bob's public identity keys and supported algorithms. + + +----------------+ +------------+ +----------+ + | Alice's Device | | Alice's HS | | Bob's HS | + +----------------+ +------------+ +----------+ + | | | + |=================>|==============>| + /keys/query + + 3) Alice selects an algorithm and claims any one-time keys needed. + + +----------------+ +------------+ +----------+ + | Alice's Device | | Alice's HS | | Bob's HS | + +----------------+ +------------+ +----------+ + | | | + |=================>|==============>| + /keys/claim + +##### Key algorithms + +The name `ed25519` corresponds to the +[Ed25519](http://ed25519.cr.yp.to/) signature algorithm. The key is a +32-byte Ed25519 public key, encoded using [unpadded Base64](). Example: + + "SogYyrkTldLz0BXP+GYWs0qaYacUI0RleEqNT8J3riQ" + +The name `curve25519` corresponds to the +[Curve25519](https://cr.yp.to/ecdh.html) ECDH algorithm. The key is a +32-byte Curve25519 public key, encoded using [unpadded Base64](). +Example: + + "JGLn/yafz74HB2AbPLYJWIVGnKAtqECOBf11yyXac2Y" + +The name `signed_curve25519` also corresponds to the Curve25519 +algorithm, but a key using this algorithm is represented by an object +with the following properties: + +`KeyObject` + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

key

string

Required. The unpadded Base64-encoded 32-byte Curve25519 public key.

signatures

Signatures

Required. Signatures of the key object.

+

The signature is calculated using the process described at Signing JSON.

+ +Example: + + { + "key":"06UzBknVHFMwgi7AVloY7ylC+xhOhEX4PkNge14Grl8", + "signatures": { + "@user:example.com": { + "ed25519:EGURVBUNJP": "YbJva03ihSj5mPk+CHMJKUKlCXCPFXjXOK6VqBnN9nA2evksQcTGn6hwQfrgRHIDDXO2le49x7jnWJHMJrJoBQ" + } + } + } + +##### Device keys + +Each device should have one Ed25519 signing key. This key should be +generated on the device from a cryptographically secure source, and the +private part of the key should never be exported from the device. This +key is used as the fingerprint for a device by other clients. + +A device will generally need to generate a number of additional keys. +Details of these will vary depending on the messaging algorithm in use. + +Algorithms generally require device identity keys as well as signing +keys. Some algorithms also require one-time keys to improve their +secrecy and deniability. These keys are used once during session +establishment, and are then thrown away. + +For Olm version 1, each device requires a single Curve25519 identity +key, and a number of signed Curve25519 one-time keys. + +##### Uploading keys + +A device uploads the public parts of identity keys to their homeserver +as a signed JSON object, using the `/keys/upload`\_ API. The JSON object +must include the public part of the device's Ed25519 key, and must be +signed by that key, as described in [Signing +JSON](../appendices.html#signing-json). + +One-time keys are also uploaded to the homeserver using the +`/keys/upload`\_ API. + +Devices must store the private part of each key they upload. They can +discard the private part of a one-time key when they receive a message +using that key. However it's possible that a one-time key given out by a +homeserver will never be used, so the device that generates the key will +never know that it can discard the key. Therefore a device could end up +trying to store too many private keys. A device that is trying to store +too many private keys may discard keys starting with the oldest. + +##### Tracking the device list for a user + +Before Alice can send an encrypted message to Bob, she needs a list of +each of his devices and the associated identity keys, so that she can +establish an encryption session with each device. This list can be +obtained by calling `/keys/query`\_, passing Bob's user ID in the +`device_keys` parameter. + +From time to time, Bob may add new devices, and Alice will need to know +this so that she can include his new devices for later encrypted +messages. A naive solution to this would be to call `/keys/query`\_ +before sending each message -however, the number of users and devices +may be large and this would be inefficient. + +It is therefore expected that each client will maintain a list of +devices for a number of users (in practice, typically each user with +whom we share an encrypted room). Furthermore, it is likely that this +list will need to be persisted between invocations of the client +application (to preserve device verification data and to alert Alice if +Bob suddenly gets a new device). + +Alice's client can maintain a list of Bob's devices via the following +process: + +1. It first sets a flag to record that it is now tracking Bob's device + list, and a separate flag to indicate that its list of Bob's devices + is outdated. Both flags should be in storage which persists over + client restarts. +2. It then makes a request to `/keys/query`\_, passing Bob's user ID in + the `device_keys` parameter. When the request completes, it stores + the resulting list of devices in persistent storage, and clears the + 'outdated' flag. +3. During its normal processing of responses to \_, Alice's client + inspects the `changed` property of the `device_lists`\_ field. If it + is tracking the device lists of any of the listed users, then it + marks the device lists for those users outdated, and initiates + another request to `/keys/query`\_ for them. +4. Periodically, Alice's client stores the `next_batch` field of the + result from \_ in persistent storage. If Alice later restarts her + client, it can obtain a list of the users who have updated their + device list while it was offline by calling `/keys/changes`\_, + passing the recorded `next_batch` field as the `from` parameter. If + the client is tracking the device list of any of the users listed in + the response, it marks them as outdated. It combines this list with + those already flagged as outdated, and initiates a `/keys/query`\_ + request for all of them. + +Warning + +Bob may update one of his devices while Alice has a request to +`/keys/query` in flight. Alice's client may therefore see Bob's user ID +in the `device_lists` field of the `/sync` response while the first +request is in flight, and initiate a second request to `/keys/query`. +This may lead to either of two related problems. + +The first problem is that, when the first request completes, the client +will clear the 'outdated' flag for Bob's devices. If the second request +fails, or the client is shut down before it completes, this could lead +to Alice using an outdated list of Bob's devices. + +The second possibility is that, under certain conditions, the second +request may complete *before* the first one. When the first request +completes, the client could overwrite the later results from the second +request with those from the first request. + +Clients MUST guard against these situations. For example, a client could +ensure that only one request to `/keys/query` is in flight at a time for +each user, by queuing additional requests until the first completes. +Alternatively, the client could make a new request immediately, but +ensure that the first request's results are ignored (possibly by +cancelling the request). + +Note + +When Bob and Alice share a room, with Bob tracking Alice's devices, she +may leave the room and then add a new device. Bob will not be notified +of this change, as he doesn't share a room anymore with Alice. When they +start sharing a room again, Bob has an out-of-date list of Alice's +devices. In order to address this issue, Bob's homeserver will add +Alice's user ID to the `changed` property of the `device_lists` field, +thus Bob will update his list of Alice's devices as part of his normal +processing. Note that Bob can also be notified when he stops sharing any +room with Alice by inspecting the `left` property of the `device_lists` +field, and as a result should remove her from its list of tracked users. + +##### Sending encrypted attachments + +When encryption is enabled in a room, files should be uploaded encrypted +on the homeserver. + +In order to achieve this, a client should generate a single-use 256-bit +AES key, and encrypt the file using AES-CTR. The counter should be +64-bit long, starting at 0 and prefixed by a random 64-bit +Initialization Vector (IV), which together form a 128-bit unique counter +block. + +Warning + +An IV must never be used multiple times with the same key. This implies +that if there are multiple files to encrypt in the same message, +typically an image and its thumbnail, the files must not share both the +same key and IV. + +Then, the encrypted file can be uploaded to the homeserver. The key and +the IV must be included in the room event along with the resulting +`mxc://` in order to allow recipients to decrypt the file. As the event +containing those will be Megolm encrypted, the server will never have +access to the decrypted file. + +A hash of the ciphertext must also be included, in order to prevent the +homeserver from changing the file content. + +A client should send the data as an encrypted `m.room.message` event, +using either `m.file` as the msgtype, or the appropriate msgtype for the +file type. The key is sent using the [JSON Web +Key](https://tools.ietf.org/html/rfc7517#appendix-A.3) format, with a +[W3C extension](https://w3c.github.io/webcrypto/#iana-section-jwk). + +Extensions to `m.room.message` msgtypes +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +This module adds `file` and `thumbnail_file` properties, of type +`EncryptedFile`, to `m.room.message` msgtypes that reference files, such +as [m.file]() and [m.image](), replacing the `url` and `thumbnail_url` +properties. + +`EncryptedFile` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
urlstringRequired. The URL to the file.
keyJWKRequired. A JSON Web Key object.

iv

string

Required. The 128-bit unique counter block used by AES-CTR, encoded as unpadded base64.

hashes

{string: string}

Required. A map from an algorithm name to a hash of the ciphertext, encoded as unpadded base64. Clients should support the SHA-256 hash, which uses the key sha256.

v

string

Required. Version of the encrypted attachments protocol. Must be v2.

+ +`JWK` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
ktystringRequired. Key type. Must be oct.

key_ops

[string]

Required. Key operations. Must at least contain encrypt and decrypt.

algstringRequired. Algorithm. Must be A256CTR.
kstringRequired. The key, encoded as urlsafe unpadded base64.

ext

boolean

Required. Extractable. Must be true. This is a W3C extension.

+ +Example: + +##### Claiming one-time keys + +A client wanting to set up a session with another device can claim a +one-time key for that device. This is done by making a request to the +`/keys/claim`\_ API. + +A homeserver should rate-limit the number of one-time keys that a given +user or remote server can claim. A homeserver should discard the public +part of a one time key once it has given that key to another user. + +#### Device verification + +Before Alice sends Bob encrypted data, or trusts data received from him, +she may want to verify that she is actually communicating with him, +rather than a man-in-the-middle. This verification process requires an +out-of-band channel: there is no way to do it within Matrix without +trusting the administrators of the homeservers. + +In Matrix, verification works by Alice meeting Bob in person, or +contacting him via some other trusted medium, and use [SAS +Verification](#SAS Verification) to interactively verify Bob's devices. +Alice and Bob may also read aloud their unpadded base64 encoded Ed25519 +public key, as returned by `/keys/query`. + +Device verification may reach one of several conclusions. For example: + +- Alice may "accept" the device. This means that she is satisfied that + the device belongs to Bob. She can then encrypt sensitive material + for that device, and knows that messages received were sent from + that device. +- Alice may "reject" the device. She will do this if she knows or + suspects that Bob does not control that device (or equivalently, + does not trust Bob). She will not send sensitive material to that + device, and cannot trust messages apparently received from it. +- Alice may choose to skip the device verification process. She is not + able to verify that the device actually belongs to Bob, but has no + reason to suspect otherwise. The encryption protocol continues to + protect against passive eavesdroppers. + +Note + +Once the signing key has been verified, it is then up to the encryption +protocol to verify that a given message was sent from a device holding +that Ed25519 private key, or to encrypt a message so that it may only be +decrypted by such a device. For the Olm protocol, this is documented at +. + +##### Key verification framework + +Verifying keys manually by reading out the Ed25519 key is not very +user-friendly, and can lead to errors. In order to help mitigate errors, +and to make the process easier for users, some verification methods are +supported by the specification. The methods all use a common framework +for negotiating the key verification. + +To use this framework, Alice's client would send +`m.key.verification.request` events to Bob's devices. All of the +`to_device` messages sent to Bob MUST have the same `transaction_id` to +indicate they are part of the same request. This allows Bob to reject +the request on one device, and have it apply to all of his devices. +Similarly, it allows Bob to process the verification on one device +without having to involve all of his devices. + +When Bob's device receives an `m.key.verification.request`, it should +prompt Bob to verify keys with Alice using one of the supported methods +in the request. If Bob's device does not understand any of the methods, +it should not cancel the request as one of his other devices may support +the request. Instead, Bob's device should tell Bob that an unsupported +method was used for starting key verification. The prompt for Bob to +accept/reject Alice's request (or the unsupported method prompt) should +be automatically dismissed 10 minutes after the `timestamp` field or 2 +minutes after Bob's client receives the message, whichever comes first, +if Bob does not interact with the prompt. The prompt should additionally +be hidden if an appropriate `m.key.verification.cancel` message is +received. + +If Bob rejects the request, Bob's client must send an +`m.key.verification.cancel` message to Alice's device. Upon receipt, +Alice's device should tell her that Bob does not want to verify her +device and send `m.key.verification.cancel` messages to all of Bob's +devices to notify them that the request was rejected. + +If Bob accepts the request, Bob's device starts the key verification +process by sending an `m.key.verification.start` message to Alice's +device. Upon receipt of this message, Alice's device should send an +`m.key.verification.cancel` message to all of Bob's other devices to +indicate the process has been started. The start message must use the +same `transaction_id` from the original key verification request if it +is in response to the request. The start message can be sent +independently of any request. + +Individual verification methods may add additional steps, events, and +properties to the verification messages. Event types for methods defined +in this specification must be under the `m.key.verification` namespace +and any other event types must be namespaced according to the Java +package naming convention. + +Any of Alice's or Bob's devices can cancel the key verification request +or process at any time with an `m.key.verification.cancel` message to +all applicable devices. + +This framework yields the following handshake, assuming both Alice and +Bob each have 2 devices, Bob's first device accepts the key verification +request, and Alice's second device initiates the request. Note how +Alice's first device is not involved in the request or verification +process. + + +---------------+ +---------------+ +-------------+ +-------------+ + | AliceDevice1 | | AliceDevice2 | | BobDevice1 | | BobDevice2 | + +---------------+ +---------------+ +-------------+ +-------------+ + | | | | + | | m.key.verification.request | | + | |---------------------------------->| | + | | | | + | | m.key.verification.request | | + | |-------------------------------------------------->| + | | | | + | | m.key.verification.start | | + | |<----------------------------------| | + | | | | + | | m.key.verification.cancel | | + | |-------------------------------------------------->| + | | | | + +After the handshake, the verification process begins. + +{{m\_key\_verification\_request\_event}} + +{{m\_key\_verification\_start\_event}} + +{{m\_key\_verification\_cancel\_event}} + +##### Short Authentication String (SAS) verification + +SAS verification is a user-friendly key verification process built off +the common framework outlined above. SAS verification is intended to be +a highly interactive process for users, and as such exposes verification +methods which are easier for users to use. + +The verification process is heavily inspired by Phil Zimmermann's ZRTP +key agreement handshake. A key part of key agreement in ZRTP is the hash +commitment: the party that begins the Diffie-Hellman key sharing sends a +hash of their part of the Diffie-Hellman exchange, and does not send +their part of the Diffie-Hellman exchange until they have received the +other party's part. Thus an attacker essentially only has one attempt to +attack the Diffie-Hellman exchange, and hence we can verify fewer bits +while still achieving a high degree of security: if we verify n bits, +then an attacker has a 1 in 2n chance of success. For +example, if we verify 40 bits, then an attacker has a 1 in +1,099,511,627,776 chance (or less than 1 in 1012 chance) of +success. A failed attack would result in a mismatched Short +Authentication String, alerting users to the attack. + +The verification process takes place over [to-device]() messages in two +phases: + +1. Key agreement phase (based on [ZRTP key + agreement](https://tools.ietf.org/html/rfc6189#section-4.4.1)). +2. Key verification phase (based on HMAC). + +The process between Alice and Bob verifying each other would be: + +1. Alice and Bob establish a secure out-of-band connection, such as + meeting in-person or a video call. "Secure" here means that either + party cannot be impersonated, not explicit secrecy. +2. Alice and Bob communicate which devices they'd like to verify with + each other. +3. Alice selects Bob's device from the device list and begins + verification. +4. Alice's client ensures it has a copy of Bob's device key. +5. Alice's device sends Bob's device an `m.key.verification.start` + message. +6. Bob's device receives the message and selects a key agreement + protocol, hash algorithm, message authentication code, and SAS + method supported by Alice's device. +7. Bob's device ensures it has a copy of Alice's device key. +8. Bob's device creates an ephemeral Curve25519 key pair + (*K**B**p**r**i**v**a**t**e*, *K**B**p**u**b**l**i**c*), + and calculates the hash (using the chosen algorithm) of the public + key *K**B**p**u**b**l**i**c*. +9. Bob's device replies to Alice's device with an + `m.key.verification.accept` message. +10. Alice's device receives Bob's message and stores the commitment hash + for later use. +11. Alice's device creates an ephemeral Curve25519 key pair + (*K**A**p**r**i**v**a**t**e*, *K**A**p**u**b**l**i**c*) + and replies to Bob's device with an `m.key.verification.key`, + sending only the public key + *K**A**p**u**b**l**i**c*. +12. Bob's device receives Alice's message and replies with its own + `m.key.verification.key` message containing its public key + *K**B**p**u**b**l**i**c*. +13. Alice's device receives Bob's message and verifies the commitment + hash from earlier matches the hash of the key Bob's device just sent + and the content of Alice's `m.key.verification.start` message. +14. Both Alice and Bob's devices perform an Elliptic-curve + Diffie-Hellman + (*E**C**D**H*(*K**A**p**r**i**v**a**t**e*, *K**B**p**u**b**l**i**c*)), + using the result as the shared secret. +15. Both Alice and Bob's devices display a SAS to their users, which is + derived from the shared key using one of the methods in this + section. If multiple SAS methods are available, clients should allow + the users to select a method. +16. Alice and Bob compare the strings shown by their devices, and tell + their devices if they match or not. +17. Assuming they match, Alice and Bob's devices calculate the HMAC of + their own device keys and a comma-separated sorted list of the key + IDs that they wish the other user to verify, using SHA-256 as the + hash function. HMAC is defined in [RFC + 2104](https://tools.ietf.org/html/rfc2104). The key for the HMAC is + different for each item and is calculated by generating 32 bytes + (256 bits) using [the key verification HKDF](#sas-hkdf). +18. Alice's device sends Bob's device an `m.key.verification.mac` + message containing the MAC of Alice's device keys and the MAC of her + key IDs to be verified. Bob's device does the same for Bob's device + keys and key IDs concurrently with Alice. +19. When the other device receives the `m.key.verification.mac` message, + the device calculates the HMAC of its copies of the other device's + keys given in the message, as well as the HMAC of the + comma-separated, sorted, list of key IDs in the message. The device + compares these with the HMAC values given in the message, and if + everything matches then the device keys are verified. + +The wire protocol looks like the following between Alice and Bob's +devices: + + +-------------+ +-----------+ + | AliceDevice | | BobDevice | + +-------------+ +-----------+ + | | + | m.key.verification.start | + |-------------------------------->| + | | + | m.key.verification.accept | + |<--------------------------------| + | | + | m.key.verification.key | + |-------------------------------->| + | | + | m.key.verification.key | + |<--------------------------------| + | | + | m.key.verification.mac | + |-------------------------------->| + | | + | m.key.verification.mac | + |<--------------------------------| + | | + +###### Error and exception handling + +At any point the interactive verification can go wrong. The following +describes what to do when an error happens: + +- Alice or Bob can cancel the verification at any time. An + `m.key.verification.cancel` message must be sent to signify the + cancellation. +- The verification can time out. Clients should time out a + verification that does not complete within 10 minutes. Additionally, + clients should expire a `transaction_id` which goes unused for 10 + minutes after having last sent/received it. The client should inform + the user that the verification timed out, and send an appropriate + `m.key.verification.cancel` message to the other device. +- When the same device attempts to initiate multiple verification + attempts, the recipient should cancel all attempts with that device. +- When a device receives an unknown `transaction_id`, it should send + an appropriate `m.key.verification.cancel` message to the other + device indicating as such. This does not apply for inbound + `m.key.verification.start` or `m.key.verification.cancel` messages. +- If the two devices do not share a common key share, hash, HMAC, or + SAS method then the device should notify the other device with an + appropriate `m.key.verification.cancel` message. +- If the user claims the Short Authentication Strings do not match, + the device should send an appropriate `m.key.verification.cancel` + message to the other device. +- If the device receives a message out of sequence or that it was not + expecting, it should notify the other device with an appropriate + `m.key.verification.cancel` message. + +###### Verification messages specific to SAS + +Building off the common framework, the following events are involved in +SAS verification. + +The `m.key.verification.cancel` event is unchanged, however the +following error codes are used in addition to those already specified: + +- `m.unknown_method`: The devices are unable to agree on the key + agreement, hash, MAC, or SAS method. +- `m.mismatched_commitment`: The hash commitment did not match. +- `m.mismatched_sas`: The SAS did not match. + +{{m\_key\_verification\_start\_m\_sas\_v1\_event}} + +{{m\_key\_verification\_accept\_event}} + +{{m\_key\_verification\_key\_event}} + +{{m\_key\_verification\_mac\_event}} + +###### HKDF calculation + +In all of the SAS methods, HKDF is as defined in [RFC +5869](https://tools.ietf.org/html/rfc5869) and uses the previously +agreed-upon hash function for the hash function. The shared secret is +supplied as the input keying material. No salt is used. When the +`key_agreement_protocol` is `curve25519-hkdf-sha256`, the info parameter +is the concatenation of: + +> - The string `MATRIX_KEY_VERIFICATION_SAS|`. +> - The Matrix ID of the user who sent the `m.key.verification.start` +> message, followed by `|`. +> - The Device ID of the device which sent the +> `m.key.verification.start` message, followed by `|`. +> - The public key from the `m.key.verification.key` message sent by +> the device which sent the `m.key.verification.start` message, +> followed by `|`. +> - The Matrix ID of the user who sent the `m.key.verification.accept` +> message, followed by `|`. +> - The Device ID of the device which sent the +> `m.key.verification.accept` message, followed by `|`. +> - The public key from the `m.key.verification.key` message sent by +> the device which sent the `m.key.verification.accept` message, +> followed by `|`. +> - The `transaction_id` being used. + +When the `key_agreement_protocol` is the deprecated method `curve25519`, +the info parameter is the concatenation of: + +> - The string `MATRIX_KEY_VERIFICATION_SAS`. +> - The Matrix ID of the user who sent the `m.key.verification.start` +> message. +> - The Device ID of the device which sent the +> `m.key.verification.start` message. +> - The Matrix ID of the user who sent the `m.key.verification.accept` +> message. +> - The Device ID of the device which sent the +> `m.key.verification.accept` message. +> - The `transaction_id` being used. + +New implementations are discouraged from implementing the `curve25519` +method. + +Rationale + +HKDF is used over the plain shared secret as it results in a harder +attack as well as more uniform data to work with. + +For verification of each party's device keys, HKDF is as defined in RFC +5869 and uses SHA-256 as the hash function. The shared secret is +supplied as the input keying material. No salt is used, and in the info +parameter is the concatenation of: + +> - The string `MATRIX_KEY_VERIFICATION_MAC`. +> - The Matrix ID of the user whose key is being MAC-ed. +> - The Device ID of the device sending the MAC. +> - The Matrix ID of the other user. +> - The Device ID of the device receiving the MAC. +> - The `transaction_id` being used. +> - The Key ID of the key being MAC-ed, or the string `KEY_IDS` if the +> item being MAC-ed is the list of key IDs. + +###### SAS method: `decimal` + +Generate 5 bytes using [HKDF](#sas-hkdf) then take sequences of 13 bits +to convert to decimal numbers (resulting in 3 numbers between 0 and 8191 +inclusive each). Add 1000 to each calculated number. + +The bitwise operations to get the numbers given the 5 bytes +*B*0, *B*1, *B*2, *B*3, *B*4 +would be: + +- First: (*B*0 ≪ 5|*B*1 ≫ 3) + 1000 +- Second: + ((*B*1&0*x*7) ≪ 10|*B*2 ≪ 2|*B*3 ≫ 6) + 1000 +- Third: ((*B*3&0*x*3*F*) ≪ 7|*B*4 ≫ 1) + 1000 + +The digits are displayed to the user either with an appropriate +separator, such as dashes, or with the numbers on individual lines. + +###### SAS method: `emoji` + +Generate 6 bytes using [HKDF](#sas-hkdf) then split the first 42 bits +into 7 groups of 6 bits, similar to how one would base64 encode +something. Convert each group of 6 bits to a number and use the +following table to get the corresponding emoji: + +{{sas\_emoji\_table}} + +Note + +This table is available as JSON at + + +Rationale + +The emoji above were chosen to: + +- Be recognisable without colour. +- Be recognisable at a small size. +- Be recognisable by most cultures. +- Be distinguishable from each other. +- Easily described by a few words. +- Avoid symbols with negative connotations. +- Be likely similar across multiple platforms. + +Clients SHOULD show the emoji with the descriptions from the table, or +appropriate translation of those descriptions. Client authors SHOULD +collaborate to create a common set of translations for all languages. + +Note + +Known translations for the emoji are available from + +and can be translated online: + + +##### Cross-signing + +Rather than requiring Alice to verify each of Bob's devices with each of +her own devices and vice versa, the cross-signing feature allows users +to sign their device keys such that Alice and Bob only need to verify +once. With cross-signing, each user has a set of cross-signing keys that +are used to sign their own device keys and other users' keys, and can be +used to trust device keys that were not verified directly. + +Each user has three ed25519 key pairs for cross-signing: + +- a master key (MSK) that serves as the user's identity in + cross-signing and signs their other cross-signing keys; +- a user-signing key (USK) -- only visible to the user that it belongs + to --that signs other users' master keys; and +- a self-signing key (SSK) that signs the user's own device keys. + +The master key may also be used to sign other items such as the backup +key. The master key may also be signed by the user's own device keys to +aid in migrating from device verifications: if Alice's device had +previously verified Bob's device and Bob's device has signed his master +key, then Alice's device can trust Bob's master key, and she can sign it +with her user-signing key. + +Users upload their cross-signing keys to the server using [POST +/\_matrix/client/r0/keys/device\_signing/upload](). When Alice uploads +new cross-signing keys, her user ID will appear in the `changed` +property of the `device_lists` field of the `/sync` of response of all +users who share an encrypted room with her. When Bob sees Alice's user +ID in his `/sync`, he will call [POST /\_matrix/client/r0/keys/query]() +to retrieve Alice's device and cross-signing keys. + +If Alice has a device and wishes to send an encrypted message to Bob, +she can trust Bob's device if: + +- Alice's device is using a master key that has signed her + user-signing key, +- Alice's user-signing key has signed Bob's master key, +- Bob's master key has signed Bob's self-signing key, and +- Bob's self-signing key has signed Bob's device key. + +The following diagram illustrates how keys are signed: + + +------------------+ .................. +----------------+ + | +--------------+ | .................. : | +------------+ | + | | v v v : : v v v | | + | | +-----------+ : : +-----------+ | | + | | | Alice MSK | : : | Bob MSK | | | + | | +-----------+ : : +-----------+ | | + | | | : : : : | | | + | | +--+ :... : : ...: +--+ | | + | | v v : : v v | | + | | +-----------+ ............. : : ............. +-----------+ | | + | | | Alice SSK | : Alice USK : : : : Bob USK : | Bob SSK | | | + | | +-----------+ :...........: : : :...........: +-----------+ | | + | | | ... | : : : : | ... | | | + | | V V :........: :........: V V | | + | | +---------+ -+ +---------+ -+ | | + | | | Devices | ...| | Devices | ...| | | + | | +---------+ -+ +---------+ -+ | | + | | | ... | | ... | | | + | +------+ | | +----+ | + +----------------+ +--------------+ + +In the diagram, boxes represent keys and lines represent signatures with +the arrows pointing from the signing key to the key being signed. Dotted +boxes and lines represent keys and signatures that are only visible to +the user who created them. + +The following diagram illustrates Alice's view, hiding the keys and +signatures that she cannot see: + + +------------------+ +----------------+ +----------------+ + | +--------------+ | | | | +------------+ | + | | v v | v v v | | + | | +-----------+ | +-----------+ | | + | | | Alice MSK | | | Bob MSK | | | + | | +-----------+ | +-----------+ | | + | | | | | | | | + | | +--+ +--+ | +--+ | | + | | v v | v | | + | | +-----------+ +-----------+ | +-----------+ | | + | | | Alice SSK | | Alice USK | | | Bob SSK | | | + | | +-----------+ +-----------+ | +-----------+ | | + | | | ... | | | | ... | | | + | | V V +--------+ V V | | + | | +---------+ -+ +---------+ -+ | | + | | | Devices | ...| | Devices | ...| | | + | | +---------+ -+ +---------+ -+ | | + | | | ... | | ... | | | + | +------+ | | +----+ | + +----------------+ +--------------+ + +[Verification methods](#device-verification) can be used to verify a +user's master key by using the master public key, encoded using unpadded +base64, as the device ID, and treating it as a normal device. For +example, if Alice and Bob verify each other using SAS, Alice's +`m.key.verification.mac` message to Bob may include +`"ed25519:alices+master+public+key": "alices+master+public+key"` in the +`mac` property. Servers therefore must ensure that device IDs will not +collide with cross-signing public keys. + +###### Key and signature security + +A user's master key could allow an attacker to impersonate that user to +other users, or other users to that user. Thus clients must ensure that +the private part of the master key is treated securely. If clients do +not have a secure means of storing the master key (such as a secret +storage system provided by the operating system), then clients must not +store the private part. + +If a user's client sees that any other user has changed their master +key, that client must notify the user about the change before allowing +communication between the users to continue. + +A user's user-signing and self-signing keys are intended to be easily +replaceable if they are compromised by re-issuing a new key signed by +the user's master key and possibly by re-verifying devices or users. +However, doing so relies on the user being able to notice when their +keys have been compromised, and it involves extra work for the user, and +so although clients do not have to treat the private parts as +sensitively as the master key, clients should still make efforts to +store the private part securely, or not store it at all. Clients will +need to balance the security of the keys with the usability of signing +users and devices when performing key verification. + +To avoid leaking of social graphs, servers will only allow users to see: + +- signatures made by the user's own master, self-signing or + user-signing keys, +- signatures made by the user's own devices about their own master + key, +- signatures made by other users' self-signing keys about their + respective devices, +- signatures made by other users' master keys about their respective + self-signing key, or +- signatures made by other users' devices about their respective + master keys. + +Users will not be able to see signatures made by other users' +user-signing keys. + +{{cross\_signing\_cs\_http\_api}} + +#### Sharing keys between devices + +If Bob has an encrypted conversation with Alice on his computer, and +then logs in through his phone for the first time, he may want to have +access to the previously exchanged messages. To address this issue, +several methods are provided to allow users to transfer keys from one +device to another. + +##### Key requests + +When a device is missing keys to decrypt messages, it can request the +keys by sending [m.room\_key\_request]() to-device messages to other +devices with `action` set to `request`. + +If a device wishes to share the keys with that device, it can forward +the keys to the first device by sending an encrypted +[m.forwarded\_room\_key]() to-device message. The first device should +then send an [m.room\_key\_request]() to-device message with `action` +set to `request_cancellation` to the other devices that it had +originally sent the key request to; a device that receives a +`request_cancellation` should disregard any previously-received +`request` message with the same `request_id` and `requesting_device_id`. + +If a device does not wish to share keys with that device, it can +indicate this by sending an [m.room\_key.withheld]() to-device message, +as described in [Reporting that decryption keys are +withheld](#reporting-that-decryption-keys-are-withheld). + +Note + +Key sharing can be a big attack vector, thus it must be done very +carefully. A reasonable strategy is for a user's client to only send +keys requested by the verified devices of the same user. + +##### Server-side key backups + +Devices may upload encrypted copies of keys to the server. When a device +tries to read a message that it does not have keys for, it may request +the key from the server and decrypt it. Backups are per-user, and users +may replace backups with new backups. + +In contrast with [Key requests](#key-requests), Server-side key backups +do not require another device to be online from which to request keys. +However, as the session keys are stored on the server encrypted, it +requires users to enter a decryption key to decrypt the session keys. + +To create a backup, a client will call [POST +/\_matrix/client/r0/room\_keys/version]() and define how the keys are to +be encrypted through the backup's `auth_data`; other clients can +discover the backup by calling [GET +/\_matrix/client/r0/room\_keys/version](). Keys are encrypted according +to the backup's `auth_data` and added to the backup by calling [PUT +/\_matrix/client/r0/room\_keys/keys]() or one of its variants, and can +be retrieved by calling [GET /\_matrix/client/r0/room\_keys/keys]() or +one of its variants. Keys can only be written to the most recently +created version of the backup. Backups can also be deleted using [DELETE +/\_matrix/client/r0/room\_keys/version/{version}](), or individual keys +can be deleted using [DELETE /\_matrix/client/r0/room\_keys/keys]() or +one of its variants. + +Clients must only store keys in backups after they have ensured that the +`auth_data` is trusted, either by checking the signatures on it, or by +deriving the public key from a private key that it obtained from a +trusted source. + +When a client uploads a key for a session that the server already has a +key for, the server will choose to either keep the existing key or +replace it with the new key based on the key metadata as follows: + +- if the keys have different values for `is_verified`, then it will + keep the key that has `is_verified` set to `true`; +- if they have the same values for `is_verified`, then it will keep + the key with a lower `first_message_index`; +- and finally, is `is_verified` and `first_message_index` are equal, + then it will keep the key with a lower `forwarded_count`. + +###### Recovery key + +If the recovery key (the private half of the backup encryption key) is +presented to the user to save, it is presented as a string constructed +as follows: + +1. The 256-bit curve25519 private key is prepended by the bytes `0x8B` + and `0x01` +2. All the bytes in the string above, including the two header bytes, + are XORed together to form a parity byte. This parity byte is + appended to the byte string. +3. The byte string is encoded using base58, using the same [mapping as + is used for Bitcoin + addresses](https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart), + that is, using the alphabet + `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. +4. A space should be added after every 4th character. + +When reading in a recovery key, clients must disregard whitespace, and +perform the reverse of steps 1 through 3. + +###### Backup algorithm: `m.megolm_backup.v1.curve25519-aes-sha2` + +When a backup is created with the `algorithm` set to +`m.megolm_backup.v1.curve25519-aes-sha2`, the `auth_data` should have +the following format: + +`AuthData` + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

public_key

string

Required. The curve25519 public key used to encrypt the backups, encoded in unpadded base64.

signatures

Signatures

Optional. Signatures of the auth_data, as Signed JSON

+ +The `session_data` field in the backups is constructed as follows: + +1. Encode the session key to be backed up as a JSON object with the + properties: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

algorithm

string

Required. The end-to-end message encryption algorithm that the key is for. Must be m.megolm.v1.aes-sha2.

forwarding_curve25519_key_chain

[string]

Required. Chain of Curve25519 keys through which this session was forwarded, via m.forwarded_room_key events.

sender_key

string

Required. Unpadded base64-encoded device curve25519 key.

sender_claimed_keys

{string: string}

Required. A map from algorithm name (ed25519) to the identity key for the sending device.

session_key

string

Required. Unpadded base64-encoded session key in session-sharing format.

+ +2. Generate an ephemeral curve25519 key, and perform an ECDH with the + ephemeral key and the backup's public key to generate a shared + secret. The public half of the ephemeral key, encoded using unpadded + base64, becomes the `ephemeral` property of the `session_data`. + +3. Using the shared secret, generate 80 bytes by performing an HKDF + using SHA-256 as the hash, with a salt of 32 bytes of 0, and with + the empty string as the info. The first 32 bytes are used as the AES + key, the next 32 bytes are used as the MAC key, and the last 16 + bytes are used as the AES initialization vector. + +4. Stringify the JSON object, and encrypt it using AES-CBC-256 with + PKCS\#7 padding. This encrypted data, encoded using unpadded base64, + becomes the `ciphertext` property of the `session_data`. + +5. Pass the raw encrypted data (prior to base64 encoding) through + HMAC-SHA-256 using the MAC key generated above. The first 8 bytes of + the resulting MAC are base64-encoded, and become the `mac` property + of the `session_data`. + +{{key\_backup\_cs\_http\_api}} + +##### Key exports + +Keys can be manually exported from one device to an encrypted file, +copied to another device, and imported. The file is encrypted using a +user-supplied passphrase, and is created as follows: + +1. Encode the sessions as a JSON object, formatted as described in [Key + export format](#key-export-format). + +2. Generate a 512-bit key from the user-entered passphrase by computing + [PBKDF2](https://tools.ietf.org/html/rfc2898#section-5.2)(HMAC-SHA-512, + passphrase, S, N, 512), where S is a 128-bit + cryptographically-random salt and N is the number of rounds. N + should be at least 100,000. The keys K and K' are set to the first + and last 256 bits of this generated key, respectively. K is used as + an AES-256 key, and K' is used as an HMAC-SHA-256 key. + +3. Serialize the JSON object as a UTF-8 string, and encrypt it using + AES-CTR-256 with the key K generated above, and with a 128-bit + cryptographically-random initialization vector, IV, that has bit 63 + set to zero. (Setting bit 63 to zero in IV is needed to work around + differences in implementations of AES-CTR.) + +4. Concatenate the following data: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Size (bytes)Description
1Export format version, which must be 0x01.
16The salt S.
16The initialization vector IV.
4The number of rounds N, as a big-endian unsigned 32-bit integer.
variableThe encrypted JSON object.

32

The HMAC-SHA-256 of all the above string concatenated together, using K' as the key.

+ +5. Base64-encode the string above. Newlines may be added to avoid + overly long lines. + +6. Prepend the resulting string with + `-----BEGIN MEGOLM SESSION DATA-----`, with a trailing newline, and + append `-----END MEGOLM SESSION DATA-----`, with a leading and + trailing newline. + +###### Key export format + +The exported sessions are formatted as a JSON array of `SessionData` +objects described as follows: + +`SessionData` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

algorithm

string

Required. The encryption algorithm that the session uses. Must be m.megolm.v1.aes-sha2.

forwarding_curve25519_key_chain

[string]

Required. Chain of Curve25519 keys through which this session was forwarded, via m.forwarded_room_key events.

room_id

string

Required. The room where the session is used.

sender_key

string

Required. The Curve25519 key of the device which initiated the session originally.

sender_claimed_keys

{string: string}

Required. The Ed25519 key of the device which initiated the session originally.

session_idstringRequired. The ID of the session.
session_keystringRequired. The key for the session.
+ +This is similar to the format before encryption used for the session +keys in [Server-side key backups](#server-side-key-backups) but adds the +`room_id` and `session_id` fields. + +Example: + + [ + { + "algorithm": "m.megolm.v1.aes-sha2", + "forwarding_curve25519_key_chain": [ + "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw" + ], + "room_id": "!Cuyf34gef24t:localhost", + "sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU", + "sender_claimed_keys": { + "ed25519": "", + }, + "session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ", + "session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf..." + }, + ... + ] + +#### Messaging Algorithms + +##### Messaging Algorithm Names + +Messaging algorithm names use the extensible naming scheme used +throughout this specification. Algorithm names that start with `m.` are +reserved for algorithms defined by this specification. Implementations +wanting to experiment with new algorithms must be uniquely globally +namespaced following Java's package naming conventions. + +Algorithm names should be short and meaningful, and should list the +primitives used by the algorithm so that it is easier to see if the +algorithm is using a broken primitive. + +A name of `m.olm.v1` is too short: it gives no information about the +primitives in use, and is difficult to extend for different primitives. +However a name of +`m.olm.v1.ecdh-curve25519-hdkfsha256.hmacsha256.hkdfsha256-aes256-cbc-hmac64sha256` +is too long despite giving a more precise description of the algorithm: +it adds to the data transfer overhead and sacrifices clarity for human +readers without adding any useful extra information. + +##### `m.olm.v1.curve25519-aes-sha2` + +The name `m.olm.v1.curve25519-aes-sha2` corresponds to version 1 of the +Olm ratchet, as defined by the [Olm +specification](http://matrix.org/docs/spec/olm.html). This uses: + +- Curve25519 for the initial key agreement. +- HKDF-SHA-256 for ratchet key derivation. +- Curve25519 for the root key ratchet. +- HMAC-SHA-256 for the chain key ratchet. +- HKDF-SHA-256, AES-256 in CBC mode, and 8 byte truncated HMAC-SHA-256 + for authenticated encryption. + +Devices that support Olm must include "m.olm.v1.curve25519-aes-sha2" in +their list of supported messaging algorithms, must list a Curve25519 +device key, and must publish Curve25519 one-time keys. + +An event encrypted using Olm has the following format: + + { + "type": "m.room.encrypted", + "content": { + "algorithm": "m.olm.v1.curve25519-aes-sha2", + "sender_key": "", + "ciphertext": { + "": { + "type": 0, + "body": "" + } + } + } + } + +`ciphertext` is a mapping from device Curve25519 key to an encrypted +payload for that device. `body` is a Base64-encoded Olm message body. +`type` is an integer indicating the type of the message body: 0 for the +initial pre-key message, 1 for ordinary messages. + +Olm sessions will generate messages with a type of 0 until they receive +a message. Once a session has decrypted a message it will produce +messages with a type of 1. + +When a client receives a message with a type of 0 it must first check if +it already has a matching session. If it does then it will use that +session to try to decrypt the message. If there is no existing session +then the client must create a new session and use the new session to +decrypt the message. A client must not persist a session or remove +one-time keys used by a session until it has successfully decrypted a +message using that session. + +Messages with type 1 can only be decrypted with an existing session. If +there is no matching session, the client must treat this as an invalid +message. + +The plaintext payload is of the form: + + { + "type": "", + "content": "", + "sender": "", + "recipient": "", + "recipient_keys": { + "ed25519": "" + }, + "keys": { + "ed25519": "" + } + } + +The type and content of the plaintext message event are given in the +payload. + +Other properties are included in order to prevent an attacker from +publishing someone else's curve25519 keys as their own and subsequently +claiming to have sent messages which they didn't. `sender` must +correspond to the user who sent the event, `recipient` to the local +user, and `recipient_keys` to the local ed25519 key. + +Clients must confirm that the `sender_key` and the `ed25519` field value +under the `keys` property match the keys returned by `/keys/query`\_ for +the given user, and must also verify the signature of the payload. +Without this check, a client cannot be sure that the sender device owns +the private part of the ed25519 key it claims to have in the Olm +payload. This is crucial when the ed25519 key corresponds to a verified +device. + +If a client has multiple sessions established with another device, it +should use the session from which it last received and successfully +decrypted a message. For these purposes, a session that has not received +any messages should use its creation time as the time that it last +received a message. A client may expire old sessions by defining a +maximum number of olm sessions that it will maintain for each device, +and expiring sessions on a Least Recently Used basis. The maximum number +of olm sessions maintained per device should be at least 4. + +###### Recovering from undecryptable messages + +Occasionally messages may be undecryptable by clients due to a variety +of reasons. When this happens to an Olm-encrypted message, the client +should assume that the Olm session has become corrupted and create a new +one to replace it. + +Note + +Megolm-encrypted messages generally do not have the same problem. +Usually the key for an undecryptable Megolm-encrypted message will come +later, allowing the client to decrypt it successfully. Olm does not have +a way to recover from the failure, making this session replacement +process required. + +To establish a new session, the client sends an [m.dummy](#m-dummy) +to-device event to the other party to notify them of the new session +details. + +Clients should rate-limit the number of sessions it creates per device +that it receives a message from. Clients should not create a new session +with another device if it has already created one for that given device +in the past 1 hour. + +Clients should attempt to mitigate loss of the undecryptable messages. +For example, Megolm sessions that were sent using the old session would +have been lost. The client can attempt to retrieve the lost sessions +through `m.room_key_request` messages. + +##### `m.megolm.v1.aes-sha2` + +The name `m.megolm.v1.aes-sha2` corresponds to version 1 of the Megolm +ratchet, as defined by the [Megolm +specification](http://matrix.org/docs/spec/megolm.html). This uses: + +- HMAC-SHA-256 for the hash ratchet. +- HKDF-SHA-256, AES-256 in CBC mode, and 8 byte truncated HMAC-SHA-256 + for authenticated encryption. +- Ed25519 for message authenticity. + +Devices that support Megolm must support Olm, and include +"m.megolm.v1.aes-sha2" in their list of supported messaging algorithms. + +An event encrypted using Megolm has the following format: + + { + "type": "m.room.encrypted", + "content": { + "algorithm": "m.megolm.v1.aes-sha2", + "sender_key": "", + "device_id": "", + "session_id": "", + "ciphertext": "" + } + } + +The encrypted payload can contain any message event. The plaintext is of +the form: + + { + "type": "", + "content": "", + "room_id": "" + } + +We include the room ID in the payload, because otherwise the homeserver +would be able to change the room a message was sent in. + +Clients must guard against replay attacks by keeping track of the +ratchet indices of Megolm sessions. They should reject messages with a +ratchet index that they have already decrypted. Care should be taken in +order to avoid false positives, as a client may decrypt the same event +twice as part of its normal processing. + +As with Olm events, clients must confirm that the `sender_key` belongs +to the user who sent the message. The same reasoning applies, but the +sender ed25519 key has to be inferred from the `keys.ed25519` property +of the event which established the Megolm session. + +In order to enable end-to-end encryption in a room, clients can send an +`m.room.encryption` state event specifying `m.megolm.v1.aes-sha2` as its +`algorithm` property. + +When creating a Megolm session in a room, clients must share the +corresponding session key using Olm with the intended recipients, so +that they can decrypt future messages encrypted using this session. An +`m.room_key` event is used to do this. Clients must also handle +`m.room_key` events sent by other devices in order to decrypt their +messages. + +#### Protocol definitions + +##### Events + +{{m\_room\_encryption\_event}} + +{{m\_room\_encrypted\_event}} + +{{m\_room\_key\_event}} + +{{m\_room\_key\_request\_event}} + +{{m\_forwarded\_room\_key\_event}} + +{{m\_dummy\_event}} + +##### Key management API + +{{keys\_cs\_http\_api}} + +##### Extensions to /sync + +This module adds an optional `device_lists` property to the \_ response, +as specified below. The server need only populate this property for an +incremental `/sync` (i.e., one where the `since` parameter was +specified). The client is expected to use `/keys/query`\_ or +`/keys/changes`\_ for the equivalent functionality after an initial +sync, as documented in [Tracking the device list for a +user](#tracking-the-device-list-for-a-user). + +It also adds a `one_time_keys_count` property. Note the spelling +difference with the `one_time_key_counts` property in the +`/keys/upload`\_ response. + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

device_lists

DeviceLists

Optional. Information on e2e device updates. Note: only present on an incremental sync.

device_one_time_keys_count

{string: integer}

Optional. For each key algorithm, the number of unclaimed one-time keys currently held on the server for this device.

+ +`DeviceLists` + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

changed

[string]

List of users who have updated their device identity or cross-signing keys, or who now share an encrypted room with the client since the previous sync response.

left

[string]

List of users with whom we do not share any encrypted rooms anymore since the previous sync response.

+ +Note + +For optimal performance, Alice should be added to `changed` in Bob's +sync only when she updates her devices or cross-signing keys, or when +Alice and Bob now share a room but didn't share any room previously. +However, for the sake of simpler logic, a server may add Alice to +`changed` when Alice and Bob share a new room, even if they previously +already shared a room. + +Example response: + + { + "next_batch": "s72595_4483_1934", + "rooms": {"leave": {}, "join": {}, "invite": {}}, + "device_lists": { + "changed": [ + "@alice:example.com", + ], + "left": [ + "@bob:example.com", + ], + }, + "device_one_time_keys_count": { + "curve25519": 10, + "signed_curve25519": 20 + } + } + +#### Reporting that decryption keys are withheld + +When sending an encrypted event to a room, a client can optionally +signal to other devices in that room that it is not sending them the +keys needed to decrypt the event. In this way, the receiving client can +indicate to the user why it cannot decrypt the event, rather than just +showing a generic error message. + +In the same way, when one device requests keys from another using [Key +requests](#key-requests), the device from which the key is being +requested may want to tell the requester that it is purposely not +sharing the key. + +If Alice withholds a megolm session from Bob for some messages in a +room, and then later on decides to allow Bob to decrypt later messages, +she can send Bob the megolm session, ratcheted up to the point at which +she allows Bob to decrypt the messages. If Bob logs into a new device +and uses key sharing to obtain the decryption keys, the new device will +be sent the megolm sessions that have been ratcheted up. Bob's old +device can include the reason that the session was initially not shared +by including a `withheld` property in the `m.forwarded_room_key` message +that is an object with the `code` and `reason` properties from the +`m.room_key.withheld` message. + +{{m\_room\_key\_withheld\_event}} diff --git a/content/client-server-api/modules/event_context.md b/content/client-server-api/modules/event_context.md new file mode 100644 index 00000000..32d7b9e8 --- /dev/null +++ b/content/client-server-api/modules/event_context.md @@ -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. diff --git a/content/client-server-api/modules/guest_access.md b/content/client-server-api/modules/guest_access.md new file mode 100644 index 00000000..ec996995 --- /dev/null +++ b/content/client-server-api/modules/guest_access.md @@ -0,0 +1,108 @@ +--- +type: module +weight: 160 +--- + +### Guest Access + +There are times when it is desirable for clients to be able to interact +with rooms without having to fully register for an account on a +homeserver or join the room. This module specifies how these clients +should interact with servers in order to participate in rooms as guests. + +Guest users retrieve access tokens from a homeserver using the ordinary +[register +endpoint](#post-matrix-client-%CLIENT_MAJOR_VERSION%-register), +specifying the `kind` parameter as `guest`. They may then interact with +the client-server API as any other user would, but will only have access +to a subset of the API as described the Client behaviour subsection +below. Homeservers may choose not to allow this access at all to their +local users, but have no information about whether users on other +homeservers are guests or not. + +Guest users can also upgrade their account by going through the ordinary +`register` flow, but specifying the additional POST parameter +`guest_access_token` containing the guest's access token. They are also +required to specify the `username` parameter to the value of the local +part of their username, which is otherwise optional. + +This module does not fully factor in federation; it relies on individual +homeservers properly adhering to the rules set out in this module, +rather than allowing all homeservers to enforce the rules on each other. + +#### Events + +{{m\_room\_guest\_access\_event}} + +#### Client behaviour + +The following API endpoints are allowed to be accessed by guest accounts +for retrieving events: + +- [GET + /rooms/:room\_id/state](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-state) +- [GET + /rooms/:room\_id/context/:event\_id](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-context-eventid) +- [GET + /rooms/:room\_id/event/:event\_id](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-event-eventid) +- [GET + /rooms/:room\_id/state/:event\_type/:state\_key](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-state-eventtype-statekey) +- [GET + /rooms/:room\_id/messages](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-messages) +- [GET + /rooms/:room\_id/members](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-members) +- [GET + /rooms/:room\_id/initialSync](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-initialsync) +- [GET /sync](#get-matrix-client-%CLIENT_MAJOR_VERSION%-sync) +- [GET /events]() as used for room previews. + +The following API endpoints are allowed to be accessed by guest accounts +for sending events: + +- [POST + /rooms/:room\_id/join](#post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-join) +- [POST + /rooms/:room\_id/leave](#post-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-leave) +- [PUT + /rooms/:room\_id/send/m.room.message/:txn\_id](#put-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-send-eventtype-txnid) +- [PUT + /sendToDevice/{eventType}/{txnId}](#put-matrix-client-%CLIENT_MAJOR_VERSION%-sendtodevice-eventtype-txnid) + +The following API endpoints are allowed to be accessed by guest accounts +for their own account maintenance: + +- [PUT + /profile/:user\_id/displayname](#put-matrix-client-%CLIENT_MAJOR_VERSION%-profile-userid-displayname) +- [GET /devices](#get-matrix-client-%CLIENT_MAJOR_VERSION%-devices) +- [GET + /devices/{deviceId}](#get-matrix-client-%CLIENT_MAJOR_VERSION%-devices-deviceid) +- [PUT + /devices/{deviceId}](#put-matrix-client-%CLIENT_MAJOR_VERSION%-devices-deviceid) + +The following API endpoints are allowed to be accessed by guest accounts +for end-to-end encryption: + +- [POST + /keys/upload](#post-matrix-client-%CLIENT_MAJOR_VERSION%-keys-upload) +- [POST + /keys/query](#post-matrix-client-%CLIENT_MAJOR_VERSION%-keys-query) +- [POST + /keys/claim](#post-matrix-client-%CLIENT_MAJOR_VERSION%-keys-claim) + +#### Server behaviour + +Servers MUST only allow guest users to join rooms if the +`m.room.guest_access` state event is present on the room, and has the +`guest_access` value `can_join`. If the `m.room.guest_access` event is +changed to stop this from being the case, the server MUST set those +users' `m.room.member` state to `leave`. + +#### Security considerations + +Each homeserver manages its own guest accounts itself, and whether an +account is a guest account or not is not information passed from server +to server. Accordingly, any server participating in a room is trusted to +properly enforce the permissions outlined in this section. + +Homeservers may want to enable protections such as captchas for guest +registration to prevent spam, denial of service, and similar attacks. diff --git a/content/client-server-api/modules/history_visibility.md b/content/client-server-api/modules/history_visibility.md new file mode 100644 index 00000000..322114fc --- /dev/null +++ b/content/client-server-api/modules/history_visibility.md @@ -0,0 +1,91 @@ +--- +type: module +weight: 120 +--- + +### Room History Visibility + +This module adds support for controlling the visibility of previous +events in a room. + +In all cases except `world_readable`, a user needs to join a room to +view events in that room. Once they have joined a room, they will gain +access to a subset of events in the room. How this subset is chosen is +controlled by the `m.room.history_visibility` event outlined below. +After a user has left a room, they may see any events which they were +allowed to see before they left the room, but no events received after +they left. + +The four options for the `m.room.history_visibility` event are: + +- `world_readable` - All events while this is the + `m.room.history_visibility` value may be shared by any participating + homeserver with anyone, regardless of whether they have ever joined + the room. +- `shared` - Previous events are always accessible to newly joined + members. All events in the room are accessible, even those sent when + the member was not a part of the room. +- `invited` - Events are accessible to newly joined members from the + point they were invited onwards. Events stop being accessible when + the member's state changes to something other than `invite` or + `join`. +- `joined` - Events are accessible to newly joined members from the + point they joined the room onwards. Events stop being accessible + when the member's state changes to something other than `join`. + +Warning + +These options are applied at the point an event is *sent*. Checks are +performed with the state of the `m.room.history_visibility` event when +the event in question is added to the DAG. This means clients cannot +retrospectively choose to show or hide history to new users if the +setting at that time was more restrictive. + +#### Events + +{{m\_room\_history\_visibility\_event}} + +#### Client behaviour + +Clients that implement this module MUST present to the user the possible +options for setting history visibility when creating a room. + +Clients may want to display a notice that their events may be read by +non-joined people if the value is set to `world_readable`. + +#### Server behaviour + +By default if no `history_visibility` is set, or if the value is not +understood, the visibility is assumed to be `shared`. The rules +governing whether a user is allowed to see an event depend on the state +of the room *at that event*. + +1. If the `history_visibility` was set to `world_readable`, allow. +2. If the user's `membership` was `join`, allow. +3. If `history_visibility` was set to `shared`, and the user joined the + room at any point after the event was sent, allow. +4. If the user's `membership` was `invite`, and the + `history_visibility` was set to `invited`, allow. +5. Otherwise, deny. + +For `m.room.history_visibility` events themselves, the user should be +allowed to see the event if the `history_visibility` before *or* after +the event would allow them to see it. (For example, a user should be +able to see `m.room.history_visibility` events which change the +`history_visibility` from `world_readable` to `joined` *or* from +`joined` to `world_readable`, even if that user was not a member of the +room.) + +Likewise, for the user's own `m.room.member` events, the user should be +allowed to see the event if their `membership` before *or* after the +event would allow them to see it. (For example, a user can always see +`m.room.member` events which set their membership to `join`, or which +change their membership from `join` to any other value, even if +`history_visibility` is `joined`.) + +#### Security considerations + +The default value for `history_visibility` is `shared` for +backwards-compatibility reasons. Clients need to be aware that by not +setting this event they are exposing all of their room history to anyone +in the room. diff --git a/content/client-server-api/modules/ignore_users.md b/content/client-server-api/modules/ignore_users.md new file mode 100644 index 00000000..18fadb67 --- /dev/null +++ b/content/client-server-api/modules/ignore_users.md @@ -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. diff --git a/content/client-server-api/modules/instant_messaging.md b/content/client-server-api/modules/instant_messaging.md new file mode 100644 index 00000000..76ec9b17 --- /dev/null +++ b/content/client-server-api/modules/instant_messaging.md @@ -0,0 +1,482 @@ +--- +type: module +weight: 10 +--- + +### Instant Messaging + +This module adds support for sending human-readable messages to a room. +It also adds support for associating human-readable information with the +room itself such as a room name and topic. + +#### Events + +{{m\_room\_message\_event}} + +{{m\_room\_message\_feedback\_event}} + +Usage of this event is discouraged for several reasons: +- The number of feedback events will grow very quickly with the number + of users in the room. This event provides no way to "batch" + feedback, unlike the [receipts module](). +- Pairing feedback to messages gets complicated when paginating as + feedback arrives before the message it is acknowledging. +- There are no guarantees that the client has seen the event ID being + acknowledged. + +{{m\_room\_name\_event}} + +{{m\_room\_topic\_event}} + +{{m\_room\_avatar\_event}} + +{{m\_room\_pinned\_events\_event}} + +##### m.room.message msgtypes + +Each [m.room.message]() MUST have a `msgtype` key which identifies the +type of message being sent. Each type has their own required and +optional keys, as outlined below. If a client cannot display the given +`msgtype` then it SHOULD display the fallback plain text `body` key +instead. + +Some message types support HTML in the event content that clients should +prefer to display if available. Currently `m.text`, `m.emote`, and +`m.notice` support an additional `format` parameter of +`org.matrix.custom.html`. When this field is present, a `formatted_body` +with the HTML must be provided. The plain text version of the HTML +should be provided in the `body`. + +Clients should limit the HTML they render to avoid Cross-Site Scripting, +HTML injection, and similar attacks. The strongly suggested set of HTML +tags to permit, denying the use and rendering of anything else, is: +`font`, `del`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `blockquote`, `p`, +`a`, `ul`, `ol`, `sup`, `sub`, `li`, `b`, `i`, `u`, `strong`, `em`, +`strike`, `code`, `hr`, `br`, `div`, `table`, `thead`, `tbody`, `tr`, +`th`, `td`, `caption`, `pre`, `span`, `img`. + +Not all attributes on those tags should be permitted as they may be +avenues for other disruption attempts, such as adding `onclick` handlers +or excessively large text. Clients should only permit the attributes +listed for the tags below. Where `data-mx-bg-color` and `data-mx-color` +are listed, clients should translate the value (a 6-character hex color +code) to the appropriate CSS/attributes for the tag. + +`font` +`data-mx-bg-color`, `data-mx-color` + +`span` +`data-mx-bg-color`, `data-mx-color` + +`a` +`name`, `target`, `href` (provided the value is not relative and has a +scheme matching one of: `https`, `http`, `ftp`, `mailto`, `magnet`) + +`img` +`width`, `height`, `alt`, `title`, `src` (provided it is a [Matrix +Content (MXC) URI]()) + +`ol` +`start` + +`code` +`class` (only classes which start with `language-` for syntax +highlighting) + +Additionally, web clients should ensure that *all* `a` tags get a +`rel="noopener"` to prevent the target page from referencing the +client's tab/window. + +Tags must not be nested more than 100 levels deep. Clients should only +support the subset of tags they can render, falling back to other +representations of the tags where possible. For example, a client may +not be able to render tables correctly and instead could fall back to +rendering tab-delimited text. + +In addition to not rendering unsafe HTML, clients should not emit unsafe +HTML in events. Likewise, clients should not generate HTML that is not +needed, such as extra paragraph tags surrounding text due to Rich Text +Editors. HTML included in events should otherwise be valid, such as +having appropriate closing tags, appropriate attributes (considering the +custom ones defined in this specification), and generally valid +structure. + +A special tag, `mx-reply`, may appear on rich replies (described below) +and should be allowed if, and only if, the tag appears as the very first +tag in the `formatted_body`. The tag cannot be nested and cannot be +located after another tag in the tree. Because the tag contains HTML, an +`mx-reply` is expected to have a partner closing tag and should be +treated similar to a `div`. Clients that support rich replies will end +up stripping the tag and its contents and therefore may wish to exclude +the tag entirely. + +Note + +A future iteration of the specification will support more powerful and +extensible message formatting options, such as the proposal +[MSC1767](https://github.com/matrix-org/matrix-doc/pull/1767). + +{{msgtype\_events}} + +#### Client behaviour + +Clients SHOULD verify the structure of incoming events to ensure that +the expected keys exist and that they are of the right type. Clients can +discard malformed events or display a placeholder message to the user. +Redacted `m.room.message` events MUST be removed from the client. This +can either be replaced with placeholder text (e.g. "\[REDACTED\]") or +the redacted message can be removed entirely from the messages view. + +Events which have attachments (e.g. `m.image`, `m.file`) SHOULD be +uploaded using the [content repository module]() where available. The +resulting `mxc://` URI can then be used in the `url` key. + +Clients MAY include a client generated thumbnail image for an attachment +under a `info.thumbnail_url` key. The thumbnail SHOULD also be a +`mxc://` URI. Clients displaying events with attachments can either use +the client generated thumbnail or ask its homeserver to generate a +thumbnail from the original attachment using the [content repository +module](). + +##### Recommendations when sending messages + +In the event of send failure, clients SHOULD retry requests using an +exponential-backoff algorithm for a certain amount of time T. It is +recommended that T is no longer than 5 minutes. After this time, the +client should stop retrying and mark the message as "unsent". Users +should be able to manually resend unsent messages. + +Users may type several messages at once and send them all in quick +succession. Clients SHOULD preserve the order in which they were sent by +the user. This means that clients should wait for the response to the +previous request before sending the next request. This can lead to +head-of-line blocking. In order to reduce the impact of head-of-line +blocking, clients should use a queue per room rather than a global +queue, as ordering is only relevant within a single room rather than +between rooms. + +##### Local echo + +Messages SHOULD appear immediately in the message view when a user +presses the "send" button. This should occur even if the message is +still sending. This is referred to as "local echo". Clients SHOULD +implement "local echo" of messages. Clients MAY display messages in a +different format to indicate that the server has not processed the +message. This format should be removed when the server responds. + +Clients need to be able to match the message they are sending with the +same message which they receive from the event stream. The echo of the +same message from the event stream is referred to as "remote echo". Both +echoes need to be identified as the same message in order to prevent +duplicate messages being displayed. Ideally this pairing would occur +transparently to the user: the UI would not flicker as it transitions +from local to remote. Flickering can be reduced through clients making +use of the transaction ID they used to send a particular event. The +transaction ID used will be included in the event's `unsigned` data as +`transaction_id` when it arrives through the event stream. + +Clients unable to make use of the transaction ID are likely to +experience flickering when the remote echo arrives on the event stream +*before* the request to send the message completes. In that case the +event arrives before the client has obtained an event ID, making it +impossible to identify it as a remote echo. This results in the client +displaying the message twice for some time (depending on the server +responsiveness) before the original request to send the message +completes. Once it completes, the client can take remedial actions to +remove the duplicate event by looking for duplicate event IDs. + +##### Calculating the display name for a user + +Clients may wish to show the human-readable display name of a room +member as part of a membership list, or when they send a message. +However, different members may have conflicting display names. Display +names MUST be disambiguated before showing them to the user, in order to +prevent spoofing of other users. + +To ensure this is done consistently across clients, clients SHOULD use +the following algorithm to calculate a disambiguated display name for a +given user: + +1. Inspect the `m.room.member` state event for the relevant user id. +2. If the `m.room.member` state event has no `displayname` field, or if + that field has a `null` value, use the raw user id as the display + name. Otherwise: +3. If the `m.room.member` event has a `displayname` which is unique + among members of the room with `membership: join` or + `membership: invite`, use the given `displayname` as the + user-visible display name. Otherwise: +4. The `m.room.member` event has a non-unique `displayname`. This + should be disambiguated using the user id, for example "display name + (@id:homeserver.org)". + +Developers should take note of the following when implementing the above +algorithm: + +- The user-visible display name of one member can be affected by + changes in the state of another member. For example, if + `@user1:matrix.org` is present in a room, with `displayname: Alice`, + then when `@user2:example.com` joins the room, also with + `displayname: Alice`, *both* users must be given disambiguated + display names. Similarly, when one of the users then changes their + display name, there is no longer a clash, and *both* users can be + given their chosen display name. Clients should be alert to this + possibility and ensure that all affected users are correctly + renamed. +- The display name of a room may also be affected by changes in the + membership list. This is due to the room name sometimes being based + on user display names (see [Calculating the display name for a + room](#calculating-the-display-name-for-a-room)). +- If the entire membership list is searched for clashing display + names, this leads to an O(N^2) implementation for building the list + of room members. This will be very inefficient for rooms with large + numbers of members. It is recommended that client implementations + maintain a hash table mapping from `displayname` to a list of room + members using that name. Such a table can then be used for efficient + calculation of whether disambiguation is needed. + +##### Displaying membership information with messages + +Clients may wish to show the display name and avatar URL of the room +member who sent a message. This can be achieved by inspecting the +`m.room.member` state event for that user ID (see [Calculating the +display name for a user](#calculating-the-display-name-for-a-user)). + +When a user paginates the message history, clients may wish to show the +**historical** display name and avatar URL for a room member. This is +possible because older `m.room.member` events are returned when +paginating. This can be implemented efficiently by keeping two sets of +room state: old and current. As new events arrive and/or the user +paginates back in time, these two sets of state diverge from each other. +New events update the current state and paginated events update the old +state. When paginated events are processed sequentially, the old state +represents the state of the room *at the time the event was sent*. This +can then be used to set the historical display name and avatar URL. + +##### Calculating the display name for a room + +Clients may wish to show a human-readable name for a room. There are a +number of possibilities for choosing a useful name. To ensure that rooms +are named consistently across clients, clients SHOULD use the following +algorithm to choose a name: + +1. If the room has an [m.room.name]() state event with a non-empty + `name` field, use the name given by that field. +2. If the room has an [m.room.canonical\_alias]() state event with a + valid `alias` field, use the alias given by that field as the name. + Note that clients should avoid using `alt_aliases` when calculating + the room name. +3. If none of the above conditions are met, a name should be composed + based on the members of the room. Clients should consider + [m.room.member]() events for users other than the logged-in user, as + defined below. + 1. If the number of `m.heroes` for the room are greater or equal to + `m.joined_member_count + m.invited_member_count - 1`, then use + the membership events for the heroes to calculate display names + for the users ([disambiguating them if + required](#calculating-the-display-name-for-a-user)) and + concatenating them. For example, the client may choose to show + "Alice, Bob, and Charlie (@charlie:example.org)" as the room + name. The client may optionally limit the number of users it + uses to generate a room name. + 2. If there are fewer heroes than + `m.joined_member_count + m.invited_member_count - 1`, and + `m.joined_member_count + m.invited_member_count` is greater than + 1, the client should use the heroes to calculate display names + for the users ([disambiguating them if + required](#calculating-the-display-name-for-a-user)) and + concatenating them alongside a count of the remaining users. For + example, "Alice, Bob, and 1234 others". + 3. If `m.joined_member_count + m.invited_member_count` is less than + or equal to 1 (indicating the member is alone), the client + should use the rules above to indicate that the room was empty. + For example, "Empty Room (was Alice)", "Empty Room (was Alice + and 1234 others)", or "Empty Room" if there are no heroes. + +Clients SHOULD internationalise the room name to the user's language +when using the `m.heroes` to calculate the name. Clients SHOULD use +minimum 5 heroes to calculate room names where possible, but may use +more or less to fit better with their user experience. + +##### Forming relationships between events + +In some cases, events may wish to reference other events. This could be +to form a thread of messages for the user to follow along with, or to +provide more context as to what a particular event is describing. +Currently, the only kind of relation defined is a "rich reply" where a +user may reference another message to create a thread-like conversation. + +Relationships are defined under an `m.relates_to` key in the event's +`content`. If the event is of the type `m.room.encrypted`, the +`m.relates_to` key MUST NOT be covered by the encryption and instead be +put alongside the encryption information held in the `content`. + +###### Rich replies + +Users may wish to reference another message when forming their own +message, and clients may wish to better embed the referenced message for +the user to have a better context for the conversation being had. This +sort of embedding another message in a message is known as a "rich +reply", or occasionally just a "reply". + +A rich reply is formed through use of an `m.relates_to` relation for +`m.in_reply_to` where a single key, `event_id`, is used to reference the +event being replied to. The referenced event ID SHOULD belong to the +same room where the reply is being sent. Clients should be cautious of +the event ID belonging to another room, or being invalid entirely. Rich +replies can only be constructed in the form of `m.room.message` events +with a `msgtype` of `m.text` or `m.notice`. Due to the fallback +requirements, rich replies cannot be constructed for types of `m.emote`, +`m.file`, etc. Rich replies may reference any other `m.room.message` +event, however. Rich replies may reference another event which also has +a rich reply, infinitely. + +An `m.in_reply_to` relationship looks like the following: + + { + ... + "type": "m.room.message", + "content": { + "msgtype": "m.text", + "body": "", + "format": "org.matrix.custom.html", + "formatted_body": "", + "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: + + +
+ In reply to + @alice:example.org +
+ +
+
+ This is where the reply goes. + +If the related event does not have a `formatted_body`, the event's +`body` should be considered after encoding any HTML special characters. +Note that the `href` in both of the anchors use a [matrix.to +URI](../appendices.html#matrix-to-navigation). + +######## Stripping the fallback + +Clients which support rich replies MUST strip the fallback from the +event before rendering the event. This is because the text provided in +the fallback cannot be trusted to be an accurate representation of the +event. After removing the fallback, clients are recommended to represent +the event referenced by `m.in_reply_to` similar to the fallback's +representation, although clients do have creative freedom for their user +interface. Clients should prefer the `formatted_body` over the `body`, +just like with other `m.room.message` events. + +To strip the fallback on the `body`, the client should iterate over each +line of the string, removing any lines that start with the fallback +prefix ("> ", 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: + + +
+ In reply to + * @alice:example.org +
+ +
+
+ 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 + + +
+ In reply to + @alice:example.org +
+ sent a file. +
+
+ This is where the reply goes. + +For `m.image`, the text should be `"sent an image."`. For `m.video`, the +text should be `"sent a video."`. For `m.audio`, the text should be +`"sent an audio file"`. + +#### Server behaviour + +Homeservers SHOULD reject `m.room.message` events which don't have a +`msgtype` key, or which don't have a textual `body` key, with an HTTP +status code of 400. + +#### Security considerations + +Messages sent using this module are not encrypted, although end to end +encryption is in development (see [E2E module]()). + +Clients should sanitise **all displayed keys** for unsafe HTML to +prevent Cross-Site Scripting (XSS) attacks. This includes room names and +topics. diff --git a/content/client-server-api/modules/mentions.md b/content/client-server-api/modules/mentions.md new file mode 100644 index 00000000..9baebe8d --- /dev/null +++ b/content/client-server-api/modules/mentions.md @@ -0,0 +1,58 @@ +--- +type: module +weight: 300 +--- + +### User, room, and group mentions + +This module allows users to mention other users, rooms, and groups +within a room message. This is achieved by including a [matrix.to +URI](../appendices.html#matrix-to-navigation) in the HTML body of an +[m.room.message]() event. This module does not have any server-specific +behaviour to it. + +Mentions apply only to [m.room.message]() events where the `msgtype` is +`m.text`, `m.emote`, or `m.notice`. The `format` for the event must be +`org.matrix.custom.html` and therefore requires a `formatted_body`. + +To make a mention, reference the entity being mentioned in the +`formatted_body` using an anchor, like so: + + { + "body": "Hello Alice!", + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "formatted_body": "Hello Alice!" + } + +#### 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. diff --git a/content/client-server-api/modules/moderation_policies.md b/content/client-server-api/modules/moderation_policies.md new file mode 100644 index 00000000..923df71e --- /dev/null +++ b/content/client-server-api/modules/moderation_policies.md @@ -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.` 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. diff --git a/content/client-server-api/modules/openid.md b/content/client-server-api/modules/openid.md new file mode 100644 index 00000000..af8b31c9 --- /dev/null +++ b/content/client-server-api/modules/openid.md @@ -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}} diff --git a/content/client-server-api/modules/presence.md b/content/client-server-api/modules/presence.md new file mode 100644 index 00000000..83f9c560 --- /dev/null +++ b/content/client-server-api/modules/presence.md @@ -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. diff --git a/content/client-server-api/modules/push.md b/content/client-server-api/modules/push.md new file mode 100644 index 00000000..b377715c --- /dev/null +++ b/content/client-server-api/modules/push.md @@ -0,0 +1,721 @@ +--- +type: module +weight: 130 +--- + +### Push Notifications + + +--------------------+ +-------------------+ + Matrix HTTP | | | | + Notification Protocol | App Developer | | Device Vendor | + | | | | + +-------------------+ | +----------------+ | | +---------------+ | + | | | | | | | | | | + | Matrix homeserver +-----> Push Gateway +------> Push Provider | | + | | | | | | | | | | + +-^-----------------+ | +----------------+ | | +----+----------+ | + | | | | | | + Matrix | | | | | | + Client/Server API + | | | | | + | | +--------------------+ +-------------------+ + | +--+-+ | + | | <-------------------------------------------+ + +---+ | + | | Provider Push Protocol + +----+ + + Mobile Device or Client + +This module adds support for push notifications. Homeservers send +notifications of events to user-configured HTTP endpoints. Users may +also configure a number of rules that determine which events generate +notifications. These are all stored and managed by the user's +homeserver. This allows user-specific push settings to be reused between +client applications. + +The above diagram shows the flow of push notifications being sent to a +handset where push notifications are submitted via the handset vendor, +such as Apple's APNS or Google's GCM. This happens as follows: + +1. The client app signs in to a homeserver. +2. The client app registers with its vendor's Push Provider and obtains + a routing token of some kind. +3. The mobile app uses the Client/Server API to add a 'pusher', + providing the URL of a specific Push Gateway which is configured for + that application. It also provides the routing token it has acquired + from the Push Provider. +4. The homeserver starts sending HTTP requests to the Push Gateway + using the supplied URL. The Push Gateway relays this notification to + the Push Provider, passing the routing token along with any + necessary private credentials the provider requires to send push + notifications. +5. The Push Provider sends the notification to the device. + +Definitions for terms used in this section are below: + +Push Provider +A push provider is a service managed by the device vendor which can send +notifications directly to the device. Google Cloud Messaging (GCM) and +Apple Push Notification Service (APNS) are two examples of push +providers. + +Push Gateway +A push gateway is a server that receives HTTP event notifications from +homeservers and passes them on to a different protocol such as APNS for +iOS devices or GCM for Android devices. Clients inform the homeserver +which Push Gateway to send notifications to when it sets up a Pusher. + +Pusher +A pusher is a worker on the homeserver that manages the sending of HTTP +notifications for a user. A user can have multiple pushers: one per +device. + +Push Rule +A push rule is a single rule that states under what *conditions* an +event should be passed onto a push gateway and *how* the notification +should be presented. These rules are stored on the user's homeserver. +They are manually configured by the user, who can create and view them +via the Client/Server API. + +Push Ruleset +A push ruleset *scopes a set of rules according to some criteria*. For +example, some rules may only be applied for messages from a particular +sender, a particular room, or by default. The push ruleset contains the +entire set of scopes and rules. + +#### Client behaviour + +Clients MUST configure a Pusher before they will receive push +notifications. There is a single API endpoint for this, as described +below. + +{{pusher\_cs\_http\_api}} + +##### Listing Notifications + +A client can retrieve a list of events that it has been notified about. +This may be useful so that users can see a summary of what important +messages they have received. + +{{notifications\_cs\_http\_api}} + +##### Receiving notifications + +Servers MUST include the number of unread notifications in a client's +`/sync` stream, and MUST update it as it changes. Notifications are +determined by the push rules which apply to an event. + +When the user updates their read receipt (either by using the API or by +sending an event), notifications prior to and including that event MUST +be marked as read. + +##### Push Rules + +A push rule is a single rule that states under what *conditions* an +event should be passed onto a push gateway and *how* the notification +should be presented. There are different "kinds" of push rules and each +rule has an associated priority. Every push rule MUST have a `kind` and +`rule_id`. The `rule_id` is a unique string within the kind of rule and +its' scope: `rule_ids` do not need to be unique between rules of the +same kind on different devices. Rules may have extra keys depending on +the value of `kind`. + +The different `kind`s of rule, in the order that they are checked, are: + +Override Rules `override` +The highest priority rules are user-configured overrides. + +Content-specific Rules `content` +These configure behaviour for (unencrypted) messages that match certain +patterns. Content rules take one parameter: `pattern`, that gives the +glob pattern to match against. This is treated in the same way as +`pattern` for `event_match`. + +Room-specific Rules `room` +These rules change the behaviour of all messages for a given room. The +`rule_id` of a room rule is always the ID of the room that it affects. + +Sender-specific rules `sender` +These rules configure notification behaviour for messages from a +specific Matrix user ID. The `rule_id` of Sender rules is always the +Matrix user ID of the user whose messages they'd apply to. + +Underride rules `underride` +These are identical to `override` rules, but have a lower priority than +`content`, `room` and `sender` rules. + +Rules with the same `kind` can specify an ordering priority. This +determines which rule is selected in the event of multiple matches. For +example, a rule matching "tea" and a separate rule matching "time" would +both match the sentence "It's time for tea". The ordering of the rules +would then resolve the tiebreak to determine which rule is executed. +Only `actions` for highest priority rule will be sent to the Push +Gateway. + +Each rule can be enabled or disabled. Disabled rules never match. If no +rules match an event, the homeserver MUST NOT notify the Push Gateway +for that event. Homeservers MUST NOT notify the Push Gateway for events +that the user has sent themselves. + +###### Actions + +All rules have an associated list of `actions`. An action affects if and +how a notification is delivered for a matching event. The following +actions are defined: + +`notify` +This causes each matching event to generate a notification. + +`dont_notify` +This prevents each matching event from generating a notification + +`coalesce` +This enables notifications for matching events but activates homeserver +specific behaviour to intelligently coalesce multiple events into a +single notification. Not all homeservers may support this. Those that do +not support it should treat it as the `notify` action. + +`set_tweak` +Sets an entry in the `tweaks` dictionary key that is sent in the +notification request to the Push Gateway. This takes the form of a +dictionary with a `set_tweak` key whose value is the name of the tweak +to set. It may also have a `value` key which is the value to which it +should be set. + +Actions that have no parameters are represented as a string. Otherwise, +they are represented as a dictionary with a key equal to their name and +other keys as their parameters, e.g. +`{ "set_tweak": "sound", "value": "default" }` + +####### Tweaks + +The `set_tweak` action is used to add an entry to the 'tweaks' +dictionary that is sent in the notification request to the Push Gateway. +The following tweaks are defined: + +`sound` +A string representing the sound to be played when this notification +arrives. A value of `default` means to play a default sound. A device +may choose to alert the user by some other means if appropriate, eg. +vibration. + +`highlight` +A boolean representing whether or not this message should be highlighted +in the UI. This will normally take the form of presenting the message in +a different colour and/or style. The UI might also be adjusted to draw +particular attention to the room in which the event occurred. If a +`highlight` tweak is given with no value, its value is defined to be +`true`. If no highlight tweak is given at all then the value of +`highlight` is defined to be false. + +Tweaks are passed transparently through the homeserver so client +applications and Push Gateways may agree on additional tweaks. For +example, a tweak may be added to specify how to flash the notification +light on a mobile device. + +###### Conditions + +`override` and `underride` rules MAY have a list of 'conditions'. All +conditions must hold true for an event in order for the rule to match. A +rule with no conditions always matches. The following conditions are +defined: + +`event_match` +This is a glob pattern match on a field of the event. Parameters: + +- `key`: The dot-separated field of the event to match, e.g. + `content.body` +- `pattern`: The glob-style pattern to match against. Patterns with no + special glob characters should be treated as having asterisks + prepended and appended when testing the condition. + +`contains_display_name` +This matches unencrypted messages where `content.body` contains the +owner's display name in that room. This is a separate rule because +display names may change and as such it would be hard to maintain a rule +that matched the user's display name. This condition has no parameters. + +`room_member_count` +This matches the current number of members in the room. Parameters: + +- `is`: A decimal integer optionally prefixed by one of, `==`, `<`, + `>`, `>=` or `<=`. A prefix of `<` matches rooms where the member + count is strictly less than the given number and so forth. If no + prefix is present, this parameter defaults to `==`. + +`sender_notification_permission` +This takes into account the current power levels in the room, ensuring +the sender of the event has high enough power to trigger the +notification. + +Parameters: + +- `key`: A string that determines the power level the sender must have + to trigger notifications of a given type, such as `room`. Refer to + the [m.room.power\_levels]() event schema for information about what + the defaults are and how to interpret the event. The `key` is used + to look up the power level required to send a notification type from + the `notifications` object in the power level event content. + +Unrecognised conditions MUST NOT match any events, effectively making +the push rule disabled. + +`room`, `sender` and `content` rules do not have conditions in the same +way, but instead have predefined conditions. In the cases of `room` and +`sender` rules, the `rule_id` of the rule determines its behaviour. + +###### Predefined Rules + +Homeservers can specify "server-default rules" which operate at a lower +priority than "user-defined rules". The `rule_id` for all server-default +rules MUST start with a dot (".") to identify them as "server-default". +The following server-default rules are specified: + +####### Default Override Rules + +######## `.m.rule.master` + +Matches all events. This can be enabled to turn off all push +notifications other than those generated by override rules set by the +user. By default this rule is disabled. + +Definition + + { + "rule_id": ".m.rule.master", + "default": true, + "enabled": false, + "conditions": [], + "actions": [ + "dont_notify" + ] + } + +######## `.m.rule.suppress_notices` + +Matches messages with a `msgtype` of `notice`. + +Definition: + + { + "rule_id": ".m.rule.suppress_notices", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "content.msgtype", + "pattern": "m.notice", + } + ], + "actions": [ + "dont_notify", + ] + } + +######## `.m.rule.invite_for_me` + +Matches any invites to a new room for this user. + +Definition: + + { + "rule_id": ".m.rule.invite_for_me", + "default": true, + "enabled": true, + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + }, + { + "key": "content.membership", + "kind": "event_match", + "pattern": "invite" + }, + { + "key": "state_key", + "kind": "event_match", + "pattern": "[the user's Matrix ID]" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + } + ] + } + +######## `.m.rule.member_event` + +Matches any `m.room.member_event`. + +Definition: + + { + "rule_id": ".m.rule.member_event", + "default": true, + "enabled": true, + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + } + ], + "actions": [ + "dont_notify" + ] + } + +######## `.m.rule.contains_display_name` + +Matches any message whose content is unencrypted and contains the user's +current display name in the room in which it was sent. + +Definition: + + { + "rule_id": ".m.rule.contains_display_name", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "contains_display_name" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ] + } + +######## `.m.rule.tombstone` + +Matches any state event whose type is `m.room.tombstone`. This is +intended to notify users of a room when it is upgraded, similar to what +an `@room` notification would accomplish. + +Definition: + + { + "rule_id": ".m.rule.tombstone", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.tombstone" + }, + { + "kind": "event_match", + "key": "state_key", + "pattern": "" + } + ], + "actions": [ + "notify", + { + "set_tweak": "highlight" + } + ] + } + +######## `.m.rule.roomnotif` + +Matches any message whose content is unencrypted and contains the text +`@room`, signifying the whole room should be notified of the event. + +Definition: + + { + "rule_id": ".m.rule.roomnotif", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "content.body", + "pattern": "@room" + }, + { + "kind": "sender_notification_permission", + "key": "room" + } + ], + "actions": [ + "notify", + { + "set_tweak": "highlight" + } + ] + } + +####### Default Content Rules + +######## `.m.rule.contains_user_name` + +Matches any message whose content is unencrypted and contains the local +part of the user's Matrix ID, separated by word boundaries. + +Definition (as a `content` rule): + + { + "rule_id": ".m.rule.contains_user_name", + "default": true, + "enabled": true, + "pattern": "[the local part of the user's Matrix ID]", + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ] + } + +####### Default Underride Rules + +######## `.m.rule.call` + +Matches any incoming VOIP call. + +Definition: + + { + "rule_id": ".m.rule.call", + "default": true, + "enabled": true, + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.call.invite" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "ring" + } + ] + } + +######## `.m.rule.encrypted_room_one_to_one` + +Matches any encrypted event sent in a room with exactly two members. +Unlike other push rules, this rule cannot be matched against the content +of the event by nature of it being encrypted. This causes the rule to be +an "all or nothing" match where it either matches *all* events that are +encrypted (in 1:1 rooms) or none. + +Definition: + + { + "rule_id": ".m.rule.encrypted_room_one_to_one", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "room_member_count", + "is": "2" + }, + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.encrypted" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + } + ] + } + +######## `.m.rule.room_one_to_one` + +Matches any message sent in a room with exactly two members. + +Definition: + + { + "rule_id": ".m.rule.room_one_to_one", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "room_member_count", + "is": "2" + }, + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.message" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + } + ] + } + +######## `.m.rule.message` + +Matches all chat messages. + +Definition: + + { + "rule_id": ".m.rule.message", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.message" + } + ], + "actions": [ + "notify" + ] + } + +######## `.m.rule.encrypted` + +Matches all encrypted events. Unlike other push rules, this rule cannot +be matched against the content of the event by nature of it being +encrypted. This causes the rule to be an "all or nothing" match where it +either matches *all* events that are encrypted (in group rooms) or none. + +Definition: + + { + "rule_id": ".m.rule.encrypted", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.encrypted" + } + ], + "actions": [ + "notify" + ] + } + +##### Push Rules: API + +Clients can retrieve, add, modify and remove push rules globally or +per-device using the APIs below. + +{{pushrules\_cs\_http\_api}} + +##### Push Rules: Events + +When a user changes their push rules a `m.push_rules` event is sent to +all clients in the `account_data` section of their next `/sync` request. +The content of the event is the current push rules for the user. + +{{m\_push\_rules\_event}} + +###### Examples + +To create a rule that suppresses notifications for the room with ID +`!dj234r78wl45Gh4D:matrix.org`: + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \ + '{ + "actions" : ["dont_notify"] + }' + +To suppress notifications for the user `@spambot:matrix.org`: + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \ + '{ + "actions" : ["dont_notify"] + }' + +To always notify for messages that contain the work 'cake' and set a +specific sound (with a rule\_id of `SSByZWFsbHkgbGlrZSBjYWtl`): + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \ + '{ + "pattern": "cake", + "actions" : ["notify", {"set_sound":"cakealarm.wav"}] + }' + +To add a rule suppressing notifications for messages starting with +'cake' but ending with 'lie', superseding the previous rule: + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \ + '{ + "pattern": "cake*lie", + "actions" : ["notify"] + }' + +To add a custom sound for notifications messages containing the word +'beer' in any rooms with 10 members or fewer (with greater importance +than the room, sender and content rules): + + curl -X PUT -H "Content-Type: application/json" "https://example.com/_matrix/client/%CLIENT_MAJOR_VERSION%/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456" -d \ + '{ + "conditions": [ + {"kind": "event_match", "key": "content.body", "pattern": "beer" }, + {"kind": "room_member_count", "is": "<=10"} + ], + "actions" : [ + "notify", + {"set_sound":"beeroclock.wav"} + ] + }' + +#### Server behaviour + +#### Push Gateway behaviour + +##### Recommendations for APNS + +The exact format for sending APNS notifications is flexible and up to +the client app and its' push gateway to agree on. As APNS requires that +the sender has a private key owned by the app developer, each app must +have its own push gateway. It is recommended that: + +- The APNS token be base64 encoded and used as the pushkey. +- A different app\_id be used for apps on the production and sandbox + APS environments. +- APNS push gateways do not attempt to wait for errors from the APNS + gateway before returning and instead to store failures and return + 'rejected' responses next time that pushkey is used. + +#### Security considerations + +Clients specify the Push Gateway URL to use to send event notifications +to. This URL should be over HTTPS and *never* over HTTP. + +As push notifications will pass through a Push Provider, message content +shouldn't be sent in the push itself where possible. Instead, Push +Gateways should send a "sync" command to instruct the client to get new +events from the homeserver directly. diff --git a/content/client-server-api/modules/read_markers.md b/content/client-server-api/modules/read_markers.md new file mode 100644 index 00000000..ccbafd26 --- /dev/null +++ b/content/client-server-api/modules/read_markers.md @@ -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. diff --git a/content/client-server-api/modules/receipts.md b/content/client-server-api/modules/receipts.md new file mode 100644 index 00000000..485ac0fc --- /dev/null +++ b/content/client-server-api/modules/receipts.md @@ -0,0 +1,87 @@ +--- +type: module +weight: 40 +--- + +### Receipts + +This module adds in support for receipts. These receipts are a form of +acknowledgement of an event. This module defines a single +acknowledgement: `m.read` which indicates that the user has read up to a +given event. + +Sending a receipt for each event can result in sending large amounts of +traffic to a homeserver. To prevent this from becoming a problem, +receipts are implemented using "up to" markers. This marker indicates +that the acknowledgement applies to all events "up to and including" the +event specified. For example, marking an event as "read" would indicate +that the user had read all events *up to* the referenced event. See the +[Receiving notifications](#receiving-notifications) section for more +information on how read receipts affect notification counts. + +#### Events + +Each `user_id`, `receipt_type` pair must be associated with only a +single `event_id`. + +{{m\_receipt\_event}} + +#### Client behaviour + +In `/sync`, receipts are listed under the `ephemeral` array of events +for a given room. New receipts that come down the event streams are +deltas which update existing mappings. Clients should replace older +receipt acknowledgements based on `user_id` and `receipt_type` pairs. +For example: + + Client receives m.receipt: + user = @alice:example.com + receipt_type = m.read + event_id = $aaa:example.com + + Client receives another m.receipt: + user = @alice:example.com + receipt_type = m.read + event_id = $bbb:example.com + + The client should replace the older acknowledgement for $aaa:example.com with + this one for $bbb:example.com + +Clients should send read receipts when there is some certainty that the +event in question has been **displayed** to the user. Simply receiving +an event does not provide enough certainty that the user has seen the +event. The user SHOULD need to *take some action* such as viewing the +room that the event was sent to or dismissing a notification in order +for the event to count as "read". Clients SHOULD NOT send read receipts +for events sent by their own user. + +A client can update the markers for its user by interacting with the +following HTTP APIs. + +{{receipts\_cs\_http\_api}} + +#### Server behaviour + +For efficiency, receipts SHOULD be batched into one event per room +before delivering them to clients. + +Receipts are sent across federation as EDUs with type `m.receipt`. The +format of the EDUs are: + + { + : { + : { + : { } + }, + ... + }, + ... + } + +These are always sent as deltas to previously sent receipts. Currently +only a single `` 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. diff --git a/content/client-server-api/modules/report_content.md b/content/client-server-api/modules/report_content.md new file mode 100644 index 00000000..ff90207d --- /dev/null +++ b/content/client-server-api/modules/report_content.md @@ -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. diff --git a/content/client-server-api/modules/room_previews.md b/content/client-server-api/modules/room_previews.md new file mode 100644 index 00000000..8d2519c0 --- /dev/null +++ b/content/client-server-api/modules/room_previews.md @@ -0,0 +1,42 @@ +--- +type: module +weight: 170 +--- + +### Room Previews + +It is sometimes desirable to offer a preview of a room, where a user can +"lurk" and read messages posted to the room, without joining the room. +This can be particularly effective when combined with [Guest Access](). + +Previews are implemented via the `world_readable` [Room History +Visibility](). setting, along with a special version of the [GET +/events](#get-matrix-client-%CLIENT_MAJOR_VERSION%-events) endpoint. + +#### Client behaviour + +A client wishing to view a room without joining it should call [GET +/rooms/:room\_id/initialSync](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-initialsync), +followed by [GET /events](#peeking_events_api). Clients will need to do +this in parallel for each room they wish to view. + +Clients can of course also call other endpoints such as [GET +/rooms/:room\_id/messages](#get-matrix-client-%CLIENT_MAJOR_VERSION%-rooms-roomid-messages) +and [GET /search](#get-matrix-client-%CLIENT_MAJOR_VERSION%-search) to +access events outside the `/events` stream. + +{{peeking\_events\_cs\_http\_api}} + +#### Server behaviour + +For clients which have not joined a room, servers are required to only +return events where the room state at the event had the +`m.room.history_visibility` state event present with +`history_visibility` value `world_readable`. + +#### Security considerations + +Clients may wish to display to their users that rooms which are +`world_readable` *may* be showing messages to non-joined users. There is +no way using this module to find out whether any non-joined guest users +*do* see events in the room, or to list or count any lurking users. diff --git a/content/client-server-api/modules/room_upgrades.md b/content/client-server-api/modules/room_upgrades.md new file mode 100644 index 00000000..1e5437f3 --- /dev/null +++ b/content/client-server-api/modules/room_upgrades.md @@ -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. diff --git a/content/client-server-api/modules/search.md b/content/client-server-api/modules/search.md new file mode 100644 index 00000000..3dfe6463 --- /dev/null +++ b/content/client-server-api/modules/search.md @@ -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..next_batch` +- `search_categories..groups...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. diff --git a/content/client-server-api/modules/secrets.md b/content/client-server-api/modules/secrets.md new file mode 100644 index 00000000..7a337f42 --- /dev/null +++ b/content/client-server-api/modules/secrets.md @@ -0,0 +1,450 @@ +--- +type: module +weight: 110 +--- + +### Secrets + +Clients may have secret information that they wish to be made available +to other authorised clients, but that the server should not be able to +see, so the information must be encrypted as it passes through the +server. This can be done either asynchronously, by storing encrypted +data on the server for later retrieval, or synchronously, by sending +messages to each other. + +Each secret has an identifier that is used by clients to refer to the +secret when storing, fetching, requesting, or sharing the secret. +Secrets are plain strings; structured data can be stored by encoding it +as a string. + +#### Storage + +When secrets are stored on the server, they are stored in the user's +[account-data](#module-account-data), using an event type equal to the +secret's identifier. The keys that secrets are encrypted with are +described by data that is also stored in the user's account-data. Users +can have multiple keys, allowing them to control what sets of secrets +clients can access, depending on what keys are given to them. + +##### Key storage + +Each key has an ID, and the description of the key is stored in the +user's account\_data using the event type +`m.secret_storage.key.[key ID]`. The contents of the account data for +the key will include an `algorithm` property, which indicates the +encryption algorithm used, as well as a `name` property, which is a +human-readable name. Key descriptions may also have a `passphrase` +property for generating the key from a user-entered passphrase, as +described in [deriving keys from +passphrases](#deriving-keys-from-passphrases). + +`KeyDescription` + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
namestringRequired. The name of the key.

algorithm

string

Required. The encryption algorithm to be used for this key. Currently, only m.secret_storage.v1.aes-hmac-sha2 is supported.

passphrase

string

See deriving keys from passphrases section for a description of this property.

+ +Other properties depend on the encryption algorithm, and are described +below. + +A key can be marked as the "default" key by setting the user's +account\_data with event type `m.secret_storage.default_key` to an +object that has the ID of the key as its `key` property. The default key +will be used to encrypt all secrets that the user would expect to be +available on all their clients. Unless the user specifies otherwise, +clients will try to use the default key to decrypt secrets. + +##### Secret storage + +Encrypted data is stored in the user's account\_data using the event +type defined by the feature that uses the data. The account\_data will +have an `encrypted` property that is a map from key ID to an object. The +algorithm from the `m.secret_storage.key.[key ID]` data for the given +key defines how the other properties are interpreted, though it's +expected that most encryption schemes would have `ciphertext` and `mac` +properties, where the `ciphertext` property is the unpadded +base64-encoded ciphertext, and the `mac` is used to ensure the integrity +of the data. + +`Secret` + + + + + + + + + + + + + + + + +
ParameterTypeDescription

encrypted

{string: object}

Required. Map from key ID the encrypted data. The exact format for the encrypted data is dependent on the key algorithm. See the definition of AesHmacSha2EncryptedData in the m.secret_storage.v1.aes-hmac-sha2 section.

+ +Example: + +Some secret is encrypted using keys with ID `key_id_1` and `key_id_2`: + +`org.example.some.secret`: + + { + "encrypted": { + "key_id_1": { + "ciphertext": "base64+encoded+encrypted+data", + "mac": "base64+encoded+mac", + // ... other properties according to algorithm property in + // m.secret_storage.key.key_id_1 + }, + "key_id_2": { + // ... + } + } + } + +and the key descriptions for the keys would be: + +`m.secret_storage.key.key_id_1`: + + { + "name": "Some key", + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + // ... other properties according to algorithm + } + +`m.secret_storage.key.key_id_2`: + + { + "name": "Some other key", + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + // ... other properties according to algorithm + } + +###### `m.secret_storage.v1.aes-hmac-sha2` + +Secrets encrypted using the `m.secret_storage.v1.aes-hmac-sha2` +algorithm are encrypted using AES-CTR-256, and authenticated using +HMAC-SHA-256. The secret is encrypted as follows: + +1. Given the secret storage key, generate 64 bytes by performing an + HKDF with SHA-256 as the hash, a salt of 32 bytes of 0, and with the + secret name as the info. The first 32 bytes are used as the AES key, + and the next 32 bytes are used as the MAC key +2. Generate 16 random bytes, set bit 63 to 0 (in order to work around + differences in AES-CTR implementations), and use this as the AES + initialization vector. This becomes the `iv` property, encoded using + base64. +3. Encrypt the data using AES-CTR-256 using the AES key generated + above. This encrypted data, encoded using base64, becomes the + `ciphertext` property. +4. Pass the raw encrypted data (prior to base64 encoding) through + HMAC-SHA-256 using the MAC key generated above. The resulting MAC is + base64-encoded and becomes the `mac` property. + +`AesHmacSha2EncryptedData` + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

iv

string

Required. The 16-byte initialization vector, encoded as base64.

ciphertext

string

Required. The AES-CTR-encrypted data, encoded as base64.

macstringRequired. The MAC, encoded as base64.
+ +For the purposes of allowing clients to check whether a user has +correctly entered the key, clients should: + +1. encrypt and MAC a message consisting of 32 bytes of 0 as described + above, using the empty string as the info parameter to the HKDF in + step 1. +2. store the `iv` and `mac` in the `m.secret_storage.key.[key ID]` + account-data. + +`AesHmacSha2KeyDescription` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
namestringRequired. The name of the key.

algorithm

string

Required. The encryption algorithm to be used for this key. Currently, only m.secret_storage.v1.aes-hmac-sha2 is supported.

passphrase

object

See deriving keys from passphrases section for a description of this property.

ivstringThe 16-byte initialization vector, encoded as base64.

mac

string

The MAC of the result of encrypting 32 bytes of 0, encoded as base64.

+ +For example, the `m.secret_storage.key.key_id` for a key using this +algorithm could look like: + + { + "name": "m.default", + "algorithm": "m.secret_storage.v1.aes-hmac-sha2", + "iv": "random+data", + "mac": "mac+of+encrypted+zeros" + } + +and data encrypted using this algorithm could look like this: + + { + "encrypted": { + "key_id": { + "iv": "16+bytes+base64", + "ciphertext": "base64+encoded+encrypted+data", + "mac": "base64+encoded+mac" + } + } + } + +###### Key representation + +When a user is given a raw key for `m.secret_storage.v1.aes-hmac-sha2`, +it will be presented as a string constructed as follows: + +1. The key is prepended by the two bytes `0x8b` and `0x01` +2. All the bytes in the string above, including the two header bytes, + are XORed together to form a parity byte. This parity byte is + appended to the byte string. +3. The byte string is encoded using base58, using the same [mapping as + is used for Bitcoin + addresses](https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart), + that is, using the alphabet + `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. +4. The string is formatted into groups of four characters separated by + spaces. + +When decoding a raw key, the process should be reversed, with the +exception that whitespace is insignificant in the user's input. + +###### Deriving keys from passphrases + +A user may wish to use a chosen passphrase rather than a randomly +generated key. In this case, information on how to generate the key from +a passphrase will be stored in the `passphrase` property of the +`m.secret_storage.key.[key ID]` account-data. The `passphrase` property +has an `algorithm` property that indicates how to generate the key from +the passphrase. Other properties of the `passphrase` property are +defined by the `algorithm` specified. + +####### `m.pbkdf2` + +For the `m.pbkdf2` algorithm, the `passphrase` property has the +following properties: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
algorithmstringRequired. Must be m.pbkdf2
saltstringRequired. The salt used in PBKDF2.
iterationsintegerRequired. The number of iterations to use in PBKDF2.

bits

integer

Optional. The number of bits to generate for the key. Defaults to 256.

+ +The key is generated using PBKDF2 with SHA-512 as the hash, using the +salt given in the `salt` parameter, and the number of iterations given +in the `iterations` parameter. + +Example: + + { + "passphrase": { + "algorithm": "m.pbkdf2", + "salt": "MmMsAlty", + "iterations": 100000, + "bits": 256 + }, + ... + } + +#### Sharing + +To request a secret from other devices, a client sends an +`m.secret.requests` device event with `action` set to `request` and +`name` set to the identifier of the secret. A device that wishes to +share the secret will reply with an `m.secret.send` event, encrypted +using olm. When the original client obtains the secret, it sends an +`m.secret.request` event with `action` set to `request_cancellation` to +all devices other than the one that it received the secret from. Clients +should ignore `m.secret.send` events received from devices that it did +not send an `m.secret.request` event to. + +Clients must ensure that they only share secrets with other devices that +are allowed to see them. For example, clients should only share secrets +with the user’s own devices that are verified and may prompt the user to +confirm sharing the secret. + +##### Event definitions + +###### `m.secret.request` + +Sent by a client to request a secret from another device or to cancel a +previous request. It is sent as an unencrypted to-device event. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

name

string

Required if action is request. The name of the secret that is being requested.

actionenumRequired. One of ["request", "request_cancellation"].
requesting_device_idstringRequired. The ID of the device requesting the secret.

request_id

string

Required. A random string uniquely identifying (with respect to the requester and the target) the target for a secret. If the secret is requested from multiple devices at the same time, the same ID may be used for every target. The same ID is also used in order to cancel a previous request.

+ +Example: + + { + "name": "org.example.some.secret", + "action": "request", + "requesting_device_id": "ABCDEFG", + "request_id": "randomly_generated_id_9573" + } + +###### `m.secret.send` + +Sent by a client to share a secret with another device, in response to +an `m.secret.request` event. It must be encrypted as an +`m.room.encrypted` event, then sent as a to-device event. + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
request_idstringRequired. The ID of the request that this a response to.
secretstringRequired. The contents of the secret.
+ +Example: + + { + "request_id": "randomly_generated_id_9573", + "secret": "ThisIsASecretDon'tTellAnyone" + } diff --git a/content/client-server-api/modules/send_to_device.md b/content/client-server-api/modules/send_to_device.md new file mode 100644 index 00000000..1090aa82 --- /dev/null +++ b/content/client-server-api/modules/send_to_device.md @@ -0,0 +1,143 @@ +--- +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/%SERVER_RELEASE_LABEL%.html#send-to-device-messaging). + +#### Protocol definitions + +{{to\_device\_cs\_http\_api}} + +##### Extensions to /sync + +This module adds the following properties to the \_ response: + + + + + + + + + + + + + + + + +
ParameterTypeDescription

to_device

ToDevice

Optional. Information on the send-to-device messages for the client device.

+ +`ToDevice` + + + + + + + + + + + + + + + + +
ParameterTypeDescription
events[Event]List of send-to-device messages.
+ +`Event` + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription

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.

typestringThe type of event.
+ +Example response: + + { + "next_batch": "s72595_4483_1934", + "rooms": {"leave": {}, "join": {}, "invite": {}}, + "to_device": { + "events": [ + { + "sender": "@alice:example.com", + "type": "m.new_device", + "content": { + "device_id": "XYZABCDE", + "rooms": ["!726s6s6q:example.com"] + } + } + ] + } + } diff --git a/content/client-server-api/modules/server_acls.md b/content/client-server-api/modules/server_acls.md new file mode 100644 index 00000000..00d9a085 --- /dev/null +++ b/content/client-server-api/modules/server_acls.md @@ -0,0 +1,62 @@ +--- +type: module +weight: 290 +--- + +### Server Access Control Lists (ACLs) for rooms + +In some scenarios room operators may wish to prevent a malicious or +untrusted server from participating in their room. Sending an +[m.room.server\_acl]() state event into a room is an effective way to +prevent the server from participating in the room at the federation +level. + +Server ACLs can also be used to make rooms only federate with a limited +set of servers, or retroactively make the room no longer federate with +any other server, similar to setting the `m.federate` value on the +[m.room.create]() event. + +{{m\_room\_server\_acl\_event}} + +Note + +Port numbers are not supported because it is unclear to parsers whether +a port number should be matched or an IP address literal. Additionally, +it is unlikely that one would trust a server running on a particular +domain's port but not a different port, especially considering the +server host can easily change ports. + +Note + +CIDR notation is not supported for IP addresses because Matrix does not +encourage the use of IPs for identifying servers. Instead, a blanket +`allow_ip_literals` is provided to cover banning them. + +#### Client behaviour + +Clients are not expected to perform any additional duties beyond sending +the event. Clients should describe changes to the server ACLs to the +user in the user interface, such as in the timeline. + +Clients may wish to kick affected users from the room prior to denying a +server access to the room to help prevent those servers from +participating and to provide feedback to the users that they have been +excluded from the room. + +#### Server behaviour + +Servers MUST prevent blacklisted servers from sending events or +participating in the room when an [m.room.server\_acl]() event is +present in the room state. Which APIs are specifically affected are +described in the Server-Server API specification. + +Servers should still send events to denied servers if they are still +residents of the room. + +#### Security considerations + +Server ACLs are only effective if every server in the room honours them. +Servers that do not honour the ACLs may still permit events sent by +denied servers into the room, leaking them to other servers in the room. +To effectively enforce an ACL in a room, the servers that do not honour +the ACLs should be denied in the room as well. diff --git a/content/client-server-api/modules/server_notices.md b/content/client-server-api/modules/server_notices.md new file mode 100644 index 00000000..47b33afc --- /dev/null +++ b/content/client-server-api/modules/server_notices.md @@ -0,0 +1,68 @@ +--- +type: module +weight: 320 +--- + +### Server Notices + +Homeserver hosts often want to send messages to users in an official +capacity, or have resource limits which affect a user's ability to use +the homeserver. For example, the homeserver may be limited to a certain +number of active users per month and has exceeded that limit. To +communicate this failure to users, the homeserver would use the Server +Notices room. + +The aesthetics of the room (name, topic, avatar, etc) are left as an +implementation detail. It is recommended that the homeserver decorate +the room such that it looks like an official room to users. + +#### Events + +Notices are sent to the client as normal `m.room.message` events with a +`msgtype` of `m.server_notice` in the server notices room. Events with a +`m.server_notice` `msgtype` outside of the server notice room must be +ignored by clients. + +The specified values for `server_notice_type` are: + +`m.server_notice.usage_limit_reached` +The server has exceeded some limit which requires the server +administrator to intervene. The `limit_type` describes the kind of limit +reached. The specified values for `limit_type` are: + +`monthly_active_user` +The server's number of active users in the last 30 days has exceeded the +maximum. New connections are being refused by the server. What defines +"active" is left as an implementation detail, however servers are +encouraged to treat syncing users as "active". + +{{m\_room\_message\_m\_server\_notice\_event}} + +#### Client behaviour + +Clients can identify the server notices room by the `m.server_notice` +tag on the room. Active notices are represented by the [pinned +events](#m-room-pinned-events) in the server notices room. Server notice +events pinned in that room should be shown to the user through special +UI and not through the normal pinned events interface in the client. For +example, clients may show warning banners or bring up dialogs to get the +user's attention. Events which are not server notice events and are +pinned in the server notices room should be shown just like any other +pinned event in a room. + +The client must not expect to be able to reject an invite to join the +server notices room. Attempting to reject the invite must result in a +`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM` error. Servers should not prevent +the user leaving the room after joining the server notices room, however +the same error code must be used if the server will prevent leaving the +room. + +#### Server behaviour + +Servers should manage exactly 1 server notices room per user. Servers +must identify this room to clients with the `m.server_notice` tag. +Servers should invite the target user rather than automatically join +them to the server notice room. + +How servers send notices to clients, and which user they use to send the +events, is left as an implementation detail for the server. diff --git a/content/client-server-api/modules/sso_login.md b/content/client-server-api/modules/sso_login.md new file mode 100644 index 00000000..99787bf7 --- /dev/null +++ b/content/client-server-api/modules/sso_login.md @@ -0,0 +1,309 @@ +--- +type: module +weight: 220 +--- + +### SSO client login/authentication + +Single Sign-On (SSO) is a generic term which refers to protocols which +allow users to log into applications via a single web-based +authentication portal. Examples include OpenID Connect, "Central +Authentication Service" (CAS) and SAML. + +This module allows a Matrix homeserver to delegate user authentication +to an external authentication server supporting one of these protocols. +In this process, there are three systems involved: + +> - A Matrix client, using the APIs defined this specification, which +> is seeking to authenticate a user to a Matrix homeserver. +> - A Matrix homeserver, implementing the APIs defined in this +> specification, but which is delegating user authentication to the +> authentication server. +> - An "authentication server", which is responsible for +> authenticating the user. + +This specification is concerned only with communication between the +Matrix client and the homeserver, and is independent of the SSO protocol +used to communicate with the authentication server. Different Matrix +homeserver implementations might support different SSO protocols. + +Clients and homeservers implementing the SSO flow will need to consider +both [login]() and [user-interactive authentication](). The flow is +similar in both cases, but there are slight differences. + +Typically, SSO systems require a single "callback" URI to be configured +at the authentication server. Once the user is authenticated, their +browser is redirected to that URI. It is up to the Matrix homeserver +implementation to implement a suitable endpoint. For example, for CAS +authentication the homeserver should provide a means for the +administrator to configure where the CAS server is and the REST +endpoints which consume the ticket. + +#### Client login via SSO + +An overview of the process is as follows: + +1. The Matrix client calls `GET /login`\_ to find the supported login + types, and the homeserver includes a flow with + `"type": "m.login.sso"` in the response. +2. To initiate the `m.login.sso` login type, the Matrix client + instructs the user's browser to navigate to the + `/login/sso/redirect`\_ endpoint on the user's homeserver. +3. The homeserver responds with an HTTP redirect to the SSO user + interface, which the browser follows. +4. The authentication server and the homeserver interact to verify the + user's identity and other authentication information, potentially + using a number of redirects. +5. The browser is directed to the `redirectUrl` provided by the client + with a `loginToken` query parameter for the client to log in with. +6. The client exchanges the login token for an access token by calling + the `/login`\_ endpoint with a `type` of `m.login.token`. + +For native applications, typically steps 1 to 4 are carried out by +opening an embedded web view. + +These steps are illustrated as follows: + + Matrix Client Matrix Homeserver Auth Server + | | | + |-------------(0) GET /login----------->| | + |<-------------login types--------------| | + | | | + | Webview | | + | | | | + |----->| | | + | |--(1) GET /login/sso/redirect-->| | + | |<---------(2) 302---------------| | + | | | | + | |<========(3) Authentication process================>| + | | | | + | |<--(4) redirect to redirectUrl--| | + |<-----| | | + | | | + |---(5) POST /login with login token--->| | + |<-------------access token-------------| | + +Note + +In the older [r0.4.0 +version](https://matrix.org/docs/spec/client_server/r0.4.0.html#cas-based-client-login) +of this specification it was possible to authenticate via CAS when the +homeserver provides a `m.login.cas` login flow. This specification +deprecates the use of `m.login.cas` to instead prefer `m.login.sso`, +which is the same process with the only change being which redirect +endpoint to use: for `m.login.cas`, use `/cas/redirect` and for +`m.login.sso` use `/sso/redirect` (described below). The endpoints are +otherwise the same. + +##### Client behaviour + +The client starts the process by instructing the browser to navigate to +`/login/sso/redirect`\_ with an appropriate `redirectUrl`. Once +authentication is successful, the browser will be redirected to that +`redirectUrl`. + +{{sso\_login\_redirect\_cs\_http\_api}} + +###### Security considerations + +1. CSRF attacks via manipulation of parameters on the `redirectUrl` + + Clients should validate any requests to the `redirectUrl`. In + particular, it may be possible for attackers to falsify any query + parameters, leading to cross-site request forgery (CSRF) attacks. + + For example, consider a web-based client at + `https://client.example.com`, which wants to initiate SSO login on + the homeserver at `server.example.org`. It does this by storing the + homeserver name in a query parameter for the `redirectUrl`: it + redirects to + `https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=server.example.org`. + + An attacker could trick a victim into following a link to + `https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=evil.com`, + which would result in the client sending a login token for the + victim's account to the attacker-controlled site `evil.com`. + + To guard against this, clients MUST NOT store state (such as the + address of the homeserver being logged into) anywhere it can be + modified by external processes. + + Instead, the state could be stored in + [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) + or in a cookie. + +2. For added security, clients SHOULD include a unique identifier in + the `redirectUrl` and reject any callbacks that do not contain a + recognised identifier, to guard against unsolicited login attempts + and replay attacks. + +##### Server behaviour + +###### Redirecting to the Authentication server + +The server should handle +`/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect` as follows: + +1. It should build a suitable request for the SSO system. +2. It should store enough state that the flow can be securely resumed + after the SSO process completes. One way to do this is by storing a + cookie which is stored in the user's browser, by adding a + `Set-Cookie` header to the response. +3. It should redirect the user's browser to the SSO login page with the + appropriate parameters. + +See also the "Security considerations" below. + +###### Handling the callback from the Authentication server + +Note that there will normally be a single callback URI which is used for +both login and user-interactive authentication: it is up to the +homeserver implementation to distinguish which is taking place. + +The homeserver should validate the response from the SSO system: this +may require additional calls to the authentication server, and/or may +require checking a signature on the response. + +The homeserver then proceeds as follows: + +1. The homeserver MUST map the user details received from the + authentication server to a valid [Matrix user + identifier](../appendices.html#user-identifiers). The guidance in + [Mapping from other character + sets](../appendices.html#mapping-from-other-character-sets) may be + useful. +2. If the generated user identifier represents a new user, it should be + registered as a new user. +3. The homeserver should generate a short-term login token. This is an + opaque token, suitable for use with the `m.login.token` type of the + `/login`\_ API. The lifetime of this token SHOULD be limited to + around five seconds. +4. The homeserver adds a query parameter of `loginToken`, with the + value of the generated login token, to the `redirectUrl` given in + the `/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect` + request. (Note: `redirectURL` may or may not include existing query + parameters. If it already includes one or more `loginToken` + parameters, they should be removed before adding the new one.) +5. The homeserver redirects the user's browser to the URI thus built. + +##### Security considerations + +1. Homeservers should ensure that login tokens are not sent to + malicious clients. + + For example, consider a homeserver at `server.example.org`. An + attacker tricks a victim into following a link to + `https://server.example.org/login/sso/redirect?redirectUrl=https://evil.com`, + resulting in a login token being sent to the attacker-controlled + site `evil.com`. This is a form of cross-site request forgery + (CSRF). + + To mitigate this, Homeservers SHOULD confirm with the user that they + are happy to grant access to their matrix account to the site named + in the `redirectUrl`. This can be done either *before* redirecting + to the SSO login page when handling the + `/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect` + endpoint, or *after* login when handling the callback from the + authentication server. (If the check is performed before + redirecting, it is particularly important that the homeserver guards + against unsolicited authentication attempts as below). + + It may be appropriate to whitelist a set of known-trusted client + URLs in this process. In particular, the homeserver's own [login + fallback]() implementation could be excluded. + +2. For added security, homeservers SHOULD guard against unsolicited + authentication attempts by tracking pending requests. One way to do + this is to set a cookie when handling + `/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect`, which + is checked and cleared when handling the callback from the + authentication server. + +#### SSO during User-Interactive Authentication + +[User-interactive authentication]() is used by client-server endpoints +which require additional confirmation of the user's identity (beyond +holding an access token). Typically this means that the user must +re-enter their password, but for homeservers which delegate to an SSO +server, this means redirecting to the authentication server during +user-interactive auth. + +The implemementation of this is based on the [Fallback]() mechanism for +user-interactive auth. + +#### Client behaviour + +Clients do not need to take any particular additional steps beyond +ensuring that the fallback mechanism has been implemented, and treating +the `m.login.sso` authentication type the same as any other unknown type +(i.e. they should open a browser window for +`/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/m.login.sso/fallback/web?session=`. +Once the flow has completed, the client retries the request with the +session only.) + +#### Server behaviour + +##### Redirecting to the Authentication server + +The server should handle +`/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/m.login.sso/fallback/web` +in much the same way as +`/_matrix/client/%CLIENT_MAJOR_VERSION%/login/sso/redirect`, which is to +say: + +1. It should build a suitable request for the SSO system. +2. It should store enough state that the flow can be securely resumed + after the SSO process completes. One way to do this is by storing a + cookie which is stored in the user's browser, by adding a + `Set-Cookie` header to the response. +3. It should redirect the user's browser to the SSO login page with the + appropriate parameters. + +See also the "Security considerations" below. + +###### Handling the callback from the Authentication server + +Note that there will normally be a single callback URI which is used for +both login and user-interactive authentication: it is up to the +homeserver implementation to distinguish which is taking place. + +The homeserver should validate the response from the SSO system: this +may require additional calls to the authentication server, and/or may +require checking a signature on the response. + +The homeserver then returns the [user-interactive authentication +fallback completion]() page to the user's browser. + +###### Security considerations + +1. Confirming the operation + + The homeserver SHOULD confirm that the user is happy for the + operation to go ahead. The goal of the user-interactive + authentication operation is to guard against a compromised + `access_token` being used to take over the user's account. Simply + redirecting the user to the SSO system is insufficient, since they + may not realise what is being asked of them, or the SSO system may + even confirm the authentication automatically. + + For example, the homeserver might serve a page with words to the + effect of: + + > A client is trying to remove a device from your account. To + > confirm this action, re-authenticate with single sign-on. If you + > did not expect this, your account may be compromised! + + This confirmation could take place before redirecting to the SSO + authentication page (when handling the + `/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/m.login.sso/fallback/web` + endpoint), or *after* authentication when handling the callback from + the authentication server. (If the check is performed before + redirecting, it is particularly important that the homeserver guards + against unsolicited authentication attempts as below). + +2. For added security, homeservers SHOULD guard against unsolicited + authentication attempts by tracking pending requests. One way to do + this is to set a cookie when handling + `/_matrix/client/%CLIENT_MAJOR_VERSION%/auth/m.login.sso/fallback/web`, + which is checked and cleared when handling the callback from the + authentication server. diff --git a/content/client-server-api/modules/stickers.md b/content/client-server-api/modules/stickers.md new file mode 100644 index 00000000..b1435f21 --- /dev/null +++ b/content/client-server-api/modules/stickers.md @@ -0,0 +1,40 @@ +--- +type: module +weight: 250 +--- + +### Sticker Messages + +This module allows users to send sticker messages in to rooms or direct +messaging sessions. + +Sticker messages are specialised image messages that are displayed +without controls (e.g. no "download" link, or light-box view on click, +as would be displayed for for [m.image]() events). + +Sticker messages are intended to provide simple "reaction" events in the +message timeline. The matrix client should provide some mechanism to +display the sticker "body" e.g. as a tooltip on hover, or in a modal +when the sticker image is clicked. + +#### Events + +Sticker events are received as a single `m.sticker` event in the +`timeline` section of a room, in a `/sync`. + +{{m\_sticker\_event}} + +#### Client behaviour + +Clients supporting this message type should display the image content +from the event URL directly in the timeline. + +A thumbnail image should be provided in the `info` object. This is +largely intended as a fallback for clients that do not fully support the +`m.sticker` event type. In most cases it is fine to set the thumbnail +URL to the same URL as the main event content. + +It is recommended that sticker image content should be 512x512 pixels in +size or smaller. The dimensions of the image file should be twice the +intended display size specified in the `info` object in order to assist +rendering sharp images on higher DPI screens. diff --git a/content/client-server-api/modules/tags.md b/content/client-server-api/modules/tags.md new file mode 100644 index 00000000..e84da4e2 --- /dev/null +++ b/content/client-server-api/modules/tags.md @@ -0,0 +1,66 @@ +--- +type: module +weight: 180 +--- + +### Room Tagging + +Users can add tags to rooms. Tags are namespaced strings used to label +rooms. A room may have multiple tags. Tags are only visible to the user +that set them but are shared across all their devices. + +#### Events + +The tags on a room are received as single `m.tag` event in the +`account_data` section of a room. The content of the `m.tag` event is a +`tags` key whose value is an object mapping the name of each tag to +another object. + +The JSON object associated with each tag gives information about the +tag, e.g how to order the rooms with a given tag. + +Ordering information is given under the `order` key as a number between +0 and 1. The numbers are compared such that 0 is displayed first. +Therefore a room with an `order` of `0.2` would be displayed before a +room with an `order` of `0.7`. If a room has a tag without an `order` +key then it should appear after the rooms with that tag that have an +`order` key. + +The name of a tag MUST NOT exceed 255 bytes. + +The tag namespace is defined as follows: + +- The namespace `m.*` is reserved for tags defined in the Matrix + specification. Clients must ignore any tags in this namespace they + don't understand. +- The namespace `u.*` is reserved for user-defined tags. The portion + of the string after the `u.` is defined to be the display name of + this tag. No other semantics should be inferred from tags in this + namespace. +- A client or app willing to use special tags for advanced + functionality should namespace them similarly to state keys: + `tld.name.*` +- Any tag in the `tld.name.*` form but not matching the namespace of + the current client should be ignored +- Any tag not matching the above rules should be interpreted as a user + tag from the `u.*` namespace, as if the name had already had `u.` + stripped from the start (ie. the name of the tag is used as the + display name directly). These non-namespaced tags are supported for + historical reasons. New tags should use one of the defined + namespaces above. + +Several special names are listed in the specification: The following +tags are defined in the `m.*` namespace: + +- `m.favourite`: The user's favourite rooms. These should be shown + with higher precedence than other rooms. +- `m.lowpriority`: These should be shown with lower precedence than + others. +- `m.server_notice`: Used to identify [Server Notice + Rooms](#module-server-notices). + +{{m\_tag\_event}} + +#### Client Behaviour + +{{tags\_cs\_http\_api}} diff --git a/content/client-server-api/modules/third_party_invites.md b/content/client-server-api/modules/third_party_invites.md new file mode 100644 index 00000000..1c689fe5 --- /dev/null +++ b/content/client-server-api/modules/third_party_invites.md @@ -0,0 +1,235 @@ +--- +type: module +weight: 140 +--- + +### Third party invites + +This module adds in support for inviting new members to a room where +their Matrix user ID is not known, instead addressing them by a third +party identifier such as an email address. There are two flows here; one +if a Matrix user ID is known for the third party identifier, and one if +not. Either way, the client calls `/invite` with the details of the +third party identifier. + +The homeserver asks the identity server whether a Matrix user ID is +known for that identifier: + +- If it is, an invite is simply issued for that user. +- If it is not, the homeserver asks the identity server to record the + details of the invitation, and to notify the invitee's homeserver of + this pending invitation if it gets a binding for this identifier in + the future. The identity server returns a token and public key to + the inviting homeserver. + +When the invitee's homeserver receives the notification of the binding, +it should insert an `m.room.member` event into the room's graph for that +user, with `content.membership` = `invite`, as well as a +`content.third_party_invite` property which contains proof that the +invitee does indeed own that third party identifier. See the +[m.room.member](#m-room-member) schema for more information. + +#### Events + +{{m\_room\_third\_party\_invite\_event}} + +#### Client behaviour + +A client asks a server to invite a user by their third party identifier. + +{{third\_party\_membership\_cs\_http\_api}} + +#### Server behaviour + +Upon receipt of an `/invite`, the server is expected to look up the +third party identifier with the provided identity server. If the lookup +yields a result for a Matrix User ID then the normal invite process can +be initiated. This process ends up looking like this: + + +---------+ +-------------+ +-----------------+ + | Client | | Homeserver | | IdentityServer | + +---------+ +-------------+ +-----------------+ + | | | + | POST /invite | | + |------------------------------------>| | + | | | + | | GET /lookup | + | |--------------------------------------------------->| + | | | + | | User ID result | + | |<---------------------------------------------------| + | | | + | | Invite process for the discovered User ID | + | |------------------------------------------ | + | | | | + | |<----------------------------------------- | + | | | + | Complete the /invite request | | + |<------------------------------------| | + | | | + +However, if the lookup does not yield a bound User ID, the homeserver +must store the invite on the identity server and emit a valid +`m.room.third_party_invite` event to the room. This process ends up +looking like this: + + +---------+ +-------------+ +-----------------+ + | Client | | Homeserver | | IdentityServer | + +---------+ +-------------+ +-----------------+ + | | | + | POST /invite | | + |------------------------------------>| | + | | | + | | GET /lookup | + | |-------------------------------------------------------------->| + | | | + | | "no users" result | + | |<--------------------------------------------------------------| + | | | + | | POST /store-invite | + | |-------------------------------------------------------------->| + | | | + | | Information needed for the m.room.third_party_invite | + | |<--------------------------------------------------------------| + | | | + | | Emit m.room.third_party_invite to the room | + | |------------------------------------------- | + | | | | + | |<------------------------------------------ | + | | | + | Complete the /invite request | | + |<------------------------------------| | + | | | + +All homeservers MUST verify the signature in the event's +`content.third_party_invite.signed` object. + +The third party user will then need to verify their identity, which +results in a call from the identity server to the homeserver that bound +the third party identifier to a user. The homeserver then exchanges the +`m.room.third_party_invite` event in the room for a complete +`m.room.member` event for `membership: invite` for the user that has +bound the third party identifier. + +If a homeserver is joining a room for the first time because of an +`m.room.third_party_invite`, the server which is already participating +in the room (which is chosen as per the standard server-server +specification) MUST validate that the public key used for signing is +still valid, by checking `key_validity_url` in the above described way. + +No other homeservers may reject the joining of the room on the basis of +`key_validity_url`, this is so that all homeservers have a consistent +view of the room. They may, however, indicate to their clients that a +member's membership is questionable. + +For example, given H1, H2, and H3 as homeservers, UserA as a user of H1, +and an identity server IS, the full sequence for a third party invite +would look like the following. This diagram assumes H1 and H2 are +residents of the room while H3 is attempting to join. + + +-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+ + | UserA | | ThirdPartyUser | | H1 | | H2 | | H3 | | IS | + +-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+ + | | | | | | + | POST /invite for ThirdPartyUser | | | | + |----------------------------------->| | | | + | | | | | | + | | | GET /lookup | | | + | | |---------------------------------------------------------------------------------------------->| + | | | | | | + | | | | Lookup results (empty object) | + | | |<----------------------------------------------------------------------------------------------| + | | | | | | + | | | POST /store-invite | | | + | | |---------------------------------------------------------------------------------------------->| + | | | | | | + | | | | Token, keys, etc for third party invite | + | | |<----------------------------------------------------------------------------------------------| + | | | | | | + | | | (Federation) Emit m.room.third_party_invite | | | + | | |----------------------------------------------->| | | + | | | | | | + | Complete /invite request | | | | + |<-----------------------------------| | | | + | | | | | | + | | Verify identity | | | | + | |-------------------------------------------------------------------------------------------------------------------->| + | | | | | | + | | | | | POST /3pid/onbind | + | | | | |<---------------------------| + | | | | | | + | | | PUT /exchange_third_party_invite/:roomId | | + | | |<-----------------------------------------------------------------| | + | | | | | | + | | | Verify the request | | | + | | |------------------- | | | + | | | | | | | + | | |<------------------ | | | + | | | | | | + | | | (Federation) Emit m.room.member for invite | | | + | | |----------------------------------------------->| | | + | | | | | | + | | | | | | + | | | (Federation) Emit the m.room.member event sent to H2 | | + | | |----------------------------------------------------------------->| | + | | | | | | + | | | Complete /exchange_third_party_invite/:roomId request | | + | | |----------------------------------------------------------------->| | + | | | | | | + | | | | | Participate in the room | + | | | | |------------------------ | + | | | | | | | + | | | | |<----------------------- | + | | | | | | + +Note that when H1 sends the `m.room.member` event to H2 and H3 it does +not have to block on either server's receipt of the event. Likewise, H1 +may complete the `/exchange_third_party_invite/:roomId` request at the +same time as sending the `m.room.member` event to H2 and H3. +Additionally, H3 may complete the `/3pid/onbind` request it got from IS +at any time - the completion is not shown in the diagram. + +H1 MUST verify the request from H3 to ensure the `signed` property is +correct as well as the `key_validity_url` as still being valid. This is +done by making a request to the [identity server +/isvalid](../identity_service/%IDENTITY_RELEASE_LABEL%.html#get-matrix-identity-v2-pubkey-isvalid) +endpoint, using the provided URL rather than constructing a new one. The +query string and response for the provided URL must match the Identity +Service Specification. + +The reason that no other homeserver may reject the event based on +checking `key_validity_url` is that we must ensure event acceptance is +deterministic. If some other participating server doesn't have a network +path to the keyserver, or if the keyserver were to go offline, or revoke +its keys, that other server would reject the event and cause the +participating servers' graphs to diverge. This relies on participating +servers trusting each other, but that trust is already implied by the +server-server protocol. Also, the public key signature verification must +still be performed, so the attack surface here is minimized. + +#### Security considerations + +There are a number of privacy and trust implications to this module. + +It is important for user privacy that leaking the mapping between a +matrix user ID and a third party identifier is hard. In particular, +being able to look up all third party identifiers from a matrix user ID +(and accordingly, being able to link each third party identifier) should +be avoided wherever possible. To this end, the third party identifier is +not put in any event, rather an opaque display name provided by the +identity server is put into the events. Clients should not remember or +display third party identifiers from invites, other than for the use of +the inviter themself. + +Homeservers are not required to trust any particular identity server(s). +It is generally a client's responsibility to decide which identity +servers it trusts, not a homeserver's. Accordingly, this API takes +identity servers as input from end users, and doesn't have any specific +trusted set. It is possible some homeservers may want to supply +defaults, or reject some identity servers for *its* users, but no +homeserver is allowed to dictate which identity servers *other* +homeservers' users trust. + +There is some risk of denial of service attacks by flooding homeservers +or identity servers with many requests, or much state to store. +Defending against these is left to the implementer's discretion. diff --git a/content/client-server-api/modules/third_party_networks.md b/content/client-server-api/modules/third_party_networks.md new file mode 100644 index 00000000..13142470 --- /dev/null +++ b/content/client-server-api/modules/third_party_networks.md @@ -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}} diff --git a/content/client-server-api/modules/typing_notifications.md b/content/client-server-api/modules/typing_notifications.md new file mode 100644 index 00000000..d899b4e1 --- /dev/null +++ b/content/client-server-api/modules/typing_notifications.md @@ -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. diff --git a/content/client-server-api/modules/voip_events.md b/content/client-server-api/modules/voip_events.md new file mode 100644 index 00000000..9c155708 --- /dev/null +++ b/content/client-server-api/modules/voip_events.md @@ -0,0 +1,87 @@ +--- +type: module +weight: 20 +--- + +### Voice over IP + +This module outlines how two users in a room can set up a Voice over IP +(VoIP) call to each other. Voice and video calls are built upon the +WebRTC 1.0 standard. Call signalling is achieved by sending [message +events]() to the room. In this version of the spec, only two-party +communication is supported (e.g. between two peers, or between a peer +and a multi-point conferencing unit). This means that clients MUST only +send call events to rooms with exactly two participants. + +#### Events + +{{voip\_events}} + +#### Client behaviour + +A call is set up with message events exchanged as follows: + + Caller Callee + [Place Call] + m.call.invite -----------> + m.call.candidate --------> + [..candidates..] --------> + [Answers call] + <--------------- m.call.answer + [Call is active and ongoing] + <--------------- m.call.hangup + +Or a rejected call: + + Caller Callee + m.call.invite ------------> + m.call.candidate ---------> + [..candidates..] ---------> + [Rejects call] + <-------------- m.call.hangup + +Calls are negotiated according to the WebRTC specification. + +##### Glare + +"Glare" is a problem which occurs when two users call each other at +roughly the same time. This results in the call failing to set up as +there already is an incoming/outgoing call. A glare resolution algorithm +can be used to determine which call to hangup and which call to answer. +If both clients implement the same algorithm then they will both select +the same call and the call will be successfully connected. + +As calls are "placed" to rooms rather than users, the glare resolution +algorithm outlined below is only considered for calls which are to the +same room. The algorithm is as follows: + +- If an `m.call.invite` to a room is received whilst the client is + **preparing to send** an `m.call.invite` to the same room: + - the client should cancel its outgoing call and instead + automatically accept the incoming call on behalf of the user. +- If an `m.call.invite` to a room is received **after the client has + sent** an `m.call.invite` to the same room and is waiting for a + response: + - the client should perform a lexicographical comparison of the + call IDs of the two calls and use the *lesser* of the two calls, + aborting the greater. If the incoming call is the lesser, the + client should accept this call on behalf of the user. + +The call setup should appear seamless to the user as if they had simply +placed a call and the other party had accepted. This means any media +stream that had been setup for use on a call should be transferred and +used for the call that replaces it. + +#### Server behaviour + +The homeserver MAY provide a TURN server which clients can use to +contact the remote party. The following HTTP API endpoints will be used +by clients in order to get information about the TURN server. + +{{voip\_cs\_http\_api}} + +#### Security considerations + +Calls should only be placed to rooms with one other user in them. If +they are placed to group chat rooms it is possible that another user +will intercept and answer the call. diff --git a/layouts/shortcodes/cs-modules.html b/layouts/shortcodes/cs-modules.html new file mode 100644 index 00000000..eb294166 --- /dev/null +++ b/layouts/shortcodes/cs-modules.html @@ -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 }}