From 059f324e7bf6197276c68f7be2ef1bc409a39e80 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 7 Jan 2021 16:22:13 +0000 Subject: [PATCH 01/77] Spaces Summary --- proposals/0-spaces-summary.md | 182 ++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 proposals/0-spaces-summary.md diff --git a/proposals/0-spaces-summary.md b/proposals/0-spaces-summary.md new file mode 100644 index 00000000000..23243bf5c05 --- /dev/null +++ b/proposals/0-spaces-summary.md @@ -0,0 +1,182 @@ +### Spaces Summary API + +*This MSC depends on [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772).* + +Spaces are rooms with `m.space` as the [room type](https://github.com/matrix-org/matrix-doc/pull/1840). +Spaces can include state events to specify parent/child relationships. +These relationships point to other rooms, which may themselves be spaces. +This means spaces can have subspaces and rooms. This creates a graph: a space directory. + +This MSC defines a new endpoint which can be used to reveal information about the space directory. + +Consider the graph: +``` + A + ^ + |___ + | | + V V + B R1 + ^ + | + V + R2 + +R1,R2 = rooms +A,B = spaces +<--> = parent/child relationship events +``` +This MSC aims to create a way for clients to produce a tree view along the lines of: +``` +Space A + | + |___ Room 1 + | + Space B + | + |___ Room 2 +``` +Clients are able to do this currently by peeking into all of these rooms +(assuming they have permission to) but this is costly and slow. + +#### Client API + +``` +POST /_matrix/client/r0/rooms/{roomID}/spaces +{ + "max_rooms_per_space": 5, // The maximum number of rooms to return for a given space + "limit": 100, // The maximum number of rooms/subspaces to return, server can override this, default: 100. + "batch": "opaque_string" // A token to use if this is a subsequent HTTP hit, default: "". +} +``` + +which returns: + +``` +{ + "next_batch": "opaque string", + "rooms": [ + { + "aliases": [ + "#murrays:cheese.bar" + ], + "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE", + "guest_can_join": false, + "name": "CHEESE", + "num_joined_members": 37, + "room_id": "!ol19s:bleecker.street", + "topic": "Tasty tasty cheese", + "world_readable": true, + + "num_refs": 42 + }, + { ... } + ], + "events": [ + { + "type": "m.space.child", + "state_key": "!efgh:example.com", + "content": { + "via": ["example.com"], + "present": true, + "order": "abcd", + "default": true + } + }, + { + "type": "m.room.parent", + "state_key": "", + "content": { + "room_id": "!space:example.com", + "via": ["example.com"] + } + } + ] +} +``` + +Justifications for the request API shape are as follows: + - The HTTP path: Spaces are scoped to a specific room to act as an anchor point for + navigating the directory. Alternatives are `/r0/spaces` with `room_id` inside the + body, but this feels less idiomatic for room-scoped requests. + - The HTTP method: there's a lot of data to provide to the server, and GET requests + shouldn't have an HTTP body, hence opting for POST. The same request can produce + different results over time so PUT isn't acceptable as an alternative. + - `max_rooms_per_space`: UIs can only display a set number of rooms per space, so allowing + clients to specify this limit is desirable. Subsequent rooms can be obtained by paginating. + The graph has 2 distinct types of nodes, and some UIs may want to weight one type above + the other. However, it's impossible to always know what type of node a given room ID falls + under because the server may not be joined to that room (to determine the room type) or the + caller may not have permission to see this information. + - `limit`: The maximum number of events to return in `events`. It is desirable for clients + and servers to be able to put a maximum cap on the amount of data returned to the client. + **This limit may be exceeded if the root room has `> limit` rooms.** + - `batch`: Required for pagination. Could be a query parameter but it's easier if + request data is in one place. + +Justifications for the response API shape are as follows: + - `rooms`: These are the nodes of the graph. The objects in the array are exactly the same as `PublicRoomsChunk` in the + [specification](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms) + as the information displayed to users is the same. There is one _additional_ key + which is `num_refs` which is the total number state events which point to or from this room. This + includes all `m.space.child` events in the room, _in addition to_ `m.room.parent` events which point to + this room as a parent. + - `events`: These are the edges of the graph. The objects in the array are complete (or stripped?) `m.room.parent` + or `m.space.child` events. + - `next_batch`: Its presence indicates that there are more results to return. + +Server behaviour: + - Extract the room ID from the request. Sanity check request data. Begin walking the graph + starting with the room ID in the request in a queue of unvisited rooms according to the + following rules: + * If this room has already been processed, skip. NB: do not remember this between calls, + as servers will need to visit the same room more than once to return additional events. + * Is the caller currently joined to the room or is the room `world_readable`? + If no, skip this room. If yes, continue. + * If this room has not ever been in `rooms` (across multiple requests), extract the + `PublicRoomsChunk` for this room. + * Get all `m.space.child` and `m.room.parent` state events for the room. *In addition*, get + all `m.space.child` and `m.room.parent` state events which *point to* (via `state_key` or `content.room_id`) + this room. This requires servers to store reverse lookups. Add the total number of events + to `PublicRoomsChunk` under `num_refs`. Add `PublicRoomsChunk` to `rooms`. + * If this is the root room from the original request, insert all these events into `events` if + they haven't been added before (across multiple requests). + * Else add them to `events` honouring the `limit` and `max_rooms_per_space` values. If either + are exceeded, stop adding events. If the event has already been added, do not add it again. + * Mark this room as processed. + * For each referenced room ID in the events being returned to the caller (both parent and child) + add the room ID to the queue of unvisited rooms. Loop from the beginning. + - This guarantees that all edges for the root node are given to the client. Not all edges of subspaces + will be returned, nor will edges of all rooms be returned. This can be detected by clients in two ways: + * Comparing `num_refs` with the *total number* of edges pointing to/from the room. + * Comparing the number of `m.space.child` state events in the room with `max_rooms_per_space`, where + `max_rooms_per_space` is 1 greater than the actual desired maximum value. + - If not all events were returned due to reaching a `limit` or `max_rooms_per_space`, return a + `next_batch` token. The server SHOULD NOT return duplicate events or rooms on subsequent + requests: this can be achieved by remembering the event/room IDs returned to the caller between calls. + This results in each request uncovering more nodes/edges until the entire tree has been explored. + + +Client behaviour: + - Decide which room should be the root of the tree, then call this endpoint with the root room ID. + - The data in `rooms` determines _what_ to show. The events in `events` determine _where_ to show it. + Take all the data in `rooms` and key them by room ID. + - Loop through the `events` and keep track of parent->child relationships by looking at the `room_id` + of the event and the `state_key` which is the child room ID. Clients may want to treat + child->parent relationships (`m.room.parent` events) the same way or differently. Treating them the + same way will guarantee that the entire graph is exposed on the UI, but can cause issues because it + can result in multiple roots (a child can refer to a new unknown parent). If a child->parent relationship + exists but a corresponding parent->child relationship does not exist, this room is a "secret" room which + should be indicated as such. If a parent->child relationship exists but a corresponding child->parent + relationship does not exist, this room is a "user-curated collection" and should be indicated as such. + Persist the mappings in a map: one child can have multiple parents and one parent can have multiple + children. + - Starting at the root room ID: + * Compare the `num_refs` value in `rooms.$room_id` to the total number of events which reference this + room in `events` (across all rooms). If they differ, a partial response has been returned for this + space and additional results should be loaded when required. The API guarantees that *all* events for + the root room ID will be returned, regardless of how many events there are (even if they exceed `limit`). + * Lookup all children for this room ID. For each child: + - If the child is a room (not a space), look up the room data from `rooms` and render it. + - Else the child is a space, render the space as a heading (using the room name/topic) and + restart the lookup using the new space room ID. \ No newline at end of file From 14eb56c8016a458e2e0f88bca85d086847edf800 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 7 Jan 2021 16:23:07 +0000 Subject: [PATCH 02/77] MSC2946 --- proposals/{0-spaces-summary.md => 2946-spaces-summary.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename proposals/{0-spaces-summary.md => 2946-spaces-summary.md} (100%) diff --git a/proposals/0-spaces-summary.md b/proposals/2946-spaces-summary.md similarity index 100% rename from proposals/0-spaces-summary.md rename to proposals/2946-spaces-summary.md From aea5336eb37fc6b46eacf7b3322828d3431fa194 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 7 Jan 2021 16:35:49 +0000 Subject: [PATCH 03/77] Clarity --- proposals/2946-spaces-summary.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 23243bf5c05..59aa8a25c2f 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -44,7 +44,7 @@ Clients are able to do this currently by peeking into all of these rooms ``` POST /_matrix/client/r0/rooms/{roomID}/spaces { - "max_rooms_per_space": 5, // The maximum number of rooms to return for a given space + "max_rooms_per_space": 5, // The maximum number of rooms/subspaces to return for a given space, if negative unbounded. default: -1. "limit": 100, // The maximum number of rooms/subspaces to return, server can override this, default: 100. "batch": "opaque_string" // A token to use if this is a subsequent HTTP hit, default: "". } @@ -68,7 +68,8 @@ which returns: "topic": "Tasty tasty cheese", "world_readable": true, - "num_refs": 42 + "num_refs": 42, + "room_type": "m.space" }, { ... } ], @@ -117,10 +118,13 @@ Justifications for the request API shape are as follows: Justifications for the response API shape are as follows: - `rooms`: These are the nodes of the graph. The objects in the array are exactly the same as `PublicRoomsChunk` in the [specification](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms) - as the information displayed to users is the same. There is one _additional_ key - which is `num_refs` which is the total number state events which point to or from this room. This - includes all `m.space.child` events in the room, _in addition to_ `m.room.parent` events which point to - this room as a parent. + as the information displayed to users is the same. There are two _additional_ keys + which are: + * `num_refs` which is the total number of state events which point to or from this room (inbound/outbound edges). + This includes all `m.space.child` events in the room, _in addition to_ `m.room.parent` events which point to + this room as a parent. + * `room_type` which is the room type, which is `m.space` for subspaces. It can be omitted if there is no room type + in which case it should be interpreted as a normal room. - `events`: These are the edges of the graph. The objects in the array are complete (or stripped?) `m.room.parent` or `m.space.child` events. - `next_batch`: Its presence indicates that there are more results to return. From 7618ed6f98d0ecadf7b8ba72e4ce6486706a4c74 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 7 Jan 2021 16:37:00 +0000 Subject: [PATCH 04/77] More clarity --- proposals/2946-spaces-summary.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 59aa8a25c2f..1b868c91a07 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -181,6 +181,7 @@ Client behaviour: space and additional results should be loaded when required. The API guarantees that *all* events for the root room ID will be returned, regardless of how many events there are (even if they exceed `limit`). * Lookup all children for this room ID. For each child: - - If the child is a room (not a space), look up the room data from `rooms` and render it. + - If the child is a room (not a space, check the `room_type` field), look up the room data from + `rooms` and render it. - Else the child is a space, render the space as a heading (using the room name/topic) and restart the lookup using the new space room ID. \ No newline at end of file From 6e051d5f1e92c3c1ecfae8b95bf5a6fcffdeb559 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 7 Jan 2021 16:48:54 +0000 Subject: [PATCH 05/77] Clarify what no room data means for clients --- proposals/2946-spaces-summary.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 1b868c91a07..eb7d45f2c8d 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -181,6 +181,9 @@ Client behaviour: space and additional results should be loaded when required. The API guarantees that *all* events for the root room ID will be returned, regardless of how many events there are (even if they exceed `limit`). * Lookup all children for this room ID. For each child: + - If there is no corresponding room data for this room ID then this room is either a subspace or a room. + The room is not world readable or the server does not have any information about this room. Clients + MAY be able to join this room by issuing a `/join` request. - If the child is a room (not a space, check the `room_type` field), look up the room data from `rooms` and render it. - Else the child is a space, render the space as a heading (using the room name/topic) and From 619c100cb95be1cabcc8d08c8d04c887d80e5fcd Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 13 Jan 2021 17:47:33 +0000 Subject: [PATCH 06/77] Federation API --- proposals/2946-spaces-summary.md | 46 ++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index eb7d45f2c8d..317e5bfbe0f 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -135,6 +135,7 @@ Server behaviour: following rules: * If this room has already been processed, skip. NB: do not remember this between calls, as servers will need to visit the same room more than once to return additional events. + * Mark this room as processed. * Is the caller currently joined to the room or is the room `world_readable`? If no, skip this room. If yes, continue. * If this room has not ever been in `rooms` (across multiple requests), extract the @@ -147,7 +148,6 @@ Server behaviour: they haven't been added before (across multiple requests). * Else add them to `events` honouring the `limit` and `max_rooms_per_space` values. If either are exceeded, stop adding events. If the event has already been added, do not add it again. - * Mark this room as processed. * For each referenced room ID in the events being returned to the caller (both parent and child) add the room ID to the queue of unvisited rooms. Loop from the beginning. - This guarantees that all edges for the root node are given to the client. Not all edges of subspaces @@ -187,4 +187,46 @@ Client behaviour: - If the child is a room (not a space, check the `room_type` field), look up the room data from `rooms` and render it. - Else the child is a space, render the space as a heading (using the room name/topic) and - restart the lookup using the new space room ID. \ No newline at end of file + restart the lookup using the new space room ID. + +#### Federation API + +Servers may not be joined to all subspaces in the graph. If this happens, they will lack the room state to form a response. +Servers may get this information by peeking into the room, but this includes a live stream of events which is unecessary and +is a single request per room in the graph. It would be preferable if there was a federation endpoint which included this +information and nothing more. This is more performant and is a single request per _server_ (which may have many nodes +of the graph). Effectively, this federation API requests the view of the graph from the point of view of the destination +server. + +``` +POST /_matrix/federation/v1/spaces/{roomID} +{ + "exclude_rooms": ["!a:b", "!b:c"] // Optional. Do not return state events in these rooms, nor include these rooms in `rooms`. + "max_rooms_per_space": 5, // The maximum number of rooms/subspaces to return for a given space, if negative unbounded. default: -1. + "limit": 100, // The maximum number of rooms/subspaces to return, server can override this, default: 100. + "batch": "opaque_string" // A token to use if this is a subsequent HTTP hit, default: "". +} +``` + +Justifications for the request API shape are the same as before with one exception: + - The HTTP path: Per-room federation endpoints are not put under `/rooms` so this proposal doesn't either. + - The `exclude_rooms` parameter: In order to stop redundant information being sent to the server, this field allows requesting + servers the ability to suppress node/edge information on a per-room basis. If a room ID is present in this list, + the server should not return node information under `rooms` nor should it return _any state events in this room_. NB: state + events which _point to_ this room should still be included. + +The response body remains unchanged from the client format. + +Sending server behaviour: + - When walking the spaces graph, if the server is not joined to a given room, remember the `via` server names and the room ID. + - Send a federated request to a server in `via` for the unknown room, marking rooms the server is already joined to + in `exclude_rooms`. + - Servers MAY eagerly request graph information and SHOULD cache the response for a configurable duration. This proposal recommends + 1 hour. + +Receiving server behaviour: + - Validate the request and check sender signatures. + - Walk the graph in the same way as the CS API endpoint, remembering to exclude rooms in `exclude_rooms`. "Exclude" in this + context merely means do not add the room or state events in that room to the response. The room itself MUST still be walked + so servers can extract transitive rooms e.g `A -> B -> C` and the requesting server requests `room_id: A, exclude_rooms: [B]` + must return `C`. From 104cf780c315415dc75cee0e2d00687f613ea538 Mon Sep 17 00:00:00 2001 From: Kegsay Date: Wed, 13 Jan 2021 17:49:56 +0000 Subject: [PATCH 07/77] Update 2946-spaces-summary.md --- proposals/2946-spaces-summary.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 317e5bfbe0f..2021b0db28f 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -1,4 +1,4 @@ -### Spaces Summary API +## Spaces Summary API *This MSC depends on [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772).* @@ -39,7 +39,7 @@ Space A Clients are able to do this currently by peeking into all of these rooms (assuming they have permission to) but this is costly and slow. -#### Client API +### Client API ``` POST /_matrix/client/r0/rooms/{roomID}/spaces @@ -189,7 +189,9 @@ Client behaviour: - Else the child is a space, render the space as a heading (using the room name/topic) and restart the lookup using the new space room ID. -#### Federation API + +### Federation API + Servers may not be joined to all subspaces in the graph. If this happens, they will lack the room state to form a response. Servers may get this information by peeking into the room, but this includes a live stream of events which is unecessary and From 8f6fb9d8484afce76aaa826ed06b0e174575d73d Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 13 Jan 2021 17:55:45 +0000 Subject: [PATCH 08/77] auto_join filter --- proposals/2946-spaces-summary.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 2021b0db28f..9b91afa062b 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -45,6 +45,7 @@ Clients are able to do this currently by peeking into all of these rooms POST /_matrix/client/r0/rooms/{roomID}/spaces { "max_rooms_per_space": 5, // The maximum number of rooms/subspaces to return for a given space, if negative unbounded. default: -1. + "auto_join_only": true, // If true, only return m.space.child events with auto_join:true, default: false, which returns all events. "limit": 100, // The maximum number of rooms/subspaces to return, server can override this, default: 100. "batch": "opaque_string" // A token to use if this is a subsequent HTTP hit, default: "". } @@ -81,7 +82,7 @@ which returns: "via": ["example.com"], "present": true, "order": "abcd", - "default": true + "auto_join": true } }, { @@ -112,6 +113,11 @@ Justifications for the request API shape are as follows: - `limit`: The maximum number of events to return in `events`. It is desirable for clients and servers to be able to put a maximum cap on the amount of data returned to the client. **This limit may be exceeded if the root room has `> limit` rooms.** + - `auto_join_only`: If `true`, only a subset of the graph is returned based on the presence + of `auto_join: true` in the `content` field of `m.space.child`. Some clients may only + care about the "main" or "default" rooms, which are rooms with this flag set. This does + not affect parent state events: they are still returned. This does not modify the value + of `num_refs`. - `batch`: Required for pagination. Could be a query parameter but it's easier if request data is in one place. From 200147c62a0c66f187836c3bf085ae5b6da162df Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 13 Jan 2021 17:59:37 +0000 Subject: [PATCH 09/77] Blurb on auth for fed api --- proposals/2946-spaces-summary.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 9b91afa062b..2c35834a49e 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -238,3 +238,6 @@ Receiving server behaviour: context merely means do not add the room or state events in that room to the response. The room itself MUST still be walked so servers can extract transitive rooms e.g `A -> B -> C` and the requesting server requests `room_id: A, exclude_rooms: [B]` must return `C`. + - Servers are authorised to see node/edge information if they are either joined to the room or the room is `world_readable`. + A well-behaved server will not send requests for rooms they are already joined to, so they should only be shown `world_readable` + rooms. From f2457cfa786019e6a5c041f8fe48b582b178fcdd Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 15 Jan 2021 12:40:34 +0000 Subject: [PATCH 10/77] Update to reflect MSC1772 changes --- proposals/2946-spaces-summary.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 2c35834a49e..e396ab00b3b 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -86,10 +86,9 @@ which returns: } }, { - "type": "m.room.parent", - "state_key": "", + "type": "m.space.parent", + "state_key": "!space:example.com", "content": { - "room_id": "!space:example.com", "via": ["example.com"] } } @@ -127,11 +126,11 @@ Justifications for the response API shape are as follows: as the information displayed to users is the same. There are two _additional_ keys which are: * `num_refs` which is the total number of state events which point to or from this room (inbound/outbound edges). - This includes all `m.space.child` events in the room, _in addition to_ `m.room.parent` events which point to + This includes all `m.space.child` events in the room, _in addition to_ `m.space.parent` events which point to this room as a parent. * `room_type` which is the room type, which is `m.space` for subspaces. It can be omitted if there is no room type in which case it should be interpreted as a normal room. - - `events`: These are the edges of the graph. The objects in the array are complete (or stripped?) `m.room.parent` + - `events`: These are the edges of the graph. The objects in the array are complete (or stripped?) `m.space.parent` or `m.space.child` events. - `next_batch`: Its presence indicates that there are more results to return. @@ -146,10 +145,13 @@ Server behaviour: If no, skip this room. If yes, continue. * If this room has not ever been in `rooms` (across multiple requests), extract the `PublicRoomsChunk` for this room. - * Get all `m.space.child` and `m.room.parent` state events for the room. *In addition*, get - all `m.space.child` and `m.room.parent` state events which *point to* (via `state_key` or `content.room_id`) + * Get all `m.space.child` and `m.space.parent` state events for the room. *In addition*, get + all `m.space.child` and `m.space.parent` state events which *point to* (via `state_key`) this room. This requires servers to store reverse lookups. Add the total number of events to `PublicRoomsChunk` under `num_refs`. Add `PublicRoomsChunk` to `rooms`. + Do NOT include state events which are missing the `content.via` field, as this indicates + a redacted link. These events do not contribute to `num_refs` and should not be returned + to the caller. * If this is the root room from the original request, insert all these events into `events` if they haven't been added before (across multiple requests). * Else add them to `events` honouring the `limit` and `max_rooms_per_space` values. If either @@ -171,9 +173,9 @@ Client behaviour: - Decide which room should be the root of the tree, then call this endpoint with the root room ID. - The data in `rooms` determines _what_ to show. The events in `events` determine _where_ to show it. Take all the data in `rooms` and key them by room ID. - - Loop through the `events` and keep track of parent->child relationships by looking at the `room_id` - of the event and the `state_key` which is the child room ID. Clients may want to treat - child->parent relationships (`m.room.parent` events) the same way or differently. Treating them the + - Loop through the `events` and keep track of parent->child relationships by looking at the `state_key` + which is the child room ID. Clients may want to treat child->parent relationships + (`m.space.parent` events) the same way or differently. Treating them the same way will guarantee that the entire graph is exposed on the UI, but can cause issues because it can result in multiple roots (a child can refer to a new unknown parent). If a child->parent relationship exists but a corresponding parent->child relationship does not exist, this room is a "secret" room which From 1430661e5613e98d3bbd5b1b612876c44494eb81 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 15 Jan 2021 15:10:37 +0000 Subject: [PATCH 11/77] Mention auth chain on federation api --- proposals/2946-spaces-summary.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index e396ab00b3b..94135d94b04 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -225,7 +225,9 @@ Justifications for the request API shape are the same as before with one excepti the server should not return node information under `rooms` nor should it return _any state events in this room_. NB: state events which _point to_ this room should still be included. -The response body remains unchanged from the client format. +The response body remains unchanged from the client format. Servers are unable to verify the auth chain of the returned events +as they are typically not joined to the rooms returned. Servers MUST NOT persist these events in any potential room DAG that may +be created if the server were to join the room. Sending server behaviour: - When walking the spaces graph, if the server is not joined to a given room, remember the `via` server names and the room ID. From 09b0848cc85480f659fa17d113cba42b560691ce Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 18 Jan 2021 15:54:51 +0000 Subject: [PATCH 12/77] Add 'version' field --- proposals/2946-spaces-summary.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 94135d94b04..773a8fcefdd 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -225,9 +225,10 @@ Justifications for the request API shape are the same as before with one excepti the server should not return node information under `rooms` nor should it return _any state events in this room_. NB: state events which _point to_ this room should still be included. -The response body remains unchanged from the client format. Servers are unable to verify the auth chain of the returned events -as they are typically not joined to the rooms returned. Servers MUST NOT persist these events in any potential room DAG that may -be created if the server were to join the room. +The response body remains unchanged from the client format with the exception of a `version` field added to each room object under `rooms`. +Servers MUST use this field to determine how to decode the events in `events`. If the room version is unknown, the server may ignore these +events/rooms. Servers are unable to verify the auth chain of the returned events as they are typically not joined to the rooms returned. +Servers MUST NOT persist these events in any potential room DAG that may be created if the server were to join the room. Sending server behaviour: - When walking the spaces graph, if the server is not joined to a given room, remember the `via` server names and the room ID. From 7b2f3dc59ff6c17bedb632ee2eeeff6d3f57d6e0 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 19 Jan 2021 10:54:56 +0000 Subject: [PATCH 13/77] Stripped state; remove room versions --- proposals/2946-spaces-summary.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 773a8fcefdd..88973afc568 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -83,14 +83,18 @@ which returns: "present": true, "order": "abcd", "auto_join": true - } + }, + "room_id": "!ol19s:bleecker.street", + "sender": "@alice:bleecker.street" }, { "type": "m.space.parent", "state_key": "!space:example.com", "content": { "via": ["example.com"] - } + }, + "room_id": "!ol19s:bleecker.street", + "sender": "@alice:bleecker.street" } ] } @@ -130,8 +134,9 @@ Justifications for the response API shape are as follows: this room as a parent. * `room_type` which is the room type, which is `m.space` for subspaces. It can be omitted if there is no room type in which case it should be interpreted as a normal room. - - `events`: These are the edges of the graph. The objects in the array are complete (or stripped?) `m.space.parent` - or `m.space.child` events. + - `events`: These are the edges of the graph. The objects in the array are stripped `m.space.parent` + or `m.space.child` events. This means that they only contain the `type`, `state_key`, `content`, `room_id` and `sender` + keys, similar to `invite_state` in the `/sync` API. - `next_batch`: Its presence indicates that there are more results to return. Server behaviour: @@ -225,10 +230,16 @@ Justifications for the request API shape are the same as before with one excepti the server should not return node information under `rooms` nor should it return _any state events in this room_. NB: state events which _point to_ this room should still be included. -The response body remains unchanged from the client format with the exception of a `version` field added to each room object under `rooms`. -Servers MUST use this field to determine how to decode the events in `events`. If the room version is unknown, the server may ignore these -events/rooms. Servers are unable to verify the auth chain of the returned events as they are typically not joined to the rooms returned. -Servers MUST NOT persist these events in any potential room DAG that may be created if the server were to join the room. +The response body remains unchanged from the client format. Servers are unable to verify the auth chain of the returned events +as they are typically not joined to the rooms returned. Servers MUST NOT persist these events in any potential room DAG that +may be created if the server were to join the room. The decision to use stripped state events instead of the actual events +was made because: + - Clients just care about the data, and servers shouldn't be persisting the unverified events in the DAG, meaning data like + `prev_events` and `auth_events` would be useless. + - Events deserialise differently based on the room version which would need to be injected into the response if we decided + to use full events. In addition, because this endpoint returns events from multiple rooms then servers would need to partially + deserialise the event to extract the `room_id` field to work out which room version to use. This is bad because it relies on + the `room_id` field never changing in a future room version. Sending server behaviour: - When walking the spaces graph, if the server is not joined to a given room, remember the `via` server names and the room ID. From 6224859fc97c6b53b2cbc8359a091b02d611bfe5 Mon Sep 17 00:00:00 2001 From: Kegsay Date: Thu, 25 Feb 2021 14:16:26 +0000 Subject: [PATCH 14/77] Update 2946-spaces-summary.md --- proposals/2946-spaces-summary.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 88973afc568..3505ffa3963 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -257,3 +257,12 @@ Receiving server behaviour: - Servers are authorised to see node/edge information if they are either joined to the room or the room is `world_readable`. A well-behaved server will not send requests for rooms they are already joined to, so they should only be shown `world_readable` rooms. + + ### Unstable Prefix + + The following mapping will be used for identifiers in this MSC during development: + + Proposed final identifier | Purpose | Development identifier +------------------------------- | ------- | ---- +`/_matrix/client/r0/rooms/{roomID}/spaces` | CS API Path | `/_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces` +`/_matrix/federation/v1/spaces/{roomID}` | SS API Path | `/_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID}` From 211e5e68da76feb52b90871d781d0a37106770b1 Mon Sep 17 00:00:00 2001 From: Kegsay Date: Mon, 15 Mar 2021 10:05:13 +0000 Subject: [PATCH 15/77] Update proposals/2946-spaces-summary.md Co-authored-by: Patrick Cloke --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 3505ffa3963..104088d21ae 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -46,7 +46,7 @@ POST /_matrix/client/r0/rooms/{roomID}/spaces { "max_rooms_per_space": 5, // The maximum number of rooms/subspaces to return for a given space, if negative unbounded. default: -1. "auto_join_only": true, // If true, only return m.space.child events with auto_join:true, default: false, which returns all events. - "limit": 100, // The maximum number of rooms/subspaces to return, server can override this, default: 100. + "limit": 100, // The maximum number of events to return, server can override this, default: 100. "batch": "opaque_string" // A token to use if this is a subsequent HTTP hit, default: "". } ``` From 725277ef742695974a749c8de2a3834188056cea Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 23 Mar 2021 18:10:15 +0000 Subject: [PATCH 16/77] Replace with link to draft doc. --- proposals/2946-spaces-summary.md | 268 +------------------------------ 1 file changed, 2 insertions(+), 266 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 104088d21ae..f5c357a7f48 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -1,268 +1,4 @@ ## Spaces Summary API -*This MSC depends on [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772).* - -Spaces are rooms with `m.space` as the [room type](https://github.com/matrix-org/matrix-doc/pull/1840). -Spaces can include state events to specify parent/child relationships. -These relationships point to other rooms, which may themselves be spaces. -This means spaces can have subspaces and rooms. This creates a graph: a space directory. - -This MSC defines a new endpoint which can be used to reveal information about the space directory. - -Consider the graph: -``` - A - ^ - |___ - | | - V V - B R1 - ^ - | - V - R2 - -R1,R2 = rooms -A,B = spaces -<--> = parent/child relationship events -``` -This MSC aims to create a way for clients to produce a tree view along the lines of: -``` -Space A - | - |___ Room 1 - | - Space B - | - |___ Room 2 -``` -Clients are able to do this currently by peeking into all of these rooms -(assuming they have permission to) but this is costly and slow. - -### Client API - -``` -POST /_matrix/client/r0/rooms/{roomID}/spaces -{ - "max_rooms_per_space": 5, // The maximum number of rooms/subspaces to return for a given space, if negative unbounded. default: -1. - "auto_join_only": true, // If true, only return m.space.child events with auto_join:true, default: false, which returns all events. - "limit": 100, // The maximum number of events to return, server can override this, default: 100. - "batch": "opaque_string" // A token to use if this is a subsequent HTTP hit, default: "". -} -``` - -which returns: - -``` -{ - "next_batch": "opaque string", - "rooms": [ - { - "aliases": [ - "#murrays:cheese.bar" - ], - "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE", - "guest_can_join": false, - "name": "CHEESE", - "num_joined_members": 37, - "room_id": "!ol19s:bleecker.street", - "topic": "Tasty tasty cheese", - "world_readable": true, - - "num_refs": 42, - "room_type": "m.space" - }, - { ... } - ], - "events": [ - { - "type": "m.space.child", - "state_key": "!efgh:example.com", - "content": { - "via": ["example.com"], - "present": true, - "order": "abcd", - "auto_join": true - }, - "room_id": "!ol19s:bleecker.street", - "sender": "@alice:bleecker.street" - }, - { - "type": "m.space.parent", - "state_key": "!space:example.com", - "content": { - "via": ["example.com"] - }, - "room_id": "!ol19s:bleecker.street", - "sender": "@alice:bleecker.street" - } - ] -} -``` - -Justifications for the request API shape are as follows: - - The HTTP path: Spaces are scoped to a specific room to act as an anchor point for - navigating the directory. Alternatives are `/r0/spaces` with `room_id` inside the - body, but this feels less idiomatic for room-scoped requests. - - The HTTP method: there's a lot of data to provide to the server, and GET requests - shouldn't have an HTTP body, hence opting for POST. The same request can produce - different results over time so PUT isn't acceptable as an alternative. - - `max_rooms_per_space`: UIs can only display a set number of rooms per space, so allowing - clients to specify this limit is desirable. Subsequent rooms can be obtained by paginating. - The graph has 2 distinct types of nodes, and some UIs may want to weight one type above - the other. However, it's impossible to always know what type of node a given room ID falls - under because the server may not be joined to that room (to determine the room type) or the - caller may not have permission to see this information. - - `limit`: The maximum number of events to return in `events`. It is desirable for clients - and servers to be able to put a maximum cap on the amount of data returned to the client. - **This limit may be exceeded if the root room has `> limit` rooms.** - - `auto_join_only`: If `true`, only a subset of the graph is returned based on the presence - of `auto_join: true` in the `content` field of `m.space.child`. Some clients may only - care about the "main" or "default" rooms, which are rooms with this flag set. This does - not affect parent state events: they are still returned. This does not modify the value - of `num_refs`. - - `batch`: Required for pagination. Could be a query parameter but it's easier if - request data is in one place. - -Justifications for the response API shape are as follows: - - `rooms`: These are the nodes of the graph. The objects in the array are exactly the same as `PublicRoomsChunk` in the - [specification](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms) - as the information displayed to users is the same. There are two _additional_ keys - which are: - * `num_refs` which is the total number of state events which point to or from this room (inbound/outbound edges). - This includes all `m.space.child` events in the room, _in addition to_ `m.space.parent` events which point to - this room as a parent. - * `room_type` which is the room type, which is `m.space` for subspaces. It can be omitted if there is no room type - in which case it should be interpreted as a normal room. - - `events`: These are the edges of the graph. The objects in the array are stripped `m.space.parent` - or `m.space.child` events. This means that they only contain the `type`, `state_key`, `content`, `room_id` and `sender` - keys, similar to `invite_state` in the `/sync` API. - - `next_batch`: Its presence indicates that there are more results to return. - -Server behaviour: - - Extract the room ID from the request. Sanity check request data. Begin walking the graph - starting with the room ID in the request in a queue of unvisited rooms according to the - following rules: - * If this room has already been processed, skip. NB: do not remember this between calls, - as servers will need to visit the same room more than once to return additional events. - * Mark this room as processed. - * Is the caller currently joined to the room or is the room `world_readable`? - If no, skip this room. If yes, continue. - * If this room has not ever been in `rooms` (across multiple requests), extract the - `PublicRoomsChunk` for this room. - * Get all `m.space.child` and `m.space.parent` state events for the room. *In addition*, get - all `m.space.child` and `m.space.parent` state events which *point to* (via `state_key`) - this room. This requires servers to store reverse lookups. Add the total number of events - to `PublicRoomsChunk` under `num_refs`. Add `PublicRoomsChunk` to `rooms`. - Do NOT include state events which are missing the `content.via` field, as this indicates - a redacted link. These events do not contribute to `num_refs` and should not be returned - to the caller. - * If this is the root room from the original request, insert all these events into `events` if - they haven't been added before (across multiple requests). - * Else add them to `events` honouring the `limit` and `max_rooms_per_space` values. If either - are exceeded, stop adding events. If the event has already been added, do not add it again. - * For each referenced room ID in the events being returned to the caller (both parent and child) - add the room ID to the queue of unvisited rooms. Loop from the beginning. - - This guarantees that all edges for the root node are given to the client. Not all edges of subspaces - will be returned, nor will edges of all rooms be returned. This can be detected by clients in two ways: - * Comparing `num_refs` with the *total number* of edges pointing to/from the room. - * Comparing the number of `m.space.child` state events in the room with `max_rooms_per_space`, where - `max_rooms_per_space` is 1 greater than the actual desired maximum value. - - If not all events were returned due to reaching a `limit` or `max_rooms_per_space`, return a - `next_batch` token. The server SHOULD NOT return duplicate events or rooms on subsequent - requests: this can be achieved by remembering the event/room IDs returned to the caller between calls. - This results in each request uncovering more nodes/edges until the entire tree has been explored. - - -Client behaviour: - - Decide which room should be the root of the tree, then call this endpoint with the root room ID. - - The data in `rooms` determines _what_ to show. The events in `events` determine _where_ to show it. - Take all the data in `rooms` and key them by room ID. - - Loop through the `events` and keep track of parent->child relationships by looking at the `state_key` - which is the child room ID. Clients may want to treat child->parent relationships - (`m.space.parent` events) the same way or differently. Treating them the - same way will guarantee that the entire graph is exposed on the UI, but can cause issues because it - can result in multiple roots (a child can refer to a new unknown parent). If a child->parent relationship - exists but a corresponding parent->child relationship does not exist, this room is a "secret" room which - should be indicated as such. If a parent->child relationship exists but a corresponding child->parent - relationship does not exist, this room is a "user-curated collection" and should be indicated as such. - Persist the mappings in a map: one child can have multiple parents and one parent can have multiple - children. - - Starting at the root room ID: - * Compare the `num_refs` value in `rooms.$room_id` to the total number of events which reference this - room in `events` (across all rooms). If they differ, a partial response has been returned for this - space and additional results should be loaded when required. The API guarantees that *all* events for - the root room ID will be returned, regardless of how many events there are (even if they exceed `limit`). - * Lookup all children for this room ID. For each child: - - If there is no corresponding room data for this room ID then this room is either a subspace or a room. - The room is not world readable or the server does not have any information about this room. Clients - MAY be able to join this room by issuing a `/join` request. - - If the child is a room (not a space, check the `room_type` field), look up the room data from - `rooms` and render it. - - Else the child is a space, render the space as a heading (using the room name/topic) and - restart the lookup using the new space room ID. - - -### Federation API - - -Servers may not be joined to all subspaces in the graph. If this happens, they will lack the room state to form a response. -Servers may get this information by peeking into the room, but this includes a live stream of events which is unecessary and -is a single request per room in the graph. It would be preferable if there was a federation endpoint which included this -information and nothing more. This is more performant and is a single request per _server_ (which may have many nodes -of the graph). Effectively, this federation API requests the view of the graph from the point of view of the destination -server. - -``` -POST /_matrix/federation/v1/spaces/{roomID} -{ - "exclude_rooms": ["!a:b", "!b:c"] // Optional. Do not return state events in these rooms, nor include these rooms in `rooms`. - "max_rooms_per_space": 5, // The maximum number of rooms/subspaces to return for a given space, if negative unbounded. default: -1. - "limit": 100, // The maximum number of rooms/subspaces to return, server can override this, default: 100. - "batch": "opaque_string" // A token to use if this is a subsequent HTTP hit, default: "". -} -``` - -Justifications for the request API shape are the same as before with one exception: - - The HTTP path: Per-room federation endpoints are not put under `/rooms` so this proposal doesn't either. - - The `exclude_rooms` parameter: In order to stop redundant information being sent to the server, this field allows requesting - servers the ability to suppress node/edge information on a per-room basis. If a room ID is present in this list, - the server should not return node information under `rooms` nor should it return _any state events in this room_. NB: state - events which _point to_ this room should still be included. - -The response body remains unchanged from the client format. Servers are unable to verify the auth chain of the returned events -as they are typically not joined to the rooms returned. Servers MUST NOT persist these events in any potential room DAG that -may be created if the server were to join the room. The decision to use stripped state events instead of the actual events -was made because: - - Clients just care about the data, and servers shouldn't be persisting the unverified events in the DAG, meaning data like - `prev_events` and `auth_events` would be useless. - - Events deserialise differently based on the room version which would need to be injected into the response if we decided - to use full events. In addition, because this endpoint returns events from multiple rooms then servers would need to partially - deserialise the event to extract the `room_id` field to work out which room version to use. This is bad because it relies on - the `room_id` field never changing in a future room version. - -Sending server behaviour: - - When walking the spaces graph, if the server is not joined to a given room, remember the `via` server names and the room ID. - - Send a federated request to a server in `via` for the unknown room, marking rooms the server is already joined to - in `exclude_rooms`. - - Servers MAY eagerly request graph information and SHOULD cache the response for a configurable duration. This proposal recommends - 1 hour. - -Receiving server behaviour: - - Validate the request and check sender signatures. - - Walk the graph in the same way as the CS API endpoint, remembering to exclude rooms in `exclude_rooms`. "Exclude" in this - context merely means do not add the room or state events in that room to the response. The room itself MUST still be walked - so servers can extract transitive rooms e.g `A -> B -> C` and the requesting server requests `room_id: A, exclude_rooms: [B]` - must return `C`. - - Servers are authorised to see node/edge information if they are either joined to the room or the room is `world_readable`. - A well-behaved server will not send requests for rooms they are already joined to, so they should only be shown `world_readable` - rooms. - - ### Unstable Prefix - - The following mapping will be used for identifiers in this MSC during development: - - Proposed final identifier | Purpose | Development identifier -------------------------------- | ------- | ---- -`/_matrix/client/r0/rooms/{roomID}/spaces` | CS API Path | `/_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces` -`/_matrix/federation/v1/spaces/{roomID}` | SS API Path | `/_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID}` +This API is still in a draft stage: see +https://hackmd.io/fNYh4tjUT5mQfR1uuRzWDA for the current draft. From 0fd8d8d6a6f8d9a14390afe58de2b5c68703e12f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Apr 2021 14:31:53 -0400 Subject: [PATCH 17/77] Add a preamble and copy the current draft API. --- proposals/2946-spaces-summary.md | 190 ++++++++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 3 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index f5c357a7f48..9c822a20124 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -1,4 +1,188 @@ -## Spaces Summary API +## MSC2946: Spaces Summary -This API is still in a draft stage: see -https://hackmd.io/fNYh4tjUT5mQfR1uuRzWDA for the current draft. +This MSC depends on [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772), which +describes why a Space is useful: + +> Collecting rooms together into groups is useful for a number of purposes. Examples include: +> +> * Allowing users to discover different rooms related to a particular topic: for example "official matrix.org rooms". +> * Allowing administrators to manage permissions across a number of rooms: for example "a new employee has joined my company and needs access to all of our rooms". +> * Letting users classify their rooms: for example, separating "work" from "personal" rooms. +> +> We refer to such collections of rooms as "spaces". + +MSC2946 attempts to solve how the user of a space discovers rooms in that space. This +is useful for quickly exposing a user to many aspects of an entire community, using the +examples above, joining the "official matrix.org rooms" space might suggest joining a few +rooms: + +* A room to discuss deevelopment of the Matrix Spec. +* An announements room for news related to matrix.org. +* An off-topic room for members of the space. + +Note that it is implied that joining a space forces a user to join any of these, but +having a discovery mechanism is useful. + +## Proposal + +A new client-server API (and corresponding server-server API) is added which allows +for querying for the rooms and spaces contained within a space. This allows a client +to display a hierarchy of rooms to a user in an efficient manner (i.e. without having +to walk the full state of the space). + +### Client-server API + +Walks the space tree, starting at the provided room ID ("the root room"), +and visiting other rooms/spaces found via `org.matrix.msc1772.space.child` +events, recursing through those children into their children, etc. + +Example request: + +```jsonc +POST /_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces + +{ + "max_rooms_per_space": 5, + "suggested_only": true +} +``` + +or: + +```text +GET /_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces? + max_rooms_per_space=5& + suggested_only=true +``` + +Example response: + +```jsonc +{ + "rooms": [ + { + "room_id": "!ol19s:bleecker.street", + "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE", + "guest_can_join": false, + "name": "CHEESE", + "num_joined_members": 37, + "topic": "Tasty tasty cheese", + "world_readable": true, + + "room_type": "org.matrix.msc1772.space" + }, + { ... } + ], + "events": [ + { + "type": "org.matrix.msc1772.space.child", + "state_key": "!efgh:example.com", + "content": { + "via": ["example.com"], + "suggested": true + }, + "room_id": "!ol19s:bleecker.street", + "sender": "@alice:bleecker.street" + }, + { ... } + ] +} +``` + +Request params: + +* **`suggested_only`**: Optional. If `true`, return only child events and rooms where the + `org.matrix.msc1772.space.child` event has `suggested: true`. Defaults to + `false`. (For the POST request, must be a boolean. For GET, must be either + `true` or `false`, case sensitive.) +* **`max_rooms_per_space`**: Optional: a client-defined limit to the maximum + number of children to return per space. Doesn't apply to the root space (ie, + the `room_id` in the request). The server also has its own internal limit + (currently 50) (which *does* apply to the root room); attempts to exceed this + limit are ignored. Must be a non-negative integer. + +Response fields: + +* **`rooms`**: for each room/space, starting with the root room, a + summary of that room. The fields are the same as those returned by + `/publicRooms` (see + [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), + with the addition of: + * **`room_type`**: the value of the `org.matrix.msc1772.type` field from the + room's `m.room.create` event, if any. +* **`events`**: child events of the returned rooms. For each event, only the + following fields are returned: `type`, `state_key`, `content`, `room_id`, + `sender`. + +We start by looking at the root room, and add it to `rooms`. We also add any +`child` events in the room to `events`. We then recurse into the targets of +the `child` events, adding the rooms to `rooms` and any child events to +`events`. We then move onto grandchildren, and carry on in this way until +either all discovered rooms have been inspected, or we hit the server-side +limit on the number of rooms (currently 50). + +Other notes: + +* No consideration is currently given to `parent` events. +* If the user doesn't have permission to view/peek the root room (including if + that room does not exist), a 403 error is returned with `M_FORBIDDEN`. Any + inaccessible children are simply omitted from the result (though the `child` + events that point to them are still returned). +* There could be loops in the returned child events - clients should handle this + gracefully. +* Similarly, note that a child room might also be a grandchild. +* `suggested_only` applies transitively. For example, if a space A has child + space B which is *not* suggested, and space B has suggested child room C, and + the client makes a summary request for A with `suggested_only=true`, + neither B **nor** C will be returned. +* The current implementation doesn't honour `order` fields in child events. + +### Server-server API + +Much the same interface as the C-S API. + +Example request: + +```jsonc +POST /_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID} +{ + "exclude_rooms": ["!a:b", "!b:c"], + "max_rooms_per_space": 5, + "suggested_only": true +} +``` + +Response has the same shape as the C-S API. + +Request params are the same as the C-S API, with the addition of: + +* **`exclude_rooms`**: Optional. A list of room IDs that can be omitted + from the response. + +This is largely the same as the C-S API, but differences are: + +* The calling server can specify a list of spaces/rooms to omit from the + response (via `exclude_rooms`). +* `max_rooms_per_space` applies to the root room as well as any returned + children. +* If the target server is not a member of any discovered children (so + would have to send another request over federation to inspect them), no + attempt is made to recurse into them - they are simply omitted from the + response. + * If the target server is not a member of the root room, an empty + response is returned. +* Currently, no consideration is given to room membership: the spaces/rooms + must be world-readable (ie, peekable) for them to appear in the results. + XXX: this will have to change for private rooms. + +## Potential issues + +## Alternatives + +## Security considerations + +## Unstable prefix + +## TODO + +* Update this to use the stable identifiers from MSC1772 and MSC2946 everywhere. From dee9040eee9ab6555e7f33e0e92881083394847f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Apr 2021 14:55:00 -0400 Subject: [PATCH 18/77] Switch to using stable identifiers (and add an unstable identifiers section). --- proposals/2946-spaces-summary.md | 34 ++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 9c822a20124..62b09a031ce 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -33,13 +33,13 @@ to walk the full state of the space). ### Client-server API Walks the space tree, starting at the provided room ID ("the root room"), -and visiting other rooms/spaces found via `org.matrix.msc1772.space.child` +and visiting other rooms/spaces found via `m.space.child` events, recursing through those children into their children, etc. Example request: ```jsonc -POST /_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces +POST /_matrix/client/r0/rooms/{roomID}/spaces { "max_rooms_per_space": 5, @@ -50,7 +50,7 @@ POST /_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces or: ```text -GET /_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces? +GET /_matrix/client/r0/rooms/{roomID}/spaces? max_rooms_per_space=5& suggested_only=true ``` @@ -69,13 +69,13 @@ Example response: "topic": "Tasty tasty cheese", "world_readable": true, - "room_type": "org.matrix.msc1772.space" + "room_type": "m.space" }, { ... } ], "events": [ { - "type": "org.matrix.msc1772.space.child", + "type": "m.space.child", "state_key": "!efgh:example.com", "content": { "via": ["example.com"], @@ -92,7 +92,7 @@ Example response: Request params: * **`suggested_only`**: Optional. If `true`, return only child events and rooms where the - `org.matrix.msc1772.space.child` event has `suggested: true`. Defaults to + `m.space.child` event has `suggested: true`. Defaults to `false`. (For the POST request, must be a boolean. For GET, must be either `true` or `false`, case sensitive.) * **`max_rooms_per_space`**: Optional: a client-defined limit to the maximum @@ -108,7 +108,7 @@ Response fields: `/publicRooms` (see [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), with the addition of: - * **`room_type`**: the value of the `org.matrix.msc1772.type` field from the + * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. * **`events`**: child events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, @@ -144,7 +144,7 @@ Much the same interface as the C-S API. Example request: ```jsonc -POST /_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID} +POST /_matrix/federation/v1/spaces/{roomID} { "exclude_rooms": ["!a:b", "!b:c"], "max_rooms_per_space": 5, @@ -183,6 +183,20 @@ This is largely the same as the C-S API, but differences are: ## Unstable prefix -## TODO +During development of this feature it will be available at an unstable endpoints. +The client-server API will be: -* Update this to use the stable identifiers from MSC1772 and MSC2946 everywhere. +`/_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces` + +And the server-server API will be: + +`/_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID}` + +Note that the unstable identifiers from [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) also apply: + +Proposed final identifier | Purpose | Development identifier +------------------------------- | ------- | ---- +`type` | property in `m.room.create` | `org.matrix.msc1772.type` +`m.space` | value of `type` in `m.room.create` | `org.matrix.msc1772.space` +`m.space.child` | event type | `org.matrix.msc1772.space.child` +`m.space.parent` | event type | `org.matrix.msc1772.space.parent` From a3b62a830f96cf89a47b8b9066b48a8621354cec Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Apr 2021 15:18:06 -0400 Subject: [PATCH 19/77] Updates / clarifications. --- proposals/2946-spaces-summary.md | 58 ++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 62b09a031ce..b981cbc0b3d 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -11,13 +11,13 @@ describes why a Space is useful: > > We refer to such collections of rooms as "spaces". -MSC2946 attempts to solve how the user of a space discovers rooms in that space. This +MSC2946 attempts to solve how a member of a space discovers rooms in that space. This is useful for quickly exposing a user to many aspects of an entire community, using the examples above, joining the "official matrix.org rooms" space might suggest joining a few rooms: * A room to discuss deevelopment of the Matrix Spec. -* An announements room for news related to matrix.org. +* An announcements room for news related to matrix.org. * An off-topic room for members of the space. Note that it is implied that joining a space forces a user to join any of these, but @@ -92,14 +92,17 @@ Example response: Request params: * **`suggested_only`**: Optional. If `true`, return only child events and rooms where the - `m.space.child` event has `suggested: true`. Defaults to - `false`. (For the POST request, must be a boolean. For GET, must be either - `true` or `false`, case sensitive.) + `m.space.child` event has `suggested: true`. Defaults to `false`. + + For the POST request, must be a boolean. For GET, must be either `true` or `false`, + case sensitive. * **`max_rooms_per_space`**: Optional: a client-defined limit to the maximum number of children to return per space. Doesn't apply to the root space (ie, - the `room_id` in the request). The server also has its own internal limit - (currently 50) (which *does* apply to the root room); attempts to exceed this - limit are ignored. Must be a non-negative integer. + the `room_id` in the request). + + Server implementations may also have an internal limit (recommended to be 50) + (which *does* apply to the root room); attempts to exceed this limit are + ignored. Must be a non-negative integer. Response fields: @@ -110,23 +113,26 @@ Response fields: with the addition of: * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. -* **`events`**: child events of the returned rooms. For each event, only the +* **`events`**: `m.space.child` events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, `sender`. + +#### Algorithm -We start by looking at the root room, and add it to `rooms`. We also add any -`child` events in the room to `events`. We then recurse into the targets of -the `child` events, adding the rooms to `rooms` and any child events to -`events`. We then move onto grandchildren, and carry on in this way until -either all discovered rooms have been inspected, or we hit the server-side -limit on the number of rooms (currently 50). +1. Start at the "root" room (the provided room ID). +2. Generate a summary and add it to `rooms`. +3. Add any `m.space.child` events in the room to `events`. +4. Recurse into the targets of the `m.space.child` events, added the rooms to `rooms` + and any `m.space.child` events to `events`. +5. Recurse into grandchildren, etc. until either all discovered rooms have been + inspected, or the server-side limit on the number of rooms is reached. Other notes: -* No consideration is currently given to `parent` events. +* No consideration is currently given to `m.space.parent` events. * If the user doesn't have permission to view/peek the root room (including if that room does not exist), a 403 error is returned with `M_FORBIDDEN`. Any - inaccessible children are simply omitted from the result (though the `child` + inaccessible children are simply omitted from the result (though the `m.space.child` events that point to them are still returned). * There could be loops in the returned child events - clients should handle this gracefully. @@ -139,7 +145,7 @@ Other notes: ### Server-server API -Much the same interface as the C-S API. +Much the same interface as the Client-Server API. Example request: @@ -152,14 +158,14 @@ POST /_matrix/federation/v1/spaces/{roomID} } ``` -Response has the same shape as the C-S API. +Response has the same shape as the Client-Server API. -Request params are the same as the C-S API, with the addition of: +Request params are the same as the Client-Server API, with the addition of: * **`exclude_rooms`**: Optional. A list of room IDs that can be omitted from the response. -This is largely the same as the C-S API, but differences are: +This is largely the same as the Client-Server API, but differences are: * The calling server can specify a list of spaces/rooms to omit from the response (via `exclude_rooms`). @@ -173,14 +179,22 @@ This is largely the same as the C-S API, but differences are: response is returned. * Currently, no consideration is given to room membership: the spaces/rooms must be world-readable (ie, peekable) for them to appear in the results. - XXX: this will have to change for private rooms. ## Potential issues +* To reduce complexity, only a limited number of rooms are returned for a room, + no effort is made to paginate the results. Proper pagination is left to a future + MSC. + ## Alternatives +An initial version of this walked both `m.space.child` and `m.space.parent` events, +but this seems unnecessary to provide the expected user experience. + ## Security considerations +None. + ## Unstable prefix During development of this feature it will be available at an unstable endpoints. From f28ad9b0018c1d19cc25027882cf56d441e4df98 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 14 Apr 2021 07:02:37 -0400 Subject: [PATCH 20/77] Fix typo. --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index b981cbc0b3d..a1b08548466 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -62,7 +62,7 @@ Example response: "rooms": [ { "room_id": "!ol19s:bleecker.street", - "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE", + "avatar_url": "mxc://bleecker.street/CHEDDARandBRIE", "guest_can_join": false, "name": "CHEESE", "num_joined_members": 37, From d911c828f9960c0157248b02762a70b27985e2c1 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 14 Apr 2021 12:45:35 -0400 Subject: [PATCH 21/77] Clean-ups. --- proposals/2946-spaces-summary.md | 45 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index a1b08548466..40990a979a9 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -20,9 +20,6 @@ rooms: * An announcements room for news related to matrix.org. * An off-topic room for members of the space. -Note that it is implied that joining a space forces a user to join any of these, but -having a discovery mechanism is useful. - ## Proposal A new client-server API (and corresponding server-server API) is added which allows @@ -122,26 +119,35 @@ Response fields: 1. Start at the "root" room (the provided room ID). 2. Generate a summary and add it to `rooms`. 3. Add any `m.space.child` events in the room to `events`. -4. Recurse into the targets of the `m.space.child` events, added the rooms to `rooms` - and any `m.space.child` events to `events`. +4. Recurse into the targets of the `m.space.child` events, generate a summary for + each room and add it to `rooms`, also and any `m.space.child` events of the room + to `events`. 5. Recurse into grandchildren, etc. until either all discovered rooms have been inspected, or the server-side limit on the number of rooms is reached. Other notes: -* No consideration is currently given to `m.space.parent` events. * If the user doesn't have permission to view/peek the root room (including if that room does not exist), a 403 error is returned with `M_FORBIDDEN`. Any inaccessible children are simply omitted from the result (though the `m.space.child` events that point to them are still returned). * There could be loops in the returned child events - clients should handle this gracefully. -* Similarly, note that a child room might also be a grandchild. -* `suggested_only` applies transitively. For example, if a space A has child - space B which is *not* suggested, and space B has suggested child room C, and - the client makes a summary request for A with `suggested_only=true`, - neither B **nor** C will be returned. -* The current implementation doesn't honour `order` fields in child events. +* Similarly, note that a child room might appear multiple times (e.g. also be a + grandchild). +* `suggested_only` applies transitively. + + For example, if a space A has child space B which is *not* suggested, and space + B has suggested child room C, and the client makes a summary request for A with + `suggested_only=true`, neither B **nor** C will be returned. + + Similarly, if a space A has child space B which is suggested, and space B has + suggested child room C which is suggested, and the client makes a summary request + for A with `suggested_only=true`, both B and C will be returned. +* The current implementation doesn't honour `order` fields in child events, as + suggested in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772). +* `m.space.child` with an invalid `via` (invalid is defined as missing, not an + array or an empty array) are ignored. ### Server-server API @@ -182,14 +188,14 @@ This is largely the same as the Client-Server API, but differences are: ## Potential issues -* To reduce complexity, only a limited number of rooms are returned for a room, - no effort is made to paginate the results. Proper pagination is left to a future - MSC. +To reduce complexity, only a limited number of rooms are returned for a room, +no effort is made to paginate the results. Proper pagination is left to a future +MSC. ## Alternatives -An initial version of this walked both `m.space.child` and `m.space.parent` events, -but this seems unnecessary to provide the expected user experience. +An initial version of this followed both `m.space.child` and `m.space.parent` events, +but this is unnecessary to provide the expected user experience. ## Security considerations @@ -197,13 +203,12 @@ None. ## Unstable prefix -During development of this feature it will be available at an unstable endpoints. -The client-server API will be: +During development of this feature it will be available at unstable endpoints. +The client-server API will be: `/_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces` And the server-server API will be: - `/_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID}` Note that the unstable identifiers from [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) also apply: From 74f12d56ffbd317fdf93847e67aa2e85bd3cd108 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 30 Apr 2021 09:33:57 +0100 Subject: [PATCH 22/77] Update proposals/2946-spaces-summary.md Co-authored-by: Travis Ralston --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 40990a979a9..c18580adf0c 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -11,7 +11,7 @@ describes why a Space is useful: > > We refer to such collections of rooms as "spaces". -MSC2946 attempts to solve how a member of a space discovers rooms in that space. This +This MSC attempts to solve how a member of a space discovers rooms in that space. This is useful for quickly exposing a user to many aspects of an entire community, using the examples above, joining the "official matrix.org rooms" space might suggest joining a few rooms: From 8b1fe00630ff88a907bc3c4063c5f2a3bc51e9e5 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 3 May 2021 12:41:46 -0400 Subject: [PATCH 23/77] Drop unstable identifiers from MSC1772. --- proposals/2946-spaces-summary.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index c18580adf0c..8702d85cbbd 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -210,12 +210,3 @@ The client-server API will be: And the server-server API will be: `/_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID}` - -Note that the unstable identifiers from [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) also apply: - -Proposed final identifier | Purpose | Development identifier -------------------------------- | ------- | ---- -`type` | property in `m.room.create` | `org.matrix.msc1772.type` -`m.space` | value of `type` in `m.room.create` | `org.matrix.msc1772.space` -`m.space.child` | event type | `org.matrix.msc1772.space.child` -`m.space.parent` | event type | `org.matrix.msc1772.space.parent` From 8fdbfb15c2b64f89689683b2eaae39120228b203 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 4 May 2021 14:36:54 -0400 Subject: [PATCH 24/77] Various updates and clarifications. --- proposals/2946-spaces-summary.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 8702d85cbbd..83feb46282e 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -16,7 +16,7 @@ is useful for quickly exposing a user to many aspects of an entire community, us examples above, joining the "official matrix.org rooms" space might suggest joining a few rooms: -* A room to discuss deevelopment of the Matrix Spec. +* A room to discuss development of the Matrix Spec. * An announcements room for news related to matrix.org. * An off-topic room for members of the space. @@ -24,14 +24,14 @@ rooms: A new client-server API (and corresponding server-server API) is added which allows for querying for the rooms and spaces contained within a space. This allows a client -to display a hierarchy of rooms to a user in an efficient manner (i.e. without having +to efficiently display a hierarchy of rooms to a user (i.e. without having to walk the full state of the space). ### Client-server API -Walks the space tree, starting at the provided room ID ("the root room"), -and visiting other rooms/spaces found via `m.space.child` -events, recursing through those children into their children, etc. +An endpoint is provided to walk the space tree, starting at the provided room ID +("the root room"), and visiting other rooms/spaces found via `m.space.child` +events. It recurses into the children and into their children, etc. Example request: @@ -92,12 +92,12 @@ Request params: `m.space.child` event has `suggested: true`. Defaults to `false`. For the POST request, must be a boolean. For GET, must be either `true` or `false`, - case sensitive. + case-sensitive. * **`max_rooms_per_space`**: Optional: a client-defined limit to the maximum number of children to return per space. Doesn't apply to the root space (ie, the `room_id` in the request). - Server implementations may also have an internal limit (recommended to be 50) + Server implementations may also have an internal limit (recommended as 50) (which *does* apply to the root room); attempts to exceed this limit are ignored. Must be a non-negative integer. @@ -164,7 +164,7 @@ POST /_matrix/federation/v1/spaces/{roomID} } ``` -Response has the same shape as the Client-Server API. +The response has the same shape as the Client-Server API. Request params are the same as the Client-Server API, with the addition of: @@ -208,5 +208,5 @@ During development of this feature it will be available at unstable endpoints. The client-server API will be: `/_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces` -And the server-server API will be: +The server-server API will be: `/_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID}` From f145fa3e8ac63edb5d7e9777cb55ecefea20beb8 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 5 May 2021 08:25:53 -0400 Subject: [PATCH 25/77] Include the origin_server_ts in the response, as needed by MSC1772. --- proposals/2946-spaces-summary.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 83feb46282e..68368da339c 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -65,7 +65,7 @@ Example response: "num_joined_members": 37, "topic": "Tasty tasty cheese", "world_readable": true, - + "origin_server_ts": 1432735824653, "room_type": "m.space" }, { ... } @@ -110,6 +110,9 @@ Response fields: with the addition of: * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. + * **`origin_server_ts`**: the value of the `origin_server_ts` field from the + room's `m.room.create` event. This is required for sorting of rooms as specified + in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772). * **`events`**: `m.space.child` events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, `sender`. From f9c00a568bbed703d878db2a710d6fbc8d1ecd80 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 5 May 2021 11:43:47 -0400 Subject: [PATCH 26/77] Rename a parameter for clarity. --- proposals/2946-spaces-summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 68368da339c..c14fef3eb96 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -65,7 +65,7 @@ Example response: "num_joined_members": 37, "topic": "Tasty tasty cheese", "world_readable": true, - "origin_server_ts": 1432735824653, + "creation_ts": 1432735824653, "room_type": "m.space" }, { ... } @@ -110,7 +110,7 @@ Response fields: with the addition of: * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. - * **`origin_server_ts`**: the value of the `origin_server_ts` field from the + * **`creation_ts`**: the value of the `origin_server_ts` field from the room's `m.room.create` event. This is required for sorting of rooms as specified in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772). * **`events`**: `m.space.child` events of the returned rooms. For each event, only the From 9c2e85a5daf9314355767cd42bd6c8d3e93bd476 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 5 May 2021 13:08:37 -0400 Subject: [PATCH 27/77] Fix typo. Co-authored-by: David Baker --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index c14fef3eb96..80761e1fb2f 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -123,7 +123,7 @@ Response fields: 2. Generate a summary and add it to `rooms`. 3. Add any `m.space.child` events in the room to `events`. 4. Recurse into the targets of the `m.space.child` events, generate a summary for - each room and add it to `rooms`, also and any `m.space.child` events of the room + each room and add it to `rooms`, also add any `m.space.child` events of the room to `events`. 5. Recurse into grandchildren, etc. until either all discovered rooms have been inspected, or the server-side limit on the number of rooms is reached. From 760cda80736f23bf4364f93dc8147fbe0f1844c5 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 5 May 2021 16:34:06 -0400 Subject: [PATCH 28/77] Various clarifications based on feedback. --- proposals/2946-spaces-summary.md | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 80761e1fb2f..b7409e2ab0f 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -33,6 +33,9 @@ An endpoint is provided to walk the space tree, starting at the provided room ID ("the root room"), and visiting other rooms/spaces found via `m.space.child` events. It recurses into the children and into their children, etc. +Note that there is no requirement for any of the rooms to be of have a `type` of +`m.space`, any room with `m.space.child` events is considered. + Example request: ```jsonc @@ -117,27 +120,35 @@ Response fields: following fields are returned: `type`, `state_key`, `content`, `room_id`, `sender`. +Errors: + +403 with an error code of `M_FORBIDDEN`: if the user doesn't have permission to +view/peek the root room (including if that room does not exist). + #### Algorithm +A rough algorithm follows: + 1. Start at the "root" room (the provided room ID). 2. Generate a summary and add it to `rooms`. 3. Add any `m.space.child` events in the room to `events`. -4. Recurse into the targets of the `m.space.child` events, generate a summary for - each room and add it to `rooms`, also add any `m.space.child` events of the room - to `events`. -5. Recurse into grandchildren, etc. until either all discovered rooms have been - inspected, or the server-side limit on the number of rooms is reached. +4. Recurse into the targets of the `m.space.child` events. + 1. If the room is not accessible (or has already been processed), do not + process it. + 2. Generate a summary for the room and add it to `rooms`. + 3. Add any `m.space.child` events of the room to `events`. +5. Recurse into any newly added targets of `m.space.child` events (i.e. repeat + step 4), until either all discovered rooms have been inspected, or the + server-side limit on the number of rooms is reached. Other notes: -* If the user doesn't have permission to view/peek the root room (including if - that room does not exist), a 403 error is returned with `M_FORBIDDEN`. Any - inaccessible children are simply omitted from the result (though the `m.space.child` - events that point to them are still returned). +* Any inaccessible children are omitted from the result, but the `m.space.child` + events that point to them are still returned. * There could be loops in the returned child events - clients should handle this gracefully. * Similarly, note that a child room might appear multiple times (e.g. also be a - grandchild). + grandchild). Clients and servers should handle this appropriately. * `suggested_only` applies transitively. For example, if a space A has child space B which is *not* suggested, and space From a5ad9a487c9d046f36d11a02b41fae2d57f0885b Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 6 May 2021 08:29:14 -0400 Subject: [PATCH 29/77] Add auth / rate-limiting info. --- proposals/2946-spaces-summary.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index b7409e2ab0f..10679568d70 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -36,6 +36,8 @@ events. It recurses into the children and into their children, etc. Note that there is no requirement for any of the rooms to be of have a `type` of `m.space`, any room with `m.space.child` events is considered. +This endpoint requires authentication and is not subject to rate-limiting. + Example request: ```jsonc @@ -119,7 +121,7 @@ Response fields: * **`events`**: `m.space.child` events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, `sender`. - + Errors: 403 with an error code of `M_FORBIDDEN`: if the user doesn't have permission to From 4c10e0266e47a77b195afcc5923683a51ba7d56d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 6 May 2021 08:47:17 -0400 Subject: [PATCH 30/77] Combine some double spaces. --- proposals/2946-spaces-summary.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 10679568d70..c803f557198 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -103,7 +103,7 @@ Request params: the `room_id` in the request). Server implementations may also have an internal limit (recommended as 50) - (which *does* apply to the root room); attempts to exceed this limit are + (which *does* apply to the root room); attempts to exceed this limit are ignored. Must be a non-negative integer. Response fields: @@ -125,7 +125,7 @@ Response fields: Errors: 403 with an error code of `M_FORBIDDEN`: if the user doesn't have permission to -view/peek the root room (including if that room does not exist). +view/peek the root room (including if that room does not exist). #### Algorithm @@ -140,7 +140,7 @@ A rough algorithm follows: 2. Generate a summary for the room and add it to `rooms`. 3. Add any `m.space.child` events of the room to `events`. 5. Recurse into any newly added targets of `m.space.child` events (i.e. repeat - step 4), until either all discovered rooms have been inspected, or the + step 4), until either all discovered rooms have been inspected, or the server-side limit on the number of rooms is reached. Other notes: @@ -155,7 +155,7 @@ Other notes: For example, if a space A has child space B which is *not* suggested, and space B has suggested child room C, and the client makes a summary request for A with - `suggested_only=true`, neither B **nor** C will be returned. + `suggested_only=true`, neither B **nor** C will be returned. Similarly, if a space A has child space B which is suggested, and space B has suggested child room C which is suggested, and the client makes a summary request From ad5af4d571ca5c918b9c3c8fbb54d091ff9e9eab Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 6 May 2021 11:05:52 -0400 Subject: [PATCH 31/77] Use only GET endpoints. --- proposals/2946-spaces-summary.md | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index c803f557198..cb1840d5186 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -40,17 +40,6 @@ This endpoint requires authentication and is not subject to rate-limiting. Example request: -```jsonc -POST /_matrix/client/r0/rooms/{roomID}/spaces - -{ - "max_rooms_per_space": 5, - "suggested_only": true -} -``` - -or: - ```text GET /_matrix/client/r0/rooms/{roomID}/spaces? max_rooms_per_space=5& @@ -96,8 +85,7 @@ Request params: * **`suggested_only`**: Optional. If `true`, return only child events and rooms where the `m.space.child` event has `suggested: true`. Defaults to `false`. - For the POST request, must be a boolean. For GET, must be either `true` or `false`, - case-sensitive. + Must be either `true` or `false`, case-sensitive. * **`max_rooms_per_space`**: Optional: a client-defined limit to the maximum number of children to return per space. Doesn't apply to the root space (ie, the `room_id` in the request). @@ -172,7 +160,7 @@ Much the same interface as the Client-Server API. Example request: ```jsonc -POST /_matrix/federation/v1/spaces/{roomID} +GET /_matrix/federation/v1/spaces/{roomID} { "exclude_rooms": ["!a:b", "!b:c"], "max_rooms_per_space": 5, From dba41f9135f5106a0d58648bf165893d5dd20971 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 6 May 2021 11:07:55 -0400 Subject: [PATCH 32/77] Add notes about DoS potential. --- proposals/2946-spaces-summary.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index cb1840d5186..ef486658a9f 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -203,7 +203,10 @@ but this is unnecessary to provide the expected user experience. ## Security considerations -None. +A space with many rooms on different homeservers could cause multiple federation +requests to be made. A carefully crafted room with inadequate limits on the maximum +rooms per space (or a maximum total number of rooms) could be used in a denial +of service attack. ## Unstable prefix From 8a968ebcf1890af416c6fb3de6253121aa2dc4d6 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 6 May 2021 11:22:03 -0400 Subject: [PATCH 33/77] Tweaks from review. --- proposals/2946-spaces-summary.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index ef486658a9f..52bf574a1d8 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -83,9 +83,7 @@ Example response: Request params: * **`suggested_only`**: Optional. If `true`, return only child events and rooms where the - `m.space.child` event has `suggested: true`. Defaults to `false`. - - Must be either `true` or `false`, case-sensitive. + `m.space.child` event has `suggested: true`. Must be a boolean, defaults to `false`. * **`max_rooms_per_space`**: Optional: a client-defined limit to the maximum number of children to return per space. Doesn't apply to the root space (ie, the `room_id` in the request). @@ -113,7 +111,11 @@ Response fields: Errors: 403 with an error code of `M_FORBIDDEN`: if the user doesn't have permission to -view/peek the root room (including if that room does not exist). +view/peek the root room (including if that room does not exist). This matches the +behavior of other room endpoints (e.g. +[`/_matrix/client/r0/rooms/{roomID}/aliases`](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-rooms-roomid-aliases)). +To not divulge whether the user doesn't have permission vs whether the room +does not exist. #### Algorithm From b379c42e88fa9c2013a91a7a6991e865d08ba05a Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 6 May 2021 12:34:08 -0400 Subject: [PATCH 34/77] Add context about why stripped events are returned. --- proposals/2946-spaces-summary.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 52bf574a1d8..d66aa7c28b9 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -106,7 +106,7 @@ Response fields: in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772). * **`events`**: `m.space.child` events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, - `sender`. + `sender`.[1](#f1) Errors: @@ -219,3 +219,10 @@ The client-server API will be: The server-server API will be: `/_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID}` + +## Footnotes + +[1]: The rationale for including stripped events here is to reduce +potential dataleaks (e.g. timestamps, `prev_content`, etc.) and to ensure that +clients do not treat any of this data as authoritative (e.g. if it came back +over federation). The data should not be persisted as actual events.[↩](#a1) From 27f526cbd9089f64e655d0e8896f9664f943d0b2 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 6 May 2021 12:43:47 -0400 Subject: [PATCH 35/77] Remove some implementation details. --- proposals/2946-spaces-summary.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index d66aa7c28b9..717a31ff26d 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -86,11 +86,10 @@ Request params: `m.space.child` event has `suggested: true`. Must be a boolean, defaults to `false`. * **`max_rooms_per_space`**: Optional: a client-defined limit to the maximum number of children to return per space. Doesn't apply to the root space (ie, - the `room_id` in the request). + the `room_id` in the request). Must be a non-negative integer. - Server implementations may also have an internal limit (recommended as 50) - (which *does* apply to the root room); attempts to exceed this limit are - ignored. Must be a non-negative integer. + Server implementations should impose a maximum value to avoid resource + exhaustion. Response fields: From c142433c65ff02e799575b1989a88660c8bddf3b Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 10 May 2021 10:43:49 -0400 Subject: [PATCH 36/77] Add notes on ordering. --- proposals/2946-spaces-summary.md | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 717a31ff26d..aca70275a50 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -197,6 +197,64 @@ To reduce complexity, only a limited number of rooms are returned for a room, no effort is made to paginate the results. Proper pagination is left to a future MSC. +### MSC1772 Ordering + +[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) defines the ordering +of "default ordering of siblings in the room list" using the `order` key: + +> Rooms are sorted based on a lexicographic ordering of the Unicode codepoints +> of the characters in `order` values. Rooms with no `order` come last, in +> ascending numeric order of the `origin_server_ts` of their `m.room.create` +> events, or ascending lexicographic order of their `room_id`s in case of equal +> `origin_server_ts`. `order`s which are not strings, or do not consist solely +> of ascii characters in the range `\x20` (space) to `\x7F` (~), or consist of +> more than 50 characters, are forbidden and the field should be ignored if +> received. + +Unfortunately there are situations when a homeserver comes across a reference to +a child room that is unknown to it and must decide the ordering. Without being +able to see the `m.room.create` event (which it might not have permission to see) +no proper ordering can be given. + +Consider the following case of a space with 3 child rooms: + +``` + Space A + | + +--------+--------+ + | | | +Room B Room C Room D +``` + +Space A, Room B, and Room C are on HS1, while Room D is on HS2. HS1 has no users +in Room D (and thus has no state from it). Room B, C, and D do not have an +`order` field set (and default to using the ordering rules above). + +When a user asks HS1 for the space summary with a `max_rooms_per_space` equal to +`2` it cannot fulfill this request since it is unsure how to order Room B, Room +C, and Room D, but it can only return 2 of them. It *can* reach out over +federation to HS2 and request a space summary for Room D, but this is undesirable: + +* HS1 might not have the permissions to know any of the state of Room D, so might + receive a 403 error. +* If we expand the example above to many rooms than this becomes expensive to + query a remote server simply for ordering. + +This proposes changing the ordering rules from MSC1772 to the following: + +* Rooms are sorted based on a lexicographic ordering of the Unicode codepoints + of the characters in `order` values. + + `order`s which are not strings, or do not consist solely of ascii characters + in the range `\x20` (space) to `\x7F` (~), or consist of more than 50 + characters, are forbidden and the field should be ignored if received. +* Rooms with no `order` come last, in ascending lexicographic order of their + `room_id`s. + +This removes the clauses discussing using the `origin_server_ts` of the +`m.room.create` event to allow a defined sorting of siblings based purely on the +information available in the `m.space.child` event. + ## Alternatives An initial version of this followed both `m.space.child` and `m.space.parent` events, From af8c7b04d9f87bb2c4292a549b7db36ae6ef2324 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 10 May 2021 10:45:20 -0400 Subject: [PATCH 37/77] Remove unnecessary data. --- proposals/2946-spaces-summary.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index aca70275a50..d72abf5141f 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -59,7 +59,6 @@ Example response: "num_joined_members": 37, "topic": "Tasty tasty cheese", "world_readable": true, - "creation_ts": 1432735824653, "room_type": "m.space" }, { ... } @@ -100,9 +99,6 @@ Response fields: with the addition of: * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. - * **`creation_ts`**: the value of the `origin_server_ts` field from the - room's `m.room.create` event. This is required for sorting of rooms as specified - in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772). * **`events`**: `m.space.child` events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, `sender`.[1](#f1) From bcde9e0840b1b7d1c95b02d45a8470b661c870c1 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 10 May 2021 13:28:14 -0400 Subject: [PATCH 38/77] Clarify the server-server API. --- proposals/2946-spaces-summary.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index d72abf5141f..cb206ea99b5 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -128,6 +128,10 @@ A rough algorithm follows: step 4), until either all discovered rooms have been inspected, or the server-side limit on the number of rooms is reached. + In the case of the homeserver not having access to the state of a room, the + server-server API (see below) can be used to query for this information over + federation. + Other notes: * Any inaccessible children are omitted from the result, but the `m.space.child` @@ -152,22 +156,23 @@ Other notes: ### Server-server API -Much the same interface as the Client-Server API. +The Server-Server API has almost the same interface as the Client-Server API. +It is used when a homeserver does not have the state of a room to include in the +summary. Example request: ```jsonc -GET /_matrix/federation/v1/spaces/{roomID} -{ - "exclude_rooms": ["!a:b", "!b:c"], - "max_rooms_per_space": 5, - "suggested_only": true -} +GET /_matrix/federation/v1/spaces/{roomID}? + exclude_rooms=%21a%3Ab& + exclude_rooms=%21b%3Ac& + max_rooms_per_space=5& + suggested_only=true& ``` The response has the same shape as the Client-Server API. -Request params are the same as the Client-Server API, with the addition of: +Request parameters are the same as the Client-Server API, with the addition of: * **`exclude_rooms`**: Optional. A list of room IDs that can be omitted from the response. @@ -180,8 +185,9 @@ This is largely the same as the Client-Server API, but differences are: children. * If the target server is not a member of any discovered children (so would have to send another request over federation to inspect them), no - attempt is made to recurse into them - they are simply omitted from the - response. + attempt is made to recurse into them - they" are simply omitted from the + `rooms` key of the response. (Although they will still appear in the `events` + key). * If the target server is not a member of the root room, an empty response is returned. * Currently, no consideration is given to room membership: the spaces/rooms From 328ae81af6eead4bf244f747eafa88e56c0b2bb3 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 10 May 2021 13:29:03 -0400 Subject: [PATCH 39/77] More clarifications. --- proposals/2946-spaces-summary.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index cb206ea99b5..7f2ca99ff63 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -130,7 +130,8 @@ A rough algorithm follows: In the case of the homeserver not having access to the state of a room, the server-server API (see below) can be used to query for this information over - federation. + federation from one of the servers provided in the `via` key of the + `m.space.child` event. Other notes: From 518db51158412cf767eaf9a6ef7166105a156905 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 11 May 2021 12:29:03 -0400 Subject: [PATCH 40/77] Remove obsolete note. --- proposals/2946-spaces-summary.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 7f2ca99ff63..d5b2fae06e5 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -150,8 +150,6 @@ Other notes: Similarly, if a space A has child space B which is suggested, and space B has suggested child room C which is suggested, and the client makes a summary request for A with `suggested_only=true`, both B and C will be returned. -* The current implementation doesn't honour `order` fields in child events, as - suggested in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772). * `m.space.child` with an invalid `via` (invalid is defined as missing, not an array or an empty array) are ignored. From 3b0051fb103f150810901375a2191ae9c1b2e566 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 19 May 2021 13:17:42 -0400 Subject: [PATCH 41/77] Some clarifications to what accessible means. --- proposals/2946-spaces-summary.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index d5b2fae06e5..0548b6dec5e 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -120,8 +120,8 @@ A rough algorithm follows: 2. Generate a summary and add it to `rooms`. 3. Add any `m.space.child` events in the room to `events`. 4. Recurse into the targets of the `m.space.child` events. - 1. If the room is not accessible (or has already been processed), do not - process it. + 1. If the room is inaccessible (as defined by [room history visibility](https://matrix.org/docs/spec/client_server/latest#id87)) + or has already been processed, do not process it. 2. Generate a summary for the room and add it to `rooms`. 3. Add any `m.space.child` events of the room to `events`. 5. Recurse into any newly added targets of `m.space.child` events (i.e. repeat @@ -137,8 +137,8 @@ Other notes: * Any inaccessible children are omitted from the result, but the `m.space.child` events that point to them are still returned. -* There could be loops in the returned child events - clients should handle this - gracefully. +* There could be loops in the returned child events - clients (and servers) + should handle this gracefully. * Similarly, note that a child room might appear multiple times (e.g. also be a grandchild). Clients and servers should handle this appropriately. * `suggested_only` applies transitively. From 5cd8270ec5478c07fd86be23f196aaeda783d00d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 19 May 2021 13:27:42 -0400 Subject: [PATCH 42/77] Update notes about sorting to include the origin_server_ts of the m.space.child event. This reverts commit af8c7b04d9f87bb2c4292a549b7db36ae6ef2324. --- proposals/2946-spaces-summary.md | 33 +++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 0548b6dec5e..47beeef6b0e 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -72,7 +72,8 @@ Example response: "suggested": true }, "room_id": "!ol19s:bleecker.street", - "sender": "@alice:bleecker.street" + "sender": "@alice:bleecker.street", + "creation_ts": 1432735824653 }, { ... } ] @@ -101,7 +102,11 @@ Response fields: room's `m.room.create` event, if any. * **`events`**: `m.space.child` events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, - `sender`.[1](#f1) + `sender`, [1](#f1) with the addition of: + * **`creation_ts`**: the value of the `origin_server_ts` field from the + `m.space.child` event. This is required for sorting of rooms as specified + in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) and updated + below. Errors: @@ -243,18 +248,20 @@ federation to HS2 and request a space summary for Room D, but this is undesirabl This proposes changing the ordering rules from MSC1772 to the following: -* Rooms are sorted based on a lexicographic ordering of the Unicode codepoints - of the characters in `order` values. - - `order`s which are not strings, or do not consist solely of ascii characters - in the range `\x20` (space) to `\x7F` (~), or consist of more than 50 - characters, are forbidden and the field should be ignored if received. -* Rooms with no `order` come last, in ascending lexicographic order of their - `room_id`s. +> Rooms are sorted based on a lexicographic ordering of the Unicode codepoints +> of the characters in `order` values. Rooms with no `order` come last, in +> ascending numeric order of the `origin_server_ts` of their `m.space.child` +> events, or ascending lexicographic order of their `room_id`s in case of equal +> `origin_server_ts`. `order`s which are not strings, or do not consist solely +> of ascii characters in the range `\x20` (space) to `\x7E` (~), or consist of +> more than 50 characters, are forbidden and the field should be ignored if +> received. -This removes the clauses discussing using the `origin_server_ts` of the -`m.room.create` event to allow a defined sorting of siblings based purely on the -information available in the `m.space.child` event. +This modifies the clauses for calculating the `origin_server_ts` of the +`m.room.create` event to refer to the `m.space.child` event instead. This allows +for a defined sorting of siblings based purely on the information available in +the `m.space.child` event while still allowing for a natural ordering due to the +age of the relationship. ## Alternatives From 797dda44c4158e83dcff017f1ef2f36d7c2c4f3c Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 11 Jun 2021 09:53:01 -0400 Subject: [PATCH 43/77] Only consider `m.space` rooms and do not return links to nowhere. --- proposals/2946-spaces-summary.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 47beeef6b0e..63f97404117 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -33,8 +33,8 @@ An endpoint is provided to walk the space tree, starting at the provided room ID ("the root room"), and visiting other rooms/spaces found via `m.space.child` events. It recurses into the children and into their children, etc. -Note that there is no requirement for any of the rooms to be of have a `type` of -`m.space`, any room with `m.space.child` events is considered. +Note that only rooms that have a `type` of `m.space` are considered when searching +for `m.space.child` events. This endpoint requires authentication and is not subject to rate-limiting. @@ -140,10 +140,10 @@ A rough algorithm follows: Other notes: -* Any inaccessible children are omitted from the result, but the `m.space.child` - events that point to them are still returned. +* Any inaccessible children are omitted from the result, as well as the + `m.space.child` events that point to them. * There could be loops in the returned child events - clients (and servers) - should handle this gracefully. + should handle this gracefully. * Similarly, note that a child room might appear multiple times (e.g. also be a grandchild). Clients and servers should handle this appropriately. * `suggested_only` applies transitively. From 105fd934b1229e5d67d7622ffa4c6c5367a1871d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 25 Jun 2021 12:38:11 -0400 Subject: [PATCH 44/77] Updates based on MSC3173 merging and updates to MSC3083. --- proposals/2946-spaces-summary.md | 53 ++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 63f97404117..393abb867af 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -59,7 +59,8 @@ Example response: "num_joined_members": 37, "topic": "Tasty tasty cheese", "world_readable": true, - "room_type": "m.space" + "room_type": "m.space", + "allowed_spaces": ["!abcdef:bleecker.street"] }, { ... } ], @@ -98,8 +99,10 @@ Response fields: `/publicRooms` (see [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), with the addition of: - * **`room_type`**: the value of the `m.type` field from the - room's `m.room.create` event, if any. + * **`room_type`**: the value of the `m.type` field from the room's + `m.room.create` event, if any. + * **`allowed_room_ids`**: A list of room IDs which give access to this room per + [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083). * **`events`**: `m.space.child` events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, `sender`, [1](#f1) with the addition of: @@ -125,7 +128,8 @@ A rough algorithm follows: 2. Generate a summary and add it to `rooms`. 3. Add any `m.space.child` events in the room to `events`. 4. Recurse into the targets of the `m.space.child` events. - 1. If the room is inaccessible (as defined by [room history visibility](https://matrix.org/docs/spec/client_server/latest#id87)) + 1. If the user is not joined to the room and is not joinable (as defined by + [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173)) or has already been processed, do not process it. 2. Generate a summary for the room and add it to `rooms`. 3. Add any `m.space.child` events of the room to `events`. @@ -194,8 +198,45 @@ This is largely the same as the Client-Server API, but differences are: key). * If the target server is not a member of the root room, an empty response is returned. -* Currently, no consideration is given to room membership: the spaces/rooms - must be world-readable (ie, peekable) for them to appear in the results. +* The spaces/rooms must be joinable by the server for them to appear in the + results. + +Since the server-server API does not know the user who is requesting a summary of +the space, the response should divulge the above information if any member of a +requesting server could see it. The requesting server is trusted to properly +filter this information. + +If a room delegates access to a space (via [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083)) +and there are any users on the requesting server in the correct space, the requesting +server has a right to know about the rooms in that space and should return the +relevant summaries, along with enough information that the requesting server can +then do the necessary filtering. + +Consider that Alice and Bob share a server; Alice is a member of a space, but Bob +is not. The remote server will not know whether the request is on behalf of Alice +or Bob (and hence whether it should share details of restricted rooms within that +space). + +Consider the above with a restricted room on a different server which defers +access to the above space. When summarizing the space, the homeserver must make +a request over federation for information on the room. The response would include +the room (since Alice is able to join it), but the calling server does not know +*why* they received the room, without additional information the server cannot +properly filter the returned results. + +Note that there are still potential situations where each server individually +doesn't have enough information to properly return the full summary, but these +do not seem reasonable in what is considered a normal structure of spaces. (E.g. +in the above example, if the remote server is not in the space and does not know +whether the server is in the space or not it cannot return the room.) + +(The alternative, where the calling server sends the requesting `user_id`, and +the target server does the filtering, is unattractive because it rules out a +future world where the calling server can cache the result.) + +This does not decrease security since a server could lie and make a request on +behalf of a user in the proper space to see the given information. I.e. the +calling server must be trusted anyway. ## Potential issues From a7a08ebc8b067f411a9b0b9ab5b277b5b04f4548 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 2 Jul 2021 08:15:10 -0400 Subject: [PATCH 45/77] Updates per MSC2403. --- proposals/2946-spaces-summary.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 393abb867af..fc9e65b5a42 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -59,6 +59,7 @@ Example response: "num_joined_members": 37, "topic": "Tasty tasty cheese", "world_readable": true, + "join_rules": "public", "room_type": "m.space", "allowed_spaces": ["!abcdef:bleecker.street"] }, @@ -101,8 +102,6 @@ Response fields: with the addition of: * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. - * **`allowed_room_ids`**: A list of room IDs which give access to this room per - [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083). * **`events`**: `m.space.child` events of the returned rooms. For each event, only the following fields are returned: `type`, `state_key`, `content`, `room_id`, `sender`, [1](#f1) with the addition of: @@ -185,6 +184,12 @@ Request parameters are the same as the Client-Server API, with the addition of: * **`exclude_rooms`**: Optional. A list of room IDs that can be omitted from the response. +Response fields are the same as the Client-Server API, with the addition of: + +* **`rooms`**: Each room contains an additional field: + * **`allowed_room_ids`**: A list of room IDs which give access to this room per + [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083). + This is largely the same as the Client-Server API, but differences are: * The calling server can specify a list of spaces/rooms to omit from the From 094de302aefa8dd6a07ac947b0186061ae64960c Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 27 Jul 2021 14:36:15 -0400 Subject: [PATCH 46/77] Remove field which is not part of the C-S API. --- proposals/2946-spaces-summary.md | 1 - 1 file changed, 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index fc9e65b5a42..6ab7c1f1859 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -61,7 +61,6 @@ Example response: "world_readable": true, "join_rules": "public", "room_type": "m.space", - "allowed_spaces": ["!abcdef:bleecker.street"] }, { ... } ], From c0a63abb3fc69b8b0b60d007ebfdb46786a8fb3c Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 28 Jul 2021 10:18:30 -0400 Subject: [PATCH 47/77] Rewrite the proposal. --- proposals/2946-spaces-summary.md | 378 +++++++++++++++++-------------- 1 file changed, 208 insertions(+), 170 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 6ab7c1f1859..4a94bdb3f6a 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -1,4 +1,4 @@ -## MSC2946: Spaces Summary +# MSC2946: Spaces Summary This MSC depends on [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772), which describes why a Space is useful: @@ -25,7 +25,7 @@ rooms: A new client-server API (and corresponding server-server API) is added which allows for querying for the rooms and spaces contained within a space. This allows a client to efficiently display a hierarchy of rooms to a user (i.e. without having -to walk the full state of the space). +to walk the full state of each room). ### Client-server API @@ -33,20 +33,81 @@ An endpoint is provided to walk the space tree, starting at the provided room ID ("the root room"), and visiting other rooms/spaces found via `m.space.child` events. It recurses into the children and into their children, etc. -Note that only rooms that have a `type` of `m.space` are considered when searching -for `m.space.child` events. +Any child room that the user is joined or is potentially joinable (TODO REF) is included +in the response. When a room with a `type` of `m.space` is found, it is searched +for valid `m.space.child` events to recurse into. + +In order to provide a consistent experience, the space tree should be walked in +a depth-first manner, e.g. whenever a space is found it should be recursed into +by sorting the children rooms and iterating through them. + +There could be loops in the returned child events; clients and servers should +handle this gracefully. Similarly, note that a child room might appear multiple +times (e.g. also be a grandchild). Clients and servers should handle this +appropriately. This endpoint requires authentication and is not subject to rate-limiting. -Example request: +TODO Define pagination + +#### Request format + +```text +GET /_matrix/client/r0/rooms/{roomID}/spaces +``` + +Query Parameters: + +* **`suggested_only`**: Optional. If `true`, return only child events and rooms + where the `m.space.child` event has `suggested: true`. Must be a boolean, + defaults to `false`. + + This applies transitively, i.e. if a `suggested_only` is `true` and a space is + not suggested then it should not be searched for children. The inverse is also + true, if a space is suggested, but a child of that space is not then the child + should not be included. +* **`limit`**: Optional: a client-defined limit to the maximum + number of rooms to return per page. Must be a non-negative integer. + + Server implementations should impose a maximum value to avoid resource + exhaustion. +* **`max_depth`**: Optional: The maximum depth in the tree (from the root room) + to return. The deepest depth returned will not include children events. Defaults + to no-limit. Must be a non-negative integer. + + Server implementations may wish to impose a maximum value to avoid resource + exhaustion. +* **`from`**: Optional. Pagination token given to retrieve the next set of rooms. + +#### Response Format + +* **`rooms`**: `[object]` For each room/space, starting with the root room, a + summary of that room. The fields are the same as those returned by + `/publicRooms` (see + [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), + with the addition of: + * **`room_type`**: the value of the `m.type` field from the room's + `m.room.create` event, if any. + * **`children_state`**: The `m.space.child` events of the room. For each event, + only the following fields are included[1](#f1): + `type`, `state_key`, `content`, `room_id`, `sender`, with the addition of: + * **`creation_ts`**: the value of the `origin_server_ts` field from the + `m.space.child` event. This is required for sorting of rooms as specified + below. +* **`next_token`**: Optional `string`. The token to supply in the `from` param + of the next `/spaces` request in order to request more rooms. If this is absent, + there are no more results. + +#### Example request: ```text GET /_matrix/client/r0/rooms/{roomID}/spaces? - max_rooms_per_space=5& - suggested_only=true + limit=30& + suggested_only=true& + max_depth=4 ``` -Example response: +#### Example response: ```jsonc { @@ -61,104 +122,70 @@ Example response: "world_readable": true, "join_rules": "public", "room_type": "m.space", + "children_state": [ + { + "type": "m.space.child", + "state_key": "!efgh:example.com", + "content": { + "via": ["example.com"], + "suggested": true + }, + "room_id": "!ol19s:bleecker.street", + "sender": "@alice:bleecker.street", + "creation_ts": 1432735824653 + }, + { ... } + ] }, { ... } ], - "events": [ - { - "type": "m.space.child", - "state_key": "!efgh:example.com", - "content": { - "via": ["example.com"], - "suggested": true - }, - "room_id": "!ol19s:bleecker.street", - "sender": "@alice:bleecker.street", - "creation_ts": 1432735824653 - }, - { ... } - ] + "next_token": "abcdef" } ``` -Request params: +#### Errors: -* **`suggested_only`**: Optional. If `true`, return only child events and rooms where the - `m.space.child` event has `suggested: true`. Must be a boolean, defaults to `false`. -* **`max_rooms_per_space`**: Optional: a client-defined limit to the maximum - number of children to return per space. Doesn't apply to the root space (ie, - the `room_id` in the request). Must be a non-negative integer. +An HTTP response with a status code of 403 and an error code of `M_FORBIDDEN` +should be returned if the user doesn't have permission to view/peek the root room. +This should also be returned if that room does not exist, which matches the +behavior of other room endpoints (e.g. +[`/_matrix/client/r0/rooms/{roomID}/aliases`](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-rooms-roomid-aliases)) +to not divulge that a room exists which the user doesn't have permission to view. - Server implementations should impose a maximum value to avoid resource - exhaustion. +An HTTP response with a status code of 400 and an error code of `M_INVALID_PARAM` +should be returned if the `from` token provided is unknown to the server. -Response fields: +#### Client behaviour -* **`rooms`**: for each room/space, starting with the root room, a - summary of that room. The fields are the same as those returned by - `/publicRooms` (see - [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), - with the addition of: - * **`room_type`**: the value of the `m.type` field from the room's - `m.room.create` event, if any. -* **`events`**: `m.space.child` events of the returned rooms. For each event, only the - following fields are returned: `type`, `state_key`, `content`, `room_id`, - `sender`, [1](#f1) with the addition of: - * **`creation_ts`**: the value of the `origin_server_ts` field from the - `m.space.child` event. This is required for sorting of rooms as specified - in [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) and updated - below. - -Errors: - -403 with an error code of `M_FORBIDDEN`: if the user doesn't have permission to -view/peek the root room (including if that room does not exist). This matches the -behavior of other room endpoints (e.g. -[`/_matrix/client/r0/rooms/{roomID}/aliases`](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-rooms-roomid-aliases)). -To not divulge whether the user doesn't have permission vs whether the room -does not exist. - -#### Algorithm - -A rough algorithm follows: - -1. Start at the "root" room (the provided room ID). -2. Generate a summary and add it to `rooms`. -3. Add any `m.space.child` events in the room to `events`. -4. Recurse into the targets of the `m.space.child` events. - 1. If the user is not joined to the room and is not joinable (as defined by - [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173)) - or has already been processed, do not process it. - 2. Generate a summary for the room and add it to `rooms`. - 3. Add any `m.space.child` events of the room to `events`. -5. Recurse into any newly added targets of `m.space.child` events (i.e. repeat - step 4), until either all discovered rooms have been inspected, or the - server-side limit on the number of rooms is reached. - - In the case of the homeserver not having access to the state of a room, the - server-server API (see below) can be used to query for this information over - federation from one of the servers provided in the `via` key of the - `m.space.child` event. - -Other notes: - -* Any inaccessible children are omitted from the result, as well as the - `m.space.child` events that point to them. -* There could be loops in the returned child events - clients (and servers) - should handle this gracefully. -* Similarly, note that a child room might appear multiple times (e.g. also be a - grandchild). Clients and servers should handle this appropriately. -* `suggested_only` applies transitively. - - For example, if a space A has child space B which is *not* suggested, and space - B has suggested child room C, and the client makes a summary request for A with - `suggested_only=true`, neither B **nor** C will be returned. - - Similarly, if a space A has child space B which is suggested, and space B has - suggested child room C which is suggested, and the client makes a summary request - for A with `suggested_only=true`, both B and C will be returned. -* `m.space.child` with an invalid `via` (invalid is defined as missing, not an - array or an empty array) are ignored. +TODO + +#### Server behaviour + +The server should generate the response as discussed above, by doing a depth-first +search (starting at the "root" room) for any `m.space.child` events. Any +`m.space.child` with an invalid `via` are discarded (invalid is defined as in +[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772): missing, not an +array or an empty array). + +In the case of the homeserver not having access to the state of a room, the +server-server API (see below) can be used to query for this information over +federation from one of the servers provided in the `via` key of the +`m.space.child` event. It is recommended to cache the federation response for a +period of time and to prefer local data over data returned over federation. + +When the current response page is full, the current state should be persisted +and a pagination token should be generated (if there is more data to return). +If the client does not request the next page after a short period of time the +persisted data may be discarded to limit resource usage. It maybe possible to +generate reusable pagination tokens (i.e. sharable across users), but this is +left as an implementation specific detail. + +The persisted state will generally include: + +* Any processed rooms (and whether the requesting user is able to join them). +* A queue of rooms to process (in depth-first order with rooms at the same level + ordered according to below). +* Pending information from the latest federation response. ### Server-server API @@ -166,87 +193,71 @@ The Server-Server API has almost the same interface as the Client-Server API. It is used when a homeserver does not have the state of a room to include in the summary. -Example request: +The main difference is that it does *not* recurse into spaces and does not support +pagination. This is somewhat equivalent to a Client-Server request with a `max_depth=1`. -```jsonc -GET /_matrix/federation/v1/spaces/{roomID}? - exclude_rooms=%21a%3Ab& - exclude_rooms=%21b%3Ac& - max_rooms_per_space=5& - suggested_only=true& +If the requesting server wishes to explore a sub-space an additional federation +request can be made for any returned spaces. This should allow for trivially caching +responses. + +Since the server-server API does not know the requesting user, the response should +divulge the information if any member of the requesting server could join the room. +The requesting server is trusted to properly filter this information. + +* If the target server is not a member of some children rooms (so would have to + send another request over federation to inspect them), no attempt is made to + recurse into them. - they are simply omitted from the `rooms` key of the + response. (Although they will still appear in the `children_state`key of + another room). + + TODO How do we tell the difference between a room the server does not know about + and a room that the requester is not allowed to know about. + +#### Request format + +```text +GET /_matrix/federation/v1/spaces/{roomID} ``` -The response has the same shape as the Client-Server API. +Query Parameters: -Request parameters are the same as the Client-Server API, with the addition of: +* **`suggested_only`**: The same as the Client-Server API. -* **`exclude_rooms`**: Optional. A list of room IDs that can be omitted - from the response. +TODO Do we need any server limits here? -Response fields are the same as the Client-Server API, with the addition of: +#### Response format -* **`rooms`**: Each room contains an additional field: +The response format is similar to the Client-Server API: + +* **`rooms`**: `[object]` The same as the Client-Server API with an additional + field: * **`allowed_room_ids`**: A list of room IDs which give access to this room per - [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083). - -This is largely the same as the Client-Server API, but differences are: - -* The calling server can specify a list of spaces/rooms to omit from the - response (via `exclude_rooms`). -* `max_rooms_per_space` applies to the root room as well as any returned - children. -* If the target server is not a member of any discovered children (so - would have to send another request over federation to inspect them), no - attempt is made to recurse into them - they" are simply omitted from the - `rooms` key of the response. (Although they will still appear in the `events` - key). - * If the target server is not a member of the root room, an empty - response is returned. -* The spaces/rooms must be joinable by the server for them to appear in the - results. - -Since the server-server API does not know the user who is requesting a summary of -the space, the response should divulge the above information if any member of a -requesting server could see it. The requesting server is trusted to properly -filter this information. - -If a room delegates access to a space (via [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083)) -and there are any users on the requesting server in the correct space, the requesting -server has a right to know about the rooms in that space and should return the -relevant summaries, along with enough information that the requesting server can -then do the necessary filtering. - -Consider that Alice and Bob share a server; Alice is a member of a space, but Bob -is not. The remote server will not know whether the request is on behalf of Alice -or Bob (and hence whether it should share details of restricted rooms within that -space). - -Consider the above with a restricted room on a different server which defers -access to the above space. When summarizing the space, the homeserver must make -a request over federation for information on the room. The response would include -the room (since Alice is able to join it), but the calling server does not know -*why* they received the room, without additional information the server cannot -properly filter the returned results. + [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[2](#f2) +* **`unknown_rooms`**: Optional `[string]`. A list of room IDs which are children + of the requested room, but the target server is not a member of. The requesting + server may need to request information about them from *other* servers. -Note that there are still potential situations where each server individually -doesn't have enough information to properly return the full summary, but these -do not seem reasonable in what is considered a normal structure of spaces. (E.g. -in the above example, if the remote server is not in the space and does not know -whether the server is in the space or not it cannot return the room.) + This is used to differentiate between rooms which the requesting server does + not have access to (which will simply be missing in the response) vs. those + that the target server cannot include in the response. + +#### Example request: + +```jsonc +GET /_matrix/federation/v1/spaces/{roomID}? + suggested_only=true +``` -(The alternative, where the calling server sends the requesting `user_id`, and -the target server does the filtering, is unattractive because it rules out a -future world where the calling server can cache the result.) +#### Errors: -This does not decrease security since a server could lie and make a request on -behalf of a user in the proper space to see the given information. I.e. the -calling server must be trusted anyway. +An HTTP response with a status code of 404 is returned if the target server is +not a member of the requested room. + +TODO How to differentiate between unknown vs. unaccessible rooms. ## Potential issues -To reduce complexity, only a limited number of rooms are returned for a room, -no effort is made to paginate the results. Proper pagination is left to a future -MSC. +TODO ### MSC1772 Ordering @@ -310,25 +321,33 @@ age of the relationship. ## Alternatives -An initial version of this followed both `m.space.child` and `m.space.parent` events, -but this is unnecessary to provide the expected user experience. +Peeking to explore the room state could be used to build the tree of rooms/spaces, +but this would be significantly more expensive for both clients and servers. It +would also require peeking over federation (which is explored in +[MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444)). ## Security considerations A space with many rooms on different homeservers could cause multiple federation -requests to be made. A carefully crafted room with inadequate limits on the maximum -rooms per space (or a maximum total number of rooms) could be used in a denial -of service attack. +requests to be made. A carefully crafted room with inadequate server enforced +limits could be used in a denial of service attack. + +The requesting server over federation is trusted to filter the response for the +requesting user. The alternative, where the requesting server sends the requesting +`user_id`, and the target server does the filtering, is unattractive because it +rules out a caching of the result. This does not decrease security since a server +could lie and make a request on behalf of a user in the proper space to see the +given information. I.e. the calling server must be trusted anyway. ## Unstable prefix During development of this feature it will be available at unstable endpoints. The client-server API will be: -`/_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/spaces` +`/_matrix/client/unstable/org.matrix.msc2946.v2/rooms/{roomID}/spaces` The server-server API will be: -`/_matrix/federation/unstable/org.matrix.msc2946/spaces/{roomID}` +`/_matrix/federation/unstable/org.matrix.msc2946.v2/spaces/{roomID}` ## Footnotes @@ -336,3 +355,22 @@ The server-server API will be: potential dataleaks (e.g. timestamps, `prev_content`, etc.) and to ensure that clients do not treat any of this data as authoritative (e.g. if it came back over federation). The data should not be persisted as actual events.[↩](#a1) + +[2]: As a worked example, in the context of +[MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083), consider that Alice +and Bob share a server; Alice is a member of a space, but Bob is not. A remote +server will not know whether the request is on behalf of Alice or Bob (and hence +whether it should share details of restricted rooms within that space). + +Consider if the space is modified to include a restricted room on a different server +which allows access from the space. When summarizing the space, the homeserver must make +a request over federation for information on the room. The response should include +the room (since Alice is able to join it). Without additional information the +calling server does not know *why* they received the room and cannot properly +filter the returned results. + +Note that there are still potential situations where each server individually +doesn't have enough information to properly return the full summary, but these +do not seem reasonable in what is considered a normal structure of spaces. (E.g. +in the above example, if the remote server is not in the space and does not know +whether the server is in the space or not it cannot return the room.)[↩](#a2) From 3d7769fc8ffe02f18d186fffc2314d7582d9f070 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 28 Jul 2021 10:30:51 -0400 Subject: [PATCH 48/77] Handle todo comments. --- proposals/2946-spaces-summary.md | 45 +++++++++++++++----------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 4a94bdb3f6a..537dd3b9f58 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -33,8 +33,9 @@ An endpoint is provided to walk the space tree, starting at the provided room ID ("the root room"), and visiting other rooms/spaces found via `m.space.child` events. It recurses into the children and into their children, etc. -Any child room that the user is joined or is potentially joinable (TODO REF) is included -in the response. When a room with a `type` of `m.space` is found, it is searched +Any child room that the user is joined or is potentially joinable (per +[MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173)) is included in +the response. When a room with a `type` of `m.space` is found, it is searched for valid `m.space.child` events to recurse into. In order to provide a consistent experience, the space tree should be walked in @@ -48,8 +49,6 @@ appropriately. This endpoint requires authentication and is not subject to rate-limiting. -TODO Define pagination - #### Request format ```text @@ -204,14 +203,13 @@ Since the server-server API does not know the requesting user, the response shou divulge the information if any member of the requesting server could join the room. The requesting server is trusted to properly filter this information. -* If the target server is not a member of some children rooms (so would have to - send another request over federation to inspect them), no attempt is made to - recurse into them. - they are simply omitted from the `rooms` key of the - response. (Although they will still appear in the `children_state`key of - another room). - - TODO How do we tell the difference between a room the server does not know about - and a room that the requester is not allowed to know about. +If the target server is not a member of some children rooms (so would have to send +another request over federation to inspect them), no attempt is made to recurse +into them. They are simply omitted from the `rooms` key of the response. +(Although they will still appear in the `children_state`key of another room). + +Similarly, if a server set limit on the size of the response is reached, additional +rooms are not added to the response and can be queried individually. #### Request format @@ -223,8 +221,6 @@ Query Parameters: * **`suggested_only`**: The same as the Client-Server API. -TODO Do we need any server limits here? - #### Response format The response format is similar to the Client-Server API: @@ -251,13 +247,8 @@ GET /_matrix/federation/v1/spaces/{roomID}? #### Errors: An HTTP response with a status code of 404 is returned if the target server is -not a member of the requested room. - -TODO How to differentiate between unknown vs. unaccessible rooms. - -## Potential issues - -TODO +not a member of the requested room or the requesting server is not allowed to +access the room. ### MSC1772 Ordering @@ -319,6 +310,11 @@ for a defined sorting of siblings based purely on the information available in the `m.space.child` event while still allowing for a natural ordering due to the age of the relationship. +## Potential issues + +A large flat space (a single room with many `m.space.child` events) could cause +a large federation response + ## Alternatives Peeking to explore the room state could be used to build the tree of rooms/spaces, @@ -328,9 +324,10 @@ would also require peeking over federation (which is explored in ## Security considerations -A space with many rooms on different homeservers could cause multiple federation -requests to be made. A carefully crafted room with inadequate server enforced -limits could be used in a denial of service attack. +A space with many sub-spaces and rooms on different homeservers could cause +a large number of federation requests. A carefully crafted space with inadequate +server enforced limits could be used in a denial of service attack. Generally +this is mitigated by enforcing server limits and caching of responses. The requesting server over federation is trusted to filter the response for the requesting user. The alternative, where the requesting server sends the requesting From 562772187c630c31c0df621999db21032c0bda4b Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 29 Jul 2021 13:40:48 -0400 Subject: [PATCH 49/77] Update URLs. --- proposals/2946-spaces-summary.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 537dd3b9f58..2c10373a350 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -52,7 +52,7 @@ This endpoint requires authentication and is not subject to rate-limiting. #### Request format ```text -GET /_matrix/client/r0/rooms/{roomID}/spaces +GET /_matrix/client/r0/rooms/{roomID}/hierarchy ``` Query Parameters: @@ -100,7 +100,7 @@ Query Parameters: #### Example request: ```text -GET /_matrix/client/r0/rooms/{roomID}/spaces? +GET /_matrix/client/r0/rooms/{roomID}/hierarchy? limit=30& suggested_only=true& max_depth=4 @@ -214,7 +214,7 @@ rooms are not added to the response and can be queried individually. #### Request format ```text -GET /_matrix/federation/v1/spaces/{roomID} +GET /_matrix/federation/v1/hierarchy/{roomID} ``` Query Parameters: @@ -240,7 +240,7 @@ The response format is similar to the Client-Server API: #### Example request: ```jsonc -GET /_matrix/federation/v1/spaces/{roomID}? +GET /_matrix/federation/v1/hierarchy/{roomID}? suggested_only=true ``` @@ -341,10 +341,10 @@ given information. I.e. the calling server must be trusted anyway. During development of this feature it will be available at unstable endpoints. The client-server API will be: -`/_matrix/client/unstable/org.matrix.msc2946.v2/rooms/{roomID}/spaces` +`/_matrix/client/unstable/org.matrix.msc2946/rooms/{roomID}/hierarchy` The server-server API will be: -`/_matrix/federation/unstable/org.matrix.msc2946.v2/spaces/{roomID}` +`/_matrix/federation/unstable/org.matrix.msc2946/hierarchy/{roomID}` ## Footnotes From 7d0c8f6789456b715e4ace5d5868c8dc6f17f6be Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 29 Jul 2021 13:40:55 -0400 Subject: [PATCH 50/77] Rename field. --- proposals/2946-spaces-summary.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 2c10373a350..c1e5e528758 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -90,8 +90,7 @@ Query Parameters: * **`children_state`**: The `m.space.child` events of the room. For each event, only the following fields are included[1](#f1): `type`, `state_key`, `content`, `room_id`, `sender`, with the addition of: - * **`creation_ts`**: the value of the `origin_server_ts` field from the - `m.space.child` event. This is required for sorting of rooms as specified + * **`origin_server_ts`**: This is required for sorting of rooms as specified below. * **`next_token`**: Optional `string`. The token to supply in the `from` param of the next `/spaces` request in order to request more rooms. If this is absent, From 420d698ca35bdf37b913dcb4028048de7fd51558 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 9 Aug 2021 11:05:06 -0400 Subject: [PATCH 51/77] Updates based on implementation. --- proposals/2946-spaces-summary.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index c1e5e528758..11838ab1552 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -187,9 +187,8 @@ The persisted state will generally include: ### Server-server API -The Server-Server API has almost the same interface as the Client-Server API. -It is used when a homeserver does not have the state of a room to include in the -summary. +The Server-Server API has a similar interface to the Client-Server API. It is +used when a homeserver does not have the state of a room to include in the summary. The main difference is that it does *not* recurse into spaces and does not support pagination. This is somewhat equivalent to a Client-Server request with a `max_depth=1`. @@ -224,17 +223,25 @@ Query Parameters: The response format is similar to the Client-Server API: -* **`rooms`**: `[object]` The same as the Client-Server API with an additional - field: +* **`room`**: `[obejct]` The summary of the requested room. +* **`children`**: `[object]` For each room/space, a summary of that room. The fields + are the same as those returned by `/publicRooms` (see + [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), + with the addition of: + * **`room_type`**: the value of the `m.type` field from the room's + `m.room.create` event, if any. * **`allowed_room_ids`**: A list of room IDs which give access to this room per - [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[2](#f2) -* **`unknown_rooms`**: Optional `[string]`. A list of room IDs which are children - of the requested room, but the target server is not a member of. The requesting - server may need to request information about them from *other* servers. - + [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[2](#f2)* **`next_token`**: Optional `string`. The token to supply in the `from` param + of the next `/spaces` request in order to request more rooms. If this is absent, + there are no more results. +* **`inaccessible_children`**: Optional `[string]`. A list of room IDs which are + children of the requested room, but are inaccessible to the requesting server. + The requesting server should not attempt to request information about them + from other servers. + This is used to differentiate between rooms which the requesting server does - not have access to (which will simply be missing in the response) vs. those - that the target server cannot include in the response. + not have access to from those that the target server cannot include in the + response (which will simply be missing in the response). #### Example request: From 5cd0db43ff093cf3990f6c698e4a371d3c7fdf1d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 10 Aug 2021 14:36:46 -0400 Subject: [PATCH 52/77] Clarify the state which is persisted. --- proposals/2946-spaces-summary.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 11838ab1552..0e851d297f6 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -180,10 +180,10 @@ left as an implementation specific detail. The persisted state will generally include: -* Any processed rooms (and whether the requesting user is able to join them). +* Any processed rooms. * A queue of rooms to process (in depth-first order with rooms at the same level ordered according to below). -* Pending information from the latest federation response. +* Pending information from federation responses. ### Server-server API @@ -238,7 +238,7 @@ The response format is similar to the Client-Server API: children of the requested room, but are inaccessible to the requesting server. The requesting server should not attempt to request information about them from other servers. - + This is used to differentiate between rooms which the requesting server does not have access to from those that the target server cannot include in the response (which will simply be missing in the response). From 14bdc42c5d592c763b4c5c225fd45177cd92ce7f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 10 Aug 2021 14:47:42 -0400 Subject: [PATCH 53/77] Expand notes about errors. --- proposals/2946-spaces-summary.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 0e851d297f6..ef54e6a193c 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -78,6 +78,9 @@ Query Parameters: exhaustion. * **`from`**: Optional. Pagination token given to retrieve the next set of rooms. + Note that if a pagination token is provided, then the parameters given for + `suggested_only` and `max_depth` must be the same. + #### Response Format * **`rooms`**: `[object]` For each room/space, starting with the root room, a @@ -151,7 +154,8 @@ behavior of other room endpoints (e.g. to not divulge that a room exists which the user doesn't have permission to view. An HTTP response with a status code of 400 and an error code of `M_INVALID_PARAM` -should be returned if the `from` token provided is unknown to the server. +should be returned if the `from` token provided is unknown to the server or if +the `suggested_only` or `max_depth` parameters are modified during pagination. #### Client behaviour From 00d3d67971e4e929639cc2ec096487f500aefd7e Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 11 Aug 2021 07:43:20 -0400 Subject: [PATCH 54/77] Update MSC with pagination parameter. --- proposals/2946-spaces-summary.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index ef54e6a193c..bf4a2361e19 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -95,7 +95,7 @@ Query Parameters: `type`, `state_key`, `content`, `room_id`, `sender`, with the addition of: * **`origin_server_ts`**: This is required for sorting of rooms as specified below. -* **`next_token`**: Optional `string`. The token to supply in the `from` param +* **`next_batch`**: Optional `string`. The token to supply in the `from` param of the next `/spaces` request in order to request more rooms. If this is absent, there are no more results. @@ -140,7 +140,7 @@ GET /_matrix/client/r0/rooms/{roomID}/hierarchy? }, { ... } ], - "next_token": "abcdef" + "next_batch": "abcdef" } ``` @@ -235,9 +235,7 @@ The response format is similar to the Client-Server API: * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. * **`allowed_room_ids`**: A list of room IDs which give access to this room per - [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[2](#f2)* **`next_token`**: Optional `string`. The token to supply in the `from` param - of the next `/spaces` request in order to request more rooms. If this is absent, - there are no more results. + [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[2](#f2) * **`inaccessible_children`**: Optional `[string]`. A list of room IDs which are children of the requested room, but are inaccessible to the requesting server. The requesting server should not attempt to request information about them From e39eac30bcec3fcd589e51ea31e5edecf206db8c Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 13 Aug 2021 07:19:04 -0400 Subject: [PATCH 55/77] Fix wrong endpoint. Co-authored-by: Matthew Hodgson --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index bf4a2361e19..b5a9a93fe60 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -96,7 +96,7 @@ Query Parameters: * **`origin_server_ts`**: This is required for sorting of rooms as specified below. * **`next_batch`**: Optional `string`. The token to supply in the `from` param - of the next `/spaces` request in order to request more rooms. If this is absent, + of the next `/hierarchy` request in order to request more rooms. If this is absent, there are no more results. #### Example request: From 68239981bd802fa4e7c4f628561813314b5fdeb1 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 27 Aug 2021 15:18:40 -0400 Subject: [PATCH 56/77] Clarifications based on implementation. --- proposals/2946-spaces-summary.md | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index b5a9a93fe60..47071eb6788 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -178,37 +178,37 @@ period of time and to prefer local data over data returned over federation. When the current response page is full, the current state should be persisted and a pagination token should be generated (if there is more data to return). If the client does not request the next page after a short period of time the -persisted data may be discarded to limit resource usage. It maybe possible to -generate reusable pagination tokens (i.e. sharable across users), but this is -left as an implementation specific detail. +persisted data may be discarded to limit resource usage. -The persisted state will generally include: +The persisted state will includes: -* Any processed rooms. -* A queue of rooms to process (in depth-first order with rooms at the same level - ordered according to below). -* Pending information from federation responses. +* The processed rooms. +* Rooms to process (in depth-first order with rooms at the same depth + ordered according [according to MSC1772, as updated to below](#msc1772-ordering)). +* Room information from federation responses for rooms which have yet to be + processed. ### Server-server API -The Server-Server API has a similar interface to the Client-Server API. It is -used when a homeserver does not have the state of a room to include in the summary. +The Server-Server API has a similar interface to the Client-Server API, but a +simplified response. It is used when a homeserver is not participating in a room +(and cannot summarize room due to not having the state). The main difference is that it does *not* recurse into spaces and does not support pagination. This is somewhat equivalent to a Client-Server request with a `max_depth=1`. -If the requesting server wishes to explore a sub-space an additional federation -request can be made for any returned spaces. This should allow for trivially caching -responses. +Additional federation requests are made to recurse into sub-spaces. This allows +for trivially caching responses for a short period of time (since it is not +easily known the room summary might have changed). Since the server-server API does not know the requesting user, the response should -divulge the information if any member of the requesting server could join the room. -The requesting server is trusted to properly filter this information. +divulge information based on if any member of the requesting server could join +the room. The requesting server is trusted to properly filter this information. If the target server is not a member of some children rooms (so would have to send another request over federation to inspect them), no attempt is made to recurse -into them. They are simply omitted from the `rooms` key of the response. -(Although they will still appear in the `children_state`key of another room). +into them. They are simply omitted from the `children` key of the response. +(Although they will still appear in the `children_state`key of the `room`.) Similarly, if a server set limit on the size of the response is reached, additional rooms are not added to the response and can be queried individually. @@ -227,7 +227,8 @@ Query Parameters: The response format is similar to the Client-Server API: -* **`room`**: `[obejct]` The summary of the requested room. +* **`room`**: `[object]` The summary of the requested room, as given in the + Client-Server API response. * **`children`**: `[object]` For each room/space, a summary of that room. The fields are the same as those returned by `/publicRooms` (see [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), From 5a5a404671357e35a3e8c1a9cabb68106bc73622 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 7 Sep 2021 12:38:27 -0400 Subject: [PATCH 57/77] Remove empty section. --- proposals/2946-spaces-summary.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 47071eb6788..6a0ba7f2200 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -157,10 +157,6 @@ An HTTP response with a status code of 400 and an error code of `M_INVALID_PARAM should be returned if the `from` token provided is unknown to the server or if the `suggested_only` or `max_depth` parameters are modified during pagination. -#### Client behaviour - -TODO - #### Server behaviour The server should generate the response as discussed above, by doing a depth-first From 01743482beeab42a7389dc0a279fe1d0989afebd Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 10 Sep 2021 08:38:09 -0400 Subject: [PATCH 58/77] Fix typo. Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 6a0ba7f2200..69ffbb28e28 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -176,7 +176,7 @@ and a pagination token should be generated (if there is more data to return). If the client does not request the next page after a short period of time the persisted data may be discarded to limit resource usage. -The persisted state will includes: +The persisted state will include: * The processed rooms. * Rooms to process (in depth-first order with rooms at the same depth From 545ff90b733de432d078ee1a61158227b5d830d8 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 21 Sep 2021 08:32:18 -0400 Subject: [PATCH 59/77] Rename field in example. --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 69ffbb28e28..93a9fd39b0c 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -133,7 +133,7 @@ GET /_matrix/client/r0/rooms/{roomID}/hierarchy? }, "room_id": "!ol19s:bleecker.street", "sender": "@alice:bleecker.street", - "creation_ts": 1432735824653 + "origin_server_ts": 1432735824653 }, { ... } ] From 42ba46ed28dbf9526d911d462e1290bb8bb9d9bc Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 21 Sep 2021 08:36:17 -0400 Subject: [PATCH 60/77] Clarify error code. --- proposals/2946-spaces-summary.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 93a9fd39b0c..819cb4a2a54 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -251,9 +251,9 @@ GET /_matrix/federation/v1/hierarchy/{roomID}? #### Errors: -An HTTP response with a status code of 404 is returned if the target server is -not a member of the requested room or the requesting server is not allowed to -access the room. +An HTTP response with a status code of 404 and an error code of `M_NOT_FOUND` is +returned if the target server is not a member of the requested room or the +requesting server is not allowed to access the room. ### MSC1772 Ordering From dee3b2d6976f2ad23dcc2b87c63a797d5b9178ba Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 21 Sep 2021 08:40:18 -0400 Subject: [PATCH 61/77] Clarify ordering changes. --- proposals/2946-spaces-summary.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 819cb4a2a54..9432f4a6ebd 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -288,10 +288,10 @@ Space A, Room B, and Room C are on HS1, while Room D is on HS2. HS1 has no users in Room D (and thus has no state from it). Room B, C, and D do not have an `order` field set (and default to using the ordering rules above). -When a user asks HS1 for the space summary with a `max_rooms_per_space` equal to -`2` it cannot fulfill this request since it is unsure how to order Room B, Room -C, and Room D, but it can only return 2 of them. It *can* reach out over -federation to HS2 and request a space summary for Room D, but this is undesirable: +When a user asks HS1 for the space summary with a `limit` equal to `2` it cannot +fulfill this request since it is unsure how to order Room B, Room C, and Room D, +but it can only return 2 of them. It *can* reach out over federation to HS2 and +request a space summary for Room D, but this is undesirable: * HS1 might not have the permissions to know any of the state of Room D, so might receive a 403 error. @@ -309,10 +309,10 @@ This proposes changing the ordering rules from MSC1772 to the following: > more than 50 characters, are forbidden and the field should be ignored if > received. -This modifies the clauses for calculating the `origin_server_ts` of the -`m.room.create` event to refer to the `m.space.child` event instead. This allows +This modifies the clause for calculating the order to use the `origin_server_ts` +of the `m.space.child` event instead of the `m.room.create` event.. This allows for a defined sorting of siblings based purely on the information available in -the `m.space.child` event while still allowing for a natural ordering due to the +the state of the space while still allowing for a natural ordering due to the age of the relationship. ## Potential issues From a9803c3ae7155755835aefaac3caffb6a4be7f50 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 28 Sep 2021 18:21:35 -0400 Subject: [PATCH 62/77] Clarify wording. Co-authored-by: Travis Ralston --- proposals/2946-spaces-summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 9432f4a6ebd..a3b5bfa881c 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -235,8 +235,8 @@ The response format is similar to the Client-Server API: [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[2](#f2) * **`inaccessible_children`**: Optional `[string]`. A list of room IDs which are children of the requested room, but are inaccessible to the requesting server. - The requesting server should not attempt to request information about them - from other servers. + Other servers are unlikely to have information about them as well, thus the + requesting server can consider the rooms inaccessible from everywhere. This is used to differentiate between rooms which the requesting server does not have access to from those that the target server cannot include in the From e9592fff34d37df061b98e575f3dbc08427eed5f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 29 Sep 2021 14:22:41 -0400 Subject: [PATCH 63/77] Fix typos. Co-authored-by: Hubert Chathi --- proposals/2946-spaces-summary.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index a3b5bfa881c..121f0beb337 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -180,7 +180,7 @@ The persisted state will include: * The processed rooms. * Rooms to process (in depth-first order with rooms at the same depth - ordered according [according to MSC1772, as updated to below](#msc1772-ordering)). + ordered [according to MSC1772, as updated to below](#msc1772-ordering)). * Room information from federation responses for rooms which have yet to be processed. @@ -206,7 +206,7 @@ another request over federation to inspect them), no attempt is made to recurse into them. They are simply omitted from the `children` key of the response. (Although they will still appear in the `children_state`key of the `room`.) -Similarly, if a server set limit on the size of the response is reached, additional +Similarly, if a server-set limit on the size of the response is reached, additional rooms are not added to the response and can be queried individually. #### Request format @@ -310,7 +310,7 @@ This proposes changing the ordering rules from MSC1772 to the following: > received. This modifies the clause for calculating the order to use the `origin_server_ts` -of the `m.space.child` event instead of the `m.room.create` event.. This allows +of the `m.space.child` event instead of the `m.room.create` event. This allows for a defined sorting of siblings based purely on the information available in the state of the space while still allowing for a natural ordering due to the age of the relationship. @@ -318,7 +318,7 @@ age of the relationship. ## Potential issues A large flat space (a single room with many `m.space.child` events) could cause -a large federation response +a large federation response. ## Alternatives From 8978562464f643c48838f6d6a0f8376308b47bf9 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 29 Sep 2021 14:34:01 -0400 Subject: [PATCH 64/77] Clarify that rooms do not belong to servers. Co-authored-by: Hubert Chathi --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 121f0beb337..749e52ac1ed 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -284,7 +284,7 @@ Consider the following case of a space with 3 child rooms: Room B Room C Room D ``` -Space A, Room B, and Room C are on HS1, while Room D is on HS2. HS1 has no users +HS1 has users in Space A, Room B, and Room C, while HS2 has users in Room D. HS1 has no users in Room D (and thus has no state from it). Room B, C, and D do not have an `order` field set (and default to using the ordering rules above). From 622f8eda98f3bb4ea62a1614a38e6cca3d54e1f2 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 29 Sep 2021 14:34:50 -0400 Subject: [PATCH 65/77] Fix example to use correct URL. Co-authored-by: Hubert Chathi --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 749e52ac1ed..478b172a3ca 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -102,7 +102,7 @@ Query Parameters: #### Example request: ```text -GET /_matrix/client/r0/rooms/{roomID}/hierarchy? +GET /_matrix/client/r0/rooms/%21ol19s%3Ableecker.street/hierarchy? limit=30& suggested_only=true& max_depth=4 From 6ad9ead1b61b7b4bbe1c4e47e35f78ab29738402 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 29 Sep 2021 15:00:39 -0400 Subject: [PATCH 66/77] Clarify using local vs. remote data. Co-authored-by: Hubert Chathi --- proposals/2946-spaces-summary.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 478b172a3ca..e9f1498d3c5 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -169,7 +169,10 @@ In the case of the homeserver not having access to the state of a room, the server-server API (see below) can be used to query for this information over federation from one of the servers provided in the `via` key of the `m.space.child` event. It is recommended to cache the federation response for a -period of time and to prefer local data over data returned over federation. +period of time. The federation results may contain information on a room +that the requesting server is already participating in; the requesting server +should use its local data for such rooms rather than the data returned over +federation. When the current response page is full, the current state should be persisted and a pagination token should be generated (if there is more data to return). From 482597e9b7a1cbd92d9c64955aadd6b2b1fe3db0 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 29 Sep 2021 14:58:56 -0400 Subject: [PATCH 67/77] Clarify bits aboud stripped state. --- proposals/2946-spaces-summary.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index e9f1498d3c5..3369efaa43f 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -90,9 +90,9 @@ Query Parameters: with the addition of: * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. - * **`children_state`**: The `m.space.child` events of the room. For each event, - only the following fields are included[1](#f1): - `type`, `state_key`, `content`, `room_id`, `sender`, with the addition of: + * **`children_state`**: The stripped state of the `m.space.child` events of + the room per [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173). + In addition to the standard stripped state fields, the following is included: * **`origin_server_ts`**: This is required for sorting of rooms as specified below. * **`next_batch`**: Optional `string`. The token to supply in the `from` param @@ -235,7 +235,7 @@ The response format is similar to the Client-Server API: * **`room_type`**: the value of the `m.type` field from the room's `m.room.create` event, if any. * **`allowed_room_ids`**: A list of room IDs which give access to this room per - [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[2](#f2) + [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[1](#f1) * **`inaccessible_children`**: Optional `[string]`. A list of room IDs which are children of the requested room, but are inaccessible to the requesting server. Other servers are unlikely to have information about them as well, thus the @@ -356,12 +356,7 @@ The server-server API will be: ## Footnotes -[1]: The rationale for including stripped events here is to reduce -potential dataleaks (e.g. timestamps, `prev_content`, etc.) and to ensure that -clients do not treat any of this data as authoritative (e.g. if it came back -over federation). The data should not be persisted as actual events.[↩](#a1) - -[2]: As a worked example, in the context of +[1]: As a worked example, in the context of [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083), consider that Alice and Bob share a server; Alice is a member of a space, but Bob is not. A remote server will not know whether the request is on behalf of Alice or Bob (and hence @@ -378,4 +373,4 @@ Note that there are still potential situations where each server individually doesn't have enough information to properly return the full summary, but these do not seem reasonable in what is considered a normal structure of spaces. (E.g. in the above example, if the remote server is not in the space and does not know -whether the server is in the space or not it cannot return the room.)[↩](#a2) +whether the server is in the space or not it cannot return the room.)[↩](#a1) From 41bfaa5ead4ee2ffaaaebaadf67caa95679e976a Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 29 Sep 2021 15:02:16 -0400 Subject: [PATCH 68/77] Clarify access control of federation responses. --- proposals/2946-spaces-summary.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 3369efaa43f..af126064dc8 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -202,7 +202,9 @@ easily known the room summary might have changed). Since the server-server API does not know the requesting user, the response should divulge information based on if any member of the requesting server could join -the room. The requesting server is trusted to properly filter this information. +the room. The requesting server is trusted to properly filter this information +using the `world_readable`, `join_rules`, and `allowed_room_ids` fields from the +response. If the target server is not a member of some children rooms (so would have to send another request over federation to inspect them), no attempt is made to recurse From f6f41b18628eb50fb14a05ad02eb4bd07ca28ec0 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 29 Sep 2021 15:07:01 -0400 Subject: [PATCH 69/77] Clarify error code. Co-authored-by: Hubert Chathi --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index af126064dc8..28317e11cbf 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -299,7 +299,7 @@ but it can only return 2 of them. It *can* reach out over federation to HS2 and request a space summary for Room D, but this is undesirable: * HS1 might not have the permissions to know any of the state of Room D, so might - receive a 403 error. + receive a 404 error. * If we expand the example above to many rooms than this becomes expensive to query a remote server simply for ordering. From 828c0760ee651d1d974bb8c09ed69b12690e71f7 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 5 Oct 2021 12:51:24 -0400 Subject: [PATCH 70/77] Be less prescriptive about expiring data. --- proposals/2946-spaces-summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 28317e11cbf..7e4addb8985 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -176,8 +176,8 @@ federation. When the current response page is full, the current state should be persisted and a pagination token should be generated (if there is more data to return). -If the client does not request the next page after a short period of time the -persisted data may be discarded to limit resource usage. +To prevent resource exhaustion, the server may expire persisted data that it +deems to be stale. The persisted state will include: From 7fd45e5064e0e5918d513674fb4138fa06b33b3f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 6 Oct 2021 12:12:24 -0400 Subject: [PATCH 71/77] Limit must be non-zero. Co-authored-by: Travis Ralston --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 7e4addb8985..d0f899c5353 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -66,7 +66,7 @@ Query Parameters: true, if a space is suggested, but a child of that space is not then the child should not be included. * **`limit`**: Optional: a client-defined limit to the maximum - number of rooms to return per page. Must be a non-negative integer. + number of rooms to return per page. Must an integer greater than zero. Server implementations should impose a maximum value to avoid resource exhaustion. From 902a12415f384be1092570deb362755efaaddf62 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 6 Oct 2021 14:54:21 -0400 Subject: [PATCH 72/77] Rate limiting. Co-authored-by: Travis Ralston --- proposals/2946-spaces-summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index d0f899c5353..b19f8314d88 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -47,7 +47,7 @@ handle this gracefully. Similarly, note that a child room might appear multiple times (e.g. also be a grandchild). Clients and servers should handle this appropriately. -This endpoint requires authentication and is not subject to rate-limiting. +This endpoint requires authentication and is subject to rate-limiting. #### Request format From bf5f84d9350e6e61e2e9404af271e407ac710285 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 6 Oct 2021 15:14:47 -0400 Subject: [PATCH 73/77] Add a note about room upgrades. --- proposals/2946-spaces-summary.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index b19f8314d88..5b4d661b7bc 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -325,6 +325,13 @@ age of the relationship. A large flat space (a single room with many `m.space.child` events) could cause a large federation response. +Room version upgrades of rooms in a space are unsolved and left to a future MSC. +When upgrading a room it is unclear if the old room should be removed (in which +case users who have not yet joined the new room will no longer see it in the space) +or leave the old room (in which case users who have joined the new room will see +both). The current recommendation is for clients de-duplicate rooms which are +known old versions of rooms in the space. + ## Alternatives Peeking to explore the room state could be used to build the tree of rooms/spaces, From b43333a9381fb4bd1711f88f0f6c35231d21c808 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 12 Oct 2021 13:16:15 -0400 Subject: [PATCH 74/77] Update stable URLs per MSC2844. --- proposals/2946-spaces-summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 5b4d661b7bc..93712b62660 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -52,7 +52,7 @@ This endpoint requires authentication and is subject to rate-limiting. #### Request format ```text -GET /_matrix/client/r0/rooms/{roomID}/hierarchy +GET /_matrix/client/v1/rooms/{roomID}/hierarchy ``` Query Parameters: @@ -102,7 +102,7 @@ Query Parameters: #### Example request: ```text -GET /_matrix/client/r0/rooms/%21ol19s%3Ableecker.street/hierarchy? +GET /_matrix/client/v1/rooms/%21ol19s%3Ableecker.street/hierarchy? limit=30& suggested_only=true& max_depth=4 From c74adf7389b6d646b4de13103efedd677923e3c1 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 12 Oct 2021 13:44:27 -0400 Subject: [PATCH 75/77] Clarify federation return values. --- proposals/2946-spaces-summary.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 93712b62660..635ddd0b8c9 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -228,16 +228,9 @@ Query Parameters: The response format is similar to the Client-Server API: -* **`room`**: `[object]` The summary of the requested room, as given in the - Client-Server API response. -* **`children`**: `[object]` For each room/space, a summary of that room. The fields - are the same as those returned by `/publicRooms` (see - [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), - with the addition of: - * **`room_type`**: the value of the `m.type` field from the room's - `m.room.create` event, if any. - * **`allowed_room_ids`**: A list of room IDs which give access to this room per - [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[1](#f1) +* **`room`**: `object` The summary of the requested room, see below for details. +* **`children`**: `[object]` For each room/space, a summary of that room, see + below for details. * **`inaccessible_children`**: Optional `[string]`. A list of room IDs which are children of the requested room, but are inaccessible to the requesting server. Other servers are unlikely to have information about them as well, thus the @@ -247,6 +240,15 @@ The response format is similar to the Client-Server API: not have access to from those that the target server cannot include in the response (which will simply be missing in the response). +For both the `room` and `children` fields the summary of the room/space includes +the fields returned by `/publicRooms` (see [spec](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)), +with the addition of: + +* **`room_type`**: the value of the `m.type` field from the room's `m.room.create` + event, if any. +* **`allowed_room_ids`**: A list of room IDs which give access to this room per + [MSC3083](https://github.com/matrix-org/matrix-doc/pull/3083).[1](#f1) + #### Example request: ```jsonc From fe5a9a73d665881a38148b66126f50b0eb194163 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 26 Oct 2021 11:02:21 -0400 Subject: [PATCH 76/77] Clarify `origin_server_ts`. Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- proposals/2946-spaces-summary.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 635ddd0b8c9..0f26af439a7 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -93,8 +93,9 @@ Query Parameters: * **`children_state`**: The stripped state of the `m.space.child` events of the room per [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173). In addition to the standard stripped state fields, the following is included: - * **`origin_server_ts`**: This is required for sorting of rooms as specified - below. + * **`origin_server_ts`**: `integer`. The `origin_server_ts` field from the + room's `m.space.child` event. This is required for sorting of rooms as + specified below. * **`next_batch`**: Optional `string`. The token to supply in the `from` param of the next `/hierarchy` request in order to request more rooms. If this is absent, there are no more results. From a9f6cf6bb3b8e7921fc88973e424912f3237d01b Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 26 Oct 2021 12:00:30 -0400 Subject: [PATCH 77/77] Tweak wording around `inaccessible_children`. --- proposals/2946-spaces-summary.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proposals/2946-spaces-summary.md b/proposals/2946-spaces-summary.md index 0f26af439a7..fc0c136b8cc 100644 --- a/proposals/2946-spaces-summary.md +++ b/proposals/2946-spaces-summary.md @@ -234,8 +234,9 @@ The response format is similar to the Client-Server API: below for details. * **`inaccessible_children`**: Optional `[string]`. A list of room IDs which are children of the requested room, but are inaccessible to the requesting server. - Other servers are unlikely to have information about them as well, thus the - requesting server can consider the rooms inaccessible from everywhere. + Assuming the target server is non-malicious and well-behaved, then other + non-malicious servers should respond with the same set of inaccessible rooms. + Thus the requesting server can consider the rooms inaccessible from everywhere. This is used to differentiate between rooms which the requesting server does not have access to from those that the target server cannot include in the