tuwunel_api/client/keys/
upload_keys.rs1use axum::extract::State;
2use ruma::{
3 DeviceId, UserId, api::client::keys::upload_keys, encryption::DeviceKeys, serde::Raw,
4};
5use tuwunel_core::{Err, Result, debug, err};
6use tuwunel_service::Services;
7
8use crate::Ruma;
9
10pub(crate) async fn upload_keys_route(
18 State(services): State<crate::State>,
19 body: Ruma<upload_keys::v3::Request>,
20) -> Result<upload_keys::v3::Response> {
21 let sender_user = body.sender_user();
22 let sender_device = body.sender_device()?;
23
24 services
25 .users
26 .add_one_time_keys(
27 sender_user,
28 sender_device,
29 &body.one_time_keys,
30 services.config.one_time_key_limit,
31 )
32 .await?;
33
34 let fallback_keys = body
35 .fallback_keys
36 .iter()
37 .map(|(id, val)| (id.as_ref(), val));
38
39 services
40 .users
41 .add_fallback_keys(sender_user, sender_device, fallback_keys)
42 .await?;
43
44 if let Some(device_keys) = body.device_keys.as_ref() {
45 store_device_keys(&services, sender_user, sender_device, device_keys).await?;
46 }
47
48 Ok(upload_keys::v3::Response {
49 one_time_key_counts: services
50 .users
51 .count_one_time_keys(sender_user, sender_device)
52 .await,
53 })
54}
55
56async fn store_device_keys(
57 services: &Services,
58 sender_user: &UserId,
59 sender_device: &DeviceId,
60 device_keys: &Raw<DeviceKeys>,
61) -> Result {
62 let new_keys = device_keys.deserialize().map_err(|e| {
63 err!(Request(BadJson(debug_warn!(
64 ?device_keys,
65 "Invalid device keys JSON uploaded by client: {e}"
66 ))))
67 })?;
68
69 if new_keys.user_id != sender_user {
70 return Err!(Request(Unknown(
71 "User ID in keys uploaded does not match your own user ID"
72 )));
73 }
74 if new_keys.device_id != sender_device {
75 return Err!(Request(Unknown(
76 "Device ID in keys uploaded does not match your own device ID"
77 )));
78 }
79
80 let unchanged = services
84 .users
85 .get_device_keys(sender_user, sender_device)
86 .await
87 .and_then(|keys| keys.deserialize().map_err(Into::into))
88 .is_ok_and(|existing| existing.keys == new_keys.keys);
89
90 if unchanged {
91 debug!(
92 ?sender_user,
93 ?sender_device,
94 ?device_keys,
95 "Ignoring user uploaded keys as they are an exact copy already in the database"
96 );
97
98 return Ok(());
99 }
100
101 services
102 .users
103 .add_device_keys(sender_user, sender_device, device_keys)
104 .await;
105
106 Ok(())
107}