1use std::{
21 collections::{BTreeMap, HashMap, HashSet},
22 time::Duration,
23};
24
25use ruma::{OwnedDeviceId, OwnedRoomId, OwnedUserId};
26use serde::{Deserialize, Serialize};
27use vodozemac::{Curve25519PublicKey, base64_encode};
28use zeroize::{Zeroize, ZeroizeOnDrop};
29
30use super::{DehydrationError, GossipRequest};
31use crate::{
32 Account, Device, DeviceData, GossippedSecret, Session, UserIdentity, UserIdentityData,
33 olm::{
34 InboundGroupSession, OlmMessageHash, OutboundGroupSession, PrivateCrossSigningIdentity,
35 SenderData,
36 },
37 types::{
38 EventEncryptionAlgorithm,
39 events::{
40 room_key_bundle::RoomKeyBundleContent,
41 room_key_withheld::{RoomKeyWithheldContent, RoomKeyWithheldEvent},
42 },
43 },
44};
45
46#[derive(Default, Debug)]
52#[allow(missing_docs)]
53pub struct PendingChanges {
54 pub account: Option<Account>,
55}
56
57impl PendingChanges {
58 pub fn is_empty(&self) -> bool {
60 self.account.is_none()
61 }
62}
63
64#[derive(Default, Debug)]
67#[allow(missing_docs)]
68pub struct Changes {
69 pub private_identity: Option<PrivateCrossSigningIdentity>,
70 pub backup_version: Option<String>,
71 pub backup_decryption_key: Option<BackupDecryptionKey>,
72 pub dehydrated_device_pickle_key: Option<DehydratedDeviceKey>,
73 pub sessions: Vec<Session>,
74 pub message_hashes: Vec<OlmMessageHash>,
75 pub inbound_group_sessions: Vec<InboundGroupSession>,
76 pub outbound_group_sessions: Vec<OutboundGroupSession>,
77 pub key_requests: Vec<GossipRequest>,
78 pub identities: IdentityChanges,
79 pub devices: DeviceChanges,
80 pub withheld_session_info: BTreeMap<OwnedRoomId, BTreeMap<String, RoomKeyWithheldEntry>>,
82 pub room_settings: HashMap<OwnedRoomId, RoomSettings>,
83 pub secrets: Vec<GossippedSecret>,
84 pub next_batch_token: Option<String>,
85
86 pub received_room_key_bundles: Vec<StoredRoomKeyBundleData>,
89
90 pub room_key_backups_fully_downloaded: HashSet<OwnedRoomId>,
93}
94
95#[derive(Clone, Debug, Serialize, Deserialize)]
99pub struct StoredRoomKeyBundleData {
100 pub sender_user: OwnedUserId,
102
103 pub sender_key: Curve25519PublicKey,
105
106 pub sender_data: SenderData,
109
110 pub bundle_data: RoomKeyBundleContent,
112}
113
114#[derive(Clone, Debug, Serialize, Deserialize)]
116pub struct TrackedUser {
117 pub user_id: OwnedUserId,
119 pub dirty: bool,
124}
125
126impl Changes {
127 pub fn is_empty(&self) -> bool {
129 self.private_identity.is_none()
130 && self.backup_version.is_none()
131 && self.backup_decryption_key.is_none()
132 && self.dehydrated_device_pickle_key.is_none()
133 && self.sessions.is_empty()
134 && self.message_hashes.is_empty()
135 && self.inbound_group_sessions.is_empty()
136 && self.outbound_group_sessions.is_empty()
137 && self.key_requests.is_empty()
138 && self.identities.is_empty()
139 && self.devices.is_empty()
140 && self.withheld_session_info.is_empty()
141 && self.room_settings.is_empty()
142 && self.secrets.is_empty()
143 && self.next_batch_token.is_none()
144 && self.received_room_key_bundles.is_empty()
145 }
146}
147
148#[derive(Debug, Clone, Default)]
159#[allow(missing_docs)]
160pub struct IdentityChanges {
161 pub new: Vec<UserIdentityData>,
162 pub changed: Vec<UserIdentityData>,
163 pub unchanged: Vec<UserIdentityData>,
164}
165
166impl IdentityChanges {
167 pub(super) fn is_empty(&self) -> bool {
168 self.new.is_empty() && self.changed.is_empty()
169 }
170
171 pub(super) fn into_maps(
174 self,
175 ) -> (
176 BTreeMap<OwnedUserId, UserIdentityData>,
177 BTreeMap<OwnedUserId, UserIdentityData>,
178 BTreeMap<OwnedUserId, UserIdentityData>,
179 ) {
180 let new: BTreeMap<_, _> = self
181 .new
182 .into_iter()
183 .map(|identity| (identity.user_id().to_owned(), identity))
184 .collect();
185
186 let changed: BTreeMap<_, _> = self
187 .changed
188 .into_iter()
189 .map(|identity| (identity.user_id().to_owned(), identity))
190 .collect();
191
192 let unchanged: BTreeMap<_, _> = self
193 .unchanged
194 .into_iter()
195 .map(|identity| (identity.user_id().to_owned(), identity))
196 .collect();
197
198 (new, changed, unchanged)
199 }
200}
201
202#[derive(Debug, Clone, Default)]
203#[allow(missing_docs)]
204pub struct DeviceChanges {
205 pub new: Vec<DeviceData>,
206 pub changed: Vec<DeviceData>,
207 pub deleted: Vec<DeviceData>,
208}
209
210#[derive(Clone, Debug, Default)]
213pub struct DeviceUpdates {
214 pub new: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Device>>,
220 pub changed: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Device>>,
222}
223
224#[derive(Clone, Debug, Default)]
227pub struct IdentityUpdates {
228 pub new: BTreeMap<OwnedUserId, UserIdentity>,
234 pub changed: BTreeMap<OwnedUserId, UserIdentity>,
236 pub unchanged: BTreeMap<OwnedUserId, UserIdentity>,
238}
239
240#[derive(Clone, Zeroize, ZeroizeOnDrop, Deserialize, Serialize)]
250#[serde(transparent)]
251pub struct BackupDecryptionKey {
252 pub(crate) inner: Box<[u8; BackupDecryptionKey::KEY_SIZE]>,
253}
254
255impl BackupDecryptionKey {
256 pub const KEY_SIZE: usize = 32;
258
259 pub fn new() -> Result<Self, rand::Error> {
261 let mut rng = rand::thread_rng();
262
263 let mut key = Box::new([0u8; Self::KEY_SIZE]);
264 rand::Fill::try_fill(key.as_mut_slice(), &mut rng)?;
265
266 Ok(Self { inner: key })
267 }
268
269 pub fn to_base64(&self) -> String {
271 base64_encode(self.inner.as_slice())
272 }
273}
274
275#[cfg(not(tarpaulin_include))]
276impl std::fmt::Debug for BackupDecryptionKey {
277 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278 f.debug_tuple("BackupDecryptionKey").field(&"...").finish()
279 }
280}
281
282#[derive(Clone, Zeroize, ZeroizeOnDrop, Deserialize, Serialize)]
287#[serde(transparent)]
288pub struct DehydratedDeviceKey {
289 pub(crate) inner: Box<[u8; DehydratedDeviceKey::KEY_SIZE]>,
290}
291
292impl DehydratedDeviceKey {
293 pub const KEY_SIZE: usize = 32;
295
296 pub fn new() -> Result<Self, rand::Error> {
298 let mut rng = rand::thread_rng();
299
300 let mut key = Box::new([0u8; Self::KEY_SIZE]);
301 rand::Fill::try_fill(key.as_mut_slice(), &mut rng)?;
302
303 Ok(Self { inner: key })
304 }
305
306 pub fn from_slice(slice: &[u8]) -> Result<Self, DehydrationError> {
310 if slice.len() == 32 {
311 let mut key = Box::new([0u8; 32]);
312 key.copy_from_slice(slice);
313 Ok(DehydratedDeviceKey { inner: key })
314 } else {
315 Err(DehydrationError::PickleKeyLength(slice.len()))
316 }
317 }
318
319 pub fn from_bytes(raw_key: &[u8; 32]) -> Self {
321 let mut inner = Box::new([0u8; Self::KEY_SIZE]);
322 inner.copy_from_slice(raw_key);
323
324 Self { inner }
325 }
326
327 pub fn to_base64(&self) -> String {
329 base64_encode(self.inner.as_slice())
330 }
331}
332
333impl From<&[u8; 32]> for DehydratedDeviceKey {
334 fn from(value: &[u8; 32]) -> Self {
335 DehydratedDeviceKey { inner: Box::new(*value) }
336 }
337}
338
339impl From<DehydratedDeviceKey> for Vec<u8> {
340 fn from(key: DehydratedDeviceKey) -> Self {
341 key.inner.to_vec()
342 }
343}
344
345#[cfg(not(tarpaulin_include))]
346impl std::fmt::Debug for DehydratedDeviceKey {
347 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
348 f.debug_tuple("DehydratedDeviceKey").field(&"...").finish()
349 }
350}
351
352impl DeviceChanges {
353 pub fn extend(&mut self, other: DeviceChanges) {
355 self.new.extend(other.new);
356 self.changed.extend(other.changed);
357 self.deleted.extend(other.deleted);
358 }
359
360 pub fn is_empty(&self) -> bool {
362 self.new.is_empty() && self.changed.is_empty() && self.deleted.is_empty()
363 }
364}
365
366#[derive(Debug, Clone, Default)]
368pub struct RoomKeyCounts {
369 pub total: usize,
371 pub backed_up: usize,
373}
374
375#[derive(Default, Clone, Debug)]
377pub struct BackupKeys {
378 pub decryption_key: Option<BackupDecryptionKey>,
380 pub backup_version: Option<String>,
382}
383
384#[derive(Default, Zeroize, ZeroizeOnDrop)]
387pub struct CrossSigningKeyExport {
388 pub master_key: Option<String>,
390 pub self_signing_key: Option<String>,
392 pub user_signing_key: Option<String>,
394}
395
396#[cfg(not(tarpaulin_include))]
397impl std::fmt::Debug for CrossSigningKeyExport {
398 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
399 f.debug_struct("CrossSigningKeyExport")
400 .field("master_key", &self.master_key.is_some())
401 .field("self_signing_key", &self.self_signing_key.is_some())
402 .field("user_signing_key", &self.user_signing_key.is_some())
403 .finish_non_exhaustive()
404 }
405}
406
407#[derive(Clone, Copy, Debug, PartialEq, Eq)]
410pub(crate) enum UserKeyQueryResult {
411 WasPending,
412 WasNotPending,
413
414 TimeoutExpired,
416}
417
418#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
420pub struct RoomSettings {
421 pub algorithm: EventEncryptionAlgorithm,
423
424 #[cfg(feature = "experimental-encrypted-state-events")]
426 #[serde(default)]
427 pub encrypt_state_events: bool,
428
429 pub only_allow_trusted_devices: bool,
432
433 pub session_rotation_period: Option<Duration>,
436
437 pub session_rotation_period_messages: Option<usize>,
440}
441
442impl Default for RoomSettings {
443 fn default() -> Self {
444 Self {
445 algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
446 #[cfg(feature = "experimental-encrypted-state-events")]
447 encrypt_state_events: false,
448 only_allow_trusted_devices: false,
449 session_rotation_period: None,
450 session_rotation_period_messages: None,
451 }
452 }
453}
454
455#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
457pub struct RoomKeyInfo {
458 pub algorithm: EventEncryptionAlgorithm,
463
464 pub room_id: OwnedRoomId,
466
467 pub sender_key: Curve25519PublicKey,
469
470 pub session_id: String,
472}
473
474impl From<&InboundGroupSession> for RoomKeyInfo {
475 fn from(group_session: &InboundGroupSession) -> Self {
476 RoomKeyInfo {
477 algorithm: group_session.algorithm().clone(),
478 room_id: group_session.room_id().to_owned(),
479 sender_key: group_session.sender_key(),
480 session_id: group_session.session_id().to_owned(),
481 }
482 }
483}
484
485#[derive(Clone, Debug, Deserialize, Serialize)]
487pub struct RoomKeyWithheldInfo {
488 pub room_id: OwnedRoomId,
490
491 pub session_id: String,
493
494 pub withheld_event: RoomKeyWithheldEntry,
499}
500
501#[derive(Clone, Debug, Serialize, Deserialize)]
504pub struct RoomKeyWithheldEntry {
505 pub sender: OwnedUserId,
510 pub content: RoomKeyWithheldContent,
513}
514
515impl From<RoomKeyWithheldEvent> for RoomKeyWithheldEntry {
516 fn from(value: RoomKeyWithheldEvent) -> Self {
517 Self { sender: value.sender, content: value.content }
518 }
519}
520
521#[derive(Debug, Clone)]
529pub struct RoomKeyBundleInfo {
530 pub sender: OwnedUserId,
532
533 pub sender_key: Curve25519PublicKey,
535
536 pub room_id: OwnedRoomId,
538}
539
540impl From<&StoredRoomKeyBundleData> for RoomKeyBundleInfo {
541 fn from(value: &StoredRoomKeyBundleData) -> Self {
542 let StoredRoomKeyBundleData { sender_user, sender_data: _, bundle_data, sender_key } =
543 value;
544 let sender_key = *sender_key;
545
546 Self { sender: sender_user.clone(), room_id: bundle_data.room_id.clone(), sender_key }
547 }
548}