From 997e76fcf7a5fa984dd70e78a580b38f2654d4ef Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Wed, 13 Sep 2017 19:27:36 +0100 Subject: [PATCH 1/8] Update JSON body for 3PID onbind requests --- specification/identity_service_api.rst | 34 ++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/specification/identity_service_api.rst b/specification/identity_service_api.rst index 36f4c3d4..fa03e162 100644 --- a/specification/identity_service_api.rst +++ b/specification/identity_service_api.rst @@ -239,19 +239,27 @@ At a later point, if the owner of that particular 3pid binds it with a Matrix us Content-Type: application/json { - "invites": [{ - "mxid": "@foo:bar.com", - "token": "abc123", - "signatures": { - "my.id.server": { - "ed25519:0": "def987" - } - } - }], - - "medium": "email", - "address": "foo@bar.com", - "mxid": "@foo:bar.com" + "medium": "email", + "address": "foo@bar.baz", + "mxid": "@alice:example.tld", + "invites": [ + { + "medium": "email", + "address": "foo@bar.baz", + "mxid": "@alice:example.tld", + "room_id": "!something:example.tld", + "sender": "@bob:example.tld", + "signed": { + "mxid": "@alice:example.tld", + "signatures": { + "vector.im": { + "ed25519:0": "somesignature" + } + }, + "token": "sometoken" + } + } + ] } Where the signature is produced using a long-term private key. From af961321e9577efa8fe6eecebe96a5a5c6831e56 Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Thu, 14 Sep 2017 19:13:36 +0100 Subject: [PATCH 2/8] Specify remote invite --- specification/server_server_api.rst | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index cb76c3d5..3f8a2c60 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -749,6 +749,64 @@ that requested by the requestor in the ``v`` parameter). Specify (or remark that it is unspecified) how the server handles divergent history. DFS? BFS? Anything weirder? +Inviting to a room +------------------ + +When a user wishes to invite an other user to a local room and this other user +is on a different server, the inviting server will send a request to the invited +server:: + + PUT .../invite/{roomId}/{eventId} + +The required fields in the JSON body are: + +==================== ======== ============ + Key Type Description +==================== ======== ============ +``room_id`` String The room ID of the room. Must be the same as the + room ID specified in the path. +``event_id`` String The ID of the event. Must be the same as the event + ID specified in the path. +``type`` String The value ``m.room.member``. +``auth_events`` List An event-reference list containing the IDs of the + authorization events that would allow this member + to be invited in the room. +``content`` Object The content of the event. +``depth`` Integer The depth of the event. +``origin`` String The name of the inviting homeserver. +``origin_server_ts`` Integer A timestamp added by the inviting homeserver. +``prev_events`` List An event-reference list containing the IDs of the + immediate predecessor events. +``sender`` String The Matrix ID of the user who sent the original + `m.room.third_party_invite`. +``state_key`` String The Matrix ID of the invited user. +``signatures`` Object The signature of the event from the origin server. +``unsigned`` Object An object containing the properties that aren't + part of the signature's computation. +==================== ======== ============ + +Where the ``content`` key contains the content for the ``m.room.member`` event +specified in the `Client-Server API`_. Note that the ``membership`` property of +the content must be ``invite``. + +Upon receiving this request, the invited homeserver will append its signature to +the event and respond to the request with the following JSON body:: + + [ + 200, + "event": {...} + ] + +Where ``event`` contains the event signed by both homeservers, using the same +JSON keys as the initial request on ``/invite/{roomId}/{eventId}``. Note that, +except for the ``signatures`` object (which now contains an additional signature), +all of the event's keys remain the same as in the event initially provided. + +This response format is due to a typo in Synapse, the first implementation of +Matrix's APIs, and is preserved to maintain compatibility. + +Now that the event has been signed by both the inviting homeserver and the +invited homeserver, it can be sent to all of the users in the room. Authentication -------------- @@ -1143,5 +1201,8 @@ that are too long. [[TODO(markjh) We might want to allow the server to omit the output of well known hash functions like SHA-256 when none of the keys have been redacted]] + +.. _`Invitation storage`: ../identity_service/unstable.html#invitation-storage +.. _`Client-Server API`: ../client_server/unstable.html#m-room-member .. _`Canonical JSON`: ../appendices.html#canonical-json .. _`Unpadded Base64`: ../appendices.html#unpadded-base64 From 9d90fa2caea6201e834da4d9c6a7b557d3179987 Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Thu, 14 Sep 2017 19:44:40 +0100 Subject: [PATCH 3/8] Specify third-party invites --- specification/server_server_api.rst | 102 ++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 3f8a2c60..65186e0b 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -808,6 +808,107 @@ Matrix's APIs, and is preserved to maintain compatibility. Now that the event has been signed by both the inviting homeserver and the invited homeserver, it can be sent to all of the users in the room. +Third-party invites +------------------- + +When an user wants to invite another user in a room but doesn't know the Matrix +ID to invite, they can do so using a third-party identifier (e.g. an e-mail or a +phone number). + +This identifier and its bindings to Matrix IDs are verified by an identity server +implementing the `Identity Service API`_. + +.. _`Identity Service API`: ../identity_service/unstable.html + +Cases where an association exists for a third-party identifier +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the third-party identifier is already bound to a Matrix ID, a lookup request +on the identity server will return it. The invite is then processed by the inviting +homeserver as a standard ``m.room.member`` invite event. This is the simplest case. + +Cases where an association doesn't exist for a third-party identifier +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the third-party identifier isn't bound to any Matrix ID, the inviting +homeserver will request the identity server to store an invite for this identifier +and to deliver it to whoever binds it to its Matrix ID. It will also send a +``m.room.third_party_invite`` event in the room to specify a display name, a token +and public keys the identity server provided as a response to the invite storage +request. + +When a third-party identifier with pending invites gets bound to a Matrix ID, +the identity server will send a ``POST`` request to the ID's homeserver as described +in the `Invitation Storage`_ section of the Identity Service API. + +The following process applies for each invite sent by the identity server: + +The invited homeserver will create a ``m.room.member`` invite event containing +a special ``third_party_invite`` section containing the token and a signed object, +both provided by the identity server. + +If the invited homeserver is in the room the invite came from, it can auth the +event and send it. + +However, if the invited homeserver isn't in the room the invite came from, it +will need to request the room's homeserver to auth the event:: + + PUT .../exchange_third_party_invite/{roomId} + +Where ``roomId`` is the ID of the room the invite is for. + +The required fields in the JSON body are: + +==================== ======= ================================================== + Key Type Description +==================== ======= ================================================== +``type`` String The event type. Must be `m.room.member`. +``room_id`` String The ID of the room the event is for. Must be the + same as the ID specified in the path. +``sender`` String The Matrix ID of the user who sent the original + `m.room.third_party_invite`. +``state_key`` String The Matrix ID of the invited user. +``content`` Object The content of the event. +==================== ======= ================================================== + +Where the ``content`` key contains the content for the ``m.room.member`` event +as described in the `Client-Server API`_. Its ``membership`` key must be +``invite`` and its content must include the ``third_party_invite`` object. + +The inviting homeserver will then be able to authenticate the event. It will send +a fully authenticated event to the invited homeserver as described in the `Inviting +to a room`_ section above. + +Once the invited homeserver responded with the event to which it appended its +signature, the inviting homeserver will respond with ``200 OK`` and an empty body +(``{}``) to the initial request on ``/exchange_third_party_invite/{roomId}`` and +send the now verified ``m.room.member`` invite event to the room's members. + +Verifying the invite +++++++++++++++++++++ + +When a homeserver receives a ``m.room.member`` invite event for a room it's in +with a ``third_party_invite`` object, it must verify that the association between +the third-party identifier initially invited to the room and the Matrix ID that +claim to be bound to it has been verified without having to rely on a third-party +server. + +To do so, it will fetch from the room's state events the ``m.room.third_party_invite`` +event for which the state key matches with the value for the ``token`` key in the +``third_party_invite`` object from the ``m.room.member`` event's content to fetch the +public keys initially delivered by the identity server that stored the invite. + +It will then use these keys to verify that the ``signed`` object (in the +``third_party_invite`` object from the ``m.room.member`` event's content) was +signed by the same identity server. + +Since this ``signed`` object can only be delivered once in the ``POST`` request +emitted by the identity server upon binding between the third-party identifier +and the Matrix ID, and contains the invited user's Matrix ID and the token +delivered when the invite was stored, this verification will prove that the +``m.room.member`` invite event comes from the user owning the invited third-party +identifier. + Authentication -------------- @@ -1204,5 +1305,6 @@ that are too long. .. _`Invitation storage`: ../identity_service/unstable.html#invitation-storage .. _`Client-Server API`: ../client_server/unstable.html#m-room-member +.. _`Inviting to a room`: #inviting-to-a-room .. _`Canonical JSON`: ../appendices.html#canonical-json .. _`Unpadded Base64`: ../appendices.html#unpadded-base64 From 4a9969110827266963e713740ab623d664861c2e Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Thu, 14 Sep 2017 19:48:43 +0100 Subject: [PATCH 4/8] Move link to the bottom of the file --- specification/server_server_api.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 65186e0b..3f7957d6 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -818,8 +818,6 @@ phone number). This identifier and its bindings to Matrix IDs are verified by an identity server implementing the `Identity Service API`_. -.. _`Identity Service API`: ../identity_service/unstable.html - Cases where an association exists for a third-party identifier ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1304,6 +1302,7 @@ that are too long. .. _`Invitation storage`: ../identity_service/unstable.html#invitation-storage +.. _`Identity Service API`: ../identity_service/unstable.html .. _`Client-Server API`: ../client_server/unstable.html#m-room-member .. _`Inviting to a room`: #inviting-to-a-room .. _`Canonical JSON`: ../appendices.html#canonical-json From 94374c696bc8c03244ee3c490d01c75040b009dd Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Thu, 14 Sep 2017 19:51:23 +0100 Subject: [PATCH 5/8] Update changelog --- changelogs/client_server.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelogs/client_server.rst b/changelogs/client_server.rst index b5f31209..7fe0b030 100644 --- a/changelogs/client_server.rst +++ b/changelogs/client_server.rst @@ -51,6 +51,10 @@ - Spec clarifications: + - Add endpoints and logic for invites and third-party invites to the federation + spec and update the JSON of the request sent by the identity server upon 3PID + binding + (`#997 `) - Fix response format and 404 example for room alias lookup (`#960 `) - Fix examples of ``m.room.member`` event and room state change, From c71575c94d38650b8e30817ea5c40a1be3779a70 Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Thu, 14 Sep 2017 19:53:11 +0100 Subject: [PATCH 6/8] Remove useless blank line --- specification/server_server_api.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 3f7957d6..4bcb8cbc 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -1300,7 +1300,6 @@ that are too long. [[TODO(markjh) We might want to allow the server to omit the output of well known hash functions like SHA-256 when none of the keys have been redacted]] - .. _`Invitation storage`: ../identity_service/unstable.html#invitation-storage .. _`Identity Service API`: ../identity_service/unstable.html .. _`Client-Server API`: ../client_server/unstable.html#m-room-member From 8de93147b14ade39666a869f5dbd1fdd6592921c Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Fri, 15 Sep 2017 16:57:05 +0100 Subject: [PATCH 7/8] Typo --- specification/server_server_api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 4bcb8cbc..23d684a1 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -888,7 +888,7 @@ Verifying the invite When a homeserver receives a ``m.room.member`` invite event for a room it's in with a ``third_party_invite`` object, it must verify that the association between the third-party identifier initially invited to the room and the Matrix ID that -claim to be bound to it has been verified without having to rely on a third-party +claims to be bound to it has been verified without having to rely on a third-party server. To do so, it will fetch from the room's state events the ``m.room.third_party_invite`` From 6b6a941e3614a0e0c0408ee0096363a68e2c596b Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Fri, 15 Sep 2017 16:58:34 +0100 Subject: [PATCH 8/8] Phrasing --- specification/server_server_api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 23d684a1..eb863e74 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -752,7 +752,7 @@ that requested by the requestor in the ``v`` parameter). Inviting to a room ------------------ -When a user wishes to invite an other user to a local room and this other user +When a user wishes to invite an other user to a local room and the other user is on a different server, the inviting server will send a request to the invited server::