1use std::{
21 collections::{BTreeMap, HashMap, HashSet},
22 time::Duration,
23};
24
25use ruma::{MilliSecondsSinceUnixEpoch, 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 pub rooms_pending_key_bundle: HashMap<OwnedRoomId, Option<RoomPendingKeyBundleDetails>>,
97}
98
99#[derive(Clone, Debug, Serialize, Deserialize)]
103pub struct StoredRoomKeyBundleData {
104 pub sender_user: OwnedUserId,
106
107 pub sender_key: Curve25519PublicKey,
109
110 pub sender_data: SenderData,
113
114 pub bundle_data: RoomKeyBundleContent,
116}
117
118#[derive(Clone, Debug, Serialize, Deserialize)]
120pub struct TrackedUser {
121 pub user_id: OwnedUserId,
123 pub dirty: bool,
128}
129
130impl Changes {
131 pub fn is_empty(&self) -> bool {
133 self.private_identity.is_none()
134 && self.backup_version.is_none()
135 && self.backup_decryption_key.is_none()
136 && self.dehydrated_device_pickle_key.is_none()
137 && self.sessions.is_empty()
138 && self.message_hashes.is_empty()
139 && self.inbound_group_sessions.is_empty()
140 && self.outbound_group_sessions.is_empty()
141 && self.key_requests.is_empty()
142 && self.identities.is_empty()
143 && self.devices.is_empty()
144 && self.withheld_session_info.is_empty()
145 && self.room_settings.is_empty()
146 && self.secrets.is_empty()
147 && self.next_batch_token.is_none()
148 && self.received_room_key_bundles.is_empty()
149 }
150}
151
152#[derive(Debug, Clone, Default)]
163#[allow(missing_docs)]
164pub struct IdentityChanges {
165 pub new: Vec<UserIdentityData>,
166 pub changed: Vec<UserIdentityData>,
167 pub unchanged: Vec<UserIdentityData>,
168}
169
170impl IdentityChanges {
171 pub(super) fn is_empty(&self) -> bool {
172 self.new.is_empty() && self.changed.is_empty()
173 }
174
175 pub(super) fn into_maps(
178 self,
179 ) -> (
180 BTreeMap<OwnedUserId, UserIdentityData>,
181 BTreeMap<OwnedUserId, UserIdentityData>,
182 BTreeMap<OwnedUserId, UserIdentityData>,
183 ) {
184 let new: BTreeMap<_, _> = self
185 .new
186 .into_iter()
187 .map(|identity| (identity.user_id().to_owned(), identity))
188 .collect();
189
190 let changed: BTreeMap<_, _> = self
191 .changed
192 .into_iter()
193 .map(|identity| (identity.user_id().to_owned(), identity))
194 .collect();
195
196 let unchanged: BTreeMap<_, _> = self
197 .unchanged
198 .into_iter()
199 .map(|identity| (identity.user_id().to_owned(), identity))
200 .collect();
201
202 (new, changed, unchanged)
203 }
204}
205
206#[derive(Debug, Clone, Default)]
207#[allow(missing_docs)]
208pub struct DeviceChanges {
209 pub new: Vec<DeviceData>,
210 pub changed: Vec<DeviceData>,
211 pub deleted: Vec<DeviceData>,
212}
213
214#[derive(Clone, Debug, Default)]
217pub struct DeviceUpdates {
218 pub new: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Device>>,
224 pub changed: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Device>>,
226}
227
228#[derive(Clone, Debug, Default)]
231pub struct IdentityUpdates {
232 pub new: BTreeMap<OwnedUserId, UserIdentity>,
238 pub changed: BTreeMap<OwnedUserId, UserIdentity>,
240 pub unchanged: BTreeMap<OwnedUserId, UserIdentity>,
242}
243
244#[derive(Clone, Zeroize, ZeroizeOnDrop, Deserialize, Serialize)]
254#[serde(transparent)]
255pub struct BackupDecryptionKey {
256 pub(crate) inner: Box<[u8; BackupDecryptionKey::KEY_SIZE]>,
257}
258
259impl BackupDecryptionKey {
260 pub const KEY_SIZE: usize = 32;
262
263 pub fn new() -> Result<Self, rand::Error> {
265 let mut rng = rand::thread_rng();
266
267 let mut key = Box::new([0u8; Self::KEY_SIZE]);
268 rand::Fill::try_fill(key.as_mut_slice(), &mut rng)?;
269
270 Ok(Self { inner: key })
271 }
272
273 pub fn to_base64(&self) -> String {
275 base64_encode(self.inner.as_slice())
276 }
277}
278
279#[cfg(not(tarpaulin_include))]
280impl std::fmt::Debug for BackupDecryptionKey {
281 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
282 f.debug_tuple("BackupDecryptionKey").field(&"...").finish()
283 }
284}
285
286#[derive(Clone, Zeroize, ZeroizeOnDrop, Deserialize, Serialize)]
291#[serde(transparent)]
292pub struct DehydratedDeviceKey {
293 pub(crate) inner: Box<[u8; DehydratedDeviceKey::KEY_SIZE]>,
294}
295
296impl DehydratedDeviceKey {
297 pub const KEY_SIZE: usize = 32;
299
300 pub fn new() -> Result<Self, rand::Error> {
302 let mut rng = rand::thread_rng();
303
304 let mut key = Box::new([0u8; Self::KEY_SIZE]);
305 rand::Fill::try_fill(key.as_mut_slice(), &mut rng)?;
306
307 Ok(Self { inner: key })
308 }
309
310 pub fn from_slice(slice: &[u8]) -> Result<Self, DehydrationError> {
314 if slice.len() == 32 {
315 let mut key = Box::new([0u8; 32]);
316 key.copy_from_slice(slice);
317 Ok(DehydratedDeviceKey { inner: key })
318 } else {
319 Err(DehydrationError::PickleKeyLength(slice.len()))
320 }
321 }
322
323 pub fn from_bytes(raw_key: &[u8; 32]) -> Self {
325 let mut inner = Box::new([0u8; Self::KEY_SIZE]);
326 inner.copy_from_slice(raw_key);
327
328 Self { inner }
329 }
330
331 pub fn to_base64(&self) -> String {
333 base64_encode(self.inner.as_slice())
334 }
335}
336
337impl From<&[u8; 32]> for DehydratedDeviceKey {
338 fn from(value: &[u8; 32]) -> Self {
339 DehydratedDeviceKey { inner: Box::new(*value) }
340 }
341}
342
343impl From<DehydratedDeviceKey> for Vec<u8> {
344 fn from(key: DehydratedDeviceKey) -> Self {
345 key.inner.to_vec()
346 }
347}
348
349#[cfg(not(tarpaulin_include))]
350impl std::fmt::Debug for DehydratedDeviceKey {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 f.debug_tuple("DehydratedDeviceKey").field(&"...").finish()
353 }
354}
355
356impl DeviceChanges {
357 pub fn extend(&mut self, other: DeviceChanges) {
359 self.new.extend(other.new);
360 self.changed.extend(other.changed);
361 self.deleted.extend(other.deleted);
362 }
363
364 pub fn is_empty(&self) -> bool {
366 self.new.is_empty() && self.changed.is_empty() && self.deleted.is_empty()
367 }
368}
369
370#[derive(Debug, Clone, Default)]
372pub struct RoomKeyCounts {
373 pub total: usize,
375 pub backed_up: usize,
377}
378
379#[derive(Default, Clone, Debug)]
381pub struct BackupKeys {
382 pub decryption_key: Option<BackupDecryptionKey>,
384 pub backup_version: Option<String>,
386}
387
388#[derive(Default, Zeroize, ZeroizeOnDrop)]
391pub struct CrossSigningKeyExport {
392 pub master_key: Option<String>,
394 pub self_signing_key: Option<String>,
396 pub user_signing_key: Option<String>,
398}
399
400#[cfg(not(tarpaulin_include))]
401impl std::fmt::Debug for CrossSigningKeyExport {
402 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
403 f.debug_struct("CrossSigningKeyExport")
404 .field("master_key", &self.master_key.is_some())
405 .field("self_signing_key", &self.self_signing_key.is_some())
406 .field("user_signing_key", &self.user_signing_key.is_some())
407 .finish_non_exhaustive()
408 }
409}
410
411#[derive(Clone, Copy, Debug, PartialEq, Eq)]
414pub(crate) enum UserKeyQueryResult {
415 WasPending,
416 WasNotPending,
417
418 TimeoutExpired,
420}
421
422#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
424pub struct RoomSettings {
425 pub algorithm: EventEncryptionAlgorithm,
427
428 #[cfg(feature = "experimental-encrypted-state-events")]
430 #[serde(default)]
431 pub encrypt_state_events: bool,
432
433 pub only_allow_trusted_devices: bool,
436
437 pub session_rotation_period: Option<Duration>,
440
441 pub session_rotation_period_messages: Option<usize>,
444}
445
446impl Default for RoomSettings {
447 fn default() -> Self {
448 Self {
449 algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
450 #[cfg(feature = "experimental-encrypted-state-events")]
451 encrypt_state_events: false,
452 only_allow_trusted_devices: false,
453 session_rotation_period: None,
454 session_rotation_period_messages: None,
455 }
456 }
457}
458
459#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
461pub struct RoomKeyInfo {
462 pub algorithm: EventEncryptionAlgorithm,
467
468 pub room_id: OwnedRoomId,
470
471 pub sender_key: Curve25519PublicKey,
473
474 pub session_id: String,
476}
477
478impl From<&InboundGroupSession> for RoomKeyInfo {
479 fn from(group_session: &InboundGroupSession) -> Self {
480 RoomKeyInfo {
481 algorithm: group_session.algorithm().clone(),
482 room_id: group_session.room_id().to_owned(),
483 sender_key: group_session.sender_key(),
484 session_id: group_session.session_id().to_owned(),
485 }
486 }
487}
488
489#[derive(Clone, Debug, Deserialize, Serialize)]
491pub struct RoomKeyWithheldInfo {
492 pub room_id: OwnedRoomId,
494
495 pub session_id: String,
497
498 pub withheld_event: RoomKeyWithheldEntry,
503}
504
505#[derive(Clone, Debug, Serialize, Deserialize)]
508pub struct RoomKeyWithheldEntry {
509 pub sender: OwnedUserId,
514 pub content: RoomKeyWithheldContent,
517}
518
519impl From<RoomKeyWithheldEvent> for RoomKeyWithheldEntry {
520 fn from(value: RoomKeyWithheldEvent) -> Self {
521 Self { sender: value.sender, content: value.content }
522 }
523}
524
525#[derive(Debug, Clone)]
533pub struct RoomKeyBundleInfo {
534 pub sender: OwnedUserId,
536
537 pub sender_key: Curve25519PublicKey,
539
540 pub room_id: OwnedRoomId,
542}
543
544impl From<&StoredRoomKeyBundleData> for RoomKeyBundleInfo {
545 fn from(value: &StoredRoomKeyBundleData) -> Self {
546 let StoredRoomKeyBundleData { sender_user, sender_data: _, bundle_data, sender_key } =
547 value;
548 let sender_key = *sender_key;
549
550 Self { sender: sender_user.clone(), room_id: bundle_data.room_id.clone(), sender_key }
551 }
552}
553
554#[derive(Debug, Clone, Serialize, Deserialize)]
557pub struct RoomPendingKeyBundleDetails {
558 pub room_id: OwnedRoomId,
562
563 pub invite_accepted_at: MilliSecondsSinceUnixEpoch,
566
567 pub inviter: OwnedUserId,
569}