tuwunel_api/server/
user.rs1use axum::extract::State;
2use futures::{FutureExt, StreamExt, TryFutureExt, future::join3};
3use ruma::{
4 UserId,
5 api::{
6 client::device::Device,
7 federation::{
8 device::get_devices::{
9 self,
10 v1::{Response as GetDevicesResponse, UserDevice},
11 },
12 keys::{claim_keys, get_keys},
13 },
14 },
15 uint,
16};
17use tuwunel_core::{Err, Result, utils::future::TryExtExt};
18
19use crate::{
20 Ruma,
21 client::{claim_keys_helper, get_keys_helper},
22};
23
24pub(crate) async fn get_devices_route(
28 State(services): State<crate::State>,
29 body: Ruma<get_devices::v1::Request>,
30) -> Result<get_devices::v1::Response> {
31 let user_id = &body.user_id;
32 if !services.globals.user_is_local(user_id) {
33 return Err!(Request(InvalidParam("Tried to access user from other server.")));
34 }
35
36 let allowed_signatures = |u: &UserId| u.server_name() == body.origin();
37 let stream_id = services
38 .users
39 .get_devicelist_version(user_id)
40 .map_ok(TryInto::try_into)
41 .map_ok(Result::ok)
42 .ok()
43 .await;
44
45 let master_key = services
46 .users
47 .get_master_key(None, user_id, &allowed_signatures)
48 .ok();
49
50 let self_signing_key = services
51 .users
52 .get_self_signing_key(None, user_id, &allowed_signatures)
53 .ok();
54
55 let devices = services
56 .users
57 .all_devices_metadata(user_id)
58 .filter_map(async |Device { device_id, display_name, .. }: Device| {
59 let device_display_name = services
60 .config
61 .allow_device_name_federation
62 .then_some(display_name)
63 .flatten()
64 .or_else(|| Some(device_id.as_str().into()));
65
66 services
67 .users
68 .get_device_keys(user_id, &device_id)
69 .map_ok(|keys| UserDevice {
70 device_id: device_id.clone(),
71 device_display_name,
72 keys,
73 })
74 .map(Result::ok)
75 .await
76 })
77 .collect::<Vec<_>>();
78
79 let (master_key, self_signing_key, devices) = join3(master_key, self_signing_key, devices)
81 .boxed()
82 .await;
83
84 Ok(GetDevicesResponse {
85 user_id: body.body.user_id,
86 stream_id: stream_id.flatten().unwrap_or_else(|| uint!(0)),
87 devices,
88 self_signing_key,
89 master_key,
90 })
91}
92
93pub(crate) async fn get_keys_route(
97 State(services): State<crate::State>,
98 body: Ruma<get_keys::v1::Request>,
99) -> Result<get_keys::v1::Response> {
100 if body
101 .device_keys
102 .iter()
103 .any(|(u, _)| !services.globals.user_is_local(u))
104 {
105 return Err!(Request(InvalidParam("User does not belong to this server.")));
106 }
107
108 let result = get_keys_helper(
109 &services,
110 None,
111 &body.device_keys,
112 |u| Some(u.server_name()) == body.origin.as_deref(),
113 services.config.allow_device_name_federation,
114 )
115 .await?;
116
117 Ok(get_keys::v1::Response {
118 device_keys: result.device_keys,
119 master_keys: result.master_keys,
120 self_signing_keys: result.self_signing_keys,
121 })
122}
123
124pub(crate) async fn claim_keys_route(
128 State(services): State<crate::State>,
129 body: Ruma<claim_keys::v1::Request>,
130) -> Result<claim_keys::v1::Response> {
131 if body
132 .one_time_keys
133 .iter()
134 .any(|(u, _)| !services.globals.user_is_local(u))
135 {
136 return Err!(Request(InvalidParam("Tried to access user from other server.")));
137 }
138
139 let result = claim_keys_helper(&services, &body.one_time_keys).await?;
140
141 Ok(claim_keys::v1::Response { one_time_keys: result.one_time_keys })
142}