diff --git a/event-schemas/examples/v1/m.room.member b/event-schemas/examples/v1/m.room.member index 279eb484..a5ab79b5 100644 --- a/event-schemas/examples/v1/m.room.member +++ b/event-schemas/examples/v1/m.room.member @@ -4,11 +4,13 @@ "membership": "join", "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto", "displayname": "Alice Margatroid", - "token": "pc98", - "public_key": "abc123", - "key_validity_url": "https://magic.forest/verifykey", - "signature": "q1w2e3", - "sender": "@zun:zun.soft" + "third_party_invite": { + "token": "pc98", + "public_key": "abc123", + "key_validity_url": "https://magic.forest/verifykey", + "signature": "q1w2e3", + "sender": "@zun:zun.soft" + } }, "state_key": "@alice:localhost", "origin_server_ts": 1431961217939, diff --git a/event-schemas/schema/v1/m.room.member b/event-schemas/schema/v1/m.room.member index 47ce4d6c..56104328 100644 --- a/event-schemas/schema/v1/m.room.member +++ b/event-schemas/schema/v1/m.room.member @@ -22,26 +22,33 @@ "type": ["string", "null"], "description": "The display name for this user, if any. This is added by the homeserver." }, - "token": { - "type": "string", - "description": "A token which must be correctly signed, in order to join the room." - }, - "key_validity_url": { - "type": "string", - "description": "A URL which can be fetched, with querystring public_key=public_key, to validate whether the key has been revoked. The URL must return a JSON object containing a boolean property named 'valid'." - }, - "public_key": { - "type": "string", - "description": "A base64-encoded ed25519 key with which token must be signed." - }, - "signature": { - "type": "string", - "description": "A base64-encoded signature of token with public_key." - }, - "sender": { - "type": "string", - "description": "The matrix user ID of the user who send the invite which is being used." - } + "third_party_invite": { + "type": "object", + "title": "invite", + "properties": { + "token": { + "type": "string", + "description": "A token which must be correctly signed, in order to join the room." + }, + "key_validity_url": { + "type": "string", + "description": "A URL which can be fetched, with querystring public_key=public_key, to validate whether the key has been revoked. The URL must return a JSON object containing a boolean property named 'valid'." + }, + "public_key": { + "type": "string", + "description": "A base64-encoded ed25519 key with which token must be signed." + }, + "signature": { + "type": "string", + "description": "A base64-encoded signature of token with public_key." + }, + "sender": { + "type": "string", + "description": "The matrix user ID of the user who send the invite which is being used." + } + }, + "required": ["token", "key_validity_url", "public_key", "signature", "sender"] + } }, "required": ["membership"] }, diff --git a/specification/modules/third_party_invites.rst b/specification/modules/third_party_invites.rst index ae0d74e8..3f5a38a4 100644 --- a/specification/modules/third_party_invites.rst +++ b/specification/modules/third_party_invites.rst @@ -7,6 +7,22 @@ This module adds in support for inviting new members to a room where their Matrix user ID is not known, instead addressing them by a third party identifier such as an email address. +There are two flows here; one if a Matrix user ID is known for the third party +identifier, and one if not. Either way, the client calls /invite with the +details of the third party identifier. + +The homeserver asks the identity server whether a Matrix user ID is known for +that identifier. If it is, an invite is simply issued for that user. + +If it is not, the homeserver asks the identity server to record the details of +the invitation, and to notify the client of this pending invitation if it gets +a binding for this identifier in the future. The identity server returns to the +homeserver a token, as well as its public key. + +If a client then tries to join the room in the future, it will be allowed to if +it presents both the token, and a signature of that token from the identity +server which can be verified with the public key. + Events ------ @@ -17,23 +33,47 @@ Client behaviour A client asks a server to invite a user by their third party identifier. -See the documentation for /invite for more information. - Server behaviour ---------------- -All homeservers MUST verify that sign(``token``, ``public_key``) = ``signature``. +All homeservers MUST verify that sig(``token``, ``public_key``) = ``signature``. If a client of the current homeserver is joining by an ``m.room.third_party_invite``, that homesever MUST validate that the public -key used for signing is still valid, by checking ``key_validity_url``. +key used for signing is still valid, by checking ``key_validity_url``. It does +this by making an HTTP GET request to ``key_validity_url``, with the querystring +?public_key=``public_key``. A JSON object will be returned, and the key is +considered valid if the object contains a key named ``valid`` whose value is +``true``. If this cannot be verified, the invitation must be rejected. If a homeserver is joining a room for the first time because of an ``m.room.third_party_invite``, the server which is already participating in the room MUST validate that the public key used for signing is still valid, by -checking ``key_validity_url``. +checking ``key_validity_url`` in the above described way. No other homeservers may reject the joining of the room on the basis of ``key_validity_url``, this is so that all homeservers have a consistent view of -the room. +the room. They may, however, indicate to their clients that a member's' +membership is questionable. + +For example: + +If room R has two participating homeservers, H1, H2 + +And user A on H1 invites a third party identifier to room R + +H1 asks the identity server for a binding to a Matrix user ID, and has none, +so issues an ``m.room.third_party_invite`` event to the room. + +When the third party user validates their identity, they are told about the +invite, and ask their homeserver, H3, to join the room. + +H3 validates that sign(``token``, ``public_key``) = ``signature``, and may check +``key_validity_url``. + +H3 then asks H1 to join it to the room. H1 *must* validate that +sign(``token``, ``public_key``) = ``signature`` *and* check ``key_validity_url``. + +Having validated these things, H1 writes the join event to the room, and H3 +begins participating in the room. H2 *must* accept this event.