Skip to content

Commit e39f38a

Browse files
deepbluev7anoadragon453KitsuneRalrichvdhclokep
authored andcommitted
MSC3266: Room summary API (#3266)
* Room summary proposal Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Remove alias resolution step from the federation API * Reference #688 in the alternatives section Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Remove `is_direct` from response Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Fix unstable prefixes for implementations which keep the prefix and rest of the path separate Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Add allowed_room_ids field That way the requesting server knows, if any user would have access to that room and it can forward the room to the user. Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Extend rationale for additional fields to reference MSC2946 Also explain that membership is already accessible information. Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Add bulk API as an alternative Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Remove federation API and address feedback - Add some additional rationale to some things. - Federation API now reuses MSC 2946 - roomid -> roomId - Move it out of /rooms, because it allows using an alias Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * fix prefixes again * Remove extensions to federation API since that MSC is amended now Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Fix minor inaccuracy about the spaces sumary api * Add encryption field back * Add room version field Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Apply suggestions from code review Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Co-authored-by: Alexey Rusakov <Kitsune-Ral@users.sf.net> * Add a bit more reasoning * version -> room_version * Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Try to address review comments Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Fix incorrect statement about encryption being a bool Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> * Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Split up the big alternatives section * Collapse the same descriptions for publicRooms and hierarchy into one * Shorten the 'accessible' section again * Update proposals/3266-room-summary.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/3266-room-summary.md * Update proposals/3266-room-summary.md Co-authored-by: Alexey Rusakov <Kitsune-Ral@users.sf.net> * Support knock_restricted rooms and rename to room_summary As well as a few smaller clarifications. * Be more explicit about authentication * Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com> * Fix error codes and missing "Optional" * Also add allowed_room_ids to hierarchy API It suffers from the same knock_restricted issue. * Apply suggestions from code review Co-authored-by: Eric Eastwood <madlittlemods@gmail.com> Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com> * Update spec links * Clarify accessibility rules * Update proposals/3266-room-summary.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update proposals/3266-room-summary.md Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> * Unauthenticated access is impl-dependent * add to response * Clarify resposnse documentation. * Clarify situation for invited rooms * further clarification about unauth access * Update proposals/3266-room-summary.md Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> --------- Signed-off-by: Nicolas Werner <nicolas.werner@hotmail.de> Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Co-authored-by: Alexey Rusakov <Kitsune-Ral@users.sf.net> Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com> Co-authored-by: Eric Eastwood <madlittlemods@gmail.com> Co-authored-by: Richard van der Hoff <richard@matrix.org> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org>
1 parent a15271b commit e39f38a

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed

proposals/3266-room-summary.md

+312
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
# MSC3266: Room Summary API
2+
3+
Quite a few clients and tools have a need to preview a room:
4+
5+
- matrix.to may want to show avatar and name of a room.
6+
- Nextcloud may want to list the names and avatars of your `/joined_rooms` when
7+
asking where to share the media.
8+
- A client may want to preview a room, when hovering a room alias, id or after
9+
clicking on it.
10+
- A client may want to preview a room, when the user is trying to knock on it or
11+
to show pending knocks.
12+
- A traveller bot may use that to show a room summary on demand without actually
13+
keeping the whole room state around and having to subscribe to /sync (or
14+
using the appservice API).
15+
- A client can use this to knock on a room instead of joining it when the user
16+
tries to join my room alias or link.
17+
- External services can use this API to preview rooms like shields.io.
18+
19+
There are a few ways to request a room summary, but they only support some of
20+
the use cases. The [spaces hierarchy API](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv1roomsroomidhierarchy) only provides
21+
limited control over what rooms to summarize and returns a lot more data than
22+
necessary. `{roomid}/initialSync` and `{roomid}/state/{event_type}` don't work
23+
over federation and are much heavier than necessary or need a lot of http calls
24+
for each room.
25+
26+
## Proposal
27+
28+
A new client-server API, which allows you to fetch a summary of a room by id or
29+
alias.
30+
31+
### Client-Server API
32+
33+
The API returns a summary of the given room, provided the user is either already
34+
a member, or has the necessary permissions to join. (For example, the user may
35+
be a member of a room mentioned in an `allow` condition in the join rules of a
36+
restricted room.)
37+
38+
For unauthenticated requests a response should only be returned if the room is
39+
publicly accessible; specifically, that means either:
40+
* the room has `join_rule: public` or `join_rule: knock`, or:
41+
* the room has `history_visibility: world_readable`.
42+
43+
Note that rooms the user has been invited to or knocked at might result in
44+
outdated or partial information, or even a 404 `M_NOT_FOUND` response, since
45+
the the homeserver may not have access to the current state of the room. (In
46+
particular: the federation API does not provide a mechanism to get the current
47+
state of a non-publically-joinable room where the requesting server has no
48+
joined members. Improving this is left for a future MSC.)
49+
50+
A request could look like this:
51+
52+
```
53+
GET /_matrix/client/v1/room_summary/{roomIdOrAlias}?
54+
via=matrix.org&
55+
via=neko.dev
56+
```
57+
58+
(This is not under `/rooms`, because it can be used with an alias.)
59+
60+
- `roomIdOrAlias` can be the roomid or an alias to a room.
61+
- `via` are servers that should be tried to request a summary from, if it can't
62+
be generated locally. These can be from a matrix URI, matrix.to link or a
63+
`m.space.child` event for example.
64+
65+
A successful `200` response should contain a JSON object giving information about the room. For example:
66+
67+
```json5
68+
{
69+
room_id: "!ol19s:bleecker.street",
70+
avatar_url: "mxc://bleecker.street/CHEDDARandBRIE",
71+
guest_can_join: false,
72+
name: "CHEESE",
73+
num_joined_members: 37,
74+
topic: "Tasty tasty cheese",
75+
world_readable: true,
76+
join_rule: "public",
77+
room_type: "m.space",
78+
membership: "invite",
79+
encryption: "m.megolm.v100",
80+
room_version: "9001",
81+
}
82+
```
83+
84+
See below for a more detailed description of the response.
85+
86+
#### Unauthenticated and guest access
87+
88+
This API may optionally be exposed to unauthenticated users, or guest users, at the choice of
89+
server implementations and administrators. Clients MUST NOT rely on being able
90+
to use the endpoint without authentication, and should degrade gracefully if
91+
access is denied.
92+
93+
* Rationale: unauthenticated access is beneficial for third-party services such as
94+
https://matrix.to. On the other hand, allowing unauthenticated access may leak
95+
information about rooms that would otherwise be restricted to registered users (particularly
96+
on servers which do not allow public federation), and may lead to unexpected
97+
resource usage.
98+
99+
Servers may rate limit how often they fetch information over federation more heavily, if the
100+
user is unauthenticated.
101+
102+
When the endpoint is called unauthenticated, the `membership` field will be
103+
absent in the response.
104+
105+
As mentioned above, a successful response should only be returned for
106+
unauthenticated requests where the room is publicly accessible.
107+
108+
#### Response format
109+
110+
If the room cannot be found, the server should return a `404`
111+
HTTP status code along with an `M_NOT_FOUND` error code. The server should
112+
NOT return `M_UNAUTHORIZED` or otherwise divulge existence of a room, that
113+
requires authentication to preview, if the request is unauthenticated or
114+
authenticated by a user without access to the room.
115+
116+
If the request is successful, the server returns a JSON object containing the
117+
following properties:
118+
119+
| property name | description |
120+
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
121+
| avatar_url | Optional. Avatar of the room |
122+
| canonical_alias | Optional. The canonical alias of the room, if any. |
123+
| guest_can_join | Required. Whether guests can join the room. |
124+
| join_rule | Optional. Join rules of the room |
125+
| name | Optional. Name of the room |
126+
| num_joined_members | Required. Member count of the room |
127+
| room_id | Required. Id of the room |
128+
| room_type | Optional. Type of the room, if any, i.e. `m.space` |
129+
| topic | Optional. Topic of the room |
130+
| world_readable | Required. If the room history can be read without joining. |
131+
| allowed_room_ids | Optional. If the room is a restricted room, these are the room IDs which are specified by the join rules. Empty or omitted otherwise. |
132+
| encryption | Optional. If the room is encrypted, this specifies the algorithm used for this room. Otherwise, omitted. |
133+
| membership | Optional (1). The current membership of this user in the room. Usually `leave` if the server has no local users (so fetches the room over federation). |
134+
| room_version | Optional (for historical reasons (2)). Version of the room. |
135+
136+
(1) The `membership` field will not be present when called unauthenticated, but
137+
is required when called authenticated.
138+
139+
(2) Prior to this MSC, `/_matrix/federation/v1/hierarchy/{roomId}` doesn't
140+
return the room version, so `room_version` may be unavailable for remote
141+
rooms.
142+
143+
Most of the fields above are the same as those returned by
144+
[`/_matrix/client/v3/publicRooms`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv3publicrooms). (Those
145+
same fields are also a subset of those returned by
146+
[`/_matrix/client/v1/rooms/{roomId}/hierarchy`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv1roomsroomidhierarchy).) The
147+
exceptions are:
148+
149+
* `allowed_room_ids`. This is currently accessible via the federation
150+
hierarchy endpoint [`GET
151+
/_matrix/federation/v1/hierarchy/{roomId}`](https://spec.matrix.org/v1.13/server-server-api/#get_matrixfederationv1hierarchyroomid),
152+
and is necessary
153+
to distinguish if the room can be joined or only knocked at.
154+
155+
* `encryption`. Currently part of the [stripped
156+
state](https://spec.matrix.org/v1.13/client-server-api/#stripped-state). Some
157+
users may only want to join encrypted rooms; alternatively, clients may want to filter
158+
out encrypted rooms, for example if they don't support encryption, or do not
159+
support particular encryption algorithms.
160+
161+
* `membership`. Exposed solely for convenience: a client has many other ways
162+
to access this information.
163+
164+
* `room_version`. Also part of the [stripped
165+
state](https://spec.matrix.org/v1.13/client-server-api/#stripped-state).
166+
Can be used by clients to show incompatibilities with a room early.
167+
168+
#### Modifications to `/_matrix/client/v1/rooms/{roomId}/hierarchy`
169+
170+
For symmetry the `room_version`, `allowed_room_ids` and `encryption` fields are
171+
also added to the `/hierarchy` API.
172+
173+
### Server-Server API
174+
175+
For fetching room summaries of a room a server is not joined to, the federation API of the
176+
[`/hierarchy`](https://spec.matrix.org/v1.13/server-server-api/#get_matrixfederationv1hierarchyroomid)
177+
endpoint is reused. This provides (with a few changes) all the information
178+
needed in this MSC, but it also provides a few additional fields and one level
179+
of children of this room.
180+
181+
Additionally the `encryption` and `room_version` fields are added to the
182+
responses for each room.
183+
184+
In theory one could also add the `max_depth` parameter with allowed values of 0
185+
and 1, so that child rooms are excluded, but this performance optimization does
186+
not seem necessary at this time and could be added at any later point while
187+
degrading gracefully.
188+
189+
(Originally there was a separate federation API for this, but it was decided by
190+
the author that lowering the duplication on the federation side is the way to
191+
go.)
192+
193+
## Potential issues
194+
195+
### Performance
196+
197+
Clients may start calling this API very often instead of using the
198+
[`/hierarchy`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv1roomsroomidhierarchy)
199+
for spaces or caching the state received via `/sync`.
200+
Looking up all the state events required for this API may cause performance
201+
issues in that case.
202+
203+
To mitigate that, servers are recommended to cache the response for this API and
204+
apply rate limiting if necessary.
205+
206+
## Alternatives
207+
208+
### The Space Summary / `/hierarchy` API
209+
210+
The
211+
[`/hierarchy`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv1roomsroomidhierarchy)
212+
API could be used, but it returns more data than necessary by default (but it
213+
can be limited to just 1 room) such as all the `m.space.child` events in a
214+
space, but also is missing the room version, membership and the encryption
215+
field.
216+
217+
Additionally the `/hierarchy` API doesn't work using aliases. This currently
218+
doesn't allow users to preview rooms not known to the local server over
219+
federation. While the user can resolve the alias and then call the `/hierarchy`
220+
API using the resolved roomid, a roomid is not a routable entity, so the server
221+
never receives the information which servers to ask about the requested rooms.
222+
This MSC resolves that by providing a way to pass server names to ask for the
223+
room as well as the alias directly.
224+
225+
For server to server communication the efficiency is not as important, which is
226+
why we use the same API as the `/hierarchy` API to fetch the data over
227+
federation.
228+
229+
### The `sync` API
230+
231+
For joined rooms, the `/sync` API can be used to get a summary for all joined
232+
rooms. Apart from not working for unjoined rooms, like knocks, invites and space
233+
children, `/sync` is very heavy for the server and the client needs to cobble
234+
together information from the `state`, `timeline` and
235+
[`summary`](https://github.com/matrix-org/matrix-doc/issues/688) sections to
236+
calculate the room name, topic and other fields provided in this MSC.
237+
238+
Furthermore, the membership counts in the summary field are only included, if
239+
the client is using lazy loading. This MSC provides similar information as
240+
calling `/sync`, but to allow it to work for unjoined rooms it only uses information
241+
from the stripped state. Additionally, it excludes `m.heroes` as well as membership
242+
events, since those are not included in the stripped state of a room. (A client
243+
can call `/joined_members` to receive those if needed. It may still make sense
244+
to include heroes so that clients could construct a human-friendly room display
245+
name in case both the name and the canonical alias are absent; but solving the
246+
security implications with that may better be left to a separate MSC.)
247+
248+
### The `/state` API
249+
250+
The `/state` API could be used, but the response is much bigger than needed,
251+
can't be cached as easily and may need more requests. This also doesn't work
252+
over federation (yet). The variant of this API, which returns the full state of
253+
a room, also does not return stripped events, which prevents it from being used
254+
by non-members. The event for specific events DOES return stripped events, but
255+
could not provide a member count for a room.
256+
257+
### Proper peeking
258+
259+
Peeking could solve this too, but with additional overhead and
260+
[MSC2753](https://github.com/matrix-org/matrix-doc/pull/2753) is much more
261+
complex. You need to add a peek and remember to remove it. For many usecases you
262+
just want to do one request to get info about a room, no history and no updates.
263+
This MSC solves that by reusing the existing hierarchy APIs, returns a
264+
lightweight response and provides a convenient API instead.
265+
266+
### A more batched API
267+
268+
This API could take a list of rooms with included `via`s for each room instead
269+
of a single room (as a POST request). This may have performance benefits for the
270+
federation API and a client could then easily request a summary of all joined
271+
rooms. It could still request the summary of a single room by just including
272+
only a single room in the POST or a convenience GET could be provided by the
273+
server (that looks like this proposal). At the same time, a batched API is inherently
274+
more complex to implement for both clients and servers. Additionally, there are no
275+
known use cases yet that would benefit from batched access.
276+
277+
### MSC3429: Individual room preview API (closed)
278+
279+
[MSC3429](https://github.com/matrix-org/matrix-doc/pull/3429) is an alternative
280+
implementation, but it chooses a different layout. While this layout might make
281+
sense in the future, it is inconsistent with the APIs already in use, harder to
282+
use for clients (iterate array over directly including the interesting fields)
283+
and can't reuse the federation API. In my opinion an MSC in the future, that
284+
bases all summary APIs on a list of stripped events seems like the more
285+
reasonable approach to me and would make the APIs more extensible.
286+
287+
## Security considerations
288+
289+
This API may leak data, if implemented incorrectly or malicious servers could
290+
return wrong results for a summary.
291+
292+
Those are the same concerns as on [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946)
293+
or [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173).
294+
295+
This API could also be used for denial of service type attacks. Appropriate
296+
ratelimiting and caching should be able to mitigate that.
297+
298+
## Unstable prefix
299+
300+
This uses the `im.nheko.summary` unstable prefix. As such the paths are prefixed
301+
with `unstable/im.nheko.summary`.
302+
303+
- the client API will be
304+
`/_matrix/client/unstable/im.nheko.summary/summary/{roomIdOrAlias}`.
305+
306+
Some implementations still use
307+
`/_matrix/client/unstable/im.nheko.summary/rooms/{roomIdOrAlias}/summary`,
308+
but this was a mistake in this MSC. Endpoints using aliases shouldn't be under /rooms.
309+
310+
Additionally the fields `encryption` and `room_version` in the summaries are
311+
prefixed with `im.nheko.summary` as well since it is new. The latter might still
312+
be called `im.nheko.summary.version` in some implementations.

0 commit comments

Comments
 (0)