1use std::{
21 collections::{BTreeMap, HashMap},
22 time::Duration,
23};
24
25use ruma::{OwnedDeviceId, OwnedRoomId, OwnedUserId};
26use serde::{Deserialize, Serialize};
27use vodozemac::{base64_encode, Curve25519PublicKey};
28use zeroize::{Zeroize, ZeroizeOnDrop};
29
30use super::{DehydrationError, GossipRequest};
31use crate::{
32 olm::{
33 InboundGroupSession, OlmMessageHash, OutboundGroupSession, PrivateCrossSigningIdentity,
34 SenderData,
35 },
36 types::{
37 events::{
38 room_key_bundle::RoomKeyBundleContent,
39 room_key_withheld::{RoomKeyWithheldContent, RoomKeyWithheldEvent},
40 },
41 EventEncryptionAlgorithm,
42 },
43 Account, Device, DeviceData, GossippedSecret, Session, UserIdentity, UserIdentityData,
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
91#[derive(Clone, Debug, Serialize, Deserialize)]
95pub struct StoredRoomKeyBundleData {
96 pub sender_user: OwnedUserId,
98
99 pub sender_key: Curve25519PublicKey,
101
102 pub sender_data: SenderData,
105
106 pub bundle_data: RoomKeyBundleContent,
108}
109
110#[derive(Clone, Debug, Serialize, Deserialize)]
112pub struct TrackedUser {
113 pub user_id: OwnedUserId,
115 pub dirty: bool,
120}
121
122impl Changes {
123 pub fn is_empty(&self) -> bool {
125 self.private_identity.is_none()
126 && self.backup_version.is_none()
127 && self.backup_decryption_key.is_none()
128 && self.dehydrated_device_pickle_key.is_none()
129 && self.sessions.is_empty()
130 && self.message_hashes.is_empty()
131 && self.inbound_group_sessions.is_empty()
132 && self.outbound_group_sessions.is_empty()
133 && self.key_requests.is_empty()
134 && self.identities.is_empty()
135 && self.devices.is_empty()
136 && self.withheld_session_info.is_empty()
137 && self.room_settings.is_empty()
138 && self.secrets.is_empty()
139 && self.next_batch_token.is_none()
140 && self.received_room_key_bundles.is_empty()
141 }
142}
143
144#[derive(Debug, Clone, Default)]
155#[allow(missing_docs)]
156pub struct IdentityChanges {
157 pub new: Vec<UserIdentityData>,
158 pub changed: Vec<UserIdentityData>,
159 pub unchanged: Vec<UserIdentityData>,
160}
161
162impl IdentityChanges {
163 pub(super) fn is_empty(&self) -> bool {
164 self.new.is_empty() && self.changed.is_empty()
165 }
166
167 pub(super) fn into_maps(
170 self,
171 ) -> (
172 BTreeMap<OwnedUserId, UserIdentityData>,
173 BTreeMap<OwnedUserId, UserIdentityData>,
174 BTreeMap<OwnedUserId, UserIdentityData>,
175 ) {
176 let new: BTreeMap<_, _> = self
177 .new
178 .into_iter()
179 .map(|identity| (identity.user_id().to_owned(), identity))
180 .collect();
181
182 let changed: BTreeMap<_, _> = self
183 .changed
184 .into_iter()
185 .map(|identity| (identity.user_id().to_owned(), identity))
186 .collect();
187
188 let unchanged: BTreeMap<_, _> = self
189 .unchanged
190 .into_iter()
191 .map(|identity| (identity.user_id().to_owned(), identity))
192 .collect();
193
194 (new, changed, unchanged)
195 }
196}
197
198#[derive(Debug, Clone, Default)]
199#[allow(missing_docs)]
200pub struct DeviceChanges {
201 pub new: Vec<DeviceData>,
202 pub changed: Vec<DeviceData>,
203 pub deleted: Vec<DeviceData>,
204}
205
206#[derive(Clone, Debug, Default)]
209pub struct DeviceUpdates {
210 pub new: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Device>>,
216 pub changed: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Device>>,
218}
219
220#[derive(Clone, Debug, Default)]
223pub struct IdentityUpdates {
224 pub new: BTreeMap<OwnedUserId, UserIdentity>,
230 pub changed: BTreeMap<OwnedUserId, UserIdentity>,
232 pub unchanged: BTreeMap<OwnedUserId, UserIdentity>,
234}
235
236#[derive(Clone, Zeroize, ZeroizeOnDrop, Deserialize, Serialize)]
246#[serde(transparent)]
247pub struct BackupDecryptionKey {
248 pub(crate) inner: Box<[u8; BackupDecryptionKey::KEY_SIZE]>,
249}
250
251impl BackupDecryptionKey {
252 pub const KEY_SIZE: usize = 32;
254
255 pub fn new() -> Result<Self, rand::Error> {
257 let mut rng = rand::thread_rng();
258
259 let mut key = Box::new([0u8; Self::KEY_SIZE]);
260 rand::Fill::try_fill(key.as_mut_slice(), &mut rng)?;
261
262 Ok(Self { inner: key })
263 }
264
265 pub fn to_base64(&self) -> String {
267 base64_encode(self.inner.as_slice())
268 }
269}
270
271#[cfg(not(tarpaulin_include))]
272impl std::fmt::Debug for BackupDecryptionKey {
273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274 f.debug_tuple("BackupDecryptionKey").field(&"...").finish()
275 }
276}
277
278#[derive(Clone, Zeroize, ZeroizeOnDrop, Deserialize, Serialize)]
283#[serde(transparent)]
284pub struct DehydratedDeviceKey {
285 pub(crate) inner: Box<[u8; DehydratedDeviceKey::KEY_SIZE]>,
286}
287
288impl DehydratedDeviceKey {
289 pub const KEY_SIZE: usize = 32;
291
292 pub fn new() -> Result<Self, rand::Error> {
294 let mut rng = rand::thread_rng();
295
296 let mut key = Box::new([0u8; Self::KEY_SIZE]);
297 rand::Fill::try_fill(key.as_mut_slice(), &mut rng)?;
298
299 Ok(Self { inner: key })
300 }
301
302 pub fn from_slice(slice: &[u8]) -> Result<Self, DehydrationError> {
306 if slice.len() == 32 {
307 let mut key = Box::new([0u8; 32]);
308 key.copy_from_slice(slice);
309 Ok(DehydratedDeviceKey { inner: key })
310 } else {
311 Err(DehydrationError::PickleKeyLength(slice.len()))
312 }
313 }
314
315 pub fn from_bytes(raw_key: &[u8; 32]) -> Self {
317 let mut inner = Box::new([0u8; Self::KEY_SIZE]);
318 inner.copy_from_slice(raw_key);
319
320 Self { inner }
321 }
322
323 pub fn to_base64(&self) -> String {
325 base64_encode(self.inner.as_slice())
326 }
327}
328
329impl From<&[u8; 32]> for DehydratedDeviceKey {
330 fn from(value: &[u8; 32]) -> Self {
331 DehydratedDeviceKey { inner: Box::new(*value) }
332 }
333}
334
335impl From<DehydratedDeviceKey> for Vec<u8> {
336 fn from(key: DehydratedDeviceKey) -> Self {
337 key.inner.to_vec()
338 }
339}
340
341#[cfg(not(tarpaulin_include))]
342impl std::fmt::Debug for DehydratedDeviceKey {
343 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
344 f.debug_tuple("DehydratedDeviceKey").field(&"...").finish()
345 }
346}
347
348impl DeviceChanges {
349 pub fn extend(&mut self, other: DeviceChanges) {
351 self.new.extend(other.new);
352 self.changed.extend(other.changed);
353 self.deleted.extend(other.deleted);
354 }
355
356 pub fn is_empty(&self) -> bool {
358 self.new.is_empty() && self.changed.is_empty() && self.deleted.is_empty()
359 }
360}
361
362#[derive(Debug, Clone, Default)]
364pub struct RoomKeyCounts {
365 pub total: usize,
367 pub backed_up: usize,
369}
370
371#[derive(Default, Clone, Debug)]
373pub struct BackupKeys {
374 pub decryption_key: Option<BackupDecryptionKey>,
376 pub backup_version: Option<String>,
378}
379
380#[derive(Default, Zeroize, ZeroizeOnDrop)]
383pub struct CrossSigningKeyExport {
384 pub master_key: Option<String>,
386 pub self_signing_key: Option<String>,
388 pub user_signing_key: Option<String>,
390}
391
392#[cfg(not(tarpaulin_include))]
393impl std::fmt::Debug for CrossSigningKeyExport {
394 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
395 f.debug_struct("CrossSigningKeyExport")
396 .field("master_key", &self.master_key.is_some())
397 .field("self_signing_key", &self.self_signing_key.is_some())
398 .field("user_signing_key", &self.user_signing_key.is_some())
399 .finish_non_exhaustive()
400 }
401}
402
403#[derive(Clone, Copy, Debug, PartialEq, Eq)]
406pub(crate) enum UserKeyQueryResult {
407 WasPending,
408 WasNotPending,
409
410 TimeoutExpired,
412}
413
414#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
416pub struct RoomSettings {
417 pub algorithm: EventEncryptionAlgorithm,
419
420 #[cfg(feature = "experimental-encrypted-state-events")]
422 #[serde(default)]
423 pub encrypt_state_events: bool,
424
425 pub only_allow_trusted_devices: bool,
428
429 pub session_rotation_period: Option<Duration>,
432
433 pub session_rotation_period_messages: Option<usize>,
436}
437
438impl Default for RoomSettings {
439 fn default() -> Self {
440 Self {
441 algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
442 #[cfg(feature = "experimental-encrypted-state-events")]
443 encrypt_state_events: false,
444 only_allow_trusted_devices: false,
445 session_rotation_period: None,
446 session_rotation_period_messages: None,
447 }
448 }
449}
450
451#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
453pub struct RoomKeyInfo {
454 pub algorithm: EventEncryptionAlgorithm,
459
460 pub room_id: OwnedRoomId,
462
463 pub sender_key: Curve25519PublicKey,
465
466 pub session_id: String,
468}
469
470impl From<&InboundGroupSession> for RoomKeyInfo {
471 fn from(group_session: &InboundGroupSession) -> Self {
472 RoomKeyInfo {
473 algorithm: group_session.algorithm().clone(),
474 room_id: group_session.room_id().to_owned(),
475 sender_key: group_session.sender_key(),
476 session_id: group_session.session_id().to_owned(),
477 }
478 }
479}
480
481#[derive(Clone, Debug, Deserialize, Serialize)]
483pub struct RoomKeyWithheldInfo {
484 pub room_id: OwnedRoomId,
486
487 pub session_id: String,
489
490 pub withheld_event: RoomKeyWithheldEntry,
495}
496
497#[derive(Clone, Debug, Serialize, Deserialize)]
500pub struct RoomKeyWithheldEntry {
501 pub sender: OwnedUserId,
506 pub content: RoomKeyWithheldContent,
509}
510
511impl From<RoomKeyWithheldEvent> for RoomKeyWithheldEntry {
512 fn from(value: RoomKeyWithheldEvent) -> Self {
513 Self { sender: value.sender, content: value.content }
514 }
515}
516
517#[derive(Debug, Clone)]
525pub struct RoomKeyBundleInfo {
526 pub sender: OwnedUserId,
528
529 pub sender_key: Curve25519PublicKey,
531
532 pub room_id: OwnedRoomId,
534}
535
536impl From<&StoredRoomKeyBundleData> for RoomKeyBundleInfo {
537 fn from(value: &StoredRoomKeyBundleData) -> Self {
538 let StoredRoomKeyBundleData { sender_user, sender_data: _, bundle_data, sender_key } =
539 value;
540 let sender_key = *sender_key;
541
542 Self { sender: sender_user.clone(), room_id: bundle_data.room_id.clone(), sender_key }
543 }
544}