diff --git a/changelogs/appendices/newsfragments/2193.feature b/changelogs/appendices/newsfragments/2193.feature new file mode 100644 index 00000000..317f317f --- /dev/null +++ b/changelogs/appendices/newsfragments/2193.feature @@ -0,0 +1 @@ +Room IDs can now appear without a domain component in [room version 12](/rooms/v12), as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291). diff --git a/changelogs/client_server/newsfragments/2193.feature.1 b/changelogs/client_server/newsfragments/2193.feature.1 new file mode 100644 index 00000000..befb76d2 --- /dev/null +++ b/changelogs/client_server/newsfragments/2193.feature.1 @@ -0,0 +1 @@ +When upgrading rooms to [room version 12](/rooms/v12), `additional_creators` may be specified on the [`POST /_matrix/client/v3/rooms/{roomId}/upgrade`](/client-server-api/#post_matrixclientv3roomsroomidupgrade) endpoint, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). diff --git a/changelogs/client_server/newsfragments/2193.feature.2 b/changelogs/client_server/newsfragments/2193.feature.2 new file mode 100644 index 00000000..280a83e6 --- /dev/null +++ b/changelogs/client_server/newsfragments/2193.feature.2 @@ -0,0 +1 @@ +When creating rooms with [room version 12](/rooms/v12), the `trusted_private_chat` preset should merge the invitees into the supplied `content.additional_creators` in the resulting room, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). diff --git a/changelogs/client_server/newsfragments/2193.feature.3 b/changelogs/client_server/newsfragments/2193.feature.3 new file mode 100644 index 00000000..5f8b1fab --- /dev/null +++ b/changelogs/client_server/newsfragments/2193.feature.3 @@ -0,0 +1 @@ +In [room version 12](/rooms/v12), the power level of room creators is now infinitely high as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). diff --git a/changelogs/client_server/newsfragments/2193.feature.4 b/changelogs/client_server/newsfragments/2193.feature.4 new file mode 100644 index 00000000..98d8f126 --- /dev/null +++ b/changelogs/client_server/newsfragments/2193.feature.4 @@ -0,0 +1 @@ +In [room version 12](/rooms/v12), room IDs no longer have a domain component as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291). diff --git a/changelogs/client_server/newsfragments/2193.feature.5 b/changelogs/client_server/newsfragments/2193.feature.5 new file mode 100644 index 00000000..e1b54e80 --- /dev/null +++ b/changelogs/client_server/newsfragments/2193.feature.5 @@ -0,0 +1 @@ +When creating rooms with [room version 12](/rooms/v12), the initial power levels will restrict the ability to upgrade rooms by default, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). diff --git a/changelogs/internal/newsfragments/2193.feature b/changelogs/internal/newsfragments/2193.feature new file mode 100644 index 00000000..43972665 --- /dev/null +++ b/changelogs/internal/newsfragments/2193.feature @@ -0,0 +1 @@ +TODO: Placeholder \ No newline at end of file diff --git a/changelogs/room_versions/newsfragments/2193.clarification b/changelogs/room_versions/newsfragments/2193.clarification new file mode 100644 index 00000000..39e25b5a --- /dev/null +++ b/changelogs/room_versions/newsfragments/2193.clarification @@ -0,0 +1 @@ +In room versions 1 through 12, an event's `auth_events` have always needed to belong to the same room as per [MSC4307](https://github.com/matrix-org/matrix-spec-proposals/pull/4307). diff --git a/changelogs/room_versions/newsfragments/2193.feature.1 b/changelogs/room_versions/newsfragments/2193.feature.1 new file mode 100644 index 00000000..88e57469 --- /dev/null +++ b/changelogs/room_versions/newsfragments/2193.feature.1 @@ -0,0 +1 @@ +Add [room version 12](/rooms/v12) as per [MSC4304](https://github.com/matrix-org/matrix-spec-proposals/pull/4304). diff --git a/changelogs/room_versions/newsfragments/2193.feature.2 b/changelogs/room_versions/newsfragments/2193.feature.2 new file mode 100644 index 00000000..995fe87b --- /dev/null +++ b/changelogs/room_versions/newsfragments/2193.feature.2 @@ -0,0 +1 @@ +Room IDs in room version 12 are now the event ID of the create event with the normal room ID sigil (`!`), as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291). diff --git a/changelogs/room_versions/newsfragments/2193.feature.3 b/changelogs/room_versions/newsfragments/2193.feature.3 new file mode 100644 index 00000000..2a396a3e --- /dev/null +++ b/changelogs/room_versions/newsfragments/2193.feature.3 @@ -0,0 +1 @@ +Room creators are formalized in room version 12 and have infinitely high power level, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). diff --git a/changelogs/room_versions/newsfragments/2193.feature.4 b/changelogs/room_versions/newsfragments/2193.feature.4 new file mode 100644 index 00000000..c9f22df1 --- /dev/null +++ b/changelogs/room_versions/newsfragments/2193.feature.4 @@ -0,0 +1 @@ +State Resolution is updated in room version 12 to reduce the opportunity for "state resets", as per [MSC4297](https://github.com/matrix-org/matrix-spec-proposals/pull/4297). diff --git a/changelogs/room_versions/newsfragments/2193.feature.5 b/changelogs/room_versions/newsfragments/2193.feature.5 new file mode 100644 index 00000000..6c1ee1fc --- /dev/null +++ b/changelogs/room_versions/newsfragments/2193.feature.5 @@ -0,0 +1 @@ +The default room version is now room version 12, though servers SHOULD keep using room version 11 for a little while, as per [MSC4304](https://github.com/matrix-org/matrix-spec-proposals/pull/4304). diff --git a/content/appendices.md b/content/appendices.md index 349b05e9..923f9315 100644 --- a/content/appendices.md +++ b/content/appendices.md @@ -657,27 +657,48 @@ provides no way to encode ASCII punctuation). #### Room IDs -A room has exactly one room ID. A room ID has the format: +{{% changed-in v="1.16" %}} Room IDs can now appear without a domain depending on +the room version. + +A room has exactly one room ID. Room IDs take the form: + + !opaque_id + +However, the precise format depends upon the [room version specification](/rooms): +some room versions included a `domain` component, whereas more recent room versions +omit the domain and use a base64-encoded hash instead. + +Room IDs are case-sensitive and not meant to be human-readable. They are intended +to be used as fully opaque strings by clients, even when a `domain` component is +present. + +If the room version requires a `domain` component, room IDs take the following +form: !opaque_id:domain -The `domain` of a room ID is the [server name](#server-name) of the -homeserver which created the room. 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 in -question is still available at the corresponding homeserver. +In such a form, the `opaque_id` is a localpart. The localpart MUST only contain +valid non-surrogate Unicode code points, including control characters, except `:` +and `NUL` (U+0000). The localpart SHOULD only consist of alphanumeric characters +(`A-Z`, `a-z`, `0-9`) when generating them. The `domain` is the [server name](#server-name) +of the homeserver which created the room - it is only used to reduce namespace +collisions. There is no implication that the room in question is still available +at the corresponding homeserver. Combined, the localpart, domain, and `!` sigil +MUST NOT exceed 255 bytes. -Room IDs are case-sensitive. They are not meant to be -human-readable. They are intended to be treated as fully opaque strings -by clients. +When a room version requires the `domain`-less format, room IDs are simply the +[event ID](#event-ids) of the `m.room.create` event using `!` as the sigil instead +of `$`. The grammar is otherwise inherited verbatim. -The localpart of a room ID (`opaque_id` above) may contain any valid -non-surrogate Unicode code points, including control characters, except `:` and `NUL` -(U+0000), but it is recommended to only include ASCII letters and -digits (`A-Z`, `a-z`, `0-9`) when generating them. +{{% boxes/note %}} +Applications which previously relied upon the `domain` in a room ID can instead +parse the [user IDs](#user-identifiers) found in the `m.room.create` event's `sender`. -The length of a room ID, including the `!` sigil and the domain, MUST -NOT exceed 255 bytes. +Though the `m.room.create` event's `additional_creators` (in `content`) may be +used when present, applications should take care when parsing or interpreting the +list. The user IDs in `additional_creators` will have correct grammar, but may +not be real users or may not belong to actual Matrix homeservers. +{{% /boxes/note %}} #### Room Aliases diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 173769c9..18a9cc27 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -2506,7 +2506,7 @@ and the client is not permitted to make any changes. When `enabled` is `true`, clients are permitted to modify profile fields, subject to the restrictions implied by the OPTIONAL lists `allowed` and -`disallowed`. +`disallowed`. If `allowed` is present, clients can modify only the fields listed. They SHOULD assume all other fields to be managed by @@ -2546,7 +2546,7 @@ This capability is now deprecated. Clients SHOULD use the [`m.profile_fields`](/client-server-api/#mprofile_fields-capability) capability instead. -For backwards compatibility, servers that forbid setting the +For backwards compatibility, servers that forbid setting the `displayname` profile field in the `m.profile_fields` capability MUST still present this capability with `"enabled": false`. {{% /boxes/note %}} @@ -2581,7 +2581,7 @@ This capability is now deprecated. Clients SHOULD use the [`m.profile_fields`](/client-server-api/#mprofile_fields-capability) capability instead. -For backwards compatibility, servers that forbid setting the +For backwards compatibility, servers that forbid setting the `avatar_url` profile field in the `m.profile_fields` capability MUST still present this capability with `"enabled": false`. {{% /boxes/note %}} @@ -3414,27 +3414,49 @@ request. ### Permissions -{{% boxes/note %}} -This section is a work in progress. -{{% /boxes/note %}} +{{% changed-in v="1.16" %}} Updated section to discuss creator power level +in room version 12 and beyond. Permissions for rooms are done via the concept of power levels - to do any action in a room a user must have a suitable power level. Power levels are stored as state events in a given room. The power levels -required for operations and the power levels for users are defined in -`m.room.power_levels`, where both a default and specific users' power -levels can be set. By default all users have a power level of 0, other -than the room creator whose power level defaults to 100. Users can grant -other users increased power levels up to their own power level. For -example, user A with a power level of 50 could increase the power level -of user B to a maximum of level 50. Power levels for users are tracked -per-room even if the user is not present in the room. The keys contained -in `m.room.power_levels` determine the levels required for certain -operations such as kicking, banning and sending state events. See -[m.room.power\_levels](#room-events) for more information. - -Clients may wish to assign names to particular power levels. A suggested -mapping is as follows: - 0 User - 50 Moderator - 100 Admin +required for operations and the power levels assigned to specific users +are defined in the `m.room.power_levels` state event. The `m.room.power_levels` +state event additionally defines some defaults, though room creators +are special in that: + +* In [room versions](/rooms) 1 through 11, room creators by default + have power level 100 but still can have that level changed by power level + events, by the same rules as other members. +* In [room version 12](/rooms/v12) (and beyond), room creators are + *not* specified in the power levels event and have an infinitely high + power level that is immutable. After room creation, users + cannot be given this same infinitely high power level. + +Users can grant other users increased power levels up to their own +power level (or the maximum allowable integer for the room when their +power level is infinitely high). For example, user A with a power level +of 50 could increase the power level of user B to a maximum of level 50. +Power levels for users are tracked per-room even if the user is not +present in the room. The keys contained in `m.room.power_levels` determine +the levels required for certain operations such as kicking, banning, and +sending state events. See [`m.room.power_levels`](#mroompower_levels) for more +information. + +Clients may wish to assign names to particular power levels. Most rooms +will use the default power level hierarchy assigned during room creation, +but rooms may still deviate slightly. + +A suggested mapping is as follows: + +* 0 to `state_default-1` (typically 49): User +* `state_default` to the level required to send `m.room.power_levels` events + minus 1 (typically 99): Moderator +* The level required send `m.room.power_levels` events and above: Administrator +* Creators of the room, in room version 12 and beyond: Creator + +Clients may also wish to distinguish "above admin" power levels based on the +level required to send `m.room.tombstone` events. ### Room membership diff --git a/content/client-server-api/modules/room_upgrades.md b/content/client-server-api/modules/room_upgrades.md index 647fb377..0950b34f 100644 --- a/content/client-server-api/modules/room_upgrades.md +++ b/content/client-server-api/modules/room_upgrades.md @@ -36,6 +36,17 @@ server: previous room, no `type` is specified on the new room's create event either. +{{% boxes/note %}} +{{% added-in v="1.16" %}} If both the new and old [room version](/rooms) support +additional creators, the server will not transfer those additional creators automatically. +They must be explicitly set during the `/upgrade` call. +{{% /boxes/note %}} + +{{% boxes/note %}} +{{% added-in v="1.16" %}} When upgrading to room version 12 or later, the `predecessor` field MAY NOT contain +an `event_id`. +{{% /boxes/note %}} + 3. Replicates transferable state events to the new room. The exact details for what is transferred is left as an implementation detail, however the recommended state events to transfer are: diff --git a/content/rooms/_index.md b/content/rooms/_index.md index d970bfe7..3e7aec72 100644 --- a/content/rooms/_index.md +++ b/content/rooms/_index.md @@ -36,11 +36,12 @@ 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 | 8 | 9 | 10 | 11 | -|-------------------|---|---|---|---|---|---|---|---|---|----|----| -| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | -| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | -| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | +| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | +|-------------------|---|---|---|---|---|---|---|---|---|----|----|----| +| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | +| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | +| **Additional room creators** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ## Complete list of room versions @@ -52,9 +53,22 @@ stable and unstable periodically for a variety of reasons, including discovered security vulnerabilities and age. Clients should not ask room administrators to upgrade their rooms if the -room is running a stable version. Servers SHOULD use **room version 11** as +room is running a stable version. Servers SHOULD use **room version 12** as the default room version when creating new rooms. +{{% boxes/note %}} + +{{% added-in v="1.16" %}} + +Room version 12 is introduced and made default in this specification release. +Servers are encouraged to continue using room version 11 as the default room +version for the early days and weeks following this specification release, +and then gradually switch the default over when they deem appropriate. + + + +{{% /boxes/note %}} + The available room versions are: - [Version 1](/rooms/v1) - **Stable**. The initial room version. @@ -76,6 +90,9 @@ The available room versions are: - [Version 10](/rooms/v10) - **Stable**. Enforces integer-only power levels and adds `knock_restricted` join rule. - [Version 11](/rooms/v11) - **Stable**. Clarifies the redaction algorithm. +- [Version 12](/rooms/v12) - **Stable**. Changes room IDs to be hashes of the + create event, formalizes room creators with infinite power level, and iterates + on state resolution. ## Room version grammar diff --git a/content/rooms/fragments/v1-auth-rules.md b/content/rooms/fragments/v1-auth-rules.md index 3ea09982..ba637beb 100644 --- a/content/rooms/fragments/v1-auth-rules.md +++ b/content/rooms/fragments/v1-auth-rules.md @@ -30,10 +30,14 @@ The rules are as follows: specified by the [auth events selection](/server-server-api#auth-events-selection) algorithm described in the server specification, reject. + + **Note**: This room version requires an `m.room.create` event to be selected. 3. If there are entries which were themselves rejected under the [checks performed on receipt of a PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject. 4. If there is no `m.room.create` event among the entries, reject. + 5. If any event in `auth_events` has a `room_id` which does not match that of + the event being authorised, reject. 3. If the `content` of the `m.room.create` event in the room state has the property `m.federate` set to `false`, and the `sender` domain of the event does not match the `sender` domain of the create event, reject. diff --git a/content/rooms/fragments/v12-event-format.md b/content/rooms/fragments/v12-event-format.md new file mode 100644 index 00000000..ca596638 --- /dev/null +++ b/content/rooms/fragments/v12-event-format.md @@ -0,0 +1,4 @@ + +Events in rooms of this version have the following structure: + +{{% definition path="api/server-server/definitions/pdu_v12" %}} diff --git a/content/rooms/fragments/v3-auth-rules.md b/content/rooms/fragments/v3-auth-rules.md index 577dfe4e..6b7f294e 100644 --- a/content/rooms/fragments/v3-auth-rules.md +++ b/content/rooms/fragments/v3-auth-rules.md @@ -38,10 +38,14 @@ The complete list of rules, as of room version 3, is as follows: specified by the [auth events selection](/server-server-api#auth-events-selection) algorithm described in the server specification, reject. + + **Note**: This room version requires an `m.room.create` event to be selected. 3. If there are entries which were themselves rejected under the [checks performed on receipt of a PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject. 4. If there is no `m.room.create` event among the entries, reject. + 5. If any event in `auth_events` has a `room_id` which does not match that of + the event being authorised, reject. 3. If the `content` of the `m.room.create` event in the room state has the property `m.federate` set to `false`, and the `sender` domain of the event does not match the `sender` domain of the create event, reject. diff --git a/content/rooms/fragments/v8-auth-rules.md b/content/rooms/fragments/v8-auth-rules.md index 8da010ef..9e267e53 100644 --- a/content/rooms/fragments/v8-auth-rules.md +++ b/content/rooms/fragments/v8-auth-rules.md @@ -44,10 +44,14 @@ The rules are as follows: specified by the [auth events selection](/server-server-api#auth-events-selection) algorithm described in the server specification, reject. + + **Note**: This room version requires an `m.room.create` event to be selected. 3. If there are entries which were themselves rejected under the [checks performed on receipt of a PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject. 4. If there is no `m.room.create` event among the entries, reject. + 5. If any event in `auth_events` has a `room_id` which does not match that of + the event being authorised, reject. 3. If the `content` of the `m.room.create` event in the room state has the property `m.federate` set to `false`, and the `sender` domain of the event does not match the `sender` domain of the create event, reject. diff --git a/content/rooms/v10.md b/content/rooms/v10.md index 81daf4d6..3cfe1998 100644 --- a/content/rooms/v10.md +++ b/content/rooms/v10.md @@ -120,10 +120,14 @@ The rules are as follows: specified by the [auth events selection](/server-server-api#auth-events-selection) algorithm described in the server specification, reject. + + **Note**: This room version requires an `m.room.create` event to be selected. 3. If there are entries which were themselves rejected under the [checks performed on receipt of a PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject. 4. If there is no `m.room.create` event among the entries, reject. + 5. If any event in `auth_events` has a `room_id` which does not match that of + the event being authorised, reject. 3. If the `content` of the `m.room.create` event in the room state has the property `m.federate` set to `false`, and the `sender` domain of the event does not match the `sender` domain of the create event, reject. diff --git a/content/rooms/v11.md b/content/rooms/v11.md index 1be3a405..db1b1928 100644 --- a/content/rooms/v11.md +++ b/content/rooms/v11.md @@ -127,10 +127,14 @@ The rules are as follows: specified by the [auth events selection](/server-server-api#auth-events-selection) algorithm described in the server specification, reject. + + **Note**: This room version requires an `m.room.create` event to be selected. 3. If there are entries which were themselves rejected under the [checks performed on receipt of a PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject. 4. If there is no `m.room.create` event among the entries, reject. + 5. If any event in `auth_events` has a `room_id` which does not match that of + the event being authorised, reject. 3. If the `content` of the `m.room.create` event in the room state has the property `m.federate` set to `false`, and the `sender` domain of the event does not match the `sender` domain of the create event, reject. diff --git a/content/rooms/v12.md b/content/rooms/v12.md new file mode 100644 index 00000000..992488f0 --- /dev/null +++ b/content/rooms/v12.md @@ -0,0 +1,502 @@ +--- +title: Room Version 12 +type: docs +weight: 100 +version: 12 +--- + +This room version builds on [version 11](/rooms/v11), iterating on the state resolution +algorithm, giving room creators infinite power level, and changing the format of room +IDs to be a hash of the create event. + +## Client considerations + +### Event format + +Clients SHOULD observe the following changes to events in this room version: + +* Room IDs no longer include a domain component and are instead a hash of the + `m.room.create` event, per below. See the [room ID grammar](/appendices#room-ids) + for more information. + +* A concept of "room creators" is formally defined as the `sender` of the `m.room.create` + event *plus* any `additional_creators` from the `m.room.create` event's `content`, + if present. In prior room versions, the only creator was the `sender` of the + `m.room.create` event (or `creator` in much older room versions). + +* Room creators have infinitely high power level and cannot be specified in the + `m.room.power_levels` event, nor can they be changed after the room is created. + +## 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 %}} + +Room version 12 is based upon room version 11 with the following considerations. + +### Event format + +{{% rver-fragment name="v12-event-format" %}} + +### Authorization rules + +Events must be signed by the server denoted by the `sender` property. + +The types of state events that affect authorization are: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_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 %}} + +{{% boxes/note %}} +{{% added-in v=12 %}} The power level of "room creators" is infinitely high. + +Room creators include: +* The user ID denoted by the `sender` of the `m.room.create` event in the room. +* Any user IDs contained in the `additional_creators` array in `content` of the + `m.room.create` event in the room, if `additional_creators` is present. + +Room creators cannot be demoted to a lower power level, even through `m.room.power_levels`. +This is reflected in rule 10.4 below. +{{% /boxes/note %}} + +{{% boxes/note %}} +`m.room.redaction` events are subject to auth rules in the same way as any other event. +In practice, that means they will normally be allowed by the auth rules, unless the +`m.room.power_levels` event sets a power level requirement for `m.room.redaction` +events via the `events` or `events_default` properties. In particular, the _redact +level_ is **not** considered by the auth rules. + +The ability to send a redaction event does not mean that the redaction itself should +be performed. Receiving servers must perform additional checks, as described in +the [Handling redactions](#handling-redactions) section. +{{% /boxes/note %}} + +{{% boxes/note %}} +The `m.room.create` event MUST NOT be selected for `auth_events` on events. The +`room_id` (being the `m.room.create` event's ID) implies this instead. This is +reflected in a change to rule 3.2 below. +{{% /boxes/note %}} + +The rules are as follows: + +1. If type is `m.room.create`: + 1. If it has any `prev_events`, reject. + 2. {{% changed-in v=12 %}} If the event has a `room_id`, reject. + + **Note**: The room ID is the event ID of the event with sigil `!` instead + of `$`. + 3. If `content.room_version` is present and is not a recognised + version, reject. + 4. {{% added-in v=12 %}} If `additional_creators` is present in `content` and + is not an array of strings where each string passes the same [user ID](/appendices#user-identifiers) + validation applied to `sender`, reject. + 5. Otherwise, allow. +2. {{% added-in v=12 %}} If the event's `room_id` is not an event ID for an accepted + (not rejected) `m.room.create` event, with the sigil `!` instead of `$`, reject. +3. Considering the event's `auth_events`: + 1. If there are duplicate entries for a given `type` and `state_key` pair, + reject. + 2. {{% changed-in v=12 %}} If there are 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, reject. + + **Note**: In this room version, `m.room.create` MUST NOT be selected. + 3. If there are entries which were themselves rejected under the [checks + performed on receipt of a + PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject. + 5. If any event in `auth_events` has a `room_id` which does not match that of + the event being authorised, reject. +4. If the `content` of the `m.room.create` event in the room state has the + property `m.federate` set to `false`, and the `sender` domain of the event + does not match the `sender` domain of the create event, reject. +5. If type is `m.room.member`: + 1. If there is no `state_key` property, or no `membership` property in + `content`, reject. + 2. If `content` has a `join_authorised_via_users_server` + key: + 1. If the event is not validly signed by the homeserver of the user ID denoted + by the key, reject. + 3. If `membership` is `join`: + 1. {{% changed-in v=11 %}} + If the only previous event is an `m.room.create` and the + `state_key` is the sender of the `m.room.create`, 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` or `knock` then allow if + membership state is `invite` or `join`. + 5. If the `join_rule` is `restricted` or `knock_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 a `third_party_invite` property: + 1. If *target user* is banned, reject. + 2. If `content.third_party_invite` does not have a `signed` + property, reject. + 3. If `signed` does not have `mxid` and `token` properties, + 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` property. + 2. A list of public keys in the `public_keys` property. + 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`, `join`, + or `knock`. + 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` or + `knock_restricted`, reject. + 2. If `sender` does not match `state_key`, reject. + 3. If the `sender`'s current membership is not `ban`, `invite`, + or `join`, allow. + 4. Otherwise, reject. + 8. 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 any of the properties `users_default`, `events_default`, `state_default`, + `ban`, `redact`, `kick`, or `invite` in `content` are present and + not an integer, reject. + 2. If either of the properties `events` or `notifications` in `content` + are present and not an object with values that are integers, + reject. + 3. If the `users` property in `content` is not an object with keys that + are valid user IDs with values that are integers, reject. + 4. {{% added-in v=12 %}} If the `users` property in `content` contains the + `sender` of the `m.room.create` event or any of the `additional_creators` + array (if present) from the `content` of the `m.room.create` event, reject. + 5. If there is no previous `m.room.power_levels` event in the room, + allow. + 6. For the properties `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. + 7. For each entry being changed in, or removed from, the `events` or + `notifications` properties: + 1. If the current value is greater than the `sender`'s current + power level, reject. + 8. For each entry being added to, or changed in, the `events` or + `notifications` properties: + 1. If the new value is greater than the `sender`'s current power + level, reject. + 9. For each entry being changed in, or removed from, the `users` property, + other than the `sender`'s own entry: + 1. If the current value is greater than or equal to the `sender`'s + current power level, reject. + 10. For each entry being added to, or changed in, the `users` property: + 1. If the new value is greater than the `sender`'s current power + level, reject. + 10. Otherwise, allow. +11. 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 %}} + +### State resolution + +{{% boxes/note %}} +{{% added-in v=12 %}} This state resolution algorithm is largely the same as the +algorithm found in [room version 2](/rooms/v2) with the following modifications: + +1. The *iterative auth checks algorithm* in the [Algorithm](#algorithm) subsection + now starts with an *empty* state map instead of the unconflicted state map. + +2. A new [definition](#definitions) for *conflicted state subgraph* has been added + which describes events that are required to authorize events during iterative + auth checks. + +3. To ensure the new conflicted state subgraph is actually referenced, the definition + for *full conflicted set* additionally includes the subgraph. +{{% /boxes/note %}} + +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 the `event_type` and `state_key` of *E* is + replaced by the `event_id` of *E*. + +The room state *S(E)* before *E* is the *resolution* of the set of +states {*S′(E*1*)*, *S′(E*2*)*, …} +after the `prev_event`s {*E*1, *E*2, …} of *E*. +The resolution of a set of states is given in the algorithm below. + +#### Definitions + +The state resolution algorithm for version 2 rooms uses the following +definitions, given the set of room states +{*S*1, *S*2, …}: + +**Power events.** +A *power event* is a state event with type `m.room.power_levels` or +`m.room.join_rules`, or a state event with type `m.room.member` where +the `membership` is `leave` or `ban` and the `sender` does not match the +`state_key`. The idea behind this is that power events are events that +might remove someone's ability to do something in the room. + +**Unconflicted state map and conflicted state set.** +The keys of the state maps *Si* are 2-tuples of strings of the form +*K* = `(event_type, state_key)`. The values *V* are state events. +The key-value pairs (*K*, *V*) across all state maps *Si* can be +divided into two collections. +If a given key *K* is present in every *Si* with the same value *V* +in each state map, then the pair (*K*, *V*) belongs to the *unconflicted state map*. +Otherwise, *V* belongs to the *conflicted state set*. + +Note that the unconflicted state map only has one event for each key *K*, +whereas the conflicted state set may contain multiple events with the same key. + +**Auth chain.** +The *auth chain* of an event *E* is the set containing all of *E*'s auth events, +all of *their* auth events, and so on recursively, stretching back to the +start of the room. Put differently, these are the events reachable by walking +the graph induced by an event's `auth_events` links. + +**Auth difference.** +The *auth difference* is calculated by first calculating the full auth +chain for each state *S**i*, that is the union of the auth +chains for each event in *S**i*, and then taking every event +that doesn't appear in every auth chain. If *C**i* is the +full auth chain of *S**i*, then the auth difference is +∪ *C**i* − ∩ *C**i*. + +{{% added-in v=12 %}} **Conflicted state subgraph.** +Starting from an event in the *conflicted state set* and following `auth_events` +edges may lead to another event in the conflicted state set. The union of all +such paths between any pair of events in the conflicted state set (including +endpoints) forms a subgraph of the original `auth_event` graph, called the +*conflicted state subgraph*. + +{{% changed-in v=12 %}} **Full conflicted set.** +The *full conflicted set* is the union of the conflicted state set, the conflicted +state subgraph, and the auth difference. + +**Reverse topological power ordering.** +The *reverse topological power ordering* of a set of events is the +lexicographically smallest topological ordering based on the DAG formed +by auth events. The reverse topological power ordering is ordered from +earliest event to latest. For comparing two topological orderings to +determine which is the lexicographically smallest, the following +comparison relation on events is used: for events *x* and *y*, +*x* < *y* if + +1. *x*'s sender has *greater* power level than *y*'s sender, when + looking at their respective `auth_event`s; or +2. the senders have the same power level, but *x*'s `origin_server_ts` + is *less* than *y*'s `origin_server_ts`; or +3. the senders have the same power level and the events have the same + `origin_server_ts`, but *x*'s `event_id` is *less* than *y*'s + `event_id`. + +The reverse topological power ordering can be found by sorting the +events using Kahn's algorithm for topological sorting, and at each step +selecting, among all the candidate vertices, the smallest vertex using +the above comparison relation. + +**Mainline ordering.** +Let *P* = *P*0 be an `m.room.power_levels` event. +Starting with *i* = 0, repeatedly fetch *P**i*+1, the +`m.room.power_levels` event in the `auth_events` of *Pi*. +Increment *i* and repeat until *Pi* has no `m.room.power_levels` +event in its `auth_events`. +The *mainline of P*0 is the list of events + [*P*0 , *P*1, ... , *Pn*], +fetched in this way. + +Let *e* = *e0* be another event (possibly another +`m.room.power_levels` event). We can compute a similar list of events + [*e*1, ..., *em*], +where *e**j*+1 is the `m.room.power_levels` event in the +`auth_events` of *ej* and where *em* has no +`m.room.power_levels` event in its `auth_events`. (Note that the event we +started with, *e0*, is not included in this list. Also note that it +may be empty, because *e* may not cite an `m.room.power_levels` event in its +`auth_events` at all.) + +Now compare these two lists as follows. +* Find the smallest index *j* ≥ 1 for which *ej* belongs to the + mainline of *P*. +* If such a *j* exists, then *ej* = *Pi* for some unique + index *i* ≥ 0. Otherwise set *i* = ∞, where ∞ is a sentinel value greater + than any integer. +* In both cases, the *mainline position* of *e* is *i*. + +Given mainline positions calculated from *P*, the *mainline ordering based on* *P* of a set of events is the ordering, +from smallest to largest, using the following comparison relation on +events: for events *x* and *y*, *x* < *y* if + +1. the mainline position of *x* is **greater** than + the mainline position of *y* (i.e. the auth chain of + *x* is based on an earlier event in the mainline than *y*); or +2. the mainline positions of the events are the same, but *x*'s + `origin_server_ts` is *less* than *y*'s `origin_server_ts`; or +3. the mainline positions of the events are the same and the events have the + same `origin_server_ts`, but *x*'s `event_id` is *less* than *y*'s + `event_id`. + +**Iterative auth checks.** +The *iterative auth checks algorithm* takes as input an initial room +state and a sorted list of state events, and constructs a new room state +by iterating through the event list and applying the state event to the +room state if the state event is allowed by the [authorization +rules](/server-server-api#authorization-rules). +If the state event is not allowed by the authorization rules, then the +event is ignored. If a `(event_type, state_key)` key that is required +for checking the authorization rules is not present in the state, then +the appropriate state event from the event's `auth_events` is used if +the auth event is not rejected. + +#### Algorithm + +The *resolution* of a set of states is obtained as follows: + +1. Select the set *X* of all *power events* that appear in the *full + conflicted set*. For each such power event *P*, enlarge *X* by adding + the events in the auth chain of *P* which also belong to the full + conflicted set. Sort *X* into a list using the *reverse topological + power ordering*. +2. {{% changed-in v=12 %}} Apply the *iterative auth checks algorithm*, + starting from an *empty* state map, to the list of events from the previous + step to get a partially resolved state. +3. Take all remaining events that weren't picked in step 1 and order + them by the mainline ordering based on the power level in the + partially resolved state obtained in step 2. +4. Apply the *iterative auth checks algorithm* on the partial resolved + state and the list of events from the previous step. +5. Update the result by replacing any event with the event with the + same key from the *unconflicted state map*, if such an event exists, + to get the final resolved state. + +#### Rejected events + +Events that have been rejected due to failing auth based on the state at +the event (rather than based on their auth chain) are handled as usual +by the algorithm, unless otherwise specified. + +Note that no events rejected due to failure to auth against their auth +chain should appear in the process, as they should not appear in state +(the algorithm only uses events that appear in either the state sets or +in the auth chain of the events in the state sets). + +{{% boxes/rationale %}} +This helps ensure that different servers' view of state is more likely +to converge, since rejection state of an event may be different. This +can happen if a third server gives an incorrect version of the state +when a server joins a room via it (either due to being faulty or +malicious). Convergence of state is a desirable property as it ensures +that all users in the room have a (mostly) consistent view of the state +of the room. If the view of the state on different servers diverges it +can lead to bifurcation of the room due to e.g. servers disagreeing on +who is in the room. + +Intuitively, using rejected events feels dangerous, however: + +1. Servers cannot arbitrarily make up state, since they still need to + pass the auth checks based on the event's auth chain (e.g. they + can't grant themselves power levels if they didn't have them + before). +2. For a previously rejected event to pass auth there must be a set of + state that allows said event. A malicious server could therefore + produce a fork where it claims the state is that particular set of + state, duplicate the rejected event to point to that fork, and send + the event. The duplicated event would then pass the auth checks. + Ignoring rejected events would therefore not eliminate any potential + attack vectors. +{{% /boxes/rationale %}} + +Rejected auth events are deliberately excluded from use in the iterative +auth checks, as auth events aren't re-authed (although non-auth events +are) during the iterative auth checks. + +## Unchanged from v11 + +The following sections have not been modified since v11, but are included for +completeness. + +### Redactions + +{{% rver-fragment name="v11-redactions" %}} + +### Handling redactions + +{{% rver-fragment name="v3-handling-redactions" %}} + +### Event IDs + +{{% rver-fragment name="v4-event-ids" %}} + +### Canonical JSON + +{{% rver-fragment name="v6-canonical-json" %}} + +### Signing key validity period + +{{% rver-fragment name="v5-signing-requirements" %}} diff --git a/content/rooms/v6.md b/content/rooms/v6.md index 2f728587..5c061073 100644 --- a/content/rooms/v6.md +++ b/content/rooms/v6.md @@ -102,10 +102,14 @@ The rules are as follows: specified by the [auth events selection](/server-server-api#auth-events-selection) algorithm described in the server specification, reject. + + **Note**: This room version requires an `m.room.create` event to be selected. 3. If there are entries which were themselves rejected under the [checks performed on receipt of a PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject. 4. If there is no `m.room.create` event among the entries, reject. + 5. If any event in `auth_events` has a `room_id` which does not match that of + the event being authorised, reject. 3. If the `content` of the `m.room.create` event in the room state has the property `m.federate` set to `false`, and the `sender` domain of the event does not match the `sender` domain of the create event, reject. diff --git a/content/rooms/v7.md b/content/rooms/v7.md index 34e2a8eb..100e1c74 100644 --- a/content/rooms/v7.md +++ b/content/rooms/v7.md @@ -81,10 +81,14 @@ The rules are as follows: specified by the [auth events selection](/server-server-api#auth-events-selection) algorithm described in the server specification, reject. + + **Note**: This room version requires an `m.room.create` event to be selected. 3. If there are entries which were themselves rejected under the [checks performed on receipt of a PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject. 4. If there is no `m.room.create` event among the entries, reject. + 5. If any event in `auth_events` has a `room_id` which does not match that of + the event being authorised, reject. 3. If the `content` of the `m.room.create` event in the room state has the property `m.federate` set to `false`, and the `sender` domain of the event does not match the `sender` domain of the create event, reject. diff --git a/content/server-server-api.md b/content/server-server-api.md index 2c52c0e3..e98d2e4c 100644 --- a/content/server-server-api.md +++ b/content/server-server-api.md @@ -119,7 +119,7 @@ to send. The process overall is as follows: server must present a valid certificate for the hostname. 3. If the hostname is not an IP literal, a regular HTTPS request is - made to `https:///.well-known/matrix/server` (according to + made to `https:///.well-known/matrix/server` (according to [RFC 8615](https://datatracker.ietf.org/doc/html/rfc8615)), expecting the schema defined later in this section. 30x redirects should be followed, however redirection loops should be avoided. Responses @@ -461,9 +461,12 @@ specification](/rooms). Whenever a server receives an event from a remote server, the receiving server must ensure that the event: -1. Is a valid event, otherwise it is dropped. For an event to be valid, it - must contain a `room_id`, and it must comply with the event format of - that [room version](/rooms). +1. {{% changed-in v="1.16" %}} Is a valid event, otherwise it is dropped. For + an event to be valid, it must comply with the event format of that [room version](/rooms). + For some room versions, a `room_id` may also be required on the event in order + to determine the room version to check the event against. See the event format + section of the [room version specifications](/rooms) for details on when it + is required. 2. Passes signature checks, otherwise it is dropped. 3. Passes hash checks, otherwise it is redacted before being processed further. @@ -529,7 +532,8 @@ the sender permission to send the event. The `auth_events` for the `m.room.create` event in a room is empty; for other events, it should be the following subset of the room state: -- The `m.room.create` event. +- {{% changed-in v="1.16" %}} Depending on the [room version](/rooms), the + `m.room.create` event. - The current `m.room.power_levels` event, if any. @@ -1050,7 +1054,7 @@ from the user owning the invited third-party identifier. ## Published Room Directory -To complement the [room directory in the Client-Server API](/client-server-api#published-room-directory), +To complement the [room directory in the Client-Server API](/client-server-api#published-room-directory), homeservers need a way to query the published rooms of another server. This can be done by making a request to the `/publicRooms` endpoint for the server the room directory should be retrieved for. diff --git a/data/api/client-server/create_room.yaml b/data/api/client-server/create_room.yaml index 339217c5..2f9d3449 100644 --- a/data/api/client-server/create_room.yaml +++ b/data/api/client-server/create_room.yaml @@ -33,9 +33,23 @@ paths: 2. An `m.room.member` event for the creator to join the room. This is needed so the remaining events can be sent. - 3. A default `m.room.power_levels` event, giving the room creator - (and not other members) permission to send state events. Overridden - by the `power_level_content_override` parameter. + 3. A default `m.room.power_levels` event. Overridden by the + `power_level_content_override` parameter. + + In [room versions](/rooms) 1 through 11, the room creator (and not + other members) will be given permission to send state events. + + In room versions 12 and later, the room creator is given infinite + power level and cannot be specified in the `users` field of + `m.room.power_levels`, so is not listed explicitly. + + **Note**: For `trusted_private_chat`, the users specified in the + `invite` parameter SHOULD also be appended to `additional_creators` + by the server, per the `creation_content` parameter. + + If the room's version is 12 or higher, the power level for sending + `m.room.tombstone` events MUST explicitly be higher than `state_default`. + For example, set to 150 instead of 100. 4. An `m.room.canonical_alias` event if `room_alias_name` is given. @@ -61,8 +75,10 @@ paths: The server will create a `m.room.create` event in the room with the requesting user as the creator, alongside other keys provided in the - `creation_content`. + `creation_content` or implied by behaviour of `creation_content`. operationId: createRoom + x-changedInMatrixVersion: + "1.16": Added server behaviour for how the initial power levels change depending on room version. security: - accessTokenQuery: [] - accessTokenBearer: [] @@ -142,11 +158,20 @@ paths: creation_content: title: CreationContent type: object + x-changedInMatrixVersion: + "1.16": Added server behaviour for how to handle `trusted_private_chat` and invited users. description: |- Extra keys, such as `m.federate`, to be added to the content - of the [`m.room.create`](/client-server-api/#mroomcreate) event. The server will overwrite the following + of the [`m.room.create`](/client-server-api/#mroomcreate) event. + + The server will overwrite the following keys: `creator`, `room_version`. Future versions of the specification may allow the server to overwrite other keys. + + When using the `trusted_private_chat` preset, the server SHOULD combine + `additional_creators` specified here and the `invite` array into the + eventual `m.room.create` event's `additional_creators`, deduplicating + between the two parameters. initial_state: type: array description: |- @@ -225,7 +250,7 @@ paths: } "400": description: |- - + The request is invalid. A meaningful `errcode` and description error text will be returned. Example reasons for rejection include: diff --git a/data/api/client-server/room_upgrades.yaml b/data/api/client-server/room_upgrades.yaml index 5109a9b7..7e3ceff9 100644 --- a/data/api/client-server/room_upgrades.yaml +++ b/data/api/client-server/room_upgrades.yaml @@ -41,6 +41,23 @@ paths: new_version: type: string description: The new version for the room. + additional_creators: + type: array + items: + type: string + description: Additional user ID to consider a room creator, if the room version supports it. + x-addedInMatrixVersion: "1.16" + description: |- + When upgrading to a [room version](/rooms) which supports additional creators, + the [user IDs](/appendices#user-identifiers) which should be considered room + creators in addition to the user performing the upgrade. + + If the room being upgraded has additional creators, they are *not* automatically + copied to the new room. The full set of additional creators needs to be set to + retain (or add/remove) more room creators. + + When upgrading to a room version which doesn't support additional creators, this + field is ignored and has no effect during the upgrade process. example: { "new_version": "2" } diff --git a/data/api/server-server/definitions/components/depth_v6.yaml b/data/api/server-server/definitions/components/depth_v6.yaml new file mode 100644 index 00000000..e8ef28c1 --- /dev/null +++ b/data/api/server-server/definitions/components/depth_v6.yaml @@ -0,0 +1,25 @@ +# Copyright 2025 The Matrix.org Foundation C.I.C. +# +# 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 +description: |- + The depth field of PDUs for room version 6 and beyond. +properties: + # v6 enforces Canonical JSON and therefore needs a depth limit change + depth: + type: integer + description: |- + The maximum depth of the `prev_events`, plus one. Must be less than the + maximum value for an integer (2^53 - 1). If the room's depth is already at + the limit, the depth must be set to the limit. + example: 12 \ No newline at end of file diff --git a/data/api/server-server/definitions/components/pdu_base.yaml b/data/api/server-server/definitions/components/pdu_base.yaml index be275611..0bb3a34c 100644 --- a/data/api/server-server/definitions/components/pdu_base.yaml +++ b/data/api/server-server/definitions/components/pdu_base.yaml @@ -14,10 +14,6 @@ type: object description: Common fields for all PDU versions properties: - room_id: - type: string - description: Room identifier. - example: "!abc123:matrix.org" sender: type: string description: The ID of the user sending the event. @@ -69,7 +65,6 @@ properties: description: The number of milliseconds that have passed since this message was sent. example: 4612 required: - - room_id - sender - origin_server_ts - type diff --git a/data/api/server-server/definitions/components/room_id_before_v12.yaml b/data/api/server-server/definitions/components/room_id_before_v12.yaml new file mode 100644 index 00000000..d51adb12 --- /dev/null +++ b/data/api/server-server/definitions/components/room_id_before_v12.yaml @@ -0,0 +1,23 @@ +# Copyright 2025 The Matrix.org Foundation C.I.C. +# +# 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 +description: |- + The room_id field of PDUs for room version 11 and prior. +properties: + room_id: + type: string + description: Room identifier. + example: "!abc123:matrix.org" +required: + - room_id diff --git a/data/api/server-server/definitions/components/room_id_v12.yaml b/data/api/server-server/definitions/components/room_id_v12.yaml new file mode 100644 index 00000000..5ad69800 --- /dev/null +++ b/data/api/server-server/definitions/components/room_id_v12.yaml @@ -0,0 +1,23 @@ +# Copyright 2025 The Matrix.org Foundation C.I.C. +# +# 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 +description: |- + The room_id field of PDUs for room version 12 and beyond. +properties: + room_id: + type: string + description: Room identifier. Omitted from `m.room.create` events. + example: "!Nhcu5BS-UMnFX7hBVfVSoXiD7OgH6iRT-xyIuqDnpYQ" +required: + - room_id diff --git a/data/api/server-server/definitions/pdu_v1.yaml b/data/api/server-server/definitions/pdu_v1.yaml index d2fb2ef9..7936b629 100644 --- a/data/api/server-server/definitions/pdu_v1.yaml +++ b/data/api/server-server/definitions/pdu_v1.yaml @@ -18,6 +18,7 @@ example: $ref: "../examples/pdu_v1.json" allOf: - $ref: "components/pdu_base.yaml" + - $ref: "components/room_id_before_v12.yaml" - type: object properties: event_id: diff --git a/data/api/server-server/definitions/pdu_v11.yaml b/data/api/server-server/definitions/pdu_v11.yaml index 409b99c6..172d0c1e 100644 --- a/data/api/server-server/definitions/pdu_v11.yaml +++ b/data/api/server-server/definitions/pdu_v11.yaml @@ -13,20 +13,12 @@ # limitations under the License. type: object title: Persistent Data Unit -description: A persistent data unit (event) for room version 11 and beyond. +description: A persistent data unit (event) for room version 11. example: $ref: "../examples/pdu_v11.json" allOf: # v11 is the v6 event, but without redacts. - $ref: "components/pdu_base.yaml" - $ref: "components/auth_events_prev_events_v4.yaml" - - type: object - properties: - # v6 enforces Canonical JSON and therefore needs a depth limit change - depth: - type: integer - description: |- - The maximum depth of the `prev_events`, plus one. Must be less than the - maximum value for an integer (2^53 - 1). If the room's depth is already at - the limit, the depth must be set to the limit. - example: 12 \ No newline at end of file + - $ref: "components/room_id_before_v12.yaml" + - $ref: "components/depth_v6.yaml" diff --git a/data/api/server-server/definitions/pdu_v12.yaml b/data/api/server-server/definitions/pdu_v12.yaml new file mode 100644 index 00000000..51cbe5a2 --- /dev/null +++ b/data/api/server-server/definitions/pdu_v12.yaml @@ -0,0 +1,24 @@ +# Copyright 2025 The Matrix.org Foundation C.I.C. +# +# 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 12 and beyond. +example: + $ref: "../examples/pdu_v12.json" +allOf: + # v12 is the v11 event, but with special room ID requirements. + - $ref: "components/pdu_base.yaml" + - $ref: "components/auth_events_prev_events_v4.yaml" + - $ref: "components/depth_v6.yaml" + - $ref: "components/room_id_v12.yaml" # this is the v12 change \ No newline at end of file diff --git a/data/api/server-server/definitions/pdu_v3.yaml b/data/api/server-server/definitions/pdu_v3.yaml index ccca717b..44402bea 100644 --- a/data/api/server-server/definitions/pdu_v3.yaml +++ b/data/api/server-server/definitions/pdu_v3.yaml @@ -18,6 +18,7 @@ example: $ref: "../examples/pdu_v3.json" allOf: - $ref: "components/pdu_base.yaml" + - $ref: "components/room_id_before_v12.yaml" - type: object properties: redacts: diff --git a/data/api/server-server/definitions/pdu_v4.yaml b/data/api/server-server/definitions/pdu_v4.yaml index 2edf1b31..1fc8c9b2 100644 --- a/data/api/server-server/definitions/pdu_v4.yaml +++ b/data/api/server-server/definitions/pdu_v4.yaml @@ -20,6 +20,7 @@ example: allOf: - $ref: "components/pdu_base.yaml" - $ref: "components/auth_events_prev_events_v4.yaml" + - $ref: "components/room_id_before_v12.yaml" - type: object properties: redacts: diff --git a/data/api/server-server/definitions/pdu_v6.yaml b/data/api/server-server/definitions/pdu_v6.yaml index 1278a6e3..0ea83b50 100644 --- a/data/api/server-server/definitions/pdu_v6.yaml +++ b/data/api/server-server/definitions/pdu_v6.yaml @@ -20,17 +20,11 @@ example: allOf: - $ref: "components/pdu_base.yaml" - $ref: "components/auth_events_prev_events_v4.yaml" + - $ref: "components/room_id_before_v12.yaml" + - $ref: "components/depth_v6.yaml" - type: object properties: redacts: type: string description: For redaction events, the ID of the event being redacted. example: "$def_456-oldevent" - # v6 enforces Canonical JSON and therefore needs a depth limit change - depth: - type: integer - description: |- - The maximum depth of the `prev_events`, plus one. Must be less than the - maximum value for an integer (2^53 - 1). If the room's depth is already at - the limit, the depth must be set to the limit. - example: 12 diff --git a/data/api/server-server/examples/pdu_v12.json b/data/api/server-server/examples/pdu_v12.json new file mode 100644 index 00000000..9d7120e3 --- /dev/null +++ b/data/api/server-server/examples/pdu_v12.json @@ -0,0 +1,9 @@ +{ + "allOf": [ + { "$ref": "components/pdu_base.json" }, + { "$ref": "components/auth_events_prev_events_v4.json" }, + { + "room_id": "!Nhcu5BS-UMnFX7hBVfVSoXiD7OgH6iRT-xyIuqDnpYQ" + } + ] +} diff --git a/data/event-schemas/schema/m.room.create.yaml b/data/event-schemas/schema/m.room.create.yaml index 19b2bae4..2db5fd57 100644 --- a/data/event-schemas/schema/m.room.create.yaml +++ b/data/event-schemas/schema/m.room.create.yaml @@ -33,8 +33,36 @@ properties: description: The ID of the old room. event_id: type: string - description: The event ID of the last known event in the old room. - required: [room_id, event_id] + deprecated: true + x-changedInMatrixVersion: + "1.16": |- + This field became deprecated and may not be present in all cases. It SHOULD still + be populated where possible/practical. Previously, it was required. + description: |- + The event ID of the last known event in the old room, if known. + + If not set, clients SHOULD search for the `m.room.tombstone` state event to navigate to + when directing the user to the old room (potentially after joining the room, if requested + by the user). + required: [room_id] + additional_creators: + type: array + items: + type: string + description: Additional user ID to consider a creator of the room, if supported by the room version. + x-addedInMatrixVersion: "1.16" + description: |- + Starting with room version 12, the other user IDs to consider as creators for the room in + addition to the `sender` of this event. Each string MUST be a valid [user ID](/appendices#user-identifiers) + for the room version. + + When not present or empty, the `sender` of the event is the only creator. + + In room versions 1 through 11, this field serves no purpose and is not validated. Clients + SHOULD NOT attempt to parse or understand this field in these room versions. + + **Note**: Because `creator` was removed in room version 11, the field is not used to determine + which user(s) are room creators in room version 12 and beyond either. type: object state_key: description: A zero-length string. diff --git a/data/event-schemas/schema/m.room.power_levels.yaml b/data/event-schemas/schema/m.room.power_levels.yaml index 858c5274..9c9cf6fd 100644 --- a/data/event-schemas/schema/m.room.power_levels.yaml +++ b/data/event-schemas/schema/m.room.power_levels.yaml @@ -44,7 +44,15 @@ properties: events: additionalProperties: type: integer - description: The level required to send specific event types. This is a mapping from event type to power level required. + description: |- + The level required to send specific event types. This is a mapping from event type to power level required. + + Though not a default, when the server sends the initial power levels event during [room creation](/client-server-api#creation) + in [room versions](/rooms) 12 and higher, the `m.room.tombstone` event MUST be explicitly defined and given + a power level higher than `state_default`. For example, power level 150. Clients may override this using the + described `power_level_content_override` field. + x-changedInMatrixVersion: + "1.16": Described `m.room.tombstone` defaults during creation of a room version 12 or higher room. title: Event power levels type: object events_default: @@ -71,16 +79,28 @@ properties: "^@": x-pattern-format: mx-user-id type: integer - description: The power levels for specific users. This is a mapping from `user_id` to power level for that user. + description: |- + The power levels for specific users. This is a mapping from `user_id` to power level for that user. + + **Note**: In [room versions](/rooms) 12 and higher it is not permitted to specify the room creators here. + x-changedInMatrixVersion: + "1.16": Added a note that room creators cannot be specified here in room versions 12 and higher. title: User power levels type: object users_default: + x-changedInMatrixVersion: + "1.16": The room creator power level now changes depending on room version. description: |- The power level for users in the room whose `user_id` is not mentioned in the `users` key. Defaults to 0 if unspecified. - **Note**: When there is no `m.room.power_levels` event in the room, the room creator has - a power level of 100, and all other users have a power level of 0. + **Note**: In [room versions](/rooms) 1 through 11, when there is no `m.room.power_levels` + event in the room, the room creator has a power level of 100, and all other users have a + power level of 0. + + **Note**: In room versions 12 and higher, room creators have infinite power level regardless + of the existence of `m.room.power_levels` in the room. When `m.room.power_levels` is not + in the room however, all other users have a power level of 0. type: integer notifications: properties: