Skip to main content

arminius_server_client/handlers/
devices.rs

1// SPDX-FileCopyrightText: 2025 BWI GmbH
2//
3// SPDX-License-Identifier: Apache-2.0
4
5//! Implements APIs to manage the logged in devices for the current user.
6//! Currently, only querying is implemented.
7
8mod tests;
9
10use arminius_lib_component::{
11	Component, ServerState,
12	error::{InternalServerError, MatrixApiError, ResultExt as _},
13	ruma_requests::ArminiusResponse,
14};
15use arminius_lib_db::DefaultDb;
16use arminius_lib_db_devices::DeviceQueries as _;
17use axum::{Router, extract::State, http::StatusCode, routing::get};
18use ruma::api::{
19	client::device::{get_device, get_devices},
20	error::ErrorKind,
21};
22
23use crate::client_request::AuthenticatedClientRequest;
24
25/// Handler Error for device data operations
26#[derive(thiserror::Error, Debug, MatrixApiError)]
27enum GetDeviceError {
28	/// Unrecoverable error.
29	/// See <https://bundesmessenger.gitlab.io/backend/neo/arminius/arminius/03-development/errors.html#unrecoverable-errors>
30	#[error(transparent)]
31	InternalServerError(#[from] InternalServerError),
32
33	/// Error for when device data is queried.
34	#[error("Device not found")]
35	#[matrix_api_error(status_code = StatusCode::NOT_FOUND, error_kind = ErrorKind::NotFound)]
36	DeviceNotFound,
37}
38
39/// Handler for `GET /_matrix/client/v3/devices` (See
40/// <https://spec.matrix.org/latest/client-server-api/#get_matrixclientv3devices>).
41///
42/// This endpoint gets information about all devices for the current user.
43async fn get_devices_handler(
44	mut database: State<DefaultDb>,
45	AuthenticatedClientRequest(claims, _): AuthenticatedClientRequest<get_devices::v3::Request>,
46) -> Result<ArminiusResponse<get_devices::v3::Response>, InternalServerError> {
47	let devices = database
48		.fetch_devices_for_user(&claims.user_id)
49		.await
50		.unrecoverable_error("Fetching devices data")?;
51
52	let response = devices
53		.into_iter()
54		.map(|device| ruma::api::client::device::Device::new(device.device_id))
55		.collect();
56
57	Ok(get_devices::v3::Response::new(response).into())
58}
59
60/// Handler for `GET /_matrix/client/v3/devices/{deviceId}` (See
61/// <https://spec.matrix.org/latest/client-server-api/#get_matrixclientv3devicesdeviceid>).
62///
63/// This endpoint Gets information on a single device, by device id.
64async fn get_device_handler(
65	mut database: State<DefaultDb>,
66	AuthenticatedClientRequest(claims, request): AuthenticatedClientRequest<
67		get_device::v3::Request,
68	>,
69) -> Result<ArminiusResponse<get_device::v3::Response>, GetDeviceError> {
70	let device = database
71		.fetch_device_for_user(&claims.user_id, &request.device_id)
72		.await
73		.unrecoverable_error("Fetching device data")?
74		.ok_or(GetDeviceError::DeviceNotFound)?;
75
76	Ok(get_device::v3::Response::new(ruma::api::client::device::Device::new(device.device_id))
77		.into())
78}
79
80/// Component implementing endpoint for device management
81#[derive(Debug)]
82pub struct DevicesComponent;
83
84impl Component for DevicesComponent {
85	fn router() -> Router<ServerState> {
86		Router::new()
87			.route("/_matrix/client/v3/devices", get(get_devices_handler))
88			.route("/_matrix/client/v3/devices/{device_id}", get(get_device_handler))
89	}
90}