Update 3pid spec based on new implementation
This commit is contained in:
parent
232b10b0f6
commit
161441fa3a
6 changed files with 246 additions and 163 deletions
|
@ -73,9 +73,12 @@ paths:
|
|||
post:
|
||||
summary: Invite a user to participate in a particular room.
|
||||
description: |-
|
||||
.. _invite-by-user-id-endpoint:
|
||||
|
||||
*Note that there are two forms of this API, which are documented separately.
|
||||
This version of the API requires that the inviter knows the Matrix
|
||||
identifier of the invitee.*
|
||||
identifier of the invitee. The other is documented in the*
|
||||
`third party invites section`_.
|
||||
|
||||
This API invites a user to participate in a particular room.
|
||||
They do not start participating in the room until they actually join the
|
||||
|
@ -86,6 +89,8 @@ paths:
|
|||
|
||||
If the user was invited to the room, the home server will append a
|
||||
``m.room.member`` event to the room.
|
||||
|
||||
.. _third party invites section: `invite-by-third-party-id-endpoint`_
|
||||
security:
|
||||
- accessToken: []
|
||||
parameters:
|
||||
|
@ -132,106 +137,3 @@ paths:
|
|||
description: This request was rate-limited.
|
||||
schema:
|
||||
"$ref": "definitions/error.yaml"
|
||||
|
||||
"/rooms/{roomId}/invite":
|
||||
post:
|
||||
summary: Invite a user to participate in a particular room.
|
||||
description: |-
|
||||
*Note that there are two forms of this API, which are documented separately.
|
||||
This version of the API does not require that the inviter know the Matrix
|
||||
identifier of the invitee, and instead relies on third party identifiers.
|
||||
The homeserver uses an identity server to perform the mapping from
|
||||
third party identifier to a Matrix identifier.*
|
||||
|
||||
This API invites a user to participate in a particular room.
|
||||
They do not start participating in the room until they actually join the
|
||||
room.
|
||||
|
||||
Only users currently in a particular room can invite other users to
|
||||
join that room.
|
||||
|
||||
If the identity server did know the Matrix user identifier for the
|
||||
third party identifier, the home server will append a ``m.room.member``
|
||||
event to the room.
|
||||
|
||||
If the identity server does not know a Matrix user identifier for the
|
||||
passed third party identifier, the homeserver will issue an invitation
|
||||
which can be accepted upon providing proof of ownership of the third
|
||||
party identifier. This is achieved by the identity server generating a
|
||||
token, which it gives to the inviting homeserver. The homeserver will
|
||||
add an ``m.room.third_party_invite`` event into the graph for the room,
|
||||
containing that token.
|
||||
|
||||
When the invitee binds the invited third party identifier to a Matrix
|
||||
user ID, the identity server will give the user a list of pending
|
||||
invitations, each containing:
|
||||
|
||||
- The room ID to which they were invited
|
||||
|
||||
- The token given to the homeserver
|
||||
|
||||
- A signature of the token, signed with the identity server's private key
|
||||
|
||||
- The matrix user ID who invited them to the room
|
||||
|
||||
If a token is requested from the identity server, the home server will
|
||||
append a ``m.room.third_party_invite`` event to the room.
|
||||
security:
|
||||
- accessToken: []
|
||||
parameters:
|
||||
- in: path
|
||||
type: string
|
||||
name: roomId
|
||||
description: The room identifier (not alias) to which to invite the user.
|
||||
required: true
|
||||
x-example: "!d41d8cd:matrix.org"
|
||||
- in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
example: |-
|
||||
{
|
||||
"id_server": "matrix.org",
|
||||
"medium": "email",
|
||||
"address": "cheeky@monkey.com",
|
||||
"display_name": "A very cheeky monkey"
|
||||
}
|
||||
properties:
|
||||
id_server:
|
||||
type: string
|
||||
description: The hostname+port of the identity server which should be used for third party identifier lookups.
|
||||
medium:
|
||||
type: string
|
||||
# TODO: Link to identity service spec when it eixsts
|
||||
description: The kind of address being passed in the address field, for example ``email``.
|
||||
address:
|
||||
type: string
|
||||
description: The invitee's third party identifier.
|
||||
display_name:
|
||||
type: string
|
||||
description: A user-friendly string describing who has been invited. It should not contain the address of the invitee, to avoid leaking mappings between third party identities and matrix user IDs.
|
||||
required: ["id_server", "medium", "address", "display_name"]
|
||||
responses:
|
||||
200:
|
||||
description: The user has been invited to join the room.
|
||||
examples:
|
||||
application/json: |-
|
||||
{}
|
||||
schema:
|
||||
type: object
|
||||
403:
|
||||
description: |-
|
||||
You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are:
|
||||
|
||||
- The invitee has been banned from the room.
|
||||
- The invitee is already a member of the room.
|
||||
- The inviter is not currently in the room.
|
||||
- The inviter's power level is insufficient to invite users to the room.
|
||||
examples:
|
||||
application/json: |-
|
||||
{"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
|
||||
429:
|
||||
description: This request was rate-limited.
|
||||
schema:
|
||||
"$ref": "definitions/error.yaml"
|
||||
|
|
127
api/client-server/v1/third_party_membership.yaml
Normal file
127
api/client-server/v1/third_party_membership.yaml
Normal file
|
@ -0,0 +1,127 @@
|
|||
swagger: '2.0'
|
||||
info:
|
||||
title: "Matrix Client-Server v1 Room Membership API for third party identifiers"
|
||||
version: "1.0.0"
|
||||
host: localhost:8008
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/client/api/v1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
securityDefinitions:
|
||||
accessToken:
|
||||
type: apiKey
|
||||
description: The user_id or application service access_token
|
||||
name: access_token
|
||||
in: query
|
||||
paths:
|
||||
"/rooms/{roomId}/invite":
|
||||
post:
|
||||
summary: Invite a user to participate in a particular room.
|
||||
description: |-
|
||||
.. _invite-by-third-party-id-endpoint:
|
||||
|
||||
*Note that there are two forms of this API, which are documented separately.
|
||||
This version of the API does not require that the inviter know the Matrix
|
||||
identifier of the invitee, and instead relies on third party identifiers.
|
||||
The homeserver uses an identity server to perform the mapping from
|
||||
third party identifier to a Matrix identifier. The other is documented in the*
|
||||
`joining rooms section`_.
|
||||
|
||||
This API invites a user to participate in a particular room.
|
||||
They do not start participating in the room until they actually join the
|
||||
room.
|
||||
|
||||
Only users currently in a particular room can invite other users to
|
||||
join that room.
|
||||
|
||||
If the identity server did know the Matrix user identifier for the
|
||||
third party identifier, the home server will append a ``m.room.member``
|
||||
event to the room.
|
||||
|
||||
If the identity server does not know a Matrix user identifier for the
|
||||
passed third party identifier, the homeserver will issue an invitation
|
||||
which can be accepted upon providing proof of ownership of the third
|
||||
party identifier. This is achieved by the identity server generating a
|
||||
token, which it gives to the inviting homeserver. The homeserver will
|
||||
add an ``m.room.third_party_invite`` event into the graph for the room,
|
||||
containing that token.
|
||||
|
||||
When the invitee binds the invited third party identifier to a Matrix
|
||||
user ID, the identity server will give the user a list of pending
|
||||
invitations, each containing:
|
||||
|
||||
- The room ID to which they were invited
|
||||
|
||||
- The token given to the homeserver
|
||||
|
||||
- A signature of the token, signed with the identity server's private key
|
||||
|
||||
- The matrix user ID who invited them to the room
|
||||
|
||||
If a token is requested from the identity server, the home server will
|
||||
append a ``m.room.third_party_invite`` event to the room.
|
||||
|
||||
.. _joining rooms section: `invite-by-user-id-endpoint`_
|
||||
security:
|
||||
- accessToken: []
|
||||
parameters:
|
||||
- in: path
|
||||
type: string
|
||||
name: roomId
|
||||
description: The room identifier (not alias) to which to invite the user.
|
||||
required: true
|
||||
x-example: "!d41d8cd:matrix.org"
|
||||
- in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
example: |-
|
||||
{
|
||||
"id_server": "matrix.org",
|
||||
"medium": "email",
|
||||
"address": "cheeky@monkey.com",
|
||||
"display_name": "A very cheeky monkey"
|
||||
}
|
||||
properties:
|
||||
id_server:
|
||||
type: string
|
||||
description: The hostname+port of the identity server which should be used for third party identifier lookups.
|
||||
medium:
|
||||
type: string
|
||||
# TODO: Link to identity service spec when it eixsts
|
||||
description: The kind of address being passed in the address field, for example ``email``.
|
||||
address:
|
||||
type: string
|
||||
description: The invitee's third party identifier.
|
||||
display_name:
|
||||
type: string
|
||||
description: A user-friendly string describing who has been invited. It should not contain the address of the invitee, to avoid leaking mappings between third party identities and matrix user IDs.
|
||||
required: ["id_server", "medium", "address", "display_name"]
|
||||
responses:
|
||||
200:
|
||||
description: The user has been invited to join the room.
|
||||
examples:
|
||||
application/json: |-
|
||||
{}
|
||||
schema:
|
||||
type: object
|
||||
403:
|
||||
description: |-
|
||||
You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are:
|
||||
|
||||
- The invitee has been banned from the room.
|
||||
- The invitee is already a member of the room.
|
||||
- The inviter is not currently in the room.
|
||||
- The inviter's power level is insufficient to invite users to the room.
|
||||
examples:
|
||||
application/json: |-
|
||||
{"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
|
||||
429:
|
||||
description: This request was rate-limited.
|
||||
schema:
|
||||
"$ref": "definitions/error.yaml"
|
|
@ -3,22 +3,7 @@
|
|||
"content": {
|
||||
"membership": "join",
|
||||
"avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto",
|
||||
"displayname": "Alice Margatroid",
|
||||
"third_party_invite": {
|
||||
"token": "pc98",
|
||||
"public_key": "abc123",
|
||||
"key_validity_url": "https://magic.forest/verifykey",
|
||||
"signed": {
|
||||
"mxid": "@alice:localhost",
|
||||
"token": "pc98",
|
||||
"signatures": {
|
||||
"magic.forest": {
|
||||
"ed25519:0": "poi098"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sender": "@zun:zun.soft"
|
||||
}
|
||||
"displayname": "Alice Margatroid"
|
||||
},
|
||||
"invite_room_state": [
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"type": "object",
|
||||
"title": "The current membership state of a user in the room.",
|
||||
"description": "Adjusts the membership state for a user in a room. It is preferable to use the membership APIs (``/rooms/<room id>/invite`` etc) when performing membership actions rather than adjusting the state directly as there are a restricted set of valid transformations. For example, user A cannot force user B to join a room, and trying to force this state change directly will fail. \n\nThe ``third_party_invite`` property will be set if the invite was an ``m.room.third_party_invite`` event, and absent if the invite was an ``m.room.member`` event.\n\nThis event also includes an ``invite_room_state`` key **outside the** ``content`` **key**. This contains an array of ``StrippedState`` Events. These events provide information on a few select state events such as the room name.",
|
||||
"description": "Adjusts the membership state for a user in a room. It is preferable to use the membership APIs (``/rooms/<room id>/invite`` etc) when performing membership actions rather than adjusting the state directly as there are a restricted set of valid transformations. For example, user A cannot force user B to join a room, and trying to force this state change directly will fail. \n\nThe ``third_party_invite`` property will be set if this invite is an ``invite`` event and is the successor of an ``m.room.third_party_invite`` event, and absent otherwise.\n\nThis event also includes an ``invite_room_state`` key **outside the** ``content`` **key**. This contains an array of ``StrippedState`` Events. These events provide information on a few select state events such as the room name.",
|
||||
"allOf": [{
|
||||
"$ref": "core-event-schema/state_event.json"
|
||||
}],
|
||||
|
@ -27,18 +27,6 @@
|
|||
"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."
|
||||
},
|
||||
"signed": {
|
||||
"type": "object",
|
||||
"title": "signed",
|
||||
|
@ -58,13 +46,9 @@
|
|||
}
|
||||
},
|
||||
"required": ["mxid", "signatures", "token"]
|
||||
},
|
||||
"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", "sender", "signed"]
|
||||
"required": ["signed"]
|
||||
}
|
||||
},
|
||||
"required": ["membership"]
|
||||
|
|
50
specification/modules/anonymous_access.rst
Normal file
50
specification/modules/anonymous_access.rst
Normal file
|
@ -0,0 +1,50 @@
|
|||
Guest access
|
||||
================
|
||||
|
||||
.. _module:guest-access:
|
||||
|
||||
It may be desirable to allow users without a fully registered user account to
|
||||
ephemerally access Matrix rooms. This module specifies limited ways of doing so.
|
||||
|
||||
Note that this is not currently a complete anonymous access solution; in
|
||||
particular, it only allows servers to provided anonymous access to rooms in
|
||||
which they are already participating, and relies on individual homeservers to
|
||||
adhere to the conventions which this module sets, rather than allowing all
|
||||
participating homeservers to enforce them.
|
||||
|
||||
Events
|
||||
------
|
||||
|
||||
{{m_room_guest_accessibility}}
|
||||
|
||||
Client behaviour
|
||||
----------------
|
||||
A client can register for guest access using the FOO endpoint. From that point
|
||||
on, they can interact with a limited subset of the existing client-server API,
|
||||
as if they were a fully registered user, using the access token granted to them
|
||||
by the server.
|
||||
|
||||
These users are only allowed to make calls in relation to rooms which have the
|
||||
``m.room.history_visibility`` event set to ``world_readable``.
|
||||
|
||||
The APIs they are allowed to hit are:
|
||||
|
||||
/rooms/{roomId}/messages
|
||||
/rooms/{roomId}/state
|
||||
/rooms/{roomId}/state/{eventType}/{stateKey}
|
||||
/events
|
||||
|
||||
Server behaviour
|
||||
----------------
|
||||
Does the server need to handle any of the new events in a special way (e.g.
|
||||
typing timeouts, presence). Advice on how to persist events and/or requests are
|
||||
recommended to aid implementation. Federation-specific logic should be included
|
||||
here.
|
||||
|
||||
Security considerations
|
||||
-----------------------
|
||||
This includes privacy leaks: for example leaking presence info. How do
|
||||
misbehaving clients or servers impact this module? This section should always be
|
||||
included, if only to say "we've thought about it but there isn't anything to do
|
||||
here".
|
||||
|
|
@ -1,27 +1,30 @@
|
|||
Third party invites
|
||||
===================
|
||||
|
||||
.. _module:third_party_invites:
|
||||
.. _module:third-party-invites:
|
||||
|
||||
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.
|
||||
that identifier:
|
||||
|
||||
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 a token
|
||||
and public key to the homeserver.
|
||||
- If it is, an invite is simply issued for that user.
|
||||
|
||||
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.
|
||||
- If it is not, the homeserver asks the identity server to record the details of
|
||||
the invitation, and to notify the invitee's homeserver of this pending invitation if it gets
|
||||
a binding for this identifier in the future. The identity server returns a token
|
||||
and public key to the inviting homeserver.
|
||||
|
||||
When the invitee's homeserver receives the notification of the binding, it
|
||||
should insert an ``m.room.member`` event into the room's graph for that user,
|
||||
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
|
||||
------
|
||||
|
@ -33,15 +36,18 @@ Client behaviour
|
|||
|
||||
A client asks a server to invite a user by their third party identifier.
|
||||
|
||||
{{third_party_membership_http_api}}
|
||||
|
||||
Server behaviour
|
||||
----------------
|
||||
|
||||
All homeservers MUST verify the signature in the event's
|
||||
``content.third_party_invite.signed`` object.
|
||||
|
||||
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``. It does
|
||||
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
|
||||
|
@ -84,23 +90,23 @@ membership is questionable.
|
|||
|
||||
For example:
|
||||
|
||||
If room R has two participating homeservers, H1, H2
|
||||
#. Room R has two participating homeservers, H1, H2
|
||||
|
||||
And user A on H1 invites a third party identifier to room R
|
||||
#. 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,
|
||||
#. 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.
|
||||
#. 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.
|
||||
|
||||
H3 validates the signature in the event's
|
||||
``content.third_party_invite.signed`` object.
|
||||
#. 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``
|
||||
#. 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 join event to the room, and H3
|
||||
#. Having validated these things, H1 writes the invite event to the room, and H3
|
||||
begins participating in the room. H2 *must* accept this event.
|
||||
|
||||
The reason that no other homeserver may reject the event based on checking
|
||||
|
@ -112,3 +118,32 @@ This relies on participating servers trusting each other, but that trust is
|
|||
already implied by the server-server protocol. Also, the public key signature
|
||||
verification must still be performed, so the attack surface here is minimized.
|
||||
|
||||
Security considerations
|
||||
-----------------------
|
||||
|
||||
There are a number of privary and trust implications to this module.
|
||||
|
||||
It is important for user privacy that leaking the mapping between a matrix user
|
||||
ID and a third party identifier is hard. In particular, being able to look up
|
||||
all third party identifiers from a matrix user ID (and accordingly, being able
|
||||
to link each third party identifier) should be avoided wherever possible.
|
||||
To this end, when implementing this API care should be taken to avoid
|
||||
adding links between these two identifiers as room events. This mapping can be
|
||||
unintentionally created by specifying the third party identifier in the
|
||||
``display_name`` field of the ``m.room.third_party_invite`` event, and then
|
||||
observing which matrix user ID joins the room using that invite. Clients SHOULD
|
||||
set ``display_name`` to a value other than the third party identifier, e.g. the
|
||||
invitee's common name.
|
||||
|
||||
Homeservers are not required to trust any particular identity server(s). It is
|
||||
generally a client's responsibility to decide which identity servers it trusts,
|
||||
not a homeserver's. Accordingly, this API takes identity servers as input from
|
||||
end users, and doesn't have any specific trusted set. It is possible some
|
||||
homeservers may want to supply defaults, or reject some identity servers for
|
||||
*its* users, but no homeserver is allowed to dictate which identity servers
|
||||
*other* homeservers' users trust.
|
||||
|
||||
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.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue