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
+
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+
+
+url |
+string |
+Required. The URL to the file. |
+
+
+key |
+JWK |
+Required. 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`
+
+
+
+
+
+
+
+kty |
+string |
+Required. Key type. Must be oct . |
+
+
+key_ops |
+[string] |
+Required. Key operations. Must at least contain encrypt and decrypt . |
+
+
+alg |
+string |
+Required. Algorithm. Must be A256CTR . |
+
+
+k |
+string |
+Required. 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`
+
+
+
+
+
+
+
+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:
+
+
+
+
+
+
+
+ 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:
+
+
+
+
+
+
+
+ 1 |
+ Export format version, which must be 0x01 . |
+
+
+ 16 |
+ The salt S. |
+
+
+ 16 |
+ The initialization vector IV. |
+
+
+ 4 |
+ The number of rounds N, as a big-endian unsigned 32-bit integer. |
+
+
+ variable |
+ The 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`
+
+
+
+
+
+
+
+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_id |
+string |
+Required. The ID of the session. |
+
+
+session_key |
+string |
+Required. 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.
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+
+
+name |
+string |
+Required. 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`
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+
+
+iv |
+string |
+Required. The 16-byte initialization vector, encoded as base64. |
+
+
+ciphertext |
+string |
+Required. The AES-CTR-encrypted data, encoded as base64. |
+
+
+mac |
+string |
+Required. 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`
+
+
+
+
+
+
+
+name |
+string |
+Required. 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. |
+
+
+iv |
+string |
+The 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:
+
+
+
+
+
+
+
+algorithm |
+string |
+Required. Must be m.pbkdf2 |
+
+
+salt |
+string |
+Required. The salt used in PBKDF2. |
+
+
+iterations |
+integer |
+Required. 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.
+
+
+
+
+
+
+
+name |
+string |
+Required if action is request . The name of the secret that is being requested. |
+
+
+action |
+enum |
+Required. One of ["request", "request_cancellation"]. |
+
+
+requesting_device_id |
+string |
+Required. 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.
+
+
+
+
+
+
+
+request_id |
+string |
+Required. The ID of the request that this a response to. |
+
+
+secret |
+string |
+Required. 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:
+
+
+
+
+
+
+
+to_device |
+ToDevice |
+Optional. Information on the send-to-device messages for the client device. |
+
+
+
+
+`ToDevice`
+
+
+
+
+
+
+
+events |
+[Event] |
+List of send-to-device messages. |
+
+
+
+
+`Event`
+
+
+
+
+
+
+
+content |
+EventContent |
+The content of this event. The fields in this object will vary depending on the type of event. |
+
+
+sender |
+string |
+The Matrix user ID of the user who sent this event. |
+
+
+type |
+string |
+The type of event. |
+
+
+
+
+Example response:
+
+ {
+ "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 }}