362 lines
12 KiB
ReStructuredText
362 lines
12 KiB
ReStructuredText
.. Copyright 2018 New Vector Ltd
|
|
..
|
|
.. Licensed under the Apache License, Version 2.0 (the "License");
|
|
.. you may not use this file except in compliance with the License.
|
|
.. You may obtain a copy of the License at
|
|
..
|
|
.. http://www.apache.org/licenses/LICENSE-2.0
|
|
..
|
|
.. Unless required by applicable law or agreed to in writing, software
|
|
.. distributed under the License is distributed on an "AS IS" BASIS,
|
|
.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
.. See the License for the specific language governing permissions and
|
|
.. limitations under the License.
|
|
|
|
|
|
.. Note: This document appended to the end of the intro, so this next line
|
|
.. appears under "Other Room Versions".
|
|
|
|
This is the specification for **room version 1** (``"1"``).
|
|
|
|
Changelog
|
|
---------
|
|
|
|
.. topic:: Room version 1
|
|
{{rooms_changelog_v1}}
|
|
|
|
This version of the specification is generated from
|
|
`matrix-doc <https://github.com/matrix-org/matrix-doc>`_ as of Git commit
|
|
`{{git_version}} <https://github.com/matrix-org/matrix-doc/tree/{{git_rev}}>`_.
|
|
|
|
For the full historical changelog, see
|
|
https://github.com/matrix-org/matrix-doc/blob/master/changelogs/rooms.rst
|
|
|
|
|
|
Room IDs and Event IDs
|
|
----------------------
|
|
|
|
A room has exactly one room ID. A room ID has the format::
|
|
|
|
!opaque_id:domain
|
|
|
|
An event has exactly one event ID. An event ID has the format::
|
|
|
|
$opaque_id:domain
|
|
|
|
The ``domain`` of a room/event ID is the `server name`_ of the homeserver which
|
|
created the room/event. The domain is used only for namespacing to avoid the
|
|
risk of clashes of identifiers between different homeservers. There is no
|
|
implication that the room or event in question is still available at the
|
|
corresponding homeserver.
|
|
|
|
Event IDs and Room IDs are case-sensitive. They are not meant to be human
|
|
readable.
|
|
|
|
.. TODO-spec
|
|
What is the grammar for the opaque part? https://matrix.org/jira/browse/SPEC-389
|
|
|
|
|
|
.. _`server name`: ../appendices.html#server-name
|
|
|
|
Event schema
|
|
------------
|
|
|
|
All communication in Matrix is expressed in the form of data objects called
|
|
Events. These are the fundamental building blocks common to the client-server,
|
|
server-server and application-service APIs, and are described below.
|
|
|
|
Note that the structure of these events may be different than those in the
|
|
server-server API.
|
|
|
|
{{common_event_fields}}
|
|
|
|
{{common_room_event_fields}}
|
|
|
|
{{common_state_event_fields}}
|
|
|
|
|
|
Size limits
|
|
-----------
|
|
|
|
The complete event MUST NOT be larger than 65535 bytes, when formatted as a
|
|
`PDU for the Server-Server protocol <../server_server/%SERVER_RELEASE_LABEL%#pdus>`_,
|
|
including any signatures, and encoded as `Canonical JSON`_.
|
|
|
|
There are additional restrictions on sizes per key:
|
|
|
|
- ``sender`` MUST NOT exceed 255 bytes (including domain).
|
|
- ``room_id`` MUST NOT exceed 255 bytes.
|
|
- ``state_key`` MUST NOT exceed 255 bytes.
|
|
- ``type`` MUST NOT exceed 255 bytes.
|
|
- ``event_id`` MUST NOT exceed 255 bytes.
|
|
|
|
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.
|
|
|
|
|
|
Server implementation components
|
|
--------------------------------
|
|
|
|
.. WARNING::
|
|
The information contained in this section is strictly for server implementors.
|
|
Applications which use the Client-Server API are generally unaffected by the
|
|
details contained here, and can safely ignore their presence.
|
|
|
|
|
|
The algorithms defined here should only apply to version 1 rooms. Other algorithms
|
|
may be used by other room versions, and as such servers should be aware of which
|
|
version room they are dealing with prior to executing a given algorithm.
|
|
|
|
.. WARNING::
|
|
Although room version 1 is the most popular room version, it is known to have
|
|
undesirable effects. Servers implementing support for room version 1 should be
|
|
aware that restrictions should be generally relaxed and be aware that inconsistencies
|
|
may occur until room version 2 is ready and adopted.
|
|
|
|
State resolution
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
.. WARNING::
|
|
This section documents the state resolution algorithm as implemented by
|
|
Synapse as of December 2017 (and therefore the de-facto Matrix protocol).
|
|
However, this algorithm is known to have some problems.
|
|
|
|
The room state :math:`S'(E)` after an event :math:`E` is defined in terms of
|
|
the room state :math:`S(E)` before :math:`E`, and depends on whether
|
|
:math:`E` is a state event or a message event:
|
|
|
|
* If :math:`E` is a message event, then :math:`S'(E) = S(E)`.
|
|
|
|
* If :math:`E` is a state event, then :math:`S'(E)` is :math:`S(E)`, except
|
|
that its entry corresponding to :math:`E`'s ``event_type`` and ``state_key``
|
|
is replaced by :math:`E`'s ``event_id``.
|
|
|
|
The room state :math:`S(E)` before :math:`E` is the *resolution* of the set of
|
|
states :math:`\{ S'(E'), S'(E''), … \}` consisting of the states after each of
|
|
:math:`E`'s ``prev_event``\s :math:`\{ E', E'', … \}`.
|
|
|
|
The *resolution* of a set of states is defined as follows. The resolved state
|
|
is built up in a number of passes; here we use :math:`R` to refer to the
|
|
results of the resolution so far.
|
|
|
|
* Start by setting :math:`R` to the union of the states to be resolved,
|
|
excluding any *conflicting* events.
|
|
|
|
* First we resolve conflicts between ``m.room.power_levels`` events. If there
|
|
is no conflict, this step is skipped, otherwise:
|
|
|
|
* Assemble all the ``m.room.power_levels`` events from the states to
|
|
be resolved into a list.
|
|
|
|
* Sort the list by ascending ``depth`` then descending ``sha1(event_id)``.
|
|
|
|
* Add the first event in the list to :math:`R`.
|
|
|
|
* For each subsequent event in the list, check that the event would be
|
|
allowed by the `authorization rules`_ for a room in state :math:`R`. If the
|
|
event would be allowed, then update :math:`R` with the event and continue
|
|
with the next event in the list. If it would not be allowed, stop and
|
|
continue below with ``m.room.join_rules`` events.
|
|
|
|
* Repeat the above process for conflicts between ``m.room.join_rules`` events.
|
|
|
|
* Repeat the above process for conflicts between ``m.room.member`` events.
|
|
|
|
* No other events affect the authorization rules, so for all other conflicts,
|
|
just pick the event with the highest depth and lowest ``sha1(event_id)`` that
|
|
passes authentication in :math:`R` and add it to :math:`R`.
|
|
|
|
A *conflict* occurs between states where those states have different
|
|
``event_ids`` for the same ``(state_type, state_key)``. The events thus
|
|
affected are said to be *conflicting* events.
|
|
|
|
|
|
Authorisation rules
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
The rules governing whether an event is authorized depend solely on the
|
|
state of the room at the point in the room graph at which the new event is to
|
|
be inserted. The types of state events that affect authorization are:
|
|
|
|
- ``m.room.create``
|
|
- ``m.room.member``
|
|
- ``m.room.join_rules``
|
|
- ``m.room.power_levels``
|
|
- ``m.room.third_party_invite``
|
|
|
|
The rules are as follows:
|
|
|
|
1. If type is ``m.room.create``:
|
|
|
|
a. If it has any previous events, reject.
|
|
b. If the domain of the ``room_id`` does not match the domain of the
|
|
``sender``, reject.
|
|
c. If ``content.room_version`` is present and is not a recognised version,
|
|
reject.
|
|
d. If ``content`` has no ``creator`` field, reject.
|
|
e. Otherwise, allow.
|
|
|
|
#. Reject if event has ``auth_events`` that:
|
|
|
|
a. have duplicate entries for a given ``type`` and ``state_key`` pair
|
|
#. have entries whose ``type`` and ``state_key`` don't match those
|
|
specified by the `auth events selection`_ algorithm described above.
|
|
|
|
#. If event does not have a ``m.room.create`` in its ``auth_events``, reject.
|
|
|
|
#. If type is ``m.room.aliases``:
|
|
|
|
a. If event has no ``state_key``, reject.
|
|
b. If sender's domain doesn't matches ``state_key``, reject.
|
|
c. Otherwise, allow.
|
|
|
|
#. If type is ``m.room.member``:
|
|
|
|
a. If no ``state_key`` key or ``membership`` key in ``content``, reject.
|
|
|
|
#. If ``membership`` is ``join``:
|
|
|
|
i. If the only previous event is an ``m.room.create``
|
|
and the ``state_key`` is the creator, allow.
|
|
|
|
#. If the ``sender`` does not match ``state_key``, reject.
|
|
|
|
#. If the ``sender`` is banned, reject.
|
|
|
|
#. If the ``join_rule`` is ``invite`` then allow if membership state
|
|
is ``invite`` or ``join``.
|
|
|
|
#. If the ``join_rule`` is ``public``, allow.
|
|
|
|
#. Otherwise, reject.
|
|
|
|
#. If ``membership`` is ``invite``:
|
|
|
|
i. If ``content`` has ``third_party_invite`` key:
|
|
|
|
#. If *target user* is banned, reject.
|
|
|
|
#. If ``content.third_party_invite`` does not have a
|
|
``signed`` key, reject.
|
|
|
|
#. If ``signed`` does not have ``mxid`` and ``token`` keys, reject.
|
|
|
|
#. If ``mxid`` does not match ``state_key``, reject.
|
|
|
|
#. If there is no ``m.room.third_party_invite`` event in the
|
|
current room state with ``state_key`` matching ``token``, reject.
|
|
|
|
#. If ``sender`` does not match ``sender`` of the
|
|
``m.room.third_party_invite``, reject.
|
|
|
|
#. If any signature in ``signed`` matches any public key in the
|
|
``m.room.third_party_invite`` event, allow. The public keys are
|
|
in ``content`` of ``m.room.third_party_invite`` as:
|
|
|
|
#. A single public key in the ``public_key`` field.
|
|
#. A list of public keys in the ``public_keys`` field.
|
|
|
|
#. Otherwise, reject.
|
|
|
|
#. If the ``sender``'s current membership state is not ``join``, reject.
|
|
|
|
#. If *target user*'s current membership state is ``join`` or ``ban``,
|
|
reject.
|
|
|
|
#. If the ``sender``'s power level is greater than or equal to the *invite
|
|
level*, allow.
|
|
|
|
#. Otherwise, reject.
|
|
|
|
#. If ``membership`` is ``leave``:
|
|
|
|
i. If the ``sender`` matches ``state_key``, allow if and only if that user's
|
|
current membership state is ``invite`` or ``join``.
|
|
|
|
#. If the ``sender``'s current membership state is not ``join``, reject.
|
|
|
|
#. If the *target user*'s current membership state is ``ban``, and the
|
|
``sender``'s power level is less than the *ban level*, reject.
|
|
|
|
#. If the ``sender``'s power level is greater than or equal to the *kick
|
|
level*, and the *target user*'s power level is less than the
|
|
``sender``'s power level, allow.
|
|
|
|
#. Otherwise, reject.
|
|
|
|
#. If ``membership`` is ``ban``:
|
|
|
|
i. If the ``sender``'s current membership state is not ``join``, reject.
|
|
|
|
#. If the ``sender``'s power level is greater than or equal to the *ban
|
|
level*, and the *target user*'s power level is less than the
|
|
``sender``'s power level, allow.
|
|
|
|
#. Otherwise, reject.
|
|
|
|
#. Otherwise, the membership is unknown. Reject.
|
|
|
|
#. If the ``sender``'s current membership state is not ``join``, reject.
|
|
|
|
#. If type is ``m.room.third_party_invite``:
|
|
|
|
a. Allow if and only if ``sender``'s current power level is greater than
|
|
or equal to the *invite level*.
|
|
|
|
#. If the event type's *required power level* is greater than the ``sender``'s power
|
|
level, reject.
|
|
|
|
#. If the event has a ``state_key`` that starts with an ``@`` and does not match
|
|
the ``sender``, reject.
|
|
|
|
#. If type is ``m.room.power_levels``:
|
|
|
|
a. If ``users`` key in ``content`` is not a dictionary with keys that are
|
|
valid user IDs with values that are integers (or a string that is an
|
|
integer), reject.
|
|
|
|
#. If there is no previous ``m.room.power_levels`` event in the room, allow.
|
|
|
|
#. For each of the keys ``users_default``, ``events_default``,
|
|
``state_default``, ``ban``, ``redact``, ``kick``, ``invite``, as well as
|
|
each entry being changed under the ``events`` or ``users`` keys:
|
|
|
|
i. If the current value is higher than the ``sender``'s current power level,
|
|
reject.
|
|
|
|
#. If the new value is higher than the ``sender``'s current power level,
|
|
reject.
|
|
|
|
#. For each entry being changed under the ``users`` key, other than the
|
|
``sender``'s own entry:
|
|
|
|
i. If the current value is equal to the ``sender``'s current power level,
|
|
reject.
|
|
|
|
#. Otherwise, allow.
|
|
|
|
#. If type is ``m.room.redaction``:
|
|
|
|
a. If the ``sender``'s power level is greater than or equal to the *redact
|
|
level*, allow.
|
|
|
|
#. If the domain of the ``event_id`` of the event being redacted is the same
|
|
as the domain of the ``event_id`` of the ``m.room.redaction``, allow.
|
|
|
|
#. Otherwise, reject.
|
|
|
|
#. Otherwise, allow.
|
|
|
|
.. NOTE::
|
|
|
|
Some consequences of these rules:
|
|
|
|
* Unless you are a member of the room, the only permitted operations (apart
|
|
from the intial create/join) are: joining a public room; accepting or
|
|
rejecting an invitation to a room.
|
|
|
|
* To unban somebody, you must have power level greater than or equal to both
|
|
the kick *and* ban levels, *and* greater than the target user's power
|
|
level.
|