Merge pull request #1828 from matrix-org/travis/spec/rooms-v3

Add specification for room version 3: Event IDs as hashes
pull/977/head
Travis Ralston 6 years ago committed by GitHub
commit df01acc6e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -13,7 +13,7 @@
# limitations under the License.
type: object
title: Persistent Data Unit
description: A persistent data unit (event)
description: A persistent data unit (event) for room versions 1 and 2.
example:
$ref: "../examples/pdu.json"
allOf:
@ -26,13 +26,13 @@ allOf:
description: |-
Content hashes of the PDU, following the algorithm specified in `Signing Events`_.
example: {
"sha256": "thishashcoversallfieldsincasethisisredacted"
"sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted"
}
properties:
sha256:
type: string
description: The hash.
example: thishashcoversallfieldsincasthisisredacted
example: ThisHashCoversAllFieldsInCaseThisIsRedacted
required: ['sha256']
signatures:
type: object
@ -40,7 +40,7 @@ allOf:
Signatures for the PDU, following the algorithm specified in `Signing Events`_.
example: {
"example.com": {
"ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
"ed25519:key_version:": "86BytesOfSignatureOfTheRedactedEvent"
}
}
additionalProperties:

@ -0,0 +1,73 @@
# Copyright 2019 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.
type: object
title: Persistent Data Unit
description: A persistent data unit (event) for room version 3 and beyond.
example:
$ref: "../examples/pdu_v3.json"
allOf:
- $ref: "unsigned_pdu_base.yaml"
- type: object
properties:
auth_events:
type: array
items:
type: string
description: Event ID.
description: |-
Event IDs for the authorization events that would
allow this event to be in the room.
example: ["$base64EncodedHash", "$AnotherEvent"]
prev_events:
type: array
items:
type: string
description: Event ID.
description: |-
Event IDs for the most recent events in the room
that the homeserver was aware of when it made this event.
example: ["$base64EncodedHash", "$AnotherEvent"]
hashes:
type: object
title: Event Hash
description: |-
Content hashes of the PDU, following the algorithm specified in `Signing Events`_.
example: {
"sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted"
}
properties:
sha256:
type: string
description: The hash.
example: ThisHashCoversAllFieldsInCaseThisIsRedacted
required: ['sha256']
signatures:
type: object
description: |-
Signatures for the PDU, following the algorithm specified in `Signing Events`_.
example: {
"example.com": {
"ed25519:key_version:": "86BytesOfSignatureOfTheRedactedEvent"
}
}
additionalProperties:
type: object
title: Server Signatures
additionalProperties:
type: string
required:
- auth_events
- prev_events
- hashes
- signatures

@ -1,4 +1,4 @@
# Copyright 2018 New Vector Ltd
# Copyright 2018-2019 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.
@ -16,140 +16,13 @@ title: Unsigned Persistent Data Unit
description: An unsigned persistent data unit (event)
example:
$ref: "../examples/unsigned_pdu.json"
allOf:
- $ref: "unsigned_pdu_base.yaml"
- type: object
properties:
event_id:
type: string
description: The event ID for the PDU.
example: "$a4ecee13e2accdadf56c1025:example.com"
room_id:
type: string
description: Room identifier.
example: "!abc123:matrix.org"
sender:
type: string
description: The ID of the user sending the event.
example: "@someone:matrix.org"
origin:
type: string
description: The ``server_name`` of the homeserver that created this event.
example: "matrix.org"
origin_server_ts:
type: integer
format: int64
description: Timestamp in milliseconds on origin homeserver when this event was created.
example: 1234567890
type:
type: string
description: Event type
example: "m.room.message"
state_key:
type: string
description: |-
If this key is present, the event is a state event, and it will replace previous events
with the same ``type`` and ``state_key`` in the room state.
example: "my_key"
content:
type: object
description: The content of the event.
example: {"key": "value"}
prev_events:
type: array
description: |-
Event IDs and reference hashes for the most recent events in the room
that the homeserver was aware of when it made this event.
items:
type: array
maxItems: 2
minItems: 2
items:
- type: string
title: Event ID
example: "$abc123:matrix.org"
- type: object
title: Event Hash
example: {
"sha256": "abase64encodedsha256hashshouldbe43byteslong"
}
properties:
sha256:
type: string
description: The event hash.
example: abase64encodedsha256hashshouldbe43byteslong
required: ['sha256']
depth:
type: integer
description: |-
The maximum depth of the ``prev_events``, plus one. Must be less than the
maximum value for an integer (2^63 - 1). If the room's depth is already at
the limit, the depth must be set to the limit.
example: 12
auth_events:
type: array
description: |-
Event IDs and reference hashes for the authorization events that would
allow this event to be in the room.
items:
type: array
maxItems: 2
minItems: 2
items:
- type: string
title: Event ID
example: "$abc123:matrix.org"
- type: object
title: Event Hash
example: {
"sha256": "abase64encodedsha256hashshouldbe43byteslong"
}
properties:
sha256:
type: string
description: The event hash.
example: abase64encodedsha256hashshouldbe43byteslong
required: ['sha256']
redacts:
type: string
description: For redaction events, the ID of the event being redacted.
example: "$def456:matrix.org"
unsigned:
type: object
title: Example Unsigned Data
description: |-
Additional data added by the origin server but not covered by the ``signatures``. More
keys than those defined here may be used.
example: {"key": "value"}
properties:
age:
type: integer
description: The number of milliseconds that have passed since this message was sent.
example: 4612
replaces_state:
type: string
description: The event ID of the state event this event replaces.
example: "$state_event:example.org"
prev_sender:
type: string
description: The sender of the replaced state event.
example: "@someone:example.org"
prev_content:
type: object
description: The content of the replaced state event.
example: {
"membership": "join",
"displayname": "Bob"
}
redacted_because:
type: string
description: A reason for why the event was redacted.
example: "Inappropriate content"
required:
- event_id
- room_id
- sender
- origin
- origin_server_ts
- type
- content
- prev_events
- depth
- auth_events

