286 lines
12 KiB
Markdown
286 lines
12 KiB
Markdown
---
|
||
title: Room Version 1
|
||
type: docs
|
||
weight: 10
|
||
---
|
||
|
||
This room version is the first ever version for rooms, and contains the
|
||
building blocks for other room versions.
|
||
|
||
## Client considerations
|
||
|
||
Clients may need to consider some algorithms performed by the server for
|
||
their own implementation.
|
||
|
||
### Redactions
|
||
|
||
Upon receipt of a redaction event, the server must strip off any keys
|
||
not in the following list:
|
||
|
||
- `event_id`
|
||
- `type`
|
||
- `room_id`
|
||
- `sender`
|
||
- `state_key`
|
||
- `content`
|
||
- `hashes`
|
||
- `signatures`
|
||
- `depth`
|
||
- `prev_events`
|
||
- `prev_state`
|
||
- `auth_events`
|
||
- `origin`
|
||
- `origin_server_ts`
|
||
- `membership`
|
||
|
||
The content object must also be stripped of all keys, unless it is one
|
||
of one of the following event types:
|
||
|
||
- `m.room.member` allows key `membership`.
|
||
- `m.room.create` allows key `creator`.
|
||
- `m.room.join_rules` allows key `join_rule`.
|
||
- `m.room.power_levels` allows keys `ban`, `events`, `events_default`,
|
||
`kick`, `redact`, `state_default`, `users`, `users_default`.
|
||
- `m.room.aliases` allows key `aliases`.
|
||
- `m.room.history_visibility` allows key `history_visibility`.
|
||
|
||
## 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 %}}
|
||
|
||
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.
|
||
|
||
{{% boxes/warning %}}
|
||
Although there are many rooms using room version 1, it is known to have
|
||
undesirable effects. Servers implementing support for room version 1
|
||
should be aware that restrictions should be generally relaxed and that
|
||
inconsistencies may occur.
|
||
{{% /boxes/warning %}}
|
||
|
||
### State resolution
|
||
|
||
{{% boxes/warning %}}
|
||
Room version 1 is known to have bugs that can cause the state of rooms
|
||
to reset to older versions of the room's state. For example this could
|
||
mean that users who had joined the room may be removed from the room,
|
||
admins and moderators could lose their power level, and users who have
|
||
been banned from the room may be able to rejoin. Other state events such
|
||
as the the room's name or topic could also reset to a previous version.
|
||
|
||
This is fixed in the state resolution algorithm introduced in room
|
||
version 2.
|
||
{{% /boxes/warning %}}
|
||
|
||
The room state *S*′(*E*) after an event *E* is defined in terms of the
|
||
room state *S*(*E*) before *E*, and depends on whether *E* is a state
|
||
event or a message event:
|
||
|
||
- If *E* is a message event, then *S*′(*E*) = *S*(*E*).
|
||
- If *E* is a state event, then *S*′(*E*) is *S*(*E*), except that its
|
||
entry corresponding to *E*'s `event_type` and `state_key` is
|
||
replaced by *E*'s `event_id`.
|
||
|
||
The room state *S*(*E*) before *E* is the *resolution* of the set of
|
||
states {*S*′(*E*′), *S*′(*E*″), …} consisting of the states after each
|
||
of *E*'s `prev_event`s {*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 *R* to refer to the
|
||
results of the resolution so far.
|
||
|
||
- Start by setting *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 *R*.
|
||
- For each subsequent event in the list, check that the event
|
||
would be allowed by the authorization rules for a room in state
|
||
*R*. If the event would be allowed, then update *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 *R* and add it to
|
||
*R*.
|
||
|
||
A *conflict* occurs between states where those states have different
|
||
`event_ids` for the same `(event_type, state_key)`. The events thus
|
||
affected are said to be *conflicting* events.
|
||
|
||
### 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`
|
||
|
||
{{% boxes/note %}}
|
||
Power levels are inferred from defaults when not explicitly supplied.
|
||
For example, mentions of the `sender`'s power level can also refer to
|
||
the default power level for users in the room.
|
||
{{% /boxes/note %}}
|
||
|
||
The rules are as follows:
|
||
|
||
1. If type is `m.room.create`:
|
||
1. If it has any previous events, reject.
|
||
2. If the domain of the `room_id` does not match the domain of the
|
||
`sender`, reject.
|
||
3. If `content.room_version` is present and is not a recognised
|
||
version, reject.
|
||
4. If `content` has no `creator` field, reject.
|
||
5. Otherwise, allow.
|
||
2. Reject if event has `auth_events` that:
|
||
1. have duplicate entries for a given `type` and `state_key` pair
|
||
2. have entries whose `type` and `state_key` don't match those
|
||
specified by the [auth events
|
||
selection](/server-server-api#auth-events-selection)
|
||
algorithm described in the server specification.
|
||
3. If event does not have a `m.room.create` in its `auth_events`,
|
||
reject.
|
||
4. If type is `m.room.aliases`:
|
||
1. If event has no `state_key`, reject.
|
||
2. If sender's domain doesn't matches `state_key`, reject.
|
||
3. Otherwise, allow.
|
||
5. If type is `m.room.member`:
|
||
1. If no `state_key` key or `membership` key in `content`, reject.
|
||
2. If `membership` is `join`:
|
||
1. If the only previous event is an `m.room.create` and the
|
||
`state_key` is the creator, allow.
|
||
2. If the `sender` does not match `state_key`, reject.
|
||
3. If the `sender` is banned, reject.
|
||
4. If the `join_rule` is `invite` then allow if membership
|
||
state is `invite` or `join`.
|
||
5. If the `join_rule` is `public`, allow.
|
||
6. Otherwise, reject.
|
||
3. If `membership` is `invite`:
|
||
1. If `content` has `third_party_invite` key:
|
||
1. If *target user* is banned, reject.
|
||
2. If `content.third_party_invite` does not have a `signed`
|
||
key, reject.
|
||
3. If `signed` does not have `mxid` and `token` keys,
|
||
reject.
|
||
4. If `mxid` does not match `state_key`, reject.
|
||
5. If there is no `m.room.third_party_invite` event in the
|
||
current room state with `state_key` matching `token`,
|
||
reject.
|
||
6. If `sender` does not match `sender` of the
|
||
`m.room.third_party_invite`, reject.
|
||
7. 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:
|
||
1. A single public key in the `public_key` field.
|
||
2. A list of public keys in the `public_keys` field.
|
||
8. Otherwise, reject.
|
||
2. If the `sender`'s current membership state is not `join`,
|
||
reject.
|
||
3. If *target user*'s current membership state is `join` or
|
||
`ban`, reject.
|
||
4. If the `sender`'s power level is greater than or equal to
|
||
the *invite level*, allow.
|
||
5. Otherwise, reject.
|
||
4. If `membership` is `leave`:
|
||
1. If the `sender` matches `state_key`, allow if and only if
|
||
that user's current membership state is `invite` or `join`.
|
||
2. If the `sender`'s current membership state is not `join`,
|
||
reject.
|
||
3. If the *target user*'s current membership state is `ban`,
|
||
and the `sender`'s power level is less than the *ban level*,
|
||
reject.
|
||
4. 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.
|
||
5. Otherwise, reject.
|
||
5. If `membership` is `ban`:
|
||
1. If the `sender`'s current membership state is not `join`,
|
||
reject.
|
||
2. 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.
|
||
3. Otherwise, reject.
|
||
6. Otherwise, the membership is unknown. Reject.
|
||
6. If the `sender`'s current membership state is not `join`, reject.
|
||
7. If type is `m.room.third_party_invite`:
|
||
1. Allow if and only if `sender`'s current power level is greater
|
||
than or equal to the *invite level*.
|
||
8. If the event type's *required power level* is greater than the
|
||
`sender`'s power level, reject.
|
||
9. If the event has a `state_key` that starts with an `@` and does not
|
||
match the `sender`, reject.
|
||
10. If type is `m.room.power_levels`:
|
||
1. 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.
|
||
2. If there is no previous `m.room.power_levels` event in the room,
|
||
allow.
|
||
3. For the keys `users_default`, `events_default`, `state_default`,
|
||
`ban`, `redact`, `kick`, `invite` check if they were added,
|
||
changed or removed. For each found alteration:
|
||
1. If the current value is higher than the `sender`'s current
|
||
power level, reject.
|
||
2. If the new value is higher than the `sender`'s current power
|
||
level, reject.
|
||
4. For each entry being added, changed or removed in both the
|
||
`events` and `users` keys:
|
||
1. If the current value is higher than the `sender`'s current
|
||
power level, reject.
|
||
2. If the new value is higher than the `sender`'s current power
|
||
level, reject.
|
||
5. For each entry being changed under the `users` key, other than
|
||
the `sender`'s own entry:
|
||
1. If the current value is equal to the `sender`'s current
|
||
power level, reject.
|
||
6. Otherwise, allow.
|
||
11. If type is `m.room.redaction`:
|
||
1. If the `sender`'s power level is greater than or equal to the
|
||
*redact level*, allow.
|
||
2. 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.
|
||
3. Otherwise, reject.
|
||
12. Otherwise, allow.
|
||
|
||
{{% boxes/note %}}
|
||
Some consequences of these rules:
|
||
|
||
- Unless you are a member of the room, the only permitted operations
|
||
(apart from the initial 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.
|
||
{{% /boxes/note %}}
|
||
|
||
### Event format
|
||
|
||
Events in version 1 rooms have the following structure:
|
||
|
||
{{% definition path="api/server-server/definitions/pdu" %}}
|
||
|
||
### Canonical JSON
|
||
|
||
Servers MUST NOT strictly enforce the JSON format specified in the
|
||
[appendices](/appendices#canonical-json) for the reasons
|
||
described there.
|