From 6c499db3baefdbb8de2a2241062decced04f46e0 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 3 Jan 2019 18:49:30 +0000 Subject: [PATCH 01/88] WIP groups as rooms MSC --- proposals/1772-groups-as-rooms.md | 166 ++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 proposals/1772-groups-as-rooms.md diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md new file mode 100644 index 00000000..c4fc2353 --- /dev/null +++ b/proposals/1772-groups-as-rooms.md @@ -0,0 +1,166 @@ +# Proposal for groups as rooms (take 2) + +This obsoletes MSC1215. + +## Problem + +The current groups API has some serious issues: + * It is a large API surface to implement, maintain and spec - particularly for + all the different clients out there. + * Much of the API overlaps significantly with mechanisms we already have for + managing rooms: + * Tracking membership identity + * Tracking membership hierarchy + * Inviting/kicking/banning user + * Tracking key/value metadata + * There are membership management features which could benefit rooms which + would also benefit groups and vice versa (e.g. "auditorium mode") + * The current implementations on Riot Web/iOS/Android all suffer bugs and + issues which have been solved previously for rooms. + * no local-echo of invites + * failures to set group avatars + * ability to specify multiple admins + * It doesn't support pushing updates to clients (particularly for flair + membership): https://github.com/vector-im/riot-web/issues/5235 + * It doesn't support third party invites. + * Groups could benefit from other features which already exist today for rooms + * e.g. Room Directories + * Groups are centralised, rather than being existing across multiple + participating servers. + +## Solution + +Represent groups by rooms rather than a custom first-class entity. + +We reserve aliases which begin with a `+` to represent groups - e.g. the room +for group `+test:example.com` is `#+test:example.com`. + +We introduce a `m.room.groups` state event which defines how a room should +behave as a group - i.e. the rooms which it groups together, and any subgroups +nested within it. + +```json +{ + "type": "m.room.groups", + "contents": { + "rooms": [ + { + "room": "#room1:example.com", + }, + { + "room": "#room2:example.com", + "autojoin": true + }, + { + "room": "#room3:example.com", + }, + ], + "subgroups": [ + { + "group": "+something:example.com", + }, + { + "group": "+otherthing:example.com", + }, + ] + }, +} +``` + +Name, Topic, Membership etc share the same events as a normal room. + +The flair for a group is given by the room avatar. + +Long description requires a new event: `m.room.description`. This can also be +used for rooms as well as groups. + +Groups may be nested, and membership of groups is defined as the union of the +members of the group room and its subgroups. If `+top:example.com` has two +subgroups, the user membership of `+top:example.com` is the union of the +subgroups and the group itself. This allows hierarchies of groups & users to be +defined. + +Clients peek in rooms (recursing into subgroups as needed) in order to determine +group membership. + +Invites, 3PID invites, Power Levels etc all work as for a normal room. + +Normal messages within the room could be showed and used as a 'lobby' area for +the given group. + +This requires no server changes at all, other than better support for peeking +(see Dependencies below), and could allow the existing /groups API to be +deprecated and removed outright. + +## ACLs + +Currently the group server has total control over specifying the list of users +who may be present in a group, as seen by a given querying user. In other words, +arbitrary users can see entirely different views of a group at the server's +discretion. + +Whilst this is very powerful for mapping arbitrary group structures into Matrix, +it may be overengineered. + +Instead, the common case is wanting to define a group where some users are +publicly visible as members, and others are not. This is what the current use +cases require today. A simple way of achieving would be to create a subgroup +for the private members - e.g. have +sensitive:matrix.org and +sensitive- +private:matrix.org. The membership of `+sensitive-private:matrix.org` is set up +with `m.room.join_rules` to not to allow peeking; you have to be joined to see +the members, and users who don't want to be seen by the public to be member of +the group are added to the subgroup. + +XXX: is there a use case today for having a group where users are unaware of the +other users' membership? e.g. if I am a member of `+scandalous:matrix.org` +should i have a way to stop other members knowing that I am? One solution here +could be "auditorium mode", where users cannot see other users' identities +(unless they speak). This could be added later, however, and would also be +useful for normal rooms. + +## Flair + +TODO: We need to establish how users should safely advertise their flair. +Perhaps they can claim whatever flair they like on their profile (MSC1769) and +clients need to then doublecheck whether the assertion is true by peeking in the +room in question to check it's true? + +## Dependencies + +This needs peeking to work effectively on CS API. + +This needs peeking to work effectively over federation (e.g. by having servers +join remote rooms as @null:example.com in order to participate in them for +peeking purposes). + +These dependencies are shared with profiles-as-rooms (MSC1769). + +## Security considerations + +XXX: how do we stop cycles & recursion abuse of the subgroups? + +## Tradeoffs + +This consciously sacrifices the ability to delegate group lookups through +to a centralised group server. However, group data can already be stale as we +rely on cached attestations from federated servers to apply ACLs even if the +remote server is not available. So this isn’t much worse than eventually +consistent group membership as you’d find in a room. + +It also means that large groups have to be bridged in their entirety into the +room, rather than querying/searching incrementally. This is something we should +fix for bridged rooms in general too, however. + +This also consciously sacrifices the ability for a group server to provide +different 'views' of groups to different querying users, as being +overengineered. Instead, all common use cases should be modellable by modelling +group memnbership as room membership (nesting if required). + +## Issues + +How does this work with MSC1229 (removing MXIDs)? + +## History + +This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE +Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs \ No newline at end of file From 346f7ac113b12cedc4a3ec574a4be562a5d79a04 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 3 Jan 2019 18:55:06 +0000 Subject: [PATCH 02/88] add hyperlinks --- proposals/1772-groups-as-rooms.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index c4fc2353..ffd4803b 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -1,6 +1,6 @@ # Proposal for groups as rooms (take 2) -This obsoletes MSC1215. +This obsoletes [MSC1215](https://github.com/matrix-org/matrix-doc/issues/1215). ## Problem @@ -121,9 +121,10 @@ useful for normal rooms. ## Flair TODO: We need to establish how users should safely advertise their flair. -Perhaps they can claim whatever flair they like on their profile (MSC1769) and -clients need to then doublecheck whether the assertion is true by peeking in the -room in question to check it's true? +Perhaps they can claim whatever flair they like on their profile +([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769)) and clients +need to then doublecheck whether the assertion is true by peeking in the room in +question to check it's true? ## Dependencies @@ -133,7 +134,8 @@ This needs peeking to work effectively over federation (e.g. by having servers join remote rooms as @null:example.com in order to participate in them for peeking purposes). -These dependencies are shared with profiles-as-rooms (MSC1769). +These dependencies are shared with profiles-as-rooms +([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769)). ## Security considerations @@ -158,7 +160,8 @@ group memnbership as room membership (nesting if required). ## Issues -How does this work with MSC1229 (removing MXIDs)? +How does this work with [MSC1229](https://github.com/matrix-org/matrix- +doc/issues/1229) (removing MXIDs)? ## History From 1e81fbd2d89855cd719e0e8a3d89a75327ed08c9 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 3 Jan 2019 18:55:58 +0000 Subject: [PATCH 03/88] md --- proposals/1772-groups-as-rooms.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index ffd4803b..febf4172 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -105,11 +105,12 @@ it may be overengineered. Instead, the common case is wanting to define a group where some users are publicly visible as members, and others are not. This is what the current use cases require today. A simple way of achieving would be to create a subgroup -for the private members - e.g. have +sensitive:matrix.org and +sensitive- -private:matrix.org. The membership of `+sensitive-private:matrix.org` is set up -with `m.room.join_rules` to not to allow peeking; you have to be joined to see -the members, and users who don't want to be seen by the public to be member of -the group are added to the subgroup. +for the private members - e.g. have `+sensitive:matrix.org` and +`+sensitive-private:matrix.org`. The membership of +`+sensitive-private:matrix.org` is set up with `m.room.join_rules` to not to +allow peeking; you have to be joined to see the members, and users who don't +want to be seen by the public to be member of the group are added to the +subgroup. XXX: is there a use case today for having a group where users are unaware of the other users' membership? e.g. if I am a member of `+scandalous:matrix.org` From a884fd8772fcadc2cb51aa2d13eee5ef50c88225 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 3 Jan 2019 19:07:30 +0000 Subject: [PATCH 04/88] wordwrap fix --- proposals/1772-groups-as-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index febf4172..42262a38 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -161,8 +161,8 @@ group memnbership as room membership (nesting if required). ## Issues -How does this work with [MSC1229](https://github.com/matrix-org/matrix- -doc/issues/1229) (removing MXIDs)? +How does this work with +[MSC1229](https://github.com/matrix-org/matrix-doc/issues/1229) (removing MXIDs)? ## History From 43ae6ad7c1a4a914dd67d9d262986524873a68d5 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 3 Jan 2019 19:07:50 +0000 Subject: [PATCH 05/88] md --- proposals/1772-groups-as-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 42262a38..f8b9a052 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -166,5 +166,5 @@ How does this work with ## History -This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE -Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs \ No newline at end of file + * This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE + * Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs \ No newline at end of file From e00eff567a0b7fb645566a49dd65d5a78619ceee Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 4 Jan 2019 01:43:41 +0000 Subject: [PATCH 06/88] add thought about splitting events --- proposals/1772-groups-as-rooms.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index f8b9a052..f5c7c4e8 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -67,6 +67,10 @@ nested within it. } ``` +XXX: alternatively, perhaps all the rooms and subgroups should be their own +state event with a unique state key, ensuring that this can scale to large +groups and doesn't have to be edited atomically. + Name, Topic, Membership etc share the same events as a normal room. The flair for a group is given by the room avatar. From cd5a8420a8849b980df14df7dcc40c69a21bbbcd Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 6 Jan 2019 00:35:50 +0000 Subject: [PATCH 07/88] flesh out how flair could work --- proposals/1772-groups-as-rooms.md | 37 +++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index f5c7c4e8..dceafc4e 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -73,7 +73,7 @@ groups and doesn't have to be edited atomically. Name, Topic, Membership etc share the same events as a normal room. -The flair for a group is given by the room avatar. +The flair image for a group is given by the room avatar. Long description requires a new event: `m.room.description`. This can also be used for rooms as well as groups. @@ -125,11 +125,34 @@ useful for normal rooms. ## Flair -TODO: We need to establish how users should safely advertise their flair. -Perhaps they can claim whatever flair they like on their profile -([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769)) and clients -need to then doublecheck whether the assertion is true by peeking in the room in -question to check it's true? +A proposal for how to safely determine user flair is: + + * User publishes the groups they wish to announce on their profile + ([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769) + as a m.flair state event: it lists the groups which they are advertising. + + * When a client wants to know the current flair for a set of users (i.e. + those which it is currently displaying in the timeline), it peeks the + profile rooms of those users. However, we can't trust the flair which the + users advertise on the profile - it has to be cross-referenced from the + memberships of the groups in question. + +To do this cross-referencing, options are: + + 1. The client checks the group membership (very inefficient, given the server + could/should do it for them), or... + 2. The server checks the group membership by peeking the group and somehow + decorates the `m.flair` event as validated before sending it to the client. + This is also inefficient, as it forces the server to peek a potentially large + group (unless we extend federation to allow peeking specific state events) + 3. The origin `m.flair` event includes the event_id of the user's + `m.room.membership` event in the group. The server performing the check can + then query this specific event from one of the servers hosting the group-room, + and we perhaps extend the S2S API to say whether a given state event is current + considered current_state or not. If the `m.room.membership` event is confirmed + as current, then the `m.flair` is decorated as being confirmed. + +Of these, option 3 feels best? ## Dependencies @@ -171,4 +194,4 @@ How does this work with ## History * This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE - * Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs \ No newline at end of file + * Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs From 19e94203fa8d05e1423d2044f9c1ed4bdfde0c2e Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 6 Jan 2019 13:51:04 +0000 Subject: [PATCH 08/88] flesh out state events split per state-key for defining groups --- proposals/1772-groups-as-rooms.md | 37 ++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index dceafc4e..aebc41a0 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -69,7 +69,42 @@ nested within it. XXX: alternatively, perhaps all the rooms and subgroups should be their own state event with a unique state key, ensuring that this can scale to large -groups and doesn't have to be edited atomically. +groups and doesn't have to be edited atomically. A key like `present: true` +would be needed to distinguish from a deleted state event. Something like: + +```json +{ + "type": "m.room.group", + "state_key": "#room1:example.com", + "contents": { + "present": true + } +} + +{ + "type": "m.room.group", + "state_key": "#room1:example.com", + "contents": { + "present": true, + "autojoin": true + } +} + +{ + "type": "m.room.subgroup", + "state_key": "+something:example.com", + "contents": { + "present": true + } +} +{ + "type": "m.room.subgroup", + "state_key": "+otherthing:example.com", + "contents": { + "present": true + } +} +``` Name, Topic, Membership etc share the same events as a normal room. From 010246ea6d379d5d7fbdfb038da9aaf29008775a Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 6 Jan 2019 13:56:41 +0000 Subject: [PATCH 09/88] typo --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index aebc41a0..e2ed55fe 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -224,7 +224,7 @@ group memnbership as room membership (nesting if required). ## Issues How does this work with -[MSC1229](https://github.com/matrix-org/matrix-doc/issues/1229) (removing MXIDs)? +[MSC1228](https://github.com/matrix-org/matrix-doc/issues/1228) (removing MXIDs)? ## History From 88ff3de28a03f96e660063bc11cec0524c5e7b82 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 6 Jan 2019 13:57:56 +0000 Subject: [PATCH 10/88] spell out deps --- proposals/1772-groups-as-rooms.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index e2ed55fe..467ccdc6 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -192,10 +192,11 @@ Of these, option 3 feels best? ## Dependencies This needs peeking to work effectively on CS API. +([MSC1776](https://github.com/matrix-org/matrix-doc/issues/1776)) This needs peeking to work effectively over federation (e.g. by having servers join remote rooms as @null:example.com in order to participate in them for -peeking purposes). +peeking purposes) - ([MSC1777](https://github.com/matrix-org/matrix-doc/issues/1777)) These dependencies are shared with profiles-as-rooms ([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769)). From 54bf339ae8b3732b46bf0ac8c772657c1ee6e8cf Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 6 Jan 2019 16:11:54 +0000 Subject: [PATCH 11/88] typo --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 467ccdc6..6e12507f 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -25,7 +25,7 @@ The current groups API has some serious issues: * It doesn't support third party invites. * Groups could benefit from other features which already exist today for rooms * e.g. Room Directories - * Groups are centralised, rather than being existing across multiple + * Groups are centralised, rather than being replicated across all participating servers. ## Solution From 1bbe638927b9bd03f980291a338fd0b19594f15c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 6 Jan 2019 16:59:19 +0000 Subject: [PATCH 12/88] typo --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 6e12507f..8128abda 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -83,7 +83,7 @@ would be needed to distinguish from a deleted state event. Something like: { "type": "m.room.group", - "state_key": "#room1:example.com", + "state_key": "#room2:example.com", "contents": { "present": true, "autojoin": true From 417501d8ccd068069dd8071dc37e792ad006ab01 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 20 Oct 2020 12:00:43 +0100 Subject: [PATCH 13/88] various minor edits --- proposals/1772-groups-as-rooms.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 8128abda..2ad9fdb4 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -108,7 +108,9 @@ would be needed to distinguish from a deleted state event. Something like: Name, Topic, Membership etc share the same events as a normal room. -The flair image for a group is given by the room avatar. +The flair image for a group is given by the room avatar. (In future it might +preferable to use hand-crafted small resolution images: see +[matrix-doc#1778](https://github.com/matrix-org/matrix-doc/issues/1778). Long description requires a new event: `m.room.description`. This can also be used for rooms as well as groups. @@ -165,13 +167,13 @@ A proposal for how to safely determine user flair is: * User publishes the groups they wish to announce on their profile ([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769) as a m.flair state event: it lists the groups which they are advertising. - + * When a client wants to know the current flair for a set of users (i.e. those which it is currently displaying in the timeline), it peeks the profile rooms of those users. However, we can't trust the flair which the users advertise on the profile - it has to be cross-referenced from the memberships of the groups in question. - + To do this cross-referencing, options are: 1. The client checks the group membership (very inefficient, given the server @@ -191,12 +193,12 @@ Of these, option 3 feels best? ## Dependencies -This needs peeking to work effectively on CS API. -([MSC1776](https://github.com/matrix-org/matrix-doc/issues/1776)) +This needs peeking to work effectively over the CS API +([MSC1776](https://github.com/matrix-org/matrix-doc/issues/1776)). This needs peeking to work effectively over federation (e.g. by having servers -join remote rooms as @null:example.com in order to participate in them for -peeking purposes) - ([MSC1777](https://github.com/matrix-org/matrix-doc/issues/1777)) +join remote rooms as `@null:example.com` in order to participate in them for +peeking purposes - [MSC1777](https://github.com/matrix-org/matrix-doc/issues/1777)). These dependencies are shared with profiles-as-rooms ([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769)). @@ -220,13 +222,21 @@ fix for bridged rooms in general too, however. This also consciously sacrifices the ability for a group server to provide different 'views' of groups to different querying users, as being overengineered. Instead, all common use cases should be modellable by modelling -group memnbership as room membership (nesting if required). +group membership as room membership (nesting if required). ## Issues How does this work with [MSC1228](https://github.com/matrix-org/matrix-doc/issues/1228) (removing MXIDs)? +## Unstable prefix + +While this proposal is not in a published version of the specification, +implementations should use `org.matrix.msc1772` to represent the `m` +namespace. For example, `m.room.subgroup` becomes +`org.matrix.msc1772.room.subgroup`. + + ## History * This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE From 96cd76c8681f766c0f25bef4a050979e9745b8d0 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 20 Oct 2020 12:00:53 +0100 Subject: [PATCH 14/88] remove 'one big event' proposal --- proposals/1772-groups-as-rooms.md | 39 +++---------------------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 2ad9fdb4..3c9f8a24 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -35,42 +35,9 @@ Represent groups by rooms rather than a custom first-class entity. We reserve aliases which begin with a `+` to represent groups - e.g. the room for group `+test:example.com` is `#+test:example.com`. -We introduce a `m.room.groups` state event which defines how a room should -behave as a group - i.e. the rooms which it groups together, and any subgroups -nested within it. - -```json -{ - "type": "m.room.groups", - "contents": { - "rooms": [ - { - "room": "#room1:example.com", - }, - { - "room": "#room2:example.com", - "autojoin": true - }, - { - "room": "#room3:example.com", - }, - ], - "subgroups": [ - { - "group": "+something:example.com", - }, - { - "group": "+otherthing:example.com", - }, - ] - }, -} -``` - -XXX: alternatively, perhaps all the rooms and subgroups should be their own -state event with a unique state key, ensuring that this can scale to large -groups and doesn't have to be edited atomically. A key like `present: true` -would be needed to distinguish from a deleted state event. Something like: +We introduce `m.room.group` and `m.room.subgroup` events which define the rooms +and subgroups within the group. A `present: true` key is included to +distinguish from a deleted state event. Something like: ```json { From 0baf49abe8287394bdf1f4ec536b09ab0c3f9474 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 20 Oct 2020 12:12:28 +0100 Subject: [PATCH 15/88] We are not considering hidden-membership rooms yet --- proposals/1772-groups-as-rooms.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 3c9f8a24..777d353b 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -120,12 +120,9 @@ allow peeking; you have to be joined to see the members, and users who don't want to be seen by the public to be member of the group are added to the subgroup. -XXX: is there a use case today for having a group where users are unaware of the -other users' membership? e.g. if I am a member of `+scandalous:matrix.org` -should i have a way to stop other members knowing that I am? One solution here -could be "auditorium mode", where users cannot see other users' identities -(unless they speak). This could be added later, however, and would also be -useful for normal rooms. +In future, there may be a usecase for groups where members are unaware of the +other users' membership. This would also be useful for other rooms, and is left +for a future proposal. ## Flair From 4040254001b94e02dee7a405e59d738ba7c0a116 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 27 Oct 2020 18:15:20 +0000 Subject: [PATCH 16/88] Update for new terminology and current thinking --- proposals/1772-groups-as-rooms.md | 256 +++++++++++++++++------------- 1 file changed, 148 insertions(+), 108 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 777d353b..36f0ff86 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -1,10 +1,25 @@ -# Proposal for groups as rooms (take 2) +# Proposal for Matrix "spaces" (formerly known as "groups as rooms (take 2)") This obsoletes [MSC1215](https://github.com/matrix-org/matrix-doc/issues/1215). -## Problem +## Background and objectives -The current groups API has some serious issues: +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". + +Synapse and Element-Web currently implement an unspecced "groups" API which +attempts to provide this functionality (see +[matrix-doc#1513](https://github.com/matrix-org/matrix-doc/issues/1513)). This +API has some serious issues: * It is a large API surface to implement, maintain and spec - particularly for all the different clients out there. * Much of the API overlaps significantly with mechanisms we already have for @@ -22,26 +37,39 @@ The current groups API has some serious issues: * ability to specify multiple admins * It doesn't support pushing updates to clients (particularly for flair membership): https://github.com/vector-im/riot-web/issues/5235 - * It doesn't support third party invites. + * It doesn't support third-party invites. * Groups could benefit from other features which already exist today for rooms * e.g. Room Directories * Groups are centralised, rather than being replicated across all participating servers. -## Solution +In this document, the existing implementation will be referred to as +"`/r0/groups`". + +This proposal suggests a new approach where spaces are themselves represented +by rooms, rather than a custom first-class entity. This requires few server +changes, other than better support for peeking (see Dependencies below). The +existing `/r0/groups` API would be deprecated in Synapse and remain +unspecified. + +## Proposal + +Each space is represented by its own room, known as a "space-room". The rooms +within the space are determined by state events within the space-room. -Represent groups by rooms rather than a custom first-class entity. +Spaces are referred to primarily by their alias, for example +`#foo:matrix.org`. -We reserve aliases which begin with a `+` to represent groups - e.g. the room -for group `+test:example.com` is `#+test:example.com`. +Space-rooms are distinguished from regular messaging rooms by the `m.room.type` +of `m.space` (see [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840)). -We introduce `m.room.group` and `m.room.subgroup` events which define the rooms -and subgroups within the group. A `present: true` key is included to -distinguish from a deleted state event. Something like: +We introduce an `m.space.child` state event type which defines the rooms within +the group: A `present: true` key is included to distinguish from a deleted +state event. Something like: ```json { - "type": "m.room.group", + "type": "m.space.child", "state_key": "#room1:example.com", "contents": { "present": true @@ -49,144 +77,151 @@ distinguish from a deleted state event. Something like: } { - "type": "m.room.group", + "type": "m.space.child", "state_key": "#room2:example.com", "contents": { "present": true, - "autojoin": true + "autojoin": true # TODO: what does this mean? } } { - "type": "m.room.subgroup", - "state_key": "+something:example.com", - "contents": { - "present": true - } -} -{ - "type": "m.room.subgroup", - "state_key": "+otherthing:example.com", - "contents": { - "present": true - } + "type": "m.space.child", + "state_key": "#oldroom:example.com", + "contents": {} } ``` -Name, Topic, Membership etc share the same events as a normal room. +Space-rooms may have `m.room.name` and `m.room.topic` state events in the same +way as a normal room. -The flair image for a group is given by the room avatar. (In future it might -preferable to use hand-crafted small resolution images: see -[matrix-doc#1778](https://github.com/matrix-org/matrix-doc/issues/1778). +Normal messages within a space-room are discouraged (but not blocked by the +server): user interfaces are not expected to have a way to enter or display +such messages. + +### Membership of spaces + +Users can be members of spaces (represented by `m.room.member` state events as +normal). Depending on the configuration of the space (in particular whether +`m.room.history_visibility` is set to `world_readable` or otherwise), +membership of the space may be required to view the room list, membership list, +etc. -Long description requires a new event: `m.room.description`. This can also be -used for rooms as well as groups. +"Public" or "community" spaces would be set to `world_readable` to allow clients +to see the directory of rooms within the space by peeking into the space-room +(thus avoiding the need to add `m.room.member` events to the event graph within +the room). -Groups may be nested, and membership of groups is defined as the union of the -members of the group room and its subgroups. If `+top:example.com` has two -subgroups, the user membership of `+top:example.com` is the union of the -subgroups and the group itself. This allows hierarchies of groups & users to be -defined. +Join rules, invites and 3PID invites work as for a normal room. -Clients peek in rooms (recursing into subgroups as needed) in order to determine -group membership. +### Long description -Invites, 3PID invites, Power Levels etc all work as for a normal room. +We would like to allow groups to have a long description using rich +formatting. This will use a new state event type `m.room.description` (with +empty `state_key`) whose content is the same format as `m.room.message` (ie, +contains a `msgtype` and possibly `formatted_body`). -Normal messages within the room could be showed and used as a 'lobby' area for -the given group. +TODO: this could also be done via pinned messages. Failing that +`m.room.description` should probably be a separate MSC. -This requires no server changes at all, other than better support for peeking -(see Dependencies below), and could allow the existing /groups API to be -deprecated and removed outright. +### Inheritance of power-levels -## ACLs +TODO -Currently the group server has total control over specifying the list of users -who may be present in a group, as seen by a given querying user. In other words, -arbitrary users can see entirely different views of a group at the server's -discretion. +### Automated joins/leaves -Whilst this is very powerful for mapping arbitrary group structures into Matrix, -it may be overengineered. +TODO -Instead, the common case is wanting to define a group where some users are -publicly visible as members, and others are not. This is what the current use -cases require today. A simple way of achieving would be to create a subgroup -for the private members - e.g. have `+sensitive:matrix.org` and -`+sensitive-private:matrix.org`. The membership of -`+sensitive-private:matrix.org` is set up with `m.room.join_rules` to not to -allow peeking; you have to be joined to see the members, and users who don't -want to be seen by the public to be member of the group are added to the -subgroup. +## Future extensions -In future, there may be a usecase for groups where members are unaware of the -other users' membership. This would also be useful for other rooms, and is left -for a future proposal. +The following sections are not blocking parts of this proposal, but are +included as a useful reference for how we imagine it will be extended in future. -## Flair +### Sub-spaces -A proposal for how to safely determine user flair is: +Questions to be answered here include: - * User publishes the groups they wish to announce on their profile + * Should membership of a sub-space grant any particular access to the parent + space, or vice-versa? We might need to extend `m.room.history_visibility` to + support more flexibility; fortunately this is not involved in event auth so + does not require new room versions. + + * What happens if somebody defines a cycle? (It's probably fine, but anything + interpreting the relationships needs to be careful to limit recursion.) + +### Restricting access to the spaces membership list + +In the existing `/r0/groups` API, the group server has total control over the +visibility of group membership, as seen by a given querying user. In other +words, arbitrary users can see entirely different views of a group at the +server's discretion. + +Whilst this is very powerful for mapping arbitrary organisational structures +into Matrix, it may be overengineered. Instead, the common case is (we believe) +a space where some users are publicly visible as members, and others are not. + +One way to of achieving this would be to create a separate space for the +private members - e.g. have `#foo:matrix.org` and `#foo-private:matrix.org`. +`#foo-private:matrix.org` is set up with `m.room.history_visibility` to not to +allow peeking; you have to be joined to see the members. + +### Flair + +("Flair" is a term we use to describe a small badge which appears next to a +user's displayname to advertise their membership of a space.) + +The flair image for a group is given by the room avatar. (In future it might +preferable to use hand-crafted small resolution images: see +[matrix-doc#1778](https://github.com/matrix-org/matrix-doc/issues/1778). + +One way this might be implemented is: + + * User publishes the spaces they wish to announce on their profile ([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769) - as a m.flair state event: it lists the groups which they are advertising. + as an `m.flair` state event: it lists the spaces which they are advertising. * When a client wants to know the current flair for a set of users (i.e. those which it is currently displaying in the timeline), it peeks the - profile rooms of those users. However, we can't trust the flair which the - users advertise on the profile - it has to be cross-referenced from the - memberships of the groups in question. - -To do this cross-referencing, options are: - - 1. The client checks the group membership (very inefficient, given the server - could/should do it for them), or... - 2. The server checks the group membership by peeking the group and somehow - decorates the `m.flair` event as validated before sending it to the client. - This is also inefficient, as it forces the server to peek a potentially large - group (unless we extend federation to allow peeking specific state events) - 3. The origin `m.flair` event includes the event_id of the user's - `m.room.membership` event in the group. The server performing the check can - then query this specific event from one of the servers hosting the group-room, - and we perhaps extend the S2S API to say whether a given state event is current - considered current_state or not. If the `m.room.membership` event is confirmed - as current, then the `m.flair` is decorated as being confirmed. - -Of these, option 3 feels best? + profile rooms of those users. (Ideally there would be an API to support + peeking multiple rooms at once to facilitate this.) + + * The client must check that the user is *actually* a member of the advertised + spaces. Nominally it can do this by peeking the membership list of the + space; however for efficiency we could expose a dedicated Client-Server API + to do this check (and both servers and clients can cache the results fairly + aggressively.) ## Dependencies -This needs peeking to work effectively over the CS API -([MSC1776](https://github.com/matrix-org/matrix-doc/issues/1776)). + * [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) for room + types. -This needs peeking to work effectively over federation (e.g. by having servers -join remote rooms as `@null:example.com` in order to participate in them for -peeking purposes - [MSC1777](https://github.com/matrix-org/matrix-doc/issues/1777)). + * [MSC1776](https://github.com/matrix-org/matrix-doc/issues/1776) for + effective peeking over the C/S API. + + * [MSC1777](https://github.com/matrix-org/matrix-doc/issues/1777) (or similar) + for effective peeking over Federation. These dependencies are shared with profiles-as-rooms ([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769)). ## Security considerations -XXX: how do we stop cycles & recursion abuse of the subgroups? +* The peek server has significant power. TODO: expand. ## Tradeoffs -This consciously sacrifices the ability to delegate group lookups through -to a centralised group server. However, group data can already be stale as we -rely on cached attestations from federated servers to apply ACLs even if the -remote server is not available. So this isn’t much worse than eventually -consistent group membership as you’d find in a room. +* If the membership of a space would be large (for example: an organisation of + several thousand people), this membership has to copied entirely into the + room, rather than querying/searching incrementally. -It also means that large groups have to be bridged in their entirety into the -room, rather than querying/searching incrementally. This is something we should -fix for bridged rooms in general too, however. + This is particularly problematic if that membership list is based on an + external service such as LDAP, since there is no way to keep the space + membership in sync with the LDAP directory. -This also consciously sacrifices the ability for a group server to provide -different 'views' of groups to different querying users, as being -overengineered. Instead, all common use cases should be modellable by modelling -group membership as room membership (nesting if required). +* No allowance is made for exposing different 'views' of the membership list to + different querying users. (It may be possible to simulate this behaviour + using smaller spaces). ## Issues @@ -197,11 +232,16 @@ How does this work with While this proposal is not in a published version of the specification, implementations should use `org.matrix.msc1772` to represent the `m` -namespace. For example, `m.room.subgroup` becomes -`org.matrix.msc1772.room.subgroup`. +namespace. For example, `m.space.child` becomes +`org.matrix.msc1772.space.child`. ## History * This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE * Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs + + +## Footnotes + +[1] It's a From 52853b57e134497cf417d7659952f38a4b1ce8b6 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 27 Oct 2020 18:41:45 +0000 Subject: [PATCH 17/88] more updates --- proposals/1772-groups-as-rooms.md | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 36f0ff86..a6885d8b 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -63,9 +63,10 @@ Spaces are referred to primarily by their alias, for example Space-rooms are distinguished from regular messaging rooms by the `m.room.type` of `m.space` (see [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840)). -We introduce an `m.space.child` state event type which defines the rooms within -the group: A `present: true` key is included to distinguish from a deleted -state event. Something like: +We introduce an `m.space.child` state event type, which defines the rooms +within the space. The `state_key` is an alias for a child room, and `present: +true` key is included to distinguish from a deleted state event. Something +like: ```json { @@ -81,10 +82,11 @@ state event. Something like: "state_key": "#room2:example.com", "contents": { "present": true, - "autojoin": true # TODO: what does this mean? + "autojoin": true // TODO: what does this mean? } } +// no longer a child room { "type": "m.space.child", "state_key": "#oldroom:example.com", @@ -215,19 +217,15 @@ These dependencies are shared with profiles-as-rooms several thousand people), this membership has to copied entirely into the room, rather than querying/searching incrementally. - This is particularly problematic if that membership list is based on an - external service such as LDAP, since there is no way to keep the space - membership in sync with the LDAP directory. +* If the membership list is based on an external service such as LDAP, it is + hard to keep the space membership in sync with the LDAP directory. In + practice, it might be possible to do so via a nightly "synchronisation" job + which searches the LDAP directory, or via "AD auditing". * No allowance is made for exposing different 'views' of the membership list to different querying users. (It may be possible to simulate this behaviour using smaller spaces). -## Issues - -How does this work with -[MSC1228](https://github.com/matrix-org/matrix-doc/issues/1228) (removing MXIDs)? - ## Unstable prefix While this proposal is not in a published version of the specification, @@ -240,8 +238,3 @@ namespace. For example, `m.space.child` becomes * This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE * Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs - - -## Footnotes - -[1] It's a From c145d398f7f403cdcfa5fb5072a930f5c37b3f79 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 29 Oct 2020 11:23:48 +0000 Subject: [PATCH 18/88] Notes on propagating PLs etc --- proposals/1772-groups-as-rooms.md | 173 ++++++++++++++++++++++++++++-- 1 file changed, 167 insertions(+), 6 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index a6885d8b..b9f933ad 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -6,6 +6,7 @@ This obsoletes [MSC1215](https://github.com/matrix-org/matrix-doc/issues/1215). 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 @@ -61,14 +62,16 @@ Spaces are referred to primarily by their alias, for example `#foo:matrix.org`. Space-rooms are distinguished from regular messaging rooms by the `m.room.type` -of `m.space` (see [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840)). +of `m.space` (see +[MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840)). XXX nobody has +convinced me this is actually required. We introduce an `m.space.child` state event type, which defines the rooms within the space. The `state_key` is an alias for a child room, and `present: true` key is included to distinguish from a deleted state event. Something like: -```json +```js { "type": "m.space.child", "state_key": "#room1:example.com", @@ -94,6 +97,17 @@ like: } ``` +XXX if we use aliases here, and we are using it to maintain a tree of rooms in +the room list, what happens when the alias gets repointed and we don't know +about it? Maybe room IDs would be better, though the interaction with room +upgrades would need considering. + +XXX Rooms also need to be able to advertise related spaces, so that users can +discover other, related, rooms. + +XXX We also want to be have "secret" rooms within a heirarchy: do this with +either a "parent" state in the child, or possibly by hashing the room id? + Space-rooms may have `m.room.name` and `m.room.topic` state events in the same way as a normal room. @@ -118,7 +132,7 @@ Join rules, invites and 3PID invites work as for a normal room. ### Long description -We would like to allow groups to have a long description using rich +We would like to allow spaces to have a long description using rich formatting. This will use a new state event type `m.room.description` (with empty `state_key`) whose content is the same format as `m.room.message` (ie, contains a `msgtype` and possibly `formatted_body`). @@ -128,11 +142,147 @@ TODO: this could also be done via pinned messages. Failing that ### Inheritance of power-levels -TODO +XXX: this section still in progress + +One use-case for spaces is to help manage power levels across a group of +rooms. For example: "Jim has just joined the management team at my company. He +should have moderator rights across all of the company rooms." + +Since the event-authorisation rules cannot easily be changed, we must map any +changes in space membership onto real `m.room.power_levels` events in the child +rooms. + +There are two parts to this: one, indicating the relationship, and second, the +mechanics of propagating changes into real `m.room.power_levels` events. + +#### Representing the mapping from spaces to power levels + + * Option 1: list the PLs which should apply in all child rooms in an event in + the parent. For example: + + ```js + { + "type": "m.space.child_power_levels", + "state_key": "", + "content": { + // content as per regular power_levels event + } + } + ``` + + Problem 1: No automated mapping from space membership to user list, so the + user list would have to be maintained manually. On the other hand, this + could be fine in some situations, where we're just using the space to group + together rooms, rather than as a user list. + + Problem 2: No scope for nuance, where different rooms have slightly + different PLs. + + Problem 3: what happens to rooms where several spaces claim it as a child? + They end up fighting? + + Problem 4: Doesn't allow for random room admins to delegate their PLs to a + space without being admins in that space. + + * Option 2: Express the desired PLs as state in the child rooms + + This will need to be an ordered list, so that overlaps have defined behaviour: + + ```js + { + "type": "m.room.power_level_mappings", + "state_key": "", + "content": { + "mappings": [ + { + "users": ["@superuser:matrix.org"], + "power_level": 100, + }, + { + "spaces": ["#mods:example.org"], + "power_level": 50, + } + ] + } + } + ``` + + The intention would be that an automated process would peek into + `#mods:example.org` and + + Problem 1: possibly hard to map onto a comprehensible UI? + + Problem 2: scope for getting wildly out of sync? + + Question: is it safe to use an alias to refer to a space here? What happens + if the alias gets repointed and we don't notice? + +#### Propagating changes into rooms -### Automated joins/leaves + * Push-based: -TODO + * We require any user who is an admin in the space (ie, anyone who has + permission to change the access rights in the space) to also be admins + and members of any child rooms. + + Say Bob is an admin in #doglovers and makes a change that should be + propagated to all children of that space. His server is then responsible + for generating a power-levels event on his behalf for each room. + + Problem: Bob may not want to be a member of all such rooms. + + * We nominate a non-human "group admin" which is responsible for propagating + the changes into child rooms. It observes changes made in the parent space + and performs the necessary copying actions. + + Problem: Control is now centralised on the homeserver of the admin bot. If + that server goes down, changes are no longer propagated correctly. + + * We make it possible to specify several "group admin bot" users as above, + on different servers. All of them must have membership and admin in all + child rooms. Between them, they keep the child rooms in sync. + + Problem: How do the bots decide which will actually make the changes? + * Maybe a random delay is good enough to avoid too much glare? + * Or the humans nominate an "active" bot, with the others acting as + standbys until they are promoted? + + * Pull-based: the user that created the relationship (or rather, their + homeserver) is responsible for copying access controls into the room. + + This has the advantage that users can set up their own spaces to mirror a + space, without having any particular control in that group. (XXX: Is that + actually a useful feature, at least as far as PLs are concerned?) + + Problem: What do you do if the admin who sets ip the PL relationship + disappears? Again, either the humans have to step in and create a new + admin, or maybe we can have multiple admins with random backoff? + + Problem 2: What if the group server you are peeking to to maintain state is + unreachable? You could specify multiple vias for different servers via which + you can peek? + +All of the above solutions share the common problem that if the admin user +(human or virtual) loses membership or admin rights in the child room, then +the room will get out of sync. + +### Membership restrictions + +XXX: this section still in progress + +Another desirable feature is to give room admins the power to restrict +membership of their room based on the membership of spaces[1](#f1) (and by implication, when a user leaves the required +space, they should be ejected from the room). For example, "Any members of the +#doglovers space can join this room". + +### Automated joins + +XXX: this section still in progress + +A related feature is: "all members of the company should automatically join the +#general room", and by extension "all users should automatically join the +#brainwashing room and may not leave". ## Future extensions @@ -151,6 +301,8 @@ Questions to be answered here include: * What happens if somebody defines a cycle? (It's probably fine, but anything interpreting the relationships needs to be careful to limit recursion.) +XXX seems we need to un-de-scope this. + ### Restricting access to the spaces membership list In the existing `/r0/groups` API, the group server has total control over the @@ -238,3 +390,12 @@ namespace. For example, `m.space.child` becomes * This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE * Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs + + +## Footnotes + +[1]: The converse, "anybody can join, provided they are not members +of the '#catlovers' space" is less useful since (a) users in the banned space +could simply leave it at any time; (b) this functionality is already somewhat +provided by [Moderation policy +lists](https://matrix.org/docs/spec/client_server/r0.6.1#moderation-policy-lists). [↩](#a1) From 15f34e5be910ddd210d210646e15c577c68df926 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 29 Oct 2020 13:07:21 +0000 Subject: [PATCH 19/88] supporting trad PLs --- proposals/1772-groups-as-rooms.md | 86 +++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index b9f933ad..18b9addb 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -195,12 +195,12 @@ mechanics of propagating changes into real `m.room.power_levels` events. "content": { "mappings": [ { - "users": ["@superuser:matrix.org"], - "power_level": 100, + "spaces": ["#mods:example.org"], + "power_level": 50 }, { - "spaces": ["#mods:example.org"], - "power_level": 50, + "spaces": ["#users:example.org"], + "power_level": 1 } ] } @@ -208,7 +208,10 @@ mechanics of propagating changes into real `m.room.power_levels` events. ``` The intention would be that an automated process would peek into - `#mods:example.org` and + `#mods:example.org` and `#users:example.org` and generate a new + `m.room.power_levels` event whenever the membership of either space + changes. If a user is in both spaces, `#mods` takes priority because that is + listed first. Problem 1: possibly hard to map onto a comprehensible UI? @@ -217,8 +220,14 @@ mechanics of propagating changes into real `m.room.power_levels` events. Question: is it safe to use an alias to refer to a space here? What happens if the alias gets repointed and we don't notice? + XXX Question: currently there are restrictions which stop users assigning PLs + above their own current power level. Do we need to replicate these + restrictions? If so, that probably necessitates changes to event auth? + #### Propagating changes into rooms +Several options: + * Push-based: * We require any user who is an admin in the space (ie, anyone who has @@ -266,6 +275,73 @@ All of the above solutions share the common problem that if the admin user (human or virtual) loses membership or admin rights in the child room, then the room will get out of sync. +#### Supporting traditional PL assignments in addition to those derived from spaces + +When a user departs from a space, we expect the automated mapper process to +remove any power-levels that were granted to that user by virtue of being a +member of the space. The question arises of how the mapper can distinguish +between power-levels that were granted manually using the traditional +mechanism (so should not be changed) and those that were inherited from the +space and should be removed. + +Options: + + * Add a new field to `power_levels` for automatically-maintained power + levels. For example: + + ```js + { + "type": "m.room.power_levels", + "content": { + "users": { + "@roomadmin:example.com": 100 + }, + "auto_users": { + "@spaceuser1:example.org": 50 + } + } + } + ``` + + This would require changes to the event authorization rules, and hence + require a new room version. + + * Add hints to the automated mapper so that it can maintain manually-assigned + PLs. This could either be another field in `power_levels` which plays no + part in event auth: + + ```js + { + "type": "m.room.power_levels", + "content": { + "users": { + "@roomadmin:example.com": 100, + "@spaceuser1:example.org": 50 + }, + "manual_users": { + "@roomadmin:example.com": 100 + } + } + } + ``` + + ... or stored in a separate event. Clients would be responsible for updating + both copies of the manually-assigned PLs on change. + + Problem: Requiring clients to make two changes feels fragile. What if they + get it wrong? what if they don't know about the second copy because they + haven't been designed to work in rooms in spaces? + + * Require that even regular PLs go through the automated mapper, by making + them an explicit input to that mapper, for example with entries in the + `m.room.power_level_mappings` event suggested above. + + Problem: Requires clients to distinguish between rooms where there is an + automated mapper, and those where the client should manipulate the PLs + directly. (Maybe that's not so bad? The presence of the `mappings` event + should be enough? But still sucks that there are two ways to do the same + thing, and clients which don't support spaces will get it wrong.) + ### Membership restrictions XXX: this section still in progress From e746aa3aad2a0f92ea2a6468f74510f573f6b9de Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Fri, 30 Oct 2020 11:16:32 +0000 Subject: [PATCH 20/88] Apply suggestions from code review Co-authored-by: Matthew Hodgson --- proposals/1772-groups-as-rooms.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 18b9addb..56d4e505 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -105,7 +105,7 @@ upgrades would need considering. XXX Rooms also need to be able to advertise related spaces, so that users can discover other, related, rooms. -XXX We also want to be have "secret" rooms within a heirarchy: do this with +XXX We also want to be have "secret" rooms within a hierarchy: do this with either a "parent" state in the child, or possibly by hashing the room id? Space-rooms may have `m.room.name` and `m.room.topic` state events in the same @@ -228,7 +228,7 @@ mechanics of propagating changes into real `m.room.power_levels` events. Several options: - * Push-based: + * Push-based options: * We require any user who is an admin in the space (ie, anyone who has permission to change the access rights in the space) to also be admins @@ -263,7 +263,7 @@ Several options: space, without having any particular control in that group. (XXX: Is that actually a useful feature, at least as far as PLs are concerned?) - Problem: What do you do if the admin who sets ip the PL relationship + Problem: What do you do if the admin who sets up the PL relationship disappears? Again, either the humans have to step in and create a new admin, or maybe we can have multiple admins with random backoff? From 2f557daac119264b146a206a8a92e16df08a1300 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 30 Oct 2020 18:46:05 +0000 Subject: [PATCH 21/88] Clarifications to room/space relationship --- proposals/1772-groups-as-rooms.md | 204 +++++++++++++++++++----------- 1 file changed, 132 insertions(+), 72 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 56d4e505..4f56344a 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -66,48 +66,6 @@ of `m.space` (see [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840)). XXX nobody has convinced me this is actually required. -We introduce an `m.space.child` state event type, which defines the rooms -within the space. The `state_key` is an alias for a child room, and `present: -true` key is included to distinguish from a deleted state event. Something -like: - -```js -{ - "type": "m.space.child", - "state_key": "#room1:example.com", - "contents": { - "present": true - } -} - -{ - "type": "m.space.child", - "state_key": "#room2:example.com", - "contents": { - "present": true, - "autojoin": true // TODO: what does this mean? - } -} - -// no longer a child room -{ - "type": "m.space.child", - "state_key": "#oldroom:example.com", - "contents": {} -} -``` - -XXX if we use aliases here, and we are using it to maintain a tree of rooms in -the room list, what happens when the alias gets repointed and we don't know -about it? Maybe room IDs would be better, though the interaction with room -upgrades would need considering. - -XXX Rooms also need to be able to advertise related spaces, so that users can -discover other, related, rooms. - -XXX We also want to be have "secret" rooms within a hierarchy: do this with -either a "parent" state in the child, or possibly by hashing the room id? - Space-rooms may have `m.room.name` and `m.room.topic` state events in the same way as a normal room. @@ -118,10 +76,10 @@ such messages. ### Membership of spaces Users can be members of spaces (represented by `m.room.member` state events as -normal). Depending on the configuration of the space (in particular whether -`m.room.history_visibility` is set to `world_readable` or otherwise), -membership of the space may be required to view the room list, membership list, -etc. +normal). The existing [`m.room.history_visibility` +mechanism](https://matrix.org/docs/spec/client_server/r0.6.1#room-history-visibility) +controls whether membership of the space is required to view the room list, +membership list, etc. "Public" or "community" spaces would be set to `world_readable` to allow clients to see the directory of rooms within the space by peeking into the space-room @@ -130,6 +88,122 @@ the room). Join rules, invites and 3PID invites work as for a normal room. +### Relationship between rooms and spaces + +The intention is that rooms and spaces form a hierarchy, which clients can use +to structure the user's room list into a tree view. The parent/child +relationship can be expressed in one of two ways: + + 1. The admins of a space can advertise rooms and subspaces for their space by + setting `m.space.child` state events. The `state_key` is an alias for a + child room or space, and `present: true` key is included to distinguish + from a deleted state event. Something like: + + ```js + { + "type": "m.space.child", + "state_key": "#room1:example.com", + "content": { + "present": true + } + } + + { + "type": "m.space.child", + "state_key": "#room2:example.com", + "content": { + "present": true, + "order": "abcd", + "default": true + } + } + + // no longer a child room + { + "type": "m.space.child", + "state_key": "#oldroom:example.com", + "content": {} + } + ``` + + Children where `present` is not present or is not set to `true` are ignored. + + The `order` key is a string which is used to provide a default ordering of + siblings in the room list. (Rooms are sorted based on a lexicographic + ordering of of `order` vales; rooms with no `order` come last. `order`s + which are not strings, or do not consist solely of ascii characters in the + range `\x20` (space) to `\x7F` (`~`) are forbidden and should be ignored if + received.) + + If `default` is set to `true`, that indicates a "default child": see [below](#default-children). + + XXX if we use aliases here, what happens when the alias gets repointed and + we don't know about it? Or we are already in a room which *claims* to be + `#room1:example.com`, but actually isn't? Probably room IDs (+ vias) would + be better, though the interaction with room upgrades would need + considering. + + 2. Separately, rooms can claim parents via `m.room.parent` state + events, where the `state_key` is the alias (?) of the parent space: + + ```js + { + "type": "m.room.parent", + "state_key": "#space1:example.com", + "content": { + "present": true + } + } + ``` + + In this case, after a user joins such a room, the client could optionally + start peeking into the parent space, enabling it to find other rooms in + that space and group them together. + + XXX how do we avoid abuse where randoms claim that their room is part of a + space it's not? + + XXX do we need an "order" in this direction too? + +This structure means that rooms can end up with multiple parents. This implies +that the room will appear multiple times in the room list hierarchy. + +In a typical hierarchy, we expect *both* parent->child and child->parent +relationships to exist, so that the space can be discovered from the room, and +vice versa. Occasions when the relationship only exists in one direction +include: + + * User-curated lists of rooms: in this case the space will not be listed as a + parent of the room. + + * "Secret" rooms: rooms where the admin does not want the room to be + advertised as part of a given space, but *does* want the room to form part + of the heirarchy of that space for those in the know. + +### Sub-spaces + +XXX: Questions to be answered here include: + + * Should membership of a sub-space grant any particular access to the parent + space, or vice-versa? We might need to extend `m.room.history_visibility` to + support more flexibility; fortunately this is not involved in event auth so + does not require new room versions. + + * What happens if somebody defines a cycle? (It's probably fine, but anything + interpreting the relationships needs to be careful to limit recursion.) + +### Default children + +The `default` flag on a child listing allows a space admin to list the +"default" sub-spaces and rooms in that space. This means that when a user joins +the parent space, they will automatically be joined to those default +children. XXX implement this on the client or server? + +Clients could display the default children in the room list whenever the space +appears in the list. + +XXX: do we need force-joins, where users may not leave a room they autojoined? + ### Long description We would like to allow spaces to have a long description using rich @@ -222,7 +296,8 @@ mechanics of propagating changes into real `m.room.power_levels` events. XXX Question: currently there are restrictions which stop users assigning PLs above their own current power level. Do we need to replicate these - restrictions? If so, that probably necessitates changes to event auth? + restrictions? If so, that probably necessitates changes to event auth? (Does + anyone actually make use of allowing non-admins to send PL events today?) #### Propagating changes into rooms @@ -344,41 +419,26 @@ Options: ### Membership restrictions -XXX: this section still in progress +A desirable feature is to give room admins the power to restrict membership of +their room based on the membership of spaces (for example, "only members of the +#doglovers space can join this room"[1](#f1)). -Another desirable feature is to give room admins the power to restrict -membership of their room based on the membership of spaces[1](#f1) (and by implication, when a user leaves the required -space, they should be ejected from the room). For example, "Any members of the -#doglovers space can join this room". +XXX can we maybe do this with invites generated on demand? If not, we probably +need some sort of "silent invite" state for each user, -### Automated joins +By implication, when a user leaves the required space, they should be ejected +from the room. -XXX: this section still in progress +XXX: how do we implement the ejection? We could leave it up to the ejectee's +server, but what happens if it doesn't play the game? So we probably need to +enact a ban... but then, which server has responisiblity, and which user is used? -A related feature is: "all members of the company should automatically join the -#general room", and by extension "all users should automatically join the -#brainwashing room and may not leave". ## Future extensions The following sections are not blocking parts of this proposal, but are included as a useful reference for how we imagine it will be extended in future. -### Sub-spaces - -Questions to be answered here include: - - * Should membership of a sub-space grant any particular access to the parent - space, or vice-versa? We might need to extend `m.room.history_visibility` to - support more flexibility; fortunately this is not involved in event auth so - does not require new room versions. - - * What happens if somebody defines a cycle? (It's probably fine, but anything - interpreting the relationships needs to be careful to limit recursion.) - -XXX seems we need to un-de-scope this. - ### Restricting access to the spaces membership list In the existing `/r0/groups` API, the group server has total control over the From 11bb604c5e50e9f82d647f884ce1b8a93fd6fdb1 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 30 Oct 2020 18:47:37 +0000 Subject: [PATCH 22/88] add an xxx --- proposals/1772-groups-as-rooms.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 4f56344a..1f5a1a7f 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -218,6 +218,8 @@ TODO: this could also be done via pinned messages. Failing that XXX: this section still in progress +XXX: make it clear that "child rooms" here are not necessarily actually children... + One use-case for spaces is to help manage power levels across a group of rooms. For example: "Jim has just joined the management team at my company. He should have moderator rights across all of the company rooms." From d42da585e5ad47830c35a397aee2092b4b3ca4f0 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Mon, 9 Nov 2020 12:09:48 +0000 Subject: [PATCH 23/88] Apply suggestions from code review Co-authored-by: Matthew Hodgson --- proposals/1772-groups-as-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 1f5a1a7f..d4ac126f 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -130,7 +130,7 @@ relationship can be expressed in one of two ways: The `order` key is a string which is used to provide a default ordering of siblings in the room list. (Rooms are sorted based on a lexicographic - ordering of of `order` vales; rooms with no `order` come last. `order`s + ordering of `order` values; rooms with no `order` come last. `order`s which are not strings, or do not consist solely of ascii characters in the range `\x20` (space) to `\x7F` (`~`) are forbidden and should be ignored if received.) @@ -178,7 +178,7 @@ include: * "Secret" rooms: rooms where the admin does not want the room to be advertised as part of a given space, but *does* want the room to form part - of the heirarchy of that space for those in the know. + of the hierarchy of that space for those in the know. ### Sub-spaces From 1aede33b35cd27ffed9ec7a4bd9ea63a8399ce24 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 9 Nov 2020 12:30:02 +0000 Subject: [PATCH 24/88] clarify introduction --- proposals/1772-groups-as-rooms.md | 71 +++++++++++++++++-------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index d4ac126f..72e4c0c7 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -17,40 +17,18 @@ purposes. Examples include: We refer to such collections of rooms as "spaces". -Synapse and Element-Web currently implement an unspecced "groups" API which -attempts to provide this functionality (see -[matrix-doc#1513](https://github.com/matrix-org/matrix-doc/issues/1513)). This -API has some serious issues: - * It is a large API surface to implement, maintain and spec - particularly for - all the different clients out there. - * Much of the API overlaps significantly with mechanisms we already have for - managing rooms: - * Tracking membership identity - * Tracking membership hierarchy - * Inviting/kicking/banning user - * Tracking key/value metadata - * There are membership management features which could benefit rooms which - would also benefit groups and vice versa (e.g. "auditorium mode") - * The current implementations on Riot Web/iOS/Android all suffer bugs and - issues which have been solved previously for rooms. - * no local-echo of invites - * failures to set group avatars - * ability to specify multiple admins - * It doesn't support pushing updates to clients (particularly for flair - membership): https://github.com/vector-im/riot-web/issues/5235 - * It doesn't support third-party invites. - * Groups could benefit from other features which already exist today for rooms - * e.g. Room Directories - * Groups are centralised, rather than being replicated across all - participating servers. - -In this document, the existing implementation will be referred to as -"`/r0/groups`". +Synapse and Element-Web currently implement an unspecced "groups" API (referred +to as "`/r0/groups`" in this document) which attempts to provide this +functionality (see +[matrix-doc#971](https://github.com/matrix-org/matrix-doc/issues/971)). However, +this is a complex API which has various problems (see +[appendix](#appendix-problems-with-the-r0groups-api)). This proposal suggests a new approach where spaces are themselves represented by rooms, rather than a custom first-class entity. This requires few server -changes, other than better support for peeking (see Dependencies below). The -existing `/r0/groups` API would be deprecated in Synapse and remain +changes, other than better support for peeking (see Dependencies below). + +The existing `/r0/groups` API would be deprecated in Synapse and remain unspecified. ## Proposal @@ -523,12 +501,41 @@ implementations should use `org.matrix.msc1772` to represent the `m` namespace. For example, `m.space.child` becomes `org.matrix.msc1772.space.child`. - ## History * This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE * Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs +## Appendix: problems with the `/r0/groups` API + +The existing `/r0/groups` API, as proposed in +[MSC971](https://github.com/matrix-org/matrix-doc/issues/971), has various +problems, including: + + * It is a large API surface to implement, maintain and spec - particularly for + all the different clients out there. + * Much of the API overlaps significantly with mechanisms we already have for + managing rooms: + * Tracking membership identity + * Tracking membership hierarchy + * Inviting/kicking/banning user + * Tracking key/value metadata + * There are membership management features which could benefit rooms which + would also benefit groups and vice versa (e.g. "auditorium mode") + * The current implementations on Riot Web/iOS/Android all suffer bugs and + issues which have been solved previously for rooms. + * no local-echo of invites + * failures to set group avatars + * ability to specify multiple admins + * It doesn't support pushing updates to clients (particularly for flair + membership): https://github.com/vector-im/riot-web/issues/5235 + * It doesn't support third-party invites. + * Groups could benefit from other features which already exist today for rooms + * e.g. Room Directories + * Groups are centralised, rather than being replicated across all + participating servers. + + ## Footnotes From e323ade5f706f0d77f34170828d4985ab94ccc8a Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 9 Nov 2020 15:11:16 +0000 Subject: [PATCH 25/88] Switch to room IDs --- proposals/1772-groups-as-rooms.md | 39 ++++++++++++++----------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 72e4c0c7..a0b9ff2c 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -73,23 +73,26 @@ to structure the user's room list into a tree view. The parent/child relationship can be expressed in one of two ways: 1. The admins of a space can advertise rooms and subspaces for their space by - setting `m.space.child` state events. The `state_key` is an alias for a - child room or space, and `present: true` key is included to distinguish - from a deleted state event. Something like: + setting `m.space.child` state events. The `state_key` is the ID of a child + room or space, and the content should ontain a `via` key which gives a list + of candidate servers that can be used to join the room. `present: true` key + is included to distinguish from a deleted state event. Something like: ```js { "type": "m.space.child", - "state_key": "#room1:example.com", + "state_key": "!abcd:example.com", "content": { + "via": ["example.com", "test.org"], "present": true } } { "type": "m.space.child", - "state_key": "#room2:example.com", + "state_key": "!efgh:example.com", "content": { + "via": ["example.com"], "present": true, "order": "abcd", "default": true @@ -99,7 +102,7 @@ relationship can be expressed in one of two ways: // no longer a child room { "type": "m.space.child", - "state_key": "#oldroom:example.com", + "state_key": "!jklm:example.com", "content": {} } ``` @@ -115,20 +118,15 @@ relationship can be expressed in one of two ways: If `default` is set to `true`, that indicates a "default child": see [below](#default-children). - XXX if we use aliases here, what happens when the alias gets repointed and - we don't know about it? Or we are already in a room which *claims* to be - `#room1:example.com`, but actually isn't? Probably room IDs (+ vias) would - be better, though the interaction with room upgrades would need - considering. - 2. Separately, rooms can claim parents via `m.room.parent` state - events, where the `state_key` is the alias (?) of the parent space: + events, where the `state_key` is the room ID of the parent space: ```js { "type": "m.room.parent", - "state_key": "#space1:example.com", + "state_key": "!space:example.com", "content": { + "via": ["example.com"] "present": true } } @@ -249,11 +247,13 @@ mechanics of propagating changes into real `m.room.power_levels` events. "content": { "mappings": [ { - "spaces": ["#mods:example.org"], + "space": "!mods:example.org", + "via": ["example.org"], "power_level": 50 }, { - "spaces": ["#users:example.org"], + "space": "!users:example.org", + "via": ["example.org"], "power_level": 1 } ] @@ -262,18 +262,15 @@ mechanics of propagating changes into real `m.room.power_levels` events. ``` The intention would be that an automated process would peek into - `#mods:example.org` and `#users:example.org` and generate a new + `!mods:example.org` and `!users:example.org` and generate a new `m.room.power_levels` event whenever the membership of either space - changes. If a user is in both spaces, `#mods` takes priority because that is + changes. If a user is in both spaces, `!mods` takes priority because that is listed first. Problem 1: possibly hard to map onto a comprehensible UI? Problem 2: scope for getting wildly out of sync? - Question: is it safe to use an alias to refer to a space here? What happens - if the alias gets repointed and we don't notice? - XXX Question: currently there are restrictions which stop users assigning PLs above their own current power level. Do we need to replicate these restrictions? If so, that probably necessitates changes to event auth? (Does From a73dd9c37139c652441893579ad3b634d720c5d8 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 9 Nov 2020 15:11:48 +0000 Subject: [PATCH 26/88] clarification --- proposals/1772-groups-as-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index a0b9ff2c..61ae02b1 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -311,8 +311,8 @@ Several options: * Pull-based: the user that created the relationship (or rather, their homeserver) is responsible for copying access controls into the room. - This has the advantage that users can set up their own spaces to mirror a - space, without having any particular control in that group. (XXX: Is that + This has the advantage that users can set up their own rooms to mirror a + space, without having any particular control in that space. (XXX: Is that actually a useful feature, at least as far as PLs are concerned?) Problem: What do you do if the admin who sets up the PL relationship From 839ea0e946055c620a113151bd915b8bfcc37340 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 9 Nov 2020 15:11:59 +0000 Subject: [PATCH 27/88] inheriting join rules --- proposals/1772-groups-as-rooms.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 61ae02b1..9697d08b 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -458,6 +458,11 @@ One way this might be implemented is: to do this check (and both servers and clients can cache the results fairly aggressively.) +### Inheriting join rules + +If you make a parent space invite-only, should that (optionally?) cascade into +child rooms? Seems to have some of the same problems as inheriting PLs. + ## Dependencies * [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) for room From 109c31c2c8cac7222d714be346bf5990821f4209 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 10 Nov 2020 11:45:37 +0000 Subject: [PATCH 28/88] Avoiding abuse via false `parent` claims --- proposals/1772-groups-as-rooms.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 9697d08b..e5e11dcb 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -136,10 +136,10 @@ relationship can be expressed in one of two ways: start peeking into the parent space, enabling it to find other rooms in that space and group them together. - XXX how do we avoid abuse where randoms claim that their room is part of a - space it's not? - - XXX do we need an "order" in this direction too? + To avoid abuse where a room admin falsely claims that a room is part of a + space that it should not be, clients could ignore such `m.room.parent` + events unless their sender has a sufficient power-level to send an + `m.room.child` event in the parent. This structure means that rooms can end up with multiple parents. This implies that the room will appear multiple times in the room list hierarchy. From 06b5c8342fa50c96e8d37316343b3ec2ab32a7ef Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 10 Nov 2020 12:08:29 +0000 Subject: [PATCH 29/88] notes on children and recursion --- proposals/1772-groups-as-rooms.md | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index e5e11dcb..9c389bbb 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -141,6 +141,9 @@ relationship can be expressed in one of two ways: events unless their sender has a sufficient power-level to send an `m.room.child` event in the parent. + Where the parent space also claims a parent, clients can recursively peek + into the grandparent space, and so on. + This structure means that rooms can end up with multiple parents. This implies that the room will appear multiple times in the room list hierarchy. @@ -156,30 +159,22 @@ include: advertised as part of a given space, but *does* want the room to form part of the hierarchy of that space for those in the know. -### Sub-spaces - -XXX: Questions to be answered here include: - - * Should membership of a sub-space grant any particular access to the parent - space, or vice-versa? We might need to extend `m.room.history_visibility` to - support more flexibility; fortunately this is not involved in event auth so - does not require new room versions. - - * What happens if somebody defines a cycle? (It's probably fine, but anything - interpreting the relationships needs to be careful to limit recursion.) +Cycles in the parent->child and child->parent relationships are *not* +permitted, but clients (and servers) should be aware that they may be +encountered, and ignore the relationship rather than recursing infinitely. ### Default children The `default` flag on a child listing allows a space admin to list the "default" sub-spaces and rooms in that space. This means that when a user joins the parent space, they will automatically be joined to those default -children. XXX implement this on the client or server? +children. + +XXX implement this on the client or server? Clients could display the default children in the room list whenever the space appears in the list. -XXX: do we need force-joins, where users may not leave a room they autojoined? - ### Long description We would like to allow spaces to have a long description using rich From 29b07c11ad9edbf1e45d3779702ce9d9d8722870 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 10 Nov 2020 12:56:16 +0000 Subject: [PATCH 30/88] update power level mappings --- proposals/1772-groups-as-rooms.md | 277 ++++++++++-------------------- 1 file changed, 89 insertions(+), 188 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 9c389bbb..4a0d7aed 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -185,209 +185,103 @@ contains a `msgtype` and possibly `formatted_body`). TODO: this could also be done via pinned messages. Failing that `m.room.description` should probably be a separate MSC. -### Inheritance of power-levels +### Managing power levels via spaces XXX: this section still in progress -XXX: make it clear that "child rooms" here are not necessarily actually children... - One use-case for spaces is to help manage power levels across a group of rooms. For example: "Jim has just joined the management team at my company. He should have moderator rights across all of the company rooms." -Since the event-authorisation rules cannot easily be changed, we must map any -changes in space membership onto real `m.room.power_levels` events in the child -rooms. +Since the event-authorisation rules cannot easily be extended to consider +membership in other rooms, we must map any changes in space membership onto +real `m.room.power_levels` events. + +#### Extending the power_levels event + +We now have a mix of manually- and automatically- maintained power-level +data. To support this, we extend the existing `m.room.power_levels` event to +add an `auto_users` key: + +```js +{ + "type": "m.room.power_levels", + "content": { + "users": { + "@roomadmin:example.com": 100 + }, + "auto_users": { + "@spaceuser1:example.org": 50 + } + } +} +``` -There are two parts to this: one, indicating the relationship, and second, the -mechanics of propagating changes into real `m.room.power_levels` events. +A user's power level is then specified by an entry in *either* `users` or +`auto_users`. Where a user appears in both sections, `users` takes precedence. -#### Representing the mapping from spaces to power levels +`auto_users` is subject to all of the same authorization checks as the existing +`users` key (see https://matrix.org/docs/spec/rooms/v1#authorization-rules, +paragraphs 10a, 10d, 10e). - * Option 1: list the PLs which should apply in all child rooms in an event in - the parent. For example: - - ```js - { - "type": "m.space.child_power_levels", - "state_key": "", - "content": { - // content as per regular power_levels event - } - } - ``` - - Problem 1: No automated mapping from space membership to user list, so the - user list would have to be maintained manually. On the other hand, this - could be fine in some situations, where we're just using the space to group - together rooms, rather than as a user list. +This change necessitates a new room version. - Problem 2: No scope for nuance, where different rooms have slightly - different PLs. +#### Representing the mapping from spaces to power levels - Problem 3: what happens to rooms where several spaces claim it as a child? - They end up fighting? - - Problem 4: Doesn't allow for random room admins to delegate their PLs to a - space without being admins in that space. - - * Option 2: Express the desired PLs as state in the child rooms +The desired mapping from spaces to power levels is defined in a new state event +type, `m.room.power_level_mappings`. The content should contain a `mappings` +key which is an ordered list, for example: + +```js +{ + "type": "m.room.power_level_mappings", + "state_key": "", + "content": { + "mappings": [ + { + "space": "!mods:example.org", + "via": ["example.org"], + "power_level": 50 + }, + { + "space": "!users:example.org", + "via": ["example.org"], + "power_level": 1 + } + ] + } +} +``` - This will need to be an ordered list, so that overlaps have defined behaviour: - - ```js - { - "type": "m.room.power_level_mappings", - "state_key": "", - "content": { - "mappings": [ - { - "space": "!mods:example.org", - "via": ["example.org"], - "power_level": 50 - }, - { - "space": "!users:example.org", - "via": ["example.org"], - "power_level": 1 - } - ] - } - } - ``` - - The intention would be that an automated process would peek into - `!mods:example.org` and `!users:example.org` and generate a new - `m.room.power_levels` event whenever the membership of either space - changes. If a user is in both spaces, `!mods` takes priority because that is - listed first. - - Problem 1: possibly hard to map onto a comprehensible UI? - - Problem 2: scope for getting wildly out of sync? - - XXX Question: currently there are restrictions which stop users assigning PLs - above their own current power level. Do we need to replicate these - restrictions? If so, that probably necessitates changes to event auth? (Does - anyone actually make use of allowing non-admins to send PL events today?) - -#### Propagating changes into rooms - -Several options: - - * Push-based options: - - * We require any user who is an admin in the space (ie, anyone who has - permission to change the access rights in the space) to also be admins - and members of any child rooms. - - Say Bob is an admin in #doglovers and makes a change that should be - propagated to all children of that space. His server is then responsible - for generating a power-levels event on his behalf for each room. - - Problem: Bob may not want to be a member of all such rooms. - - * We nominate a non-human "group admin" which is responsible for propagating - the changes into child rooms. It observes changes made in the parent space - and performs the necessary copying actions. - - Problem: Control is now centralised on the homeserver of the admin bot. If - that server goes down, changes are no longer propagated correctly. - - * We make it possible to specify several "group admin bot" users as above, - on different servers. All of them must have membership and admin in all - child rooms. Between them, they keep the child rooms in sync. - - Problem: How do the bots decide which will actually make the changes? - * Maybe a random delay is good enough to avoid too much glare? - * Or the humans nominate an "active" bot, with the others acting as - standbys until they are promoted? - - * Pull-based: the user that created the relationship (or rather, their - homeserver) is responsible for copying access controls into the room. - - This has the advantage that users can set up their own rooms to mirror a - space, without having any particular control in that space. (XXX: Is that - actually a useful feature, at least as far as PLs are concerned?) - - Problem: What do you do if the admin who sets up the PL relationship - disappears? Again, either the humans have to step in and create a new - admin, or maybe we can have multiple admins with random backoff? - - Problem 2: What if the group server you are peeking to to maintain state is - unreachable? You could specify multiple vias for different servers via which - you can peek? - -All of the above solutions share the common problem that if the admin user -(human or virtual) loses membership or admin rights in the child room, then -the room will get out of sync. +This means that a new `m.room.power_levels` event would be generated whenever +the membership of either `!mods` or `!users` changes. If a user is in both +spaces, `!mods` takes priority because that is listed first. -#### Supporting traditional PL assignments in addition to those derived from spaces +#### Implementing the mapping -When a user departs from a space, we expect the automated mapper process to -remove any power-levels that were granted to that user by virtue of being a -member of the space. The question arises of how the mapper can distinguish -between power-levels that were granted manually using the traditional -mechanism (so should not be changed) and those that were inherited from the -space and should be removed. - -Options: - - * Add a new field to `power_levels` for automatically-maintained power - levels. For example: - - ```js - { - "type": "m.room.power_levels", - "content": { - "users": { - "@roomadmin:example.com": 100 - }, - "auto_users": { - "@spaceuser1:example.org": 50 - } - } - } - ``` - - This would require changes to the event authorization rules, and hence - require a new room version. - - * Add hints to the automated mapper so that it can maintain manually-assigned - PLs. This could either be another field in `power_levels` which plays no - part in event auth: - - ```js - { - "type": "m.room.power_levels", - "content": { - "users": { - "@roomadmin:example.com": 100, - "@spaceuser1:example.org": 50 - }, - "manual_users": { - "@roomadmin:example.com": 100 - } - } - } - ``` +When a new room is created, the server implicitly adds a "room admin bot" to +the room, with the maximum power-level of any of the initial users. +(Homeservers should implement this "bot" internally, rather than requiring +separate software to be installed.) - ... or stored in a separate event. Clients would be responsible for updating - both copies of the manually-assigned PLs on change. +It is proposed that this "admin bot" use the special user ID with empty +localpart `@:example.com`. - Problem: Requiring clients to make two changes feels fragile. What if they - get it wrong? what if they don't know about the second copy because they - haven't been designed to work in rooms in spaces? +This bot is then responsible for monitoring the `power_level_mappings` state, +and peeking into any spaces mentioned in the content. It can then issue new +`m.room.power_levels` events whenever the membership of the spaces in question +changes. - * Require that even regular PLs go through the automated mapper, by making - them an explicit input to that mapper, for example with entries in the - `m.room.power_level_mappings` event suggested above. +It is possible that the admin bot is unable to perform the mapping (for +example, the space cannot be peeked; or the membership of the space is so large +that it cannot be expanded into a single `m.room.power_levels` event). It is +proposed that the bot could notify the room of any problems via +`m.room.message` messages of type `m.msgtype`. - Problem: Requires clients to distinguish between rooms where there is an - automated mapper, and those where the client should manipulate the PLs - directly. (Maybe that's not so bad? The presence of the `mappings` event - should be enough? But still sucks that there are two ways to do the same - thing, and clients which don't support spaces will get it wrong.) +Clearly, updating this event type is extremely powerful. It is expected that +access to it is itself restricted via `power_levels`. This could be enforced by +the admin bot so that no `m.room.power_levels` events are generated unless +`power_level_mappings` is appropriately restricted. ### Membership restrictions @@ -493,10 +387,17 @@ These dependencies are shared with profiles-as-rooms ## Unstable prefix -While this proposal is not in a published version of the specification, -implementations should use `org.matrix.msc1772` to represent the `m` -namespace. For example, `m.space.child` becomes -`org.matrix.msc1772.space.child`. + +The following mapping will be used for identifiers in this MSC during +development: + +Proposed final identifier | Purpose | Development identifier +------------------------------- | ------- | ---- +`m.space.child` | event type | `org.matrix.msc1772.space.child` +`m.space.parent` | event type | `org.matrix.msc1772.space.parent` +`m.room.power_level_mappings` | event type | `org.matrix.msc1772.room.power_level_mappings` +`auto_users` | key in `m.room.power_levels` event | `org.matrix.msc1772.auto_users` + ## History From ae71a6219a5fdc33c4c192c02c4616eee52f9024 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 11 Nov 2020 12:13:42 +0000 Subject: [PATCH 31/88] Restricting room membership via spaces --- proposals/1772-groups-as-rooms.md | 148 ++++++++++++++++++++++++------ 1 file changed, 121 insertions(+), 27 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 4a0d7aed..76520b92 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -187,7 +187,8 @@ TODO: this could also be done via pinned messages. Failing that ### Managing power levels via spaces -XXX: this section still in progress +TODO: much of this is orthogonal to the headline feature of "spaces", and +should be moved to a separate MSC. One use-case for spaces is to help manage power levels across a group of rooms. For example: "Jim has just joined the management team at my company. He @@ -234,21 +235,21 @@ key which is an ordered list, for example: ```js { - "type": "m.room.power_level_mappings", - "state_key": "", - "content": { - "mappings": [ - { - "space": "!mods:example.org", - "via": ["example.org"], - "power_level": 50 - }, - { - "space": "!users:example.org", - "via": ["example.org"], - "power_level": 1 - } - ] + "type": "m.room.power_level_mappings", + "state_key": "", + "content": { + "mappings": [ + { + "space": "!mods:example.org", + "via": ["example.org"], + "power_level": 50 + }, + { + "space": "!users:example.org", + "via": ["example.org"], + "power_level": 1 + } + ] } } ``` @@ -283,22 +284,97 @@ access to it is itself restricted via `power_levels`. This could be enforced by the admin bot so that no `m.room.power_levels` events are generated unless `power_level_mappings` is appropriately restricted. -### Membership restrictions +### Restricting room membership based on space membership A desirable feature is to give room admins the power to restrict membership of -their room based on the membership of spaces (for example, "only members of the -#doglovers space can join this room"[1](#f1)). - -XXX can we maybe do this with invites generated on demand? If not, we probably -need some sort of "silent invite" state for each user, +their room based on the membership of spaces (for example, "members of the +#doglovers space can join this room without an invitation"[1](#f1)). -By implication, when a user leaves the required space, they should be ejected -from the room. +We could represent the allowed spaces with additional content in the +`m.room.join_rules` event. For example: -XXX: how do we implement the ejection? We could leave it up to the ejectee's -server, but what happens if it doesn't play the game? So we probably need to -enact a ban... but then, which server has responisiblity, and which user is used? +```js +{ + "type": "m.room.join_rules", + "state_key": "", + "content": { + "join_rule": "public", + "allowed_spaces": [ + { + "space": "!mods:example.org", + "via": ["example.org"], + }, + { + "space": "!users:example.org", + "via": ["example.org"], + } + ] + } +} +``` +XXX: would it be better to put it in a separate event? Doing so would probably +require us to come up with a new `join_rule` state to tell servers to go and +look for the allowed spaces. + +The `allowed_spaces` key applies a restriction to the `public` join rule, so +that only users in those spaces should be allowed to join. Additionally, users +who have received an explicit `invite` event are allowed to join[2](#f2). If the `allowed_spaces` key is an empty list (or not a +list at all), no users are allowed to join without an invite. + +Unlike the regular `invite` join rule, the restriction cannot be enforced over +federation by event authorization, so servers in the room are trusted not to +allow invalid users to join.[3](#f3) + +When a server receives a `/join` request from a client or a +`/make_join`/`/send_join` request from a server, the request should only be +permitted if the user has a valid invite or is in one of the listed spaces +(established by peeking). + +XXX: redacting the join_rules above will reset the room to public, which feels dangerous? + +A new room version is not absolutely required here, but may be advisable to +ensure that servers that do not support `allowed_spaces` do not join the room +(and would also allow us to tweak the redaction rules to avoid the foot-gun). + +#### Kicking users out when they leave the allowed_space + +In the above example, suppose `@bob:server.example` leaves `!users:example.org`: +they should be removed from the room. One option is to leave the departure up +to Bob's server `server.example`, but this places a relatively high level of trust +in that server. Additionally, if `server.example` were offline, other users in +the room would still see Bob in the room (and their servers would attempt to +send message traffic to it). + +Instead, we make the removal the responsibility of the room's admin bot (see +above): the bot is expected to peek into any `allowed_spaces` and kick any +users who are members of the room and leave the union of the allowed +spaces. + +(XXX: should users in a space be kicked when that space is removed from the +`allowed_spaces` list? We think not, by analogy with what happens when you +switch the join rules from `public` to `invite`.) + +One problem here is that it will lead to users who joined via an invite being +kicked. For example: + * `@bob:server.example` creates an invite-only room. + * Later, the `join_rules` are switched to `public`, with an `allowed_space` of + `!users:example.org`, of which Bob happens to be a member. + * Later still, Bob leaves `!users:example.org`. + * Bob is kicked from his own room. + +Fixing this is thorny. Some sort of annotation on the membership events might +help. but it's unclear what the desired semantics are: + + * Assuming that users in a given space are *not* kicked when that space is + removed from `allowed_spaces`, are those users then given a pass to remain + in the room indefinitely? What happens if the space is added back to + `allowed_spaces` and *then* the user leaves it? + + * Suppose a user joins a room via a space (SpaceA). Later, SpaceB is added to + the `allowed_spaces` list and SpaceA is removed. What should happen when the + user leaves SpaceB? Are they exempt from the kick? ## Future extensions @@ -370,6 +446,13 @@ These dependencies are shared with profiles-as-rooms * The peek server has significant power. TODO: expand. +* The `allowed_spaces` feature places increased trust in the servers in the + room. We consider this acceptable: if you don't want evil servers randomly + joining spurious users into your rooms, then a) don't let evil servers in + your room in the first place, b) don't use `allowed_spaces` lists, given the + expansion increases the attack surface anyway by letting members in other + rooms dictate who's allowed into your room". + ## Tradeoffs * If the membership of a space would be large (for example: an organisation of @@ -442,3 +525,14 @@ of the '#catlovers' space" is less useful since (a) users in the banned space could simply leave it at any time; (b) this functionality is already somewhat provided by [Moderation policy lists](https://matrix.org/docs/spec/client_server/r0.6.1#moderation-policy-lists). [↩](#a1) + +[2]: Note that there is nothing stopping users sending and +receiving invites in `public` rooms today, and they work as you might +expect. The only difference is that you are not *required* to hold an `invite` +when joining the room. [↩](#a2) + +[3]: This is a marginal decrease in security from the current +situation with invite-only rooms. Currently, a misbehaving server can allow +unauthorized users to join an invite-only room by first issuing an invite to +that user. In theory that can be prevented by raising the PL required to send +an invite, but in practice that is rarely done. [↩](#a2) From b40f7da8d2a49f2823e6599ab5a7d3747914d19c Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 11 Nov 2020 15:56:52 +0000 Subject: [PATCH 32/88] Record alternatives make sure we have records of dismissed alternatives --- proposals/1772-groups-as-rooms.md | 156 +++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 76520b92..e7d6eea7 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -258,6 +258,9 @@ This means that a new `m.room.power_levels` event would be generated whenever the membership of either `!mods` or `!users` changes. If a user is in both spaces, `!mods` takes priority because that is listed first. +If `mappings` is not a list, the whole event is ignored. Any entries in the list +which do not match the expected format are ignored. + #### Implementing the mapping When a new room is created, the server implicitly adds a "room admin bot" to @@ -284,6 +287,139 @@ access to it is itself restricted via `power_levels`. This could be enforced by the admin bot so that no `m.room.power_levels` events are generated unless `power_level_mappings` is appropriately restricted. +Some sort of rate-limiting may be required to handle the case where the mapped +space has a high rate of membership churn. + +#### Alternatives + +Things that were considered and dismissed: + +* Rather than defining the mapping in the room, define a template power-levels + event in a parent space, which will be inherited by all child rooms. For example: + + ```js + { + "type": "m.space.child_power_levels", + "state_key": "", + "content": { + // content as per regular power_levels event + } + } + ``` + + Problem 1: No automated mapping from space membership to user list, so the + user list would have to be maintained manually. On the other hand, this + could be fine in some situations, where we're just using the space to group + together rooms, rather than as a user list. + + Problem 2: No scope for nuance, where different rooms have slightly + different PLs. + + Problem 3: what happens to rooms where several spaces claim it as a child? + They end up fighting? + + Problem 4: Doesn't allow for random room admins to delegate their PLs to a + space without being admins in that space. + +* To implemplement the mapping, we require any user who is an admin in the + space (ie, anyone who has permission to change the access rights in the + space) to also be admins and members of any child rooms. + + Say Bob is an admin in #doglovers and makes a change that should be + propagated to all children of that space. His server is then responsible + for generating a power-levels event on his behalf for each room. + + Problem 1: Bob may not want to be a member of all such rooms. + + Problem 2: It will feel odd that Bob's user is seen to be generating PL + events every time someone comes and goes from the space. + + Problem 3: It doesn't allow users to set up their own rooms to mirror a + space, without having any particular control in that space (though it is + questionable if that is actually a useful feature, at least as far as PLs are + concerned.) + +* Another alternative for implementing the mapping: the user that created the + relationship event (or rather, their homeserver, using the user's ID) is + responsible for copying access controls into the room. + + Problem 1: What do you do if the admin who sets up the PL relationship + disappears? The humans have to step in and create a new admin? + + Problem 2: Again it seems odd that these PL changes come from a single user. + +* Is it possible to implement the mappings from multiple users, some of which + may not have PL 100? After all it's possible to set rooms up so that you can + change PL events without having PL 100. + + It gets horribly messy very quickly, where some admin users can make some + changes. So some get supressed and then get made later anyway by a different + admin user? + +* Is it possble to apply finer-grained control to the + `m.room.power_level_mappings` event than "you must be max(PL)"? Applying + restrictions post-hoc (ie, having the admin bot ignore settings which were + set by underpriviledged users) is an absolute minefield. It might be possible + to apply restrictions at the point that the event is set, but it sounds + fiddly and it's not clear there is a real use-case. + +* This solution smells a bit funny because of the expansions (causing all the + redundant mxids everywhere as the groups constantly get expanded every time + something happens). + + * Could we could put a hash of the space membership in the PL instead of + expanding the wole list, so that servers have a way to check if they are + applying the same list as everyone else? + + Feels like it will have bad failure modes: what is a server supposed to do + when the hash doesn't match? + + * Could version the space memberships, so you can compare with the source of + the space membership data? + + * PL events just record the delta from the previous one? (So a new server + would need to get all the PLs ever, but… is that a bad thing?) ... maybe + + These optimisations can all be punted down the road to a later room version. + +* Other ways of handling the merge of automatic and manual PL settings: + + * Add hints to the automated mapper so that it can maintain manually-assigned + PLs. This could either be another field in `power_levels` which plays no + part in event auth: + + ```js + { + "type": "m.room.power_levels", + "content": { + "users": { + "@roomadmin:example.com": 100, + "@spaceuser1:example.org": 50 + }, + "manual_users": { + "@roomadmin:example.com": 100 + } + } + } + ``` + + ... or stored in a separate event. Clients would be responsible for updating + both copies of the manually-assigned PLs on change. + + Problem: Requiring clients to make two changes feels fragile. What if they + get it wrong? what if they don't know about the second copy because they + haven't been designed to work in rooms in spaces? + + * Require that even regular PLs go through the automated mapper, by making + them an explicit input to that mapper, for example with entries in the + `m.room.power_level_mappings` event suggested above. + + Problem: Requires clients to distinguish between rooms where there is an + automated mapper, and those where the client should manipulate the PLs + directly. (Maybe that's not so bad? The presence of the `mappings` event + should be enough? But still sucks that there are two ways to do the same + thing, and clients which don't support spaces will get it wrong.) + ### Restricting room membership based on space membership A desirable feature is to give room admins the power to restrict membership of @@ -376,6 +512,24 @@ help. but it's unclear what the desired semantics are: the `allowed_spaces` list and SpaceA is removed. What should happen when the user leaves SpaceB? Are they exempt from the kick? +#### Alternatives + +* Maintain some sort of pre-approved list as the space membership changes in a + similar way to the PL mapping, possibly via a new membership state. + + Could lead to a lot of membership churn, from a centralised control point. + +* Base it on invite-only rooms, and generate invite events on the fly. Kind-of + ok, except that we'd want the invites to be seen as having a sender of a + management bot rather than an arbitrary user, which would mean that all joins + would have to go through that one server (even from servers that were already + participating in the room), which feels a bit grim. We could have multiple + admin bots to mitigate this, but it gets a bit messy. + +* Change the way that `allowed_spaces` and invites interact, so that an invite + does not exempt you from the `allowed_spaces` requirements. This would be + simpler to implement, but probably doesn't match the expected UX. + ## Future extensions The following sections are not blocking parts of this proposal, but are @@ -468,8 +622,8 @@ These dependencies are shared with profiles-as-rooms different querying users. (It may be possible to simulate this behaviour using smaller spaces). -## Unstable prefix +## Unstable prefix The following mapping will be used for identifiers in this MSC during development: From 4e3b0ed05f6b4fbc6a51de60ff3e54c5f254a430 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 11 Nov 2020 16:03:09 +0000 Subject: [PATCH 33/88] add a length limit to `order` --- proposals/1772-groups-as-rooms.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index e7d6eea7..4fde7d63 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -111,10 +111,10 @@ relationship can be expressed in one of two ways: The `order` key is a string which is used to provide a default ordering of siblings in the room list. (Rooms are sorted based on a lexicographic - ordering of `order` values; rooms with no `order` come last. `order`s - which are not strings, or do not consist solely of ascii characters in the - range `\x20` (space) to `\x7F` (`~`) are forbidden and should be ignored if - received.) + ordering of `order` values; rooms with no `order` come last. `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 should be ignored if received.) If `default` is set to `true`, that indicates a "default child": see [below](#default-children). From 3b2825f21dd0cec53cce1df4275a2c5bf1800564 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 11 Nov 2020 16:38:19 +0000 Subject: [PATCH 34/88] Descope autokick and rename allowed_spaces --- proposals/1772-groups-as-rooms.md | 52 +++++++++++++++++-------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 4fde7d63..c5dd3a60 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -435,7 +435,7 @@ We could represent the allowed spaces with additional content in the "state_key": "", "content": { "join_rule": "public", - "allowed_spaces": [ + "allowed_join": [ { "space": "!mods:example.org", "via": ["example.org"], @@ -453,11 +453,12 @@ XXX: would it be better to put it in a separate event? Doing so would probably require us to come up with a new `join_rule` state to tell servers to go and look for the allowed spaces. -The `allowed_spaces` key applies a restriction to the `public` join rule, so -that only users in those spaces should be allowed to join. Additionally, users -who have received an explicit `invite` event are allowed to join[2](#f2). If the `allowed_spaces` key is an empty list (or not a -list at all), no users are allowed to join without an invite. +The `allowed_join` key applies a restriction to the `public` join rule, so that +only users satisfying one or more of the requirements should be allowed to +join. Additionally, users who have received an explicit `invite` event are +allowed to join[2](#f2). If the `allowed_join` key is an +empty list (or not a list at all), no users are allowed to join without an +invite. Unlike the regular `invite` join rule, the restriction cannot be enforced over federation by event authorization, so servers in the room are trusted not to @@ -471,10 +472,13 @@ permitted if the user has a valid invite or is in one of the listed spaces XXX: redacting the join_rules above will reset the room to public, which feels dangerous? A new room version is not absolutely required here, but may be advisable to -ensure that servers that do not support `allowed_spaces` do not join the room +ensure that servers that do not support `allowed_join` do not join the room (and would also allow us to tweak the redaction rules to avoid the foot-gun). -#### Kicking users out when they leave the allowed_space +#### Kicking users out when they leave the allowed space + +XXX: this will probably be a future extension, rather than part of the initial +implementation of `allowed_join`. In the above example, suppose `@bob:server.example` leaves `!users:example.org`: they should be removed from the room. One option is to leave the departure up @@ -484,18 +488,18 @@ the room would still see Bob in the room (and their servers would attempt to send message traffic to it). Instead, we make the removal the responsibility of the room's admin bot (see -above): the bot is expected to peek into any `allowed_spaces` and kick any -users who are members of the room and leave the union of the allowed +above): the bot is expected to peek into any spaces in `allowed_join` and kick +any users who are members of the room and leave the union of the allowed spaces. (XXX: should users in a space be kicked when that space is removed from the -`allowed_spaces` list? We think not, by analogy with what happens when you -switch the join rules from `public` to `invite`.) +`allowed_join` list? We think not, by analogy with what happens when you switch +the join rules from `public` to `invite`.) One problem here is that it will lead to users who joined via an invite being kicked. For example: * `@bob:server.example` creates an invite-only room. - * Later, the `join_rules` are switched to `public`, with an `allowed_space` of + * Later, the `join_rules` are switched to `public`, with an `allowed_join` of `!users:example.org`, of which Bob happens to be a member. * Later still, Bob leaves `!users:example.org`. * Bob is kicked from his own room. @@ -504,12 +508,12 @@ Fixing this is thorny. Some sort of annotation on the membership events might help. but it's unclear what the desired semantics are: * Assuming that users in a given space are *not* kicked when that space is - removed from `allowed_spaces`, are those users then given a pass to remain + removed from `allowed_join`, are those users then given a pass to remain in the room indefinitely? What happens if the space is added back to - `allowed_spaces` and *then* the user leaves it? + `allowed_join` and *then* the user leaves it? * Suppose a user joins a room via a space (SpaceA). Later, SpaceB is added to - the `allowed_spaces` list and SpaceA is removed. What should happen when the + the `allowed_join` list and SpaceA is removed. What should happen when the user leaves SpaceB? Are they exempt from the kick? #### Alternatives @@ -526,8 +530,8 @@ help. but it's unclear what the desired semantics are: participating in the room), which feels a bit grim. We could have multiple admin bots to mitigate this, but it gets a bit messy. -* Change the way that `allowed_spaces` and invites interact, so that an invite - does not exempt you from the `allowed_spaces` requirements. This would be +* Change the way that `allowed_join` and invites interact, so that an invite + does not exempt you from the `allowed_join` requirements. This would be simpler to implement, but probably doesn't match the expected UX. ## Future extensions @@ -598,14 +602,16 @@ These dependencies are shared with profiles-as-rooms ## Security considerations -* The peek server has significant power. TODO: expand. +* The peek server has significant power. For example, a poorly chosen peek + server could lie about the space membership and add an + `@evil_user:example.org`. -* The `allowed_spaces` feature places increased trust in the servers in the +* The `allowed_join` feature places increased trust in the servers in the room. We consider this acceptable: if you don't want evil servers randomly joining spurious users into your rooms, then a) don't let evil servers in - your room in the first place, b) don't use `allowed_spaces` lists, given the + your room in the first place, b) don't use `allowed_join` lists, given the expansion increases the attack surface anyway by letting members in other - rooms dictate who's allowed into your room". + rooms dictate who's allowed into your room. ## Tradeoffs @@ -634,7 +640,7 @@ Proposed final identifier | Purpose | Development identifier `m.space.parent` | event type | `org.matrix.msc1772.space.parent` `m.room.power_level_mappings` | event type | `org.matrix.msc1772.room.power_level_mappings` `auto_users` | key in `m.room.power_levels` event | `org.matrix.msc1772.auto_users` - +`allowed_join` | key in `m.room.join_rules` event | `org.matrix.msc1772.allowed_join` ## History From e6a69418458d0d23ba82c2ed24a4f37604d7cae8 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 11 Nov 2020 16:50:21 +0000 Subject: [PATCH 35/88] rename allowed_join again --- proposals/1772-groups-as-rooms.md | 42 ++++++++++++++++--------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index c5dd3a60..2e2b77fd 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -435,7 +435,7 @@ We could represent the allowed spaces with additional content in the "state_key": "", "content": { "join_rule": "public", - "allowed_join": [ + "allow": [ { "space": "!mods:example.org", "via": ["example.org"], @@ -449,14 +449,10 @@ We could represent the allowed spaces with additional content in the } ``` -XXX: would it be better to put it in a separate event? Doing so would probably -require us to come up with a new `join_rule` state to tell servers to go and -look for the allowed spaces. - -The `allowed_join` key applies a restriction to the `public` join rule, so that +The `allow` key applies a restriction to the `public` join rule, so that only users satisfying one or more of the requirements should be allowed to join. Additionally, users who have received an explicit `invite` event are -allowed to join[2](#f2). If the `allowed_join` key is an +allowed to join[2](#f2). If the `allow` key is an empty list (or not a list at all), no users are allowed to join without an invite. @@ -472,13 +468,13 @@ permitted if the user has a valid invite or is in one of the listed spaces XXX: redacting the join_rules above will reset the room to public, which feels dangerous? A new room version is not absolutely required here, but may be advisable to -ensure that servers that do not support `allowed_join` do not join the room +ensure that servers that do not support `allow` do not join the room (and would also allow us to tweak the redaction rules to avoid the foot-gun). #### Kicking users out when they leave the allowed space XXX: this will probably be a future extension, rather than part of the initial -implementation of `allowed_join`. +implementation of `allow`. In the above example, suppose `@bob:server.example` leaves `!users:example.org`: they should be removed from the room. One option is to leave the departure up @@ -488,18 +484,18 @@ the room would still see Bob in the room (and their servers would attempt to send message traffic to it). Instead, we make the removal the responsibility of the room's admin bot (see -above): the bot is expected to peek into any spaces in `allowed_join` and kick +above): the bot is expected to peek into any spaces in `allow` and kick any users who are members of the room and leave the union of the allowed spaces. (XXX: should users in a space be kicked when that space is removed from the -`allowed_join` list? We think not, by analogy with what happens when you switch +`allow` list? We think not, by analogy with what happens when you switch the join rules from `public` to `invite`.) One problem here is that it will lead to users who joined via an invite being kicked. For example: * `@bob:server.example` creates an invite-only room. - * Later, the `join_rules` are switched to `public`, with an `allowed_join` of + * Later, the `join_rules` are switched to `public`, with an `allow` of `!users:example.org`, of which Bob happens to be a member. * Later still, Bob leaves `!users:example.org`. * Bob is kicked from his own room. @@ -508,12 +504,12 @@ Fixing this is thorny. Some sort of annotation on the membership events might help. but it's unclear what the desired semantics are: * Assuming that users in a given space are *not* kicked when that space is - removed from `allowed_join`, are those users then given a pass to remain + removed from `allow`, are those users then given a pass to remain in the room indefinitely? What happens if the space is added back to - `allowed_join` and *then* the user leaves it? + `allow` and *then* the user leaves it? * Suppose a user joins a room via a space (SpaceA). Later, SpaceB is added to - the `allowed_join` list and SpaceA is removed. What should happen when the + the `allow` list and SpaceA is removed. What should happen when the user leaves SpaceB? Are they exempt from the kick? #### Alternatives @@ -530,10 +526,16 @@ help. but it's unclear what the desired semantics are: participating in the room), which feels a bit grim. We could have multiple admin bots to mitigate this, but it gets a bit messy. -* Change the way that `allowed_join` and invites interact, so that an invite - does not exempt you from the `allowed_join` requirements. This would be +* Change the way that `allow` and invites interact, so that an invite + does not exempt you from the `allow` requirements. This would be simpler to implement, but probably doesn't match the expected UX. +* Put the `allow` rules in a separate event? This is attractive because + `join_rules` are involved in event auth and hence state resolution, and the + fewer events that state res has to grapple with the better. However, doing + this would probably require us to come up with a new `join_rule` state to + tell servers to go and look for the allowed spaces. + ## Future extensions The following sections are not blocking parts of this proposal, but are @@ -606,10 +608,10 @@ These dependencies are shared with profiles-as-rooms server could lie about the space membership and add an `@evil_user:example.org`. -* The `allowed_join` feature places increased trust in the servers in the +* The `allow` feature for `join_rules` places increased trust in the servers in the room. We consider this acceptable: if you don't want evil servers randomly joining spurious users into your rooms, then a) don't let evil servers in - your room in the first place, b) don't use `allowed_join` lists, given the + your room in the first place, b) don't use `allow` lists, given the expansion increases the attack surface anyway by letting members in other rooms dictate who's allowed into your room. @@ -640,7 +642,7 @@ Proposed final identifier | Purpose | Development identifier `m.space.parent` | event type | `org.matrix.msc1772.space.parent` `m.room.power_level_mappings` | event type | `org.matrix.msc1772.room.power_level_mappings` `auto_users` | key in `m.room.power_levels` event | `org.matrix.msc1772.auto_users` -`allowed_join` | key in `m.room.join_rules` event | `org.matrix.msc1772.allowed_join` +`allow` | key in `m.room.join_rules` event | `org.matrix.msc1772.allow` ## History From fbad757ceb4f5c63cee0afa701043cc263f26927 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 11 Nov 2020 17:52:16 +0000 Subject: [PATCH 36/88] update dependencies links --- proposals/1772-groups-as-rooms.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 2e2b77fd..b683011c 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -590,13 +590,13 @@ child rooms? Seems to have some of the same problems as inheriting PLs. ## Dependencies - * [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) for room - types. + * (possibly?) [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) + for room types. - * [MSC1776](https://github.com/matrix-org/matrix-doc/issues/1776) for + * [MSC2753](https://github.com/matrix-org/matrix-doc/issues/2753) for effective peeking over the C/S API. - * [MSC1777](https://github.com/matrix-org/matrix-doc/issues/1777) (or similar) + * [MSC2444](https://github.com/matrix-org/matrix-doc/issues/2444) (or similar) for effective peeking over Federation. These dependencies are shared with profiles-as-rooms From 1f1e3c9a0f1574eaa5a589c60e5aba09b2d4822b Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 16 Nov 2020 11:50:17 +0000 Subject: [PATCH 37/88] MSC1840 is in --- proposals/1772-groups-as-rooms.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index b683011c..452ca131 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -41,8 +41,9 @@ Spaces are referred to primarily by their alias, for example Space-rooms are distinguished from regular messaging rooms by the `m.room.type` of `m.space` (see -[MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840)). XXX nobody has -convinced me this is actually required. +[MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840)). This allows +clients to offer slightly customised user experience depending on the purpose +of the room. Space-rooms may have `m.room.name` and `m.room.topic` state events in the same way as a normal room. @@ -590,8 +591,8 @@ child rooms? Seems to have some of the same problems as inheriting PLs. ## Dependencies - * (possibly?) [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) - for room types. + * [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) for room + types. * [MSC2753](https://github.com/matrix-org/matrix-doc/issues/2753) for effective peeking over the C/S API. @@ -638,6 +639,7 @@ development: Proposed final identifier | Purpose | Development identifier ------------------------------- | ------- | ---- +`m.space` | room type | `org.matrix.msc1772.space` `m.space.child` | event type | `org.matrix.msc1772.space.child` `m.space.parent` | event type | `org.matrix.msc1772.space.parent` `m.room.power_level_mappings` | event type | `org.matrix.msc1772.room.power_level_mappings` From d4abe406772171754b9f816249c482930823f964 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 16 Nov 2020 11:57:04 +0000 Subject: [PATCH 38/88] one parent per room --- proposals/1772-groups-as-rooms.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 452ca131..93d0b97f 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -119,16 +119,16 @@ relationship can be expressed in one of two ways: If `default` is set to `true`, that indicates a "default child": see [below](#default-children). - 2. Separately, rooms can claim parents via `m.room.parent` state - events, where the `state_key` is the room ID of the parent space: + 2. Separately, rooms can claim parents via the `m.room.parent` state + event: ```js { "type": "m.room.parent", - "state_key": "!space:example.com", + "state_key": "", "content": { + "room_id": "!space:example.com", "via": ["example.com"] - "present": true } } ``` @@ -145,6 +145,10 @@ relationship can be expressed in one of two ways: Where the parent space also claims a parent, clients can recursively peek into the grandparent space, and so on. + Note that each room can only declare a single parent. This could be + extended in future to declare additional parents, but more investigation + into appropriate semantics is needed. + This structure means that rooms can end up with multiple parents. This implies that the room will appear multiple times in the room list hierarchy. @@ -641,7 +645,7 @@ Proposed final identifier | Purpose | Development identifier ------------------------------- | ------- | ---- `m.space` | room type | `org.matrix.msc1772.space` `m.space.child` | event type | `org.matrix.msc1772.space.child` -`m.space.parent` | event type | `org.matrix.msc1772.space.parent` +`m.room.parent` | event type | `org.matrix.msc1772.room.parent` `m.room.power_level_mappings` | event type | `org.matrix.msc1772.room.power_level_mappings` `auto_users` | key in `m.room.power_levels` event | `org.matrix.msc1772.auto_users` `allow` | key in `m.room.join_rules` event | `org.matrix.msc1772.allow` From 39af7f32494b849880ddf1cc0bfe5a93313d2ab1 Mon Sep 17 00:00:00 2001 From: Peter Gervai Date: Tue, 17 Nov 2020 16:30:17 +0100 Subject: [PATCH 39/88] Update 1772-groups-as-rooms.md (#2866) Typo. --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 93d0b97f..ba9f3efb 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -75,7 +75,7 @@ relationship can be expressed in one of two ways: 1. The admins of a space can advertise rooms and subspaces for their space by setting `m.space.child` state events. The `state_key` is the ID of a child - room or space, and the content should ontain a `via` key which gives a list + room or space, and the content should contain a `via` key which gives a list of candidate servers that can be used to join the room. `present: true` key is included to distinguish from a deleted state event. Something like: From 45f260836d81155b18989234220cd0e560c12e66 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 19 Nov 2020 22:53:49 +0000 Subject: [PATCH 40/88] No cross-room auth --- proposals/1772-groups-as-rooms.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index ba9f3efb..2bd7d6d0 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -299,6 +299,16 @@ space has a high rate of membership churn. Things that were considered and dismissed: +* Extend the auth rules to include state from other rooms. Although this feels + cleaner, a robust implementation would be a hugely complicated + undertaking. In particular, room state resolution is closely linked to event + authorisation, and is already highly complex and hard to reason about, and + yet is fundamental to the security of Matrix. + + In short, we believe such a change would require significant research and + modelling. A solution based on such a foundation could not practically be + implemented in the near future. + * Rather than defining the mapping in the room, define a template power-levels event in a parent space, which will be inherited by all child rooms. For example: From 6cc3995ce825e5afbf29272967aef8adde899597 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 20 Nov 2020 13:22:44 +0000 Subject: [PATCH 41/88] explain a bit --- proposals/1772-groups-as-rooms.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 2bd7d6d0..2f794bf1 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -226,6 +226,8 @@ add an `auto_users` key: A user's power level is then specified by an entry in *either* `users` or `auto_users`. Where a user appears in both sections, `users` takes precedence. +The new `auto_users` key is maintained by a bot user, as described below. + `auto_users` is subject to all of the same authorization checks as the existing `users` key (see https://matrix.org/docs/spec/rooms/v1#authorization-rules, paragraphs 10a, 10d, 10e). @@ -278,8 +280,8 @@ localpart `@:example.com`. This bot is then responsible for monitoring the `power_level_mappings` state, and peeking into any spaces mentioned in the content. It can then issue new -`m.room.power_levels` events whenever the membership of the spaces in question -changes. +`m.room.power_levels` events, updating the value of `auto_users`, whenever the +membership of the spaces in question changes. It is possible that the admin bot is unable to perform the mapping (for example, the space cannot be peeked; or the membership of the space is so large From 51aa5e2c40af2c69a58c4a2384dd9c3c75166d8f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Thu, 26 Nov 2020 17:54:54 +0000 Subject: [PATCH 42/88] Update proposals/1772-groups-as-rooms.md Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 2f794bf1..e25735bc 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -385,7 +385,7 @@ Things that were considered and dismissed: something happens). * Could we could put a hash of the space membership in the PL instead of - expanding the wole list, so that servers have a way to check if they are + expanding the whole list, so that servers have a way to check if they are applying the same list as everyone else? Feels like it will have bad failure modes: what is a server supposed to do From 69897584e1365b8d7c3e57190d064edca55cce9f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Mon, 4 Jan 2021 13:43:59 +0000 Subject: [PATCH 43/88] Update proposals/1772-groups-as-rooms.md Co-authored-by: Matthew Hodgson --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index e25735bc..fbdaa485 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -635,7 +635,7 @@ These dependencies are shared with profiles-as-rooms ## Tradeoffs * If the membership of a space would be large (for example: an organisation of - several thousand people), this membership has to copied entirely into the + several thousand people), this membership has to be copied entirely into the room, rather than querying/searching incrementally. * If the membership list is based on an external service such as LDAP, it is From 037894a64155e9e2c62449e191858bf68f64b20d Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 13 Jan 2021 14:01:17 +0000 Subject: [PATCH 44/88] replace 'default' with 'auto_join' --- proposals/1772-groups-as-rooms.md | 34 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index fbdaa485..44f79e43 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -96,7 +96,7 @@ relationship can be expressed in one of two ways: "via": ["example.com"], "present": true, "order": "abcd", - "default": true + "auto_join": true } } @@ -117,7 +117,9 @@ relationship can be expressed in one of two ways: `\x20` (space) to `\x7F` (`~`), or consist of more than 50 characters, are forbidden and should be ignored if received.) - If `default` is set to `true`, that indicates a "default child": see [below](#default-children). + If `auto_join` is set to `true`, that indicates that the child should be + automatically joined by members of the space see + [below](#auto-joined-children). 2. Separately, rooms can claim parents via the `m.room.parent` state event: @@ -168,17 +170,29 @@ Cycles in the parent->child and child->parent relationships are *not* permitted, but clients (and servers) should be aware that they may be encountered, and ignore the relationship rather than recursing infinitely. -### Default children +### Auto-joined children -The `default` flag on a child listing allows a space admin to list the -"default" sub-spaces and rooms in that space. This means that when a user joins -the parent space, they will automatically be joined to those default -children. +The `auto_join` flag on a child listing allows a space admin to list the +sub-spaces and rooms in that space which should be automatically joined by +members of that space. -XXX implement this on the client or server? +Joining should be performed by the client. This can optionally be sped up by +using [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946) to get a +summary of the spacetree to be joined, and then using a batch join API (when +available) to join whichever subset of it makes most sense for the client's +UX. -Clients could display the default children in the room list whenever the space -appears in the list. +Obviously auto-joining can be a DoS vector, and we consider it to be antisocial +for a space to try to join its users to more than ~100 children. + +Clients could display the auto-joined children in the room list whenever the +space appears in the list - thus helping users discover other rooms in a space +even if they're not joined to that space. + +XXX: I still think it's more common that a space admin will want users to know +that a child exists (by showing it in the room list), rather than force them to +actually join it. So this would be an `advertise` flag or something on the child. +Matthew to discuss with Nad... ### Long description From 803e70a8b33fd8301d94487282856976e4b5ded1 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 13 Jan 2021 14:18:39 +0000 Subject: [PATCH 45/88] typo --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 44f79e43..0e2cf0ee 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -118,7 +118,7 @@ relationship can be expressed in one of two ways: forbidden and should be ignored if received.) If `auto_join` is set to `true`, that indicates that the child should be - automatically joined by members of the space see + automatically joined by members of the space: see [below](#auto-joined-children). 2. Separately, rooms can claim parents via the `m.room.parent` state From 42c332bd88c94162d238c59a69eecbd7f7ba1b0c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 13 Jan 2021 15:34:50 +0000 Subject: [PATCH 46/88] fix parent claiming plurality --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 0e2cf0ee..8e3e4852 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -121,7 +121,7 @@ relationship can be expressed in one of two ways: automatically joined by members of the space: see [below](#auto-joined-children). - 2. Separately, rooms can claim parents via the `m.room.parent` state + 2. Separately, rooms can claim a parent via the `m.room.parent` state event: ```js From 2de3dc4f70b438b878eb52aa0c16532284a5775e Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 13 Jan 2021 15:41:31 +0000 Subject: [PATCH 47/88] more plurality fixing --- proposals/1772-groups-as-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 8e3e4852..d4285e6a 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -151,8 +151,8 @@ relationship can be expressed in one of two ways: extended in future to declare additional parents, but more investigation into appropriate semantics is needed. -This structure means that rooms can end up with multiple parents. This implies -that the room will appear multiple times in the room list hierarchy. +This structure means that rooms can end up appearing multiple times in the +room list hierarchy, given they can be children of multiple different spaces. In a typical hierarchy, we expect *both* parent->child and child->parent relationships to exist, so that the space can be discovered from the room, and From 302d5d87b4138704538f60195878451924561eb4 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 13 Jan 2021 17:29:43 +0000 Subject: [PATCH 48/88] clarify autojoin and mention 'suggested' rooms --- proposals/1772-groups-as-rooms.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index d4285e6a..0d49dba4 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -183,16 +183,20 @@ available) to join whichever subset of it makes most sense for the client's UX. Obviously auto-joining can be a DoS vector, and we consider it to be antisocial -for a space to try to join its users to more than ~100 children. +for a space to try to autojoin its members to more than 100 children (in total). Clients could display the auto-joined children in the room list whenever the space appears in the list - thus helping users discover other rooms in a space -even if they're not joined to that space. - -XXX: I still think it's more common that a space admin will want users to know -that a child exists (by showing it in the room list), rather than force them to -actually join it. So this would be an `advertise` flag or something on the child. -Matthew to discuss with Nad... +even if they're not joined to that space. For instance, if you join +`#matrix:matrix.org`, your client could show that room in the context of its +parent space, with that space's autojoined children shown alongside it as +siblings. + +It may also be useful to have a way to "suggest" that members of a space +should join certain children (but without actually autojoining them) - to +advertise particular rooms more prominently than in the room directory. +However, this can be added in a later MSC if it's found to be needed in +practice. ### Long description From a0d06c7bd795275f083594c821b72e7e053a8125 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 01:34:10 +0000 Subject: [PATCH 49/88] factor out ACLs into a separate MSC --- proposals/1772-groups-as-rooms.md | 378 ------------------------------ 1 file changed, 378 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 0d49dba4..39cd9622 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -208,369 +208,6 @@ contains a `msgtype` and possibly `formatted_body`). TODO: this could also be done via pinned messages. Failing that `m.room.description` should probably be a separate MSC. -### Managing power levels via spaces - -TODO: much of this is orthogonal to the headline feature of "spaces", and -should be moved to a separate MSC. - -One use-case for spaces is to help manage power levels across a group of -rooms. For example: "Jim has just joined the management team at my company. He -should have moderator rights across all of the company rooms." - -Since the event-authorisation rules cannot easily be extended to consider -membership in other rooms, we must map any changes in space membership onto -real `m.room.power_levels` events. - -#### Extending the power_levels event - -We now have a mix of manually- and automatically- maintained power-level -data. To support this, we extend the existing `m.room.power_levels` event to -add an `auto_users` key: - -```js -{ - "type": "m.room.power_levels", - "content": { - "users": { - "@roomadmin:example.com": 100 - }, - "auto_users": { - "@spaceuser1:example.org": 50 - } - } -} -``` - -A user's power level is then specified by an entry in *either* `users` or -`auto_users`. Where a user appears in both sections, `users` takes precedence. - -The new `auto_users` key is maintained by a bot user, as described below. - -`auto_users` is subject to all of the same authorization checks as the existing -`users` key (see https://matrix.org/docs/spec/rooms/v1#authorization-rules, -paragraphs 10a, 10d, 10e). - -This change necessitates a new room version. - -#### Representing the mapping from spaces to power levels - -The desired mapping from spaces to power levels is defined in a new state event -type, `m.room.power_level_mappings`. The content should contain a `mappings` -key which is an ordered list, for example: - -```js -{ - "type": "m.room.power_level_mappings", - "state_key": "", - "content": { - "mappings": [ - { - "space": "!mods:example.org", - "via": ["example.org"], - "power_level": 50 - }, - { - "space": "!users:example.org", - "via": ["example.org"], - "power_level": 1 - } - ] - } -} -``` - -This means that a new `m.room.power_levels` event would be generated whenever -the membership of either `!mods` or `!users` changes. If a user is in both -spaces, `!mods` takes priority because that is listed first. - -If `mappings` is not a list, the whole event is ignored. Any entries in the list -which do not match the expected format are ignored. - -#### Implementing the mapping - -When a new room is created, the server implicitly adds a "room admin bot" to -the room, with the maximum power-level of any of the initial users. -(Homeservers should implement this "bot" internally, rather than requiring -separate software to be installed.) - -It is proposed that this "admin bot" use the special user ID with empty -localpart `@:example.com`. - -This bot is then responsible for monitoring the `power_level_mappings` state, -and peeking into any spaces mentioned in the content. It can then issue new -`m.room.power_levels` events, updating the value of `auto_users`, whenever the -membership of the spaces in question changes. - -It is possible that the admin bot is unable to perform the mapping (for -example, the space cannot be peeked; or the membership of the space is so large -that it cannot be expanded into a single `m.room.power_levels` event). It is -proposed that the bot could notify the room of any problems via -`m.room.message` messages of type `m.msgtype`. - -Clearly, updating this event type is extremely powerful. It is expected that -access to it is itself restricted via `power_levels`. This could be enforced by -the admin bot so that no `m.room.power_levels` events are generated unless -`power_level_mappings` is appropriately restricted. - -Some sort of rate-limiting may be required to handle the case where the mapped -space has a high rate of membership churn. - -#### Alternatives - -Things that were considered and dismissed: - -* Extend the auth rules to include state from other rooms. Although this feels - cleaner, a robust implementation would be a hugely complicated - undertaking. In particular, room state resolution is closely linked to event - authorisation, and is already highly complex and hard to reason about, and - yet is fundamental to the security of Matrix. - - In short, we believe such a change would require significant research and - modelling. A solution based on such a foundation could not practically be - implemented in the near future. - -* Rather than defining the mapping in the room, define a template power-levels - event in a parent space, which will be inherited by all child rooms. For example: - - ```js - { - "type": "m.space.child_power_levels", - "state_key": "", - "content": { - // content as per regular power_levels event - } - } - ``` - - Problem 1: No automated mapping from space membership to user list, so the - user list would have to be maintained manually. On the other hand, this - could be fine in some situations, where we're just using the space to group - together rooms, rather than as a user list. - - Problem 2: No scope for nuance, where different rooms have slightly - different PLs. - - Problem 3: what happens to rooms where several spaces claim it as a child? - They end up fighting? - - Problem 4: Doesn't allow for random room admins to delegate their PLs to a - space without being admins in that space. - -* To implemplement the mapping, we require any user who is an admin in the - space (ie, anyone who has permission to change the access rights in the - space) to also be admins and members of any child rooms. - - Say Bob is an admin in #doglovers and makes a change that should be - propagated to all children of that space. His server is then responsible - for generating a power-levels event on his behalf for each room. - - Problem 1: Bob may not want to be a member of all such rooms. - - Problem 2: It will feel odd that Bob's user is seen to be generating PL - events every time someone comes and goes from the space. - - Problem 3: It doesn't allow users to set up their own rooms to mirror a - space, without having any particular control in that space (though it is - questionable if that is actually a useful feature, at least as far as PLs are - concerned.) - -* Another alternative for implementing the mapping: the user that created the - relationship event (or rather, their homeserver, using the user's ID) is - responsible for copying access controls into the room. - - Problem 1: What do you do if the admin who sets up the PL relationship - disappears? The humans have to step in and create a new admin? - - Problem 2: Again it seems odd that these PL changes come from a single user. - -* Is it possible to implement the mappings from multiple users, some of which - may not have PL 100? After all it's possible to set rooms up so that you can - change PL events without having PL 100. - - It gets horribly messy very quickly, where some admin users can make some - changes. So some get supressed and then get made later anyway by a different - admin user? - -* Is it possble to apply finer-grained control to the - `m.room.power_level_mappings` event than "you must be max(PL)"? Applying - restrictions post-hoc (ie, having the admin bot ignore settings which were - set by underpriviledged users) is an absolute minefield. It might be possible - to apply restrictions at the point that the event is set, but it sounds - fiddly and it's not clear there is a real use-case. - -* This solution smells a bit funny because of the expansions (causing all the - redundant mxids everywhere as the groups constantly get expanded every time - something happens). - - * Could we could put a hash of the space membership in the PL instead of - expanding the whole list, so that servers have a way to check if they are - applying the same list as everyone else? - - Feels like it will have bad failure modes: what is a server supposed to do - when the hash doesn't match? - - * Could version the space memberships, so you can compare with the source of - the space membership data? - - * PL events just record the delta from the previous one? (So a new server - would need to get all the PLs ever, but… is that a bad thing?) ... maybe - - These optimisations can all be punted down the road to a later room version. - -* Other ways of handling the merge of automatic and manual PL settings: - - * Add hints to the automated mapper so that it can maintain manually-assigned - PLs. This could either be another field in `power_levels` which plays no - part in event auth: - - ```js - { - "type": "m.room.power_levels", - "content": { - "users": { - "@roomadmin:example.com": 100, - "@spaceuser1:example.org": 50 - }, - "manual_users": { - "@roomadmin:example.com": 100 - } - } - } - ``` - - ... or stored in a separate event. Clients would be responsible for updating - both copies of the manually-assigned PLs on change. - - Problem: Requiring clients to make two changes feels fragile. What if they - get it wrong? what if they don't know about the second copy because they - haven't been designed to work in rooms in spaces? - - * Require that even regular PLs go through the automated mapper, by making - them an explicit input to that mapper, for example with entries in the - `m.room.power_level_mappings` event suggested above. - - Problem: Requires clients to distinguish between rooms where there is an - automated mapper, and those where the client should manipulate the PLs - directly. (Maybe that's not so bad? The presence of the `mappings` event - should be enough? But still sucks that there are two ways to do the same - thing, and clients which don't support spaces will get it wrong.) - -### Restricting room membership based on space membership - -A desirable feature is to give room admins the power to restrict membership of -their room based on the membership of spaces (for example, "members of the -#doglovers space can join this room without an invitation"[1](#f1)). - -We could represent the allowed spaces with additional content in the -`m.room.join_rules` event. For example: - -```js -{ - "type": "m.room.join_rules", - "state_key": "", - "content": { - "join_rule": "public", - "allow": [ - { - "space": "!mods:example.org", - "via": ["example.org"], - }, - { - "space": "!users:example.org", - "via": ["example.org"], - } - ] - } -} -``` - -The `allow` key applies a restriction to the `public` join rule, so that -only users satisfying one or more of the requirements should be allowed to -join. Additionally, users who have received an explicit `invite` event are -allowed to join[2](#f2). If the `allow` key is an -empty list (or not a list at all), no users are allowed to join without an -invite. - -Unlike the regular `invite` join rule, the restriction cannot be enforced over -federation by event authorization, so servers in the room are trusted not to -allow invalid users to join.[3](#f3) - -When a server receives a `/join` request from a client or a -`/make_join`/`/send_join` request from a server, the request should only be -permitted if the user has a valid invite or is in one of the listed spaces -(established by peeking). - -XXX: redacting the join_rules above will reset the room to public, which feels dangerous? - -A new room version is not absolutely required here, but may be advisable to -ensure that servers that do not support `allow` do not join the room -(and would also allow us to tweak the redaction rules to avoid the foot-gun). - -#### Kicking users out when they leave the allowed space - -XXX: this will probably be a future extension, rather than part of the initial -implementation of `allow`. - -In the above example, suppose `@bob:server.example` leaves `!users:example.org`: -they should be removed from the room. One option is to leave the departure up -to Bob's server `server.example`, but this places a relatively high level of trust -in that server. Additionally, if `server.example` were offline, other users in -the room would still see Bob in the room (and their servers would attempt to -send message traffic to it). - -Instead, we make the removal the responsibility of the room's admin bot (see -above): the bot is expected to peek into any spaces in `allow` and kick -any users who are members of the room and leave the union of the allowed -spaces. - -(XXX: should users in a space be kicked when that space is removed from the -`allow` list? We think not, by analogy with what happens when you switch -the join rules from `public` to `invite`.) - -One problem here is that it will lead to users who joined via an invite being -kicked. For example: - * `@bob:server.example` creates an invite-only room. - * Later, the `join_rules` are switched to `public`, with an `allow` of - `!users:example.org`, of which Bob happens to be a member. - * Later still, Bob leaves `!users:example.org`. - * Bob is kicked from his own room. - -Fixing this is thorny. Some sort of annotation on the membership events might -help. but it's unclear what the desired semantics are: - - * Assuming that users in a given space are *not* kicked when that space is - removed from `allow`, are those users then given a pass to remain - in the room indefinitely? What happens if the space is added back to - `allow` and *then* the user leaves it? - - * Suppose a user joins a room via a space (SpaceA). Later, SpaceB is added to - the `allow` list and SpaceA is removed. What should happen when the - user leaves SpaceB? Are they exempt from the kick? - -#### Alternatives - -* Maintain some sort of pre-approved list as the space membership changes in a - similar way to the PL mapping, possibly via a new membership state. - - Could lead to a lot of membership churn, from a centralised control point. - -* Base it on invite-only rooms, and generate invite events on the fly. Kind-of - ok, except that we'd want the invites to be seen as having a sender of a - management bot rather than an arbitrary user, which would mean that all joins - would have to go through that one server (even from servers that were already - participating in the room), which feels a bit grim. We could have multiple - admin bots to mitigate this, but it gets a bit messy. - -* Change the way that `allow` and invites interact, so that an invite - does not exempt you from the `allow` requirements. This would be - simpler to implement, but probably doesn't match the expected UX. - -* Put the `allow` rules in a separate event? This is attractive because - `join_rules` are involved in event auth and hence state resolution, and the - fewer events that state res has to grapple with the better. However, doing - this would probably require us to come up with a new `join_rule` state to - tell servers to go and look for the allowed spaces. - ## Future extensions The following sections are not blocking parts of this proposal, but are @@ -618,11 +255,6 @@ One way this might be implemented is: to do this check (and both servers and clients can cache the results fairly aggressively.) -### Inheriting join rules - -If you make a parent space invite-only, should that (optionally?) cascade into -child rooms? Seems to have some of the same problems as inheriting PLs. - ## Dependencies * [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) for room @@ -643,13 +275,6 @@ These dependencies are shared with profiles-as-rooms server could lie about the space membership and add an `@evil_user:example.org`. -* The `allow` feature for `join_rules` places increased trust in the servers in the - room. We consider this acceptable: if you don't want evil servers randomly - joining spurious users into your rooms, then a) don't let evil servers in - your room in the first place, b) don't use `allow` lists, given the - expansion increases the attack surface anyway by letting members in other - rooms dictate who's allowed into your room. - ## Tradeoffs * If the membership of a space would be large (for example: an organisation of @@ -676,9 +301,6 @@ Proposed final identifier | Purpose | Development identifier `m.space` | room type | `org.matrix.msc1772.space` `m.space.child` | event type | `org.matrix.msc1772.space.child` `m.room.parent` | event type | `org.matrix.msc1772.room.parent` -`m.room.power_level_mappings` | event type | `org.matrix.msc1772.room.power_level_mappings` -`auto_users` | key in `m.room.power_levels` event | `org.matrix.msc1772.auto_users` -`allow` | key in `m.room.join_rules` event | `org.matrix.msc1772.allow` ## History From b8e3a0b45d7f2a829135b947e8a453d07b418466 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 01:34:34 +0000 Subject: [PATCH 50/88] include invite state notes --- proposals/1772-groups-as-rooms.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 39cd9622..af6d23af 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -65,7 +65,12 @@ to see the directory of rooms within the space by peeking into the space-room (thus avoiding the need to add `m.room.member` events to the event graph within the room). -Join rules, invites and 3PID invites work as for a normal room. +Join rules, invites and 3PID invites work as for a normal room, with the +exception that `invite_state` sent along with invites should be amended to +include the event containing the type `m.space`, to allow clients to discern +whether an invite is to a space-room or not. + +XXX: Should we also include a MSC2946 summary of the space in the invite too? ### Relationship between rooms and spaces From f8fb32518da79f7aa157e41ae440bd5ef3562de2 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 01:35:38 +0000 Subject: [PATCH 51/88] replace m.room.parent with m.space.parent for symmetry --- proposals/1772-groups-as-rooms.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index af6d23af..baf1338a 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -126,12 +126,12 @@ relationship can be expressed in one of two ways: automatically joined by members of the space: see [below](#auto-joined-children). - 2. Separately, rooms can claim a parent via the `m.room.parent` state + 2. Separately, rooms can claim a parent via the `m.space.parent` state event: ```js { - "type": "m.room.parent", + "type": "m.space.parent", "state_key": "", "content": { "room_id": "!space:example.com", @@ -145,9 +145,9 @@ relationship can be expressed in one of two ways: that space and group them together. To avoid abuse where a room admin falsely claims that a room is part of a - space that it should not be, clients could ignore such `m.room.parent` + space that it should not be, clients could ignore such `m.space.parent` events unless their sender has a sufficient power-level to send an - `m.room.child` event in the parent. + `m.space.child` event in the parent. Where the parent space also claims a parent, clients can recursively peek into the grandparent space, and so on. @@ -305,7 +305,7 @@ Proposed final identifier | Purpose | Development identifier ------------------------------- | ------- | ---- `m.space` | room type | `org.matrix.msc1772.space` `m.space.child` | event type | `org.matrix.msc1772.space.child` -`m.room.parent` | event type | `org.matrix.msc1772.room.parent` +`m.space.parent` | event type | `org.matrix.msc1772.room.parent` ## History From 343e1f676b89a4efbf4bc8c6748b8f2dabac7d31 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 01:37:05 +0000 Subject: [PATCH 52/88] incorporate @joepie91's clarification on secret rooms --- proposals/1772-groups-as-rooms.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index baf1338a..a2e4469b 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -147,7 +147,9 @@ relationship can be expressed in one of two ways: To avoid abuse where a room admin falsely claims that a room is part of a space that it should not be, clients could ignore such `m.space.parent` events unless their sender has a sufficient power-level to send an - `m.space.child` event in the parent. + `m.space.child` event in the parent. The rationale for checking the power + level, rather than the *actual* presence of an `m.space.child` event in the + parent, is to accommodate "secret" rooms (see below). Where the parent space also claims a parent, clients can recursively peek into the grandparent space, and so on. From 97103c44cd3277cca0f38037290530d13a5bc357 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 01:39:45 +0000 Subject: [PATCH 53/88] clarify that auto-joins are not force joins --- proposals/1772-groups-as-rooms.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index a2e4469b..d7ce2c09 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -177,11 +177,15 @@ Cycles in the parent->child and child->parent relationships are *not* permitted, but clients (and servers) should be aware that they may be encountered, and ignore the relationship rather than recursing infinitely. +XXX: we need to deterministically specify where the cycles get cut. +I think kegan found a solution for this when implementing MSC2946 in Dendrite. + ### Auto-joined children The `auto_join` flag on a child listing allows a space admin to list the sub-spaces and rooms in that space which should be automatically joined by -members of that space. +members of that space. (This is not a force-join, which are descoped for +a future MSC; the user can subsequently part these room if they desire.) Joining should be performed by the client. This can optionally be sped up by using [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946) to get a From 91fe7a79b6375ba62eb39025f00b551ea8217b80 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 02:02:27 +0000 Subject: [PATCH 54/88] switch to allowing multiple parents to accomodate @Sorunome's use cases for secret rooms to exist in multiple spaces. also remote , as we always have now we use room ids --- proposals/1772-groups-as-rooms.md | 40 ++++++++++++++++--------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index d7ce2c09..4204c695 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -81,16 +81,14 @@ relationship can be expressed in one of two ways: 1. The admins of a space can advertise rooms and subspaces for their space by setting `m.space.child` state events. The `state_key` is the ID of a child room or space, and the content should contain a `via` key which gives a list - of candidate servers that can be used to join the room. `present: true` key - is included to distinguish from a deleted state event. Something like: + of candidate servers that can be used to join the room. Something like: ```js { "type": "m.space.child", "state_key": "!abcd:example.com", "content": { - "via": ["example.com", "test.org"], - "present": true + "via": ["example.com", "test.org"] } } @@ -99,7 +97,6 @@ relationship can be expressed in one of two ways: "state_key": "!efgh:example.com", "content": { "via": ["example.com"], - "present": true, "order": "abcd", "auto_join": true } @@ -113,7 +110,7 @@ relationship can be expressed in one of two ways: } ``` - Children where `present` is not present or is not set to `true` are ignored. + Children where `via` is not present are ignored. The `order` key is a string which is used to provide a default ordering of siblings in the room list. (Rooms are sorted based on a lexicographic @@ -126,23 +123,31 @@ relationship can be expressed in one of two ways: automatically joined by members of the space: see [below](#auto-joined-children). - 2. Separately, rooms can claim a parent via the `m.space.parent` state - event: + 2. Separately, rooms can claim parents via the `m.space.parent` state + event. + + Similar to `m.space.child`, the `state_key` is the ID of the parent space, + and the content should contain a `via` key which gives a list of candidate + servers that can be used to join the parent. ```js { "type": "m.space.parent", - "state_key": "", + "state_key": "!space:example.com", "content": { - "room_id": "!space:example.com", - "via": ["example.com"] + "via": ["example.com"], + "present": true, + "canonical": true, } } ``` - In this case, after a user joins such a room, the client could optionally - start peeking into the parent space, enabling it to find other rooms in - that space and group them together. + Parents where `via` is not present are ignored. + + `canonical` determines whether this is the main parent for the space. When + a user joins a room with a canonical parent, clients may switch to view + the room in the context of that parent space, peeking into it in order to + find other rooms and group them together. To avoid abuse where a room admin falsely claims that a room is part of a space that it should not be, clients could ignore such `m.space.parent` @@ -154,12 +159,9 @@ relationship can be expressed in one of two ways: Where the parent space also claims a parent, clients can recursively peek into the grandparent space, and so on. - Note that each room can only declare a single parent. This could be - extended in future to declare additional parents, but more investigation - into appropriate semantics is needed. - This structure means that rooms can end up appearing multiple times in the -room list hierarchy, given they can be children of multiple different spaces. +room list hierarchy, given they can be children of multiple different spaces +(or have multiple parents in different spaces). In a typical hierarchy, we expect *both* parent->child and child->parent relationships to exist, so that the space can be discovered from the room, and From b10856d49d09531291d48856b4c9b336ed939526 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 02:06:55 +0000 Subject: [PATCH 55/88] let's create spaces with `events_default` PL100 --- proposals/1772-groups-as-rooms.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 4204c695..adf2bbf4 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -50,7 +50,9 @@ way as a normal room. Normal messages within a space-room are discouraged (but not blocked by the server): user interfaces are not expected to have a way to enter or display -such messages. +such messages. Space-rooms should be created with a power level for +`events_default` of 100, to prevent the rooms accidentally/maliciously +clogging up with messages from random members of the space. ### Membership of spaces From a0f89bd522a544783e5194d3fe6464309160f557 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 02:23:59 +0000 Subject: [PATCH 56/88] add XXX about via propagation --- proposals/1772-groups-as-rooms.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index adf2bbf4..8ab2f27d 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -184,6 +184,10 @@ encountered, and ignore the relationship rather than recursing infinitely. XXX: we need to deterministically specify where the cycles get cut. I think kegan found a solution for this when implementing MSC2946 in Dendrite. +XXX: we need to specify how vias are updated as time goes on (perhaps servers +with sufficient permission could automatically add themselves into the via event +via the bot from MSC2962?) + ### Auto-joined children The `auto_join` flag on a child listing allows a space admin to list the From a709671d032f047b5608aa6588f25a4b936a86ab Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 14 Jan 2021 12:55:20 +0000 Subject: [PATCH 57/88] tie break on multiple parents --- proposals/1772-groups-as-rooms.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 8ab2f27d..fa91c45c 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -148,8 +148,11 @@ relationship can be expressed in one of two ways: `canonical` determines whether this is the main parent for the space. When a user joins a room with a canonical parent, clients may switch to view - the room in the context of that parent space, peeking into it in order to - find other rooms and group them together. + the room in the context of that space, peeking into it in order to find + other rooms and group them together. In practice, well behaved rooms + should only have one `canonical` parent, but given this is not enforced: + if multiple are present the client should select the one with the lowest + room ID, as determined via a lexicographic utf-8 ordering. To avoid abuse where a room admin falsely claims that a room is part of a space that it should not be, clients could ignore such `m.space.parent` From ff85e61be908f4f5f0ba846da0dd6c439147a1b0 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 15 Jan 2021 11:19:45 +0000 Subject: [PATCH 58/88] fix dev identifier --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index fa91c45c..80c0dd6d 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -322,7 +322,7 @@ Proposed final identifier | Purpose | Development identifier ------------------------------- | ------- | ---- `m.space` | room type | `org.matrix.msc1772.space` `m.space.child` | event type | `org.matrix.msc1772.space.child` -`m.space.parent` | event type | `org.matrix.msc1772.room.parent` +`m.space.parent` | event type | `org.matrix.msc1772.space.parent` ## History From 1cfe6bc0aefd5e77823f8c402092181a481416a4 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 16 Mar 2021 12:40:49 +0000 Subject: [PATCH 59/88] MSC1840 is out again. --- proposals/1772-groups-as-rooms.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 80c0dd6d..33c508ef 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -39,11 +39,10 @@ within the space are determined by state events within the space-room. Spaces are referred to primarily by their alias, for example `#foo:matrix.org`. -Space-rooms are distinguished from regular messaging rooms by the `m.room.type` -of `m.space` (see -[MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840)). This allows -clients to offer slightly customised user experience depending on the purpose -of the room. +Space-rooms are distinguished from regular messaging rooms by the presence of a +`type: m.space` property in the `m.room.create` event. This allows clients to +offer slightly customised user experience depending on the purpose of the +room. Currently, no server-side behaviour is expected to depend on this property. Space-rooms may have `m.room.name` and `m.room.topic` state events in the same way as a normal room. @@ -69,8 +68,8 @@ the room). Join rules, invites and 3PID invites work as for a normal room, with the exception that `invite_state` sent along with invites should be amended to -include the event containing the type `m.space`, to allow clients to discern -whether an invite is to a space-room or not. +include the `m.room.create` event, to allow clients to discern whether an +invite is to a space-room or not. XXX: Should we also include a MSC2946 summary of the space in the invite too? @@ -279,9 +278,6 @@ One way this might be implemented is: ## Dependencies - * [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) for room - types. - * [MSC2753](https://github.com/matrix-org/matrix-doc/issues/2753) for effective peeking over the C/S API. @@ -312,6 +308,15 @@ These dependencies are shared with profiles-as-rooms different querying users. (It may be possible to simulate this behaviour using smaller spaces). +## Rejected alternatives + +### Use a separate state event for type of room + +[MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) proposes the use +of a separate `m.room.type` state event to distinguish different room +types. This implies that rooms can dynamically switch between being a Space, +and being a regular non-Space room. That is not a usecase we consider useful, +and allowing it would impose significant complexity on client implementations. ## Unstable prefix @@ -320,7 +325,8 @@ development: Proposed final identifier | Purpose | Development identifier ------------------------------- | ------- | ---- -`m.space` | room type | `org.matrix.msc1772.space` +`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 bc1466206daad7eb319639523d79aa3e0274d334 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 16 Mar 2021 14:16:26 +0000 Subject: [PATCH 60/88] related MSCs --- proposals/1772-groups-as-rooms.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 33c508ef..ef911b59 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -276,7 +276,13 @@ One way this might be implemented is: to do this check (and both servers and clients can cache the results fairly aggressively.) -## Dependencies +## Related MSCs + + * [MSC2946](https://github.com/matrix-org/matrix-doc/issues/2946): Spaces + Summary API. + + * [MSC2962](https://github.com/matrix-org/matrix-doc/issues/2962): Group + access control via Spaces. * [MSC2753](https://github.com/matrix-org/matrix-doc/issues/2753) for effective peeking over the C/S API. @@ -284,9 +290,6 @@ One way this might be implemented is: * [MSC2444](https://github.com/matrix-org/matrix-doc/issues/2444) (or similar) for effective peeking over Federation. -These dependencies are shared with profiles-as-rooms -([MSC1769](https://github.com/matrix-org/matrix-doc/issues/1769)). - ## Security considerations * The peek server has significant power. For example, a poorly chosen peek From 62b9154fa7b021df75ace0c80b684ed2a27b254d Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 16 Mar 2021 14:18:27 +0000 Subject: [PATCH 61/88] Remove lost footnotes These should have been part of MSC2962. --- proposals/1772-groups-as-rooms.md | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index ef911b59..75b9f967 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -366,24 +366,3 @@ problems, including: * e.g. Room Directories * Groups are centralised, rather than being replicated across all participating servers. - - - -## Footnotes - -[1]: The converse, "anybody can join, provided they are not members -of the '#catlovers' space" is less useful since (a) users in the banned space -could simply leave it at any time; (b) this functionality is already somewhat -provided by [Moderation policy -lists](https://matrix.org/docs/spec/client_server/r0.6.1#moderation-policy-lists). [↩](#a1) - -[2]: Note that there is nothing stopping users sending and -receiving invites in `public` rooms today, and they work as you might -expect. The only difference is that you are not *required* to hold an `invite` -when joining the room. [↩](#a2) - -[3]: This is a marginal decrease in security from the current -situation with invite-only rooms. Currently, a misbehaving server can allow -unauthorized users to join an invite-only room by first issuing an invite to -that user. In theory that can be prevented by raising the PL required to send -an invite, but in practice that is rarely done. [↩](#a2) From 469b64c5cdfa212c548b3594402cb4ea42744417 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 16 Mar 2021 14:23:12 +0000 Subject: [PATCH 62/88] rip out m.room.description if/when we need it, we should follow MSC2875 --- proposals/1772-groups-as-rooms.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 75b9f967..2eecddaa 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -219,16 +219,6 @@ advertise particular rooms more prominently than in the room directory. However, this can be added in a later MSC if it's found to be needed in practice. -### Long description - -We would like to allow spaces to have a long description using rich -formatting. This will use a new state event type `m.room.description` (with -empty `state_key`) whose content is the same format as `m.room.message` (ie, -contains a `msgtype` and possibly `formatted_body`). - -TODO: this could also be done via pinned messages. Failing that -`m.room.description` should probably be a separate MSC. - ## Future extensions The following sections are not blocking parts of this proposal, but are From dcb18f03dcd4fbef4d86dd5958074b498f9f28ff Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 13:14:53 +0000 Subject: [PATCH 63/88] Move security consideration to MSC2962 I think the peeking thing is specific to access control. --- proposals/1772-groups-as-rooms.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 2eecddaa..fb93caec 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -282,9 +282,7 @@ One way this might be implemented is: ## Security considerations -* The peek server has significant power. For example, a poorly chosen peek - server could lie about the space membership and add an - `@evil_user:example.org`. +None at present. ## Tradeoffs From 7d757ce8fa93cf84dbd43647d64f59f25d8923b0 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 13:18:28 +0000 Subject: [PATCH 64/88] minor wording tweaks --- proposals/1772-groups-as-rooms.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index fb93caec..d2320686 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -1,6 +1,7 @@ # Proposal for Matrix "spaces" (formerly known as "groups as rooms (take 2)") -This obsoletes [MSC1215](https://github.com/matrix-org/matrix-doc/issues/1215). +This MSC, and related proposals, supercede +[MSC1215](https://github.com/matrix-org/matrix-doc/issues/1215). ## Background and objectives @@ -284,7 +285,7 @@ One way this might be implemented is: None at present. -## Tradeoffs +## Potential issues * If the membership of a space would be large (for example: an organisation of several thousand people), this membership has to be copied entirely into the From acdb6f1c3db8d7270fae7cc5ce3ca1fca4542a60 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 13:18:47 +0000 Subject: [PATCH 65/88] Move "auto-join" out to "future extensions" we're not doing this bit yet. --- proposals/1772-groups-as-rooms.md | 43 ++++++++++++------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index d2320686..e52280f7 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -100,7 +100,6 @@ relationship can be expressed in one of two ways: "content": { "via": ["example.com"], "order": "abcd", - "auto_join": true } } @@ -121,10 +120,6 @@ relationship can be expressed in one of two ways: `\x20` (space) to `\x7F` (`~`), or consist of more than 50 characters, are forbidden and should be ignored if received.) - If `auto_join` is set to `true`, that indicates that the child should be - automatically joined by members of the space: see - [below](#auto-joined-children). - 2. Separately, rooms can claim parents via the `m.space.parent` state event. @@ -191,18 +186,25 @@ XXX: we need to specify how vias are updated as time goes on (perhaps servers with sufficient permission could automatically add themselves into the via event via the bot from MSC2962?) +## Future extensions + +The following sections are not blocking parts of this proposal, but are +included as a useful reference for how we imagine it will be extended in future. + ### Auto-joined children -The `auto_join` flag on a child listing allows a space admin to list the -sub-spaces and rooms in that space which should be automatically joined by -members of that space. (This is not a force-join, which are descoped for -a future MSC; the user can subsequently part these room if they desire.) +We could add an `auto_join` flag to `m.space.child` events to allow a space +admin to list the sub-spaces and rooms in that space which should be +automatically joined by members of that space. + +This would be distinct from a force-join: the user could subsequently part any +auto-joined room if they desire. -Joining should be performed by the client. This can optionally be sped up by -using [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946) to get a -summary of the spacetree to be joined, and then using a batch join API (when -available) to join whichever subset of it makes most sense for the client's -UX. +Joining would be performed by the client. This could possibly be sped up by +using a summary API (such as that proposed in +[MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946)) to get a summary +of the spacetree to be joined, and then using a batch join API to join +whichever subset of it makes most sense for the client's UX. Obviously auto-joining can be a DoS vector, and we consider it to be antisocial for a space to try to autojoin its members to more than 100 children (in total). @@ -211,20 +213,9 @@ Clients could display the auto-joined children in the room list whenever the space appears in the list - thus helping users discover other rooms in a space even if they're not joined to that space. For instance, if you join `#matrix:matrix.org`, your client could show that room in the context of its -parent space, with that space's autojoined children shown alongside it as +parent space, with that space's auto-joined children shown alongside it as siblings. -It may also be useful to have a way to "suggest" that members of a space -should join certain children (but without actually autojoining them) - to -advertise particular rooms more prominently than in the room directory. -However, this can be added in a later MSC if it's found to be needed in -practice. - -## Future extensions - -The following sections are not blocking parts of this proposal, but are -included as a useful reference for how we imagine it will be extended in future. - ### Restricting access to the spaces membership list In the existing `/r0/groups` API, the group server has total control over the From 2e6d7d1c54f6c023f339da03a4a5d4fd148f8c43 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 13:27:57 +0000 Subject: [PATCH 66/88] spaces are *primarily* referred to by their room ID. --- proposals/1772-groups-as-rooms.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index e52280f7..55defd3e 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -37,14 +37,14 @@ unspecified. Each space is represented by its own room, known as a "space-room". The rooms within the space are determined by state events within the space-room. -Spaces are referred to primarily by their alias, for example -`#foo:matrix.org`. - Space-rooms are distinguished from regular messaging rooms by the presence of a `type: m.space` property in the `m.room.create` event. This allows clients to offer slightly customised user experience depending on the purpose of the room. Currently, no server-side behaviour is expected to depend on this property. +As with regular rooms, public spaces are expected to have an alias, for example +`#foo:matrix.org`, which can be used to refer to the space. + Space-rooms may have `m.room.name` and `m.room.topic` state events in the same way as a normal room. From 0bdbec238b080a5e90993181264eed7e933afac8 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 16:01:42 +0000 Subject: [PATCH 67/88] Accept m.space.parent links if there is a reverse link --- proposals/1772-groups-as-rooms.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 55defd3e..d3a6cefd 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -151,10 +151,11 @@ relationship can be expressed in one of two ways: To avoid abuse where a room admin falsely claims that a room is part of a space that it should not be, clients could ignore such `m.space.parent` - events unless their sender has a sufficient power-level to send an - `m.space.child` event in the parent. The rationale for checking the power - level, rather than the *actual* presence of an `m.space.child` event in the - parent, is to accommodate "secret" rooms (see below). + events unless either (a) there is a corresponding `m.space.child` event in + the claimed parent, or (b) the sender of the `m.space.child` event has a + sufficient power-level to send such an `m.space.child` event in the parent. + [Checking the power-level rather than requiring an *actual* `m.space.child` + event in the parent allows for "secret" rooms (see below).] Where the parent space also claims a parent, clients can recursively peek into the grandparent space, and so on. From 6c9d469d563ef38bb70bcb52230ae06abec48bba Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 16:08:32 +0000 Subject: [PATCH 68/88] add an issue about lost parent links --- proposals/1772-groups-as-rooms.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index d3a6cefd..3bfdd8bc 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -153,9 +153,11 @@ relationship can be expressed in one of two ways: space that it should not be, clients could ignore such `m.space.parent` events unless either (a) there is a corresponding `m.space.child` event in the claimed parent, or (b) the sender of the `m.space.child` event has a - sufficient power-level to send such an `m.space.child` event in the parent. - [Checking the power-level rather than requiring an *actual* `m.space.child` - event in the parent allows for "secret" rooms (see below).] + sufficient power-level to send such an `m.space.child` event in the + parent. (It is not necessarily required that that user currently be a + member of the parent room - only the `m.room.power_levels` event is + inspected.) [Checking the power-level rather than requiring an *actual* + `m.space.child` event in the parent allows for "secret" rooms (see below).] Where the parent space also claims a parent, clients can recursively peek into the grandparent space, and so on. @@ -292,6 +294,13 @@ None at present. different querying users. (It may be possible to simulate this behaviour using smaller spaces). +* The requirement that `m.room.parent` links be ignored unless the sender has a + high PL in the parent room could lead to suprising effects where a parent + link suddenly ceases to take effect because a user loses their PL in the + parent room. This is mitigated in the general case by honouring the parent + link when there is a corresponding `m.room.child` event, however it remains + a problem for "secret" rooms. + ## Rejected alternatives ### Use a separate state event for type of room From 8a61ce9032dedc3bec881e97a14fcf98376c390c Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 17:27:56 +0000 Subject: [PATCH 69/88] remove 'present' flag --- proposals/1772-groups-as-rooms.md | 1 - 1 file changed, 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 3bfdd8bc..0e52951e 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -133,7 +133,6 @@ relationship can be expressed in one of two ways: "state_key": "!space:example.com", "content": { "via": ["example.com"], - "present": true, "canonical": true, } } From c0c51383e9125b8d51151a1a164e2edc8d1c0a8a Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 18:02:36 +0000 Subject: [PATCH 70/88] Move "via" problem to a "potential issue" --- proposals/1772-groups-as-rooms.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 0e52951e..f56ecf22 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -184,10 +184,6 @@ encountered, and ignore the relationship rather than recursing infinitely. XXX: we need to deterministically specify where the cycles get cut. I think kegan found a solution for this when implementing MSC2946 in Dendrite. -XXX: we need to specify how vias are updated as time goes on (perhaps servers -with sufficient permission could automatically add themselves into the via event -via the bot from MSC2962?) - ## Future extensions The following sections are not blocking parts of this proposal, but are @@ -300,6 +296,10 @@ None at present. link when there is a corresponding `m.room.child` event, however it remains a problem for "secret" rooms. +* The `via` servers listed in the `m.room.child` and `m.room.parent` events + could get out of date, and will need to be updated from time to time. This + remains an unsolved problem. + ## Rejected alternatives ### Use a separate state event for type of room From 9ca94235c6492372c956b9619ad5680c9200aa24 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 17 Mar 2021 18:25:04 +0000 Subject: [PATCH 71/88] Suggested rooms --- proposals/1772-groups-as-rooms.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index f56ecf22..a768f263 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -184,6 +184,29 @@ encountered, and ignore the relationship rather than recursing infinitely. XXX: we need to deterministically specify where the cycles get cut. I think kegan found a solution for this when implementing MSC2946 in Dendrite. +### Suggested children + +Space admins can mark particular children of a space as "suggested". This +mainly serves as a hint to clients that that they can be displayed differently +(for example by showing them eagerly in the room list), though future +server-side interfaces (such as the summary API proposed in MSC2946) might also +make use of it. + +A suggested child is identified by a `"suggested": true` property in the +`m.space.child` event: + + +```jsonc +{ + "type": "m.space.child", + "state_key": "!abcd:example.com", + "content": { + "via": ["example.com", "test.org"], + "suggested": true + } +} +``` + ## Future extensions The following sections are not blocking parts of this proposal, but are From 5e7ed2b9c48e0ee874d7f55d3486a390639c06f3 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 22 Mar 2021 17:19:44 +0000 Subject: [PATCH 72/88] Tweak wording about lexicographic ordering --- proposals/1772-groups-as-rooms.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index a768f263..d5d45774 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -115,10 +115,10 @@ relationship can be expressed in one of two ways: The `order` key is a string which is used to provide a default ordering of siblings in the room list. (Rooms are sorted based on a lexicographic - ordering of `order` values; rooms with no `order` come last. `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 should be ignored if received.) + ordering of the characters in `order` values; rooms with no `order` + come last. `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 should be ignored if received.) 2. Separately, rooms can claim parents via the `m.space.parent` state event. @@ -141,12 +141,12 @@ relationship can be expressed in one of two ways: Parents where `via` is not present are ignored. `canonical` determines whether this is the main parent for the space. When - a user joins a room with a canonical parent, clients may switch to view - the room in the context of that space, peeking into it in order to find - other rooms and group them together. In practice, well behaved rooms - should only have one `canonical` parent, but given this is not enforced: - if multiple are present the client should select the one with the lowest - room ID, as determined via a lexicographic utf-8 ordering. + a user joins a room with a canonical parent, clients may switch to view the + room in the context of that space, peeking into it in order to find other + rooms and group them together. In practice, well behaved rooms should only + have one `canonical` parent, but given this is not enforced: if multiple + are present the client should select the one with the lowest room ID, as + determined via a lexicographic ordering of the Unicode code-points. To avoid abuse where a room admin falsely claims that a room is part of a space that it should not be, clients could ignore such `m.space.parent` From 065b0990e625574e4f8f30e26727cb252887cb1f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Tue, 23 Mar 2021 11:30:02 +0000 Subject: [PATCH 73/88] Update proposals/1772-groups-as-rooms.md --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index d5d45774..addb6d54 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -38,7 +38,7 @@ Each space is represented by its own room, known as a "space-room". The rooms within the space are determined by state events within the space-room. Space-rooms are distinguished from regular messaging rooms by the presence of a -`type: m.space` property in the `m.room.create` event. This allows clients to +`type: m.space` property in the content of the `m.room.create` event. This allows clients to offer slightly customised user experience depending on the purpose of the room. Currently, no server-side behaviour is expected to depend on this property. From e7041525bf4a8c0f1cb0b04ea9e512cd7cd74f9c Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 26 Mar 2021 10:46:29 +0000 Subject: [PATCH 74/88] Include `create` in invite_room_state --- proposals/1772-groups-as-rooms.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index addb6d54..10e0b0d4 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -207,6 +207,17 @@ A suggested child is identified by a `"suggested": true` property in the } ``` +### Extended "room invite state" + +The specification is currently vague about what room state should be available +to users that have been invited to a room, though the Federation API spec does +recommend that the `invite_room_state` sent over federation via [PUT +`/_matrix/federation/v2/invite`](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid) +should include "the join rules, canonical alias, avatar, and name of the room". + +This MSC proposes adding `m.room.create` to that list, so that the recipient of +an invite can distinguish invites to spaces from other invites. + ## Future extensions The following sections are not blocking parts of this proposal, but are From 6d007e83ca0e1e095ad71b6ae189b2092ad18bf3 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 14 Apr 2021 13:10:27 -0400 Subject: [PATCH 75/88] Defer a TODO to the future. --- proposals/1772-groups-as-rooms.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 10e0b0d4..8e9a66be 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -72,8 +72,6 @@ exception that `invite_state` sent along with invites should be amended to include the `m.room.create` event, to allow clients to discern whether an invite is to a space-room or not. -XXX: Should we also include a MSC2946 summary of the space in the invite too? - ### Relationship between rooms and spaces The intention is that rooms and spaces form a hierarchy, which clients can use @@ -295,8 +293,11 @@ One way this might be implemented is: * [MSC2946](https://github.com/matrix-org/matrix-doc/issues/2946): Spaces Summary API. - * [MSC2962](https://github.com/matrix-org/matrix-doc/issues/2962): Group - access control via Spaces. + * [MSC2962](https://github.com/matrix-org/matrix-doc/issues/2962): Managing + power levels via Spaces. + + * [MSC3083](https://github.com/matrix-org/matrix-doc/issues/3083): Restricting + room membership based on space membership. * [MSC2753](https://github.com/matrix-org/matrix-doc/issues/2753) for effective peeking over the C/S API. From 12d08ca83db3527f5091c1bd331e215acc5ce1e6 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 14 Apr 2021 13:21:59 -0400 Subject: [PATCH 76/88] Consistency and update links. --- proposals/1772-groups-as-rooms.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 8e9a66be..f7a546a9 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -21,7 +21,7 @@ We refer to such collections of rooms as "spaces". Synapse and Element-Web currently implement an unspecced "groups" API (referred to as "`/r0/groups`" in this document) which attempts to provide this functionality (see -[matrix-doc#971](https://github.com/matrix-org/matrix-doc/issues/971)). However, +[MSC971](https://github.com/matrix-org/matrix-doc/issues/971)). However, this is a complex API which has various problems (see [appendix](#appendix-problems-with-the-r0groups-api)). @@ -80,10 +80,11 @@ relationship can be expressed in one of two ways: 1. The admins of a space can advertise rooms and subspaces for their space by setting `m.space.child` state events. The `state_key` is the ID of a child - room or space, and the content should contain a `via` key which gives a list + room or space, and the content must contain a `via` key which gives a list of candidate servers that can be used to join the room. Something like: - ```js + ```jsonc + // a child room { "type": "m.space.child", "state_key": "!abcd:example.com", @@ -92,12 +93,13 @@ relationship can be expressed in one of two ways: } } + // a child room with an ordering. { "type": "m.space.child", "state_key": "!efgh:example.com", "content": { "via": ["example.com"], - "order": "abcd", + "order": "abcd" } } @@ -122,16 +124,16 @@ relationship can be expressed in one of two ways: event. Similar to `m.space.child`, the `state_key` is the ID of the parent space, - and the content should contain a `via` key which gives a list of candidate + and the content must contain a `via` key which gives a list of candidate servers that can be used to join the parent. - ```js + ```jsonc { "type": "m.space.parent", "state_key": "!space:example.com", "content": { "via": ["example.com"], - "canonical": true, + "canonical": true } } ``` @@ -187,7 +189,8 @@ I think kegan found a solution for this when implementing MSC2946 in Dendrite. Space admins can mark particular children of a space as "suggested". This mainly serves as a hint to clients that that they can be displayed differently (for example by showing them eagerly in the room list), though future -server-side interfaces (such as the summary API proposed in MSC2946) might also +server-side interfaces (such as the summary API proposed in +[MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946)) might also make use of it. A suggested child is identified by a `"suggested": true` property in the @@ -205,6 +208,9 @@ A suggested child is identified by a `"suggested": true` property in the } ``` +A child which is missing the `suggested` property is treated identically to a +child with `"suggested": false`. A suggested child may be a room or a subspace. + ### Extended "room invite state" The specification is currently vague about what room state should be available @@ -359,8 +365,8 @@ Proposed final identifier | Purpose | Development identifier ## History - * This replaces MSC1215: https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE - * Other thoughts that led into this are at: https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs + * This replaces [MSC1215](https://docs.google.com/document/d/1ZnAuA_zti-K2-RnheXII1F1-oyVziT4tJffdw1-SHrE). + * Other thoughts that led into this are [documented](https://docs.google.com/document/d/1hljmD-ytdCRL37t-D_LvGDA3a0_2MwowSPIiZRxcabs). ## Appendix: problems with the `/r0/groups` API From 00912f9c1e264b0ecd54d29c3d450b38dc08cb88 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 20:45:28 +0100 Subject: [PATCH 77/88] clarify how to deterministically cut cycles --- proposals/1772-groups-as-rooms.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index f7a546a9..480383ea 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -179,10 +179,18 @@ include: Cycles in the parent->child and child->parent relationships are *not* permitted, but clients (and servers) should be aware that they may be -encountered, and ignore the relationship rather than recursing infinitely. - -XXX: we need to deterministically specify where the cycles get cut. -I think kegan found a solution for this when implementing MSC2946 in Dendrite. +encountered, and MUST spot and break cycles rather than infinitely looping. + +In order for UI to be consistent across different clients, any cycles must be +cut deterministically. For instance, if space A points to space B as a child +but space B also points to space A as a child, then clients must be consistent +on whether A is shown in the UI as the parent of B (or vice versa). Therefore +when a client spots a loop in parent->child or child->parent relationships, it +MUST ignore the cycle by cutting it such that the oldest space-room is the +root (i.e. oldest parent). 'Oldest' means the room whose `m.room.create` +event has the numerically smallest `origin_server_ts`. If the oldest rooms +are precisely the same age, we select the root as the room with the +lexicographically smallest `room_id`. ### Suggested children From f07e82e34bd8a2cc6a76ee94e7d3d9bb52d3a774 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 20:49:35 +0100 Subject: [PATCH 78/88] clarify the charsets of our lexicographic orderings --- proposals/1772-groups-as-rooms.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 480383ea..2e801d24 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -115,10 +115,11 @@ relationship can be expressed in one of two ways: The `order` key is a string which is used to provide a default ordering of siblings in the room list. (Rooms are sorted based on a lexicographic - ordering of the characters in `order` values; rooms with no `order` - come last. `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 should be ignored if received.) + ordering of the Unicode codepoints of the characters in `order` values; + rooms with no `order` come last. `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 should be + ignored if received.) 2. Separately, rooms can claim parents via the `m.space.parent` state event. @@ -189,8 +190,9 @@ when a client spots a loop in parent->child or child->parent relationships, it MUST ignore the cycle by cutting it such that the oldest space-room is the root (i.e. oldest parent). 'Oldest' means the room whose `m.room.create` event has the numerically smallest `origin_server_ts`. If the oldest rooms -are precisely the same age, we select the root as the room with the -lexicographically smallest `room_id`. +are precisely the same age, we select the root as the room with the smallest +`room_id` (lexicographically comparing the Unicode code-points of the +`room_id` string). ### Suggested children From 37e04f72ae4e931006e679320f92022c2ca72c72 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 20:56:54 +0100 Subject: [PATCH 79/88] tiebreak ordered spaces sensibly --- proposals/1772-groups-as-rooms.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 2e801d24..12e278a9 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -115,11 +115,14 @@ relationship can be expressed in one of two ways: The `order` key is a string which is used to provide a default ordering of siblings in the room list. (Rooms are sorted based on a lexicographic - ordering of the Unicode codepoints of the characters in `order` values; - rooms with no `order` come last. `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 should be - ignored if received.) + 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 should be ignored if + received.) 2. Separately, rooms can claim parents via the `m.space.parent` state event. From 1e2ed52b7e3b367228837c8d16ae08d7526858dd Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 21:02:12 +0100 Subject: [PATCH 80/88] add more justification for immutable room types --- proposals/1772-groups-as-rooms.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 12e278a9..56b115ee 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -359,10 +359,14 @@ None at present. ### Use a separate state event for type of room [MSC1840](https://github.com/matrix-org/matrix-doc/pull/1840) proposes the use -of a separate `m.room.type` state event to distinguish different room -types. This implies that rooms can dynamically switch between being a Space, -and being a regular non-Space room. That is not a usecase we consider useful, -and allowing it would impose significant complexity on client implementations. +of a separate `m.room.type` state event to distinguish different room types. +This implies that rooms can dynamically switch between being a Space, and +being a regular non-Space room. That is not a usecase we consider useful, and +allowing it would impose significant complexity on client and server +implementations. Specifically, client and server implementations who store +spaces separately from rooms would have to support migrating back and forth +between them and dealing with the ambiguities of `room_id`s no longer pointing +to valid spaces, etc. ## Unstable prefix From 0d71150424b8515fc0687be083d22c5c8b4e7687 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 21:25:39 +0100 Subject: [PATCH 81/88] remove confusing mention of peeking & dependent MSCs --- proposals/1772-groups-as-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 56b115ee..8a2862bf 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -26,8 +26,8 @@ this is a complex API which has various problems (see [appendix](#appendix-problems-with-the-r0groups-api)). This proposal suggests a new approach where spaces are themselves represented -by rooms, rather than a custom first-class entity. This requires few server -changes, other than better support for peeking (see Dependencies below). +by rooms, rather than a custom first-class entity. This requires minimal +server changes. The existing `/r0/groups` API would be deprecated in Synapse and remain unspecified. From 7432d254c699578dcf419e1f72027372d772d67a Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 22:24:12 +0100 Subject: [PATCH 82/88] incorporate travis feedback --- proposals/1772-groups-as-rooms.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 8a2862bf..1904f68b 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -37,16 +37,18 @@ unspecified. Each space is represented by its own room, known as a "space-room". The rooms within the space are determined by state events within the space-room. -Space-rooms are distinguished from regular messaging rooms by the presence of a -`type: m.space` property in the content of the `m.room.create` event. This allows clients to -offer slightly customised user experience depending on the purpose of the -room. Currently, no server-side behaviour is expected to depend on this property. +Space-rooms are distinguished from regular messaging rooms by the presence of +a `'type': 'm.space'` property in the content of the `m.room.create` event. +The value of the `type` property uses the Standardised Identifier Grammar from +MSC #2758. This allows clients to offer slightly customised user experience +depending on the purpose of the room. Currently, no server-side behaviour is +expected to depend on this property. As with regular rooms, public spaces are expected to have an alias, for example `#foo:matrix.org`, which can be used to refer to the space. -Space-rooms may have `m.room.name` and `m.room.topic` state events in the same -way as a normal room. +Space-rooms may have `m.room.name`, `m.room.avatar` and `m.room.topic` state +events in the same way as a normal room. Normal messages within a space-room are discouraged (but not blocked by the server): user interfaces are not expected to have a way to enter or display @@ -67,10 +69,9 @@ to see the directory of rooms within the space by peeking into the space-room (thus avoiding the need to add `m.room.member` events to the event graph within the room). -Join rules, invites and 3PID invites work as for a normal room, with the -exception that `invite_state` sent along with invites should be amended to -include the `m.room.create` event, to allow clients to discern whether an -invite is to a space-room or not. +Join rules, invites and 3PID invites work as for a normal room. In order for +clients to distinguish space invites from room invites, all invites must now +include the `m.room.create` event in their `invite_state`. ### Relationship between rooms and spaces @@ -111,7 +112,7 @@ relationship can be expressed in one of two ways: } ``` - Children where `via` is not present are ignored. + Children where `via` is not present or invalid (not an array) are ignored. The `order` key is a string which is used to provide a default ordering of siblings in the room list. (Rooms are sorted based on a lexicographic @@ -121,8 +122,8 @@ relationship can be expressed in one of two ways: 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 should be ignored if - received.) + consist of more than 50 characters, are forbidden and the field should be + ignored if received.) 2. Separately, rooms can claim parents via the `m.space.parent` state event. @@ -142,7 +143,7 @@ relationship can be expressed in one of two ways: } ``` - Parents where `via` is not present are ignored. + Parents where `via` is not present or invalid (not an array) are ignored. `canonical` determines whether this is the main parent for the space. When a user joins a room with a canonical parent, clients may switch to view the From 2981baad3d168f1c117b4fd413788ce36f0d2ef5 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 22:43:55 +0100 Subject: [PATCH 83/88] Update proposals/1772-groups-as-rooms.md Co-authored-by: Hubert Chathi --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 1904f68b..b6a071a4 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -40,7 +40,7 @@ within the space are determined by state events within the space-room. Space-rooms are distinguished from regular messaging rooms by the presence of a `'type': 'm.space'` property in the content of the `m.room.create` event. The value of the `type` property uses the Standardised Identifier Grammar from -MSC #2758. This allows clients to offer slightly customised user experience +[MSC2758](https://github.com/matrix-org/matrix-doc/pull/2758). This allows clients to offer slightly customised user experience depending on the purpose of the room. Currently, no server-side behaviour is expected to depend on this property. From acdf9851e91d2316e480f086c3383ebb2103ac7c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 22:45:15 +0100 Subject: [PATCH 84/88] incorporate uhoreg feedback --- proposals/1772-groups-as-rooms.md | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index b6a071a4..12e1bfa0 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -42,7 +42,10 @@ a `'type': 'm.space'` property in the content of the `m.room.create` event. The value of the `type` property uses the Standardised Identifier Grammar from [MSC2758](https://github.com/matrix-org/matrix-doc/pull/2758). This allows clients to offer slightly customised user experience depending on the purpose of the room. Currently, no server-side behaviour is -expected to depend on this property. +expected to depend on this property. A `type` property on the `m.room.create` +event is used to ensure that a room cannot change between being a space-room +and a non-space room. For more information, see the "Rejected Alternatives" +section below. As with regular rooms, public spaces are expected to have an alias, for example `#foo:matrix.org`, which can be used to refer to the space. @@ -62,12 +65,10 @@ Users can be members of spaces (represented by `m.room.member` state events as normal). The existing [`m.room.history_visibility` mechanism](https://matrix.org/docs/spec/client_server/r0.6.1#room-history-visibility) controls whether membership of the space is required to view the room list, -membership list, etc. - -"Public" or "community" spaces would be set to `world_readable` to allow clients -to see the directory of rooms within the space by peeking into the space-room -(thus avoiding the need to add `m.room.member` events to the event graph within -the room). +membership list, etc. "Public" or "community" spaces would be set to +`world_readable` to allow clients to see the directory of rooms within the +space by peeking into the space-room (thus avoiding the need to add +`m.room.member` events to the event graph within the room). Join rules, invites and 3PID invites work as for a normal room. In order for clients to distinguish space invites from room invites, all invites must now @@ -277,11 +278,18 @@ Whilst this is very powerful for mapping arbitrary organisational structures into Matrix, it may be overengineered. Instead, the common case is (we believe) a space where some users are publicly visible as members, and others are not. -One way to of achieving this would be to create a separate space for the +One way of achieving this would be to create a separate space for the private members - e.g. have `#foo:matrix.org` and `#foo-private:matrix.org`. `#foo-private:matrix.org` is set up with `m.room.history_visibility` to not to allow peeking; you have to be joined to see the members. +It's worth noting that any member of a space can currently see who else is a +member of that space, which might pose privacy problems for sensitive spaces. +While the server itself will inevitably track the space membership in state +events, a future MSC could restrict the membership from being sent to clients. +This is essentially the same as +[matrix-doc#1653](https://github.com/matrix-org/matrix-doc/issues/1653). + ### Flair ("Flair" is a term we use to describe a small badge which appears next to a @@ -344,14 +352,14 @@ None at present. different querying users. (It may be possible to simulate this behaviour using smaller spaces). -* The requirement that `m.room.parent` links be ignored unless the sender has a +* The requirement that `m.space.parent` links be ignored unless the sender has a high PL in the parent room could lead to suprising effects where a parent link suddenly ceases to take effect because a user loses their PL in the parent room. This is mitigated in the general case by honouring the parent - link when there is a corresponding `m.room.child` event, however it remains + link when there is a corresponding `m.space.child` event, however it remains a problem for "secret" rooms. -* The `via` servers listed in the `m.room.child` and `m.room.parent` events +* The `via` servers listed in the `m.space.child` and `m.space.parent` events could get out of date, and will need to be updated from time to time. This remains an unsolved problem. From 413e3463638336f0adac7d101375d71e67773819 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 29 Apr 2021 22:57:55 +0100 Subject: [PATCH 85/88] note the rationale behind using the # sigil --- proposals/1772-groups-as-rooms.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 12e1bfa0..50bab8e4 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -377,6 +377,17 @@ spaces separately from rooms would have to support migrating back and forth between them and dealing with the ambiguities of `room_id`s no longer pointing to valid spaces, etc. +### Use a different sigil/twigil for spaces + +Groups used + as a sigil to differentiate them from rooms (e.g. +matrix:matrix.org). +We considered doing similar for Spaces, e.g. a #+ twigil or reuse the + sigil, +but concluded that the resulting complexity and exoticism is not worth it. +This means that clients such as matrix.to have to peek into rooms to find out their +`type` before being able to display an appropriate UI, and users will not know +whether #matrix:matrix.org is a room or a space without using a client (e.g. if +reading an advert). It also means that if the client UI requires a space alias the +client will need to validate the entered data serverside. + ## Unstable prefix The following mapping will be used for identifiers in this MSC during From 757218c0820dad905d57d424724e414ee387ce58 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 30 Apr 2021 15:37:23 +0100 Subject: [PATCH 86/88] relax requirements on cycle-cutting and link to valere's alg --- proposals/1772-groups-as-rooms.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 50bab8e4..d970f1a6 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -191,13 +191,14 @@ In order for UI to be consistent across different clients, any cycles must be cut deterministically. For instance, if space A points to space B as a child but space B also points to space A as a child, then clients must be consistent on whether A is shown in the UI as the parent of B (or vice versa). Therefore -when a client spots a loop in parent->child or child->parent relationships, it -MUST ignore the cycle by cutting it such that the oldest space-room is the -root (i.e. oldest parent). 'Oldest' means the room whose `m.room.create` -event has the numerically smallest `origin_server_ts`. If the oldest rooms -are precisely the same age, we select the root as the room with the smallest -`room_id` (lexicographically comparing the Unicode code-points of the -`room_id` string). +when a client needs to consistently visualise a space hierarchy, it should +check for loops in parent->child or child->parent relationships and ignore the +cycle by cutting it such that the oldest space-room is the root (i.e. oldest +parent). 'Oldest' means the room whose `m.room.create` event has the +numerically smallest `origin_server_ts`. If the oldest rooms are precisely +the same age, we select the root as the room with the smallest `room_id` +(lexicographically comparing the Unicode code-points of the `room_id` string). +https://hackmd.io/eQpyqCcRR-Gj-SWZcD-Fxg shows an algorithm for doing so. ### Suggested children From c2d0d1efa0da4c13eb30a0a9f3ec32b7fcb3e6a6 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 3 May 2021 22:16:49 +0100 Subject: [PATCH 87/88] include m.room.create in knock_state (will be overtaken by MSC3173) --- proposals/1772-groups-as-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index d970f1a6..5c38c75c 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -72,7 +72,7 @@ space by peeking into the space-room (thus avoiding the need to add Join rules, invites and 3PID invites work as for a normal room. In order for clients to distinguish space invites from room invites, all invites must now -include the `m.room.create` event in their `invite_state`. +include the `m.room.create` event in their `invite_state` and `knock_state`. ### Relationship between rooms and spaces From 97737596e70917b511e8dfbeda5df8235b6cc2e2 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 4 May 2021 09:32:19 -0400 Subject: [PATCH 88/88] Remove cycle breaking algorithm to be specced in the future, if necessary. --- proposals/1772-groups-as-rooms.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/proposals/1772-groups-as-rooms.md b/proposals/1772-groups-as-rooms.md index 5c38c75c..bd416df5 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -187,19 +187,6 @@ Cycles in the parent->child and child->parent relationships are *not* permitted, but clients (and servers) should be aware that they may be encountered, and MUST spot and break cycles rather than infinitely looping. -In order for UI to be consistent across different clients, any cycles must be -cut deterministically. For instance, if space A points to space B as a child -but space B also points to space A as a child, then clients must be consistent -on whether A is shown in the UI as the parent of B (or vice versa). Therefore -when a client needs to consistently visualise a space hierarchy, it should -check for loops in parent->child or child->parent relationships and ignore the -cycle by cutting it such that the oldest space-room is the root (i.e. oldest -parent). 'Oldest' means the room whose `m.room.create` event has the -numerically smallest `origin_server_ts`. If the oldest rooms are precisely -the same age, we select the root as the room with the smallest `room_id` -(lexicographically comparing the Unicode code-points of the `room_id` string). -https://hackmd.io/eQpyqCcRR-Gj-SWZcD-Fxg shows an algorithm for doing so. - ### Suggested children Space admins can mark particular children of a space as "suggested". This