From 41b9def9f2c02118796e147f63abf23bc2d7dc04 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Wed, 17 May 2023 16:39:06 +0200 Subject: [PATCH] Add a new admin API to create a new device for a user. (#15611) This allows an external service (e.g. the matrix-authentication-service) to create devices for users. --- changelog.d/15611.feature | 1 + docs/admin_api/user_admin_api.md | 27 +++++++++++++++++++++++++++ synapse/rest/admin/devices.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 changelog.d/15611.feature diff --git a/changelog.d/15611.feature b/changelog.d/15611.feature new file mode 100644 index 0000000000..7cfb46fd0a --- /dev/null +++ b/changelog.d/15611.feature @@ -0,0 +1 @@ +Add a new admin API to create a new device for a user. diff --git a/docs/admin_api/user_admin_api.md b/docs/admin_api/user_admin_api.md index 6b952ba396..229942b311 100644 --- a/docs/admin_api/user_admin_api.md +++ b/docs/admin_api/user_admin_api.md @@ -813,6 +813,33 @@ The following fields are returned in the JSON response body: - `total` - Total number of user's devices. +### Create a device + +Creates a new device for a specific `user_id` and `device_id`. Does nothing if the `device_id` +exists already. + +The API is: + +``` +POST /_synapse/admin/v2/users//devices + +{ + "device_id": "QBUAZIFURK" +} +``` + +An empty JSON dict is returned. + +**Parameters** + +The following parameters should be set in the URL: + +- `user_id` - fully qualified: for example, `@user:server.com`. + +The following fields are required in the JSON request body: + +- `device_id` - The device ID to create. + ### Delete multiple devices Deletes the given devices for a specific `user_id`, and invalidates any access token associated with them. diff --git a/synapse/rest/admin/devices.py b/synapse/rest/admin/devices.py index 3b2f2d9abb..11ebed9bfd 100644 --- a/synapse/rest/admin/devices.py +++ b/synapse/rest/admin/devices.py @@ -137,6 +137,35 @@ class DevicesRestServlet(RestServlet): devices = await self.device_handler.get_devices_by_user(target_user.to_string()) return HTTPStatus.OK, {"devices": devices, "total": len(devices)} + async def on_POST( + self, request: SynapseRequest, user_id: str + ) -> Tuple[int, JsonDict]: + """Creates a new device for the user.""" + await assert_requester_is_admin(self.auth, request) + + target_user = UserID.from_string(user_id) + if not self.is_mine(target_user): + raise SynapseError( + HTTPStatus.BAD_REQUEST, "Can only create devices for local users" + ) + + u = await self.store.get_user_by_id(target_user.to_string()) + if u is None: + raise NotFoundError("Unknown user") + + body = parse_json_object_from_request(request) + device_id = body.get("device_id") + if not device_id: + raise SynapseError(HTTPStatus.BAD_REQUEST, "Missing device_id") + if not isinstance(device_id, str): + raise SynapseError(HTTPStatus.BAD_REQUEST, "device_id must be a string") + + await self.device_handler.check_device_registered( + user_id=user_id, device_id=device_id + ) + + return HTTPStatus.CREATED, {} + class DeleteDevicesRestServlet(RestServlet): """