Merge pull request #1505 from turt2live/travis/general/3pid_invite
Clarify how third party invites work
This commit is contained in:
commit
38ae166e9d
5 changed files with 279 additions and 52 deletions
|
@ -69,7 +69,8 @@ paths:
|
|||
get:
|
||||
summary: Check whether a long-term public key is valid.
|
||||
description: |-
|
||||
Check whether a long-term public key is valid.
|
||||
Check whether a long-term public key is valid. The response should always
|
||||
be the same, provided the key exists.
|
||||
operationId: isPubKeyValid
|
||||
parameters:
|
||||
- in: query
|
||||
|
|
|
@ -194,3 +194,126 @@ paths:
|
|||
type: object
|
||||
description: An empty object
|
||||
example: {}
|
||||
"/3pid/onbind":
|
||||
put:
|
||||
summary: |-
|
||||
Notifies the server that a third party identifier has been bound to one
|
||||
of its users.
|
||||
description: |-
|
||||
Used by Identity Servers to notify the homeserver that one of its users
|
||||
has bound a third party identifier successfully, including any pending
|
||||
room invites the Identity Server has been made aware of.
|
||||
operationId: onBindThirdPartyIdentifier
|
||||
parameters:
|
||||
- in: body
|
||||
name: body
|
||||
type: object
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
medium:
|
||||
type: string
|
||||
description: |-
|
||||
The type of third party identifier. Currently only "email" is
|
||||
a possible value.
|
||||
example: "email"
|
||||
address:
|
||||
type: string
|
||||
description: |-
|
||||
The third party identifier itself. For example, an email address.
|
||||
example: "alice@domain.com"
|
||||
mxid:
|
||||
type: string
|
||||
description: The user that is now bound to the third party identifier.
|
||||
example: "@alice:matrix.org"
|
||||
invites:
|
||||
type: array
|
||||
description: |-
|
||||
A list of pending invites that the third party identifier has received.
|
||||
items:
|
||||
type: object
|
||||
title: Third Party Invite
|
||||
properties:
|
||||
medium:
|
||||
type: string
|
||||
description: |-
|
||||
The type of third party invite issues. Currently only
|
||||
"email" is used.
|
||||
example: "email"
|
||||
address:
|
||||
type: string
|
||||
description: |-
|
||||
The third party identifier that received the invite.
|
||||
example: "alice@domain.com"
|
||||
mxid:
|
||||
type: string
|
||||
description: The now-bound user ID that received the invite.
|
||||
example: "@alice:matrix.org"
|
||||
room_id:
|
||||
type: string
|
||||
description: The room ID the invite is valid for.
|
||||
example: "!somewhere:example.org"
|
||||
sender:
|
||||
type: string
|
||||
description: The user ID that sent the invite.
|
||||
example: "@bob:matrix.org"
|
||||
# TODO (TravisR): Make this reusable when doing IS spec changes
|
||||
# also make sure it isn't lying about anything, like the key version
|
||||
signed:
|
||||
type: object
|
||||
title: Identity Server Signatures
|
||||
description: |-
|
||||
Signature from the Identity Server using a long-term private
|
||||
key.
|
||||
properties:
|
||||
mxid:
|
||||
type: string
|
||||
description: |-
|
||||
The user ID that has been bound to the third party
|
||||
identifier.
|
||||
example: "@alice:matrix.org"
|
||||
token:
|
||||
type: string
|
||||
# TODO: What is this actually?
|
||||
description: A token.
|
||||
example: "Hello World"
|
||||
signatures:
|
||||
type: object
|
||||
title: Identity Server Signature
|
||||
description: |-
|
||||
The signature from the identity server. The ``string`` key
|
||||
is the identity server's domain name, such as vector.im
|
||||
additionalProperties:
|
||||
type: object
|
||||
title: Identity Server Domain Signature
|
||||
description: The signature for the identity server.
|
||||
properties:
|
||||
"ed25519:0":
|
||||
type: string
|
||||
description: The signature.
|
||||
example: "SomeSignatureGoesHere"
|
||||
required: ['ed25519:0']
|
||||
example: {
|
||||
"vector.im": {
|
||||
"ed25519:0": "SomeSignatureGoesHere"
|
||||
}
|
||||
}
|
||||
required: ['mxid', 'token', 'signatures']
|
||||
required:
|
||||
- medium
|
||||
- address
|
||||
- mxid
|
||||
- room_id
|
||||
- sender
|
||||
- signed
|
||||
required: ['medium', 'address', 'mxid', 'invites']
|
||||
responses:
|
||||
200:
|
||||
description: The homeserver has processed the notification.
|
||||
examples:
|
||||
application/json: {}
|
||||
schema:
|
||||
type: object
|
||||
description: An empty object
|
||||
example: {}
|
||||
|
|
|
@ -179,9 +179,11 @@ An identity service has some long-term public-private keypairs. These are named
|
|||
in a scheme ``algorithm:identifier``, e.g. ``ed25519:0``. When signing an
|
||||
association, the standard `Signing JSON`_ algorithm applies.
|
||||
|
||||
In the event of key compromise, the identity service may revoke any of its keys.
|
||||
An HTTP API is offered to get public keys, and check whether a particular key is
|
||||
valid.
|
||||
.. TODO: Actually allow identity services to revoke all keys
|
||||
See: https://github.com/matrix-org/matrix-doc/issues/1633
|
||||
.. In the event of key compromise, the identity service may revoke any of its keys.
|
||||
An HTTP API is offered to get public keys, and check whether a particular key is
|
||||
valid.
|
||||
|
||||
The identity service may also keep track of some short-term public-private
|
||||
keypairs, which may have different usage and lifetime characteristics than the
|
||||
|
|
|
@ -40,6 +40,7 @@ with ``content.membership`` = ``invite``, as well as a
|
|||
``content.third_party_invite`` property which contains proof that the invitee
|
||||
does indeed own that third party identifier.
|
||||
|
||||
|
||||
Events
|
||||
------
|
||||
|
||||
|
@ -55,41 +56,79 @@ A client asks a server to invite a user by their third party identifier.
|
|||
Server behaviour
|
||||
----------------
|
||||
|
||||
Upon receipt of an ``/invite``, the server is expected to look up the third party
|
||||
identifier with the provided identity server. If the lookup yields a result for
|
||||
a Matrix User ID then the normal invite process can be initiated. This process
|
||||
ends up looking like this:
|
||||
|
||||
::
|
||||
|
||||
+---------+ +-------------+ +-----------------+
|
||||
| Client | | Homeserver | | IdentityServer |
|
||||
+---------+ +-------------+ +-----------------+
|
||||
| | |
|
||||
| POST /invite | |
|
||||
|------------------------------------>| |
|
||||
| | |
|
||||
| | GET /lookup |
|
||||
| |--------------------------------------------------->|
|
||||
| | |
|
||||
| | User ID result |
|
||||
| |<---------------------------------------------------|
|
||||
| | |
|
||||
| | Invite process for the discovered User ID |
|
||||
| |------------------------------------------ |
|
||||
| | | |
|
||||
| |<----------------------------------------- |
|
||||
| | |
|
||||
| Complete the /invite request | |
|
||||
|<------------------------------------| |
|
||||
| | |
|
||||
|
||||
|
||||
However, if the lookup does not yield a bound User ID, the homeserver must store
|
||||
the invite on the identity server and emit a valid ``m.room.third_party_invite``
|
||||
event to the room. This process ends up looking like this:
|
||||
|
||||
::
|
||||
|
||||
+---------+ +-------------+ +-----------------+
|
||||
| Client | | Homeserver | | IdentityServer |
|
||||
+---------+ +-------------+ +-----------------+
|
||||
| | |
|
||||
| POST /invite | |
|
||||
|------------------------------------>| |
|
||||
| | |
|
||||
| | GET /lookup |
|
||||
| |-------------------------------------------------------------->|
|
||||
| | |
|
||||
| | "no users" result |
|
||||
| |<--------------------------------------------------------------|
|
||||
| | |
|
||||
| | POST /store-invite |
|
||||
| |-------------------------------------------------------------->|
|
||||
| | |
|
||||
| | Information needed for the m.room.third_party_invite |
|
||||
| |<--------------------------------------------------------------|
|
||||
| | |
|
||||
| | Emit m.room.third_party_invite to the room |
|
||||
| |------------------------------------------- |
|
||||
| | | |
|
||||
| |<------------------------------------------ |
|
||||
| | |
|
||||
| Complete the /invite request | |
|
||||
|<------------------------------------| |
|
||||
| | |
|
||||
|
||||
|
||||
All homeservers MUST verify the signature in the event's
|
||||
``content.third_party_invite.signed`` object.
|
||||
|
||||
When a homeserver inserts an ``m.room.member`` ``invite`` event into the graph
|
||||
because of an ``m.room.third_party_invite`` event,
|
||||
that homesever MUST validate that the public
|
||||
key used for signing is still valid, by checking ``key_validity_url`` from the ``m.room.third_party_invite``. It does
|
||||
this by making an HTTP GET request to ``key_validity_url``:
|
||||
|
||||
.. TODO: Link to identity server spec when it exists
|
||||
|
||||
Schema::
|
||||
|
||||
=> GET $key_validity_url?public_key=$public_key
|
||||
<= HTTP/1.1 200 OK
|
||||
{
|
||||
"valid": true|false
|
||||
}
|
||||
|
||||
|
||||
Example::
|
||||
|
||||
key_validity_url = https://identity.server/is_valid
|
||||
public_key = ALJWLAFQfqffQHFqFfeqFUOEHf4AIHfefh4
|
||||
=> GET https://identity.server/is_valid?public_key=ALJWLAFQfqffQHFqFfeqFUOEHf4AIHfefh4
|
||||
<= HTTP/1.1 200 OK
|
||||
{
|
||||
"valid": true
|
||||
}
|
||||
|
||||
with the querystring
|
||||
?public_key=``public_key``. A JSON object will be returned.
|
||||
The invitation is valid if the object contains a key named ``valid`` which is
|
||||
``true``. Otherwise, the invitation MUST be rejected. This request is
|
||||
idempotent and may be retried by the homeserver.
|
||||
The third party user will then need to verify their identity, which results in
|
||||
a call from the Identity Server to the homeserver that bound the third party
|
||||
identifier to a user. The homeserver then exchanges the ``m.room.third_party_invite``
|
||||
event in the room for a complete ``m.room.member`` event for ``membership: invite``
|
||||
for the user that has bound the third party identifier.
|
||||
|
||||
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
|
||||
|
@ -99,29 +138,84 @@ validate that the public key used for signing is still valid, by checking
|
|||
|
||||
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. They may, however, indicate to their clients that a member's'
|
||||
the room. They may, however, indicate to their clients that a member's
|
||||
membership is questionable.
|
||||
|
||||
For example:
|
||||
For example, given H1, H2, and H3 as homeservers, UserA as a user of H1, and an
|
||||
identity server IS, the full sequence for a third party invite would look like
|
||||
the following. This diagram assumes H1 and H2 are residents of the room while
|
||||
H3 is attempting to join.
|
||||
|
||||
#. Room R has two participating homeservers, H1, H2
|
||||
::
|
||||
|
||||
#. User A on H1 invites a third party identifier to room R
|
||||
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
|
||||
| UserA | | ThirdPartyUser | | H1 | | H2 | | H3 | | IS |
|
||||
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
|
||||
| | | | | |
|
||||
| POST /invite for ThirdPartyUser | | | |
|
||||
|----------------------------------->| | | |
|
||||
| | | | | |
|
||||
| | | GET /lookup | | |
|
||||
| | |---------------------------------------------------------------------------------------------->|
|
||||
| | | | | |
|
||||
| | | | Lookup results (empty object) |
|
||||
| | |<----------------------------------------------------------------------------------------------|
|
||||
| | | | | |
|
||||
| | | POST /store-invite | | |
|
||||
| | |---------------------------------------------------------------------------------------------->|
|
||||
| | | | | |
|
||||
| | | | Token, keys, etc for third party invite |
|
||||
| | |<----------------------------------------------------------------------------------------------|
|
||||
| | | | | |
|
||||
| | | (Federation) Emit m.room.third_party_invite | | |
|
||||
| | |----------------------------------------------->| | |
|
||||
| | | | | |
|
||||
| Complete /invite request | | | |
|
||||
|<-----------------------------------| | | |
|
||||
| | | | | |
|
||||
| | Verify identity | | | |
|
||||
| |-------------------------------------------------------------------------------------------------------------------->|
|
||||
| | | | | |
|
||||
| | | | | POST /3pid/onbind |
|
||||
| | | | |<---------------------------|
|
||||
| | | | | |
|
||||
| | | PUT /exchange_third_party_invite/:roomId | |
|
||||
| | |<-----------------------------------------------------------------| |
|
||||
| | | | | |
|
||||
| | | Verify the request | | |
|
||||
| | |------------------- | | |
|
||||
| | | | | | |
|
||||
| | |<------------------ | | |
|
||||
| | | | | |
|
||||
| | | (Federation) Emit m.room.member for invite | | |
|
||||
| | |----------------------------------------------->| | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | (Federation) Emit the m.room.member event sent to H2 | |
|
||||
| | |----------------------------------------------------------------->| |
|
||||
| | | | | |
|
||||
| | | Complete /exchange_third_party_invite/:roomId request | |
|
||||
| | |----------------------------------------------------------------->| |
|
||||
| | | | | |
|
||||
| | | | | Participate in the room |
|
||||
| | | | |------------------------ |
|
||||
| | | | | | |
|
||||
| | | | |<----------------------- |
|
||||
| | | | | |
|
||||
|
||||
#. 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, their homeserver H3
|
||||
is notified and attempts to issue an ``m.room.member`` event to participate
|
||||
in the room.
|
||||
Note that when H1 sends the ``m.room.member`` event to H2 and H3 it does not
|
||||
have to block on either server's receipt of the event. Likewise, H1 may complete
|
||||
the ``/exchange_third_party_invite/:roomId`` request at the same time as sending
|
||||
the ``m.room.member`` event to H2 and H3. Additionally, H3 may complete the
|
||||
``/3pid/onbind`` request it got from IS at any time - the completion is not shown
|
||||
in the diagram.
|
||||
|
||||
#. H3 validates the signature given to it by the identity server.
|
||||
|
||||
#. H3 then asks H1 to join it to the room. H1 *must* validate the ``signed``
|
||||
property *and* check ``key_validity_url``.
|
||||
|
||||
#. Having validated these things, H1 writes the invite event to the room, and H3
|
||||
begins participating in the room. H2 *must* accept this event.
|
||||
H1 MUST verify the request from H3 to ensure the ``signed`` property is correct
|
||||
as well as the ``key_validity_url`` as still being valid. This is done by making
|
||||
a request to the `Identity Server /isvalid`_ endpoint, using the provided URL
|
||||
rather than constructing a new one. The query string and response for the provided
|
||||
URL must match the Identity Server specification.
|
||||
|
||||
The reason that no other homeserver may reject the event based on checking
|
||||
``key_validity_url`` is that we must ensure event acceptance is deterministic.
|
||||
|
@ -158,3 +252,6 @@ There is some risk of denial of service attacks by flooding homeservers or
|
|||
identity servers with many requests, or much state to store. Defending against
|
||||
these is left to the implementer's discretion.
|
||||
|
||||
|
||||
|
||||
.. _`Identity Server /isvalid`: ../identity_service/unstable.html#get-matrix-identity-api-v1-pubkey-isvalid
|
||||
|
|
|
@ -836,6 +836,10 @@ event to other servers in the room.
|
|||
Third-party invites
|
||||
-------------------
|
||||
|
||||
.. NOTE::
|
||||
More information about third party invites is available in the `Client-Server API`_
|
||||
under the Third Party Invites module.
|
||||
|
||||
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).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue