tuwunel_api/client/device/
devices_device.rs1use axum::extract::State;
2use ruma::{
3 MilliSecondsSinceUnixEpoch,
4 api::client::device::{delete_device, get_device, update_device},
5};
6use tuwunel_core::{Err, Result, debug, err, utils::string::to_small_string};
7
8use crate::{ClientIp, Ruma, router::auth_uiaa};
9
10pub(crate) async fn get_device_route(
14 State(services): State<crate::State>,
15 body: Ruma<get_device::v3::Request>,
16) -> Result<get_device::v3::Response> {
17 let device = services
18 .users
19 .get_device_metadata(body.sender_user(), &body.body.device_id)
20 .await
21 .map_err(|_| err!(Request(NotFound("Device not found."))))?;
22
23 Ok(get_device::v3::Response { device })
24}
25
26#[tracing::instrument(skip_all, fields(%client), name = "update_device")]
32pub(crate) async fn update_device_route(
33 State(services): State<crate::State>,
34 ClientIp(client): ClientIp,
35 body: Ruma<update_device::v3::Request>,
36) -> Result<update_device::v3::Response> {
37 let sender_user = body.sender_user();
38 let appservice = body.appservice_info.as_ref();
39
40 match services
41 .users
42 .get_device_metadata(sender_user, &body.device_id)
43 .await
44 {
45 | Ok(mut device) => {
46 let notify = device.display_name != body.display_name;
47 device.display_name.clone_from(&body.display_name);
48
49 device
50 .last_seen_ip
51 .clone_from(&Some(to_small_string(client)));
52
53 device
54 .last_seen_ts
55 .clone_from(&Some(MilliSecondsSinceUnixEpoch::now()));
56
57 assert_eq!(device.device_id, body.device_id, "device_id mismatch");
58 services
59 .users
60 .put_device_metadata(sender_user, notify, &device)
61 .await;
62
63 Ok(update_device::v3::Response::new())
64 },
65 | Err(_) => {
66 let Some(appservice) = appservice else {
67 return Err!(Request(NotFound("Device not found.")));
68 };
69
70 if !appservice.registration.device_management {
71 return Err!(Request(NotFound("Device management not enabled for appservice.")));
72 }
73
74 debug!(
75 "Creating new device for {sender_user} from appservice {} as MSC4190 is enabled \
76 and device ID does not exist",
77 appservice.registration.id
78 );
79
80 services
81 .users
82 .create_device(
83 sender_user,
84 Some(&body.device_id),
85 (None, None),
86 None,
87 body.display_name.as_deref(),
88 Some(client),
89 )
90 .await?;
91
92 Ok(update_device::v3::Response::created())
93 },
94 }
95}
96
97pub(crate) async fn delete_device_route(
108 State(services): State<crate::State>,
109 body: Ruma<delete_device::v3::Request>,
110) -> Result<delete_device::v3::Response> {
111 let appservice = body.appservice_info.as_ref();
112
113 if appservice.is_some_and(|appservice| appservice.registration.device_management) {
114 let sender_user = body.sender_user();
115 debug!(
116 "Skipping UIAA for {sender_user} as this is from an appservice and MSC4190 is \
117 enabled"
118 );
119 services
120 .users
121 .remove_device(sender_user, &body.device_id)
122 .await;
123
124 return Ok(delete_device::v3::Response {});
125 }
126
127 let ref sender_user = auth_uiaa(&services, &body).await?;
128
129 services
130 .users
131 .remove_device(sender_user, &body.device_id)
132 .await;
133
134 Ok(delete_device::v3::Response {})
135}