Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Room versions 8 and 9: Restricted rooms #3387

Merged
merged 24 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e650fca
Room versions 8 and 9: Restricted rooms
turt2live Sep 8, 2021
7a5e820
Changelogs
turt2live Sep 8, 2021
3769724
Capitalization
turt2live Sep 8, 2021
f7f2ea8
Remove verbiage for spaces because they don't exist
turt2live Sep 8, 2021
2ccae80
Iterations on text
turt2live Sep 8, 2021
e3b7735
Merge remote-tracking branch 'origin/travis/spec/v8-v9' into travis/s…
turt2live Sep 8, 2021
db2a738
Another clarification
turt2live Sep 8, 2021
c613d2e
Make error code descriptions consistent
turt2live Sep 24, 2021
d521f25
Merge remote-tracking branch 'origin/main' into travis/spec/v8-v9
turt2live Sep 24, 2021
b31298d
Apply suggestions from code review
turt2live Sep 28, 2021
9c18649
Merge branch 'main' into travis/spec/v8-v9
turt2live Dec 28, 2021
b04da31
Incorporate from merge
turt2live Dec 28, 2021
17954df
Misc language update per review
turt2live Dec 28, 2021
75fc992
Update accuracy before splitting auth rules
turt2live Dec 28, 2021
44fc526
fix wtf moment
turt2live Dec 28, 2021
3447b12
Fix up v8 and v9 to match "fully specify room versions"
turt2live Dec 28, 2021
a8fa47f
Scope auth events selection to room version
turt2live Dec 28, 2021
157f750
Apply consistency
turt2live Dec 29, 2021
42195ca
Add changelogs
turt2live Dec 29, 2021
56bf4a4
Review part 1
turt2live Jan 10, 2022
245cc17
Apply suggestions from code review
turt2live Jan 10, 2022
fd82238
Split out redaction sections
turt2live Jan 10, 2022
cc65d8a
Clarify general case of join conditions
turt2live Jan 18, 2022
e58bc1b
Update diagram
turt2live Jan 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelogs/client_server/newsfragments/3387.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for `restricted` rooms as per [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083), [MSC3289](https://github.com/matrix-org/matrix-doc/pull/3289), and [MSC3375](https://github.com/matrix-org/matrix-doc/pull/3375).
1 change: 1 addition & 0 deletions changelogs/room_versions/newsfragments/3387.feature.1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add Room Version 8 as per [MSC3289](https://github.com/matrix-org/matrix-doc/pull/3289).
richvdh marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions changelogs/room_versions/newsfragments/3387.feature.2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add Room Version 9 as per [MSC3375](https://github.com/matrix-org/matrix-doc/pull/3375).
1 change: 1 addition & 0 deletions changelogs/server_server/newsfragments/3387.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for `restricted` rooms as per [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083), [MSC3289](https://github.com/matrix-org/matrix-doc/pull/3289), and [MSC3375](https://github.com/matrix-org/matrix-doc/pull/3375).
59 changes: 55 additions & 4 deletions content/client-server-api/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,7 @@ of the message timeline. The client can fill these gaps using the
[`/rooms/<room_id>/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) API.

Continuing our example, suppose we make a third `/sync` request asking for
events since the last sync, by passing the `next_batch` token `x-y-z` as
events since the last sync, by passing the `next_batch` token `x-y-z` as
the `since` parameter. The server knows about four new events, `E7`, `E8`,
`E9` and `E10`, but decides this is too many to report at once. Instead,
the server sends a `limited` response containing `E8`, `E9` and `E10`but
Expand All @@ -1476,14 +1476,14 @@ omitting `E7`. This forms a gap, which we can see in the visualisation:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10]
^ ^ ^
| | |
since: 'x-y-z' | |
since: 'x-y-z' | |
prev_batch: 'd-e-f' next_batch: 'u-v-w'
```

The limited response includes a state delta which describes how the state
of the room changes over the gap. This delta explains how to build the state
prior to returned timeline (i.e. at `E7`) from the state the client knows
(i.e. at `E6`). To close the gap, the client should make a request to
prior to returned timeline (i.e. at `E7`) from the state the client knows
(i.e. at `E6`). To close the gap, the client should make a request to
[`/rooms/<room_id>/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages)
with the query parameters `from=x-y-z` and `to=d-e-f`.

Expand Down Expand Up @@ -1748,6 +1748,12 @@ 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
in room versions [which support knocking](/rooms/#feature-matrix).

{{% added-in v="1.2" %}} `restricted`
This room can be joined if you were invited or if you are a member of another
turt2live marked this conversation as resolved.
Show resolved Hide resolved
room listed in the join rules. If the server cannot verify membership for any
of the listed rooms then you can only join with an invite. Note that this rule
is only expected to work in room versions [which support it](/rooms/#feature-matrix).

The allowable state transitions of membership are:

![membership-flow-diagram](/diagrams/membership.png)
turt2live marked this conversation as resolved.
Show resolved Hide resolved
turt2live marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -1797,6 +1803,51 @@ server chose to auto-accept.

{{% http-api spec="client-server" api="knocking" %}}

##### Restricted rooms

{{% added-in v="1.2" %}}

Restricted rooms are rooms with a `join_rule` of `restricted`. These rooms
turt2live marked this conversation as resolved.
Show resolved Hide resolved
are accompanied by "allow conditions" as described in the
[`m.room.join_rules`](#mroomjoin_rules) state event.

If the user has an invite to the room then the restrictions will not affect
them. They should be able to join by simply accepting the invite.

When joining without an invite, the server MUST verify that the requesting
turt2live marked this conversation as resolved.
Show resolved Hide resolved
user meets at least one of the conditions. If no conditions can be verified
or no conditions are satisfied, the user will not be able to join. When the
join is happening over federation, the remote server will check the conditions
before accepting the join. See the [Server-Server Spec](/server-server-api/#restricted-rooms)
for more information.

If the room is `restricted` but no valid conditions are presented then the
room is effectively invite only.

The user does not need to maintain the conditions in order to stay a member
of the room: the conditions are only checked/evaluated during the join process.

###### Conditions

Currently there is only one condition available: `m.room_membership`. This
condition requires the user trying to join the room to be a *joined* member
of another room (specifically, the `room_id` accompanying the condition). For
example, if `!restricted:example.org` wanted to allow joined members of
`!other:example.org` to join, `!restricted:example.org` would have the following
`content` for [`m.room.join_rules`](#mroomjoin_rules):

```json
{
"join_rule": "restricted",
"allow": [
{
"room_id": "!other:example.org",
"type": "m.room_membership"
}
]
}
```

#### Leaving rooms

A user can leave a room to stop receiving events for that room. A user
Expand Down
11 changes: 8 additions & 3 deletions content/rooms/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ Alternatively, consider flipping the column/row organization to be features
up top and versions on the left.
-->

| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|-------------------|---|---|---|---|---|---|---|
| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ |
| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|-------------------|---|---|---|---|---|---|---|---|---|
| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ |
| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ |

## Complete list of room versions

Expand Down Expand Up @@ -68,6 +69,10 @@ The available room versions are:
- [Version 6](/rooms/v6) - **Stable**. Alters several
authorization rules for events.
- [Version 7](/rooms/v7) - **Stable**. Introduces knocking.
- [Version 8](/rooms/v8) - **Stable**. Adds a join rule to allow members
of another room to join without invite.
- [Version 9](/rooms/v9) - **Stable**. Builds on v8 to fix issues when
redacting some membership events.

## Room version grammar

Expand Down
160 changes: 160 additions & 0 deletions content/rooms/fragments/v8-auth-rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
---
toc_hide: true
---

Events must be signed by the server denoted by the `sender` key.

`m.room.redaction` events are not explicitly part of the auth rules.
They are still subject to the minimum power level rules, but should always
fall into "10. Otherwise, allow". Instead of being authorized at the time
of receipt, they are authorized at a later stage: see the
[Redactions](#redactions) section below for more information.

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.member`:
1. If no `state_key` key or `membership` key in `content`, reject.
2. If `content` has a `join_authorised_via_users_server`
key:
1. If the event is not validly signed by the user ID denoted
by the key, reject.
3. 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 `restricted`:
1. If membership state is `join` or `invite`, allow.
2. If the `join_authorised_via_users_server` key in `content`
is not a user with sufficient permission to invite other
users, reject.
3. Otherwise, allow.
6. If the `join_rule` is `public`, allow.
7. Otherwise, reject.
4. 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.
5. 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.
6. 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.
7. If `membership` is `knock`:
1. If the `join_rule` is anything other than `knock`, reject.
2. If `sender` does not match `state_key`, reject.
3. If the `sender`'s current membership is not `ban`, `invite`,
or `join`, allow.
8. Otherwise, the membership is unknown. Reject.
5. If the `sender`'s current membership state is not `join`, reject.
6. 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*.
7. If the event type's *required power level* is greater than the
`sender`'s power level, reject.
8. If the event has a `state_key` that starts with an `@` and does not
match the `sender`, reject.
9. 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`, `users`, and `notifications` 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.
10. 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 %}}
6 changes: 4 additions & 2 deletions content/rooms/v7.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ completeness.

{{% rver-fragment name="v4-event-format" %}}

### Handling redactions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'd be nice if we could figure out what order these things go in (in v5 'Handling redactions' is before 'Event IDs' and 'Event format'), but I guess I'm just nit-picking really.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they're supposed to be consistent, but that ship sailed when I thought they were consistent last time. Will attempt to fix in a future PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


{{% rver-fragment name="v3-handling-redactions" %}}

### Canonical JSON

{{% rver-fragment name="v6-canonical-json" %}}
Expand All @@ -209,6 +213,4 @@ completeness.

### Redactions

{{% rver-fragment name="v3-handling-redactions" %}}

{{% rver-fragment name="v6-redactions" %}}
Loading