From 501d7ecfd53498a432a58af0bb95807b07fcbcf3 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Thu, 9 Jan 2020 19:55:44 +0100 Subject: [PATCH 01/72] add knock proposal --- proposals/2400-kock.md | 155 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 proposals/2400-kock.md diff --git a/proposals/2400-kock.md b/proposals/2400-kock.md new file mode 100644 index 00000000000..e36806d4b50 --- /dev/null +++ b/proposals/2400-kock.md @@ -0,0 +1,155 @@ +# MSC2400: Add "knock" feature +Many people are in invite-only rooms. Sometimes, someone wants to join such a room and can't, as +they aren't invited. This proposal adds a feature for this user to indicate that they want to join +said room. + +# Proposal +This proposal implements the reserved "knock" membership type for the `m.room.member` state event. +This state event indicates that a user knocks a room, that is asking for permission to join. It +contains an optional "reason" parameter to specify the reason you want to join. This membership can +be set from users who aren't currently in said room. An example for the membership would look as +follows: +```json +{ + "membership": "knock", + "displayname": "Alice", + "avatar_url": "mxc://example.org/avatar", + "reason": "I want to join this room as I really love foxes!" +} +``` + +After a knock is received in a room it is expected to be displayed in the timeline, similar to other +membership changes. Clients can optionally add a way for users of a room to review all current +knocks. After a knock in a room a member of the room can invite the knocker. + +To be able to implement this properly two new endpoints need to be added, one in the client-server +API and one in the server-server API. + +## Restrictions +There are restrictions to being able to set this membership. + +### Current membership +Only users without a current membership or with their current membership being "leave" can knock a +room. This means that a user that is banned or currently in the room can't knock on it. + +### Join Rules +The `join_rule` of `m.room.join_rules` must be set to "invite". This means that people can't knock +in public rooms. Additionaly the new join rule "private" is introduced. This is so that people can, +when creating a new room, prevent anyone from knocking. + +### Power levels +The default power level for "knock" is 0. If a user has a too low power level to knock they aren't +allowed to do this. As power levels can be set for users not currently in the room this can be used +as a way to limit who can knock and who can't. + +#### Example: +`@alice:example.org` CAN knock, but `@bob:example.org` can't: The (incomplete) content of +`m.room.power_levels` is as follows: +```json +{ + "users": { + "@alice:example.org": 1 + }, + "users_default": 0, + "knock": 1 +} +``` + +## New Join Rule + + +## Client-Server API +The new endpoint for the client-server API is `POST /_matrix/client/r0/rooms/{roomId}/knock`. +The path parameter (`roomId`) is the room you want to knock. It is required. The post body accepts +an optional parameter, `reason`, which is the reason you want to join the room. A request could look +as follows: + +``` +POST /_matrix/client/r0/rooms/%21d41d8cd%3Amatrix.org/knock HTTP/1.1 +Content-Type: application/json + +{ + "reason": "I want to join this room as I really love foxes!" +} +``` + +### Responses: +#### Status code 200: +The user knocked successfully. Empty reply: +```json +{} +``` + +#### Status code 403: +The user wasn't allowed to knock (e.g. they are banned). Error reply: +```json +{ + "errcode": "M_FORBIDDEN", + "error": "The user isn't allowed to knock in this room." +} +``` + +## Server-Server API +The new endpoint for the server-server API is `PUT /_matrix/federation/v2/knock/{roomId}/{eventId}`. (`/v2/` or `/v1`? Just looked at how invite currently works) +The path parameters are the room id you want to knock and the event id of the knock event. The post +body consists of an `event` parameter, which is the knock event. A request could look as follows: + +``` +PUT /_matrix/federation/v2/knock/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1 +Content-Type: application/json + +{ + "event": { + "sender": "@alice:example.org", + "origin": "example.org", + "origin_server_ts": 1234567890, + "type: "m.room.member", + "state_key": "@alice:example.org", + "content": { + "membership": "knock", + "reason": "I want to join this room as I really love foxes!" + } + } +} +``` + +### Responses +#### Status code 200: +The knock was performed successfully. The knock event is sent back with the "event" key. +```json +{ + "event": { + "sender": "@alice:example.org", + "origin": "example.org", + "origin_server_ts": 1234567890, + "type": "m.room.member", + "state_key": "@alice:example.org", + "content": { + "membership": "knock", + "reason": "I want to join this room as I really love foxes!" + } + } +} +``` + +#### Status code 403: +The user wasn't allowed to knock. Error reply: +```json +{ + "errcode": "M_FORBIDDEN", + "error": "The user isn't allowed to knock in this room." +} +``` + +# Potential issues +This new feature would allow users to spam rooms that they don't partake in. That is why this proposal +adds both the new join rule and the new power level, in order to allow room admins to mitigate such +potential spam. + +# Alternatives +As for the join rule "invite", instead the join rule "knock" could be introduced, meaning the room +is like "invite" only that people can also knock. The difference is for existing rooms: With this +proposal people can knock in existing "invite" rooms, with the alternative suggestion they can't. + +# Security considerations +None. This doesn't allow users access to a room in any way. From bee4e9e2691da4fbf1074f7e1f24bf594ee2e79e Mon Sep 17 00:00:00 2001 From: Sorunome Date: Thu, 9 Jan 2020 19:57:24 +0100 Subject: [PATCH 02/72] move to correct msc number --- proposals/{2400-kock.md => 2403-knock.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename proposals/{2400-kock.md => 2403-knock.md} (99%) diff --git a/proposals/2400-kock.md b/proposals/2403-knock.md similarity index 99% rename from proposals/2400-kock.md rename to proposals/2403-knock.md index e36806d4b50..ffaf37e4e02 100644 --- a/proposals/2400-kock.md +++ b/proposals/2403-knock.md @@ -1,4 +1,4 @@ -# MSC2400: Add "knock" feature +# MSC2403: Add "knock" feature Many people are in invite-only rooms. Sometimes, someone wants to join such a room and can't, as they aren't invited. This proposal adds a feature for this user to indicate that they want to join said room. From 1ef7c17b9376ed46713ea1fa9d8ba8b109c574d5 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Thu, 9 Jan 2020 20:00:25 +0100 Subject: [PATCH 03/72] remove stray heading --- proposals/2403-knock.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index ffaf37e4e02..10043ca0c6c 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -55,9 +55,6 @@ as a way to limit who can knock and who can't. } ``` -## New Join Rule - - ## Client-Server API The new endpoint for the client-server API is `POST /_matrix/client/r0/rooms/{roomId}/knock`. The path parameter (`roomId`) is the room you want to knock. It is required. The post body accepts From 13964988f4f82aadb3ad3e30c287ab7056281910 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Thu, 9 Jan 2020 20:08:19 +0100 Subject: [PATCH 04/72] remove question regarding federation api version, as it has to be v2 --- proposals/2403-knock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 10043ca0c6c..6e3396c6bb3 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -87,7 +87,7 @@ The user wasn't allowed to knock (e.g. they are banned). Error reply: ``` ## Server-Server API -The new endpoint for the server-server API is `PUT /_matrix/federation/v2/knock/{roomId}/{eventId}`. (`/v2/` or `/v1`? Just looked at how invite currently works) +The new endpoint for the server-server API is `PUT /_matrix/federation/v2/knock/{roomId}/{eventId}`. The path parameters are the room id you want to knock and the event id of the knock event. The post body consists of an `event` parameter, which is the knock event. A request could look as follows: From f0411a3cc5a1f0f041e51b06fe32a9c25f2e19bc Mon Sep 17 00:00:00 2001 From: Sorunome Date: Mon, 13 Jan 2020 12:52:22 +0100 Subject: [PATCH 05/72] make clear displayname and avatar_url are optional, add status codes --- proposals/2403-knock.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 6e3396c6bb3..b8a816bcbd5 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -6,7 +6,8 @@ said room. # Proposal This proposal implements the reserved "knock" membership type for the `m.room.member` state event. This state event indicates that a user knocks a room, that is asking for permission to join. It -contains an optional "reason" parameter to specify the reason you want to join. This membership can +contains an optional "reason" parameter to specify the reason you want to join. Like other +memtership types the parameters "displayname" and "avatar_url" are optional. This membership can be set from users who aren't currently in said room. An example for the membership would look as follows: ```json @@ -77,6 +78,14 @@ The user knocked successfully. Empty reply: {} ``` +#### Status code 400: +This request was invalid, e.g. bad JSON. Example reply: +```json +{ + "errcode": "M_UNKNOWN", + "error": "An unknown error occurred"} +``` + #### Status code 403: The user wasn't allowed to knock (e.g. they are banned). Error reply: ```json @@ -86,6 +95,16 @@ The user wasn't allowed to knock (e.g. they are banned). Error reply: } ``` +#### Status code 429: +This request was rate-limited. Example reply: +```json +{ + "errcode": "M_LIMIT_EXCEEDED", + "error": "Too many requests", + "retry_after_ms": 2000 +} +``` + ## Server-Server API The new endpoint for the server-server API is `PUT /_matrix/federation/v2/knock/{roomId}/{eventId}`. The path parameters are the room id you want to knock and the event id of the knock event. The post @@ -123,12 +142,22 @@ The knock was performed successfully. The knock event is sent back with the "eve "state_key": "@alice:example.org", "content": { "membership": "knock", + "displayname": "Alice", + "avatar_url": "mxc://example.org/avatar", "reason": "I want to join this room as I really love foxes!" } } } ``` +#### Status code 400: +This request was invalid, e.g. bad JSON. Example reply: +```json +{ + "errcode": "M_UNKNOWN", + "error": "An unknown error occurred"} +``` + #### Status code 403: The user wasn't allowed to knock. Error reply: ```json From 776436a5f09fa8e8fcbd9f4f8b39f83e1956a997 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Mon, 13 Jan 2020 12:54:06 +0100 Subject: [PATCH 06/72] forgot to update one json example --- proposals/2403-knock.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index b8a816bcbd5..cbe8491decc 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -123,6 +123,8 @@ Content-Type: application/json "state_key": "@alice:example.org", "content": { "membership": "knock", + "displayname": "Alice", + "avatar_url": "mxc://example.org/avatar", "reason": "I want to join this room as I really love foxes!" } } From 53435d400d5aec31d2b0cd78ec99c83d77a3e583 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Sun, 19 Jan 2020 13:30:46 +0100 Subject: [PATCH 07/72] update with new endpoints --- proposals/2403-knock.md | 158 ++++++++++++++++++++++++++++------------ 1 file changed, 113 insertions(+), 45 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index cbe8491decc..6ef0fde42e2 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -35,7 +35,7 @@ room. This means that a user that is banned or currently in the room can't knock ### Join Rules The `join_rule` of `m.room.join_rules` must be set to "invite". This means that people can't knock -in public rooms. Additionaly the new join rule "private" is introduced. This is so that people can, +in public rooms. Additionally the new join rule "private" is introduced. This is so that people can, when creating a new room, prevent anyone from knocking. ### Power levels @@ -57,7 +57,10 @@ as a way to limit who can knock and who can't. ``` ## Client-Server API -The new endpoint for the client-server API is `POST /_matrix/client/r0/rooms/{roomId}/knock`. +Two new endpoints are introduced in the client-server API (similarly to join): +`POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST /_matrix/client/r0/knock/{roomIdOrAlias}`. + +### `POST /_matrix/client/r0/rooms/{roomId}/knock` The path parameter (`roomId`) is the room you want to knock. It is required. The post body accepts an optional parameter, `reason`, which is the reason you want to join the room. A request could look as follows: @@ -71,14 +74,14 @@ Content-Type: application/json } ``` -### Responses: -#### Status code 200: +#### Responses: +##### Status code 200: The user knocked successfully. Empty reply: ```json {} ``` -#### Status code 400: +##### Status code 400: This request was invalid, e.g. bad JSON. Example reply: ```json { @@ -86,7 +89,7 @@ This request was invalid, e.g. bad JSON. Example reply: "error": "An unknown error occurred"} ``` -#### Status code 403: +##### Status code 403: The user wasn't allowed to knock (e.g. they are banned). Error reply: ```json { @@ -95,7 +98,7 @@ The user wasn't allowed to knock (e.g. they are banned). Error reply: } ``` -#### Status code 429: +##### Status code 429: This request was rate-limited. Example reply: ```json { @@ -105,70 +108,130 @@ This request was rate-limited. Example reply: } ``` -## Server-Server API -The new endpoint for the server-server API is `PUT /_matrix/federation/v2/knock/{roomId}/{eventId}`. -The path parameters are the room id you want to knock and the event id of the knock event. The post -body consists of an `event` parameter, which is the knock event. A request could look as follows: +### `POST /_matrix/client/r0/knock/{roomIdOrAlias}` +The path parameter (`roomIdOrAlias`) is either the room ID or the alias of the room you want to +knock. Additionally several `server_name` parameters can be specified via the query parameters. The +post body accepts an optional parameter, `reason`, which is the reason you want to join the room. A +request could look as follows: ``` -PUT /_matrix/federation/v2/knock/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1 +POST /_matrix/client/r0/knock/%23monkeys%3Amatrix.org?server_name=matrix.org&server_name=elsewhere.ca HTTP/1.1 Content-Type: application/json { - "event": { - "sender": "@alice:example.org", - "origin": "example.org", - "origin_server_ts": 1234567890, - "type: "m.room.member", - "state_key": "@alice:example.org", - "content": { - "membership": "knock", - "displayname": "Alice", - "avatar_url": "mxc://example.org/avatar", - "reason": "I want to join this room as I really love foxes!" - } - } + "reason": "I want to join this room as I really love foxes!" } ``` -### Responses -#### Status code 200: -The knock was performed successfully. The knock event is sent back with the "event" key. +#### Responses: +The possible responses are the same as for the `POST /_matrix/client/r0/rooms/{roomId}/knock` endpoint. + +## Server-Server API +Similarly to join and leave over federation, a ping-pong game with two new endpoints is introduced: +`make_knock` and `send_knock`. Both endpoints must be protected via server ACLs. + +### `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` + +Asks the receiving server to return information that the sending server will need to prepare a knock +event to get into the room. + +Request format: + +| Parameter | Type | Description | +|-----------|------|-------------| +| Path parameters: +| roomId | string | Required. The room ID that should receive the knock. +| userId | string | Required. The user ID the knock event will be for. +| Query Parameters: +| ver | [string] | The room versions the sending server has support for. Defaults to `[1]`. + +Response Format: + +| Parameter | Type | Description | +|-----------|------|-------------| +| room_version | string | The version of the room where the server is trying to knock. +| event | Event Template | An unsigned template event. May differ between room versions. + +#### Responses +##### Status code 200: +Returns a template to be used to knock rooms. May depend on room version. ```json { + "room_version": "2", "event": { - "sender": "@alice:example.org", - "origin": "example.org", - "origin_server_ts": 1234567890, "type": "m.room.member", - "state_key": "@alice:example.org", + "room_id": "!somewhere:example.org", "content": { - "membership": "knock", - "displayname": "Alice", - "avatar_url": "mxc://example.org/avatar", - "reason": "I want to join this room as I really love foxes!" - } + "membership": "knock" + }, + "state_key": "@someone:example.org", + "origin": "example.org", + "origin_server_ts": 1549041175876, + "sender": "@someone:example.org" } } ``` -#### Status code 400: +##### Status code 400: This request was invalid, e.g. bad JSON. Example reply: ```json { - "errcode": "M_UNKNOWN", - "error": "An unknown error occurred"} + "errcode": "M_INCOMPATIBLE_ROOM_VERSION", + "error": "Your homeserver does not support the features required to join this room", + "room_version": "3" +} ``` -#### Status code 403: -The user wasn't allowed to knock. Error reply: -```json +### `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` +Submits a signed knock event to the resident server for it to accept into the room's graph. Note +that event format may differ between room versions. + +Request format: + +| Parameter | Type | Description | +|-----------|------|-------------| +| Path parameters: +| roomId | string | Required. The room ID that should receive the knock. +| eventId | string | Required. The event ID for the knock event. + +The JSON body is expected to be the full event. + +Response Format: + +| Parameter | Type | Description | +|-----------|------|-------------| +| | [integer, Empty Object] | + +A request could look as follows: +``` +PUT /_matrix/federation/v1/send_knock/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1 +Content-Type: application/json + { - "errcode": "M_FORBIDDEN", - "error": "The user isn't allowed to knock in this room." + "sender": "@someone:example.org", + "origin": "matrix.org", + "origin_server_ts": 1234567890, + "type": "m.room.member", + "state_key": "@someone:example.org", + "content": { + "membership": "knock", + "displayname": "Alice", + "avatar_url": "mxc://example.org/avatar", + "reason": "I want to join this room as I really love foxes!" + } } ``` +#### Response: +##### Status code 200: +The event was successfully accepted into the graph by the receiving homeserver. +```json +[ + 200, + {} +] +``` + # Potential issues This new feature would allow users to spam rooms that they don't partake in. That is why this proposal adds both the new join rule and the new power level, in order to allow room admins to mitigate such @@ -179,5 +242,10 @@ As for the join rule "invite", instead the join rule "knock" could be introduced is like "invite" only that people can also knock. The difference is for existing rooms: With this proposal people can knock in existing "invite" rooms, with the alternative suggestion they can't. +The two endpoints for the client-server API seem redundant, this MSC followed how JOIN is working +currently: One "proper" endpoint (`/rooms/{roomId}/join`) and one to work properly over federation +(`/join/{roomIdOrAlias}`). They could both be merged into one, however, as that would also affect +the join endpoint it seems out-of-scope for this MSC. + # Security considerations None. This doesn't allow users access to a room in any way. From 5ae462d5585c93819c00bb3a3af3825a1b02d613 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Fri, 7 Feb 2020 19:50:22 +0100 Subject: [PATCH 08/72] address issues --- proposals/2403-knock.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 6ef0fde42e2..91a086942f6 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -7,7 +7,7 @@ said room. This proposal implements the reserved "knock" membership type for the `m.room.member` state event. This state event indicates that a user knocks a room, that is asking for permission to join. It contains an optional "reason" parameter to specify the reason you want to join. Like other -memtership types the parameters "displayname" and "avatar_url" are optional. This membership can +membership types the parameters "displayname" and "avatar_url" are optional. This membership can be set from users who aren't currently in said room. An example for the membership would look as follows: ```json @@ -20,8 +20,10 @@ follows: ``` After a knock is received in a room it is expected to be displayed in the timeline, similar to other -membership changes. Clients can optionally add a way for users of a room to review all current -knocks. After a knock in a room a member of the room can invite the knocker. +membership changes. It is recommended to not display the reason until the user interacts with the +client in some way (e.g. clicking on a "show reason" button), as else this would basically allow +outsiders to send messages into the room. Clients can optionally add a way for users of a room to +review all current knocks. After a knock in a room, a member of the room can invite the knocker. To be able to implement this properly two new endpoints need to be added, one in the client-server API and one in the server-server API. @@ -39,9 +41,9 @@ in public rooms. Additionally the new join rule "private" is introduced. This is when creating a new room, prevent anyone from knocking. ### Power levels -The default power level for "knock" is 0. If a user has a too low power level to knock they aren't -allowed to do this. As power levels can be set for users not currently in the room this can be used -as a way to limit who can knock and who can't. +The default power level for "knock" is the default power level for the room. If a user has a too low +power level to knock they aren't allowed to do this. As power levels can be set for users not currently +in the room this can be used as a way to limit who can knock and who can't. #### Example: `@alice:example.org` CAN knock, but `@bob:example.org` can't: The (incomplete) content of @@ -56,6 +58,13 @@ as a way to limit who can knock and who can't. } ``` +## Membership changes +Once someone has sent the `knock` membership into the room a change to the following memberships is +possible: + - `invite`: The knock was accepted by someone inside the room and they are inviting the knocker into + the room. + - `leave`: Similar to how kicks are handled, the knock was rejected. + ## Client-Server API Two new endpoints are introduced in the client-server API (similarly to join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST /_matrix/client/r0/knock/{roomIdOrAlias}`. @@ -86,7 +95,8 @@ This request was invalid, e.g. bad JSON. Example reply: ```json { "errcode": "M_UNKNOWN", - "error": "An unknown error occurred"} + "error": "An unknown error occurred" +} ``` ##### Status code 403: From d47cb1fec33d5d9c9a2f33608dd51d4b116455c7 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 17 Aug 2020 14:23:33 +0100 Subject: [PATCH 09/72] Small grammatical fixes --- proposals/2403-knock.md | 63 +++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 91a086942f6..bec2b4d33ca 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -1,15 +1,15 @@ # MSC2403: Add "knock" feature Many people are in invite-only rooms. Sometimes, someone wants to join such a room and can't, as -they aren't invited. This proposal adds a feature for this user to indicate that they want to join -said room. +they aren't invited. This proposal adds a feature for a user to indicate that they want to join +a room. # Proposal This proposal implements the reserved "knock" membership type for the `m.room.member` state event. -This state event indicates that a user knocks a room, that is asking for permission to join. It +This state event indicates that when a user knocks on a room, they are asking for permission to join. It contains an optional "reason" parameter to specify the reason you want to join. Like other -membership types the parameters "displayname" and "avatar_url" are optional. This membership can -be set from users who aren't currently in said room. An example for the membership would look as -follows: +membership types the parameters, "displayname" and "avatar_url" are optional. This membership can +be set from users who aren't currently in said room. An example for the membership would look like the +following: ```json { "membership": "knock", @@ -19,34 +19,34 @@ follows: } ``` -After a knock is received in a room it is expected to be displayed in the timeline, similar to other +After a knock is received in a room, it is expected to be displayed in the timeline, similar to other membership changes. It is recommended to not display the reason until the user interacts with the -client in some way (e.g. clicking on a "show reason" button), as else this would basically allow +client in some way (e.g. clicking on a "show reason" button), as else this would essentially allow outsiders to send messages into the room. Clients can optionally add a way for users of a room to review all current knocks. After a knock in a room, a member of the room can invite the knocker. -To be able to implement this properly two new endpoints need to be added, one in the client-server -API and one in the server-server API. +To be able to implement this properly, two new endpoints need to be added: one in the Client-Server +API and one in the Server-Server API. ## Restrictions There are restrictions to being able to set this membership. ### Current membership -Only users without a current membership or with their current membership being "leave" can knock a -room. This means that a user that is banned or currently in the room can't knock on it. +Only users without a current membership or with their current membership being "leave" can knock on a +room. This means that a user that is banned or currently in the room cannot knock on it. ### Join Rules -The `join_rule` of `m.room.join_rules` must be set to "invite". This means that people can't knock +The `join_rule` of `m.room.join_rules` must be set to "invite" for a knock to succeed. This means that people can't knock in public rooms. Additionally the new join rule "private" is introduced. This is so that people can, when creating a new room, prevent anyone from knocking. ### Power levels The default power level for "knock" is the default power level for the room. If a user has a too low -power level to knock they aren't allowed to do this. As power levels can be set for users not currently -in the room this can be used as a way to limit who can knock and who can't. +power level to knock, then they aren't allowed to do so. As power levels can be set for users not currently +in the room, this can be used as a way to limit who can and can't knock. #### Example: -`@alice:example.org` CAN knock, but `@bob:example.org` can't: The (incomplete) content of +`@alice:example.org` CAN knock, but `@bob:example.org` CANNOT: The (incomplete) content of `m.room.power_levels` is as follows: ```json { @@ -59,19 +59,20 @@ in the room this can be used as a way to limit who can knock and who can't. ``` ## Membership changes -Once someone has sent the `knock` membership into the room a change to the following memberships is -possible: - - `invite`: The knock was accepted by someone inside the room and they are inviting the knocker into - the room. - - `leave`: Similar to how kicks are handled, the knock was rejected. +Once someone has sent a `knock` membership into the room, the membership for +that user can be transitioned to the following possible states: + - `invite`: In this case, the knock was accepted by someone inside the room + and they are inviting the knocker into the room. + - `leave`: In this case, similar to how kicks are handled, the knock has + been rejected. ## Client-Server API -Two new endpoints are introduced in the client-server API (similarly to join): +Two new endpoints are introduced in the Client-Server API (similarly to join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST /_matrix/client/r0/knock/{roomIdOrAlias}`. ### `POST /_matrix/client/r0/rooms/{roomId}/knock` -The path parameter (`roomId`) is the room you want to knock. It is required. The post body accepts -an optional parameter, `reason`, which is the reason you want to join the room. A request could look +The path parameter (`roomId`) is the room on which you want to knock. It is required. The post body accepts +an optional string parameter, `reason`, which is the reason you want to join the room. A request could look as follows: ``` @@ -120,8 +121,8 @@ This request was rate-limited. Example reply: ### `POST /_matrix/client/r0/knock/{roomIdOrAlias}` The path parameter (`roomIdOrAlias`) is either the room ID or the alias of the room you want to -knock. Additionally several `server_name` parameters can be specified via the query parameters. The -post body accepts an optional parameter, `reason`, which is the reason you want to join the room. A +knock on. Additionally several `server_name` parameters can be specified via the query parameters. The +post body accepts an optional string parameter, `reason`, which is the reason you want to join the room. A request could look as follows: ``` @@ -143,7 +144,7 @@ Similarly to join and leave over federation, a ping-pong game with two new endpo ### `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` Asks the receiving server to return information that the sending server will need to prepare a knock -event to get into the room. +event. Request format: @@ -164,7 +165,7 @@ Response Format: #### Responses ##### Status code 200: -Returns a template to be used to knock rooms. May depend on room version. +Returns a template to be used to knock on rooms. May depend on room version. ```json { "room_version": "2", @@ -210,7 +211,7 @@ Response Format: | Parameter | Type | Description | |-----------|------|-------------| -| | [integer, Empty Object] | +| `` | [integer, Empty Object] | A request could look as follows: ``` @@ -250,9 +251,9 @@ potential spam. # Alternatives As for the join rule "invite", instead the join rule "knock" could be introduced, meaning the room is like "invite" only that people can also knock. The difference is for existing rooms: With this -proposal people can knock in existing "invite" rooms, with the alternative suggestion they can't. +proposal people can knock in existing "invite" rooms, with the alternative suggestion being that they can't. -The two endpoints for the client-server API seem redundant, this MSC followed how JOIN is working +The two endpoints for the Client-Server API seem redundant, this MSC followed how JOIN is working currently: One "proper" endpoint (`/rooms/{roomId}/join`) and one to work properly over federation (`/join/{roomIdOrAlias}`). They could both be merged into one, however, as that would also affect the join endpoint it seems out-of-scope for this MSC. From c92752d1b86e59c3656c1d7d1d10825ba562e58b Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 17 Aug 2020 14:25:34 +0100 Subject: [PATCH 10/72] Reflow text to <79 chars --- proposals/2403-knock.md | 119 ++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index bec2b4d33ca..39d985c92f3 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -1,15 +1,16 @@ # MSC2403: Add "knock" feature -Many people are in invite-only rooms. Sometimes, someone wants to join such a room and can't, as -they aren't invited. This proposal adds a feature for a user to indicate that they want to join -a room. +Many people are in invite-only rooms. Sometimes, someone wants to join such a +room and can't, as they aren't invited. This proposal adds a feature for a +user to indicate that they want to join a room. # Proposal -This proposal implements the reserved "knock" membership type for the `m.room.member` state event. -This state event indicates that when a user knocks on a room, they are asking for permission to join. It -contains an optional "reason" parameter to specify the reason you want to join. Like other -membership types the parameters, "displayname" and "avatar_url" are optional. This membership can -be set from users who aren't currently in said room. An example for the membership would look like the -following: +This proposal implements the reserved "knock" membership type for the +`m.room.member` state event. This state event indicates that when a user +knocks on a room, they are asking for permission to join. It contains an +optional "reason" parameter to specify the reason you want to join. Like +other membership types the parameters, "displayname" and "avatar_url" are +optional. This membership can be set from users who aren't currently in said +room. An example for the membership would look like the following: ```json { "membership": "knock", @@ -19,35 +20,40 @@ following: } ``` -After a knock is received in a room, it is expected to be displayed in the timeline, similar to other -membership changes. It is recommended to not display the reason until the user interacts with the -client in some way (e.g. clicking on a "show reason" button), as else this would essentially allow -outsiders to send messages into the room. Clients can optionally add a way for users of a room to -review all current knocks. After a knock in a room, a member of the room can invite the knocker. +After a knock is received in a room, it is expected to be displayed in the +timeline, similar to other membership changes. It is recommended to not +display the reason until the user interacts with the client in some way (e.g. +clicking on a "show reason" button), as else this would essentially allow +outsiders to send messages into the room. Clients can optionally add a way +for users of a room to review all current knocks. After a knock in a room, a +member of the room can invite the knocker. -To be able to implement this properly, two new endpoints need to be added: one in the Client-Server -API and one in the Server-Server API. +To be able to implement this properly, two new endpoints need to be added: +one in the Client-Server API and one in the Server-Server API. ## Restrictions There are restrictions to being able to set this membership. ### Current membership -Only users without a current membership or with their current membership being "leave" can knock on a -room. This means that a user that is banned or currently in the room cannot knock on it. +Only users without a current membership or with their current membership +being "leave" can knock on a room. This means that a user that is banned or +currently in the room cannot knock on it. ### Join Rules -The `join_rule` of `m.room.join_rules` must be set to "invite" for a knock to succeed. This means that people can't knock -in public rooms. Additionally the new join rule "private" is introduced. This is so that people can, -when creating a new room, prevent anyone from knocking. +The `join_rule` of `m.room.join_rules` must be set to "invite" for a knock to +succeed. This means that people can't knock in public rooms. Additionally the +new join rule "private" is introduced. This is so that people can, when +creating a new room, prevent anyone from knocking. ### Power levels -The default power level for "knock" is the default power level for the room. If a user has a too low -power level to knock, then they aren't allowed to do so. As power levels can be set for users not currently -in the room, this can be used as a way to limit who can and can't knock. +The default power level for "knock" is the default power level for the room. +If a user has a too low power level to knock, then they aren't allowed to do +so. As power levels can be set for users not currently in the room, this can +be used as a way to limit who can and can't knock. #### Example: -`@alice:example.org` CAN knock, but `@bob:example.org` CANNOT: The (incomplete) content of -`m.room.power_levels` is as follows: +`@alice:example.org` CAN knock, but `@bob:example.org` CANNOT: The +(incomplete) content of `m.room.power_levels` is as follows: ```json { "users": { @@ -67,13 +73,14 @@ that user can be transitioned to the following possible states: been rejected. ## Client-Server API -Two new endpoints are introduced in the Client-Server API (similarly to join): -`POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST /_matrix/client/r0/knock/{roomIdOrAlias}`. +Two new endpoints are introduced in the Client-Server API (similarly to +join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and +`POST /_matrix/client/r0/knock/{roomIdOrAlias}`. ### `POST /_matrix/client/r0/rooms/{roomId}/knock` -The path parameter (`roomId`) is the room on which you want to knock. It is required. The post body accepts -an optional string parameter, `reason`, which is the reason you want to join the room. A request could look -as follows: +The path parameter (`roomId`) is the room on which you want to knock. It is +required. The post body accepts an optional string parameter, `reason`, which +is the reason you want to join the room. A request could look as follows: ``` POST /_matrix/client/r0/rooms/%21d41d8cd%3Amatrix.org/knock HTTP/1.1 @@ -120,9 +127,10 @@ This request was rate-limited. Example reply: ``` ### `POST /_matrix/client/r0/knock/{roomIdOrAlias}` -The path parameter (`roomIdOrAlias`) is either the room ID or the alias of the room you want to -knock on. Additionally several `server_name` parameters can be specified via the query parameters. The -post body accepts an optional string parameter, `reason`, which is the reason you want to join the room. A +The path parameter (`roomIdOrAlias`) is either the room ID or the alias of +the room you want to knock on. Additionally several `server_name` parameters +can be specified via the query parameters. The post body accepts an optional +string parameter, `reason`, which is the reason you want to join the room. A request could look as follows: ``` @@ -135,15 +143,18 @@ Content-Type: application/json ``` #### Responses: -The possible responses are the same as for the `POST /_matrix/client/r0/rooms/{roomId}/knock` endpoint. +The possible responses are the same as for the `POST +/_matrix/client/r0/rooms/{roomId}/knock` endpoint. ## Server-Server API -Similarly to join and leave over federation, a ping-pong game with two new endpoints is introduced: -`make_knock` and `send_knock`. Both endpoints must be protected via server ACLs. +Similarly to join and leave over federation, a ping-pong game with two new +endpoints is introduced: `make_knock` and `send_knock`. Both endpoints must +be protected via server ACLs. ### `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` -Asks the receiving server to return information that the sending server will need to prepare a knock +Asks the receiving server to return information that the sending server will +need to prepare a knock event. Request format: @@ -194,8 +205,8 @@ This request was invalid, e.g. bad JSON. Example reply: ``` ### `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` -Submits a signed knock event to the resident server for it to accept into the room's graph. Note -that event format may differ between room versions. +Submits a signed knock event to the resident server for it to accept into the +room's graph. Note that event format may differ between room versions. Request format: @@ -235,7 +246,8 @@ Content-Type: application/json #### Response: ##### Status code 200: -The event was successfully accepted into the graph by the receiving homeserver. +The event was successfully accepted into the graph by the receiving +homeserver. ```json [ 200, @@ -244,19 +256,22 @@ The event was successfully accepted into the graph by the receiving homeserver. ``` # Potential issues -This new feature would allow users to spam rooms that they don't partake in. That is why this proposal -adds both the new join rule and the new power level, in order to allow room admins to mitigate such -potential spam. +This new feature would allow users to spam rooms that they don't partake in. +That is why this proposal adds both the new join rule and the new power +level, in order to allow room admins to mitigate such potential spam. # Alternatives -As for the join rule "invite", instead the join rule "knock" could be introduced, meaning the room -is like "invite" only that people can also knock. The difference is for existing rooms: With this -proposal people can knock in existing "invite" rooms, with the alternative suggestion being that they can't. - -The two endpoints for the Client-Server API seem redundant, this MSC followed how JOIN is working -currently: One "proper" endpoint (`/rooms/{roomId}/join`) and one to work properly over federation -(`/join/{roomIdOrAlias}`). They could both be merged into one, however, as that would also affect -the join endpoint it seems out-of-scope for this MSC. +As for the join rule "invite", instead the join rule "knock" could be +introduced, meaning the room is like "invite" only that people can also +knock. The difference is for existing rooms: With this proposal people can +knock in existing "invite" rooms, with the alternative suggestion being that +they can't. + +The two endpoints for the Client-Server API seem redundant, this MSC followed +how JOIN is working currently: One "proper" endpoint (`/rooms/{roomId}/join`) +and one to work properly over federation (`/join/{roomIdOrAlias}`). They +could both be merged into one, however, as that would also affect the join +endpoint it seems out-of-scope for this MSC. # Security considerations None. This doesn't allow users access to a room in any way. From 38d67083eb52a4bdeee520b6ad01c2f9b6a20fe9 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 17 Aug 2020 14:27:59 +0100 Subject: [PATCH 11/72] Note that spam is a preventable, but real possibility as a result --- proposals/2403-knock.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 39d985c92f3..5221ca1ce1f 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -274,4 +274,5 @@ could both be merged into one, however, as that would also affect the join endpoint it seems out-of-scope for this MSC. # Security considerations -None. This doesn't allow users access to a room in any way. +This doesn't allow users access to a room in any way. However, care should be +taken to ensure that no spam vectors are enabled by this change. From de038f560134b15942165121000d72115286af3a Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 17 Aug 2020 14:30:28 +0100 Subject: [PATCH 12/72] Fix the response format of send_knock This aligns with the current v2 federation endpoints. However, we're still using v1 as a prefix here as it is still the first version of this endpoint. --- proposals/2403-knock.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 5221ca1ce1f..4dc7038afaa 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -249,10 +249,7 @@ Content-Type: application/json The event was successfully accepted into the graph by the receiving homeserver. ```json -[ - 200, - {} -] +{} ``` # Potential issues From 39c21689ce1cad091b4e3931593fb7a7cc45e240 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 21 Aug 2020 15:30:30 +0100 Subject: [PATCH 13/72] small grammar --- proposals/2403-knock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 4dc7038afaa..c01ac84f5c7 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -8,7 +8,7 @@ This proposal implements the reserved "knock" membership type for the `m.room.member` state event. This state event indicates that when a user knocks on a room, they are asking for permission to join. It contains an optional "reason" parameter to specify the reason you want to join. Like -other membership types the parameters, "displayname" and "avatar_url" are +other membership types, the parameters "displayname" and "avatar_url" are optional. This membership can be set from users who aren't currently in said room. An example for the membership would look like the following: ```json From 74a341ab8d52b92d19d2dbacdc221a145fa1b3d1 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 21 Aug 2020 15:36:38 +0100 Subject: [PATCH 14/72] Mention that knock -> ban is possible --- proposals/2403-knock.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index c01ac84f5c7..5d4cc68e3c0 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -71,6 +71,8 @@ that user can be transitioned to the following possible states: and they are inviting the knocker into the room. - `leave`: In this case, similar to how kicks are handled, the knock has been rejected. + - `ban`: In this case, the knock was rejected and the user has been prevented + from sending further knocks. ## Client-Server API Two new endpoints are introduced in the Client-Server API (similarly to From 716db4e656561864528974d9e736ae0eac3ec615 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 21 Aug 2020 15:42:12 +0100 Subject: [PATCH 15/72] Spell out some possible abuse vectors and how to mitigate them --- proposals/2403-knock.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 5d4cc68e3c0..6bb1aee2589 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -273,5 +273,12 @@ could both be merged into one, however, as that would also affect the join endpoint it seems out-of-scope for this MSC. # Security considerations -This doesn't allow users access to a room in any way. However, care should be -taken to ensure that no spam vectors are enabled by this change. +Clients must take care when implementing this feature in order to prevent +simple abuse vectors that can be accomplished by individual users. For +instance, When a knock occurs, client are advised to hide the reason by +default, prompting the user to reveal it only if they choose to. + +It is still theoretically possible for a server admin to create many users +with different user IDs or display names, all spelling out an abusive +message, and then having each of them knock in order. In this case, room +admins should employ typical abuse mitigation tools, such as Server ACLs. \ No newline at end of file From d6d5858b670ab5cdb7604804d01a92ec5a1180cb Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 21 Aug 2020 15:43:33 +0100 Subject: [PATCH 16/72] knock->knock and rescinding of knocks are not allowed --- proposals/2403-knock.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 6bb1aee2589..adf05089eb3 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -36,8 +36,8 @@ There are restrictions to being able to set this membership. ### Current membership Only users without a current membership or with their current membership -being "leave" can knock on a room. This means that a user that is banned or -currently in the room cannot knock on it. +being "leave" can knock on a room. This means that a user that is banned, has +already knocked or is currently in the room cannot knock on it. ### Join Rules The `join_rule` of `m.room.join_rules` must be set to "invite" for a knock to @@ -74,6 +74,14 @@ that user can be transitioned to the following possible states: - `ban`: In this case, the knock was rejected and the user has been prevented from sending further knocks. +Users are not allowed to change their membership once set to `knock`, in +order to prevent users from being able to knock multiple times and spam a +room. + +XXX: So if you knock on a room that's then abandoned that's in your `/sync` +forever? Clients should have a way to tell their server to hide and show +knocks. + ## Client-Server API Two new endpoints are introduced in the Client-Server API (similarly to join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and From 105108428f65f2ccd1ed0acbbe2d85eaf180f1cd Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 21 Aug 2020 18:50:40 +0100 Subject: [PATCH 17/72] Switch from Power Levels -> Join Rules --- proposals/2403-knock.md | 41 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index adf05089eb3..f840d4af7df 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -40,29 +40,11 @@ being "leave" can knock on a room. This means that a user that is banned, has already knocked or is currently in the room cannot knock on it. ### Join Rules -The `join_rule` of `m.room.join_rules` must be set to "invite" for a knock to -succeed. This means that people can't knock in public rooms. Additionally the -new join rule "private" is introduced. This is so that people can, when -creating a new room, prevent anyone from knocking. - -### Power levels -The default power level for "knock" is the default power level for the room. -If a user has a too low power level to knock, then they aren't allowed to do -so. As power levels can be set for users not currently in the room, this can -be used as a way to limit who can and can't knock. - -#### Example: -`@alice:example.org` CAN knock, but `@bob:example.org` CANNOT: The -(incomplete) content of `m.room.power_levels` is as follows: -```json -{ - "users": { - "@alice:example.org": 1 - }, - "users_default": 0, - "knock": 1 -} -``` +This proposal introduces a new possible value for `join_rule` in +`m.room.join_rules`: "knock". The value of `join_rule` in `m.room.join_rules` +must be set to "knock" for a knock to succeed. This means that existing rooms +will need to opt into allowing knocks in their room. rooms. Other than +allowing knocks, "knock" is no different from the "invite" join rule. ## Membership changes Once someone has sent a `knock` membership into the room, the membership for @@ -164,8 +146,7 @@ be protected via server ACLs. ### `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` Asks the receiving server to return information that the sending server will -need to prepare a knock -event. +need to prepare a knock event. Request format: @@ -264,16 +245,10 @@ homeserver. # Potential issues This new feature would allow users to spam rooms that they don't partake in. -That is why this proposal adds both the new join rule and the new power -level, in order to allow room admins to mitigate such potential spam. +That is why this proposal adds a new join rule, in order to allow room admins +to opt in to this behaviour. # Alternatives -As for the join rule "invite", instead the join rule "knock" could be -introduced, meaning the room is like "invite" only that people can also -knock. The difference is for existing rooms: With this proposal people can -knock in existing "invite" rooms, with the alternative suggestion being that -they can't. - The two endpoints for the Client-Server API seem redundant, this MSC followed how JOIN is working currently: One "proper" endpoint (`/rooms/{roomId}/join`) and one to work properly over federation (`/join/{roomIdOrAlias}`). They From bc90f1ce47183c7614a17145ee9b8de811ecc65d Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Tue, 25 Aug 2020 15:56:10 +0100 Subject: [PATCH 18/72] Fix typo --- proposals/2403-knock.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index f840d4af7df..4e122ecb763 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -43,8 +43,8 @@ already knocked or is currently in the room cannot knock on it. This proposal introduces a new possible value for `join_rule` in `m.room.join_rules`: "knock". The value of `join_rule` in `m.room.join_rules` must be set to "knock" for a knock to succeed. This means that existing rooms -will need to opt into allowing knocks in their room. rooms. Other than -allowing knocks, "knock" is no different from the "invite" join rule. +will need to opt into allowing knocks in their rooms. Other than allowing +knocks, "knock" is no different from the "invite" join rule. ## Membership changes Once someone has sent a `knock` membership into the room, the membership for From aad6ff4a05c35599a1425bb341439264666dee01 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Tue, 25 Aug 2020 16:02:08 +0100 Subject: [PATCH 19/72] Remove remaining traces of [200, {}] response format --- proposals/2403-knock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 4e122ecb763..e01ece20b71 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -213,7 +213,7 @@ Response Format: | Parameter | Type | Description | |-----------|------|-------------| -| `` | [integer, Empty Object] | +| `` | Empty Object | A request could look as follows: ``` From f3fc5399fcc17e8de3b9fdbf9be6382515110735 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 27 Aug 2020 14:59:11 +0100 Subject: [PATCH 20/72] Move client recommendations into its own section Hopefully leading to less duplication in recommendations as well --- proposals/2403-knock.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index e01ece20b71..8f638a96a11 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -20,13 +20,7 @@ room. An example for the membership would look like the following: } ``` -After a knock is received in a room, it is expected to be displayed in the -timeline, similar to other membership changes. It is recommended to not -display the reason until the user interacts with the client in some way (e.g. -clicking on a "show reason" button), as else this would essentially allow -outsiders to send messages into the room. Clients can optionally add a way -for users of a room to review all current knocks. After a knock in a room, a -member of the room can invite the knocker. +After a knock in a room, a member of the room can invite the knocker. To be able to implement this properly, two new endpoints need to be added: one in the Client-Server API and one in the Server-Server API. @@ -255,11 +249,20 @@ and one to work properly over federation (`/join/{roomIdOrAlias}`). They could both be merged into one, however, as that would also affect the join endpoint it seems out-of-scope for this MSC. +# Client UX recommendations +After a knock is received in a room, it is expected to be displayed in the +timeline, similar to other membership changes. Clients can optionally add a way +for users of a room to review all current knocks. + # Security considerations Clients must take care when implementing this feature in order to prevent simple abuse vectors that can be accomplished by individual users. For -instance, When a knock occurs, client are advised to hide the reason by -default, prompting the user to reveal it only if they choose to. +instance, when a knock occurs, clients are advised to hide the reason until +the user interacts with the client in some way (e.g. clicking on a "show +reason" button). The user should reveal the reason only if they choose to. + +It is recommended to not display the reason by default as else this would +essentially allow outsiders to send messages into the room. It is still theoretically possible for a server admin to create many users with different user IDs or display names, all spelling out an abusive From 651e73b2db2fb779c0b37ef6e3c795592432f19d Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 27 Aug 2020 15:00:17 +0100 Subject: [PATCH 21/72] It's possible to fight against spam --- proposals/2403-knock.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 8f638a96a11..cd827eb7fdf 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -238,9 +238,9 @@ homeserver. ``` # Potential issues -This new feature would allow users to spam rooms that they don't partake in. -That is why this proposal adds a new join rule, in order to allow room admins -to opt in to this behaviour. +This new feature would allow users to send events into rooms that they don't +partake in. That is why this proposal adds a new join rule, in order to allow +room admins to opt in to this behaviour. # Alternatives The two endpoints for the Client-Server API seem redundant, this MSC followed From 965c47ba0812451e101d48d9b6ddb59328233086 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 27 Aug 2020 15:03:18 +0100 Subject: [PATCH 22/72] Remove unnecessary sentence --- proposals/2403-knock.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index cd827eb7fdf..31530b5a62c 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -22,9 +22,6 @@ room. An example for the membership would look like the following: After a knock in a room, a member of the room can invite the knocker. -To be able to implement this properly, two new endpoints need to be added: -one in the Client-Server API and one in the Server-Server API. - ## Restrictions There are restrictions to being able to set this membership. From ae8ec6603c2edaa5047e68352e4a1f97549bb16f Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 27 Aug 2020 18:35:03 +0100 Subject: [PATCH 23/72] Spec how a client is notified of pending knock progress --- proposals/2403-knock.md | 115 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 31530b5a62c..926561a1092 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -57,8 +57,13 @@ knocks. ## Client-Server API Two new endpoints are introduced in the Client-Server API (similarly to -join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and -`POST /_matrix/client/r0/knock/{roomIdOrAlias}`. +join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST +/_matrix/client/r0/knock/{roomIdOrAlias}`. These allow the client to state +their intent to knock on a room. + +Additionally, additions to the `GET /_matrix/client/r0/sync` endpoint are +introduced. These allow a client to receive information about the status of +their knock attempt. ### `POST /_matrix/client/r0/rooms/{roomId}/knock` The path parameter (`roomId`) is the room on which you want to knock. It is @@ -117,7 +122,7 @@ string parameter, `reason`, which is the reason you want to join the room. A request could look as follows: ``` -POST /_matrix/client/r0/knock/%23monkeys%3Amatrix.org?server_name=matrix.org&server_name=elsewhere.ca HTTP/1.1 +POST /_matrix/client/r0/knock/%23foxes%3Amatrix.org?server_name=matrix.org&server_name=elsewhere.ca HTTP/1.1 Content-Type: application/json { @@ -129,6 +134,110 @@ Content-Type: application/json The possible responses are the same as for the `POST /_matrix/client/r0/rooms/{roomId}/knock` endpoint. +### Extensions to `GET /_matrix/client/r0/sync` + +In [the response to +`/sync`](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-sync) +is a `rooms` field. This is a dictionary which currently contains keys +`join`, `invite` and `leave`, which each provide information to the client on +various membership states regarding the user. + +It is proposed to add a fourth possible key to `rooms`, called `knock`. Its +value is a mapping from room ID to room information. The room information is +a mapping from a key `knock_state` to another mapping with key `events` being +a list of `StrippedStateEvent`. `StrippedStateEvent`s are defined as state +events that only contain the `sender`, `type`, `state_key` and `content` +keys. This behaviour matches `invite_events` which already exists to provide +information to the client their current room invites. + +These stripped state events contain information about the room, most notably +the room's name and avatar. A client will need this information to show a +nice representation of pending knocked rooms. Only `m.room.name`, +`m.room.avatar`, `m.room.join_rules` and `m.room.membership` state events +should be included here, rather than all room state event types. +Additionally, only `m.room.membership` events of the knocking user should be +included. + +This prevents unneeded state from the room leaking out, and also speeds +things up (think not sending over hundreds of membership events from big +rooms). + +XXX: Is `m.room.canonical_alias` worth allowing here for any reason? + +The following is an example of knock state coming down `/sync`. + +Request: +``` +GET /_matrix/client/r0/sync HTTP/1.1 +Content-Type: application/json +``` + +Response: +```json +{ + ... + "rooms": { + "knock": { + "!abcdefghijklmo:example.com": { + "knock_state": { + events: [ + { + "content": { + "join_rule": "knock" + }, + "sender": "@room_admin:example.com", + "state_key": "", + "type": "m.room.join_rules" + }, + { + "content": { + "name": "Some cool room" + }, + "sender": "@room_admin:example.com", + "state_key": "", + "type": "m.room.name" + }, + { + "content": { + "url": "mxc://example.com/xyz54321" + }, + "sender": "@room_admin:example.com", + "state_key": "", + "type": "m.room.avatar" + }, + { + "content": { + "avatar_url": "mxc://example.org/abc1234", + "displayname": "Knocking User", + "membership": "knock" + }, + "origin_server_ts": 1598548763903, + "sender": "@knocking_user:example.org", + "state_key": "@knocking_user:example.org", + "type": "m.room.member", + "unsigned": { + "age": 5 + }, + "event_id": "$12345" + } + ] + } + } + } + }, + ... +} +``` + +Once a knock has been made, a user in the room can decide whether they want +to accept or deny the knock. If they accept, they will invite the knocker, +which the knocker will be notified about through existing flows. + +If they deny, then a leave membership event is sent in the room, and the +knocking user will be notified through existing flows (matching the behaviour +of when an invite is recinded). + + ## Server-Server API Similarly to join and leave over federation, a ping-pong game with two new endpoints is introduced: `make_knock` and `send_knock`. Both endpoints must From 5bfd65c59fa682e5bdf72d6ea1d3fef0cdac0f85 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 28 Aug 2020 13:56:09 +0100 Subject: [PATCH 24/72] Federation knock_room_state and minor cleanup --- proposals/2403-knock.md | 67 ++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 926561a1092..f0443f5aef4 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -61,7 +61,7 @@ join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST /_matrix/client/r0/knock/{roomIdOrAlias}`. These allow the client to state their intent to knock on a room. -Additionally, additions to the `GET /_matrix/client/r0/sync` endpoint are +Additionally, extensions to the `GET /_matrix/client/r0/sync` endpoint are introduced. These allow a client to receive information about the status of their knock attempt. @@ -70,7 +70,7 @@ The path parameter (`roomId`) is the room on which you want to knock. It is required. The post body accepts an optional string parameter, `reason`, which is the reason you want to join the room. A request could look as follows: -``` +```json POST /_matrix/client/r0/rooms/%21d41d8cd%3Amatrix.org/knock HTTP/1.1 Content-Type: application/json @@ -121,7 +121,7 @@ can be specified via the query parameters. The post body accepts an optional string parameter, `reason`, which is the reason you want to join the room. A request could look as follows: -``` +```json POST /_matrix/client/r0/knock/%23foxes%3Amatrix.org?server_name=matrix.org&server_name=elsewhere.ca HTTP/1.1 Content-Type: application/json @@ -180,7 +180,7 @@ Response: "knock": { "!abcdefghijklmo:example.com": { "knock_state": { - events: [ + "events": [ { "content": { "join_rule": "knock" @@ -211,14 +211,9 @@ Response: "displayname": "Knocking User", "membership": "knock" }, - "origin_server_ts": 1598548763903, "sender": "@knocking_user:example.org", "state_key": "@knocking_user:example.org", "type": "m.room.member", - "unsigned": { - "age": 5 - }, - "event_id": "$12345" } ] } @@ -313,10 +308,10 @@ Response Format: | Parameter | Type | Description | |-----------|------|-------------| -| `` | Empty Object | +| `knock_room_state` | [StrippedStateEvent] | Required. State events providing public room metadata A request could look as follows: -``` +```json PUT /_matrix/federation/v1/send_knock/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1 Content-Type: application/json @@ -338,9 +333,53 @@ Content-Type: application/json #### Response: ##### Status code 200: The event was successfully accepted into the graph by the receiving -homeserver. +homeserver. The response contains `StrippedStateEvent`s with room metadata +(room name, avatar ...) that the knocking homeserver can pass to the client. +The event types that can be sent here should match those of the `/sync` +extensions mentioned above. + +This is loosely based off of the +[federated invite](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid) +request content. ```json -{} +{ + "knock_room_state": [ + { + "content": { + "join_rule": "knock" + }, + "sender": "@room_admin:example.com", + "state_key": "", + "type": "m.room.join_rules" + }, + { + "content": { + "name": "Some cool room" + }, + "sender": "@room_admin:example.com", + "state_key": "", + "type": "m.room.name" + }, + { + "content": { + "url": "mxc://example.com/xyz54321" + }, + "sender": "@room_admin:example.com", + "state_key": "", + "type": "m.room.avatar" + }, + { + "content": { + "avatar_url": "mxc://example.org/abc1234", + "displayname": "Knocking User", + "membership": "knock" + }, + "sender": "@knocking_user:example.org", + "state_key": "@knocking_user:example.org", + "type": "m.room.member", + } + ] +} ``` # Potential issues @@ -373,4 +412,4 @@ essentially allow outsiders to send messages into the room. It is still theoretically possible for a server admin to create many users with different user IDs or display names, all spelling out an abusive message, and then having each of them knock in order. In this case, room -admins should employ typical abuse mitigation tools, such as Server ACLs. \ No newline at end of file +admins should employ typical abuse mitigation tools, such as Server ACLs. From e93a19f62d95ac0b64e3b6d2944d1fc04304032d Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 2 Sep 2020 12:07:42 +0100 Subject: [PATCH 25/72] Indicate that this proposal requires a new room version --- proposals/2403-knock.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 926561a1092..576e480823b 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -37,6 +37,9 @@ must be set to "knock" for a knock to succeed. This means that existing rooms will need to opt into allowing knocks in their rooms. Other than allowing knocks, "knock" is no different from the "invite" join rule. +As we're updating the join rules, and thus the auth rules, this proposal will +need to be introduced as part of a new room version. + ## Membership changes Once someone has sent a `knock` membership into the room, the membership for that user can be transitioned to the following possible states: @@ -237,6 +240,11 @@ If they deny, then a leave membership event is sent in the room, and the knocking user will be notified through existing flows (matching the behaviour of when an invite is recinded). +TODO: Federation passing certain needed state events from the server that has +the room to the server that's knocking. Can we filter the events sent over so +that we can avoid the security issue with invites that we found earlier? (And +then backport this filter to invites? :) + ## Server-Server API Similarly to join and leave over federation, a ping-pong game with two new From 58cb299dde3a06b49123dc2c4976effedea37d76 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:47:20 +0100 Subject: [PATCH 26/72] Update proposals/2403-knock.md Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/2403-knock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 02fedc89719..a3b5ec70597 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -346,7 +346,7 @@ homeserver. The response contains `StrippedStateEvent`s with room metadata The event types that can be sent here should match those of the `/sync` extensions mentioned above. -This is loosely based off of the +This is loosely based on the [federated invite](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid) request content. ```json From 703fa070289281f5464fe70f455b43b6744fdd8a Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 3 Sep 2020 16:07:16 +0100 Subject: [PATCH 27/72] Remove extraneous text --- proposals/2403-knock.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 02fedc89719..ba95e3d883f 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -235,11 +235,6 @@ If they deny, then a leave membership event is sent in the room, and the knocking user will be notified through existing flows (matching the behaviour of when an invite is recinded). -TODO: Federation passing certain needed state events from the server that has -the room to the server that's knocking. Can we filter the events sent over so -that we can avoid the security issue with invites that we found earlier? (And -then backport this filter to invites? :) - ## Server-Server API Similarly to join and leave over federation, a ping-pong game with two new From 630f7c458cf590abc7575638c412cc7ef5f4617c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 4 Sep 2020 14:26:15 +0100 Subject: [PATCH 28/72] Allow users to knock over and over, removing CS complexity --- proposals/2403-knock.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 7b100670d07..5317a1eab71 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -46,18 +46,10 @@ that user can be transitioned to the following possible states: - `invite`: In this case, the knock was accepted by someone inside the room and they are inviting the knocker into the room. - `leave`: In this case, similar to how kicks are handled, the knock has - been rejected. + been rejected. Alternatively, the knocking user has rescinded their knock. - `ban`: In this case, the knock was rejected and the user has been prevented from sending further knocks. -Users are not allowed to change their membership once set to `knock`, in -order to prevent users from being able to knock multiple times and spam a -room. - -XXX: So if you knock on a room that's then abandoned that's in your `/sync` -forever? Clients should have a way to tell their server to hide and show -knocks. - ## Client-Server API Two new endpoints are introduced in the Client-Server API (similarly to join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST @@ -84,7 +76,7 @@ Content-Type: application/json #### Responses: ##### Status code 200: -The user knocked successfully. Empty reply: +The user knocked successfully. Example reply: ```json {} ``` @@ -235,7 +227,6 @@ If they deny, then a leave membership event is sent in the room, and the knocking user will be notified through existing flows (matching the behaviour of when an invite is recinded). - ## Server-Server API Similarly to join and leave over federation, a ping-pong game with two new endpoints is introduced: `make_knock` and `send_knock`. Both endpoints must @@ -414,5 +405,14 @@ essentially allow outsiders to send messages into the room. It is still theoretically possible for a server admin to create many users with different user IDs or display names, all spelling out an abusive -message, and then having each of them knock in order. In this case, room -admins should employ typical abuse mitigation tools, such as Server ACLs. +message, and then having each of them knock in order. + +Another abuse vector is allowed by the ability for users to rescind knocks. +This is to help users in case they knocked on a room accidentally, or simply +no longer want to join a room they've knocked on. While this is a useful +feature, it also allows users to spam a room by knocking and rescinding their +knocks over and over. + +In both cases, room admins should employ typical abuse mitigation tools, such +as user bans and server ACLs. Clients are encouraged to ease employing these +tools easy even if the offensive user or server is present not in the room. From fd9d57b8c47980ac7931c029bffac87f9181843c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 4 Sep 2020 14:38:29 +0100 Subject: [PATCH 29/72] Match state events sent to a remote server when inviting a user --- proposals/2403-knock.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 5317a1eab71..424270187ce 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -142,23 +142,19 @@ value is a mapping from room ID to room information. The room information is a mapping from a key `knock_state` to another mapping with key `events` being a list of `StrippedStateEvent`. `StrippedStateEvent`s are defined as state events that only contain the `sender`, `type`, `state_key` and `content` -keys. This behaviour matches `invite_events` which already exists to provide -information to the client their current room invites. +keys. These stripped state events contain information about the room, most notably the room's name and avatar. A client will need this information to show a -nice representation of pending knocked rooms. Only `m.room.name`, -`m.room.avatar`, `m.room.join_rules` and `m.room.membership` state events -should be included here, rather than all room state event types. -Additionally, only `m.room.membership` events of the knocking user should be -included. +nice representation of pending knocked rooms. The recommended events to +include are the join rules, canonical alias, avatar, and name of the room, +rather than all room state. This behaviour matches the information sent to +remote servers when invited their users to a room. This prevents unneeded state from the room leaking out, and also speeds things up (think not sending over hundreds of membership events from big rooms). -XXX: Is `m.room.canonical_alias` worth allowing here for any reason? - The following is an example of knock state coming down `/sync`. Request: From 6e47e86f0125328db1c3afe4a13fb59756fb7019 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 16 Sep 2020 15:57:12 +0100 Subject: [PATCH 30/72] Add unstable endpoint replacements --- proposals/2403-knock.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 424270187ce..ad4360816e6 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -412,3 +412,25 @@ knocks over and over. In both cases, room admins should employ typical abuse mitigation tools, such as user bans and server ACLs. Clients are encouraged to ease employing these tools easy even if the offensive user or server is present not in the room. + +# Unstable prefix + +An unstable feature flag is added to the `unstable_features` dict of +`/_matrix/client/versions` with the key `xyz.amorgan.knock` and value `true`. +If this key is present, this is a signal to clients that the homeserver has +experimental support for room knocking. + +The new endpoints should contain an unstable prefix during experimental +implementation. The unstable counterpart for each endpoint is: + +* `POST /_matrix/client/r0/rooms/{roomId}/knock` +* `POST /_matrix/client/unstable/xyz.amorgan/rooms/{roomId}/knock` + +* `POST /_matrix/client/knock/{roomIdOrAlias}` +* `POST /_matrix/client/unstable/xyz.amorgan/knock/{roomIdOrAlias}` + +* `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` +* `GET /_matrix/federation/unstable/xyz.amorgan/make_knock/{roomId}/{userId}` + +* `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` +* `PUT /_matrix/federation/unstable/xyz.amorgan/send_knock/{roomId}/{eventId}` From 340f888de3958b31bedb077301cec43c77006f1f Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 16 Sep 2020 16:05:27 +0100 Subject: [PATCH 31/72] Mention unstable prefixes for sync, join_rules and membership events --- proposals/2403-knock.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index ad4360816e6..d7f910496d2 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -434,3 +434,8 @@ implementation. The unstable counterpart for each endpoint is: * `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` * `PUT /_matrix/federation/unstable/xyz.amorgan/send_knock/{roomId}/{eventId}` + +And finally, an unstable prefix is added to the key that comes down `/sync`, +the new join rule for rooms and the `content.membership` key of the member +event sent into rooms when a user has knocked successfully. Instead of +`knock`, experimental implementations should use `xyz.amorgan.knock`. From e58e207bbf5e062031d2d033bbac085446a059a4 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 1 Oct 2020 16:19:33 +0100 Subject: [PATCH 32/72] Go into more depth about membership changes surrounding knocking --- proposals/2403-knock.md | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index d7f910496d2..64cf4df4749 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -50,6 +50,62 @@ that user can be transitioned to the following possible states: - `ban`: In this case, the knock was rejected and the user has been prevented from sending further knocks. +Let's talk about each one of these in more detail. + +### Membership change to `invite` + +The knock has been accepted by someone. +This user must have the power level to perform invites. The user's homeserver +will then send an invite - over federation if necessary - to the knocking +user. The knocking user may then join the room as if they had been invited +normally. + +### Membership change to `leave` + +The knock has been rejected by someone in the room. + +This is made a bit tricky in that it is very difficult to have knock +rejections, aka leave events from the room directed towards you, propagate +over federation if you're not in the room at the same time. This is a problem +that currently affects other similar operations, such as disinviting or +unbanning a federated user. In both cases, they won't be notified as their homeserver is not in the room. + +While we could send easily send the leave event as part of a generic +transaction to the remote homeserver, that homeserver would have no way to +validate the `prev_events` and `auth_events` that the event references. We +could send those events over as well, but those will also reference other +events that require validation and so on. + +A dumb thing we could easily do here is to trust the leave event implicitly +if it is sent by the homeserver we originally knocked through. We know this +homeserver is (or at least was) in the room, so they're probably telling the +truth. This is almost an edge case though, as while you'll knock through one +homeserver in the room, there's no guarantee that the admin that denies your +knock will be on the same homeserver you knocked through. Perhaps the homeserver you knocked through could listen for this and then send the event back to you - but what if it goes offline in the meantime? + +As such, this feature working over federation should be de-scoped for now, +and left to a future MSC which can solve this problem across the board for +all affected features in a proper way. Rejections should still work for the +homeservers that are in the room however. + +XXX: There is also an open question here about who should be able to reject a +knock. To disinvite a user, perhaps counter-intuitively, you need to have a +high enough power level to kick users, rather than invite them. You also need +to have a higher power level than them. Should the same be done for knocking, +assuming the knocking user has the default power level? + +### Membership change to `ban` + +The knock has been rejected by someone. + +This one is fairly straightforward. Someone with the appropriate power levels +in the room bans the user. This will have the same effect as rejecting the +knock, and in addition prevent any further knocks by this user from being +allowed into the room. + +If the user is unbanned, then knocks will be accepted again. + + ## Client-Server API Two new endpoints are introduced in the Client-Server API (similarly to join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST From 9e5ac042accd54bbb989109dddbb3d4256f89c44 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 1 Oct 2020 16:35:39 +0100 Subject: [PATCH 33/72] Explicitly state that the hs that received the knock must put in the room --- proposals/2403-knock.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 64cf4df4749..ee58cc53d9d 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -378,11 +378,14 @@ Content-Type: application/json #### Response: ##### Status code 200: -The event was successfully accepted into the graph by the receiving -homeserver. The response contains `StrippedStateEvent`s with room metadata -(room name, avatar ...) that the knocking homeserver can pass to the client. -The event types that can be sent here should match those of the `/sync` -extensions mentioned above. +The event was successfully accepted into the graph by the homeserver that +received the knock. It must then send this knock into the room, before +responding to the knocking homeserver, indicating the knock succeeded. + +The response contains `StrippedStateEvent`s with room metadata (room name, +avatar ...) that the knocking homeserver can pass to the client. The event +types that can be sent here should match those of the `/sync` extensions +mentioned above. This is loosely based on the [federated invite](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid) From fd8176b93d55b090b57756022cb762ab534025bc Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 1 Oct 2020 17:09:10 +0100 Subject: [PATCH 34/72] Clarify endpoint calls clients and servers need to use to handle knocks --- proposals/2403-knock.md | 65 +++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index ee58cc53d9d..8fe96eda6cd 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -60,15 +60,45 @@ will then send an invite - over federation if necessary - to the knocking user. The knocking user may then join the room as if they had been invited normally. +The accept a knock, the client should call [`POST +/_matrix/client/r0/rooms/{roomId}/invite`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-invite) +with the user ID of the knocking user in the JSON body. + +If the knocking user is on another homeserver, then the homeserver of the +accepting user will call [`PUT +/_matrix/federation/v2/invite/{roomId}/{eventId}`](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid) +on the knocking homeserver to inform it that its knock has been accepted. + +The knocking homeserver should assume an invite to a room it has knocked on means +that its knock has been accepted, even if the invite was not explicitly +related to the knock attempt. + ### Membership change to `leave` The knock has been rejected by someone in the room. -This is made a bit tricky in that it is very difficult to have knock -rejections, aka leave events from the room directed towards you, propagate -over federation if you're not in the room at the same time. This is a problem -that currently affects other similar operations, such as disinviting or -unbanning a federated user. In both cases, they won't be notified as their homeserver is not in the room. + +XXX: There is also an open question here about who should be able to reject a +knock. When revoking an invite for a user, perhaps counter-intuitively, you +need to have a high enough power level to kick users, rather than invite +them. You also need to have a higher power level than them. Should the same +be done for knocking, assuming the knocking user has the default power level? +Or should it be the same power level that's required to accept the knock? + +To reject a knock, the client should call [`POST +/_matrix/client/r0/rooms/{roomId}/kick`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-kick) +with the user ID of the knocking user in the JSON body. + +At this point, if the knocking user is on another homeserver, then the +homeserver of the rejecting user needs to send the `leave` event over +federation to the knocking homeserver. However, this is a bit tricky as it is +currently very difficult to have events from a room propagate over federation +if the receiving homeserver is not in the room. This is due to the remote +homeserver being unable to verify that the event being sent is actually from +a homeserver in the room - and that the homeserver in the room had the +required power level to send it. This is a problem that currently affects +other similar operations, such as disinviting or unbanning a federated user. +In both cases, they won't be notified as their homeserver is not in the room. While we could send easily send the leave event as part of a generic transaction to the remote homeserver, that homeserver would have no way to @@ -83,16 +113,12 @@ truth. This is almost an edge case though, as while you'll knock through one homeserver in the room, there's no guarantee that the admin that denies your knock will be on the same homeserver you knocked through. Perhaps the homeserver you knocked through could listen for this and then send the event back to you - but what if it goes offline in the meantime? -As such, this feature working over federation should be de-scoped for now, -and left to a future MSC which can solve this problem across the board for -all affected features in a proper way. Rejections should still work for the -homeservers that are in the room however. +As such, this feature working over federation is de-scoped for now, and left +to a future MSC which can solve this problem across the board for all +affected features in a suitable way. Rejections should still work for the +homeservers that are in the room, as they can validate the leave event for +they have access to the events it references. -XXX: There is also an open question here about who should be able to reject a -knock. To disinvite a user, perhaps counter-intuitively, you need to have a -high enough power level to kick users, rather than invite them. You also need -to have a higher power level than them. Should the same be done for knocking, -assuming the knocking user has the default power level? ### Membership change to `ban` @@ -105,6 +131,9 @@ allowed into the room. If the user is unbanned, then knocks will be accepted again. +To ban the user, the client should call [`POST +/_matrix/client/r0/rooms/{roomId}/ban`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-ban) with the user ID of the knocking user in the JSON body. + ## Client-Server API Two new endpoints are introduced in the Client-Server API (similarly to @@ -205,7 +234,7 @@ the room's name and avatar. A client will need this information to show a nice representation of pending knocked rooms. The recommended events to include are the join rules, canonical alias, avatar, and name of the room, rather than all room state. This behaviour matches the information sent to -remote servers when invited their users to a room. +remote homeservers when invited their users to a room. This prevents unneeded state from the room leaking out, and also speeds things up (think not sending over hundreds of membership events from big @@ -337,8 +366,8 @@ This request was invalid, e.g. bad JSON. Example reply: ``` ### `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` -Submits a signed knock event to the resident server for it to accept into the -room's graph. Note that event format may differ between room versions. +Submits a signed knock event to the resident homeserver for it to accept into +the room's graph. Note that event format may differ between room versions. Request format: @@ -458,7 +487,7 @@ reason" button). The user should reveal the reason only if they choose to. It is recommended to not display the reason by default as else this would essentially allow outsiders to send messages into the room. -It is still theoretically possible for a server admin to create many users +It is still theoretically possible for a homeserver admin to create many users with different user IDs or display names, all spelling out an abusive message, and then having each of them knock in order. From 6b992283866c8bbcb32c577561631466b758df87 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 1 Oct 2020 17:25:19 +0100 Subject: [PATCH 35/72] Remove section duplicated by membership change section --- proposals/2403-knock.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 8fe96eda6cd..da1d135e5be 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -300,14 +300,6 @@ Response: } ``` -Once a knock has been made, a user in the room can decide whether they want -to accept or deny the knock. If they accept, they will invite the knocker, -which the knocker will be notified about through existing flows. - -If they deny, then a leave membership event is sent in the room, and the -knocking user will be notified through existing flows (matching the behaviour -of when an invite is recinded). - ## Server-Server API Similarly to join and leave over federation, a ping-pong game with two new endpoints is introduced: `make_knock` and `send_knock`. Both endpoints must From 5097fad4e71e0eebc39c12ea6e750fa20e5959f7 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 1 Oct 2020 17:43:49 +0100 Subject: [PATCH 36/72] Fix unstable prefix bullet points --- proposals/2403-knock.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index da1d135e5be..10a221f4729 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -503,15 +503,23 @@ experimental support for room knocking. The new endpoints should contain an unstable prefix during experimental implementation. The unstable counterpart for each endpoint is: +C-S knock method 1: + * `POST /_matrix/client/r0/rooms/{roomId}/knock` * `POST /_matrix/client/unstable/xyz.amorgan/rooms/{roomId}/knock` +C-S knock method 2: + * `POST /_matrix/client/knock/{roomIdOrAlias}` * `POST /_matrix/client/unstable/xyz.amorgan/knock/{roomIdOrAlias}` +S-S make_knock: + * `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` * `GET /_matrix/federation/unstable/xyz.amorgan/make_knock/{roomId}/{userId}` +S-S send_knock: + * `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` * `PUT /_matrix/federation/unstable/xyz.amorgan/send_knock/{roomId}/{eventId}` From 6f7bcb6052e0eedbc89c9d5992011da8628a92e9 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 1 Oct 2020 18:49:41 +0100 Subject: [PATCH 37/72] Explicitly state what changes to the auth rules are necessary --- proposals/2403-knock.md | 44 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 10a221f4729..fe90b648cd7 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -37,8 +37,48 @@ must be set to "knock" for a knock to succeed. This means that existing rooms will need to opt into allowing knocks in their rooms. Other than allowing knocks, "knock" is no different from the "invite" join rule. -As we're updating the join rules, and thus the auth rules, this proposal will -need to be introduced as part of a new room version. +As the join rules are moedified, the auth rules are as well. The [current +auth rules](https://matrix.org/docs/spec/rooms/v1#authorization-rules) are +defined by each room version. Thus, to change these rules, implementation of +this proposal must be done in a new room version. The explicit changes to the +auth rules from room version 5 are: + +* Under "5. If type is `m.room.member`", the following should be added: + + ``` + a. If `membership` is `knock`: + i. If the `join_rule` is anything other than `knock`, reject. + ii. If `sender` matches `state_key`, reject. + iii. If the `sender`'s current membership state is not `join`, reject. + iv. If the *target user*'s membership is not `ban` or `join`, allow. + v. Otherwise, reject. + ``` + + Notes: + - a.ii is justified as it doesn't make sense for a user that is already + in the room to knock. + - a.iii is justified as an event should be rejected if it was sent by + someone not in the room (note the sender of a knock event is the + homserver that's in the room, rather than the homeserver knocking). + - a.iv is justified as knocks should be allowed if the knocking user has + been banned from the room, or they're already in the room. + + XXX: Is it a problem that any homeserver in the room can send a knock + event in? Even if they don't have the power level to send any other + events? + +* Under "11. If type is `m.room.redaction`", the following should be added: + + ``` + a. If the type of the `event_id` of the event being redacted is `m.room.member` and the `membership` field in its `content` dictionary is `knock`, reject. + ``` + + Notes: + - It seems bad if the server you sent a knock through later redacts that + knock, hence adding this. Ideally the knock should just be rejected + instead. + + XXX: Is this the best place in the auth rules to enforce this? ## Membership changes Once someone has sent a `knock` membership into the room, the membership for From 525d1d33e0bd18acf4f9757fb0bc02a850e8c5e1 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 5 Oct 2020 17:09:33 +0100 Subject: [PATCH 38/72] Some clarifications and wording fixes --- proposals/2403-knock.md | 53 +++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index fe90b648cd7..039be1176cd 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -20,10 +20,12 @@ room. An example for the membership would look like the following: } ``` -After a knock in a room, a member of the room can invite the knocker. +After a knock in a room, a member of the room can invite the knocker, or they +can decide to reject it instead. ## Restrictions -There are restrictions to being able to set this membership. +There are restrictions to being able to set this membership, as well as +accepting or denying the knock. ### Current membership Only users without a current membership or with their current membership @@ -37,11 +39,11 @@ must be set to "knock" for a knock to succeed. This means that existing rooms will need to opt into allowing knocks in their rooms. Other than allowing knocks, "knock" is no different from the "invite" join rule. -As the join rules are moedified, the auth rules are as well. The [current -auth rules](https://matrix.org/docs/spec/rooms/v1#authorization-rules) are -defined by each room version. Thus, to change these rules, implementation of -this proposal must be done in a new room version. The explicit changes to the -auth rules from room version 5 are: +As the join rules are modified, the auth rules are as well. The [current auth +rules](https://matrix.org/docs/spec/rooms/v1#authorization-rules) are defined +by each room version. To change these rules, the implementation of this +proposal must be done in a new room version. The explicit changes to the auth +rules from room version 5 are: * Under "5. If type is `m.room.member`", the following should be added: @@ -54,7 +56,7 @@ auth rules from room version 5 are: v. Otherwise, reject. ``` - Notes: + Note that: - a.ii is justified as it doesn't make sense for a user that is already in the room to knock. - a.iii is justified as an event should be rejected if it was sent by @@ -62,10 +64,9 @@ auth rules from room version 5 are: homserver that's in the room, rather than the homeserver knocking). - a.iv is justified as knocks should be allowed if the knocking user has been banned from the room, or they're already in the room. + - Knocks are not restricted by power level like invites are. The `join_rules` + are already used to enforce whether someone can or cannot knock. - XXX: Is it a problem that any homeserver in the room can send a knock - event in? Even if they don't have the power level to send any other - events? * Under "11. If type is `m.room.redaction`", the following should be added: @@ -74,9 +75,9 @@ auth rules from room version 5 are: ``` Notes: - - It seems bad if the server you sent a knock through later redacts that - knock, hence adding this. Ideally the knock should just be rejected - instead. + - The server you sent a knock through later should not be able to redact + that knock afterwards. The knock should instead be rejected by whoever + has the authority to. XXX: Is this the best place in the auth rules to enforce this? @@ -94,11 +95,12 @@ Let's talk about each one of these in more detail. ### Membership change to `invite` -The knock has been accepted by someone. -This user must have the power level to perform invites. The user's homeserver -will then send an invite - over federation if necessary - to the knocking -user. The knocking user may then join the room as if they had been invited -normally. +The knock has been accepted by someone in the room. + +The user who is accepting the knock must have the power level to perform +invites. The user's homeserver will then send an invite - over federation if +necessary - to the knocking user. The knocking user may then join the room as +if they had been invited normally. The accept a knock, the client should call [`POST /_matrix/client/r0/rooms/{roomId}/invite`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-invite) @@ -107,7 +109,7 @@ with the user ID of the knocking user in the JSON body. If the knocking user is on another homeserver, then the homeserver of the accepting user will call [`PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid) -on the knocking homeserver to inform it that its knock has been accepted. +on the knocking homeserver to inform it that the knock has been accepted. The knocking homeserver should assume an invite to a room it has knocked on means that its knock has been accepted, even if the invite was not explicitly @@ -117,7 +119,6 @@ related to the knock attempt. The knock has been rejected by someone in the room. - XXX: There is also an open question here about who should be able to reject a knock. When revoking an invite for a user, perhaps counter-intuitively, you need to have a high enough power level to kick users, rather than invite @@ -151,7 +152,9 @@ if it is sent by the homeserver we originally knocked through. We know this homeserver is (or at least was) in the room, so they're probably telling the truth. This is almost an edge case though, as while you'll knock through one homeserver in the room, there's no guarantee that the admin that denies your -knock will be on the same homeserver you knocked through. Perhaps the homeserver you knocked through could listen for this and then send the event back to you - but what if it goes offline in the meantime? +knock will be on the same homeserver you knocked through. Perhaps the +homeserver you knocked through could listen for this and then send the event +back to you - but what if it goes offline in the meantime? As such, this feature working over federation is de-scoped for now, and left to a future MSC which can solve this problem across the board for all @@ -162,7 +165,8 @@ they have access to the events it references. ### Membership change to `ban` -The knock has been rejected by someone. +The knock has been rejected by someone in the room and the user has been +banned, and is unable to send further knocks. This one is fairly straightforward. Someone with the appropriate power levels in the room bans the user. This will have the same effect as rejecting the @@ -174,6 +178,9 @@ If the user is unbanned, then knocks will be accepted again. To ban the user, the client should call [`POST /_matrix/client/r0/rooms/{roomId}/ban`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-ban) with the user ID of the knocking user in the JSON body. +Informing the knocking user about the update is the same as rejecting the +knock. + ## Client-Server API Two new endpoints are introduced in the Client-Server API (similarly to From a924f5b3d54d1427574839a6b1c7c625ed4e83a5 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 5 Oct 2020 20:24:54 +0100 Subject: [PATCH 39/72] Fix incorrect assumptions about the sender field of a knock event Got a bit confused with the sender and state_key being different in invite membership events. In case of a knock, even if the knock event is being inserted into the room by another homeserver over federation, the sender of the event is still the knocking user, just like the state_key. --- proposals/2403-knock.md | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 039be1176cd..37e8d6a8f2b 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -50,20 +50,21 @@ rules from room version 5 are: ``` a. If `membership` is `knock`: i. If the `join_rule` is anything other than `knock`, reject. - ii. If `sender` matches `state_key`, reject. - iii. If the `sender`'s current membership state is not `join`, reject. - iv. If the *target user*'s membership is not `ban` or `join`, allow. - v. Otherwise, reject. + ii. If `sender` does not match `state_key`, reject. + iii. If the `sender`'s membership is not `ban` or `join`, allow. + iv. Otherwise, reject. ``` Note that: - - a.ii is justified as it doesn't make sense for a user that is already - in the room to knock. - - a.iii is justified as an event should be rejected if it was sent by - someone not in the room (note the sender of a knock event is the - homserver that's in the room, rather than the homeserver knocking). - - a.iv is justified as knocks should be allowed if the knocking user has - been banned from the room, or they're already in the room. + - The `sender` field in the event is set to the user ID of the knocking + user, not any other user in the room that belongs to a homeserver that + the knocking user is using to inject into the room DAG. This is separate + from an invite membership event, where the `sender` is the inviter and + the `state_key` is the invitee. + - a.ii is justified as one user should not be able to knock on behalf of + another user. + - a.iii is justified as knocks should not be allowed if the knocking user + has been banned from the room, or if they are already in the room. - Knocks are not restricted by power level like invites are. The `join_rules` are already used to enforce whether someone can or cannot knock. @@ -71,13 +72,15 @@ rules from room version 5 are: * Under "11. If type is `m.room.redaction`", the following should be added: ``` - a. If the type of the `event_id` of the event being redacted is `m.room.member` and the `membership` field in its `content` dictionary is `knock`, reject. + a. If the type of the `event_id` of the event being redacted is + `m.room.member` and the `membership` field in its `content` dictionary is + `knock`, reject. ``` Notes: - The server you sent a knock through later should not be able to redact - that knock afterwards. The knock should instead be rejected by whoever - has the authority to. + that knock afterwards. The knock should instead be rejected by whoever + has the authority to. XXX: Is this the best place in the auth rules to enforce this? From 815dae6eae2bcd1573e68ac615bf83292a1a59c1 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 8 Oct 2020 18:04:32 +0100 Subject: [PATCH 40/72] Note that redactions of knocks are not a concern --- proposals/2403-knock.md | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 37e8d6a8f2b..3680b3ada0f 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -67,22 +67,10 @@ rules from room version 5 are: has been banned from the room, or if they are already in the room. - Knocks are not restricted by power level like invites are. The `join_rules` are already used to enforce whether someone can or cannot knock. - - -* Under "11. If type is `m.room.redaction`", the following should be added: - - ``` - a. If the type of the `event_id` of the event being redacted is - `m.room.member` and the `membership` field in its `content` dictionary is - `knock`, reject. - ``` - - Notes: - - The server you sent a knock through later should not be able to redact - that knock afterwards. The knock should instead be rejected by whoever - has the authority to. - - XXX: Is this the best place in the auth rules to enforce this? + +Additionally, note that redactions of knock events are not a concern, as +`membership` keys are excluded from being redacted as defined by all current +room versions. ## Membership changes Once someone has sent a `knock` membership into the room, the membership for From 6c75b83b9906e5edbcf312d39faefb9609abf95e Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 20 Nov 2020 16:45:45 +0000 Subject: [PATCH 41/72] Address Travis and Patrick's feedback --- proposals/2403-knock.md | 178 ++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 96 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 3680b3ada0f..98db3b31184 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -6,11 +6,12 @@ user to indicate that they want to join a room. # Proposal This proposal implements the reserved "knock" membership type for the `m.room.member` state event. This state event indicates that when a user -knocks on a room, they are asking for permission to join. It contains an -optional "reason" parameter to specify the reason you want to join. Like -other membership types, the parameters "displayname" and "avatar_url" are -optional. This membership can be set from users who aren't currently in said -room. An example for the membership would look like the following: +knocks on a room, they are asking for permission to join. Like all membership +events, it contains an optional "reason" parameter to specify the reason you +want to join. Like other membership types, the parameters "displayname" and +"avatar_url" are optional. This membership can be set from users who aren't +currently in said room. An example for the membership would look like the +following: ```json { "membership": "knock", @@ -33,25 +34,27 @@ being "leave" can knock on a room. This means that a user that is banned, has already knocked or is currently in the room cannot knock on it. ### Join Rules -This proposal introduces a new possible value for `join_rule` in -`m.room.join_rules`: "knock". The value of `join_rule` in `m.room.join_rules` +This proposal makes use of the existing "knock" join rule. The value of +`join_rule` in the content of the `m.room.join_rules` state event for a room must be set to "knock" for a knock to succeed. This means that existing rooms will need to opt into allowing knocks in their rooms. Other than allowing -knocks, "knock" is no different from the "invite" join rule. +knocks, a join rule of "knock" is functionally equivalent to that of +"invite", except that it additionally allows external users to change their +membership to "knock" under certain conditions. As the join rules are modified, the auth rules are as well. The [current auth -rules](https://matrix.org/docs/spec/rooms/v1#authorization-rules) are defined +rules](https://matrix.org/docs/spec/rooms/v6#authorization-rules-for-events) are defined by each room version. To change these rules, the implementation of this proposal must be done in a new room version. The explicit changes to the auth rules from room version 5 are: -* Under "5. If type is `m.room.member`", the following should be added: +* Under "5. If type is `m.room.member`", the following will be added: ``` a. If `membership` is `knock`: i. If the `join_rule` is anything other than `knock`, reject. ii. If `sender` does not match `state_key`, reject. - iii. If the `sender`'s membership is not `ban` or `join`, allow. + iii. If the `sender`'s membership is not `ban`, `knock` or `join`, allow. iv. Otherwise, reject. ``` @@ -108,29 +111,27 @@ related to the knock attempt. ### Membership change to `leave` -The knock has been rejected by someone in the room. +The knock has been rejected by someone in the room, or the knocking user has +rescinded their knock. -XXX: There is also an open question here about who should be able to reject a -knock. When revoking an invite for a user, perhaps counter-intuitively, you -need to have a high enough power level to kick users, rather than invite -them. You also need to have a higher power level than them. Should the same -be done for knocking, assuming the knocking user has the default power level? -Or should it be the same power level that's required to accept the knock? +To rescind a knock, the knocking user's client must call [`POST +/_matrix/client/r0/rooms/{roomId}/leave`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-leave). -To reject a knock, the client should call [`POST +To reject a knock, the rejecting user's client must call [`POST /_matrix/client/r0/rooms/{roomId}/kick`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-kick) -with the user ID of the knocking user in the JSON body. - -At this point, if the knocking user is on another homeserver, then the -homeserver of the rejecting user needs to send the `leave` event over -federation to the knocking homeserver. However, this is a bit tricky as it is -currently very difficult to have events from a room propagate over federation -if the receiving homeserver is not in the room. This is due to the remote -homeserver being unable to verify that the event being sent is actually from -a homeserver in the room - and that the homeserver in the room had the -required power level to send it. This is a problem that currently affects -other similar operations, such as disinviting or unbanning a federated user. -In both cases, they won't be notified as their homeserver is not in the room. +with the user ID of the knocking user in the JSON body. Rejecting a knock +over federation has a slight catch, however. + +When the knocking user is on another homeserver, the homeserver of the +rejecting user needs to send the `leave` event over federation to the +knocking homeserver. However, this is a bit tricky as it is currently very +difficult to have events from a room propagate over federation when the +receiving homeserver is not in the room. This is due to the remote homeserver +being unable to verify that the event being sent is actually from a +homeserver in the room - and that the homeserver in the room had the required +power level to send it. This is a problem that currently affects other, +similar operations, such as disinviting or unbanning a federated user. In +both cases, they won't be notified as their homeserver is not in the room. While we could send easily send the leave event as part of a generic transaction to the remote homeserver, that homeserver would have no way to @@ -147,9 +148,9 @@ knock will be on the same homeserver you knocked through. Perhaps the homeserver you knocked through could listen for this and then send the event back to you - but what if it goes offline in the meantime? -As such, this feature working over federation is de-scoped for now, and left -to a future MSC which can solve this problem across the board for all -affected features in a suitable way. Rejections should still work for the +As such, informing remote homeservers about the rejection of knocks over +federation is de-scoped for now, and left to a future MSC which can solve +this class of problem in a suitable way. Rejections should still work for the homeservers that are in the room, as they can validate the leave event for they have access to the events it references. @@ -164,7 +165,8 @@ in the room bans the user. This will have the same effect as rejecting the knock, and in addition prevent any further knocks by this user from being allowed into the room. -If the user is unbanned, then knocks will be accepted again. +If the user is unbanned, they will be able to send a new knock which could be +accepted. To ban the user, the client should call [`POST /_matrix/client/r0/rooms/{roomId}/ban`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-ban) with the user ID of the knocking user in the JSON body. @@ -174,22 +176,26 @@ knock. ## Client-Server API -Two new endpoints are introduced in the Client-Server API (similarly to -join): `POST /_matrix/client/r0/rooms/{roomId}/knock` and `POST -/_matrix/client/r0/knock/{roomIdOrAlias}`. These allow the client to state +A new endpoint is introduced in the Client-Server API: `POST +/_matrix/client/r0/knock/{roomIdOrAlias}`. This allows the client to state their intent to knock on a room. Additionally, extensions to the `GET /_matrix/client/r0/sync` endpoint are introduced. These allow a client to receive information about the status of their knock attempt. -### `POST /_matrix/client/r0/rooms/{roomId}/knock` -The path parameter (`roomId`) is the room on which you want to knock. It is -required. The post body accepts an optional string parameter, `reason`, which -is the reason you want to join the room. A request could look as follows: +The newly proposed endpoint requires authentication and can be rate limited. + + +### `POST /_matrix/client/r0/knock/{roomIdOrAlias}` +The path parameter (`roomIdOrAlias`) is either the room ID or the alias of +the room you want to knock on. Additionally several `server_name` parameters +can be specified via the query parameters. The post body accepts an optional +string parameter, `reason`, which is the reason you want to join the room. A +request could look as follows: ```json -POST /_matrix/client/r0/rooms/%21d41d8cd%3Amatrix.org/knock HTTP/1.1 +POST /_matrix/client/r0/knock/%23foxes%3Amatrix.org?server_name=matrix.org&server_name=elsewhere.ca HTTP/1.1 Content-Type: application/json { @@ -204,15 +210,6 @@ The user knocked successfully. Example reply: {} ``` -##### Status code 400: -This request was invalid, e.g. bad JSON. Example reply: -```json -{ - "errcode": "M_UNKNOWN", - "error": "An unknown error occurred" -} -``` - ##### Status code 403: The user wasn't allowed to knock (e.g. they are banned). Error reply: ```json @@ -222,36 +219,6 @@ The user wasn't allowed to knock (e.g. they are banned). Error reply: } ``` -##### Status code 429: -This request was rate-limited. Example reply: -```json -{ - "errcode": "M_LIMIT_EXCEEDED", - "error": "Too many requests", - "retry_after_ms": 2000 -} -``` - -### `POST /_matrix/client/r0/knock/{roomIdOrAlias}` -The path parameter (`roomIdOrAlias`) is either the room ID or the alias of -the room you want to knock on. Additionally several `server_name` parameters -can be specified via the query parameters. The post body accepts an optional -string parameter, `reason`, which is the reason you want to join the room. A -request could look as follows: - -```json -POST /_matrix/client/r0/knock/%23foxes%3Amatrix.org?server_name=matrix.org&server_name=elsewhere.ca HTTP/1.1 -Content-Type: application/json - -{ - "reason": "I want to join this room as I really love foxes!" -} -``` - -#### Responses: -The possible responses are the same as for the `POST -/_matrix/client/r0/rooms/{roomId}/knock` endpoint. - ### Extensions to `GET /_matrix/client/r0/sync` In [the response to @@ -267,17 +234,26 @@ a list of `StrippedStateEvent`. `StrippedStateEvent`s are defined as state events that only contain the `sender`, `type`, `state_key` and `content` keys. +Note that while `join` and `leave` keys in `/sync` use `state`, we use +`knock_state` here. This mirrors `invite`s use of `invite_state`. + These stripped state events contain information about the room, most notably the room's name and avatar. A client will need this information to show a nice representation of pending knocked rooms. The recommended events to -include are the join rules, canonical alias, avatar, and name of the room, -rather than all room state. This behaviour matches the information sent to -remote homeservers when invited their users to a room. +include are the join rules, canonical alias, avatar, name and encryption +state of the room, rather than all room state. This behaviour matches the +information sent to remote homeservers when invited their users to a room. This prevents unneeded state from the room leaking out, and also speeds things up (think not sending over hundreds of membership events from big rooms). +Also note that like `invite_state`, state events from `knock_state` are +purely for giving the user some information about the current state of the +room that they have knocked on. If the user was previously in the room, the +state events in `knock_state` are not intended to overwrite any historical +state. This applies storage of state on both the homeserver and the client. + The following is an example of knock state coming down `/sync`. Request: @@ -395,10 +371,17 @@ This request was invalid, e.g. bad JSON. Example reply: } ``` -### `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` +### `PUT /_matrix/federation/v2/send_knock/{roomId}/{eventId}` Submits a signed knock event to the resident homeserver for it to accept into the room's graph. Note that event format may differ between room versions. +While this is a new endpoint, we start off at `v2` to align with the rest of +the `/v2/send_*` endpoints. The switch from `v1` to `v2` occurred as part of +[MSC1802](https://github.com/matrix-org/matrix-doc/pull/1802) and required +that `send_*` endpoints no longer return a redundant HTTP error code in +response bodies. As we do the same here, and for consistency's sake, for +`send_knock` will begin at endpoint `v2` as well. + Request format: | Parameter | Type | Description | @@ -417,7 +400,7 @@ Response Format: A request could look as follows: ```json -PUT /_matrix/federation/v1/send_knock/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1 +PUT /_matrix/federation/v2/send_knock/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1 Content-Type: application/json { @@ -492,8 +475,8 @@ request content. # Potential issues This new feature would allow users to send events into rooms that they don't -partake in. That is why this proposal adds a new join rule, in order to allow -room admins to opt in to this behaviour. +partake in. That is why this proposal enables the a `knock` join rule, in +order to allow room admins to opt in to this behaviour. # Alternatives The two endpoints for the Client-Server API seem redundant, this MSC followed @@ -525,7 +508,10 @@ Another abuse vector is allowed by the ability for users to rescind knocks. This is to help users in case they knocked on a room accidentally, or simply no longer want to join a room they've knocked on. While this is a useful feature, it also allows users to spam a room by knocking and rescinding their -knocks over and over. +knocks over and over. Particularly note-worthy is that this will generate +state events that homeserver in the room will need to process. And while +join/leave state changes will do the same in a public room, the act of +knocking is much lighter than the act of joining a room. In both cases, room admins should employ typical abuse mitigation tools, such as user bans and server ACLs. Clients are encouraged to ease employing these @@ -533,10 +519,10 @@ tools easy even if the offensive user or server is present not in the room. # Unstable prefix -An unstable feature flag is added to the `unstable_features` dict of -`/_matrix/client/versions` with the key `xyz.amorgan.knock` and value `true`. -If this key is present, this is a signal to clients that the homeserver has -experimental support for room knocking. +An unstable feature flag is not required due to this proposal's requirement +of a new room version. Clients can check for a room version that includes +knocking via the Client-Server API's [capabilities +endpoint](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-capabilities). The new endpoints should contain an unstable prefix during experimental implementation. The unstable counterpart for each endpoint is: @@ -558,10 +544,10 @@ S-S make_knock: S-S send_knock: -* `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` +* `PUT /_matrix/federation/v2/send_knock/{roomId}/{eventId}` * `PUT /_matrix/federation/unstable/xyz.amorgan/send_knock/{roomId}/{eventId}` And finally, an unstable prefix is added to the key that comes down `/sync`, -the new join rule for rooms and the `content.membership` key of the member +the join rule for rooms and the `content.membership` key of the member event sent into rooms when a user has knocked successfully. Instead of `knock`, experimental implementations should use `xyz.amorgan.knock`. From 7dcff8f2e15839a93c00ad831d2c95844f916a7c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 27 Nov 2020 11:04:21 +0000 Subject: [PATCH 42/72] Disallow invite->knock membership changes --- proposals/2403-knock.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 98db3b31184..c45ea0af78f 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -54,7 +54,7 @@ rules from room version 5 are: a. If `membership` is `knock`: i. If the `join_rule` is anything other than `knock`, reject. ii. If `sender` does not match `state_key`, reject. - iii. If the `sender`'s membership is not `ban`, `knock` or `join`, allow. + iii. If the `sender`'s membership is not `ban`, `knock`, `invite` or `join`, allow. iv. Otherwise, reject. ``` @@ -67,7 +67,8 @@ rules from room version 5 are: - a.ii is justified as one user should not be able to knock on behalf of another user. - a.iii is justified as knocks should not be allowed if the knocking user - has been banned from the room, or if they are already in the room. + has been banned from the room, has already knocked on the room, is + invited to the room or if they are already in the room. - Knocks are not restricted by power level like invites are. The `join_rules` are already used to enforce whether someone can or cannot knock. From 42e01b8e91ba8034fea79cd3df9a3e0fcde9f313 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Tue, 2 Feb 2021 19:50:41 +0000 Subject: [PATCH 43/72] Add join_rules to room chunks returned on a public room dir query --- proposals/2403-knock.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index c45ea0af78f..296aeb203d1 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -315,6 +315,41 @@ Response: } ``` +### Changes regarding the Public Rooms Directory + +A problem arises for discovery of knockable rooms. Ideally one wouldn't have +to send their colleagues a room ID for a room that they need to knock on. One +of these methods for room discovery is the public rooms directory, which +allows us to explore a list of rooms we may be able to join. + +The spec does not prevent us from adding rooms with 'knock' join_rules to the +public rooms directory. However, there is a problem in that a user attempting +to join a room in the directory will not know whether to directly attempt a +join, or to knock first. The current content of a `PublicRoomsChunk` does not +contain this information: + +```json +{ + "aliases": [ + "#murrays:cheese.bar" + ], + "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE", + "guest_can_join": false, + "name": "CHEESE", + "num_joined_members": 37, + "room_id": "!ol19s:bleecker.street", + "topic": "Tasty tasty cheese", + "world_readable": true +} +``` + +Therefore this proposal adds `join_rule` as a new, required field to a +`PublicRoomsChunk`. The `join_rule` of knockable rooms will be `knock`, thus +giving clients the information they need to know how to attempt entry of +a room when a client selects it, as well as allowing clients to display +knockable rooms differently than publicly joinable ones. + + ## Server-Server API Similarly to join and leave over federation, a ping-pong game with two new endpoints is introduced: `make_knock` and `send_knock`. Both endpoints must From e99649cb84f87e00c13ede9a93793d5162aac581 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 8 Feb 2021 18:37:08 +0000 Subject: [PATCH 44/72] Foreshadow power level requirements for approval/denial of knock --- proposals/2403-knock.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 296aeb203d1..b97f90a01fa 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -70,8 +70,10 @@ rules from room version 5 are: has been banned from the room, has already knocked on the room, is invited to the room or if they are already in the room. - Knocks are not restricted by power level like invites are. The `join_rules` - are already used to enforce whether someone can or cannot knock. - + are already used to enforce whether someone can or cannot knock. However, + power level rules do apply when approving or denying the knock, as discussed + in the Membership Changes section below. + Additionally, note that redactions of knock events are not a concern, as `membership` keys are excluded from being redacted as defined by all current room versions. From 51a77782173ccab66310fc0bbbfd259fcee246b0 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 8 Feb 2021 18:38:38 +0000 Subject: [PATCH 45/72] typo --- proposals/2403-knock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index b97f90a01fa..fcf8cfaa979 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -547,7 +547,7 @@ This is to help users in case they knocked on a room accidentally, or simply no longer want to join a room they've knocked on. While this is a useful feature, it also allows users to spam a room by knocking and rescinding their knocks over and over. Particularly note-worthy is that this will generate -state events that homeserver in the room will need to process. And while +state events that homeservers in the room will need to process. And while join/leave state changes will do the same in a public room, the act of knocking is much lighter than the act of joining a room. From 6a0d07c79971abd9754b780dc26489ef2d6d05e3 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Tue, 9 Feb 2021 11:18:55 +0000 Subject: [PATCH 46/72] Public rooms directory backwards compatibility note --- proposals/2403-knock.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index fcf8cfaa979..6bad472d806 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -325,7 +325,7 @@ of these methods for room discovery is the public rooms directory, which allows us to explore a list of rooms we may be able to join. The spec does not prevent us from adding rooms with 'knock' join_rules to the -public rooms directory. However, there is a problem in that a user attempting +public rooms directory. However, a user attempting to join a room in the directory will not know whether to directly attempt a join, or to knock first. The current content of a `PublicRoomsChunk` does not contain this information: @@ -347,10 +347,14 @@ contain this information: Therefore this proposal adds `join_rule` as a new, required field to a `PublicRoomsChunk`. The `join_rule` of knockable rooms will be `knock`, thus -giving clients the information they need to know how to attempt entry of -a room when a client selects it, as well as allowing clients to display +giving clients the information they need to attempt entry of +a room when a client selects it. It also allows clients to display knockable rooms differently than publicly joinable ones. +For backwards compatibility with old servers, if a client does not find a +`join_rule` key in a chunk, then it should assume a `join_rule` key with +value `public`. + ## Server-Server API Similarly to join and leave over federation, a ping-pong game with two new From 5c620de273d25a5183ae911060897172c48a85fd Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 10 Feb 2021 17:29:59 +0000 Subject: [PATCH 47/72] typo fix --- proposals/2403-knock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 6bad472d806..fdba1e368fa 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -557,7 +557,7 @@ knocking is much lighter than the act of joining a room. In both cases, room admins should employ typical abuse mitigation tools, such as user bans and server ACLs. Clients are encouraged to ease employing these -tools easy even if the offensive user or server is present not in the room. +tools easy even if the offensive user or server is not present in the room. # Unstable prefix From d5a2a284c534dc34c819033d0c048f65554fdd7b Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 15 Feb 2021 12:42:50 +0000 Subject: [PATCH 48/72] Note clients should try to prevent impersonation attacks during knocking --- proposals/2403-knock.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index fdba1e368fa..c30516c8a43 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -532,6 +532,9 @@ After a knock is received in a room, it is expected to be displayed in the timeline, similar to other membership changes. Clients can optionally add a way for users of a room to review all current knocks. +Please also note the recommendations for clients in the "Security considerations" +section below. + # Security considerations Clients must take care when implementing this feature in order to prevent simple abuse vectors that can be accomplished by individual users. For @@ -544,7 +547,15 @@ essentially allow outsiders to send messages into the room. It is still theoretically possible for a homeserver admin to create many users with different user IDs or display names, all spelling out an abusive -message, and then having each of them knock in order. +message, and then having each of them knock in order. + +Clients should also do their best to prevent impersonation attacks. Similar to +joins, users can set any displayname or avatar URL they'd like when knocking on +a room. Clients SHOULD display further information to help identify the user, +such as User ID, encryption verification status, rooms you share with the user, +etc. Care should be taken to balance the importance of preventing attacks while +avoiding overloading the user with too much information or raising false +positives. Another abuse vector is allowed by the ability for users to rescind knocks. This is to help users in case they knocked on a room accidentally, or simply From 84008775742b8ecd105145c7ed4991930762cee5 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 17 Feb 2021 11:02:21 +0000 Subject: [PATCH 49/72] Make ver a required parameter for make_knock --- proposals/2403-knock.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index c30516c8a43..7cac2eec420 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -374,7 +374,11 @@ Request format: | roomId | string | Required. The room ID that should receive the knock. | userId | string | Required. The user ID the knock event will be for. | Query Parameters: -| ver | [string] | The room versions the sending server has support for. Defaults to `[1]`. +| ver | [string] | Required. The room versions the sending server has support for. + +Note that `GET /_matrix/federation/v1/make_join/{roomId}/{userId}` does not make `ver` +a required query parameter for backwards compatibility reasons. We have no such restrictions. + Response Format: From 337c87b949b1725cd8c8bff5d52c1312c3a8baf4 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 17 Feb 2021 12:11:08 +0000 Subject: [PATCH 50/72] Add 404 on make_knock if unknown room ID --- proposals/2403-knock.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 7cac2eec420..fb82adb3de3 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -417,6 +417,15 @@ This request was invalid, e.g. bad JSON. Example reply: } ``` +##### Status code 404: +The room is unknown to the remote server. Example reply: +```json +{ + "errcode": "M_NOT_FOUND", + "error": "Unknown room" +} +``` + ### `PUT /_matrix/federation/v2/send_knock/{roomId}/{eventId}` Submits a signed knock event to the resident homeserver for it to accept into the room's graph. Note that event format may differ between room versions. From 04cd6b3d3e894a465c308d018adf4e6152232d3c Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Wed, 17 Feb 2021 12:13:44 +0000 Subject: [PATCH 51/72] fix typo Co-authored-by: Hubert Chathi --- proposals/2403-knock.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index fb82adb3de3..b95e6394517 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -580,7 +580,7 @@ join/leave state changes will do the same in a public room, the act of knocking is much lighter than the act of joining a room. In both cases, room admins should employ typical abuse mitigation tools, such -as user bans and server ACLs. Clients are encouraged to ease employing these +as user bans and server ACLs. Clients are encouraged to make employing these tools easy even if the offensive user or server is not present in the room. # Unstable prefix From 74f3b12a1769fcb0ee73107d38e6a69efa8ba9aa Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 17 Feb 2021 12:15:38 +0000 Subject: [PATCH 52/72] Note experimental room version ID --- proposals/2403-knock.md | 1 + 1 file changed, 1 insertion(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index b95e6394517..df6399776c4 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -589,6 +589,7 @@ An unstable feature flag is not required due to this proposal's requirement of a new room version. Clients can check for a room version that includes knocking via the Client-Server API's [capabilities endpoint](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-capabilities). +Experimental implementation should use `xyz.amorgan.knock` as a room version identifier. The new endpoints should contain an unstable prefix during experimental implementation. The unstable counterpart for each endpoint is: From 248a3da5ca6d6861937cf5e95a517e01f1075c65 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 18 Feb 2021 16:49:03 +0000 Subject: [PATCH 53/72] Switch /send_knock/ from v2 to v1; leave a note as to why --- proposals/2403-knock.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index df6399776c4..e1888367264 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -426,16 +426,15 @@ The room is unknown to the remote server. Example reply: } ``` -### `PUT /_matrix/federation/v2/send_knock/{roomId}/{eventId}` +### `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` Submits a signed knock event to the resident homeserver for it to accept into the room's graph. Note that event format may differ between room versions. -While this is a new endpoint, we start off at `v2` to align with the rest of -the `/v2/send_*` endpoints. The switch from `v1` to `v2` occurred as part of -[MSC1802](https://github.com/matrix-org/matrix-doc/pull/1802) and required -that `send_*` endpoints no longer return a redundant HTTP error code in -response bodies. As we do the same here, and for consistency's sake, for -`send_knock` will begin at endpoint `v2` as well. +Note that in the past all `send_*` federation endpoints were updated to `/v2` +to remove a redundant HTTP error code from the return body. While we don't +have the same redundancy here, we start off at `/v1` for this new endpoint +as per +[MSC2844](https://github.com/matrix-org/matrix-doc/pull/2844). Request format: @@ -455,7 +454,7 @@ Response Format: A request could look as follows: ```json -PUT /_matrix/federation/v2/send_knock/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1 +PUT /_matrix/federation/v1/send_knock/%21abc123%3Amatrix.org/%24abc123%3Aexample.org HTTP/1.1 Content-Type: application/json { @@ -611,7 +610,7 @@ S-S make_knock: S-S send_knock: -* `PUT /_matrix/federation/v2/send_knock/{roomId}/{eventId}` +* `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` * `PUT /_matrix/federation/unstable/xyz.amorgan/send_knock/{roomId}/{eventId}` And finally, an unstable prefix is added to the key that comes down `/sync`, From eda65847a3454045d5477b50129ed18ae7dbf570 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 18 Feb 2021 17:07:31 +0000 Subject: [PATCH 54/72] Comment on push rules --- proposals/2403-knock.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index e1888367264..89df3e6957b 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -355,6 +355,22 @@ For backwards compatibility with old servers, if a client does not find a `join_rule` key in a chunk, then it should assume a `join_rule` key with value `public`. +### Push Rules + +To help knocks be noticed earlier, it would be nice to send a push +notification to those in the room who can act on a knock when it +comes in, rather than everyone in the room. This would require a +push rule to fire only when that user's power level is high enough to +accept or reject a knock. + +With the current push rules implementation it is possible to place a +condition on the sender's power level, but unfortunately the same does +not exist for event recipients. + +This MSC thus does not propose any changes to push rules at this time, +but acknowledges that it would be useful for a future MSC to address when +the underlying push rules architecture can support it. + ## Server-Server API Similarly to join and leave over federation, a ping-pong game with two new From 24f61c283cd39f5466e8908955bc3dcf99d9bb31 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 18 Feb 2021 17:11:01 +0000 Subject: [PATCH 55/72] Note that implementations may choose to auto-accept knock-related invites --- proposals/2403-knock.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 89df3e6957b..a7cd6f3ea19 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -112,6 +112,10 @@ The knocking homeserver should assume an invite to a room it has knocked on mean that its knock has been accepted, even if the invite was not explicitly related to the knock attempt. +Note that client or homeserver implementations are free to automatically +accept this invite given they're aware that it's the result of a previous +knock. + ### Membership change to `leave` The knock has been rejected by someone in the room, or the knocking user has From e790ad2120113baec2e2e4cac09f4b6090a23411 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Wed, 24 Feb 2021 18:45:11 +0000 Subject: [PATCH 56/72] Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/2403-knock.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index a7cd6f3ea19..d96d9b175a9 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -9,7 +9,7 @@ This proposal implements the reserved "knock" membership type for the knocks on a room, they are asking for permission to join. Like all membership events, it contains an optional "reason" parameter to specify the reason you want to join. Like other membership types, the parameters "displayname" and -"avatar_url" are optional. This membership can be set from users who aren't +"avatar_url" are optional. This membership can be sent by users who aren't currently in said room. An example for the membership would look like the following: ```json @@ -26,7 +26,8 @@ can decide to reject it instead. ## Restrictions There are restrictions to being able to set this membership, as well as -accepting or denying the knock. +accepting or denying the knock. A formal description of the changes to the auth rules is given below; +first we summarise the semantics of the proposed changes. ### Current membership Only users without a current membership or with their current membership @@ -42,29 +43,28 @@ knocks, a join rule of "knock" is functionally equivalent to that of "invite", except that it additionally allows external users to change their membership to "knock" under certain conditions. -As the join rules are modified, the auth rules are as well. The [current auth -rules](https://matrix.org/docs/spec/rooms/v6#authorization-rules-for-events) are defined -by each room version. To change these rules, the implementation of this -proposal must be done in a new room version. The explicit changes to the auth -rules from room version 5 are: -* Under "5. If type is `m.room.member`", the following will be added: +### Auth rules + +Each room version defines the auth rules which should be applied in that room version. +This MSC proposes a new room version with the following changes to the [auth +rules from room version 6](https://matrix.org/docs/spec/rooms/v6#authorization-rules-for-events): + +* Under "5. If type is `m.room.member`", insert the following after "e. If membership is `ban`": ``` - a. If `membership` is `knock`: + f. If `membership` is `knock`: i. If the `join_rule` is anything other than `knock`, reject. ii. If `sender` does not match `state_key`, reject. iii. If the `sender`'s membership is not `ban`, `knock`, `invite` or `join`, allow. iv. Otherwise, reject. ``` - Note that: - - The `sender` field in the event is set to the user ID of the knocking - user, not any other user in the room that belongs to a homeserver that - the knocking user is using to inject into the room DAG. This is separate - from an invite membership event, where the `sender` is the inviter and +Note that: + - Both the `sender` and `state_key` fields are set to the user ID of the knocking + user. This is different to an `invite` membership event, where the `sender` is the inviter and the `state_key` is the invitee. - - a.ii is justified as one user should not be able to knock on behalf of + - f.ii is justified as one user should not be able to knock on behalf of another user. - a.iii is justified as knocks should not be allowed if the knocking user has been banned from the room, has already knocked on the room, is @@ -95,7 +95,7 @@ Let's talk about each one of these in more detail. The knock has been accepted by someone in the room. The user who is accepting the knock must have the power level to perform -invites. The user's homeserver will then send an invite - over federation if +invites. The accepting user's homeserver will then send an invite - over federation if necessary - to the knocking user. The knocking user may then join the room as if they had been invited normally. @@ -146,7 +146,7 @@ validate the `prev_events` and `auth_events` that the event references. We could send those events over as well, but those will also reference other events that require validation and so on. -A dumb thing we could easily do here is to trust the leave event implicitly +A simple thing we could easily do here is to trust the leave event implicitly if it is sent by the homeserver we originally knocked through. We know this homeserver is (or at least was) in the room, so they're probably telling the truth. This is almost an edge case though, as while you'll knock through one From 49a72862a93d814219968cff814ff63926181645 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Fri, 26 Feb 2021 12:08:14 +0000 Subject: [PATCH 57/72] Allow knock->knock transitions --- proposals/2403-knock.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index d96d9b175a9..5727473448a 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -56,7 +56,7 @@ rules from room version 6](https://matrix.org/docs/spec/rooms/v6#authorization-r f. If `membership` is `knock`: i. If the `join_rule` is anything other than `knock`, reject. ii. If `sender` does not match `state_key`, reject. - iii. If the `sender`'s membership is not `ban`, `knock`, `invite` or `join`, allow. + iii. If the `sender`'s membership is not `ban`, `invite` or `join`, allow. iv. Otherwise, reject. ``` @@ -66,9 +66,9 @@ Note that: the `state_key` is the invitee. - f.ii is justified as one user should not be able to knock on behalf of another user. - - a.iii is justified as knocks should not be allowed if the knocking user - has been banned from the room, has already knocked on the room, is - invited to the room or if they are already in the room. + - f.iii is justified as knocks should not be allowed if the knocking user + has been banned from the room, is invited to the room or if they are already + in the room. - Knocks are not restricted by power level like invites are. The `join_rules` are already used to enforce whether someone can or cannot knock. However, power level rules do apply when approving or denying the knock, as discussed From c9f34e818e145fcc54a28c3859a2dfef94546db4 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Mar 2021 16:50:54 +0000 Subject: [PATCH 58/72] Link to /join/roomIdOrAlias --- proposals/2403-knock.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 5727473448a..5f99c93aa86 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -195,6 +195,10 @@ The newly proposed endpoint requires authentication and can be rate limited. ### `POST /_matrix/client/r0/knock/{roomIdOrAlias}` +Or the knocking equivalent of +[`POST +/_matrix/client/r0/join/{roomIdOrAlias}`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-join-roomidoralias). + The path parameter (`roomIdOrAlias`) is either the room ID or the alias of the room you want to knock on. Additionally several `server_name` parameters can be specified via the query parameters. The post body accepts an optional From c575f88d13e3020fcc35977c616eb81ca48dff34 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Mar 2021 16:53:17 +0000 Subject: [PATCH 59/72] Move endpoint extras under endpoint's header --- proposals/2403-knock.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 5f99c93aa86..e601b7a2255 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -191,16 +191,13 @@ Additionally, extensions to the `GET /_matrix/client/r0/sync` endpoint are introduced. These allow a client to receive information about the status of their knock attempt. -The newly proposed endpoint requires authentication and can be rate limited. - - ### `POST /_matrix/client/r0/knock/{roomIdOrAlias}` Or the knocking equivalent of [`POST /_matrix/client/r0/join/{roomIdOrAlias}`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-join-roomidoralias). The path parameter (`roomIdOrAlias`) is either the room ID or the alias of -the room you want to knock on. Additionally several `server_name` parameters +the room you want to knock on. Additionally, several `server_name` parameters can be specified via the query parameters. The post body accepts an optional string parameter, `reason`, which is the reason you want to join the room. A request could look as follows: @@ -214,6 +211,9 @@ Content-Type: application/json } ``` +This endpoint requires authentication and can be rate limited. + + #### Responses: ##### Status code 200: The user knocked successfully. Example reply: From 53ad7e3f662bab80b94d45e6d752c11d355c9b3c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Mar 2021 17:01:26 +0000 Subject: [PATCH 60/72] Ensure we return the room_id after knocking via the CS API --- proposals/2403-knock.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index e601b7a2255..7b91da870e8 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -216,13 +216,16 @@ This endpoint requires authentication and can be rate limited. #### Responses: ##### Status code 200: -The user knocked successfully. Example reply: +The user knocked successfully. The room ID of the knocked on room is returned. Example +reply: ```json -{} +{ + "room_id": "!ZclcEpFTORTjmWIrqH:matrix.org" +} ``` ##### Status code 403: -The user wasn't allowed to knock (e.g. they are banned). Error reply: +The user wasn't allowed to knock (e.g. they are banned). Example error reply: ```json { "errcode": "M_FORBIDDEN", From 09018be96cb998b06bb4d674be8d9c0edd862a6e Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Mar 2021 17:02:26 +0000 Subject: [PATCH 61/72] Link to existing spec documentation on the public rooms directory --- proposals/2403-knock.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 7b91da870e8..31419a70d7c 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -332,8 +332,9 @@ Response: A problem arises for discovery of knockable rooms. Ideally one wouldn't have to send their colleagues a room ID for a room that they need to knock on. One -of these methods for room discovery is the public rooms directory, which -allows us to explore a list of rooms we may be able to join. +of these methods for room discovery is the [public rooms +directory](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-publicrooms), +which allows us to explore a list of rooms we may be able to join. The spec does not prevent us from adding rooms with 'knock' join_rules to the public rooms directory. However, a user attempting From c915b6442b06384165fbd83eec045aba063e8701 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Mar 2021 17:13:29 +0000 Subject: [PATCH 62/72] Update alternatives section --- proposals/2403-knock.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 31419a70d7c..4e1794dfd14 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -561,11 +561,9 @@ partake in. That is why this proposal enables the a `knock` join rule, in order to allow room admins to opt in to this behaviour. # Alternatives -The two endpoints for the Client-Server API seem redundant, this MSC followed -how JOIN is working currently: One "proper" endpoint (`/rooms/{roomId}/join`) -and one to work properly over federation (`/join/{roomIdOrAlias}`). They -could both be merged into one, however, as that would also affect the join -endpoint it seems out-of-scope for this MSC. +The possibility of initiating a knock by sending EDUs between users instead of sending +a membership state event into a room has been raised. This is an ongoing discussion +occurring at https://github.com/matrix-org/matrix-doc/pull/2403/files#r573180627. # Client UX recommendations After a knock is received in a room, it is expected to be displayed in the From 6556b9523336297593d8e66ed02aba3048c21ef0 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Mar 2021 17:25:17 +0000 Subject: [PATCH 63/72] Move API endpoint sections up to the top of the proposal --- proposals/2403-knock.md | 326 ++++++++++++++++++++-------------------- 1 file changed, 162 insertions(+), 164 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 4e1794dfd14..5bc65e1dc46 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -24,164 +24,6 @@ following: After a knock in a room, a member of the room can invite the knocker, or they can decide to reject it instead. -## Restrictions -There are restrictions to being able to set this membership, as well as -accepting or denying the knock. A formal description of the changes to the auth rules is given below; -first we summarise the semantics of the proposed changes. - -### Current membership -Only users without a current membership or with their current membership -being "leave" can knock on a room. This means that a user that is banned, has -already knocked or is currently in the room cannot knock on it. - -### Join Rules -This proposal makes use of the existing "knock" join rule. The value of -`join_rule` in the content of the `m.room.join_rules` state event for a room -must be set to "knock" for a knock to succeed. This means that existing rooms -will need to opt into allowing knocks in their rooms. Other than allowing -knocks, a join rule of "knock" is functionally equivalent to that of -"invite", except that it additionally allows external users to change their -membership to "knock" under certain conditions. - - -### Auth rules - -Each room version defines the auth rules which should be applied in that room version. -This MSC proposes a new room version with the following changes to the [auth -rules from room version 6](https://matrix.org/docs/spec/rooms/v6#authorization-rules-for-events): - -* Under "5. If type is `m.room.member`", insert the following after "e. If membership is `ban`": - - ``` - f. If `membership` is `knock`: - i. If the `join_rule` is anything other than `knock`, reject. - ii. If `sender` does not match `state_key`, reject. - iii. If the `sender`'s membership is not `ban`, `invite` or `join`, allow. - iv. Otherwise, reject. - ``` - -Note that: - - Both the `sender` and `state_key` fields are set to the user ID of the knocking - user. This is different to an `invite` membership event, where the `sender` is the inviter and - the `state_key` is the invitee. - - f.ii is justified as one user should not be able to knock on behalf of - another user. - - f.iii is justified as knocks should not be allowed if the knocking user - has been banned from the room, is invited to the room or if they are already - in the room. - - Knocks are not restricted by power level like invites are. The `join_rules` - are already used to enforce whether someone can or cannot knock. However, - power level rules do apply when approving or denying the knock, as discussed - in the Membership Changes section below. - -Additionally, note that redactions of knock events are not a concern, as -`membership` keys are excluded from being redacted as defined by all current -room versions. - -## Membership changes -Once someone has sent a `knock` membership into the room, the membership for -that user can be transitioned to the following possible states: - - `invite`: In this case, the knock was accepted by someone inside the room - and they are inviting the knocker into the room. - - `leave`: In this case, similar to how kicks are handled, the knock has - been rejected. Alternatively, the knocking user has rescinded their knock. - - `ban`: In this case, the knock was rejected and the user has been prevented - from sending further knocks. - -Let's talk about each one of these in more detail. - -### Membership change to `invite` - -The knock has been accepted by someone in the room. - -The user who is accepting the knock must have the power level to perform -invites. The accepting user's homeserver will then send an invite - over federation if -necessary - to the knocking user. The knocking user may then join the room as -if they had been invited normally. - -The accept a knock, the client should call [`POST -/_matrix/client/r0/rooms/{roomId}/invite`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-invite) -with the user ID of the knocking user in the JSON body. - -If the knocking user is on another homeserver, then the homeserver of the -accepting user will call [`PUT -/_matrix/federation/v2/invite/{roomId}/{eventId}`](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid) -on the knocking homeserver to inform it that the knock has been accepted. - -The knocking homeserver should assume an invite to a room it has knocked on means -that its knock has been accepted, even if the invite was not explicitly -related to the knock attempt. - -Note that client or homeserver implementations are free to automatically -accept this invite given they're aware that it's the result of a previous -knock. - -### Membership change to `leave` - -The knock has been rejected by someone in the room, or the knocking user has -rescinded their knock. - -To rescind a knock, the knocking user's client must call [`POST -/_matrix/client/r0/rooms/{roomId}/leave`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-leave). - -To reject a knock, the rejecting user's client must call [`POST -/_matrix/client/r0/rooms/{roomId}/kick`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-kick) -with the user ID of the knocking user in the JSON body. Rejecting a knock -over federation has a slight catch, however. - -When the knocking user is on another homeserver, the homeserver of the -rejecting user needs to send the `leave` event over federation to the -knocking homeserver. However, this is a bit tricky as it is currently very -difficult to have events from a room propagate over federation when the -receiving homeserver is not in the room. This is due to the remote homeserver -being unable to verify that the event being sent is actually from a -homeserver in the room - and that the homeserver in the room had the required -power level to send it. This is a problem that currently affects other, -similar operations, such as disinviting or unbanning a federated user. In -both cases, they won't be notified as their homeserver is not in the room. - -While we could send easily send the leave event as part of a generic -transaction to the remote homeserver, that homeserver would have no way to -validate the `prev_events` and `auth_events` that the event references. We -could send those events over as well, but those will also reference other -events that require validation and so on. - -A simple thing we could easily do here is to trust the leave event implicitly -if it is sent by the homeserver we originally knocked through. We know this -homeserver is (or at least was) in the room, so they're probably telling the -truth. This is almost an edge case though, as while you'll knock through one -homeserver in the room, there's no guarantee that the admin that denies your -knock will be on the same homeserver you knocked through. Perhaps the -homeserver you knocked through could listen for this and then send the event -back to you - but what if it goes offline in the meantime? - -As such, informing remote homeservers about the rejection of knocks over -federation is de-scoped for now, and left to a future MSC which can solve -this class of problem in a suitable way. Rejections should still work for the -homeservers that are in the room, as they can validate the leave event for -they have access to the events it references. - - -### Membership change to `ban` - -The knock has been rejected by someone in the room and the user has been -banned, and is unable to send further knocks. - -This one is fairly straightforward. Someone with the appropriate power levels -in the room bans the user. This will have the same effect as rejecting the -knock, and in addition prevent any further knocks by this user from being -allowed into the room. - -If the user is unbanned, they will be able to send a new knock which could be -accepted. - -To ban the user, the client should call [`POST -/_matrix/client/r0/rooms/{roomId}/ban`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-ban) with the user ID of the knocking user in the JSON body. - -Informing the knocking user about the update is the same as rejecting the -knock. - - ## Client-Server API A new endpoint is introduced in the Client-Server API: `POST /_matrix/client/r0/knock/{roomIdOrAlias}`. This allows the client to state @@ -216,7 +58,7 @@ This endpoint requires authentication and can be rate limited. #### Responses: ##### Status code 200: -The user knocked successfully. The room ID of the knocked on room is returned. Example +The user knocked successfully. The room ID of the knocked on room is returned. Example reply: ```json { @@ -372,12 +214,12 @@ value `public`. To help knocks be noticed earlier, it would be nice to send a push notification to those in the room who can act on a knock when it comes in, rather than everyone in the room. This would require a -push rule to fire only when that user's power level is high enough to +push rule to fire only when that user's power level is high enough to accept or reject a knock. With the current push rules implementation it is possible to place a condition on the sender's power level, but unfortunately the same does -not exist for event recipients. +not exist for event recipients. This MSC thus does not propose any changes to push rules at this time, but acknowledges that it would be useful for a future MSC to address when @@ -385,9 +227,10 @@ the underlying push rules architecture can support it. ## Server-Server API -Similarly to join and leave over federation, a ping-pong game with two new -endpoints is introduced: `make_knock` and `send_knock`. Both endpoints must -be protected via server ACLs. +Similarly to [join](https://matrix.org/docs/spec/server_server/r0.1.4#joining-rooms) +and [leave](https://matrix.org/docs/spec/server_server/r0.1.4#leaving-rooms-rejecting-invites) +over federation, a ping-pong game with two new endpoints is introduced: `make_knock` +and `send_knock`. Both endpoints must be protected via server ACLs. ### `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` @@ -555,6 +398,161 @@ request content. } ``` +## Restrictions +There are restrictions to being able to set this membership, as well as +accepting or denying the knock. A formal description of the changes to the auth rules is given below; +first we summarise the semantics of the proposed changes. + +### Current membership +Only users without a current membership or with their current membership +being "leave" can knock on a room. This means that a user that is banned, has +already knocked or is currently in the room cannot knock on it. + +### Join Rules +This proposal makes use of the existing "knock" join rule. The value of +`join_rule` in the content of the `m.room.join_rules` state event for a room +must be set to "knock" for a knock to succeed. This means that existing rooms +will need to opt into allowing knocks in their rooms. Other than allowing +knocks, a join rule of "knock" is functionally equivalent to that of +"invite", except that it additionally allows external users to change their +membership to "knock" under certain conditions. + +### Auth rules + +Each room version defines the auth rules which should be applied in that room version. +This MSC proposes a new room version with the following changes to the [auth +rules from room version 6](https://matrix.org/docs/spec/rooms/v6#authorization-rules-for-events): + +* Under "5. If type is `m.room.member`", insert the following after "e. If membership is `ban`": + + ``` + f. If `membership` is `knock`: + i. If the `join_rule` is anything other than `knock`, reject. + ii. If `sender` does not match `state_key`, reject. + iii. If the `sender`'s membership is not `ban`, `invite` or `join`, allow. + iv. Otherwise, reject. + ``` + +Note that: + - Both the `sender` and `state_key` fields are set to the user ID of the knocking + user. This is different to an `invite` membership event, where the `sender` is the inviter and + the `state_key` is the invitee. + - f.ii is justified as one user should not be able to knock on behalf of + another user. + - f.iii is justified as knocks should not be allowed if the knocking user + has been banned from the room, is invited to the room or if they are already + in the room. + - Knocks are not restricted by power level like invites are. The `join_rules` + are already used to enforce whether someone can or cannot knock. However, + power level rules do apply when approving or denying the knock, as discussed + in the Membership Changes section below. + +Additionally, note that redactions of knock events are not a concern, as +`membership` keys are excluded from being redacted as defined by all current +room versions. + +## Membership changes +Once someone has sent a `knock` membership into the room, the membership for +that user can be transitioned to the following possible states: + - `invite`: In this case, the knock was accepted by someone inside the room + and they are inviting the knocker into the room. + - `leave`: In this case, similar to how kicks are handled, the knock has + been rejected. Alternatively, the knocking user has rescinded their knock. + - `ban`: In this case, the knock was rejected and the user has been prevented + from sending further knocks. + +Let's talk about each one of these in more detail. + +### Membership change to `invite` + +The knock has been accepted by someone in the room. + +The user who is accepting the knock must have the power level to perform +invites. The accepting user's homeserver will then send an invite - over federation if +necessary - to the knocking user. The knocking user may then join the room as +if they had been invited normally. + +To accept a knock, the client should call [`POST +/_matrix/client/r0/rooms/{roomId}/invite`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-invite) +with the user ID of the knocking user in the JSON body. + +If the knocking user is on another homeserver, then the homeserver of the +accepting user will call [`PUT +/_matrix/federation/v2/invite/{roomId}/{eventId}`](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid) +on the knocking homeserver to inform it that the knock has been accepted. + +The knocking homeserver should assume an invite to a room it has knocked on means +that its knock has been accepted, even if the invite was not explicitly +related to the knock attempt. + +Note that client or homeserver implementations are free to automatically +accept this invite given they're aware that it's the result of a previous +knock. + +### Membership change to `leave` + +The knock has been rejected by someone in the room, or the knocking user has +rescinded their knock. + +To rescind a knock, the knocking user's client must call [`POST +/_matrix/client/r0/rooms/{roomId}/leave`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-leave). + +To reject a knock, the rejecting user's client must call [`POST +/_matrix/client/r0/rooms/{roomId}/kick`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-kick) +with the user ID of the knocking user in the JSON body. Rejecting a knock +over federation has a slight catch, however. + +When the knocking user is on another homeserver, the homeserver of the +rejecting user needs to send the `leave` event over federation to the +knocking homeserver. However, this is a bit tricky as it is currently very +difficult to have events from a room propagate over federation when the +receiving homeserver is not in the room. This is due to the remote homeserver +being unable to verify that the event being sent is actually from a +homeserver in the room - and that the homeserver in the room had the required +power level to send it. This is a problem that currently affects other, +similar operations, such as disinviting or unbanning a federated user. In +both cases, they won't be notified as their homeserver is not in the room. + +While we could send easily send the leave event as part of a generic +transaction to the remote homeserver, that homeserver would have no way to +validate the `prev_events` and `auth_events` that the event references. We +could send those events over as well, but those will also reference other +events that require validation and so on. + +A simple thing we could easily do here is to trust the leave event implicitly +if it is sent by the homeserver we originally knocked through. We know this +homeserver is (or at least was) in the room, so they're probably telling the +truth. This is almost an edge case though, as while you'll knock through one +homeserver in the room, there's no guarantee that the admin that denies your +knock will be on the same homeserver you knocked through. Perhaps the +homeserver you knocked through could listen for this and then send the event +back to you - but what if it goes offline in the meantime? + +As such, informing remote homeservers about the rejection of knocks over +federation is de-scoped for now, and left to a future MSC which can solve +this class of problem in a suitable way. Rejections should still work for the +homeservers that are in the room, as they can validate the leave event for +they have access to the events it references. + +### Membership change to `ban` + +The knock has been rejected by someone in the room and the user has been +banned, and is unable to send further knocks. + +This one is fairly straightforward. Someone with the appropriate power levels +in the room bans the user. This will have the same effect as rejecting the +knock, and in addition prevent any further knocks by this user from being +allowed into the room. + +If the user is unbanned, they will be able to send a new knock which could be +accepted. + +To ban the user, the client should call [`POST +/_matrix/client/r0/rooms/{roomId}/ban`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-ban) with the user ID of the knocking user in the JSON body. + +Informing the knocking user about the update is the same as rejecting the +knock. + # Potential issues This new feature would allow users to send events into rooms that they don't partake in. That is why this proposal enables the a `knock` join rule, in From ef840c1b537933817cc9eca41aa508802690b948 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Mar 2021 17:33:26 +0000 Subject: [PATCH 64/72] Split the 'Membership change to ' section into rejecting/rescinding knocks --- proposals/2403-knock.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 5bc65e1dc46..0930fe7eff1 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -489,18 +489,14 @@ Note that client or homeserver implementations are free to automatically accept this invite given they're aware that it's the result of a previous knock. -### Membership change to `leave` +### Membership change to `leave` via rejecting a knock -The knock has been rejected by someone in the room, or the knocking user has -rescinded their knock. - -To rescind a knock, the knocking user's client must call [`POST -/_matrix/client/r0/rooms/{roomId}/leave`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-leave). +The knock has been rejected by someone in the room. To reject a knock, the rejecting user's client must call [`POST /_matrix/client/r0/rooms/{roomId}/kick`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-kick) with the user ID of the knocking user in the JSON body. Rejecting a knock -over federation has a slight catch, however. +over federation has a slight catch, though. When the knocking user is on another homeserver, the homeserver of the rejecting user needs to send the `leave` event over federation to the @@ -534,6 +530,16 @@ this class of problem in a suitable way. Rejections should still work for the homeservers that are in the room, as they can validate the leave event for they have access to the events it references. +### Membership change to `leave` via rescinding a knock +The knocking user has rescinded their knock. + +To rescind a knock, the knocking user's client must call [`POST +/_matrix/client/r0/rooms/{roomId}/leave`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-leave). +To rescind a knock over federation, the knocking homeserver must complete +a [`make_leave`, `send_leave` dance]( +https://matrix.org/docs/spec/server_server/r0.1.4#leaving-rooms-rejecting-invites) +with a homeserver in the room. + ### Membership change to `ban` The knock has been rejected by someone in the room and the user has been From 8bfef19a3961e73b6250bb58472db6c45080d4f5 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 3 Mar 2021 17:35:49 +0000 Subject: [PATCH 65/72] Remove further traces of old /rooms/roomId/knock CS endpoint --- proposals/2403-knock.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 0930fe7eff1..3fc65557ae9 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -623,12 +623,7 @@ Experimental implementation should use `xyz.amorgan.knock` as a room version ide The new endpoints should contain an unstable prefix during experimental implementation. The unstable counterpart for each endpoint is: -C-S knock method 1: - -* `POST /_matrix/client/r0/rooms/{roomId}/knock` -* `POST /_matrix/client/unstable/xyz.amorgan/rooms/{roomId}/knock` - -C-S knock method 2: +C-S knock: * `POST /_matrix/client/knock/{roomIdOrAlias}` * `POST /_matrix/client/unstable/xyz.amorgan/knock/{roomIdOrAlias}` @@ -643,7 +638,7 @@ S-S send_knock: * `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` * `PUT /_matrix/federation/unstable/xyz.amorgan/send_knock/{roomId}/{eventId}` -And finally, an unstable prefix is added to the key that comes down `/sync`, +Finally, an unstable prefix is added to the key that comes down `/sync`, the join rule for rooms and the `content.membership` key of the member event sent into rooms when a user has knocked successfully. Instead of `knock`, experimental implementations should use `xyz.amorgan.knock`. From 68d2d7cfdb6e94fd0e3a2cf5f79fd8e91d972de8 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Tue, 9 Mar 2021 17:16:25 +0000 Subject: [PATCH 66/72] Note that homeservers should pass down invites to the client if they fail on autojoin --- proposals/2403-knock.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 3fc65557ae9..5252a32e24a 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -487,7 +487,10 @@ related to the knock attempt. Note that client or homeserver implementations are free to automatically accept this invite given they're aware that it's the result of a previous -knock. +knock. In case of failing to auto-accept an invite on the homeserver, it's +recommended for homeservers to pass the invite down to the client so that it +may try at a later point (or reject the potentially broken invite) at the user's +discretion. ### Membership change to `leave` via rejecting a knock From 7f0b2d66a0f02056a526d85803be625ff6a0ae0c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Tue, 23 Mar 2021 12:23:40 +0000 Subject: [PATCH 67/72] Update unstable endpoints from i.e xyz.amorgan/knock -> xyz.amorgan.knock I'm doing this for two reasons: 1) If I ever wanted to create another knock-related MSC, it would be nice to be able to give it a different namespace for endpoints, such as xyz.amorgan.knock2/knock. If we were only using xyz.amorgan as the namespace for endpoints, that restricts that namespace to only work for one MSC which attempts to use /knock as part of an endpoint. 2) I accidentally made the implementation use xyz.amorgan.knock/knock :) --- proposals/2403-knock.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 5252a32e24a..a161e01df81 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -629,17 +629,17 @@ implementation. The unstable counterpart for each endpoint is: C-S knock: * `POST /_matrix/client/knock/{roomIdOrAlias}` -* `POST /_matrix/client/unstable/xyz.amorgan/knock/{roomIdOrAlias}` +* `POST /_matrix/client/unstable/xyz.amorgan.knock/knock/{roomIdOrAlias}` S-S make_knock: * `GET /_matrix/federation/v1/make_knock/{roomId}/{userId}` -* `GET /_matrix/federation/unstable/xyz.amorgan/make_knock/{roomId}/{userId}` +* `GET /_matrix/federation/unstable/xyz.amorgan.knock/make_knock/{roomId}/{userId}` S-S send_knock: * `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` -* `PUT /_matrix/federation/unstable/xyz.amorgan/send_knock/{roomId}/{eventId}` +* `PUT /_matrix/federation/unstable/xyz.amorgan.knock/send_knock/{roomId}/{eventId}` Finally, an unstable prefix is added to the key that comes down `/sync`, the join rule for rooms and the `content.membership` key of the member From a1a40c63465d5147a7dfbdd8bb781fee3e66df05 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Tue, 23 Mar 2021 18:17:47 +0000 Subject: [PATCH 68/72] Be consistent about event auth rules --- proposals/2403-knock.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index a161e01df81..614b9eddb05 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -405,8 +405,8 @@ first we summarise the semantics of the proposed changes. ### Current membership Only users without a current membership or with their current membership -being "leave" can knock on a room. This means that a user that is banned, has -already knocked or is currently in the room cannot knock on it. +set to "knock" or "leave" can knock on a room. This means that a user that +is banned, is invited or is currently in the room cannot knock on it. ### Join Rules This proposal makes use of the existing "knock" join rule. The value of From 11996fb4364376684b87ca8beb2b42866029bc37 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 24 Mar 2021 16:20:19 +0000 Subject: [PATCH 69/72] clarify some words --- proposals/2403-knock.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 614b9eddb05..cd89fe23a37 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -98,7 +98,8 @@ the room's name and avatar. A client will need this information to show a nice representation of pending knocked rooms. The recommended events to include are the join rules, canonical alias, avatar, name and encryption state of the room, rather than all room state. This behaviour matches the -information sent to remote homeservers when invited their users to a room. +information sent to remote homeservers when remote users are invited to a +room. This prevents unneeded state from the room leaking out, and also speeds things up (think not sending over hundreds of membership events from big From 10267df76eec6c6a77ccb69890e6b6eaf81ba6f8 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 24 Mar 2021 16:33:13 +0000 Subject: [PATCH 70/72] Add missing 403/404 response codes --- proposals/2403-knock.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index cd89fe23a37..9972c04c40b 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -75,6 +75,15 @@ The user wasn't allowed to knock (e.g. they are banned). Example error reply: } ``` +##### Status code 404: +The room was not found. Example error reply: +```json +{ + "errcode": "M_NOT_FOUND", + "error": "Unknown room." +} +``` + ### Extensions to `GET /_matrix/client/r0/sync` In [the response to @@ -289,6 +298,15 @@ This request was invalid, e.g. bad JSON. Example reply: } ``` +##### Status code 403: +This request is forbidden, e.g. the user is banned from the room. Example reply: +```json +{ + "errcode": "M_FORBIDDEN", + "error": "You are not allowed to knock on this room" +} +``` + ##### Status code 404: The room is unknown to the remote server. Example reply: ```json @@ -399,6 +417,24 @@ request content. } ``` +##### Status code 403: +This request is forbidden, e.g. the user is banned from the room. Example reply: +```json +{ + "errcode": "M_FORBIDDEN", + "error": "You are not allowed to knock on this room" +} +``` + +##### Status code 404: +The room is unknown to the remote server. Example reply: +```json +{ + "errcode": "M_NOT_FOUND", + "error": "Unknown room" +} +``` + ## Restrictions There are restrictions to being able to set this membership, as well as accepting or denying the knock. A formal description of the changes to the auth rules is given below; From 9ebfd98a7a912309375c54c0108e49920910006b Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Wed, 24 Mar 2021 16:33:47 +0000 Subject: [PATCH 71/72] Apply suggestions from code review Co-authored-by: Alexey Rusakov --- proposals/2403-knock.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index 9972c04c40b..e96705ea50c 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -549,7 +549,7 @@ power level to send it. This is a problem that currently affects other, similar operations, such as disinviting or unbanning a federated user. In both cases, they won't be notified as their homeserver is not in the room. -While we could send easily send the leave event as part of a generic +While we could easily send the leave event as part of a generic transaction to the remote homeserver, that homeserver would have no way to validate the `prev_events` and `auth_events` that the event references. We could send those events over as well, but those will also reference other @@ -601,7 +601,7 @@ knock. # Potential issues This new feature would allow users to send events into rooms that they don't -partake in. That is why this proposal enables the a `knock` join rule, in +partake in. That is why this proposal enables the `knock` join rule, in order to allow room admins to opt in to this behaviour. # Alternatives From a8f4ada8a843ee89fdcc272b1489ea81471b59d0 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 24 Mar 2021 16:49:57 +0000 Subject: [PATCH 72/72] Make join_rules field of PublicRoomChunk an optional value --- proposals/2403-knock.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/proposals/2403-knock.md b/proposals/2403-knock.md index e96705ea50c..8bad17662ae 100644 --- a/proposals/2403-knock.md +++ b/proposals/2403-knock.md @@ -209,15 +209,14 @@ contain this information: } ``` -Therefore this proposal adds `join_rule` as a new, required field to a -`PublicRoomsChunk`. The `join_rule` of knockable rooms will be `knock`, thus -giving clients the information they need to attempt entry of -a room when a client selects it. It also allows clients to display +Therefore this proposal adds `join_rule` as a new, optional field to a +`PublicRoomsChunk`. The `join_rule` of knockable rooms will be `knock`, +thus giving clients the information they need to attempt entry of a +room when a client selects it. It also allows clients to display knockable rooms differently than publicly joinable ones. -For backwards compatibility with old servers, if a client does not find a -`join_rule` key in a chunk, then it should assume a `join_rule` key with -value `public`. +For backwards compatibility with old servers, the default value of +`join_rule` is `public`. ### Push Rules