Skip to content

Commit e650fca

Browse files
committed
Room versions 8 and 9: Restricted rooms
MSCs: * #3083 * #3289 * #3375
1 parent fa479af commit e650fca

File tree

12 files changed

+388
-27
lines changed

12 files changed

+388
-27
lines changed

content/_index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,10 @@ The available room versions are:
523523
- [Version 6](/rooms/v6) - **Stable**. Alters several
524524
authorization rules for events.
525525
- [Version 7](/rooms/v7) - **Stable**. Introduces knocking.
526+
- [Version 8](/rooms/v8) - **Stable**. Adds a join rule to allow members
527+
of another room to join without invite.
528+
- [Version 9](/rooms/v9) - **Stable**. Builds on v8 to fix issues when
529+
redacting some membership events.
526530

527531
## Specification Versions
528532

content/client-server-api/_index.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,6 +1734,12 @@ This room can only be joined if you were invited, and allows anyone to
17341734
request an invite to the room. Note that this join rule is only available
17351735
to rooms based upon [room version 7](/rooms/v7).
17361736

1737+
`restricted`
1738+
This room can be joined if you were invited or if you are a member of another
1739+
room listed in the join rules. If the server cannot verify membership for any
1740+
of the listed rooms then you can only join with an invite. Note that this join
1741+
rule is only available to rooms based upon [room version 8](/rooms/v8).
1742+
17371743
The allowable state transitions of membership are:
17381744

17391745
![membership-flow-diagram](/diagrams/membership.png)
@@ -1781,6 +1787,30 @@ server chose to auto-accept.
17811787

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

