From 30d56691b1068320eb7c989484c4d06cf461b032 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 1 Sep 2018 01:47:55 +0100 Subject: [PATCH] document device list synchronisation over federation. untested closes MSC1212 --- .../event-schemas/m.device_list_update.yaml | 89 +++++++++++++++++++ api/server-server/user_devices.yaml | 84 +++++++++++++++++ specification/server_server_api.rst | 42 +++++++++ 3 files changed, 215 insertions(+) create mode 100644 api/server-server/definitions/event-schemas/m.device_list_update.yaml create mode 100644 api/server-server/user_devices.yaml 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..272cfee6 --- /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 devicelist + 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. + keys: + description: |- + The updated identity keys (if any) for this device. May be absent if the + device has no E2E keys defined. + allOf: + - $ref: 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..d1644270 --- /dev/null +++ b/api/server-server/user_devices.yaml @@ -0,0 +1,84 @@ +# 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: |- + An ID the requesting homeserver may use to detect changes in the + device list. This should increase as time goes on, and always + produce the same ``devices`` list if not incremented. + example: 334608 + 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 36d7d5d4..e9ee476f 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -996,6 +996,48 @@ 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 its local cache by calling the /user/keys/query API +on the remote server. However, subsequent updates to the cache should be applied +by consuming ``m.device_list_update`` EDUs, which must be sent by the remote server +whenever a user's device list changes. + +Servers send ``m.device_list_update`` EDUs in a sequence per source 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 `pprev_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. + +..TODO: how do you synchronise the result of the /query API with the stream_id + in the 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 ---------------------