@ -0,0 +1,151 @@
# 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.
type: object
title: Unsigned Persistent Data Unit
description: An unsigned persistent data unit (event)
example:
$ref: "../examples/unsigned_pdu_base.json"
properties:
room_id:
type: string
description: Room identifier.
example: "!abc123:matrix.org"
sender:
type: string
description: The ID of the user sending the event.
example: "@someone:matrix.org"
origin:
type: string
description: The ``server_name`` of the homeserver that created this event.
example: "matrix.org"
origin_server_ts:
type: integer
format: int64
description: Timestamp in milliseconds on origin homeserver when this event was created.
example: 1234567890
type:
type: string
description: Event type
example: "m.room.message"
state_key:
type: string
description: |-
If this key is present, the event is a state event, and it will replace previous events
with the same ``type`` and ``state_key`` in the room state.
example: "my_key"
content:
type: object
description: The content of the event.
example: {"key": "value"}
prev_events:
type: array
description: |-
Event IDs and reference hashes for the most recent events in the room
that the homeserver was aware of when it made this event.
items:
type: array
maxItems: 2
minItems: 2
items:
- type: string
title: Event ID
example: "$abc123:matrix.org"
- type: object
title: Event Hash
example: {
"sha256": "Base64EncodedSha256HashesShouldBe43BytesLong"
}
properties:
sha256:
type: string
description: The event hash.
example: Base64EncodedSha256HashesShouldBe43BytesLong
required: ['sha256']
depth:
type: integer
description: |-
The maximum depth of the ``prev_events``, plus one. Must be less than the
maximum value for an integer (2^63 - 1). If the room's depth is already at
the limit, the depth must be set to the limit.
example: 12
auth_events:
type: array
description: |-
Event IDs and reference hashes for the authorization events that would
allow this event to be in the room.
items:
type: array
maxItems: 2
minItems: 2
items:
- type: string
title: Event ID
example: "$abc123:matrix.org"
- type: object
title: Event Hash
example: {
"sha256": "Base64EncodedSha256HashesShouldBe43BytesLong"
}
properties:
sha256:
type: string
description: The event hash.
example: Base64EncodedSha256HashesShouldBe43BytesLong
required: ['sha256']
redacts:
type: string
description: For redaction events, the ID of the event being redacted.
example: "$def456:matrix.org"
unsigned:
type: object
title: Example Unsigned Data
description: |-
Additional data added by the origin server but not covered by the ``signatures``. More
keys than those defined here may be used.
example: {"key": "value"}
properties:
age:
type: integer
description: The number of milliseconds that have passed since this message was sent.
example: 4612
replaces_state:
type: string
description: The event ID of the state event this event replaces.
example: "$state_event:example.org"
prev_sender:
type: string
description: The sender of the replaced state event.
example: "@someone:example.org"
prev_content:
type: object
description: The content of the replaced state event.
example: {
"membership": "join",
"displayname": "Bob"
}
redacted_because:
type: string
description: A reason for why the event was redacted.
example: "Inappropriate content"
required:
- event_id
- room_id
- sender
- origin
- origin_server_ts
- type
- content
- prev_events
- depth
- auth_events