1790+
##### Restricted rooms
1791+
1792+
Restricted rooms are rooms with a `join_rule` of `restricted`. These rooms
1793+
are accompanied by "allow conditions" as described in the
1794+
[`m.room.join_rules`](#mroomjoin_rules) state event.
1795+
1796+
If the user has an invite to the room then the restrictions will not affect
1797+
them. They should be able to join by simply accepting the invite.
1798+
1799+
Currently there is only one condition available: `m.room_membership`. This
1800+
condition requires the user trying to join the room to be a *joined* member
1801+
of another room (specifically, the `room_id` accompanying the condition).
1802+
1803+
When joining without an invite, the server MUST verify that the requesting
1804+
user meets at least one of the conditions. If no conditions can be verified
1805+
or no conditions are satisfied, the user will not be able to join. This
1806+
validation is additionally done over federation when using a remote server
1807+
to join the room.
1808+
1809+
If the room is `restricted` but no valid conditions are presented then the
1810+
room is effectively invite only. The user does not need to maintain the
1811+
conditions in order to stay a member of the room: the conditions are only
1812+
checked/evaluated during the join process.
1813+
17841814
#### Leaving rooms
17851815

17861816
A user can leave a room to stop receiving events for that room. A user

content/rooms/_index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ weight: 60
1111
* [Room Version 5](v5)
1212
* [Room Version 6](v6)
1313
* [Room Version 7](v7)
14+
* [Room Version 8](v8)
15+
* [Room Version 9](v9)

content/rooms/v8.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
title: Room Version 8
3+
type: docs
4+
weight: 60
5+
---
6+
7+
This room version builds on [version 7](/rooms/v7) to introduce a new
8+
join rule that allows members to join the room based on membership in
9+
another room.
10+
11+
{{% boxes/warning %}}
12+
This room version is known to have issues relating to redactions of member
13+
join events. [Room version 9](/rooms/v9) should be preferred over v8 when
14+
creating rooms.
15+
{{% /boxes/warning %}}
16+
17+
## Client considerations
18+
19+
Clients are encouraged to expose the option for the join rule in their
20+
user interface for supported room versions. Specifically, this feature
21+
is intended to be used primarily in conjunction with
22+
[MSC1772-style Spaces](https://github.com/matrix-org/matrix-doc/pull/1772)
23+
(allowing members of a space to join a given room), though any v8 capable
24+
room will be able to support this newly introduced join rule.
25+
26+
The new join rule, `restricted`, is described in the Client-Server API
27+
under the [`m.room.join_rules`](/client-server-api/#mroomjoin_rules) section.
28+
29+
## Server implementation components
30+
31+
{{% boxes/warning %}}
32+
The information contained in this section is strictly for server
33+
implementors. Applications which use the Client-Server API are generally
34+
unaffected by the intricacies contained here. The section above
35+
regarding client considerations is the resource that Client-Server API
36+
use cases should reference.
37+
{{% /boxes/warning %}}
38+
39+
Room version 8 adds a new join rule to allow members of a room to join another
40+
room without invite. Otherwise, the room version inherits all properties of
41+
[Room version 7](/rooms/v7).
42+
43+
### Authorization rules for events
44+
45+
`m.room.member` events for `membership` of `join` are now validated as such:
46+
47+
1. If the only previous event is an `m.room.create` and the `state_key` is the
48+
creator, allow.
49+
2. If the `sender` does not match `state_key`, reject.
50+
3. If the `sender` is banned, reject.
51+
4. If the `join_rule` is `invite` then allow if membership state is `invite` or
52+
`knock`.
53+
5. **[New in this room version]** If the `join_rule` is `restricted`:
54+
1. If membership state is `join`, allow.
55+
2. If `content.join_authorised_via_users_server` is not a user with
56+
sufficient permission to invite other users, reject.
57+
3. If the event is not validly signed by the server denoted by the user ID in
58+
`content.join_authorised_via_users_server`, reject.
59+
4. Otherwise, allow.
60+
6. If the `join_rule` is `public`, allow.
61+
7. Otherwise, reject.
62+
63+
The remaining rules are the same as in [room version 7](/rooms/v7#server-implementation-components).
64+
65+
### Redactions
66+
67+
Events of type `m.room.join_rules` now keep the following `content` properties
68+
when the event is redacted:
69+
* `join_rule`
70+
* **[New in this room version]** `allow`
71+
72+
{{% boxes/warning %}}
73+
[Room version 9](/rooms/v9) adds additional cases of protected properties for behaviour
74+
related to restricted rooms (the functionality introduced in v8). v9 is preferred over
75+
v8 when creating new rooms.
76+
{{% /boxes/warning %}}
77+
78+
The remaining rules are the same as in [room version 6](/rooms/v6#redactions) (the
79+
last room version to modify the redaction rules).

content/rooms/v9.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
title: Room Version 9
3+
type: docs
4+
weight: 60
5+
---
6+
7+
This room version builds on [version 8](/rooms/v8) to add additional redaction
8+
rules that were unintentionally missed when incorporating v8.
9+
10+
## Client considerations
11+
12+
See [room version 8](/rooms/v8) for specific details regarding the addition of
13+
restricted rooms.
14+
15+
Clients which implement a local redaction algorithm are encouraged to read on.
16+
17+
## Server implementation components
18+
19+
{{% boxes/warning %}}
20+
The information contained in this section is strictly for server
21+
implementors. Applications which use the Client-Server API are generally
22+
unaffected by the intricacies contained here. The section above
23+
regarding client considerations is the resource that Client-Server API
24+
use cases should reference.
25+
{{% /boxes/warning %}}
26+
27+
Room version 8 added a new `restricted` join rule to allow members of a room
28+
to join another room without invite. Room version 9 is based upon v8 with the
29+
following considerations.
30+
31+
### Redactions
32+
33+
Events of type `m.room.member` now keep the following `content` properties
34+
when the event is redacted:
35+
* `membership`
36+
* **[New in this room version]** `join_authorised_via_users_server`
37+
38+
The remaining rules are the same as in [room version 8](/rooms/v8#redactions).
39+
40+
{{% boxes/rationale %}}
41+
Without the `join_authorised_via_users_server` property redacted join events
42+
can become invalid when verifying the auth chain of a given event, thus creating
43+
a split-brain scenario where the user is able to speak from one server's
44+
perspective but most others will continually reject their events.
45+
46+
This can theoretically be worked around with a rejoin to the room, being careful
47+
not to use the faulty events as `prev_events`, though instead it is encouraged
48+
to use v9 rooms over v8 rooms to outright avoid the situation.
49+
50+
[Issue #3373](https://github.com/matrix-org/matrix-doc/issues/3373) has further
51+
information.
52+
{{% /boxes/rationale %}}

content/server-server-api.md

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -407,21 +407,26 @@ the sender permission to send the event. The `auth_events` for the
407407
`m.room.create` event in a room is empty; for other events, it should be
408408
the following subset of the room state:
409409

410-
- The `m.room.create` event.
410+
- The `m.room.create` event.
411411

412-
- The current `m.room.power_levels` event, if any.
412+
- The current `m.room.power_levels` event, if any.
413413

414-
- The sender's current `m.room.member` event, if any.
414+
- The sender's current `m.room.member` event, if any.
415415

416-
- If type is `m.room.member`:
416+
- If type is `m.room.member`:
417417

418-
- The target's current `m.room.member` event, if any.
419-
- If `membership` is `join` or `invite`, the current
420-
`m.room.join_rules` event, if any.
421-
- If membership is `invite` and `content` contains a
422-
`third_party_invite` property, the current
423-
`m.room.third_party_invite` event with `state_key` matching
424-
`content.third_party_invite.signed.token`, if any.
418+
- The target's current `m.room.member` event, if any.
419+
- If `membership` is `join` or `invite`, the current
420+
`m.room.join_rules` event, if any.
421+
- If membership is `invite` and `content` contains a
422+
`third_party_invite` property, the current
423+
`m.room.third_party_invite` event with `state_key` matching
424+
`content.third_party_invite.signed.token`, if any.
425+
- If `content.join_authorised_via_users_server` is present,
426+
the `m.room.member` event with `state_key` matching
427+
`content.join_authorised_via_users_server`. Due to the
428+
auth rules for the event, the target membership event should
429+
always be eligible for inclusion.
425430

426431
#### Rejection
427432

@@ -721,15 +726,41 @@ To complete the join handshake, the joining server must now submit this
721726
new event to a resident homeserver, by using the `PUT /send_join`
722727
endpoint.
723728

724-
The resident homeserver then accepts this event into the room's event
725-
graph, and responds to the joining server with the full set of state for
726-
the newly-joined room. The resident server must also send the event to
727-
other servers participating in the room.
729+
the resident homeserver then adds its signature to this event and
730+
accepts it into the room's event graph. The joining server receives
731+
the full set of state for the newly-joined room. The resident server
732+
must also send the event to other servers participating in the room.
728733

729734
{{% http-api spec="server-server" api="joins-v1" %}}
730735

731736
{{% http-api spec="server-server" api="joins-v2" %}}
732737

738+
### Restricted rooms
739+
740+
Restricted rooms are described in detail in the
741+
[client-server API](/client-server-api/#restricted-rooms) and are available
742+
in room versions based on [v8](/rooms/v8).
743+
744+
A resident server attempting to join a server to a restricted room must
745+
ensure that the joining server satisfies at least one of the conditions
746+
specified by `m.room.join_rules`. If no conditions are available, or none
747+
match the required schema, then the joining server is considered to have
748+
failed all conditions.
749+
750+
The resident server uses a 400 `M_UNABLE_TO_AUTHORISE_JOIN` error on
751+
`/make_join` and `/send_join` to denote that the resident server is unable
752+
to validate any of the conditions, usually because the resident server
753+
does not have state information about rooms required by the conditions.
754+
755+
The resident server uses a 400 `M_UNABLE_TO_GRANT_JOIN` error on `/make_join`
756+
and `/send_join` to denote that the joining server satisfies at least
757+
one of the conditions, though the resident server would be unable to
758+
meet the auth rules governing `join_authorised_via_users_server` on the
759+
resulting `m.room.member` event.
760+
761+
If the joining server fails all conditions then a 403 `M_FORBIDDEN` error
762+
is used by the resident server.
763+
733764
## Knocking upon a room
734765

735766
Rooms can permit knocking through the join rules, and if permitted this

data/api/client-server/joining.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ paths:
9494
9595
- The room is invite-only and the user was not invited.
9696
- The user has been banned from the room.
97+
- The room is restricted and the user failed to satisfy any of the conditions.
9798
examples:
9899
application/json: {
99100
"errcode": "M_FORBIDDEN", "error": "You are not invited to this room."}
@@ -180,6 +181,7 @@ paths:
180181
181182
- The room is invite-only and the user was not invited.
182183
- The user has been banned from the room.
184+
- The room is restricted and the user failed to satisfy any of the conditions.
183185
examples:
184186
application/json: {
185187
"errcode": "M_FORBIDDEN", "error": "You are not invited to this room."}

data/api/server-server/joins-v1.yaml

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,14 @@ paths:
115115
type: string
116116
description: The value `join`.
117117
example: "join"
118+
join_authorised_via_users_server:
119+
type: string
120+
description: |-
121+
Required if the room is [restricted](/client-server-api/#restricted-rooms).
122+
An arbitrary user ID belonging to the resident server in
123+
the room being joined that is able to issue invites to other
124+
users. This is used in later validation of the auth rules for
125+
the `m.room.member` event.
118126
required: ['membership']
119127
required:
120128
- state_key
@@ -134,7 +142,8 @@ paths:
134142
"origin_server_ts": 1549041175876,
135143
"sender": "@someone:example.org",
136144
"content": {
137-
"membership": "join"
145+
"membership": "join",
146+
"join_authorised_via_users_server": "@anyone:resident.example.org"
138147
}
139148
}
140149
}
@@ -146,6 +155,19 @@ paths:
146155
147156
The error should be passed through to clients so that they
148157
may give better feedback to users.
158+
159+
If the room is [restricted](/client-server-api/#restricted-rooms)
160+
and none of the conditions can be validated by the server then
161+
the `errcode` `M_UNABLE_TO_AUTHORISE_JOIN` must be used. This can
162+
happen if the server does not know about any of the rooms listed
163+
as conditions, for example.
164+
165+
If the room is [restricted](/client-server-api/#restricted-rooms)
166+
and the user meets at least one of the conditions, but the server
167+
does not have permission to send invites (a prerequisite for later
168+
authorisation of the `m.room.member` event) then an `errcode` of
169+
`M_UNABLE_TO_GRANT_JOIN` is returned. The joining server should
170+
attempt another resident server.
149171
schema:
150172
allOf:
151173
- $ref: "../client-server/definitions/errors/error.yaml"
@@ -162,7 +184,20 @@ paths:
162184
"error": "Your homeserver does not support the features required to join this room",
163185
"room_version": "3"
164186
}
187+
403:
188+
schema:
189+
$ref: "../client-server/definitions/errors/error.yaml"
190+
description: |-
191+
The room that the joining server is attempting to join does not permit the user
192+
to join.
193+
examples:
194+
application/json: {
195+
"errcode": "M_FORBIDDEN",
196+
"error": "You are not invited to this room",
197+
}
165198
404:
199+
schema:
200+
$ref: "../client-server/definitions/errors/error.yaml"
166201
description: |-
167202
The room that the joining server is attempting to join is unknown
168203
to the receiving server.
@@ -240,6 +275,19 @@ paths:
240275
type: string
241276
description: The value `join`.
242277
example: "join"
278+
join_authorised_via_users_server:
279+
type: string
280+
description: |-
281+
Required if the room is [restricted](/client-server-api/#restricted-rooms).
282+
An arbitrary user ID belonging to the resident server in
283+
the room being joined that is able to issue invites to other
284+
users. This is used in later validation of the auth rules for
285+
the `m.room.member` event.
286+
287+
The resident server which owns the provided user ID must have a
288+
valid signature on the event. If the resident server is receiving
289+
the `/send_join` request, the signature must be added before sending
290+
or persisting the event to other servers.
243291
required: ['membership']
244292
required:
245293
- state_key
@@ -256,7 +304,8 @@ paths:
256304
"origin_server_ts": 1549041175876,
257305
"sender": "@someone:example.org",
258306
"content": {
259-
"membership": "join"
307+
"membership": "join",
308+
"join_authorised_via_users_server": "@anyone:resident.example.org"
260309
}
261310
}
262311
responses:

0 commit comments

Comments
 (0)