Merge branch 'master' into travis/spec/MSC2320-identity-versions
This commit is contained in:
commit
fc6aa30000
62 changed files with 1858 additions and 261 deletions
|
@ -232,6 +232,18 @@ reserved for events defined in the Matrix specification - for instance
|
|||
`m.room.message` is the event type for instant messages. Events are
|
||||
usually sent in the context of a "Room".
|
||||
|
||||
{{% boxes/warning %}}
|
||||
Event bodies are considered untrusted data. This means that any application using
|
||||
Matrix must validate that the event body is of the expected shape/schema
|
||||
before using the contents verbatim.
|
||||
|
||||
**It is not safe to assume that an event body will have all the expected
|
||||
fields of the expected types.**
|
||||
|
||||
See [MSC2801](https://github.com/matrix-org/matrix-doc/pull/2801) for more
|
||||
detail on why this assumption is unsafe.
|
||||
{{% /boxes/warning %}}
|
||||
|
||||
### Event Graphs
|
||||
|
||||
Events exchanged in the context of a room are stored in a directed
|
||||
|
@ -315,12 +327,12 @@ sent to the room `!qporfwt:matrix.org`:
|
|||
Federation maintains *shared data structures* per-room between multiple
|
||||
homeservers. The data is split into `message events` and `state events`.
|
||||
|
||||
Message events:
|
||||
Message events:
|
||||
These describe transient 'once-off' activity in a room such as an
|
||||
instant messages, VoIP call setups, file transfers, etc. They generally
|
||||
describe communication activity.
|
||||
|
||||
State events:
|
||||
State events:
|
||||
These describe updates to a given piece of persistent information
|
||||
('state') related to a room, such as the room's name, topic, membership,
|
||||
participating servers, etc. State is modelled as a lookup table of
|
||||
|
@ -493,7 +505,7 @@ stable and unstable periodically for a variety of reasons, including
|
|||
discovered security vulnerabilities and age.
|
||||
|
||||
Clients should not ask room administrators to upgrade their rooms if the
|
||||
room is running a stable version. Servers SHOULD use room version 6 as
|
||||
room is running a stable version. Servers SHOULD use **room version 6** as
|
||||
the default room version when creating new rooms.
|
||||
|
||||
The available room versions are:
|
||||
|
@ -510,10 +522,11 @@ The available room versions are:
|
|||
signing key validity periods.
|
||||
- [Version 6](/rooms/v6) - **Stable**. Alters several
|
||||
authorization rules for events.
|
||||
- [Version 7](/rooms/v7) - **Stable**. Introduces knocking.
|
||||
|
||||
## Specification Versions
|
||||
|
||||
The specification for each API is versioned in the form `rX.Y.Z`.
|
||||
The specification for each API is versioned in the form `rX.Y.Z`.
|
||||
- A change to `X` reflects a breaking change: a client implemented
|
||||
against `r1.0.0` may need changes to work with a server which
|
||||
supports (only) `r2.0.0`.
|
||||
|
|
|
@ -68,118 +68,118 @@ request being made was invalid.
|
|||
|
||||
The common error codes are:
|
||||
|
||||
`M_FORBIDDEN`
|
||||
`M_FORBIDDEN`
|
||||
Forbidden access, e.g. joining a room without permission, failed login.
|
||||
|
||||
`M_UNKNOWN_TOKEN`
|
||||
`M_UNKNOWN_TOKEN`
|
||||
The access token specified was not recognised.
|
||||
|
||||
An additional response parameter, `soft_logout`, might be present on the
|
||||
response for 401 HTTP status codes. See [the soft logout
|
||||
section](#soft-logout) for more information.
|
||||
|
||||
`M_MISSING_TOKEN`
|
||||
`M_MISSING_TOKEN`
|
||||
No access token was specified for the request.
|
||||
|
||||
`M_BAD_JSON`
|
||||
`M_BAD_JSON`
|
||||
Request contained valid JSON, but it was malformed in some way, e.g.
|
||||
missing required keys, invalid values for keys.
|
||||
|
||||
`M_NOT_JSON`
|
||||
`M_NOT_JSON`
|
||||
Request did not contain valid JSON.
|
||||
|
||||
`M_NOT_FOUND`
|
||||
`M_NOT_FOUND`
|
||||
No resource was found for this request.
|
||||
|
||||
`M_LIMIT_EXCEEDED`
|
||||
`M_LIMIT_EXCEEDED`
|
||||
Too many requests have been sent in a short period of time. Wait a while
|
||||
then try again.
|
||||
|
||||
`M_UNKNOWN`
|
||||
`M_UNKNOWN`
|
||||
An unknown error has occurred.
|
||||
|
||||
Other error codes the client might encounter are:
|
||||
|
||||
`M_UNRECOGNIZED`
|
||||
`M_UNRECOGNIZED`
|
||||
The server did not understand the request.
|
||||
|
||||
`M_UNAUTHORIZED`
|
||||
`M_UNAUTHORIZED`
|
||||
The request was not correctly authorized. Usually due to login failures.
|
||||
|
||||
`M_USER_DEACTIVATED`
|
||||
`M_USER_DEACTIVATED`
|
||||
The user ID associated with the request has been deactivated. Typically
|
||||
for endpoints that prove authentication, such as `/login`.
|
||||
|
||||
`M_USER_IN_USE`
|
||||
`M_USER_IN_USE`
|
||||
Encountered when trying to register a user ID which has been taken.
|
||||
|
||||
`M_INVALID_USERNAME`
|
||||
`M_INVALID_USERNAME`
|
||||
Encountered when trying to register a user ID which is not valid.
|
||||
|
||||
`M_ROOM_IN_USE`
|
||||
`M_ROOM_IN_USE`
|
||||
Sent when the room alias given to the `createRoom` API is already in
|
||||
use.
|
||||
|
||||
`M_INVALID_ROOM_STATE`
|
||||
`M_INVALID_ROOM_STATE`
|
||||
Sent when the initial state given to the `createRoom` API is invalid.
|
||||
|
||||
`M_THREEPID_IN_USE`
|
||||
`M_THREEPID_IN_USE`
|
||||
Sent when a threepid given to an API cannot be used because the same
|
||||
threepid is already in use.
|
||||
|
||||
`M_THREEPID_NOT_FOUND`
|
||||
`M_THREEPID_NOT_FOUND`
|
||||
Sent when a threepid given to an API cannot be used because no record
|
||||
matching the threepid was found.
|
||||
|
||||
`M_THREEPID_AUTH_FAILED`
|
||||
`M_THREEPID_AUTH_FAILED`
|
||||
Authentication could not be performed on the third party identifier.
|
||||
|
||||
`M_THREEPID_DENIED`
|
||||
`M_THREEPID_DENIED`
|
||||
The server does not permit this third party identifier. This may happen
|
||||
if the server only permits, for example, email addresses from a
|
||||
particular domain.
|
||||
|
||||
`M_SERVER_NOT_TRUSTED`
|
||||
`M_SERVER_NOT_TRUSTED`
|
||||
The client's request used a third party server, e.g. identity server,
|
||||
that this server does not trust.
|
||||
|
||||
`M_UNSUPPORTED_ROOM_VERSION`
|
||||
`M_UNSUPPORTED_ROOM_VERSION`
|
||||
The client's request to create a room used a room version that the
|
||||
server does not support.
|
||||
|
||||
`M_INCOMPATIBLE_ROOM_VERSION`
|
||||
`M_INCOMPATIBLE_ROOM_VERSION`
|
||||
The client attempted to join a room that has a version the server does
|
||||
not support. Inspect the `room_version` property of the error response
|
||||
for the room's version.
|
||||
|
||||
`M_BAD_STATE`
|
||||
`M_BAD_STATE`
|
||||
The state change requested cannot be performed, such as attempting to
|
||||
unban a user who is not banned.
|
||||
|
||||
`M_GUEST_ACCESS_FORBIDDEN`
|
||||
`M_GUEST_ACCESS_FORBIDDEN`
|
||||
The room or resource does not permit guests to access it.
|
||||
|
||||
`M_CAPTCHA_NEEDED`
|
||||
`M_CAPTCHA_NEEDED`
|
||||
A Captcha is required to complete the request.
|
||||
|
||||
`M_CAPTCHA_INVALID`
|
||||
`M_CAPTCHA_INVALID`
|
||||
The Captcha provided did not match what was expected.
|
||||
|
||||
`M_MISSING_PARAM`
|
||||
`M_MISSING_PARAM`
|
||||
A required parameter was missing from the request.
|
||||
|
||||
`M_INVALID_PARAM`
|
||||
`M_INVALID_PARAM`
|
||||
A parameter that was specified has the wrong value. For example, the
|
||||
server expected an integer and instead received a string.
|
||||
|
||||
`M_TOO_LARGE`
|
||||
`M_TOO_LARGE`
|
||||
The request or entity was too large.
|
||||
|
||||
`M_EXCLUSIVE`
|
||||
`M_EXCLUSIVE`
|
||||
The resource being requested is reserved by an application service, or
|
||||
the application service making the request has not created the resource.
|
||||
|
||||
`M_RESOURCE_LIMIT_EXCEEDED`
|
||||
`M_RESOURCE_LIMIT_EXCEEDED`
|
||||
The request cannot be completed because the homeserver has reached a
|
||||
resource limit imposed on it. For example, a homeserver held in a shared
|
||||
hosting environment may reach a resource limit if it starts using too
|
||||
|
@ -189,7 +189,7 @@ Typically, this error will appear on routes which attempt to modify
|
|||
state (e.g.: sending messages, account data, etc) and not routes which
|
||||
only read state (e.g.: `/sync`, get account data, etc).
|
||||
|
||||
`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
|
||||
`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
|
||||
The user is unable to reject an invite to join the server notices room.
|
||||
See the [Server Notices](#server-notices) module for more information.
|
||||
|
||||
|
@ -238,23 +238,23 @@ time.
|
|||
|
||||
In this section, the following terms are used with specific meanings:
|
||||
|
||||
`PROMPT`
|
||||
`PROMPT`
|
||||
Retrieve the specific piece of information from the user in a way which
|
||||
fits within the existing client user experience, if the client is
|
||||
inclined to do so. Failure can take place instead if no good user
|
||||
experience for this is possible at this point.
|
||||
|
||||
`IGNORE`
|
||||
`IGNORE`
|
||||
Stop the current auto-discovery mechanism. If no more auto-discovery
|
||||
mechanisms are available, then the client may use other methods of
|
||||
determining the required parameters, such as prompting the user, or
|
||||
using default values.
|
||||
|
||||
`FAIL_PROMPT`
|
||||
`FAIL_PROMPT`
|
||||
Inform the user that auto-discovery failed due to invalid/empty data and
|
||||
`PROMPT` for the parameter.
|
||||
|
||||
`FAIL_ERROR`
|
||||
`FAIL_ERROR`
|
||||
Inform the user that auto-discovery did not return any usable URLs. Do
|
||||
not continue further with the current login process. At this point,
|
||||
valid data was obtained, but no server is available to serve the client.
|
||||
|
@ -606,7 +606,7 @@ flow with three stages will resemble the following diagram:
|
|||
|
||||
#### Authentication types
|
||||
|
||||
This specification defines the following auth types:
|
||||
This specification defines the following auth types:
|
||||
- `m.login.password`
|
||||
- `m.login.recaptcha`
|
||||
- `m.login.sso`
|
||||
|
@ -893,7 +893,7 @@ type of identifier being used, and depending on the type, has other
|
|||
fields giving the information required to identify the user as described
|
||||
below.
|
||||
|
||||
This specification defines the following identifier types:
|
||||
This specification defines the following identifier types:
|
||||
- `m.id.user`
|
||||
- `m.id.thirdparty`
|
||||
- `m.id.phone`
|
||||
|
@ -1381,6 +1381,18 @@ opaque string. No changes should be required to support the currently
|
|||
available room versions.
|
||||
{{% /boxes/warning %}}
|
||||
|
||||
{{% boxes/warning %}}
|
||||
Event bodies are considered untrusted data. This means that any application using
|
||||
Matrix must validate that the event body is of the expected shape/schema
|
||||
before using the contents verbatim.
|
||||
|
||||
**It is not safe to assume that an event body will have all the expected
|
||||
fields of the expected types.**
|
||||
|
||||
See [MSC2801](https://github.com/matrix-org/matrix-doc/pull/2801) for more
|
||||
detail on why this assumption is unsafe.
|
||||
{{% /boxes/warning %}}
|
||||
|
||||
### Types of room events
|
||||
|
||||
Room events are split into two categories:
|
||||
|
@ -1435,7 +1447,7 @@ following fields.
|
|||
|
||||
### Size limits
|
||||
|
||||
The complete event MUST NOT be larger than 65535 bytes, when formatted
|
||||
The complete event MUST NOT be larger than 65536 bytes, when formatted
|
||||
as a [PDU for the Server-Server
|
||||
protocol](/server-server-api/#pdus), including any
|
||||
signatures, and encoded as [Canonical
|
||||
|
@ -1451,7 +1463,7 @@ There are additional restrictions on sizes per key:
|
|||
|
||||
Some event types have additional size restrictions which are specified
|
||||
in the description of the event. Additional keys have no limit other
|
||||
than that implied by the total 65 KB limit on events.
|
||||
than that implied by the total 64 KiB limit on events.
|
||||
|
||||
### Room Events
|
||||
|
||||
|
@ -1700,7 +1712,7 @@ event also has a `creator` key which contains the user ID of the room
|
|||
creator. It will also generate several other events in order to manage
|
||||
permissions in this room. This includes:
|
||||
|
||||
- `m.room.power_levels` : Sets the power levels of users and required power
|
||||
- `m.room.power_levels` : Sets the power levels of users and required power
|
||||
levels for various actions within the room such as sending events.
|
||||
|
||||
- `m.room.join_rules` : Whether the room is "invite-only" or not.
|
||||
|
@ -1766,57 +1778,44 @@ in that room. There are several states in which a user may be, in
|
|||
relation to a room:
|
||||
|
||||
- Unrelated (the user cannot send or receive events in the room)
|
||||
- Knocking (the user has requested to participate in the room, but has
|
||||
not yet been allowed to)
|
||||
- Invited (the user has been invited to participate in the room, but
|
||||
is not yet participating)
|
||||
- Joined (the user can send and receive events in the room)
|
||||
- Banned (the user is not allowed to join the room)
|
||||
|
||||
There is an exception to the requirement that a user join a room before
|
||||
sending events to it: users may send an `m.room.member` event to a room
|
||||
with `content.membership` set to `leave` to reject an invitation if they
|
||||
have currently been invited to a room but have not joined it.
|
||||
There are a few notable exceptions which allow non-joined members of the
|
||||
room to send events in the room:
|
||||
|
||||
- Users wishing to reject an invite would send `m.room.member` events with
|
||||
`content.membership` of `leave`. They must have been invited first.
|
||||
|
||||
- If the room allows, users can send `m.room.member` events with `content.membership`
|
||||
of `knock` to knock on the room. This is a request for an invite by the user.
|
||||
|
||||
- To retract a previous knock, a user would send a `leave` event similar to
|
||||
rejecting an invite.
|
||||
|
||||
Some rooms require that users be invited to it before they can join;
|
||||
others allow anyone to join. Whether a given room is an "invite-only"
|
||||
room is determined by the room config key `m.room.join_rules`. It can
|
||||
have one of the following values:
|
||||
|
||||
`public`
|
||||
`public`
|
||||
This room is free for anyone to join without an invite.
|
||||
|
||||
`invite`
|
||||
`invite`
|
||||
This room can only be joined if you were invited.
|
||||
|
||||
`knock`
|
||||
This room can only be joined if you were invited, and allows anyone to
|
||||
request an invite to the room. Note that this join rule is only available
|
||||
to rooms based upon [room version 7](/rooms/v7).
|
||||
|
||||
The allowable state transitions of membership are:
|
||||
|
||||
```
|
||||
/ban
|
||||
+------------------------------------------------------+
|
||||
| |
|
||||
| +----------------+ +----------------+ |
|
||||
| | /leave | | | |
|
||||
| | v v | |
|
||||
/invite +--------+ +-------+ | |
|
||||
------------>| invite |<----------| leave |----+ | |
|
||||
+--------+ /invite +-------+ | | |
|
||||
| | ^ | | |
|
||||
| | | | | |
|
||||
/join | +---------------+ | | | |
|
||||
| | /join if | | | |
|
||||
| | join_rules | | /ban | /unban |
|
||||
| | public /leave | | | |
|
||||
v v or | | | |
|
||||
+------+ /kick | | | |
|
||||
------------>| join |-------------------+ | | |
|
||||
/join +------+ v | |
|
||||
if | +-----+ | |
|
||||
join_rules +-------------------------->| ban |-----+ |
|
||||
public /ban +-----+ |
|
||||
^ ^ |
|
||||
| | |
|
||||
----------------------------------------------+ +----------------------+
|
||||
/ban
|
||||
```
|
||||

|
||||
|
||||
{{% http-api spec="client-server" api="list_joined_rooms" %}}
|
||||
|
||||
|
@ -1826,14 +1825,51 @@ The allowable state transitions of membership are:
|
|||
|
||||
{{% http-api spec="client-server" api="joining" %}}
|
||||
|
||||
##### Knocking on rooms
|
||||
|
||||
<!--
|
||||
This section is here because it's most similar to being invited/joining a
|
||||
room, though has added complexity which needs to be explained. Otherwise
|
||||
this will have been just the API definition and nothing more (like invites).
|
||||
-->
|
||||
|
||||
If the join rules allow, external users to the room can `/knock` on it to
|
||||
request permission to join. Users with appropriate permissions within the
|
||||
room can then approve (`/invite`) or deny (`/kick`, `/ban`, or otherwise
|
||||
set membership to `leave`) the knock. Knocks can be retracted by calling
|
||||
`/leave` or otherwise setting membership to `leave`.
|
||||
|
||||
Users who are currently in the room, already invited, or banned cannot
|
||||
knock on the room.
|
||||
|
||||
To accept another user's knock, the user must have permission to invite
|
||||
users to the room. To reject another user's knock, the user must have
|
||||
permission to either kick or ban users (whichever is being performed).
|
||||
Note that setting another user's membership to `leave` is kicking them.
|
||||
|
||||
The knocking homeserver should assume that an invite to the room means
|
||||
that the knock was accepted, even if the invite is not explicitly related
|
||||
to the knock.
|
||||
|
||||
Homeservers are permitted to automatically accept invites as a result of
|
||||
knocks as they should be aware of the user's intent to join the room. If
|
||||
the homeserver is not auto-accepting invites (or there was an unrecoverable
|
||||
problem with accepting it), the invite is expected to be passed down normally
|
||||
to the client to handle. Clients can expect to see the join event if the
|
||||
server chose to auto-accept.
|
||||
|
||||
{{% http-api spec="client-server" api="knocking" %}}
|
||||
|
||||
#### Leaving rooms
|
||||
|
||||
A user can leave a room to stop receiving events for that room. A user
|
||||
must have been invited to or have joined the room before they are
|
||||
eligible to leave the room. Leaving a room to which the user has been
|
||||
invited rejects the invite. Once a user leaves a room, it will no longer
|
||||
appear in the response to the [`/sync`](/client-server-api/#get_matrixclientr0sync) API unless it is explicitly
|
||||
requested via a filter with the `include_leave` field set to `true`.
|
||||
invited rejects the invite, and can retract a knock. Once a user leaves
|
||||
a room, it will no longer appear in the response to the
|
||||
[`/sync`](/client-server-api/#get_matrixclientr0sync) API unless it is
|
||||
explicitly requested via a filter with the `include_leave` field set
|
||||
to `true`.
|
||||
|
||||
Whether or not they actually joined the room, if the room is an
|
||||
"invite-only" room the user will need to be re-invited before they can
|
||||
|
@ -1841,7 +1877,7 @@ re-join the room.
|
|||
|
||||
A user can also forget a room which they have left. Rooms which have
|
||||
been forgotten will never appear the response to the [`/sync`](/client-server-api/#get_matrixclientr0sync) API,
|
||||
until the user re-joins or is re-invited.
|
||||
until the user re-joins, is re-invited, or knocks.
|
||||
|
||||
A user may wish to force another user to leave a room. This can be done
|
||||
by 'kicking' the other user. To do so, the user performing the kick MUST
|
||||
|
|
|
@ -247,8 +247,7 @@ 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
|
||||
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
###### 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
|
||||
|
@ -357,8 +356,8 @@ 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.
|
||||
contacting him via some other trusted medium, and using one of the
|
||||
verification methods defined below 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`.
|
||||
|
||||
|
@ -390,60 +389,70 @@ decrypted by such a device. For the Olm protocol, this is documented at
|
|||
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
|
||||
supported by the specification and use messages exchanged by the user's devices
|
||||
to assist in the verification. 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.
|
||||
Verification messages can be sent either in a room shared by the two parties,
|
||||
which should be a [direct messaging](#direct-messaging) room between the two
|
||||
parties, or by using [to-device](#send-to-device-messaging) messages sent
|
||||
directly between the two devices involved. In both cases, the messages
|
||||
exchanged are similar, with minor differences as detailed below. Verifying
|
||||
between two different users should be performed using in-room messages, whereas
|
||||
verifying two devices belonging to the same user should be performed using
|
||||
to-device messages.
|
||||
|
||||
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.
|
||||
A key verification session is identified by an ID that is established by the
|
||||
first message sent in that session. For verifications using in-room messages,
|
||||
the ID is the event ID of the initial message, and for verifications using
|
||||
to-device messages, the first message contains a `transaction_id` field that is
|
||||
shared by the other messages of that session.
|
||||
|
||||
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.
|
||||
In general, verification operates as follows:
|
||||
|
||||
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.
|
||||
- Alice requests a key verification with Bob by sending an
|
||||
`m.key.verification.request` event. This event indicates the verification
|
||||
methods that Alice's client supports. (Note that "Alice" and "Bob" may in
|
||||
fact be the same user, in the case where a user is verifying their own
|
||||
devices.)
|
||||
- Bob's client prompts Bob to accept the key verification. When Bob accepts
|
||||
the verification, Bob's client sends an `m.key.verification.ready` event.
|
||||
This event indicates the verification methods, corresponding to the
|
||||
verification methods supported by Alice's client, that Bob's client supports.
|
||||
- Alice's or Bob's devices allow their users to select one of the verification
|
||||
methods supported by both devices to use for verification. When Alice or Bob
|
||||
selects a verification method, their device begins the verification by
|
||||
sending an `m.key.verification.start` event, indicating the selected
|
||||
verification method. Note that if there is only one verification method in
|
||||
common between the devices then the receiver's device (Bob) can auto-select
|
||||
it.
|
||||
- Alice and Bob complete the verification as defined by the selected
|
||||
verification method. This could involve their clients exchanging messages,
|
||||
Alice and Bob exchanging information out-of-band, and/or Alice and Bob
|
||||
interacting with their devices.
|
||||
- Alice's and Bob's clients send `m.key.verification.done` events to indicate
|
||||
that the verification was successful.
|
||||
|
||||
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.
|
||||
Verifications can be cancelled by either device at any time by sending an
|
||||
`m.key.verification.cancel` event with a `code` field that indicates the reason
|
||||
it was cancelled.
|
||||
|
||||
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.
|
||||
When using to-device messages, Alice may not know which of Bob's devices to
|
||||
verify, or may not want to choose a specific device. In this case, Alice will
|
||||
send `m.key.verification.request` events to all of Bob's devices. All of these
|
||||
events will use the same transaction ID. When Bob accepts or declines the
|
||||
verification on one of his devices (sending either an
|
||||
`m.key.verification.ready` or `m.key.verification.cancel` event), Alice will
|
||||
send an `m.key.verification.cancel` event to Bob's other devices with a `code`
|
||||
of `m.accepted` in the case where Bob accepted the verification, or `m.user` in
|
||||
the case where Bob rejected the verification. This yields the following
|
||||
handshake when using to-device messages, 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. Also note that, although in
|
||||
this example, Bob's device sends the `m.key.verification.start`, Alice's device
|
||||
could also send that message. As well, the order of the
|
||||
`m.key.verification.done` messages could be reversed.
|
||||
|
||||
```
|
||||
+---------------+ +---------------+ +-------------+ +-------------+
|
||||
|
@ -456,20 +465,85 @@ process.
|
|||
| | m.key.verification.request | |
|
||||
| |-------------------------------------------------->|
|
||||
| | | |
|
||||
| | m.key.verification.start | |
|
||||
| | m.key.verification.ready | |
|
||||
| |<----------------------------------| |
|
||||
| | | |
|
||||
| | m.key.verification.cancel | |
|
||||
| |-------------------------------------------------->|
|
||||
| | | |
|
||||
| | m.key.verification.start | |
|
||||
| |<----------------------------------| |
|
||||
| | | |
|
||||
.
|
||||
. (verification messages)
|
||||
.
|
||||
| | | |
|
||||
| | m.key.verification.done | |
|
||||
| |<----------------------------------| |
|
||||
| | | |
|
||||
| | m.key.verification.done | |
|
||||
| |---------------------------------->| |
|
||||
| | | |
|
||||
```
|
||||
|
||||
After the handshake, the verification process begins.
|
||||
When using in-room messages and the room has encryption enabled, clients should
|
||||
ensure that encryption does not hinder the verification. For example, if the
|
||||
verification messages are encrypted, clients must ensure that all the
|
||||
recipient's unverified devices receive the keys necessary to decrypt the
|
||||
messages, even if they would normally not be given the keys to decrypt messages
|
||||
in the room. Alternatively, verification messages may be sent unencrypted,
|
||||
though this is not encouraged.
|
||||
|
||||
Upon receipt of Alice's `m.key.verification.request` message, 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 no supported method was found, and allow him to manually reject the
|
||||
request.
|
||||
|
||||
The prompt for Bob to accept/reject Alice's request (or the unsupported method
|
||||
prompt) should be automatically dismissed 10 minutes after the `timestamp` (in
|
||||
the case of to-device messages) or `origin_ts` (in the case of in-room
|
||||
messages) 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` event with `code` set to `m.user`. Upon receipt,
|
||||
Alice's device should tell her that Bob does not want to verify her device and,
|
||||
if the request was sent as a to-device message, send
|
||||
`m.key.verification.cancel` messages to all of Bob's devices to notify them
|
||||
that the request was rejected.
|
||||
|
||||
If Alice's and Bob's clients both send an `m.key.verification.start` message,
|
||||
and both specify the same verification method, then the
|
||||
`m.key.verification.start` message sent by the user whose ID is the
|
||||
lexicographically largest user ID should be ignored, and the situation should
|
||||
be treated the same as if only the user with the lexicographically smallest
|
||||
user ID had sent the `m.key.verification.start` message. In the case where the
|
||||
user IDs are the same (that is, when a user is verifying their own device),
|
||||
then the device IDs should be compared instead. If the two
|
||||
`m.key.verification.start` messages do not specify the same verification
|
||||
method, then the verification should be cancelled with a `code` of
|
||||
`m.unexpected_message`.
|
||||
|
||||
An `m.key.verification.start` message can also be sent independently of any
|
||||
request, specifying the verification method to use.
|
||||
|
||||
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.
|
||||
|
||||
{{% event event="m.key.verification.request" %}}
|
||||
|
||||
{{% event event="m.key.verification.ready" %}}
|
||||
|
||||
{{% event event="m.key.verification.start" %}}
|
||||
|
||||
{{% event event="m.key.verification.done" %}}
|
||||
|
||||
{{% event event="m.key.verification.cancel" %}}
|
||||
|
||||
##### Short Authentication String (SAS) verification
|
||||
|
@ -493,8 +567,11 @@ example, if we verify 40 bits, then an attacker has a 1 in
|
|||
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](#send-to-device-messaging) messages in two
|
||||
phases:
|
||||
To advertise support for this method, clients use the name `m.sas.v1` in the
|
||||
`methods` fields of the `m.key.verification.request` and
|
||||
`m.key.verification.ready` events.
|
||||
|
||||
The verification process takes place in two phases:
|
||||
|
||||
1. Key agreement phase (based on [ZRTP key
|
||||
agreement](https://tools.ietf.org/html/rfc6189#section-4.4.1)).
|
||||
|
@ -505,63 +582,62 @@ 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
|
||||
2. Alice and Bob begin a key verification using the key verification
|
||||
framework as described above.
|
||||
3. Alice's device sends Bob's device an `m.key.verification.start`
|
||||
message. Alice's device ensures it has a copy of Bob's device key.
|
||||
4. 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
|
||||
5. Bob's device ensures it has a copy of Alice's device key.
|
||||
6. Bob's device creates an ephemeral Curve25519 key pair
|
||||
(*K<sub>B</sub><sup>private</sup>*, *K<sub>B</sub><sup>public</sup>*),
|
||||
and calculates the hash (using the chosen algorithm) of the public
|
||||
key *K<sub>B</sub><sup>public</sup>*.
|
||||
9. Bob's device replies to Alice's device with an
|
||||
7. 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
|
||||
8. 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
|
||||
9. Alice's device creates an ephemeral Curve25519 key pair
|
||||
(*K<sub>A</sub><sup>private</sup>*, *K<sub>A</sub><sup>public</sup>*)
|
||||
and replies to Bob's device with an `m.key.verification.key`,
|
||||
sending only the public key
|
||||
*K<sub>A</sub><sup>public</sup>*.
|
||||
12. Bob's device receives Alice's message and replies with its own
|
||||
10. Bob's device receives Alice's message and replies with its own
|
||||
`m.key.verification.key` message containing its public key
|
||||
*K<sub>B</sub><sup>public</sup>*.
|
||||
13. Alice's device receives Bob's message and verifies the commitment
|
||||
11. 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
|
||||
12. Both Alice and Bob's devices perform an Elliptic-curve
|
||||
Diffie-Hellman
|
||||
(*ECDH(K<sub>A</sub><sup>private</sup>*, *K<sub>B</sub><sup>public</sup>*)),
|
||||
using the result as the shared secret.
|
||||
15. Both Alice and Bob's devices display a SAS to their users, which is
|
||||
13. 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
|
||||
14. 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
|
||||
15. 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](#hkdf-calculation).
|
||||
18. Alice's device sends Bob's device an `m.key.verification.mac`
|
||||
16. 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,
|
||||
17. 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.
|
||||
18. Alice and Bob's devices send `m.key.verification.done` messages to complete
|
||||
the verification.
|
||||
|
||||
The wire protocol looks like the following between Alice and Bob's
|
||||
devices:
|
||||
|
@ -865,6 +941,13 @@ example, if Alice and Bob verify each other using SAS, Alice's
|
|||
`mac` property. Servers therefore must ensure that device IDs will not
|
||||
collide with cross-signing public keys.
|
||||
|
||||
The cross-signing private keys can be stored on the server or shared with other
|
||||
devices using the [Secrets](#secrets) module. When doing so, the master,
|
||||
user-signing, and self-signing keys are identified using the names
|
||||
`m.cross_signing.master`, `m.cross_signing.user_signing`, and
|
||||
`m.cross_signing.self_signing`, respectively, and the keys are base64-encoded
|
||||
before being encrypted.
|
||||
|
||||
###### Key and signature security
|
||||
|
||||
A user's master key could allow an attacker to impersonate that user to
|
||||
|
@ -907,6 +990,135 @@ user-signing keys.
|
|||
|
||||
{{% http-api spec="client-server" api="cross_signing" %}}
|
||||
|
||||
##### QR codes
|
||||
|
||||
Verifying by QR codes provides a quick way to verify when one of the parties
|
||||
has a device capable of scanning a QR code. The QR code encodes both parties'
|
||||
master signing keys as well as a random shared secret that is used to allow
|
||||
bi-directional verification from a single scan.
|
||||
|
||||
To advertise the ability to show a QR code, clients use the names
|
||||
`m.qr_code.show.v1` and `m.reciprocate.v1` in the `methods` fields of the
|
||||
`m.key.verification.request` and `m.key.verification.ready` events. To
|
||||
advertise the ability to scan a QR code, clients use the names
|
||||
`m.qr_code.scan.v1` and `m.reciprocate.v1` in the `methods` fields of the
|
||||
`m.key.verification.request` and `m.key.verification.ready` events.
|
||||
Clients that support both showing and scanning QR codes would advertise
|
||||
`m.qr_code.show.v1`, `m.qr_code.scan.v1`, and `m.reciprocate.v1` as
|
||||
methods.
|
||||
|
||||
The process between Alice and Bob verifying each other would be:
|
||||
|
||||
1. Alice and Bob meet in person, and want to verify each other's keys.
|
||||
2. Alice and Bob begin a key verification using the key verification
|
||||
framework as described above.
|
||||
3. Alice's client displays a QR code that Bob is able to scan if Bob's client
|
||||
indicated the ability to scan, an option to scan Bob's QR code if her client
|
||||
is able to scan. Bob's client prompts displays a QR code that Alice can
|
||||
scan if Alice's client indicated the ability to scan, and an option to scan
|
||||
Alice's QR code if his client is able to scan. The format for the QR code
|
||||
is described below. Other options, like starting SAS Emoji verification,
|
||||
can be presented alongside the QR code if the devices have appropriate
|
||||
support.
|
||||
5. Alice scans Bob's QR code.
|
||||
6. Alice's device ensures that the keys encoded in the QR code match the
|
||||
expected values for the keys. If not, Alice's device displays an error
|
||||
message indicating that the code is incorrect, and sends a
|
||||
`m.key.verification.cancel` message to Bob's device.
|
||||
|
||||
Otherwise, at this point:
|
||||
- Alice's device has now verified Bob's key, and
|
||||
- Alice's device knows that Bob has the correct key for her.
|
||||
|
||||
Thus for Bob to verify Alice's key, Alice needs to tell Bob that he has the
|
||||
right key.
|
||||
7. Alice's device displays a message saying that the verification was
|
||||
successful because the QR code's keys will have matched the keys
|
||||
expected for Bob. Bob's device hasn't had a chance to verify Alice's
|
||||
keys yet so wouldn't show the same message. Bob will know that
|
||||
he has the right key for Alice because Alice's device will have shown
|
||||
this message, as otherwise the verification would be cancelled.
|
||||
8. Alice's device sends an `m.key.verification.start` message with `method` set
|
||||
to `m.reciprocate.v1` to Bob (see below). The message includes the shared
|
||||
secret from the QR code. This signals to Bob's device that Alice has
|
||||
scanned Bob's QR code.
|
||||
|
||||
This message is merely a signal for Bob's device to proceed to the next
|
||||
step, and is not used for verification purposes.
|
||||
9. Upon receipt of the `m.key.verification.start` message, Bob's device ensures
|
||||
that the shared secret matches.
|
||||
|
||||
If the shared secret does not match, it should display an error message
|
||||
indicating that an attack was attempted. (This does not affect Alice's
|
||||
verification of Bob's keys.)
|
||||
|
||||
If the shared secret does match, it asks Bob to confirm that Alice
|
||||
has scanned the QR code.
|
||||
10. Bob sees Alice's device confirm that the key matches, and presses the button
|
||||
on his device to indicate that Alice's key is verified.
|
||||
|
||||
Bob's verification of Alice's key hinges on Alice telling Bob the result of
|
||||
her scan. Since the QR code includes what Bob thinks Alice's key is,
|
||||
Alice's device can check whether Bob has the right key for her. Alice has
|
||||
no motivation to lie about the result, as getting Bob to trust an incorrect
|
||||
key would only affect communications between herself and Bob. Thus Alice
|
||||
telling Bob that the code was scanned successfully is sufficient for Bob to
|
||||
trust Alice's key, under the assumption that this communication is done
|
||||
over a trusted medium (such as in-person).
|
||||
11. Both devices send an `m.key.verification.done` message.
|
||||
|
||||
###### QR code format
|
||||
|
||||
The QR codes to be displayed and scanned using this format will encode binary
|
||||
strings in the general form:
|
||||
|
||||
- the ASCII string `MATRIX`
|
||||
- one byte indicating the QR code version (must be `0x02`)
|
||||
- one byte indicating the QR code verification mode. Should be one of the
|
||||
following values:
|
||||
- `0x00` verifying another user with cross-signing
|
||||
- `0x01` self-verifying in which the current device does trust the master key
|
||||
- `0x02` self-verifying in which the current device does not yet trust the
|
||||
master key
|
||||
- the event ID or `transaction_id` of the associated verification
|
||||
request event, encoded as:
|
||||
- two bytes in network byte order (big-endian) indicating the length in
|
||||
bytes of the ID as a UTF-8 string
|
||||
- the ID as a UTF-8 string
|
||||
- the first key, as 32 bytes. The key to use depends on the mode field:
|
||||
- if `0x00` or `0x01`, then the current user's own master cross-signing public key
|
||||
- if `0x02`, then the current device's device key
|
||||
- the second key, as 32 bytes. The key to use depends on the mode field:
|
||||
- if `0x00`, then what the device thinks the other user's master
|
||||
cross-signing key is
|
||||
- if `0x01`, then what the device thinks the other device's device key is
|
||||
- if `0x02`, then what the device thinks the user's master cross-signing key
|
||||
is
|
||||
- a random shared secret, as a byte string. It is suggested to use a secret
|
||||
that is about 8 bytes long. Note: as we do not share the length of the
|
||||
secret, and it is not a fixed size, clients will just use the remainder of
|
||||
binary string as the shared secret.
|
||||
|
||||
For example, if Alice displays a QR code encoding the following binary string:
|
||||
|
||||
```
|
||||
"MATRIX" |ver|mode| len | event ID
|
||||
4D 41 54 52 49 58 02 00 00 2D 21 41 42 43 44 ...
|
||||
| user's cross-signing key | other user's cross-signing key | shared secret
|
||||
00 01 02 03 04 05 06 07 ... 10 11 12 13 14 15 16 17 ... 20 21 22 23 24 25 26 27
|
||||
```
|
||||
|
||||
this indicates that Alice is verifying another user (say Bob), in response to
|
||||
the request from event "$ABCD...", her cross-signing key is
|
||||
`0001020304050607...` (which is "AAECAwQFBg..." in base64), she thinks that
|
||||
Bob's cross-signing key is `1011121314151617...` (which is "EBESExQVFh..." in
|
||||
base64), and the shared secret is `2021222324252627` (which is "ICEiIyQlJic" in
|
||||
base64).
|
||||
|
||||
###### Verification messages specific to QR codes
|
||||
|
||||
{{% event event="m.key.verification.start$m.reciprocate.v1" %}}
|
||||
|
||||
#### Sharing keys between devices
|
||||
|
||||
If Bob has an encrypted conversation with Alice on his computer, and
|
||||
|
@ -1004,6 +1216,11 @@ as follows:
|
|||
When reading in a recovery key, clients must disregard whitespace, and
|
||||
perform the reverse of steps 1 through 3.
|
||||
|
||||
The recovery key can also be stored on the server or shared with other devices
|
||||
using the [Secrets](#secrets) module. When doing so, it is identified using the
|
||||
name `m.megolm_backup.v1`, and the key is base64-encoded before being
|
||||
encrypted.
|
||||
|
||||
###### Backup algorithm: `m.megolm_backup.v1.curve25519-aes-sha2`
|
||||
|
||||
When a backup is created with the `algorithm` set to
|
||||
|
|
|
@ -53,7 +53,7 @@ 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`.
|
||||
`th`, `td`, `caption`, `pre`, `span`, `img`, `details`, `summary`.
|
||||
|
||||
Not all attributes on those tags should be permitted as they may be
|
||||
avenues for other disruption attempts, such as adding `onclick` handlers
|
||||
|
@ -63,10 +63,11 @@ 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`
|
||||
`data-mx-bg-color`, `data-mx-color`, `color`
|
||||
|
||||
`span`
|
||||
`data-mx-bg-color`, `data-mx-color`
|
||||
`data-mx-bg-color`, `data-mx-color`, `data-mx-spoiler` (see
|
||||
[spoiler messages](#spoiler-messages))
|
||||
|
||||
`a`
|
||||
`name`, `target`, `href` (provided the value is not relative and has a
|
||||
|
@ -461,6 +462,52 @@ 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"`.
|
||||
|
||||
##### Spoiler messages
|
||||
|
||||
Parts of a message can be hidden visually from the user through use of spoilers.
|
||||
This does not affect the server's representation of the event content - it
|
||||
is simply a visual cue to the user that the message may reveal important
|
||||
information about something, spoiling any relevant surprise.
|
||||
|
||||
To send spoilers clients MUST use the `formatted_body` and therefore the
|
||||
`org.matrix.custom.html` format, described above. This makes spoilers valid on
|
||||
any `msgtype` which can support this format appropriately.
|
||||
|
||||
Spoilers themselves are contained with `span` tags, with the reason (optionally)
|
||||
being in the `data-mx-spoiler` attribute. Spoilers without a reason must at least
|
||||
specify the attribute, though the value may be empty/undefined.
|
||||
|
||||
An example of a spoiler is:
|
||||
|
||||
```json
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"format": "org.matrix.custom.html",
|
||||
"body": "Alice [Spoiler](mxc://example.org/abc123) in the movie.",
|
||||
"formatted_body": "Alice <span data-mx-spoiler>lived happily ever after</span> in the movie."
|
||||
}
|
||||
```
|
||||
|
||||
If a reason were to be supplied, it would look like:
|
||||
|
||||
```json
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"format": "org.matrix.custom.html",
|
||||
"body": "Alice [Spoiler for health of Alice](mxc://example.org/abc123) in the movie.",
|
||||
"formatted_body": "Alice <span data-mx-spoiler='health of alice'>lived happily ever after</span> in the movie."
|
||||
}
|
||||
```
|
||||
|
||||
When sending a spoiler, clients SHOULD provide the plain text fallback in the `body`
|
||||
as shown above (including the reason). The fallback SHOULD omit the spoiler text verbatim
|
||||
since `body` might show up in text-only clients or in notifications. To prevent spoilers
|
||||
showing up in such situations, clients are strongly encouraged to first upload the plaintext
|
||||
to the media repository then reference the MXC URI in a markdown-style link, as shown above.
|
||||
|
||||
Clients SHOULD render spoilers differently with some sort of disclosure. For example, the
|
||||
client could blur the actual text and ask the user to click on it for it to be revealed.
|
||||
|
||||
#### Server behaviour
|
||||
|
||||
Homeservers SHOULD reject `m.room.message` events which don't have a
|
||||
|
|
|
@ -42,7 +42,7 @@ passphrases](#deriving-keys-from-passphrases).
|
|||
|
||||
| Parameter | Type | Description
|
||||
|------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| name | string | **Required.** The name of the key. |
|
||||
| name | string | Optional. The name of the key. If not given, the client may use a generic name such as "Unnamed key", or "Default key" if the key is marked as the default key (see below). |
|
||||
| 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](#deriving-keys-from-passphrases) section for a description of this property. |
|
||||
|
||||
|
@ -56,6 +56,18 @@ 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.
|
||||
|
||||
Clients that want to present a simplified interface to users by not supporting
|
||||
multiple keys should use the default key if one is specified. If not default
|
||||
key is specified, the client may behave as if there is no key is present at
|
||||
all. When such a client creates a key, it should mark that key as being the
|
||||
default key.
|
||||
|
||||
`DefaultKey`
|
||||
|
||||
| Parameter | Type | Description
|
||||
|------------|-----------|------------------------------------------|
|
||||
| key | string | **Required.** The ID of the default key. |
|
||||
|
||||
##### Secret storage
|
||||
|
||||
Encrypted data is stored in the user's account\_data using the event
|
||||
|
@ -118,6 +130,16 @@ and the key descriptions for the keys would be:
|
|||
}
|
||||
```
|
||||
|
||||
If `key_id_1` is the default key, then we also have:
|
||||
|
||||
`m.secret_storage.default_key`:
|
||||
|
||||
```
|
||||
{
|
||||
"key": "key_id_1"
|
||||
}
|
||||
```
|
||||
|
||||
###### `m.secret_storage.v1.aes-hmac-sha2`
|
||||
|
||||
Secrets encrypted using the `m.secret_storage.v1.aes-hmac-sha2`
|
||||
|
|
|
@ -10,3 +10,4 @@ weight: 60
|
|||
* [Room Version 4](v4)
|
||||
* [Room Version 5](v5)
|
||||
* [Room Version 6](v6)
|
||||
* [Room Version 7](v7)
|
||||
|
|
52
content/rooms/v7.md
Normal file
52
content/rooms/v7.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
title: Room Version 7
|
||||
type: docs
|
||||
weight: 60
|
||||
---
|
||||
|
||||
This room version builds on [version 6](/rooms/v6) to introduce knocking
|
||||
as a possible join rule and membership state.
|
||||
|
||||
## Client considerations
|
||||
|
||||
This is the first room version to support knocking completely. As such,
|
||||
users will not be able to knock on rooms which are not based off v7.
|
||||
|
||||
## Server implementation components
|
||||
|
||||
{{% boxes/warning %}}
|
||||
The information contained in this section is strictly for server
|
||||
implementors. Applications which use the Client-Server API are generally
|
||||
unaffected by the intricacies contained here. The section above
|
||||
regarding client considerations is the resource that Client-Server API
|
||||
use cases should reference.
|
||||
{{% /boxes/warning %}}
|
||||
|
||||
Room version 7 adds new authorization rules for events to support knocking.
|
||||
[Room version 6](/rooms/v6) has details of other authorization rule changes,
|
||||
as do the versions v6 is based upon.
|
||||
|
||||
For checks perfomed upon `m.room.member` events, the following conditions
|
||||
are added in context:
|
||||
|
||||
If type is `m.room.member`:
|
||||
|
||||
...
|
||||
|
||||
* If `membership` is `ban`:
|
||||
|
||||
...
|
||||
|
||||
* If `membership` is `knock`:
|
||||
|
||||
i. If the `join_rule` is anything other than `knock`, reject.
|
||||
|
||||
ii. If `sender` does not match `state_key`, reject.
|
||||
|
||||
iii. If the `sender`'s current membership is not `ban`, `invite`, or `join`, allow.
|
||||
|
||||
iv. Otherwise, reject.
|
||||
|
||||
...
|
||||
|
||||
The remaining rules are the same as in [room version 6](/rooms/v6#authorization-rules-for-events).
|
|
@ -18,7 +18,7 @@ signatures in HTTP Authorization headers at the HTTP layer.
|
|||
There are three main kinds of communication that occur between
|
||||
homeservers:
|
||||
|
||||
Persisted Data Units (PDUs):
|
||||
Persisted Data Units (PDUs):
|
||||
These events are broadcast from one homeserver to any others that have
|
||||
joined the same room (identified by Room ID). They are persisted in
|
||||
long-term storage and record the history of messages and state for a
|
||||
|
@ -29,12 +29,12 @@ to deliver that event to its recipient servers. However PDUs are signed
|
|||
using the originating server's private key so that it is possible to
|
||||
deliver them through third-party servers.
|
||||
|
||||
Ephemeral Data Units (EDUs):
|
||||
Ephemeral Data Units (EDUs):
|
||||
These events are pushed between pairs of homeservers. They are not
|
||||
persisted and are not part of the history of a room, nor does the
|
||||
receiving homeserver have to reply to them.
|
||||
|
||||
Queries:
|
||||
Queries:
|
||||
These are single request/response interactions between a given pair of
|
||||
servers, initiated by one side sending an HTTPS GET request to obtain
|
||||
some information, and responded by the other. They are not persisted and
|
||||
|
@ -365,19 +365,19 @@ them.
|
|||
|
||||
#### Definitions
|
||||
|
||||
Required Power Level
|
||||
Required Power Level
|
||||
A given event type has an associated *required power level*. This is
|
||||
given by the current `m.room.power_levels` event. The event type is
|
||||
either listed explicitly in the `events` section or given by either
|
||||
`state_default` or `events_default` depending on if the event is a state
|
||||
event or not.
|
||||
|
||||
Invite Level, Kick Level, Ban Level, Redact Level
|
||||
Invite Level, Kick Level, Ban Level, Redact Level
|
||||
The levels given by the `invite`, `kick`, `ban`, and `redact` properties
|
||||
in the current `m.room.power_levels` state. Each defaults to 50 if
|
||||
unspecified.
|
||||
|
||||
Target User
|
||||
Target User
|
||||
For an `m.room.member` state event, the user given by the `state_key` of
|
||||
the event.
|
||||
|
||||
|
@ -720,6 +720,24 @@ other servers participating in the room.
|
|||
|
||||
{{% http-api spec="server-server" api="joins-v2" %}}
|
||||
|
||||
## Knocking upon a room
|
||||
|
||||
Rooms can permit knocking through the join rules, and if permitted this
|
||||
gives users a way to request to join (be invited) to the room. Users who
|
||||
knock on a room where the server is already a resident of the room can
|
||||
just send the knock event directly without using this process, however
|
||||
much like [joining rooms](/server-server-api/#joining-rooms) the server
|
||||
must handshake their way into having the knock sent on its behalf.
|
||||
|
||||
The handshake is largely the same as the joining rooms handshake, where
|
||||
instead of a "joining server" there is a "knocking server", and the APIs
|
||||
to be called are different (`/make_knock` and `/send_knock`).
|
||||
|
||||
Servers can retract knocks over federation by leaving the room, as described
|
||||
below for rejecting invites.
|
||||
|
||||
{{% http-api spec="server-server" api="knocks" %}}
|
||||
|
||||
## Inviting to a room
|
||||
|
||||
When a user on a given homeserver invites another user on the same
|
||||
|
@ -728,6 +746,10 @@ the process defined here. However, when a user invites another user on a
|
|||
different homeserver, a request to that homeserver to have the event
|
||||
signed and verified must be made.
|
||||
|
||||
Note that invites are used to indicate that knocks were accepted. As such,
|
||||
receiving servers should be prepared to manually link up a previous knock
|
||||
to an invite if the invite event does not directly reference the knock.
|
||||
|
||||
{{% http-api spec="server-server" api="invites-v1" %}}
|
||||
|
||||
{{% http-api spec="server-server" api="invites-v2" %}}
|
||||
|
@ -735,10 +757,10 @@ signed and verified must be made.
|
|||
## Leaving Rooms (Rejecting Invites)
|
||||
|
||||
Normally homeservers can send appropriate `m.room.member` events to have
|
||||
users leave the room, or to reject local invites. Remote invites from
|
||||
other homeservers do not involve the server in the graph and therefore
|
||||
need another approach to reject the invite. Joining the room and
|
||||
promptly leaving is not recommended as clients and servers will
|
||||
users leave the room, to reject local invites, or to retract a knock.
|
||||
Remote invites/knocks from other homeservers do not involve the server in the
|
||||
graph and therefore need another approach to reject the invite. Joining
|
||||
the room and promptly leaving is not recommended as clients and servers will
|
||||
interpret that as accepting the invite, then leaving the room rather
|
||||
than rejecting the invite.
|
||||
|
||||
|
@ -1009,6 +1031,8 @@ The following endpoint prefixes MUST be protected:
|
|||
- `/_matrix/federation/v2/send_leave`
|
||||
- `/_matrix/federation/v1/invite`
|
||||
- `/_matrix/federation/v2/invite`
|
||||
- `/_matrix/federation/v1/make_knock`
|
||||
- `/_matrix/federation/v1/send_knock`
|
||||
- `/_matrix/federation/v1/state`
|
||||
- `/_matrix/federation/v1/state_ids`
|
||||
- `/_matrix/federation/v1/backfill`
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue