diff --git a/api/server-server/definitions/event-schemas/m.device_list_update.yaml b/api/server-server/definitions/event-schemas/m.device_list_update.yaml new file mode 100644 index 00000000..f11e957e --- /dev/null +++ b/api/server-server/definitions/event-schemas/m.device_list_update.yaml @@ -0,0 +1,89 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +type: object +title: m.device_list_update +description: |- + An EDU that lets servers push details to each other when one of their users + adds a new device to their account, required for E2E encryption to correctly + target the current set of devices for a given user. + +# FIXME: It's very unclear why we have this API surface for synchronising +# device lists, rather than just using a room (which could also be used for +# presence lists, profile info, etc). But documenting what we have for now... + +allOf: + - $ref: ../edu.yaml + - type: object + properties: + edu_type: + type: enum + enum: ['m.device_list_update'] + description: The string ``m.device_list_update``. + example: "m.device_list_update" + content: + type: object + description: The description of the device whose details has changed. + title: Device List Update + properties: + user_id: + type: string + description: The user ID who owns this device. + example: "@john:example.com" + device_id: + type: string + description: The ID of the device whose details are changing. + example: "QBUAZIFURK" + device_display_name: + type: string + description: |- + The public human-readable name of this device. Will be absent + if the device has no name. + example: "Mobile" + stream_id: + type: integer + description: |- + An ID sent by the server for this update, unique for a given + user_id. Used to identify any gaps in the sequence of ``m.device_list_update`` + EDUs broadcast by a server. + example: 6 + prev_id: + type: array + description: |- + The stream_ids of any prior m.device_list_update EDUs sent for this user + which have not been referred to already in an EDU's prev_id field. If the + receiving server does not recognise any of the prev_ids, it means an EDU + has been lost and the server should query a snapshot of the device list + via ``/user/keys/query`` in order to correctly interpret future ``m.device_list_update`` + EDUs. May be missing or empty for the first EDU in a sequence. + items: + type: integer + description: |- + The stream_id of a prior EDU in this sequence which has not been referred + to already in an EDU's prev_id field. + example: 5 + deleted: + type: boolean + description: |- + True if the server is announcing that this device has been deleted. + example: false + keys: + description: |- + The updated identity keys (if any) for this device. May be absent if the + device has no E2E keys defined. + $ref: ../../../client-server/definitions/device_keys.yaml + required: + - user_id + - device_id + - stream_id diff --git a/api/server-server/user_devices.yaml b/api/server-server/user_devices.yaml new file mode 100644 index 00000000..4805deb4 --- /dev/null +++ b/api/server-server/user_devices.yaml @@ -0,0 +1,85 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +swagger: '2.0' +info: + title: "Matrix Federation User Device Management API" + version: "1.0.0" +host: localhost:8448 +schemes: + - https +basePath: /_matrix/federation/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + $ref: definitions/security.yaml +paths: + "/user/devices/{userId}": + get: + summary: Gets all of the user's devices + description: Gets information on all of the user's devices + operationId: getUserDevices + security: + - signedRequest: [] + parameters: + - in: path + name: userId + type: string + required: true + description: |- + The user ID to retrieve devices for. Must be a user local to the + receiving homeserver. + required: true + x-example: "@alice:example.org" + responses: + 200: + description: The user's devices. + schema: + type: object + properties: + user_id: + type: string + description: The user ID devices were requested for. + example: "@alice:example.org" + stream_id: + type: integer + description: |- + A unique ID for a given user_id which describes the version of + the returned device list. This is matched with the ``stream_id`` + field in ``m.device_list_update`` EDUs in order to incrementally + update the returned device_list. + example: 5 + devices: + type: array + description: The user's devices. May be empty. + items: + type: object + title: User Device + properties: + device_id: + type: string + description: The device ID. + example: "JLAFKJWSCS" + keys: + type: object + description: Identity keys for the device. + $ref: "../client-server/definitions/device_keys.yaml" + device_display_name: + type: string + description: Optional display name for the device. + example: "Alice's Mobile Phone" + required: ['device_id', 'keys'] + required: ['user_id', 'stream_id', 'devices'] \ No newline at end of file diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index d719bfaa..7ed7e5d6 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -1122,6 +1122,52 @@ nothing else. {{openid_ss_http_api}} +Device Management +----------------- + +Details of a user's devices must be efficiently published to other users and kept +up-to-date. This is critical for reliable end-to-end encryption, in order for users +to know which devices are participating in a room. It's also required for to-device +messaging to work. This section is intended to complement the `Device Management module`_ +of the Client-Server API. + +Matrix currently uses a custom pubsub system for synchronising information +about the list of devices for a given user over federation. When a server +wishes to determine a remote user's device list for the first time, +it should populate a local cache from the result of a ``/user/keys/query`` API +on the remote server. However, subsequent updates to the cache should be applied +by consuming ``m.device_list_update`` EDUs. Each new ``m.device_list_update`` EDU +describes an incremental change to one device for a given user which should replace +any existing entry in the local server's cache of that device list. Servers must send +``m.device_list_update`` EDUs to all the servers who share a room with a given +local user, and must be sent whenever that user's device list changes (i.e. for new or +deleted devices, when that user joins a room which contains servers which are not +already receiving updates for that user's device list, or changes in device information +such as the device's human-readable name). + +Servers send ``m.device_list_update`` EDUs in a sequence per origin user, each with +a unique ``stream_id``. They also include a pointer to the most recent previous EDU(s) +that this update is relative to in the ``prev_id`` field. To simplify implementation +for clustered servers which could send multiple EDUs at the same time, the ``prev_id`` +field should include all ``m.device_list_update`` EDUs which have not been yet been +referenced in a EDU. If EDUs are emitted in series by a server, there should only ever +be one ``prev_id`` in the EDU. + +This forms a simple directed acyclic graph of ``m.device_list_update`` EDUs, showing +which EDUs a server needs to have received in order to apply an update to its local +copy of the remote user's device list. If a server receives an EDU which refers to +a ``prev_id`` it does not recognise, it must resynchronise its list by calling the +``/user/keys/query API`` and resume the process. The response contains a ``stream_id`` +which should be used to correlate with subsequent ``m.device_list_update`` EDUs. + +.. TODO: this whole thing desperately feels like it should just be state in a room, + rather than inventing a whole different DAG. The same room could be used for + profiles, presence lists, etc. + +{{user_devices_ss_http_api}} + +{{definition_ss_event_schemas_m_device_list_update}} + End-to-End Encryption ---------------------