@ -0,0 +1,19 @@
{
"$ref": "unsigned_pdu_base.json",
"hashes": {
"sha256": "thishashcoversallfieldsincasethisisredacted"
},
"signatures": {
"example.com": {
"ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus"
}
},
"auth_events": [
"$base64encodedeventid",
"$adifferenteventid"
],
"prev_events": [
"$base64encodedeventid",
"$adifferenteventid"
]
}

@ -1,27 +1,4 @@
{
"room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
"sender": "@alice:example.com",
"origin": "example.com",
"event_id": "$a4ecee13e2accdadf56c1025:example.com",
"origin_server_ts": 1404838188000,
"depth": 12,
"auth_events": [
[
"$af232176:example.org",
{"sha256": "abase64encodedsha256hashshouldbe43byteslong"}
]
],
"type": "m.room.message",
"prev_events": [
[
"$af232176:example.org",
{"sha256": "abase64encodedsha256hashshouldbe43byteslong"}
]
],
"content": {
"key": "value"
},
"unsigned": {
"age": 4612
}
"$ref": "unsigned_pdu_base.json",
"event_id": "$a4ecee13e2accdadf56c1025:example.com"
}

@ -0,0 +1,26 @@
{
"room_id": "!UcYsUzyxTGDxLBEvLy:example.org",
"sender": "@alice:example.com",
"origin": "example.com",
"origin_server_ts": 1404838188000,
"depth": 12,
"auth_events": [
[
"$af232176:example.org",
{"sha256": "abase64encodedsha256hashshouldbe43byteslong"}
]
],
"type": "m.room.message",
"prev_events": [
[
"$af232176:example.org",
{"sha256": "abase64encodedsha256hashshouldbe43byteslong"}
]
],
"content": {
"key": "value"
},
"unsigned": {
"age": 4612
}
}

@ -484,6 +484,7 @@ The available room versions are:
* `Version 1 <rooms/v1.html>`_ - **Stable**. The current version of most rooms.
* `Version 2 <rooms/v2.html>`_ - **Stable**. Implements State Resolution Version 2.
* `Version 3 <rooms/v3.html>`_ - **Stable**. Introduces events whose IDs are the event's hash.
Specification Versions
----------------------

@ -77,7 +77,7 @@ results of the resolution so far.
* 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
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.
@ -95,4 +95,200 @@ A *conflict* occurs between states where those states have different
affected are said to be *conflicting* events.
.. _`authorization rules`: ../server_server/unstable.html#authorization-rules
Authorization rules
~~~~~~~~~~~~~~~~~~~
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 in the
server specification.
#. 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.
Event format
~~~~~~~~~~~~
Events in version 1 rooms have the following structure:
{{definition_ss_pdu}}
.. _`auth events selection`: ../../server_server/unstable.html#auth-events-selection
.. _`Signing Events`: ../../server_server/unstable.html#signing-events

