arminius_lib_user_keys/
one_time_keys.rs1use std::collections::BTreeMap;
8
9use arminius_lib_component::error::{InternalServerError, ResultExt as _};
10use arminius_lib_db::{Database as _, DefaultDb};
11use arminius_lib_db_keys::{FallbackKeysQueries as _, OneTimeKeysQueries as _};
12use ruma::{
13 OneTimeKeyAlgorithm, OwnedDeviceId, OwnedOneTimeKeyId, OwnedUserId, encryption::OneTimeKey,
14 serde::Raw,
15};
16use serde::{Deserialize, Serialize};
17
18use crate::FederatedKeyFailure;
19
20pub type RawOneTimeKeys =
29 BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>>>;
30
31#[derive(Debug, Deserialize, Serialize)]
33pub struct FederatedOneTimeKeys {
34 pub one_time_keys: RawOneTimeKeys,
36}
37
38#[derive(Debug, Deserialize, Serialize)]
40pub enum FederatedOTKResponse {
41 Success(FederatedOneTimeKeys),
43 Failure(FederatedKeyFailure),
45}
46
47pub async fn claim_local_keys(
53 database: &mut DefaultDb,
54 requested_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, OneTimeKeyAlgorithm>>,
55) -> Result<RawOneTimeKeys, InternalServerError> {
56 let mut transaction = database.begin_transaction().await?;
57
58 let mut onetime_keys = transaction.fetch_one_time_keys(&requested_keys).await?;
59
60 let mut result: RawOneTimeKeys = BTreeMap::new();
61 let mut otks_to_delete = Vec::new();
62 let mut missing_fallback_keys = BTreeMap::new();
63
64 for (req_user, req_devices) in requested_keys {
65 let Some(mut found_device_keys) = onetime_keys.remove(&req_user) else {
66 missing_fallback_keys.insert(req_user, req_devices);
67 continue;
68 };
69
70 for (req_device, req_algorithm) in req_devices {
71 let Some(mut found_device_otks) = found_device_keys.remove(&req_device) else {
72 missing_fallback_keys
73 .entry(req_user.clone())
74 .or_default()
75 .insert(req_device, req_algorithm);
76 continue;
77 };
78
79 if let Some((key_id, key)) = found_device_otks
80 .keys()
81 .find(|key_id| key_id.algorithm() == req_algorithm)
82 .cloned()
83 .and_then(|key_id| found_device_otks.remove_entry(&key_id))
84 {
85 let raw_key =
86 Raw::new(&key.key).unrecoverable_error("Converting one-time key to Raw")?;
87 otks_to_delete.push(key.nid);
88
89 result
90 .entry(req_user.clone())
91 .or_default()
92 .entry(req_device)
93 .or_default()
94 .insert(key_id, raw_key);
95 } else {
96 missing_fallback_keys
97 .entry(req_user.clone())
98 .or_default()
99 .entry(req_device)
100 .or_insert(req_algorithm);
101 }
102 }
103 }
104
105 transaction.delete_one_time_keys(&otks_to_delete).await?;
107
108 let fallback_keys = transaction.fetch_fallback_keys(&missing_fallback_keys).await?;
110
111 let fallback_keys_nids: Vec<i32> = fallback_keys
112 .values()
113 .flat_map(|keys| {
114 keys.values()
115 .flat_map(|keys| keys.values().map(|key| key.nid).collect::<Vec<_>>())
116 .collect::<Vec<_>>()
117 })
118 .collect();
119
120 for (user_id, found_device_keys) in fallback_keys {
121 for (device_id, found_device_otks) in found_device_keys {
122 for (key_id, key) in found_device_otks {
123 let raw_key =
124 Raw::new(&key.key).unrecoverable_error("Converting one-time key to Raw")?;
125
126 result
127 .entry(user_id.clone())
128 .or_default()
129 .entry(device_id.clone())
130 .or_default()
131 .insert(key_id, raw_key);
132 }
133 }
134 }
135
136 transaction.set_fallback_keys_used(&fallback_keys_nids).await?;
138
139 transaction.commit().await?;
140
141 Ok(result)
142}