From 6c499db3baefdbb8de2a2241062decced04f46e0 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 3 Jan 2019 18:49:30 +0000 Subject: [PATCH 001/107] 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 002/107] 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 003/107] 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 004/107] 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 005/107] 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 006/107] 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 007/107] 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 008/107] 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 009/107] 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 010/107] 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 011/107] 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 012/107] 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 013/107] 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 014/107] 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 015/107] 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 016/107] 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 017/107] 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 018/107] 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 019/107] 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 020/107] 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 021/107] 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 022/107] 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 023/107] 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 024/107] 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 025/107] 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 026/107] 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 027/107] 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 028/107] 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 029/107] 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 030/107] 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 031/107] 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 032/107] 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 033/107] 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 034/107] 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 035/107] 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 036/107] 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 037/107] 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 038/107] 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 039/107] 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 040/107] 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 041/107] 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 042/107] 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 043/107] 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 044/107] 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 045/107] 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 046/107] 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 047/107] 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 048/107] 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 049/107] 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 050/107] 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 051/107] 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 052/107] 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 053/107] 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 054/107] 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 055/107] 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 056/107] 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 057/107] 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 058/107] 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 059/107] 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 060/107] 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 061/107] 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 062/107] 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 063/107] 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 064/107] 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 065/107] 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 066/107] 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 067/107] 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 068/107] 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 069/107] 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 070/107] 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 071/107] 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 072/107] 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 073/107] 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 074/107] 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 075/107] 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 076/107] 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 077/107] 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 078/107] 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 079/107] 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 080/107] 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 081/107] 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 082/107] 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 083/107] 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 084/107] 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 085/107] 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 086/107] 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 087/107] 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 088/107] 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 From 37c3a3f8559fbfe709e4c8e1db96c78a80f47dff Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 1 May 2021 22:46:09 -0600 Subject: [PATCH 089/107] Remove v1 identity service API Spec for https://github.com/matrix-org/matrix-doc/pull/2713 --- content/client-server-api/_index.md | 2 +- content/identity-service-api.md | 75 ++---- data/api/identity/associations.yaml | 302 ---------------------- data/api/identity/email_associations.yaml | 177 ------------- data/api/identity/invitation_signing.yaml | 97 ------- data/api/identity/lookup.yaml | 171 ------------ data/api/identity/phone_associations.yaml | 179 ------------- data/api/identity/ping.yaml | 46 ---- data/api/identity/pubkey.yaml | 129 --------- data/api/identity/store_invite.yaml | 161 ------------ 10 files changed, 16 insertions(+), 1323 deletions(-) delete mode 100644 data/api/identity/associations.yaml delete mode 100644 data/api/identity/email_associations.yaml delete mode 100644 data/api/identity/invitation_signing.yaml delete mode 100644 data/api/identity/lookup.yaml delete mode 100644 data/api/identity/phone_associations.yaml delete mode 100644 data/api/identity/ping.yaml delete mode 100644 data/api/identity/pubkey.yaml delete mode 100644 data/api/identity/store_invite.yaml diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index ec26cec8..b76ff570 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -297,7 +297,7 @@ specify parameter values. The flow for this method is as follows: 6. If the `m.identity_server` property is present, extract the `base_url` value for use as the base URL of the identity server. Validation for this URL is done as in the step above, but using - `/_matrix/identity/api/v1` as the endpoint to connect to. If the + `/_matrix/identity/v2` as the endpoint to connect to. If the `m.identity_server` property is present, but does not have a `base_url` value, then `FAIL_ERROR`. diff --git a/content/identity-service-api.md b/content/identity-service-api.md index 60115306..cd915aaf 100644 --- a/content/identity-service-api.md +++ b/content/identity-service-api.md @@ -59,48 +59,48 @@ the keys `error` and `errcode` MUST always be present. Some standard error codes are below: -`M_NOT_FOUND` +`M_NOT_FOUND` The resource requested could not be located. -`M_MISSING_PARAMS` +`M_MISSING_PARAMS` The request was missing one or more parameters. -`M_INVALID_PARAM` +`M_INVALID_PARAM` The request contained one or more invalid parameters. -`M_SESSION_NOT_VALIDATED` +`M_SESSION_NOT_VALIDATED` The session has not been validated. -`M_NO_VALID_SESSION` +`M_NO_VALID_SESSION` A session could not be located for the given parameters. -`M_SESSION_EXPIRED` +`M_SESSION_EXPIRED` The session has expired and must be renewed. -`M_INVALID_EMAIL` +`M_INVALID_EMAIL` The email address provided was not valid. -`M_EMAIL_SEND_ERROR` +`M_EMAIL_SEND_ERROR` There was an error sending an email. Typically seen when attempting to verify ownership of a given email address. -`M_INVALID_ADDRESS` +`M_INVALID_ADDRESS` The provided third party address was not valid. -`M_SEND_ERROR` +`M_SEND_ERROR` There was an error sending a notification. Typically seen when attempting to verify ownership of a given third party address. -`M_UNRECOGNIZED` +`M_UNRECOGNIZED` The request contained an unrecognised value, such as an unknown token or medium. -`M_THREEPID_IN_USE` +`M_THREEPID_IN_USE` The third party identifier is already in use by another user. Typically this error will have an additional `mxid` property to indicate who owns the third party identifier. -`M_UNKNOWN` +`M_UNKNOWN` An unknown error has occurred. ## Privacy @@ -114,22 +114,6 @@ Matrix user identity, but not in the other direction (i.e. one should not be able to get all 3PIDs associated with a Matrix user ID, or get all 3PIDs associated with a 3PID). -## Version 1 API deprecation - -As described on each of the version 1 endpoints, the v1 API is -deprecated in favour of the v2 API described here. The major difference, -with the exception of a few isolated cases, is that the v2 API requires -authentication to ensure the user has given permission for the identity -server to operate on their data. - -The v1 API is planned to be removed from the specification in a future -version. - -Clients SHOULD attempt the v2 endpoints first, and if they receive a -`404`, `400`, or similar error they should try the v1 endpoint or fail -the operation. Clients are strongly encouraged to warn the user of the -risks in using the v1 API, if they are planning on using it. - ## Web browser clients It is realistic to expect that some clients will be written to be run @@ -147,12 +131,9 @@ recommended CORS headers to be returned by servers on all requests are: ## Authentication -Most `v2` endpoints in the Identity Service API require authentication +Most endpoints in the Identity Service API require authentication in order to ensure that the requesting user has accepted all relevant -policies and is otherwise permitted to make the request. The `v1` API -(currently deprecated) does not require this authentication, however -using `v1` is strongly discouraged as it will be removed in a future -release. +policies and is otherwise permitted to make the request. Identity Servers use a scheme similar to the Client-Server API's concept of access tokens to authenticate users. The access tokens provided by an @@ -202,8 +183,6 @@ has just accepted are appended to `m.accepted_terms`. ## Status check -{{% http-api spec="identity" api="ping" %}} - {{% http-api spec="identity" api="v2_ping" %}} ## Key management @@ -217,23 +196,14 @@ The identity server may also keep track of some short-term public-private keypairs, which may have different usage and lifetime characteristics than the service's long-term keys. -{{% http-api spec="identity" api="pubkey" %}} - {{% http-api spec="identity" api="v2_pubkey" %}} ## Association lookup -{{% http-api spec="identity" api="lookup" %}} - {{% http-api spec="identity" api="v2_lookup" %}} ### Client behaviour -{{% boxes/note %}} -This section only covers the v2 lookup endpoint. The v1 endpoint is -described in isolation above. -{{% /boxes/note %}} - Prior to performing a lookup clients SHOULD make a request to the `/hash_details` endpoint to determine what algorithms the server supports (described in more detail below). The client then uses this @@ -244,11 +214,6 @@ Clients MUST support at least the `sha256` algorithm. ### Server behaviour -{{% boxes/note %}} -This section only covers the v2 lookup endpoint. The v1 endpoint is -described in isolation above. -{{% /boxes/note %}} - Servers, upon receipt of a `/lookup` request, will compare the query against known bindings it has, hashing the identifiers it knows about as needed to verify exact matches to the request. @@ -398,20 +363,14 @@ through without modification. ### Email associations -{{% http-api spec="identity" api="email_associations" %}} - {{% http-api spec="identity" api="v2_email_associations" %}} ### Phone number associations -{{% http-api spec="identity" api="phone_associations" %}} - {{% http-api spec="identity" api="v2_phone_associations" %}} ### General -{{% http-api spec="identity" api="associations" %}} - {{% http-api spec="identity" api="v2_associations" %}} ## Invitation storage @@ -427,8 +386,6 @@ the Matrix user's homeserver via the endpoint. The request MUST be signed with a long-term private key for the identity server. -{{% http-api spec="identity" api="store_invite" %}} - {{% http-api spec="identity" api="v2_store_invite" %}} ## Ephemeral invitation signing @@ -438,6 +395,4 @@ identity server offers some crypto functionality to help in accepting invitations. This is less secure than the client doing it itself, but may be useful where this isn't possible. -{{% http-api spec="identity" api="invitation_signing" %}} - {{% http-api spec="identity" api="v2_invitation_signing" %}} diff --git a/data/api/identity/associations.yaml b/data/api/identity/associations.yaml deleted file mode 100644 index f2d09af1..00000000 --- a/data/api/identity/associations.yaml +++ /dev/null @@ -1,302 +0,0 @@ -# Copyright 2018 New Vector Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -swagger: '2.0' -info: - title: "Matrix Identity Service Establishing Associations API" - version: "1.0.0" -host: localhost:8090 -schemes: - - https -basePath: /_matrix/identity/api/v1 -consumes: - - application/json -produces: - - application/json -paths: - "/3pid/getValidated3pid": - get: - summary: Check whether ownership of a 3pid was validated. - description: |- - Determines if a given 3pid has been validated by a user. - operationId: getValidated3pid - deprecated: true - parameters: - - in: query - type: string - name: sid - description: The Session ID generated by the `requestToken` call. - required: true - x-example: 1234 - - in: query - type: string - name: client_secret - description: The client secret passed to the `requestToken` call. - required: true - x-example: monkeys_are_GREAT - responses: - 200: - description: Validation information for the session. - examples: - application/json: { - "medium": "email", - "validated_at": 1457622739026, - "address": "louise@bobs.burgers" - } - schema: - type: object - properties: - medium: - type: string - description: The medium type of the 3pid. - address: - type: string - description: The address of the 3pid being looked up. - validated_at: - type: integer - description: |- - Timestamp, in milliseconds, indicating the time that the 3pid - was validated. - required: ['medium', 'address', 'validated_at'] - 400: - description: |- - The session has not been validated. - - If the session has not been validated, then `errcode` will be - `M_SESSION_NOT_VALIDATED`. If the session has timed out, then - `errcode` will be `M_SESSION_EXPIRED`. - examples: - application/json: { - "errcode": "M_SESSION_NOT_VALIDATED", - "error": "This validation session has not yet been completed" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" - 404: - description: The Session ID or client secret were not found. - examples: - application/json: { - "errcode": "M_NO_VALID_SESSION", - "error": "No valid session was found matching that sid and client secret" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" - "/3pid/bind": - post: - summary: Publish an association between a session and a Matrix user ID. - description: |- - Publish an association between a session and a Matrix user ID. - - Future calls to `/lookup` for any of the session\'s 3pids will return - this association. - - Note: for backwards compatibility with previous drafts of this - specification, the parameters may also be specified as - `application/x-form-www-urlencoded` data. However, this usage is - deprecated. - operationId: bind - deprecated: true - parameters: - - in: body - name: body - schema: - type: object - example: { - "sid": "1234", - "client_secret": "monkeys_are_GREAT", - "mxid": "@ears:matrix.org" - } - properties: - sid: - type: string - description: The Session ID generated by the `requestToken` call. - client_secret: - type: string - description: The client secret passed to the `requestToken` call. - mxid: - type: string - description: The Matrix user ID to associate with the 3pids. - required: ["sid", "client_secret", "mxid"] - responses: - 200: - description: The association was published. - examples: - application/json: { - "address": "louise@bobs.burgers", - "medium": "email", - "mxid": "@ears:matrix.org", - "not_before": 1428825849161, - "not_after": 4582425849161, - "ts": 1428825849161, - "signatures": { - "matrix.org": { - "ed25519:0": "ENiU2YORYUJgE6WBMitU0mppbQjidDLanAusj8XS2nVRHPu+0t42OKA/r6zV6i2MzUbNQ3c3MiLScJuSsOiVDQ" - } - } - } - schema: - type: object - properties: - address: - type: string - description: The 3pid address of the user being looked up. - medium: - type: string - description: The medium type of the 3pid. - mxid: - type: string - description: The Matrix user ID associated with the 3pid. - not_before: - type: integer - description: A unix timestamp before which the association is not known to be valid. - not_after: - type: integer - description: A unix timestamp after which the association is not known to be valid. - ts: - type: integer - description: The unix timestamp at which the association was verified. - signatures: - type: object - description: |- - The signatures of the verifying identity servers which show that the - association should be trusted, if you trust the verifying identity - services. - $ref: "../../schemas/server-signatures.yaml" - required: - - address - - medium - - mxid - - not_before - - not_after - - ts - - signatures - 400: - description: |- - The association was not published. - - If the session has not been validated, then `errcode` will be - `M_SESSION_NOT_VALIDATED`. If the session has timed out, then - `errcode` will be `M_SESSION_EXPIRED`. - examples: - application/json: { - "errcode": "M_SESSION_NOT_VALIDATED", - "error": "This validation session has not yet been completed" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" - 404: - description: The Session ID or client secret were not found - examples: - application/json: { - "errcode": "M_NO_VALID_SESSION", - "error": "No valid session was found matching that sid and client secret" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" - "/3pid/unbind": - post: - summary: Remove an association between a session and a Matrix user ID. - description: |- - Remove an association between a session and a Matrix user ID. - - Future calls to `/lookup` for any of the session's 3pids will not - return the removed association. - - The identity server should authenticate the request in one of two - ways: - - 1. The request is signed by the homeserver which controls the `user_id`. - 2. The request includes the `sid` and `client_secret` parameters, - as per `/3pid/bind`, which proves ownership of the 3PID. - - If this endpoint returns a JSON Matrix error, that error should be passed - through to the client requesting an unbind through a homeserver, if the - homeserver is acting on behalf of a client. - operationId: unbind - deprecated: true - parameters: - - in: body - name: body - schema: - type: object - example: { - "sid": "1234", - "client_secret": "monkeys_are_GREAT", - "mxid": "@ears:example.org", - "threepid": { - "medium": "email", - "address": "monkeys_have_ears@example.org" - } - } - properties: - sid: - type: string - description: The Session ID generated by the `requestToken` call. - client_secret: - type: string - description: The client secret passed to the `requestToken` call. - mxid: - type: string - description: The Matrix user ID to remove from the 3pids. - threepid: - type: object - title: 3PID - description: |- - The 3PID to remove. Must match the 3PID used to generate the session - if using `sid` and `client_secret` to authenticate this request. - properties: - medium: - type: string - description: |- - A medium from the [3PID Types](/appendices/#3pid-types) Appendix, matching the medium - of the identifier to unbind. - address: - type: string - description: The 3PID address to remove. - required: ['medium', 'address'] - required: ["threepid", "mxid"] - responses: - 200: - description: The association was successfully removed. - examples: - application/json: {} - schema: - type: object - 400: - description: |- - If the response body is not a JSON Matrix error, the identity server - does not support unbinds. If a JSON Matrix error is in the response - body, the requesting party should respect the error. - 404: - description: |- - If the response body is not a JSON Matrix error, the identity server - does not support unbinds. If a JSON Matrix error is in the response - body, the requesting party should respect the error. - 403: - description: |- - The credentials supplied to authenticate the request were invalid. - This may also be returned if the identity server does not support - the chosen authentication method (such as blocking homeservers from - unbinding identifiers). - examples: - application/json: { - "errcode": "M_FORBIDDEN", - "error": "Invalid homeserver signature" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" - 501: - description: |- - If the response body is not a JSON Matrix error, the identity server - does not support unbinds. If a JSON Matrix error is in the response - body, the requesting party should respect the error. diff --git a/data/api/identity/email_associations.yaml b/data/api/identity/email_associations.yaml deleted file mode 100644 index 6aa7bf4a..00000000 --- a/data/api/identity/email_associations.yaml +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2018 New Vector Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -swagger: '2.0' -info: - title: "Matrix Identity Service Email Associations API" - version: "1.0.0" -host: localhost:8090 -schemes: - - https -basePath: /_matrix/identity/api/v1 -consumes: - - application/json -produces: - - application/json -paths: - "/validate/email/requestToken": - post: - summary: Request a token for validating an email address. - description: |- - Create a session for validating an email address. - - The identity server will send an email containing a token. If that - token is presented to the identity server in the future, it indicates - that that user was able to read the email for that email address, and - so we validate ownership of the email address. - - Note that homeservers offer APIs that proxy this API, adding - additional behaviour on top, for example, - `/register/email/requestToken` is designed specifically for use when - registering an account and therefore will inform the user if the email - address given is already registered on the server. - - Note: for backwards compatibility with previous drafts of this - specification, the parameters may also be specified as - `application/x-form-www-urlencoded` data. However, this usage is - deprecated. - operationId: emailRequestToken - deprecated: true - parameters: - - in: body - name: body - schema: - $ref: "definitions/request_email_validation.yaml" - responses: - 200: - description: Session created. - schema: - $ref: "definitions/sid.yaml" - 400: - description: | - An error ocurred. Some possible errors are: - - - `M_INVALID_EMAIL`: The email address provided was invalid. - - `M_EMAIL_SEND_ERROR`: The validation email could not be sent. - examples: - application/json: { - "errcode": "M_INVALID_EMAIL", - "error": "The email address is not valid" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" - "/validate/email/submitToken": - post: - summary: Validate ownership of an email address. - description: |- - Validate ownership of an email address. - - If the three parameters are consistent with a set generated by a - `requestToken` call, ownership of the email address is considered to - have been validated. This does not publish any information publicly, or - associate the email address with any Matrix user ID. Specifically, - calls to `/lookup` will not show a binding. - - The identity server is free to match the token case-insensitively, or - carry out other mapping operations such as unicode - normalisation. Whether to do so is an implementation detail for the - identity server. Clients must always pass on the token without - modification. - - Note: for backwards compatibility with previous drafts of this - specification, the parameters may also be specified as - `application/x-form-www-urlencoded` data. However, this usage is - deprecated. - operationId: emailSubmitTokenPost - deprecated: true - parameters: - - in: body - name: body - schema: - type: object - example: { - "sid": "1234", - "client_secret": "monkeys_are_GREAT", - "token": "atoken" - } - properties: - sid: - type: string - description: The session ID, generated by the `requestToken` call. - client_secret: - type: string - description: The client secret that was supplied to the `requestToken` call. - token: - type: string - description: The token generated by the `requestToken` call and emailed to the user. - required: ["sid", "client_secret", "token"] - responses: - 200: - description: - The success of the validation. - examples: - application/json: { - "success": true - } - schema: - type: object - properties: - success: - type: boolean - description: Whether the validation was successful or not. - required: ['success'] - get: - summary: Validate ownership of an email address. - description: |- - Validate ownership of an email address. - - If the three parameters are consistent with a set generated by a - `requestToken` call, ownership of the email address is considered to - have been validated. This does not publish any information publicly, or - associate the email address with any Matrix user ID. Specifically, - calls to `/lookup` will not show a binding. - - Note that, in contrast with the POST version, this endpoint will be - used by end-users, and so the response should be human-readable. - operationId: emailSubmitTokenGet - deprecated: true - parameters: - - in: query - type: string - name: sid - required: true - description: The session ID, generated by the `requestToken` call. - x-example: 1234 - - in: query - type: string - name: client_secret - required: true - description: The client secret that was supplied to the `requestToken` call. - x-example: monkeys_are_GREAT - - in: query - type: string - name: token - required: true - description: The token generated by the `requestToken` call and emailed to the user. - x-example: atoken - responses: - 200: - description: Email address is validated. - "3xx": - description: |- - Email address is validated, and the `next_link` parameter was - provided to the `requestToken` call. The user must be redirected - to the URL provided by the `next_link` parameter. - "4xx": - description: - Validation failed. diff --git a/data/api/identity/invitation_signing.yaml b/data/api/identity/invitation_signing.yaml deleted file mode 100644 index a3d215f2..00000000 --- a/data/api/identity/invitation_signing.yaml +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2018 New Vector Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -swagger: '2.0' -info: - title: "Matrix Identity Service Ephemeral Invitation Signing API" - version: "1.0.0" -host: localhost:8090 -schemes: - - https -basePath: /_matrix/identity/api/v1 -consumes: - - application/json -produces: - - application/json -paths: - "/sign-ed25519": - post: - summary: Sign invitation details - description: |- - Sign invitation details. - - The identity server will look up `token` which was stored in a call - to `store-invite`, and fetch the sender of the invite. - operationId: blindlySignStuff - deprecated: true - parameters: - - in: body - name: body - schema: - type: object - example: { - "mxid": "@foo:bar.com", - "token": "sometoken", - "private_key": "base64encodedkey" - } - properties: - mxid: - type: string - description: The Matrix user ID of the user accepting the invitation. - token: - type: string - description: The token from the call to `store-invite`. - private_key: - type: string - description: The private key, encoded as [Unpadded base64](/appendices/#unpadded-base64). - required: ["mxid", "token", "private_key"] - responses: - 200: - description: The signed JSON of the mxid, sender, and token. - schema: - type: object - properties: - mxid: - type: string - description: The Matrix user ID of the user accepting the invitation. - sender: - type: string - description: The Matrix user ID of the user who sent the invitation. - signatures: - type: object - description: The signature of the mxid, sender, and token. - $ref: "../../schemas/server-signatures.yaml" - token: - type: string - description: The token for the invitation. - required: ['mxid', 'sender', 'signatures', 'token'] - examples: - application/json: { - "mxid": "@foo:bar.com", - "sender": "@baz:bar.com", - "signatures": { - "my.id.server": { - "ed25519:0": "def987" - } - }, - "token": "abc123" - } - 404: - description: The token was not found. - examples: - application/json: { - "errcode": "M_UNRECOGNIZED", - "error": "Didn't recognize token" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" diff --git a/data/api/identity/lookup.yaml b/data/api/identity/lookup.yaml deleted file mode 100644 index 6163807e..00000000 --- a/data/api/identity/lookup.yaml +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2016 OpenMarket Ltd -# Copyright 2017 Kamax.io -# Copyright 2017 New Vector Ltd -# Copyright 2018 New Vector Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -swagger: '2.0' -info: - title: "Matrix Identity Service Lookup API" - version: "1.0.0" -host: localhost:8090 -schemes: - - https -basePath: /_matrix/identity/api/v1 -consumes: - - application/json -produces: - - application/json -paths: - "/lookup": - get: - summary: Look up the Matrix user ID for a 3pid. - description: Look up the Matrix user ID for a 3pid. - operationId: lookupUser - deprecated: true - parameters: - - in: query - type: string - name: medium - required: true - description: The medium type of the 3pid. See the [3PID Types](/appendices/#3pid-types) Appendix. - x-example: "email" - - in: query - type: string - name: address - required: true - description: The address of the 3pid being looked up. See the [3PID Types](/appendices/#3pid-types) Appendix. - x-example: "louise@bobs.burgers" - responses: - 200: - description: - The association for that 3pid, or an empty object if no association is known. - examples: - application/json: { - "address": "louise@bobs.burgers", - "medium": "email", - "mxid": "@ears:matrix.org", - "not_before": 1428825849161, - "not_after": 4582425849161, - "ts": 1428825849161, - "signatures": { - "matrix.org": { - "ed25519:0": "ENiU2YORYUJgE6WBMitU0mppbQjidDLanAusj8XS2nVRHPu+0t42OKA/r6zV6i2MzUbNQ3c3MiLScJuSsOiVDQ" - } - } - } - schema: - type: object - properties: - address: - type: string - description: The 3pid address of the user being looked up, matching the address requested. - medium: - type: string - description: A medium from the [3PID Types](/appendices/#3pid-types) Appendix, matching the medium requested. - mxid: - type: string - description: The Matrix user ID associated with the 3pid. - not_before: - type: integer - description: A unix timestamp before which the association is not known to be valid. - not_after: - type: integer - description: A unix timestamp after which the association is not known to be valid. - ts: - type: integer - description: The unix timestamp at which the association was verified. - signatures: - type: object - description: The signatures of the verifying identity servers which show that the association should be trusted, if you trust the verifying identity servers. - $ref: "../../schemas/server-signatures.yaml" - required: - - address - - medium - - mxid - - not_before - - not_after - - ts - - signatures - "/bulk_lookup": - post: - summary: Lookup Matrix user IDs for a list of 3pids. - description: Lookup Matrix user IDs for a list of 3pids. - operationId: lookupUsers - deprecated: true - parameters: - - in: body - name: body - schema: - type: object - example: { - "threepids": - [ - ["email","user@example.org"], - ["msisdn", "123456789"], - ["email","user2@example.org"] - ] - } - properties: - threepids: - type: array - items: - type: array - title: 3PID mappings - minItems: 2 - maxItems: 2 - items: - # TODO: Give real names to these values. Adding a `title` does not work. - #- type: 3PID Medium - #- type: 3PID Address - - type: string - - type: string - description: |- - An array of arrays containing the [3PID Types](/appendices/#3pid-types) with the `medium` - in first position and the `address` in second position. - required: - - "threepids" - responses: - 200: - description: A list of known 3PID mappings for the supplied 3PIDs. - examples: - application/json: { - "threepids": [ - ["email","user@example.org", "@bla:example.org"], - ["msisdn", "123456789", "@blah2:example.com"] - ] - } - schema: - type: object - properties: - threepids: - type: array - items: - type: array - title: 3PID mappings - minItems: 3 - maxItems: 3 - items: - # TODO: Give real names to these values. Adding a `title` does not work. - #- type: 3PID Medium - #- type: 3PID Address - #- type: Matrix User ID - - type: string - - type: string - - type: string - description: |- - An array of array containing the [3PID Types](/appendices/#3pid-types) with the `medium` - in first position, the `address` in second position and Matrix user - ID in third position. - required: - - "threepids" diff --git a/data/api/identity/phone_associations.yaml b/data/api/identity/phone_associations.yaml deleted file mode 100644 index 53d4132d..00000000 --- a/data/api/identity/phone_associations.yaml +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright 2018 New Vector Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -swagger: '2.0' -info: - title: "Matrix Identity Service Phone Number Associations API" - version: "1.0.0" -host: localhost:8090 -schemes: - - https -basePath: /_matrix/identity/api/v1 -consumes: - - application/json -produces: - - application/json -paths: - "/validate/msisdn/requestToken": - post: - summary: Request a token for validating a phone number. - description: |- - Create a session for validating a phone number. - - The identity server will send an SMS message containing a token. If - that token is presented to the identity server in the future, it - indicates that that user was able to read the SMS for that phone - number, and so we validate ownership of the phone number. - - Note that homeservers offer APIs that proxy this API, adding - additional behaviour on top, for example, - `/register/msisdn/requestToken` is designed specifically for use when - registering an account and therefore will inform the user if the phone - number given is already registered on the server. - - Note: for backwards compatibility with previous drafts of this - specification, the parameters may also be specified as - `application/x-form-www-urlencoded` data. However, this usage is - deprecated. - operationId: msisdnRequestToken - deprecated: true - parameters: - - in: body - name: body - schema: - $ref: "definitions/request_msisdn_validation.yaml" - responses: - 200: - description: Session created. - schema: - $ref: "definitions/sid.yaml" - 400: - description: | - An error ocurred. Some possible errors are: - - - `M_INVALID_ADDRESS`: The phone number provided was invalid. - - `M_SEND_ERROR`: The validation SMS could not be sent. - - `M_DESTINATION_REJECTED`: The identity server cannot deliver an - SMS to the provided country or region. - examples: - application/json: { - "errcode": "M_INVALID_ADDRESS", - "error": "The phone number is not valid" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" - "/validate/msisdn/submitToken": - post: - summary: Validate ownership of a phone number. - description: |- - Validate ownership of a phone number. - - If the three parameters are consistent with a set generated by a - `requestToken` call, ownership of the phone number is considered to - have been validated. This does not publish any information publicly, or - associate the phone number address with any Matrix user - ID. Specifically, calls to `/lookup` will not show a binding. - - The identity server is free to match the token case-insensitively, or - carry out other mapping operations such as unicode - normalisation. Whether to do so is an implementation detail for the - identity server. Clients must always pass on the token without - modification. - - Note: for backwards compatibility with previous drafts of this - specification, the parameters may also be specified as - `application/x-form-www-urlencoded` data. However, this usage is - deprecated. - operationId: msisdnSubmitTokenPost - deprecated: true - parameters: - - in: body - name: body - schema: - type: object - example: { - "sid": "1234", - "client_secret": "monkeys_are_GREAT", - "token": "atoken" - } - properties: - sid: - type: string - description: The session ID, generated by the `requestToken` call. - client_secret: - type: string - description: The client secret that was supplied to the `requestToken` call. - token: - type: string - description: The token generated by the `requestToken` call and sent to the user. - required: ["sid", "client_secret", "token"] - responses: - 200: - description: - The success of the validation. - examples: - application/json: { - "success": true - } - schema: - type: object - properties: - success: - type: boolean - description: Whether the validation was successful or not. - required: ['success'] - get: - summary: Validate ownership of a phone number. - description: |- - Validate ownership of a phone number. - - If the three parameters are consistent with a set generated by a - `requestToken` call, ownership of the phone number address is - considered to have been validated. This does not publish any - information publicly, or associate the phone number with any Matrix - user ID. Specifically, calls to `/lookup` will not show a binding. - - Note that, in contrast with the POST version, this endpoint will be - used by end-users, and so the response should be human-readable. - operationId: msisdnSubmitTokenGet - deprecated: true - parameters: - - in: query - type: string - name: sid - required: true - description: The session ID, generated by the `requestToken` call. - x-example: 1234 - - in: query - type: string - name: client_secret - required: true - description: The client secret that was supplied to the `requestToken` call. - x-example: monkeys_are_GREAT - - in: query - type: string - name: token - required: true - description: The token generated by the `requestToken` call and sent to the user. - x-example: atoken - responses: - 200: - description: Phone number is validated. - "3xx": - description: |- - Phone number address is validated, and the `next_link` parameter - was provided to the `requestToken` call. The user must be - redirected to the URL provided by the `next_link` parameter. - "4xx": - description: - Validation failed. diff --git a/data/api/identity/ping.yaml b/data/api/identity/ping.yaml deleted file mode 100644 index d7249a77..00000000 --- a/data/api/identity/ping.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2018 Kamax Sàrl -# Copyright 2018 New Vector Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -swagger: "2.0" -info: - title: "Matrix Identity Service Ping API" - version: "1.0.0" -host: localhost:8090 -schemes: - - https -basePath: /_matrix/identity -produces: - - application/json -paths: - "/api/v1": - get: - summary: Checks that an identity server is available at this API endpoint. - description: |- - Checks that an identity server is available at this API endpoint. - - To discover that an identity server is available at a specific URL, - this endpoint can be queried and will return an empty object. - - This is primarly used for auto-discovery and health check purposes - by entities acting as a client for the identity server. - operationId: ping - deprecated: true - responses: - 200: - description: An identity server is ready to serve requests. - examples: - application/json: {} - schema: - type: object diff --git a/data/api/identity/pubkey.yaml b/data/api/identity/pubkey.yaml deleted file mode 100644 index a585e7ec..00000000 --- a/data/api/identity/pubkey.yaml +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2016 OpenMarket Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -swagger: '2.0' -info: - title: "Matrix Identity Service Public Key API" - version: "1.0.0" -host: localhost:8090 -schemes: - - https -basePath: /_matrix/identity/api/v1 -consumes: - - application/json -produces: - - application/json -paths: - "/pubkey/{keyId}": - get: - summary: Get a public key. - description: |- - Get the public key for the passed key ID. - operationId: getPubKey - deprecated: true - parameters: - - in: path - type: string - name: keyId - required: true - description: |- - The ID of the key. This should take the form algorithm:identifier - where algorithm identifies the signing algorithm, and the identifier - is an opaque string. - x-example: "ed25519:0" - responses: - 200: - description: - The public key exists. - examples: - application/json: { - "public_key": "VXuGitF39UH5iRfvbIknlvlAVKgD1BsLDMvBf0pmp7c" - } - schema: - type: object - properties: - public_key: - type: string - description: Unpadded Base64 encoded public key. - required: ['public_key'] - 404: - description: - The public key was not found. - examples: - application/json: { - "errcode": "M_NOT_FOUND", - "error": "The public key was not found" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" - "/pubkey/isvalid": - get: - summary: Check whether a long-term public key is valid. - description: |- - Check whether a long-term public key is valid. The response should always - be the same, provided the key exists. - operationId: isPubKeyValid - deprecated: true - parameters: - - in: query - type: string - name: public_key - required: true - description: |- - The unpadded base64-encoded public key to check. - x-example: "VXuGitF39UH5iRfvbIknlvlAVKgD1BsLDMvBf0pmp7c" - responses: - 200: - description: - The validity of the public key. - examples: - application/json: { - "valid": true - } - schema: - type: object - properties: - valid: - type: boolean - description: Whether the public key is recognised and is currently valid. - required: ['valid'] - "/pubkey/ephemeral/isvalid": - get: - summary: Check whether a short-term public key is valid. - description: |- - Check whether a short-term public key is valid. - operationId: isEphemeralPubKeyValid - deprecated: true - parameters: - - in: query - type: string - name: public_key - required: true - description: |- - The unpadded base64-encoded public key to check. - x-example: "VXuGitF39UH5iRfvbIknlvlAVKgD1BsLDMvBf0pmp7c" - responses: - 200: - description: - The validity of the public key. - examples: - application/json: { - "valid": true - } - schema: - type: object - properties: - valid: - type: boolean - description: Whether the public key is recognised and is currently valid. - required: ['valid'] diff --git a/data/api/identity/store_invite.yaml b/data/api/identity/store_invite.yaml deleted file mode 100644 index 20e40852..00000000 --- a/data/api/identity/store_invite.yaml +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright 2018 New Vector Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -swagger: '2.0' -info: - title: "Matrix Identity Service Store Invitations API" - version: "1.0.0" -host: localhost:8090 -schemes: - - https -basePath: /_matrix/identity/api/v1 -consumes: - - application/json -produces: - - application/json -paths: - "/store-invite": - post: - summary: Store pending invitations to a user's 3pid. - description: |- - Store pending invitations to a user's 3pid. - - In addition to the request parameters specified below, an arbitrary - number of other parameters may also be specified. These may be used in - the invite message generation described below. - - The service will generate a random token and an ephemeral key used for - accepting the invite. - - The service also generates a `display_name` for the inviter, which is - a redacted version of `address` which does not leak the full contents - of the `address`. - - The service records persistently all of the above information. - - It also generates an email containing all of this data, sent to the - `address` parameter, notifying them of the invitation. - - Also, the generated ephemeral public key will be listed as valid on - requests to `/_matrix/identity/api/v1/pubkey/ephemeral/isvalid`. - - Currently, invites may only be issued for 3pids of the `email` medium. - - Optional fields in the request should be populated to the best of the - server's ability. Identity servers may use these variables when notifying - the `address` of the pending invite for display purposes. - operationId: storeInvite - deprecated: true - parameters: - - in: body - name: body - schema: - type: object - properties: - medium: - type: string - description: The literal string `email`. - example: "email" - address: - type: string - description: The email address of the invited user. - example: "foo@example.com" - room_id: - type: string - description: The Matrix room ID to which the user is invited - example: "!something:example.org" - sender: - type: string - description: The Matrix user ID of the inviting user - example: "@bob:example.com" - room_alias: - type: string - description: |- - The Matrix room alias for the room to which the user is - invited. This should be retrieved from the `m.room.canonical_alias` - state event. - example: "#somewhere:exmaple.org" - room_avatar_url: - type: string - description: |- - The Content URI for the room to which the user is invited. This should - be retrieved from the `m.room.avatar` state event. - example: "mxc://example.org/s0meM3dia" - room_join_rules: - type: string - description: |- - The `join_rule` for the room to which the user is invited. This should - be retrieved from the `m.room.join_rules` state event. - example: "public" - room_name: - type: string - description: |- - The name of the room to which the user is invited. This should be retrieved - from the `m.room.name` state event. - example: "Bob's Emporium of Messages" - sender_display_name: - type: string - description: The display name of the user ID initiating the invite. - example: "Bob Smith" - sender_avatar_url: - type: string - description: The Content URI for the avatar of the user ID initiating the invite. - example: "mxc://example.org/an0th3rM3dia" - required: ["medium", "address", "room_id", "sender"] - responses: - 200: - description: The invitation was stored. - schema: - type: object - properties: - token: - type: string - description: | - The generated token. Must be a string consisting of the - characters `[0-9a-zA-Z.=_-]`. Its length must not exceed - 255 characters and it must not be empty. - public_keys: - type: array - description: | - A list of [server's long-term public key, generated ephemeral - public key]. - items: - type: string - display_name: - type: string - description: The generated (redacted) display_name. - required: ['token', 'public_keys', 'display_name'] - example: - application/json: { - "token": "sometoken", - "public_keys": [ - "serverpublickey", - "ephemeralpublickey" - ], - "display_name": "f...@b..." - } - 400: - description: | - An error has occured. - - If the 3pid is already bound to a Matrix user ID, the error code - will be `M_THREEPID_IN_USE`. If the medium is unsupported, the - error code will be `M_UNRECOGNIZED`. - examples: - application/json: { - "errcode": "M_THREEPID_IN_USE", - "error": "Binding already known", - "mxid": "@alice:example.com" - } - schema: - $ref: "../client-server/definitions/errors/error.yaml" From 67d5d9eb4948c1b475ea75538c133de4a61547e9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 1 May 2021 22:52:02 -0600 Subject: [PATCH 090/107] Changelog --- changelogs/identity_service/newsfragments/3170.removal | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/identity_service/newsfragments/3170.removal diff --git a/changelogs/identity_service/newsfragments/3170.removal b/changelogs/identity_service/newsfragments/3170.removal new file mode 100644 index 00000000..c43ca64d --- /dev/null +++ b/changelogs/identity_service/newsfragments/3170.removal @@ -0,0 +1 @@ +The v1 identity service API has been removed in favour of the v2 API, as per [MSC2713](https://github.com/matrix-org/matrix-doc/pull/2713). \ No newline at end of file From ca3c42d865e122d3ad5abfcfe9ce14d97ca427a3 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 14 Apr 2021 14:32:19 -0400 Subject: [PATCH 091/107] deprecate starting verifications without first requesting --- ...-starting-verifications-without-request.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 proposals/xxxx-deprecate-starting-verifications-without-request.md diff --git a/proposals/xxxx-deprecate-starting-verifications-without-request.md b/proposals/xxxx-deprecate-starting-verifications-without-request.md new file mode 100644 index 00000000..3d0ec821 --- /dev/null +++ b/proposals/xxxx-deprecate-starting-verifications-without-request.md @@ -0,0 +1,37 @@ +# MSCxxxx: Depretate starting key verifications without requesting first + +Currently, the spec allows a device to begin a verification via to-device +messages by sending an `m.key.verification.start` event without first sending +or receiving an `m.key.verification.request` message. However, doing so does +not provide a good user experience, and allowing this adds unnecessary +complexity to implementations. + +We propose to deprecate allowing this behaviour. + +Note that verifications in DMs do not allow this behaviour. Currently, Element +Web is the only client known to do this. + +## Proposal + +The ability to begin a key verification by sending an +`m.key.verification.start` event as a to-device event without a prior +`m.key.verification.request` is deprecated. New clients should not begin +verifications in this way, but will still need to accept verifications begun in +this way, until it is removed from the spec. + +## Potential issues + +None. + +## Alternatives + +We could do nothing and leave it in the spec. But we should clean up cruft when +possible. + +## Security considerations + +None. + +## Unstable prefix + +No unstable prefix is removed since we are simply deprecating behaviour. From e0ec01a999c5f2a6e31f57968ef2a0a77d636654 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 14 Apr 2021 14:33:57 -0400 Subject: [PATCH 092/107] use MSC number --- ...=> 3122-deprecate-starting-verifications-without-request.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename proposals/{xxxx-deprecate-starting-verifications-without-request.md => 3122-deprecate-starting-verifications-without-request.md} (94%) diff --git a/proposals/xxxx-deprecate-starting-verifications-without-request.md b/proposals/3122-deprecate-starting-verifications-without-request.md similarity index 94% rename from proposals/xxxx-deprecate-starting-verifications-without-request.md rename to proposals/3122-deprecate-starting-verifications-without-request.md index 3d0ec821..ba4b2d7f 100644 --- a/proposals/xxxx-deprecate-starting-verifications-without-request.md +++ b/proposals/3122-deprecate-starting-verifications-without-request.md @@ -1,4 +1,4 @@ -# MSCxxxx: Depretate starting key verifications without requesting first +# MSC3122: Depretate starting key verifications without requesting first Currently, the spec allows a device to begin a verification via to-device messages by sending an `m.key.verification.start` event without first sending From fbbdd0f6ccbefde1dc11ddfe346b57867050d24a Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 14 Apr 2021 14:42:21 -0400 Subject: [PATCH 093/107] I should pay attention when my editor says that things are misspelled --- .../3122-deprecate-starting-verifications-without-request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3122-deprecate-starting-verifications-without-request.md b/proposals/3122-deprecate-starting-verifications-without-request.md index ba4b2d7f..981721d8 100644 --- a/proposals/3122-deprecate-starting-verifications-without-request.md +++ b/proposals/3122-deprecate-starting-verifications-without-request.md @@ -1,4 +1,4 @@ -# MSC3122: Depretate starting key verifications without requesting first +# MSC3122: Deprecate starting key verifications without requesting first Currently, the spec allows a device to begin a verification via to-device messages by sending an `m.key.verification.start` event without first sending From ad93aa65467033b9865ab5c22c807701dbeb3b4c Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Wed, 5 May 2021 11:47:23 +0100 Subject: [PATCH 094/107] Update client_secret examples so that they are valid (#2985) The regex of allowed characters for a `client_secret` parameter is `[0-9a-zA-Z.=_-]`. This PR updates the `client_secret` spec examples, which currently include an invalid character (an apostrophe). --- changelogs/client_server/newsfragments/2985.clarification | 1 + data/api/client-server/administrative_contact.yaml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 changelogs/client_server/newsfragments/2985.clarification diff --git a/changelogs/client_server/newsfragments/2985.clarification b/changelogs/client_server/newsfragments/2985.clarification new file mode 100644 index 00000000..d3c768e3 --- /dev/null +++ b/changelogs/client_server/newsfragments/2985.clarification @@ -0,0 +1 @@ +Correct examples of `client_secret` request body parameters so that they do not include invalid characters. diff --git a/data/api/client-server/administrative_contact.yaml b/data/api/client-server/administrative_contact.yaml index cea8538e..72458b6b 100644 --- a/data/api/client-server/administrative_contact.yaml +++ b/data/api/client-server/administrative_contact.yaml @@ -139,7 +139,7 @@ paths: "id_server": "matrix.org", "id_access_token": "abc123_OpaqueString", "sid": "abc123987", - "client_secret": "d0n'tT3ll" + "client_secret": "d0nt-T3ll" } } responses: @@ -215,7 +215,7 @@ paths: required: ["client_secret", "sid"] example: { "sid": "abc123987", - "client_secret": "d0n'tT3ll" + "client_secret": "d0nt-T3ll" } responses: 200: @@ -272,7 +272,7 @@ paths: "id_server": "example.org", "id_access_token": "abc123_OpaqueString", "sid": "abc123987", - "client_secret": "d0n'tT3ll" + "client_secret": "d0nt-T3ll" } responses: 200: From 620278786ddb10f84ffcd889a385f217870c618f Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 20 Apr 2021 11:39:26 -0400 Subject: [PATCH 095/107] Update proposals/3122-deprecate-starting-verifications-without-request.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- .../3122-deprecate-starting-verifications-without-request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3122-deprecate-starting-verifications-without-request.md b/proposals/3122-deprecate-starting-verifications-without-request.md index 981721d8..110f1377 100644 --- a/proposals/3122-deprecate-starting-verifications-without-request.md +++ b/proposals/3122-deprecate-starting-verifications-without-request.md @@ -34,4 +34,4 @@ None. ## Unstable prefix -No unstable prefix is removed since we are simply deprecating behaviour. +No unstable prefix is required since we are simply deprecating behaviour. From 3c01fa4681f29944bbbba2a7f352e61e001c0661 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 4 May 2021 09:43:02 -0600 Subject: [PATCH 096/107] Remove group identifiers Groups are replaced by https://github.com/matrix-org/matrix-doc/pull/1772 and this probably shouldn't have made it into the spec in the first place without the remaining context of Groups. --- content/appendices.md | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/content/appendices.md b/content/appendices.md index 9132dd6d..aa19aeae 100644 --- a/content/appendices.md +++ b/content/appendices.md @@ -590,32 +590,6 @@ Event IDs and Room IDs are case-sensitive. They are not meant to be human-readable. They are intended to be treated as fully opaque strings by clients. -#### Group Identifiers - -Groups within Matrix are uniquely identified by their group ID. The -group ID is namespaced to the group server which hosts this group and -has the form: - - +localpart:domain - -The `localpart` of a group ID is an opaque identifier for that group. It -MUST NOT be empty, and MUST contain only the characters `a-z`, `0-9`, -`.`, `_`, `=`, `-`, and `/`. - -The `domain` of a group ID is the [server name](#server-name) of the -group server which hosts this group. - -The length of a group ID, including the `+` sigil and the domain, MUST -NOT exceed 255 characters. - -The complete grammar for a legal group ID is: - - group_id = "+" group_id_localpart ":" server_name - group_id_localpart = 1*group_id_char - group_id_char = DIGIT - / %x61-7A ; a-z - / "-" / "." / "=" / "_" / "/" - #### Room Aliases A room may have zero or more aliases. A room alias has the format: @@ -674,7 +648,6 @@ Examples of matrix.to URIs are: - Permalink by room alias: `https://matrix.to/#/%23somewhere:example.org/%24event%3Aexample.org` - User: `https://matrix.to/#/%40alice%3Aexample.org` -- Group: `https://matrix.to/#/%2Bexample%3Aexample.org` {{% boxes/note %}} Historically, clients have not produced URIs which are fully encoded. @@ -690,6 +663,16 @@ versions](/#room-versions). These slashes should normally be encoded when producing matrix.to URIs, however. {{% /boxes/note %}} +{{% boxes/note %}} + +In prior versions of this specification, a concept of "groups" were mentioned +to organize rooms. This functionality did not properly get introduced into +the specification and is subsequently replaced with "Spaces". Historical +matrix.to URIs pointing to groups might still exist: they take the form +`https://matrix.to/#/%2Bexample%3Aexample.org` (where the `+` sigil may or +may not be encoded). +{{% /boxes/note %}} + ##### Routing Room IDs are not routable on their own as there is no reliable domain to From adbe95259f596c42b9d2bf7c9cdf0582c6300492 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 20 Apr 2021 11:43:10 -0400 Subject: [PATCH 097/107] add link to relevant spec --- ...recate-starting-verifications-without-request.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/proposals/3122-deprecate-starting-verifications-without-request.md b/proposals/3122-deprecate-starting-verifications-without-request.md index 110f1377..9a00699b 100644 --- a/proposals/3122-deprecate-starting-verifications-without-request.md +++ b/proposals/3122-deprecate-starting-verifications-without-request.md @@ -1,10 +1,13 @@ # MSC3122: Deprecate starting key verifications without requesting first -Currently, the spec allows a device to begin a verification via to-device -messages by sending an `m.key.verification.start` event without first sending -or receiving an `m.key.verification.request` message. However, doing so does -not provide a good user experience, and allowing this adds unnecessary -complexity to implementations. +Currently, the [Key verification +framework](https://spec.matrix.org/unstable/client-server-api/#key-verification-framework) +allows a device to begin a verification via to-device messages by sending an +`m.key.verification.start` event without first sending or receiving an +`m.key.verification.request` message. (The last sentence of the 5th paragraph +of the Key verification framework in the unstable spec, as of the time of +writing.) However, doing so does not provide a good user experience, and +allowing this adds unnecessary complexity to implementations. We propose to deprecate allowing this behaviour. From 5d0d5a3981f08cbf515a4f0a54e5550c7782a8ef Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Thu, 6 May 2021 13:41:08 +0100 Subject: [PATCH 098/107] Clarify what happens when a concern is raised during FCP (#3180) It wasn't entirely clear what should happen to the FCP timer (and state) when a concern is raised during FCP. After some discussion, we agreed that when a concern is raised: 1. FCP will continue to not conclude until at least 5 days have passed, but once those 5 days are up it *still* won't conclude until all concerns raised during FCP are resolved. 2. If a concern warrants a large enough change in the document, then the Spec Core Team may consider cancelling FCP and restarting the timer in order for people to have some time to think about and review the new changes. --- content/proposals.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/content/proposals.md b/content/proposals.md index 28cb670c..d724f308 100644 --- a/content/proposals.md +++ b/content/proposals.md @@ -245,10 +245,13 @@ is as follows: 75% of the members of the Spec Core Team agree on its outcome, and all existing concerns have been resolved. - The FCP will then begin and last for 5 days, giving anyone else some - time to speak up before it concludes. On its conclusion, the - disposition of the FCP will be carried out. If sufficient reasoning - against the disposition is raised, the FCP can be cancelled and the - MSC will continue to evolve accordingly. + time to speak up before it concludes. If sufficient reasoning + against the disposition is provided, a member of the Spec Core Team can + raise a concern and block FCP from completing. This will not reset or + pause the 5 day FCP timer, but FCP will not conclude until all concerns have + been resolved. If sufficient change in the MSC is required to resolve those + concerns, FCP might be cancelled and reproposed. Once FCP has concluded, + the disposition of the FCP will be carried out. - Once the proposal has been accepted and merged, it is time to submit the actual change to the Specification that your proposal reasoned about. This is known as a spec PR. However in order for the spec PR @@ -373,7 +376,7 @@ be merged without the Spec Core Team focusing on them specifically. ## Implementing a proposal -As part of the proposal process the spec core team will require evidence +As part of the proposal process the Spec Core Team will require evidence of the MSC working in order for it to move into FCP. This can usually be a branch/pull request to whichever implementation of choice that proves the MSC works in practice, though in some cases the MSC itself will be From 2fa7b59e1acc9992b4c4438a7d5f1829190c197e Mon Sep 17 00:00:00 2001 From: Lukas Lihotzki Date: Thu, 6 May 2021 17:36:28 +0200 Subject: [PATCH 099/107] OpenAPI: fix tags of add3PID The tag needs to be set to include add3PID in scripts/swagger/api-docs.json. Signed-off-by: Lukas Lihotzki --- data/api/client-server/administrative_contact.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/api/client-server/administrative_contact.yaml b/data/api/client-server/administrative_contact.yaml index 72458b6b..9966015b 100644 --- a/data/api/client-server/administrative_contact.yaml +++ b/data/api/client-server/administrative_contact.yaml @@ -233,6 +233,8 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/errors/rate_limited.yaml" + tags: + - User data "/account/3pid/bind": post: summary: Binds a 3PID to the user's account through an Identity Service. From 6012ddcdec3a12fe706bd36e3ffa6f8c6fc1468b Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 10 May 2021 10:29:21 -0600 Subject: [PATCH 100/107] Mention expected client behaviour of unknown types on MSC1772 This was discussed in various places, but never quite made it to the MSC. --- 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 bd416df5..b6f60b38 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -45,7 +45,11 @@ depending on the purpose of the room. Currently, no server-side behaviour is 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. +section below. Additionally, no client behaviour is recommended for handling +unknown room types given the potential for legacy data: clients are free to +make their own decisions about hiding unknown room types from users, though +should note that a future conversation-like type (for example) might be +introduced and could be considered "unknown" by older versions of their client. 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. From 0ea5f72c831afea3fe2e03d326a9062f8812c20f Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 27 Apr 2021 17:56:30 +0000 Subject: [PATCH 101/107] Added translation using Weblate (Hungarian) --- data-definitions/sas-emoji-v1-i18n/hu.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 data-definitions/sas-emoji-v1-i18n/hu.json diff --git a/data-definitions/sas-emoji-v1-i18n/hu.json b/data-definitions/sas-emoji-v1-i18n/hu.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/data-definitions/sas-emoji-v1-i18n/hu.json @@ -0,0 +1 @@ +{} From 6c46933fbc9cc8771d9deaddc1b91b475d6c1499 Mon Sep 17 00:00:00 2001 From: Lukas Lihotzki Date: Mon, 10 May 2021 21:02:05 +0200 Subject: [PATCH 102/107] Fix Typo Signed-off-by: Lukas Lihotzki --- data/api/client-server/appservice_room_directory.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/api/client-server/appservice_room_directory.yaml b/data/api/client-server/appservice_room_directory.yaml index ec0470c3..ab66bdd9 100644 --- a/data/api/client-server/appservice_room_directory.yaml +++ b/data/api/client-server/appservice_room_directory.yaml @@ -43,7 +43,7 @@ paths: This API requires the use of an application service access token (`as_token`) instead of a typical client's access_token. This API cannot be invoked by users who are not identified as application services. - operationId: updateAppserviceRoomDirectoryVsibility + operationId: updateAppserviceRoomDirectoryVisibility parameters: - in: path type: string From 1282e8a91c46ca0385664af8c07551057b9e5ab7 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Thu, 6 May 2021 08:48:45 +0000 Subject: [PATCH 103/107] Translated using Weblate (Hungarian) Currently translated at 100.0% (64 of 64 strings) Translation: matrix-doc/SAS Emoji v1 Translate-URL: https://translate.element.io/projects/matrix-doc/sas-emoji-v1/hu/ --- data-definitions/sas-emoji-v1-i18n/hu.json | 67 +++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/data-definitions/sas-emoji-v1-i18n/hu.json b/data-definitions/sas-emoji-v1-i18n/hu.json index 0967ef42..01d56730 100644 --- a/data-definitions/sas-emoji-v1-i18n/hu.json +++ b/data-definitions/sas-emoji-v1-i18n/hu.json @@ -1 +1,66 @@ -{} +{ + "Pin": "Rajszeg", + "Folder": "Mappa", + "Headphones": "Fejhallgató", + "Anchor": "Horgony", + "Bell": "Harang", + "Trumpet": "Trombita", + "Guitar": "Gitár", + "Ball": "Labda", + "Trophy": "Trófea", + "Rocket": "Rakáta", + "Aeroplane": "Repülő", + "Bicycle": "Kerékpár", + "Train": "Vonat", + "Flag": "Zászló", + "Telephone": "Telefon", + "Hammer": "Kalapács", + "Key": "Kulcs", + "Lock": "Lakat", + "Scissors": "Olló", + "Paperclip": "Gémkapocs", + "Pencil": "Ceruza", + "Book": "Könyv", + "Light Bulb": "Égő", + "Gift": "Ajándék", + "Clock": "Óra", + "Hourglass": "Homokóra", + "Umbrella": "Esernyő", + "Thumbs Up": "Hüvelykujj fel", + "Santa": "Télapó", + "Spanner": "Csavarkulcs", + "Glasses": "Szemüveg", + "Hat": "Kalap", + "Robot": "Robot", + "Smiley": "Mosoly", + "Heart": "Szív", + "Cake": "Süti", + "Pizza": "Pizza", + "Corn": "Kukorica", + "Strawberry": "Eper", + "Apple": "Alma", + "Banana": "Banán", + "Fire": "Tűz", + "Cloud": "Felhő", + "Moon": "Hold", + "Globe": "Földgömb", + "Mushroom": "Gomba", + "Cactus": "Kaktusz", + "Tree": "Fa", + "Flower": "Virág", + "Butterfly": "Pillangó", + "Octopus": "Polip", + "Fish": "Hal", + "Turtle": "Teknős", + "Penguin": "Pingvin", + "Rooster": "Kakas", + "Panda": "Panda", + "Rabbit": "Nyúl", + "Elephant": "Elefánt", + "Pig": "Malac", + "Unicorn": "Egyszarvú", + "Horse": "Ló", + "Lion": "Oroszlán", + "Cat": "Macska", + "Dog": "Kutya" +} From 685819049acba6b78a83c198e0ec13ab7d3d9f15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 May 2021 23:55:55 +0000 Subject: [PATCH 104/107] Bump lodash from 4.17.20 to 4.17.21 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 442a2aa4..5dce70c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -539,9 +539,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "log-symbols": { From d7f01de1e6234ac9ec9357d1fd7abe9e12d54019 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 11 May 2021 22:02:08 -0600 Subject: [PATCH 105/107] Update i18n --- data-definitions/sas-emoji.json | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/data-definitions/sas-emoji.json b/data-definitions/sas-emoji.json index 0b213d9d..f0eb702c 100644 --- a/data-definitions/sas-emoji.json +++ b/data-definitions/sas-emoji.json @@ -16,6 +16,7 @@ "fi": "Koira", "fr": "Chien", "hr": "pas", + "hu": "Kutya", "it": "Cane", "ja": "犬", "nb_NO": "Hund", @@ -49,6 +50,7 @@ "fi": "Kissa", "fr": "Chat", "hr": "mačka", + "hu": "Macska", "it": "Gatto", "ja": "猫", "nb_NO": "Katt", @@ -82,6 +84,7 @@ "fi": "Leijona", "fr": "Lion", "hr": "lav", + "hu": "Oroszlán", "it": "Leone", "ja": "ライオン", "nb_NO": "Løve", @@ -115,6 +118,7 @@ "fi": "Hevonen", "fr": "Cheval", "hr": "konj", + "hu": "Ló", "it": "Cavallo", "ja": "馬", "nb_NO": "Hest", @@ -148,6 +152,7 @@ "fi": "Yksisarvinen", "fr": "Licorne", "hr": "jednorog", + "hu": "Egyszarvú", "it": "Unicorno", "ja": "ユニコーン", "nb_NO": "Enhjørning", @@ -181,6 +186,7 @@ "fi": "Sika", "fr": "Cochon", "hr": "svinja", + "hu": "Malac", "it": "Maiale", "ja": "ブタ", "nb_NO": "Gris", @@ -214,6 +220,7 @@ "fi": "Norsu", "fr": "Éléphant", "hr": "slon", + "hu": "Elefánt", "it": "Elefante", "ja": "ゾウ", "nb_NO": "Elefant", @@ -247,6 +254,7 @@ "fi": "Kani", "fr": "Lapin", "hr": "zec", + "hu": "Nyúl", "it": "Coniglio", "ja": "うさぎ", "nb_NO": "Kanin", @@ -280,6 +288,7 @@ "fi": "Panda", "fr": "Panda", "hr": "panda", + "hu": "Panda", "it": "Panda", "ja": "パンダ", "nb_NO": "Panda", @@ -313,6 +322,7 @@ "fi": "Kukko", "fr": "Coq", "hr": "kokot", + "hu": "Kakas", "it": "Gallo", "ja": "ニワトリ", "nb_NO": "Hane", @@ -346,6 +356,7 @@ "fi": "Pingviini", "fr": "Manchot", "hr": "pingvin", + "hu": "Pingvin", "it": "Pinguino", "ja": "ペンギン", "nb_NO": "Pingvin", @@ -379,6 +390,7 @@ "fi": "Kilpikonna", "fr": "Tortue", "hr": "kornjača", + "hu": "Teknős", "it": "Tartaruga", "ja": "亀", "nb_NO": "Skilpadde", @@ -412,6 +424,7 @@ "fi": "Kala", "fr": "Poisson", "hr": "riba", + "hu": "Hal", "it": "Pesce", "ja": "魚", "nb_NO": "Fisk", @@ -445,6 +458,7 @@ "fi": "Tursas", "fr": "Poulpe", "hr": "hobotnica", + "hu": "Polip", "it": "Polpo", "ja": "たこ", "nb_NO": "Blekksprut", @@ -478,6 +492,7 @@ "fi": "Perhonen", "fr": "Papillon", "hr": "leptir", + "hu": "Pillangó", "it": "Farfalla", "ja": "ちょうちょ", "nb_NO": "Sommerfugl", @@ -511,6 +526,7 @@ "fi": "Kukka", "fr": "Fleur", "hr": "svijet", + "hu": "Virág", "it": "Fiore", "ja": "花", "nb_NO": "Blomst", @@ -544,6 +560,7 @@ "fi": "Puu", "fr": "Arbre", "hr": "drvo", + "hu": "Fa", "it": "Albero", "ja": "木", "nb_NO": "Tre", @@ -577,6 +594,7 @@ "fi": "Kaktus", "fr": "Cactus", "hr": "kaktus", + "hu": "Kaktusz", "it": "Cactus", "ja": "サボテン", "nb_NO": "Kaktus", @@ -610,6 +628,7 @@ "fi": "Sieni", "fr": "Champignon", "hr": "gljiva", + "hu": "Gomba", "it": "Fungo", "ja": "きのこ", "nb_NO": "Sopp", @@ -643,6 +662,7 @@ "fi": "Maapallo", "fr": "Globe", "hr": "Globus", + "hu": "Földgömb", "it": "Globo", "ja": "地球", "nb_NO": "Globus", @@ -676,6 +696,7 @@ "fi": "Kuu", "fr": "Lune", "hr": "mjesec", + "hu": "Hold", "it": "Luna", "ja": "月", "nb_NO": "Måne", @@ -709,6 +730,7 @@ "fi": "Pilvi", "fr": "Nuage", "hr": "oblak", + "hu": "Felhő", "it": "Nuvola", "ja": "雲", "nb_NO": "Sky", @@ -742,6 +764,7 @@ "fi": "Tuli", "fr": "Feu", "hr": "vatra", + "hu": "Tűz", "it": "Fuoco", "ja": "炎", "nb_NO": "Flamme", @@ -775,6 +798,7 @@ "fi": "Banaani", "fr": "Banane", "hr": "banana", + "hu": "Banán", "it": "Banana", "ja": "バナナ", "nb_NO": "Banan", @@ -808,6 +832,7 @@ "fi": "Omena", "fr": "Pomme", "hr": "jabuka", + "hu": "Alma", "it": "Mela", "ja": "リンゴ", "nb_NO": "Eple", @@ -841,6 +866,7 @@ "fi": "Mansikka", "fr": "Fraise", "hr": "jagoda", + "hu": "Eper", "it": "Fragola", "ja": "いちご", "nb_NO": "Jordbær", @@ -874,6 +900,7 @@ "fi": "Maissi", "fr": "Maïs", "hr": "kukuruza", + "hu": "Kukorica", "it": "Mais", "ja": "とうもろこし", "nb_NO": "Mais", @@ -907,6 +934,7 @@ "fi": "Pizza", "fr": "Pizza", "hr": "pizza", + "hu": "Pizza", "it": "Pizza", "ja": "ピザ", "nb_NO": "Pizza", @@ -940,6 +968,7 @@ "fi": "Kakku", "fr": "Gâteau", "hr": "torta", + "hu": "Süti", "it": "Torta", "ja": "ケーキ", "nb_NO": "Kake", @@ -973,6 +1002,7 @@ "fi": "Sydän", "fr": "Cœur", "hr": "srca", + "hu": "Szív", "it": "Cuore", "ja": "ハート", "nb_NO": "Hjerte", @@ -1006,6 +1036,7 @@ "fi": "Hymynaama", "fr": "Sourire", "hr": "smajlića", + "hu": "Mosoly", "it": "Faccina sorridente", "ja": "スマイル", "nb_NO": "Smilefjes", @@ -1039,6 +1070,7 @@ "fi": "Robotti", "fr": "Robot", "hr": "robot", + "hu": "Robot", "it": "Robot", "ja": "ロボと", "nb_NO": "Robot", @@ -1072,6 +1104,7 @@ "fi": "Hattu", "fr": "Chapeau", "hr": "kapa", + "hu": "Kalap", "it": "Cappello", "ja": "帽子", "nb_NO": "Hatt", @@ -1105,6 +1138,7 @@ "fi": "Silmälasit", "fr": "Lunettes", "hr": "naočale", + "hu": "Szemüveg", "it": "Occhiali", "ja": "めがね", "nb_NO": "Briller", @@ -1138,6 +1172,7 @@ "fi": "Kiintoavain", "fr": "Clé à molette", "hr": "ključ", + "hu": "Csavarkulcs", "it": "Chiave inglese", "ja": "スパナ", "nb_NO": "Fastnøkkel", @@ -1171,6 +1206,7 @@ "fi": "Joulupukki", "fr": "Père Noël", "hr": "deda Mraz", + "hu": "Télapó", "it": "Babbo Natale", "ja": "サンタ", "nb_NO": "Julenisse", @@ -1204,6 +1240,7 @@ "fi": "Peukalo ylös", "fr": "Pouce en l’air", "hr": "palac gore", + "hu": "Hüvelykujj fel", "it": "Pollice alzato", "ja": "いいね", "nb_NO": "Tommel Opp", @@ -1237,6 +1274,7 @@ "fi": "Sateenvarjo", "fr": "Parapluie", "hr": "kišobran", + "hu": "Esernyő", "it": "Ombrello", "ja": "傘", "nb_NO": "Paraply", @@ -1270,6 +1308,7 @@ "fi": "Tiimalasi", "fr": "Sablier", "hr": "pješčani sat", + "hu": "Homokóra", "it": "Clessidra", "ja": "砂時計", "nb_NO": "Timeglass", @@ -1303,6 +1342,7 @@ "fi": "Pöytäkello", "fr": "Réveil", "hr": "sat", + "hu": "Óra", "it": "Orologio", "ja": "時計", "nb_NO": "Klokke", @@ -1336,6 +1376,7 @@ "fi": "Lahja", "fr": "Cadeau", "hr": "poklon", + "hu": "Ajándék", "it": "Regalo", "ja": "ギフト", "nb_NO": "Gave", @@ -1369,6 +1410,7 @@ "fi": "Hehkulamppu", "fr": "Ampoule", "hr": "žarulja", + "hu": "Égő", "it": "Lampadina", "ja": "電球", "nb_NO": "Lyspære", @@ -1402,6 +1444,7 @@ "fi": "Kirja", "fr": "Livre", "hr": "knjiga", + "hu": "Könyv", "it": "Libro", "ja": "本", "nb_NO": "Bok", @@ -1435,6 +1478,7 @@ "fi": "Lyijykynä", "fr": "Crayon", "hr": "olovka", + "hu": "Ceruza", "it": "Matita", "ja": "鉛筆", "nb_NO": "Blyant", @@ -1468,6 +1512,7 @@ "fi": "Paperiliitin", "fr": "Trombone", "hr": "spajalica", + "hu": "Gémkapocs", "it": "Graffetta", "ja": "クリップ", "nb_NO": "BInders", @@ -1501,6 +1546,7 @@ "fi": "Sakset", "fr": "Ciseaux", "hr": "škare", + "hu": "Olló", "it": "Forbici", "ja": "はさみ", "nb_NO": "Saks", @@ -1534,6 +1580,7 @@ "fi": "Lukko", "fr": "Cadenas", "hr": "zaključati", + "hu": "Lakat", "it": "Lucchetto", "ja": "錠前", "nb_NO": "Lås", @@ -1567,6 +1614,7 @@ "fi": "Avain", "fr": "Clé", "hr": "ključ", + "hu": "Kulcs", "it": "Chiave", "ja": "鍵", "nb_NO": "Nøkkel", @@ -1600,6 +1648,7 @@ "fi": "Vasara", "fr": "Marteau", "hr": "čekić", + "hu": "Kalapács", "it": "Martello", "ja": "金槌", "nb_NO": "Hammer", @@ -1633,6 +1682,7 @@ "fi": "Puhelin", "fr": "Téléphone", "hr": "telefon", + "hu": "Telefon", "it": "Telefono", "ja": "電話機", "nb_NO": "Telefon", @@ -1666,6 +1716,7 @@ "fi": "Lippu", "fr": "Drapeau", "hr": "zastava", + "hu": "Zászló", "it": "Bandiera", "ja": "旗", "nb_NO": "Flagg", @@ -1699,6 +1750,7 @@ "fi": "Juna", "fr": "Train", "hr": "vlak", + "hu": "Vonat", "it": "Treno", "ja": "電車", "nb_NO": "Tog", @@ -1732,6 +1784,7 @@ "fi": "Polkupyörä", "fr": "Vélo", "hr": "bicikl", + "hu": "Kerékpár", "it": "Bicicletta", "ja": "自転車", "nb_NO": "Sykkel", @@ -1765,6 +1818,7 @@ "fi": "Lentokone", "fr": "Avion", "hr": "avion", + "hu": "Repülő", "it": "Aeroplano", "ja": "飛行機", "nb_NO": "Fly", @@ -1798,6 +1852,7 @@ "fi": "Raketti", "fr": "Fusée", "hr": "raketa", + "hu": "Rakáta", "it": "Razzo", "ja": "ロケット", "nb_NO": "Rakett", @@ -1831,6 +1886,7 @@ "fi": "Palkinto", "fr": "Trophée", "hr": "trofej", + "hu": "Trófea", "it": "Trofeo", "ja": "トロフィー", "nb_NO": "Pokal", @@ -1864,6 +1920,7 @@ "fi": "Pallo", "fr": "Ballon", "hr": "lopta", + "hu": "Labda", "it": "Palla", "ja": "ボール", "nb_NO": "Ball", @@ -1897,6 +1954,7 @@ "fi": "Kitara", "fr": "Guitare", "hr": "gitara", + "hu": "Gitár", "it": "Chitarra", "ja": "ギター", "nb_NO": "Gitar", @@ -1930,6 +1988,7 @@ "fi": "Trumpetti", "fr": "Trompette", "hr": "truba", + "hu": "Trombita", "it": "Trombetta", "ja": "トランペット", "nb_NO": "Trompet", @@ -1963,6 +2022,7 @@ "fi": "Soittokello", "fr": "Cloche", "hr": "zvono", + "hu": "Harang", "it": "Campana", "ja": "ベル", "nb_NO": "Bjelle", @@ -1996,6 +2056,7 @@ "fi": "Ankkuri", "fr": "Ancre", "hr": "sidro", + "hu": "Horgony", "it": "Ancora", "ja": "いかり", "nb_NO": "Anker", @@ -2029,6 +2090,7 @@ "fi": "Kuulokkeet", "fr": "Casque audio", "hr": "slušalice", + "hu": "Fejhallgató", "it": "Cuffie", "ja": "ヘッドホン", "nb_NO": "Hodetelefoner", @@ -2062,6 +2124,7 @@ "fi": "Kansio", "fr": "Dossier", "hr": "mapu", + "hu": "Mappa", "it": "Cartella", "ja": "フォルダ", "nb_NO": "Mappe", @@ -2095,6 +2158,7 @@ "fi": "Nuppineula", "fr": "Punaise", "hr": "pribadača", + "hu": "Rajszeg", "it": "Puntina", "ja": "ピン", "nb_NO": "Tegnestift", From eecdcf43ab681d8bf81ccd4f6ebdf6dbc6fa428c Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 14 May 2021 15:54:14 -0600 Subject: [PATCH 106/107] Change space's valid `order` range to 0x7E 0x7F is DEL, which is clearly not intended by the proposal text. --- 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 b6f60b38..1d431f84 100644 --- a/proposals/1772-groups-as-rooms.md +++ b/proposals/1772-groups-as-rooms.md @@ -126,7 +126,7 @@ relationship can be expressed in one of two ways: `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 + solely of ascii characters in the range `\x20` (space) to `\x7E` (`~`), or consist of more than 50 characters, are forbidden and the field should be ignored if received.) From fca6992cd98f97620039d6a3761fa060448c092d Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Thu, 13 May 2021 15:23:17 +0100 Subject: [PATCH 107/107] Clarify that implementations can use stable prefixes once an MSC has merged (#3179) Fixes #3146. This PR changes the Matrix Spec Proposals page to clarify that implementations **do not** need to wait until a spec release to use stable prefixes, but that they can do so after the corresponding MSC has been merged. The justification is that once an MSC has been merged, it's fairly guaranteed that it will land in the spec. Yet it will take time for the spec release process to run its course, and we shouldn't make implementations wait for that. The exception to this is if implementating a feature in a backwards-compatible way requires a new spec version to indicate to clients/servers that a feature has been added/changed. This situation is rare though, and most implementations won't fall into this category. --- content/proposals.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/content/proposals.md b/content/proposals.md index d724f308..4a236701 100644 --- a/content/proposals.md +++ b/content/proposals.md @@ -262,7 +262,7 @@ is as follows: will warrant another MSC. Any minor, non-fundamental changes are allowed but **must** be documented in the original proposal document. This ensures that someone reading a proposal in the future - doesn't assume old information wasn't merged into the spec. + doesn't assume old information that wasn't merged into the spec. - Similar to the proposal PR, please sign off the spec PR as per the guidelines on [CONTRIBUTING.rst](https://github.com/matrix-org/matrix-doc/blob/master/CONTRIBUTING.rst). @@ -391,13 +391,11 @@ release, implementations are required to use the following process to ensure that the official Matrix namespace is not cluttered with development or testing data. -Note - -Unreleased implementations (including proofs-of-concept demonstrating +**Note:** Unreleased implementations (including proofs-of-concept demonstrating that a particular MSC works) do not have to follow this process. 1. Have an idea for a feature. -2. Implement the feature using unstable endpoints, vendor prefixes, and +1. Implement the feature using unstable endpoints, vendor prefixes, and unstable feature flags as appropriate. - When using unstable endpoints, they MUST include a vendor prefix. For example: @@ -432,22 +430,25 @@ that a particular MSC works) do not have to follow this process. - If at any point after early release, the idea changes in a backwards-incompatible way, the feature flag should also change so that implementations can adapt as needed. -3. In parallel, or ahead of implementation, open an MSC and solicit +1. In parallel, or ahead of implementation, open an MSC and solicit review per above. -4. Before FCP can be called, the Spec Core Team will require evidence +1. Before FCP can be called, the Spec Core Team will require evidence of the MSC working as proposed. A typical example of this is an implementation of the MSC, though the implementation does not need to be shipped anywhere and can therefore avoid the forwards/backwards compatibility concerns mentioned here. -5. The FCP process is completed, and assuming nothing is flagged the +1. The FCP process is completed, and assuming nothing is flagged the MSC lands. -6. A spec PR is written to incorporate the changes into Matrix. -7. A spec release happens. -8. Implementations switch to using stable prefixes (e.g.: `/r0`) if the - server supports the specification version released. If the server - doesn't advertise the specification version, but does have the - feature flag, unstable prefixes should still be used. -9. A transition period of about 2 months starts immediately after the +1. Implementations can now switch to using stable prefixes + (for example, for an endpoint, moving from + `/unstable/org.matrix.mscxxxx/frobnicate` + to `/v1/frobnicate`), assuming that the change + is backwards compatible with older implementations. In the rare occasion + where backwards compatibility is not possible without a new spec release, + implementations should continue to use unstable prefixes. +1. A spec PR is written to incorporate the changes into Matrix. +1. A spec release happens. +1. A transition period of about 2 months starts immediately after the spec release, before implementations start to encourage other implementations to switch to stable endpoints. For example, a server implementation should start asking client implementations to support @@ -466,9 +467,9 @@ com.example/new/endpoint`. In summary: -- Implementations MUST NOT use stable endpoints before the MSC is in - the spec. This includes NOT using stable endpoints in the period - between completion of FCP and release of the spec. passed. +- Implementations MUST NOT use stable endpoints before the MSC has + completed FCP. Once that has occurred, implementations are allowed + to use stable endpoints, but are not required to. - Implementations are able to ship features that are exposed to users by default before an MSC has been merged to the spec, provided they follow the process above.