@ -0,0 +1,121 @@
.. Copyright 2018-2019 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.
Room Version 3
==============
This room version builds on `version 2 <v2.html>`_ with an improved event format.
.. note:
All requirements listed in this room version specification are scoped to rooms
which actually use this room version. For example, a requirement of "all APIs must
accept the new event format" does in fact apply to all APIs, but only so much as
where the contextual room of the request is using this room version. Rooms using
other room versions should not be affected by these sweeping requirements.
Client considerations
---------------------
This room version changes the format for event IDs sent to clients. Clients should be
aware that these event IDs may contain slashes and other potentially problematic
characters. Clients should be treating event IDs as opaque identifiers and should not
be attempting to parse them into a usable form, just like with other room versions.
Clients should expect to see event IDs changed from the format of ``$randomstring:example.org``
to something like ``$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk`` (note the lack of
domain and the potentially problematic slash).
Server implementation components
--------------------------------
.. 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.
Room version 3 uses the state resolution algorithm defined in `room version 2 <v2.html>`_,
and the event format defined here.
Event IDs
~~~~~~~~~
.. admonition:: Rationale
In other room versions (namely version 1 and 2) the event ID is a distinct field
from the remainder of the event, which must be tracked as such. This leads to
complications where servers receive multiple events with the same ID in either the
same or different rooms where the server cannot easily keep track of which event it
should be using. By removing the use of a dedicated event ID, servers are required
to track the hashes on an event to determine its ID.
The event ID is the `reference hash`_ of the event encoded using `Unpadded Base64`_,
prefixed with ``$``. A resulting event ID using this approach should look similar to
``$CD66HAED5npg6074c6pDtLKalHjVfYb2q4Q3LZgrW6o``.
Event IDs should not be sent over federation to servers when the room uses
this room version. On the receiving end of an event, the server should compute
the relevant event ID for itself.
Additionally, the ``auth_events`` and ``prev_events`` have had a format change
compared to other room versions to make it easier to handle. Instead of a tuple
of values, they are now plain lists of events.
{{definition_ss_pdu_v3}}
Changes to APIs
~~~~~~~~~~~~~~~
Due to the event ID being removed from the event, some APIs need to change. All
APIs which currently accept an event ID must do so with the new format. Servers
must append the calculated event ID to all events sent to clients where an event
ID would normally be expected.
Because the format of events has changed, servers must be aware of the room version
where the event resides so that the server may parse and handle the event. The
federation API has taken this concern into consideration by ensuring that servers
are aware of (or can find) the room version during a request.
Authorization rules for events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The authorization rules for a given event have changed in this room version due
to the change in event format:
* The event no longer needs to be signed by the domain of the event ID (as there
is no domain in the event ID), but still needs to be signed by the sender's
domain.
* In past room versions, redactions were only permitted to enter the DAG if the
sender's domain matched the domain in the event ID being redacted, or the sender
had appropriate permissions per the power levels. Due to servers now not being
able to determine where an event came from during event authorization, redaction
events are always accepted (provided the event is allowed by ``events`` and
``events_default`` in the power levels). However, servers should not apply or send
redactions to clients until both the redaction event and original event have been
seen, and are valid. Servers should only apply redactions to events where the
sender's domains match, or the sender of the redaction has the appropriate
permissions per the power levels.
The remaining rules are the same as `room version 1 <v1.html#authorization-rules>`_.
.. _`Unpadded Base64`: ../../appendices.html#unpadded-base64
.. _`Canonical JSON`: ../../appendices.html#canonical-json
.. _`Signing Events`: ../../server_server/unstable.html#signing-events
.. _`reference hash`: ../../server_server/unstable.html#reference-hashes

@ -281,6 +281,8 @@ Transactions are limited in size; they can have at most 50 PDUs and 100 EDUs.
{{transactions_ss_http_api}}
.. _`Persistent Data Unit schema`:
PDUs
----
@ -327,7 +329,7 @@ following subset of the room state:
``m.room.third_party_invite`` event with ``state_key`` matching
``content.third_party_invite.signed.token``, if any.
{{definition_ss_pdu}}
For a full schema of what a PDU looks like, see the `room version specification`_.
Checks performed on receipt of a PDU
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -379,189 +381,9 @@ Authorization rules
The rules governing whether an event is authorized depends on a set of state. A
given event is checked multiple times against different sets of state, as
specified above. 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.
specified above. Each room version can have a different algorithm for how the
rules work, and which rules are applied. For more detailed information, please
see the `room version specification`_.
Rejection
+++++++++
@ -1230,6 +1052,24 @@ been given a redacted version of the event. To enforce this, the receiving
server should use the redacted copy it calculated rather than the full copy it
received.
.. _`reference hashes`:
Calculating the reference hash for an event
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The *reference hash* of an event covers the essential fields of an event,
including content hashes. It is calculated as follows.
1. The event is put through the redaction algorithm.
2. The ``signatures``, ``age_ts``, and ``unsigned`` properties are removed
from the event, if present.
3. The event is converted into `Canonical JSON`_.
4. A sha256 hash is calculed on the resulting JSON object.
Calculating the content hash for an event
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@ -34,6 +34,10 @@ targets:
files:
- rooms/v2.rst
version_label: v2
rooms@v3: # this is translated to be rooms/v3.html
files:
- rooms/v3.rst
version_label: v3
appendices:
files:
- appendices.rst

Loading…
Cancel
Save