1use std::{
16 collections::{BTreeMap, HashMap, HashSet},
17 sync::Arc,
18 time::Duration,
19};
20
21use itertools::Itertools;
22#[cfg(feature = "experimental-send-custom-to-device")]
23use matrix_sdk_common::deserialized_responses::WithheldCode;
24use matrix_sdk_common::{
25 deserialized_responses::{
26 AlgorithmInfo, DecryptedRoomEvent, DeviceLinkProblem, EncryptionInfo,
27 ProcessedToDeviceEvent, UnableToDecryptInfo, UnableToDecryptReason,
28 UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel, VerificationState,
29 },
30 locks::RwLock as StdRwLock,
31 BoxFuture,
32};
33use ruma::{
34 api::client::{
35 dehydrated_device::DehydratedDeviceData,
36 keys::{
37 claim_keys::v3::Request as KeysClaimRequest,
38 get_keys::v3::Response as KeysQueryResponse,
39 upload_keys::v3::{Request as UploadKeysRequest, Response as UploadKeysResponse},
40 upload_signatures::v3::Request as UploadSignaturesRequest,
41 },
42 sync::sync_events::DeviceLists,
43 },
44 assign,
45 events::{
46 secret::request::SecretName, AnyMessageLikeEvent, AnyMessageLikeEventContent,
47 AnyToDeviceEvent, MessageLikeEventContent,
48 },
49 serde::{JsonObject, Raw},
50 DeviceId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OwnedDeviceId, OwnedDeviceKeyId,
51 OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UInt, UserId,
52};
53use serde_json::{value::to_raw_value, Value};
54use tokio::sync::Mutex;
55use tracing::{
56 debug, error,
57 field::{debug, display},
58 info, instrument, trace, warn, Span,
59};
60use vodozemac::{
61 megolm::{DecryptionError, SessionOrdering},
62 Curve25519PublicKey, Ed25519Signature,
63};
64
65use crate::{
66 backups::{BackupMachine, MegolmV1BackupKey},
67 dehydrated_devices::{DehydratedDevices, DehydrationError},
68 error::{EventError, MegolmError, MegolmResult, OlmError, OlmResult, SetRoomSettingsError},
69 gossiping::GossipMachine,
70 identities::{user::UserIdentity, Device, IdentityManager, UserDevices},
71 olm::{
72 Account, CrossSigningStatus, EncryptionSettings, IdentityKeys, InboundGroupSession,
73 KnownSenderData, OlmDecryptionInfo, PrivateCrossSigningIdentity, SenderData,
74 SenderDataFinder, SessionType, StaticAccountData,
75 },
76 session_manager::{GroupSessionManager, SessionManager},
77 store::{
78 caches::StoreCache,
79 types::{
80 Changes, CrossSigningKeyExport, DeviceChanges, IdentityChanges, PendingChanges,
81 RoomKeyInfo, RoomSettings, StoredRoomKeyBundleData,
82 },
83 CryptoStoreWrapper, IntoCryptoStore, MemoryStore, Result as StoreResult, SecretImportError,
84 Store, StoreTransaction,
85 },
86 types::{
87 events::{
88 olm_v1::{AnyDecryptedOlmEvent, DecryptedRoomKeyBundleEvent, DecryptedRoomKeyEvent},
89 room::encrypted::{
90 EncryptedEvent, EncryptedToDeviceEvent, RoomEncryptedEventContent,
91 RoomEventEncryptionScheme, SupportedEventEncryptionSchemes,
92 ToDeviceEncryptedEventContent,
93 },
94 room_key::{MegolmV1AesSha2Content, RoomKeyContent},
95 room_key_bundle::RoomKeyBundleContent,
96 room_key_withheld::{
97 MegolmV1AesSha2WithheldContent, RoomKeyWithheldContent, RoomKeyWithheldEvent,
98 },
99 ToDeviceEvent, ToDeviceEvents,
100 },
101 requests::{
102 AnyIncomingResponse, KeysQueryRequest, OutgoingRequest, ToDeviceRequest,
103 UploadSigningKeysRequest,
104 },
105 EventEncryptionAlgorithm, Signatures,
106 },
107 utilities::timestamp_to_iso8601,
108 verification::{Verification, VerificationMachine, VerificationRequest},
109 CollectStrategy, CryptoStoreError, DecryptionSettings, DeviceData, LocalTrust,
110 RoomEventDecryptionResult, SignatureError, TrustRequirement,
111};
112
113#[derive(Clone)]
116pub struct OlmMachine {
117 pub(crate) inner: Arc<OlmMachineInner>,
118}
119
120pub struct OlmMachineInner {
121 user_id: OwnedUserId,
123 device_id: OwnedDeviceId,
125 user_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
130 store: Store,
134 session_manager: SessionManager,
136 pub(crate) group_session_manager: GroupSessionManager,
138 verification_machine: VerificationMachine,
141 pub(crate) key_request_machine: GossipMachine,
144 identity_manager: IdentityManager,
147 backup_machine: BackupMachine,
149}
150
151#[cfg(not(tarpaulin_include))]
152impl std::fmt::Debug for OlmMachine {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 f.debug_struct("OlmMachine")
155 .field("user_id", &self.user_id())
156 .field("device_id", &self.device_id())
157 .finish()
158 }
159}
160
161impl OlmMachine {
162 const CURRENT_GENERATION_STORE_KEY: &'static str = "generation-counter";
163 const HAS_MIGRATED_VERIFICATION_LATCH: &'static str = "HAS_MIGRATED_VERIFICATION_LATCH";
164
165 pub async fn new(user_id: &UserId, device_id: &DeviceId) -> Self {
176 OlmMachine::with_store(user_id, device_id, MemoryStore::new(), None)
177 .await
178 .expect("Reading and writing to the memory store always succeeds")
179 }
180
181 pub(crate) async fn rehydrate(
182 &self,
183 pickle_key: &[u8; 32],
184 device_id: &DeviceId,
185 device_data: Raw<DehydratedDeviceData>,
186 ) -> Result<OlmMachine, DehydrationError> {
187 let account = Account::rehydrate(pickle_key, self.user_id(), device_id, device_data)?;
188 let static_account = account.static_data().clone();
189
190 let store =
191 Arc::new(CryptoStoreWrapper::new(self.user_id(), device_id, MemoryStore::new()));
192 let device = DeviceData::from_account(&account);
193 store.save_pending_changes(PendingChanges { account: Some(account) }).await?;
194 store
195 .save_changes(Changes {
196 devices: DeviceChanges { new: vec![device], ..Default::default() },
197 ..Default::default()
198 })
199 .await?;
200
201 let (verification_machine, store, identity_manager) =
202 Self::new_helper_prelude(store, static_account, self.store().private_identity());
203
204 Ok(Self::new_helper(
205 device_id,
206 store,
207 verification_machine,
208 identity_manager,
209 self.store().private_identity(),
210 None,
211 ))
212 }
213
214 fn new_helper_prelude(
215 store_wrapper: Arc<CryptoStoreWrapper>,
216 account: StaticAccountData,
217 user_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
218 ) -> (VerificationMachine, Store, IdentityManager) {
219 let verification_machine =
220 VerificationMachine::new(account.clone(), user_identity.clone(), store_wrapper.clone());
221 let store = Store::new(account, user_identity, store_wrapper, verification_machine.clone());
222
223 let identity_manager = IdentityManager::new(store.clone());
224
225 (verification_machine, store, identity_manager)
226 }
227
228 fn new_helper(
229 device_id: &DeviceId,
230 store: Store,
231 verification_machine: VerificationMachine,
232 identity_manager: IdentityManager,
233 user_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
234 maybe_backup_key: Option<MegolmV1BackupKey>,
235 ) -> Self {
236 let group_session_manager = GroupSessionManager::new(store.clone());
237
238 let users_for_key_claim = Arc::new(StdRwLock::new(BTreeMap::new()));
239 let key_request_machine = GossipMachine::new(
240 store.clone(),
241 identity_manager.clone(),
242 group_session_manager.session_cache(),
243 users_for_key_claim.clone(),
244 );
245
246 let session_manager =
247 SessionManager::new(users_for_key_claim, key_request_machine.clone(), store.clone());
248
249 let backup_machine = BackupMachine::new(store.clone(), maybe_backup_key);
250
251 let inner = Arc::new(OlmMachineInner {
252 user_id: store.user_id().to_owned(),
253 device_id: device_id.to_owned(),
254 user_identity,
255 store,
256 session_manager,
257 group_session_manager,
258 verification_machine,
259 key_request_machine,
260 identity_manager,
261 backup_machine,
262 });
263
264 Self { inner }
265 }
266
267 #[instrument(skip(store, custom_account), fields(ed25519_key, curve25519_key))]
292 pub async fn with_store(
293 user_id: &UserId,
294 device_id: &DeviceId,
295 store: impl IntoCryptoStore,
296 custom_account: Option<vodozemac::olm::Account>,
297 ) -> StoreResult<Self> {
298 let store = store.into_crypto_store();
299
300 let static_account = match store.load_account().await? {
301 Some(account) => {
302 if user_id != account.user_id()
303 || device_id != account.device_id()
304 || custom_account.is_some()
305 {
306 return Err(CryptoStoreError::MismatchedAccount {
307 expected: (account.user_id().to_owned(), account.device_id().to_owned()),
308 got: (user_id.to_owned(), device_id.to_owned()),
309 });
310 }
311
312 Span::current()
313 .record("ed25519_key", display(account.identity_keys().ed25519))
314 .record("curve25519_key", display(account.identity_keys().curve25519));
315 debug!("Restored an Olm account");
316
317 account.static_data().clone()
318 }
319
320 None => {
321 let account = if let Some(account) = custom_account {
322 Account::new_helper(account, user_id, device_id)
323 } else {
324 Account::with_device_id(user_id, device_id)
325 };
326
327 let static_account = account.static_data().clone();
328
329 Span::current()
330 .record("ed25519_key", display(account.identity_keys().ed25519))
331 .record("curve25519_key", display(account.identity_keys().curve25519));
332
333 let device = DeviceData::from_account(&account);
334
335 device.set_trust_state(LocalTrust::Verified);
339
340 let changes = Changes {
341 devices: DeviceChanges { new: vec![device], ..Default::default() },
342 ..Default::default()
343 };
344 store.save_changes(changes).await?;
345 store.save_pending_changes(PendingChanges { account: Some(account) }).await?;
346
347 debug!("Created a new Olm account");
348
349 static_account
350 }
351 };
352
353 let identity = match store.load_identity().await? {
354 Some(i) => {
355 let master_key = i
356 .master_public_key()
357 .await
358 .and_then(|m| m.get_first_key().map(|m| m.to_owned()));
359 debug!(?master_key, "Restored the cross signing identity");
360 i
361 }
362 None => {
363 debug!("Creating an empty cross signing identity stub");
364 PrivateCrossSigningIdentity::empty(user_id)
365 }
366 };
367
368 let saved_keys = store.load_backup_keys().await?;
373 let maybe_backup_key = saved_keys.decryption_key.and_then(|k| {
374 if let Some(version) = saved_keys.backup_version {
375 let megolm_v1_backup_key = k.megolm_v1_public_key();
376 megolm_v1_backup_key.set_version(version);
377 Some(megolm_v1_backup_key)
378 } else {
379 None
380 }
381 });
382
383 let identity = Arc::new(Mutex::new(identity));
384 let store = Arc::new(CryptoStoreWrapper::new(user_id, device_id, store));
385
386 let (verification_machine, store, identity_manager) =
387 Self::new_helper_prelude(store, static_account, identity.clone());
388
389 Self::migration_post_verified_latch_support(&store, &identity_manager).await?;
392
393 Ok(Self::new_helper(
394 device_id,
395 store,
396 verification_machine,
397 identity_manager,
398 identity,
399 maybe_backup_key,
400 ))
401 }
402
403 pub(crate) async fn migration_post_verified_latch_support(
411 store: &Store,
412 identity_manager: &IdentityManager,
413 ) -> Result<(), CryptoStoreError> {
414 let maybe_migrate_for_identity_verified_latch =
415 store.get_custom_value(Self::HAS_MIGRATED_VERIFICATION_LATCH).await?.is_none();
416
417 if maybe_migrate_for_identity_verified_latch {
418 identity_manager.mark_all_tracked_users_as_dirty(store.cache().await?).await?;
419
420 store.set_custom_value(Self::HAS_MIGRATED_VERIFICATION_LATCH, vec![0]).await?
421 }
422 Ok(())
423 }
424
425 pub fn store(&self) -> &Store {
427 &self.inner.store
428 }
429
430 pub fn user_id(&self) -> &UserId {
432 &self.inner.user_id
433 }
434
435 pub fn device_id(&self) -> &DeviceId {
437 &self.inner.device_id
438 }
439
440 pub fn device_creation_time(&self) -> MilliSecondsSinceUnixEpoch {
447 self.inner.store.static_account().creation_local_time()
448 }
449
450 pub fn identity_keys(&self) -> IdentityKeys {
452 let account = self.inner.store.static_account();
453 account.identity_keys()
454 }
455
456 pub async fn display_name(&self) -> StoreResult<Option<String>> {
458 self.store().device_display_name().await
459 }
460
461 pub async fn tracked_users(&self) -> StoreResult<HashSet<OwnedUserId>> {
466 let cache = self.store().cache().await?;
467 Ok(self.inner.identity_manager.key_query_manager.synced(&cache).await?.tracked_users())
468 }
469
470 #[cfg(feature = "automatic-room-key-forwarding")]
479 pub fn set_room_key_requests_enabled(&self, enable: bool) {
480 self.inner.key_request_machine.set_room_key_requests_enabled(enable)
481 }
482
483 pub fn are_room_key_requests_enabled(&self) -> bool {
488 self.inner.key_request_machine.are_room_key_requests_enabled()
489 }
490
491 #[cfg(feature = "automatic-room-key-forwarding")]
500 pub fn set_room_key_forwarding_enabled(&self, enable: bool) {
501 self.inner.key_request_machine.set_room_key_forwarding_enabled(enable)
502 }
503
504 pub fn is_room_key_forwarding_enabled(&self) -> bool {
508 self.inner.key_request_machine.is_room_key_forwarding_enabled()
509 }
510
511 pub async fn outgoing_requests(&self) -> StoreResult<Vec<OutgoingRequest>> {
519 let mut requests = Vec::new();
520
521 {
522 let store_cache = self.inner.store.cache().await?;
523 let account = store_cache.account().await?;
524 if let Some(r) = self.keys_for_upload(&account).await.map(|r| OutgoingRequest {
525 request_id: TransactionId::new(),
526 request: Arc::new(r.into()),
527 }) {
528 requests.push(r);
529 }
530 }
531
532 for request in self
533 .inner
534 .identity_manager
535 .users_for_key_query()
536 .await?
537 .into_iter()
538 .map(|(request_id, r)| OutgoingRequest { request_id, request: Arc::new(r.into()) })
539 {
540 requests.push(request);
541 }
542
543 requests.append(&mut self.inner.verification_machine.outgoing_messages());
544 requests.append(&mut self.inner.key_request_machine.outgoing_to_device_requests().await?);
545
546 Ok(requests)
547 }
548
549 pub fn query_keys_for_users<'a>(
570 &self,
571 users: impl IntoIterator<Item = &'a UserId>,
572 ) -> (OwnedTransactionId, KeysQueryRequest) {
573 self.inner.identity_manager.build_key_query_for_users(users)
574 }
575
576 pub async fn mark_request_as_sent<'a>(
586 &self,
587 request_id: &TransactionId,
588 response: impl Into<AnyIncomingResponse<'a>>,
589 ) -> OlmResult<()> {
590 match response.into() {
591 AnyIncomingResponse::KeysUpload(response) => {
592 Box::pin(self.receive_keys_upload_response(response)).await?;
593 }
594 AnyIncomingResponse::KeysQuery(response) => {
595 Box::pin(self.receive_keys_query_response(request_id, response)).await?;
596 }
597 AnyIncomingResponse::KeysClaim(response) => {
598 Box::pin(
599 self.inner.session_manager.receive_keys_claim_response(request_id, response),
600 )
601 .await?;
602 }
603 AnyIncomingResponse::ToDevice(_) => {
604 Box::pin(self.mark_to_device_request_as_sent(request_id)).await?;
605 }
606 AnyIncomingResponse::SigningKeysUpload(_) => {
607 Box::pin(self.receive_cross_signing_upload_response()).await?;
608 }
609 AnyIncomingResponse::SignatureUpload(_) => {
610 self.inner.verification_machine.mark_request_as_sent(request_id);
611 }
612 AnyIncomingResponse::RoomMessage(_) => {
613 self.inner.verification_machine.mark_request_as_sent(request_id);
614 }
615 AnyIncomingResponse::KeysBackup(_) => {
616 Box::pin(self.inner.backup_machine.mark_request_as_sent(request_id)).await?;
617 }
618 }
619
620 Ok(())
621 }
622
623 async fn receive_cross_signing_upload_response(&self) -> StoreResult<()> {
625 let identity = self.inner.user_identity.lock().await;
626 identity.mark_as_shared();
627
628 let changes = Changes { private_identity: Some(identity.clone()), ..Default::default() };
629
630 self.store().save_changes(changes).await
631 }
632
633 pub async fn bootstrap_cross_signing(
652 &self,
653 reset: bool,
654 ) -> StoreResult<CrossSigningBootstrapRequests> {
655 let identity = self.inner.user_identity.lock().await.clone();
660
661 let (upload_signing_keys_req, upload_signatures_req) = if reset || identity.is_empty().await
662 {
663 info!("Creating new cross signing identity");
664
665 let (identity, upload_signing_keys_req, upload_signatures_req) = {
666 let cache = self.inner.store.cache().await?;
667 let account = cache.account().await?;
668 account.bootstrap_cross_signing().await
669 };
670
671 let public = identity.to_public_identity().await.expect(
672 "Couldn't create a public version of the identity from a new private identity",
673 );
674
675 *self.inner.user_identity.lock().await = identity.clone();
676
677 self.store()
678 .save_changes(Changes {
679 identities: IdentityChanges { new: vec![public.into()], ..Default::default() },
680 private_identity: Some(identity),
681 ..Default::default()
682 })
683 .await?;
684
685 (upload_signing_keys_req, upload_signatures_req)
686 } else {
687 info!("Trying to upload the existing cross signing identity");
688 let upload_signing_keys_req = identity.as_upload_request().await;
689
690 let upload_signatures_req = identity
692 .sign_account(self.inner.store.static_account())
693 .await
694 .expect("Can't sign device keys");
695
696 (upload_signing_keys_req, upload_signatures_req)
697 };
698
699 let upload_keys_req =
703 self.upload_device_keys().await?.map(|(_, request)| OutgoingRequest::from(request));
704
705 Ok(CrossSigningBootstrapRequests {
706 upload_signing_keys_req,
707 upload_keys_req,
708 upload_signatures_req,
709 })
710 }
711
712 pub async fn upload_device_keys(
724 &self,
725 ) -> StoreResult<Option<(OwnedTransactionId, UploadKeysRequest)>> {
726 let cache = self.store().cache().await?;
727 let account = cache.account().await?;
728
729 Ok(self.keys_for_upload(&account).await.map(|request| (TransactionId::new(), request)))
730 }
731
732 async fn receive_keys_upload_response(&self, response: &UploadKeysResponse) -> OlmResult<()> {
739 self.inner
740 .store
741 .with_transaction(|mut tr| async {
742 let account = tr.account().await?;
743 account.receive_keys_upload_response(response)?;
744 Ok((tr, ()))
745 })
746 .await
747 }
748
749 #[instrument(skip_all)]
777 pub async fn get_missing_sessions(
778 &self,
779 users: impl Iterator<Item = &UserId>,
780 ) -> StoreResult<Option<(OwnedTransactionId, KeysClaimRequest)>> {
781 self.inner.session_manager.get_missing_sessions(users).await
782 }
783
784 async fn receive_keys_query_response(
793 &self,
794 request_id: &TransactionId,
795 response: &KeysQueryResponse,
796 ) -> OlmResult<(DeviceChanges, IdentityChanges)> {
797 self.inner.identity_manager.receive_keys_query_response(request_id, response).await
798 }
799
800 async fn keys_for_upload(&self, account: &Account) -> Option<UploadKeysRequest> {
809 let (mut device_keys, one_time_keys, fallback_keys) = account.keys_for_upload();
810
811 if let Some(device_keys) = &mut device_keys {
821 let private_identity = self.store().private_identity();
822 let guard = private_identity.lock().await;
823
824 if guard.status().await.is_complete() {
825 guard.sign_device_keys(device_keys).await.expect(
826 "We should be able to sign our device keys since we confirmed that we \
827 have a complete set of private cross-signing keys",
828 );
829 }
830 }
831
832 if device_keys.is_none() && one_time_keys.is_empty() && fallback_keys.is_empty() {
833 None
834 } else {
835 let device_keys = device_keys.map(|d| d.to_raw());
836
837 Some(assign!(UploadKeysRequest::new(), {
838 device_keys, one_time_keys, fallback_keys
839 }))
840 }
841 }
842
843 async fn decrypt_to_device_event(
858 &self,
859 transaction: &mut StoreTransaction,
860 event: &EncryptedToDeviceEvent,
861 changes: &mut Changes,
862 ) -> Result<OlmDecryptionInfo, DecryptToDeviceError> {
863 let mut decrypted =
865 transaction.account().await?.decrypt_to_device_event(&self.inner.store, event).await?;
866
867 let from_dehydrated_device =
868 self.to_device_event_is_from_dehydrated_device(&decrypted, &event.sender).await?;
869
870 if from_dehydrated_device {
874 warn!(
876 sender = ?event.sender,
877 session = ?decrypted.session,
878 "Received a to-device event from a dehydrated device. This is unexpected: ignoring event"
879 );
880 Err(DecryptToDeviceError::FromDehydratedDevice)
881 } else {
882 self.handle_decrypted_to_device_event(transaction.cache(), &mut decrypted, changes)
884 .await?;
885
886 Ok(decrypted)
887 }
888 }
889
890 #[instrument(
891 skip_all,
892 fields(room_id = ? content.room_id, session_id)
896 )]
897 async fn handle_key(
898 &self,
899 sender_key: Curve25519PublicKey,
900 event: &DecryptedRoomKeyEvent,
901 content: &MegolmV1AesSha2Content,
902 ) -> OlmResult<Option<InboundGroupSession>> {
903 let session =
904 InboundGroupSession::from_room_key_content(sender_key, event.keys.ed25519, content);
905
906 match session {
907 Ok(mut session) => {
908 Span::current().record("session_id", session.session_id());
909
910 let sender_data =
911 SenderDataFinder::find_using_event(self.store(), sender_key, event, &session)
912 .await?;
913
914 session.sender_data = sender_data;
915
916 match self.store().compare_group_session(&session).await? {
917 SessionOrdering::Better => {
918 info!("Received a new megolm room key");
919
920 Ok(Some(session))
921 }
922 comparison_result => {
923 warn!(
924 ?comparison_result,
925 "Received a megolm room key that we already have a better version \
926 of, discarding"
927 );
928
929 Ok(None)
930 }
931 }
932 }
933 Err(e) => {
934 Span::current().record("session_id", &content.session_id);
935 warn!("Received a room key event which contained an invalid session key: {e}");
936
937 Ok(None)
938 }
939 }
940 }
941
942 #[instrument(skip_all, fields(algorithm = ?event.content.algorithm()))]
944 async fn add_room_key(
945 &self,
946 sender_key: Curve25519PublicKey,
947 event: &DecryptedRoomKeyEvent,
948 ) -> OlmResult<Option<InboundGroupSession>> {
949 match &event.content {
950 RoomKeyContent::MegolmV1AesSha2(content) => {
951 self.handle_key(sender_key, event, content).await
952 }
953 #[cfg(feature = "experimental-algorithms")]
954 RoomKeyContent::MegolmV2AesSha2(content) => {
955 self.handle_key(sender_key, event, content).await
956 }
957 RoomKeyContent::Unknown(_) => {
958 warn!("Received a room key with an unsupported algorithm");
959 Ok(None)
960 }
961 }
962 }
963
964 #[instrument()]
967 async fn receive_room_key_bundle_data(
968 &self,
969 event: &DecryptedRoomKeyBundleEvent,
970 changes: &mut Changes,
971 ) -> OlmResult<()> {
972 let Some(sender_device_keys) = &event.sender_device_keys else {
973 warn!("Received a room key bundle with no sender device keys: ignoring");
974 return Ok(());
975 };
976
977 let sender_device_data =
982 DeviceData::try_from(sender_device_keys).expect("failed to verify sender device keys");
983 let sender_device = self.store().wrap_device_data(sender_device_data).await?;
984
985 changes.received_room_key_bundles.push(StoredRoomKeyBundleData {
986 sender_user: event.sender.clone(),
987 sender_data: SenderData::from_device(&sender_device),
988 bundle_data: event.content.clone(),
989 });
990 Ok(())
991 }
992
993 fn add_withheld_info(&self, changes: &mut Changes, event: &RoomKeyWithheldEvent) {
994 debug!(?event.content, "Processing `m.room_key.withheld` event");
995
996 if let RoomKeyWithheldContent::MegolmV1AesSha2(
997 MegolmV1AesSha2WithheldContent::BlackListed(c)
998 | MegolmV1AesSha2WithheldContent::Unverified(c),
999 ) = &event.content
1000 {
1001 changes
1002 .withheld_session_info
1003 .entry(c.room_id.to_owned())
1004 .or_default()
1005 .insert(c.session_id.to_owned(), event.to_owned());
1006 }
1007 }
1008
1009 #[cfg(test)]
1010 pub(crate) async fn create_outbound_group_session_with_defaults_test_helper(
1011 &self,
1012 room_id: &RoomId,
1013 ) -> OlmResult<()> {
1014 let (_, session) = self
1015 .inner
1016 .group_session_manager
1017 .create_outbound_group_session(
1018 room_id,
1019 EncryptionSettings::default(),
1020 SenderData::unknown(),
1021 )
1022 .await?;
1023
1024 self.store().save_inbound_group_sessions(&[session]).await?;
1025
1026 Ok(())
1027 }
1028
1029 #[cfg(test)]
1030 #[allow(dead_code)]
1031 pub(crate) async fn create_inbound_session_test_helper(
1032 &self,
1033 room_id: &RoomId,
1034 ) -> OlmResult<InboundGroupSession> {
1035 let (_, session) = self
1036 .inner
1037 .group_session_manager
1038 .create_outbound_group_session(
1039 room_id,
1040 EncryptionSettings::default(),
1041 SenderData::unknown(),
1042 )
1043 .await?;
1044
1045 Ok(session)
1046 }
1047
1048 pub async fn encrypt_room_event(
1065 &self,
1066 room_id: &RoomId,
1067 content: impl MessageLikeEventContent,
1068 ) -> MegolmResult<Raw<RoomEncryptedEventContent>> {
1069 let event_type = content.event_type().to_string();
1070 let content = Raw::new(&content)?.cast();
1071 self.encrypt_room_event_raw(room_id, &event_type, &content).await
1072 }
1073
1074 pub async fn encrypt_room_event_raw(
1094 &self,
1095 room_id: &RoomId,
1096 event_type: &str,
1097 content: &Raw<AnyMessageLikeEventContent>,
1098 ) -> MegolmResult<Raw<RoomEncryptedEventContent>> {
1099 self.inner.group_session_manager.encrypt(room_id, event_type, content).await
1100 }
1101
1102 pub async fn discard_room_key(&self, room_id: &RoomId) -> StoreResult<bool> {
1113 self.inner.group_session_manager.invalidate_group_session(room_id).await
1114 }
1115
1116 pub async fn share_room_key(
1136 &self,
1137 room_id: &RoomId,
1138 users: impl Iterator<Item = &UserId>,
1139 encryption_settings: impl Into<EncryptionSettings>,
1140 ) -> OlmResult<Vec<Arc<ToDeviceRequest>>> {
1141 self.inner.group_session_manager.share_room_key(room_id, users, encryption_settings).await
1142 }
1143
1144 #[cfg(feature = "experimental-send-custom-to-device")]
1158 pub async fn encrypt_content_for_devices(
1159 &self,
1160 devices: Vec<DeviceData>,
1161 event_type: &str,
1162 content: &Value,
1163 ) -> OlmResult<(Vec<ToDeviceRequest>, Vec<(DeviceData, WithheldCode)>)> {
1164 let mut changes = Changes::default();
1167
1168 let result = self
1169 .inner
1170 .group_session_manager
1171 .encrypt_content_for_devices(devices, event_type, content.clone(), &mut changes)
1172 .await;
1173
1174 if !changes.is_empty() {
1176 let session_count = changes.sessions.len();
1177
1178 self.inner.store.save_changes(changes).await?;
1179
1180 trace!(
1181 session_count = session_count,
1182 "Stored the changed sessions after encrypting a custom to-device event"
1183 );
1184 }
1185
1186 result
1187 }
1188 pub async fn share_room_key_bundle_data(
1193 &self,
1194 user_id: &UserId,
1195 collect_strategy: &CollectStrategy,
1196 bundle_data: RoomKeyBundleContent,
1197 ) -> OlmResult<Vec<ToDeviceRequest>> {
1198 self.inner
1199 .group_session_manager
1200 .share_room_key_bundle_data(user_id, collect_strategy, bundle_data)
1201 .await
1202 }
1203
1204 #[deprecated(note = "Use OlmMachine::receive_verification_event instead", since = "0.7.0")]
1212 pub async fn receive_unencrypted_verification_event(
1213 &self,
1214 event: &AnyMessageLikeEvent,
1215 ) -> StoreResult<()> {
1216 self.inner.verification_machine.receive_any_event(event).await
1217 }
1218
1219 pub async fn receive_verification_event(&self, event: &AnyMessageLikeEvent) -> StoreResult<()> {
1223 self.inner.verification_machine.receive_any_event(event).await
1224 }
1225
1226 #[instrument(
1232 skip_all,
1233 fields(
1234 sender_key = ?decrypted.result.sender_key,
1235 event_type = decrypted.result.event.event_type(),
1236 ),
1237 )]
1238 async fn handle_decrypted_to_device_event(
1239 &self,
1240 cache: &StoreCache,
1241 decrypted: &mut OlmDecryptionInfo,
1242 changes: &mut Changes,
1243 ) -> OlmResult<()> {
1244 debug!(
1245 sender_device_keys =
1246 ?decrypted.result.event.sender_device_keys().map(|k| (k.curve25519_key(), k.ed25519_key())).unwrap_or((None, None)),
1247 "Received a decrypted to-device event",
1248 );
1249
1250 match &*decrypted.result.event {
1251 AnyDecryptedOlmEvent::RoomKey(e) => {
1252 let session = self.add_room_key(decrypted.result.sender_key, e).await?;
1253 decrypted.inbound_group_session = session;
1254 }
1255 AnyDecryptedOlmEvent::ForwardedRoomKey(e) => {
1256 let session = self
1257 .inner
1258 .key_request_machine
1259 .receive_forwarded_room_key(decrypted.result.sender_key, e)
1260 .await?;
1261 decrypted.inbound_group_session = session;
1262 }
1263 AnyDecryptedOlmEvent::SecretSend(e) => {
1264 let name = self
1265 .inner
1266 .key_request_machine
1267 .receive_secret_event(cache, decrypted.result.sender_key, e, changes)
1268 .await?;
1269
1270 if let Ok(ToDeviceEvents::SecretSend(mut e)) =
1273 decrypted.result.raw_event.deserialize_as()
1274 {
1275 e.content.secret_name = name;
1276 decrypted.result.raw_event = Raw::from_json(to_raw_value(&e)?);
1277 }
1278 }
1279 AnyDecryptedOlmEvent::Dummy(_) => {
1280 debug!("Received an `m.dummy` event");
1281 }
1282 AnyDecryptedOlmEvent::RoomKeyBundle(e) => {
1283 debug!("Received a room key bundle event {:?}", e);
1284 self.receive_room_key_bundle_data(e, changes).await?;
1285 }
1286 AnyDecryptedOlmEvent::Custom(_) => {
1287 warn!("Received an unexpected encrypted to-device event");
1288 }
1289 }
1290
1291 Ok(())
1292 }
1293
1294 async fn handle_verification_event(&self, event: &ToDeviceEvents) {
1295 if let Err(e) = self.inner.verification_machine.receive_any_event(event).await {
1296 error!("Error handling a verification event: {e:?}");
1297 }
1298 }
1299
1300 async fn mark_to_device_request_as_sent(&self, request_id: &TransactionId) -> StoreResult<()> {
1302 self.inner.verification_machine.mark_request_as_sent(request_id);
1303 self.inner.key_request_machine.mark_outgoing_request_as_sent(request_id).await?;
1304 self.inner.group_session_manager.mark_request_as_sent(request_id).await?;
1305 self.inner.session_manager.mark_outgoing_request_as_sent(request_id);
1306 Ok(())
1307 }
1308
1309 pub fn get_verification(&self, user_id: &UserId, flow_id: &str) -> Option<Verification> {
1311 self.inner.verification_machine.get_verification(user_id, flow_id)
1312 }
1313
1314 pub fn get_verification_request(
1316 &self,
1317 user_id: &UserId,
1318 flow_id: impl AsRef<str>,
1319 ) -> Option<VerificationRequest> {
1320 self.inner.verification_machine.get_request(user_id, flow_id)
1321 }
1322
1323 pub fn get_verification_requests(&self, user_id: &UserId) -> Vec<VerificationRequest> {
1325 self.inner.verification_machine.get_requests(user_id)
1326 }
1327
1328 async fn handle_to_device_event(&self, changes: &mut Changes, event: &ToDeviceEvents) {
1333 use crate::types::events::ToDeviceEvents::*;
1334
1335 match event {
1336 RoomKeyRequest(e) => self.inner.key_request_machine.receive_incoming_key_request(e),
1339 SecretRequest(e) => self.inner.key_request_machine.receive_incoming_secret_request(e),
1340 RoomKeyWithheld(e) => self.add_withheld_info(changes, e),
1341 KeyVerificationAccept(..)
1342 | KeyVerificationCancel(..)
1343 | KeyVerificationKey(..)
1344 | KeyVerificationMac(..)
1345 | KeyVerificationRequest(..)
1346 | KeyVerificationReady(..)
1347 | KeyVerificationDone(..)
1348 | KeyVerificationStart(..) => {
1349 self.handle_verification_event(event).await;
1350 }
1351
1352 Custom(_) | Dummy(_) => {}
1354
1355 RoomEncrypted(_) => {}
1357
1358 SecretSend(_) | RoomKey(_) | ForwardedRoomKey(_) => {}
1361 }
1362 }
1363
1364 fn record_message_id(event: &Raw<AnyToDeviceEvent>) {
1365 use serde::Deserialize;
1366
1367 #[derive(Deserialize)]
1368 struct ContentStub<'a> {
1369 #[serde(borrow, rename = "org.matrix.msgid")]
1370 message_id: Option<&'a str>,
1371 }
1372 #[derive(Deserialize)]
1373 struct ToDeviceStub<'a> {
1374 sender: &'a str,
1375 #[serde(rename = "type")]
1376 event_type: &'a str,
1377 #[serde(borrow)]
1378 content: ContentStub<'a>,
1379 }
1380
1381 if let Ok(event) = event.deserialize_as::<ToDeviceStub<'_>>() {
1382 Span::current().record("sender", event.sender);
1383 Span::current().record("event_type", event.event_type);
1384 Span::current().record("message_id", event.content.message_id);
1385 }
1386 }
1387
1388 #[instrument(skip_all, fields(sender, event_type, message_id))]
1396 async fn receive_to_device_event(
1397 &self,
1398 transaction: &mut StoreTransaction,
1399 changes: &mut Changes,
1400 raw_event: Raw<AnyToDeviceEvent>,
1401 ) -> Option<ProcessedToDeviceEvent> {
1402 Self::record_message_id(&raw_event);
1403
1404 let event: ToDeviceEvents = match raw_event.deserialize_as() {
1405 Ok(e) => e,
1406 Err(e) => {
1407 warn!("Received an invalid to-device event: {e}");
1409 return Some(ProcessedToDeviceEvent::Invalid(raw_event));
1410 }
1411 };
1412
1413 debug!("Received a to-device event");
1414
1415 match event {
1416 ToDeviceEvents::RoomEncrypted(e) => {
1417 self.receive_encrypted_to_device_event(transaction, changes, raw_event, e).await
1418 }
1419 e => {
1420 self.handle_to_device_event(changes, &e).await;
1421 Some(ProcessedToDeviceEvent::PlainText(raw_event))
1422 }
1423 }
1424 }
1425
1426 async fn receive_encrypted_to_device_event(
1434 &self,
1435 transaction: &mut StoreTransaction,
1436 changes: &mut Changes,
1437 mut raw_event: Raw<AnyToDeviceEvent>,
1438 e: ToDeviceEvent<ToDeviceEncryptedEventContent>,
1439 ) -> Option<ProcessedToDeviceEvent> {
1440 let decrypted = match self.decrypt_to_device_event(transaction, &e, changes).await {
1441 Ok(decrypted) => decrypted,
1442 Err(DecryptToDeviceError::OlmError(err)) => {
1443 if let OlmError::SessionWedged(sender, curve_key) = err {
1444 if let Err(e) =
1445 self.inner.session_manager.mark_device_as_wedged(&sender, curve_key).await
1446 {
1447 error!(
1448 error = ?e,
1449 "Couldn't mark device to be unwedged",
1450 );
1451 }
1452 }
1453
1454 return Some(ProcessedToDeviceEvent::UnableToDecrypt(raw_event));
1455 }
1456 Err(DecryptToDeviceError::FromDehydratedDevice) => return None,
1457 };
1458
1459 match decrypted.session {
1462 SessionType::New(s) | SessionType::Existing(s) => {
1463 changes.sessions.push(s);
1464 }
1465 }
1466
1467 changes.message_hashes.push(decrypted.message_hash);
1468
1469 if let Some(group_session) = decrypted.inbound_group_session {
1470 changes.inbound_group_sessions.push(group_session);
1471 }
1472
1473 match decrypted.result.raw_event.deserialize_as() {
1474 Ok(event) => {
1475 self.handle_to_device_event(changes, &event).await;
1476
1477 raw_event = event
1478 .serialize_zeroized()
1479 .expect("Zeroizing and reserializing our events should always work")
1480 .cast();
1481 }
1482 Err(e) => {
1483 warn!("Received an invalid encrypted to-device event: {e}");
1484 raw_event = decrypted.result.raw_event;
1485 }
1486 }
1487
1488 Some(ProcessedToDeviceEvent::Decrypted {
1489 raw: raw_event,
1490 encryption_info: decrypted.result.encryption_info,
1491 })
1492 }
1493
1494 async fn to_device_event_is_from_dehydrated_device(
1500 &self,
1501 decrypted: &OlmDecryptionInfo,
1502 sender_user_id: &UserId,
1503 ) -> OlmResult<bool> {
1504 if let Some(device_keys) = decrypted.result.event.sender_device_keys() {
1506 if device_keys.dehydrated.unwrap_or(false) {
1512 return Ok(true);
1513 }
1514 }
1519
1520 Ok(self
1522 .store()
1523 .get_device_from_curve_key(sender_user_id, decrypted.result.sender_key)
1524 .await?
1525 .is_some_and(|d| d.is_dehydrated()))
1526 }
1527
1528 #[instrument(skip_all)]
1546 pub async fn receive_sync_changes(
1547 &self,
1548 sync_changes: EncryptionSyncChanges<'_>,
1549 ) -> OlmResult<(Vec<ProcessedToDeviceEvent>, Vec<RoomKeyInfo>)> {
1550 let mut store_transaction = self.inner.store.transaction().await;
1551
1552 let (events, changes) =
1553 self.preprocess_sync_changes(&mut store_transaction, sync_changes).await?;
1554
1555 let room_key_updates: Vec<_> =
1558 changes.inbound_group_sessions.iter().map(RoomKeyInfo::from).collect();
1559
1560 self.store().save_changes(changes).await?;
1561 store_transaction.commit().await?;
1562
1563 Ok((events, room_key_updates))
1564 }
1565
1566 pub(crate) async fn preprocess_sync_changes(
1575 &self,
1576 transaction: &mut StoreTransaction,
1577 sync_changes: EncryptionSyncChanges<'_>,
1578 ) -> OlmResult<(Vec<ProcessedToDeviceEvent>, Changes)> {
1579 let mut events: Vec<ProcessedToDeviceEvent> = self
1581 .inner
1582 .verification_machine
1583 .garbage_collect()
1584 .iter()
1585 .map(|e| ProcessedToDeviceEvent::PlainText(e.clone()))
1589 .collect();
1590 let mut changes = Default::default();
1593
1594 {
1595 let account = transaction.account().await?;
1596 account.update_key_counts(
1597 sync_changes.one_time_keys_counts,
1598 sync_changes.unused_fallback_keys,
1599 )
1600 }
1601
1602 if let Err(e) = self
1603 .inner
1604 .identity_manager
1605 .receive_device_changes(
1606 transaction.cache(),
1607 sync_changes.changed_devices.changed.iter().map(|u| u.as_ref()),
1608 )
1609 .await
1610 {
1611 error!(error = ?e, "Error marking a tracked user as changed");
1612 }
1613
1614 for raw_event in sync_changes.to_device_events {
1615 let processed_event =
1616 Box::pin(self.receive_to_device_event(transaction, &mut changes, raw_event)).await;
1617
1618 if let Some(processed_event) = processed_event {
1619 events.push(processed_event);
1620 }
1621 }
1622
1623 let changed_sessions = self
1624 .inner
1625 .key_request_machine
1626 .collect_incoming_key_requests(transaction.cache())
1627 .await?;
1628
1629 changes.sessions.extend(changed_sessions);
1630 changes.next_batch_token = sync_changes.next_batch_token;
1631
1632 Ok((events, changes))
1633 }
1634
1635 pub async fn request_room_key(
1652 &self,
1653 event: &Raw<EncryptedEvent>,
1654 room_id: &RoomId,
1655 ) -> MegolmResult<(Option<OutgoingRequest>, OutgoingRequest)> {
1656 let event = event.deserialize()?;
1657 self.inner.key_request_machine.request_key(room_id, &event).await
1658 }
1659
1660 async fn get_room_event_verification_state(
1673 &self,
1674 session: &InboundGroupSession,
1675 sender: &UserId,
1676 ) -> MegolmResult<(VerificationState, Option<OwnedDeviceId>)> {
1677 let sender_data = self.get_or_update_sender_data(session, sender).await?;
1678
1679 let (verification_state, device_id) = match sender_data.user_id() {
1688 Some(i) if i != sender => {
1689 (VerificationState::Unverified(VerificationLevel::MismatchedSender), None)
1690 }
1691
1692 Some(_) | None => {
1693 sender_data_to_verification_state(sender_data, session.has_been_imported())
1694 }
1695 };
1696
1697 Ok((verification_state, device_id))
1698 }
1699
1700 async fn get_or_update_sender_data(
1715 &self,
1716 session: &InboundGroupSession,
1717 sender: &UserId,
1718 ) -> MegolmResult<SenderData> {
1719 fn should_recalculate_sender_data(sender_data: &SenderData) -> bool {
1730 matches!(
1731 sender_data,
1732 SenderData::UnknownDevice { .. }
1733 | SenderData::DeviceInfo { .. }
1734 | SenderData::VerificationViolation { .. }
1735 )
1736 }
1737
1738 let sender_data = if should_recalculate_sender_data(&session.sender_data) {
1739 let calculated_sender_data = SenderDataFinder::find_using_curve_key(
1758 self.store(),
1759 session.sender_key(),
1760 sender,
1761 session,
1762 )
1763 .await?;
1764
1765 if calculated_sender_data.compare_trust_level(&session.sender_data).is_gt() {
1767 let mut new_session = session.clone();
1769 new_session.sender_data = calculated_sender_data.clone();
1770 self.store().save_inbound_group_sessions(&[new_session]).await?;
1771
1772 calculated_sender_data
1774 } else {
1775 session.sender_data.clone()
1777 }
1778 } else {
1779 session.sender_data.clone()
1780 };
1781
1782 Ok(sender_data)
1783 }
1784
1785 pub async fn query_missing_secrets_from_other_sessions(&self) -> StoreResult<bool> {
1810 let identity = self.inner.user_identity.lock().await;
1811 let mut secrets = identity.get_missing_secrets().await;
1812
1813 if self.store().load_backup_keys().await?.decryption_key.is_none() {
1814 secrets.push(SecretName::RecoveryKey);
1815 }
1816
1817 if secrets.is_empty() {
1818 debug!("No missing requests to query");
1819 return Ok(false);
1820 }
1821
1822 let secret_requests = GossipMachine::request_missing_secrets(self.user_id(), secrets);
1823
1824 let unsent_request = self.store().get_unsent_secret_requests().await?;
1826 let not_yet_requested = secret_requests
1827 .into_iter()
1828 .filter(|request| !unsent_request.iter().any(|unsent| unsent.info == request.info))
1829 .collect_vec();
1830
1831 if not_yet_requested.is_empty() {
1832 debug!("The missing secrets have already been requested");
1833 Ok(false)
1834 } else {
1835 debug!("Requesting missing secrets");
1836
1837 let changes = Changes { key_requests: not_yet_requested, ..Default::default() };
1838
1839 self.store().save_changes(changes).await?;
1840 Ok(true)
1841 }
1842 }
1843
1844 async fn get_encryption_info(
1850 &self,
1851 session: &InboundGroupSession,
1852 sender: &UserId,
1853 ) -> MegolmResult<Arc<EncryptionInfo>> {
1854 let (verification_state, device_id) =
1855 self.get_room_event_verification_state(session, sender).await?;
1856
1857 let sender = sender.to_owned();
1858
1859 Ok(Arc::new(EncryptionInfo {
1860 sender,
1861 sender_device: device_id,
1862 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
1863 curve25519_key: session.sender_key().to_base64(),
1864 sender_claimed_keys: session
1865 .signing_keys()
1866 .iter()
1867 .map(|(k, v)| (k.to_owned(), v.to_base64()))
1868 .collect(),
1869 session_id: Some(session.session_id().to_owned()),
1870 },
1871 verification_state,
1872 }))
1873 }
1874
1875 async fn decrypt_megolm_events(
1876 &self,
1877 room_id: &RoomId,
1878 event: &EncryptedEvent,
1879 content: &SupportedEventEncryptionSchemes<'_>,
1880 decryption_settings: &DecryptionSettings,
1881 ) -> MegolmResult<(JsonObject, Arc<EncryptionInfo>)> {
1882 let session =
1883 self.get_inbound_group_session_or_error(room_id, content.session_id()).await?;
1884
1885 Span::current().record("sender_key", debug(session.sender_key()));
1891
1892 let result = session.decrypt(event).await;
1893 match result {
1894 Ok((decrypted_event, _)) => {
1895 let encryption_info = self.get_encryption_info(&session, &event.sender).await?;
1896
1897 self.check_sender_trust_requirement(
1898 &session,
1899 &encryption_info,
1900 &decryption_settings.sender_device_trust_requirement,
1901 )?;
1902
1903 Ok((decrypted_event, encryption_info))
1904 }
1905 Err(error) => Err(
1906 if let MegolmError::Decryption(DecryptionError::UnknownMessageIndex(_, _)) = error {
1907 let withheld_code = self
1908 .inner
1909 .store
1910 .get_withheld_info(room_id, content.session_id())
1911 .await?
1912 .map(|e| e.content.withheld_code());
1913
1914 if withheld_code.is_some() {
1915 MegolmError::MissingRoomKey(withheld_code)
1917 } else {
1918 error
1919 }
1920 } else {
1921 error
1922 },
1923 ),
1924 }
1925 }
1926
1927 fn check_sender_trust_requirement(
1933 &self,
1934 session: &InboundGroupSession,
1935 encryption_info: &EncryptionInfo,
1936 trust_requirement: &TrustRequirement,
1937 ) -> MegolmResult<()> {
1938 trace!(
1939 verification_state = ?encryption_info.verification_state,
1940 ?trust_requirement, "check_sender_trust_requirement",
1941 );
1942
1943 let verification_level = match &encryption_info.verification_state {
1946 VerificationState::Verified => return Ok(()),
1947 VerificationState::Unverified(verification_level) => verification_level,
1948 };
1949
1950 let ok = match trust_requirement {
1951 TrustRequirement::Untrusted => true,
1952
1953 TrustRequirement::CrossSignedOrLegacy => {
1954 let legacy_session = match session.sender_data {
1960 SenderData::DeviceInfo { legacy_session, .. } => legacy_session,
1961 SenderData::UnknownDevice { legacy_session, .. } => legacy_session,
1962 _ => false,
1963 };
1964
1965 match (verification_level, legacy_session) {
1975 (VerificationLevel::UnverifiedIdentity, _) => true,
1977
1978 (VerificationLevel::UnsignedDevice, true) => true,
1980
1981 (VerificationLevel::None(_), true) => true,
1983
1984 (VerificationLevel::VerificationViolation, _)
1986 | (VerificationLevel::MismatchedSender, _)
1987 | (VerificationLevel::UnsignedDevice, false)
1988 | (VerificationLevel::None(_), false) => false,
1989 }
1990 }
1991
1992 TrustRequirement::CrossSigned => match verification_level {
1995 VerificationLevel::UnverifiedIdentity => true,
1996
1997 VerificationLevel::VerificationViolation
1998 | VerificationLevel::MismatchedSender
1999 | VerificationLevel::UnsignedDevice
2000 | VerificationLevel::None(_) => false,
2001 },
2002 };
2003
2004 if ok {
2005 Ok(())
2006 } else {
2007 Err(MegolmError::SenderIdentityNotTrusted(verification_level.clone()))
2008 }
2009 }
2010
2011 async fn get_inbound_group_session_or_error(
2016 &self,
2017 room_id: &RoomId,
2018 session_id: &str,
2019 ) -> MegolmResult<InboundGroupSession> {
2020 match self.store().get_inbound_group_session(room_id, session_id).await? {
2021 Some(session) => Ok(session),
2022 None => {
2023 let withheld_code = self
2024 .inner
2025 .store
2026 .get_withheld_info(room_id, session_id)
2027 .await?
2028 .map(|e| e.content.withheld_code());
2029 Err(MegolmError::MissingRoomKey(withheld_code))
2030 }
2031 }
2032 }
2033
2034 pub async fn try_decrypt_room_event(
2049 &self,
2050 raw_event: &Raw<EncryptedEvent>,
2051 room_id: &RoomId,
2052 decryption_settings: &DecryptionSettings,
2053 ) -> Result<RoomEventDecryptionResult, CryptoStoreError> {
2054 match self.decrypt_room_event_inner(raw_event, room_id, true, decryption_settings).await {
2055 Ok(decrypted) => Ok(RoomEventDecryptionResult::Decrypted(decrypted)),
2056 Err(err) => Ok(RoomEventDecryptionResult::UnableToDecrypt(megolm_error_to_utd_info(
2057 raw_event, err,
2058 )?)),
2059 }
2060 }
2061
2062 pub async fn decrypt_room_event(
2070 &self,
2071 event: &Raw<EncryptedEvent>,
2072 room_id: &RoomId,
2073 decryption_settings: &DecryptionSettings,
2074 ) -> MegolmResult<DecryptedRoomEvent> {
2075 self.decrypt_room_event_inner(event, room_id, true, decryption_settings).await
2076 }
2077
2078 #[instrument(name = "decrypt_room_event", skip_all, fields(?room_id, event_id, origin_server_ts, sender, algorithm, session_id, message_index, sender_key))]
2079 async fn decrypt_room_event_inner(
2080 &self,
2081 event: &Raw<EncryptedEvent>,
2082 room_id: &RoomId,
2083 decrypt_unsigned: bool,
2084 decryption_settings: &DecryptionSettings,
2085 ) -> MegolmResult<DecryptedRoomEvent> {
2086 let event = event.deserialize()?;
2087
2088 Span::current()
2089 .record("sender", debug(&event.sender))
2090 .record("event_id", debug(&event.event_id))
2091 .record(
2092 "origin_server_ts",
2093 timestamp_to_iso8601(event.origin_server_ts)
2094 .unwrap_or_else(|| "<out of range>".to_owned()),
2095 )
2096 .record("algorithm", debug(event.content.algorithm()));
2097
2098 let content: SupportedEventEncryptionSchemes<'_> = match &event.content.scheme {
2099 RoomEventEncryptionScheme::MegolmV1AesSha2(c) => {
2100 Span::current().record("sender_key", debug(c.sender_key));
2101 c.into()
2102 }
2103 #[cfg(feature = "experimental-algorithms")]
2104 RoomEventEncryptionScheme::MegolmV2AesSha2(c) => c.into(),
2105 RoomEventEncryptionScheme::Unknown(_) => {
2106 warn!("Received an encrypted room event with an unsupported algorithm");
2107 return Err(EventError::UnsupportedAlgorithm.into());
2108 }
2109 };
2110
2111 Span::current().record("session_id", content.session_id());
2112 Span::current().record("message_index", content.message_index());
2113
2114 let result =
2115 self.decrypt_megolm_events(room_id, &event, &content, decryption_settings).await;
2116
2117 if let Err(e) = &result {
2118 #[cfg(feature = "automatic-room-key-forwarding")]
2119 match e {
2120 MegolmError::MissingRoomKey(_)
2123 | MegolmError::Decryption(DecryptionError::UnknownMessageIndex(_, _)) => {
2124 self.inner
2125 .key_request_machine
2126 .create_outgoing_key_request(room_id, &event)
2127 .await?;
2128 }
2129 _ => {}
2130 }
2131
2132 warn!("Failed to decrypt a room event: {e}");
2133 }
2134
2135 let (mut decrypted_event, encryption_info) = result?;
2136
2137 let mut unsigned_encryption_info = None;
2138 if decrypt_unsigned {
2139 unsigned_encryption_info = self
2141 .decrypt_unsigned_events(&mut decrypted_event, room_id, decryption_settings)
2142 .await;
2143 }
2144
2145 let event = serde_json::from_value::<Raw<AnyMessageLikeEvent>>(decrypted_event.into())?;
2146
2147 Ok(DecryptedRoomEvent { event, encryption_info, unsigned_encryption_info })
2148 }
2149
2150 async fn decrypt_unsigned_events(
2160 &self,
2161 main_event: &mut JsonObject,
2162 room_id: &RoomId,
2163 decryption_settings: &DecryptionSettings,
2164 ) -> Option<BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>> {
2165 let unsigned = main_event.get_mut("unsigned")?.as_object_mut()?;
2166 let mut unsigned_encryption_info: Option<
2167 BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>,
2168 > = None;
2169
2170 let location = UnsignedEventLocation::RelationsReplace;
2172 let replace = location.find_mut(unsigned);
2173 if let Some(decryption_result) =
2174 self.decrypt_unsigned_event(replace, room_id, decryption_settings).await
2175 {
2176 unsigned_encryption_info
2177 .get_or_insert_with(Default::default)
2178 .insert(location, decryption_result);
2179 }
2180
2181 let location = UnsignedEventLocation::RelationsThreadLatestEvent;
2184 let thread_latest_event = location.find_mut(unsigned);
2185 if let Some(decryption_result) =
2186 self.decrypt_unsigned_event(thread_latest_event, room_id, decryption_settings).await
2187 {
2188 unsigned_encryption_info
2189 .get_or_insert_with(Default::default)
2190 .insert(location, decryption_result);
2191 }
2192
2193 unsigned_encryption_info
2194 }
2195
2196 fn decrypt_unsigned_event<'a>(
2204 &'a self,
2205 event: Option<&'a mut Value>,
2206 room_id: &'a RoomId,
2207 decryption_settings: &'a DecryptionSettings,
2208 ) -> BoxFuture<'a, Option<UnsignedDecryptionResult>> {
2209 Box::pin(async move {
2210 let event = event?;
2211
2212 let is_encrypted = event
2213 .get("type")
2214 .and_then(|type_| type_.as_str())
2215 .is_some_and(|s| s == "m.room.encrypted");
2216 if !is_encrypted {
2217 return None;
2218 }
2219
2220 let raw_event = serde_json::from_value(event.clone()).ok()?;
2221 match self
2222 .decrypt_room_event_inner(&raw_event, room_id, false, decryption_settings)
2223 .await
2224 {
2225 Ok(decrypted_event) => {
2226 *event = serde_json::to_value(decrypted_event.event).ok()?;
2228 Some(UnsignedDecryptionResult::Decrypted(decrypted_event.encryption_info))
2229 }
2230 Err(err) => {
2231 let utd_info = megolm_error_to_utd_info(&raw_event, err).ok()?;
2236 Some(UnsignedDecryptionResult::UnableToDecrypt(utd_info))
2237 }
2238 }
2239 })
2240 }
2241
2242 pub async fn is_room_key_available(
2249 &self,
2250 event: &Raw<EncryptedEvent>,
2251 room_id: &RoomId,
2252 ) -> Result<bool, CryptoStoreError> {
2253 let event = event.deserialize()?;
2254
2255 let (session_id, message_index) = match &event.content.scheme {
2256 RoomEventEncryptionScheme::MegolmV1AesSha2(c) => {
2257 (&c.session_id, c.ciphertext.message_index())
2258 }
2259 #[cfg(feature = "experimental-algorithms")]
2260 RoomEventEncryptionScheme::MegolmV2AesSha2(c) => {
2261 (&c.session_id, c.ciphertext.message_index())
2262 }
2263 RoomEventEncryptionScheme::Unknown(_) => {
2264 return Ok(false);
2266 }
2267 };
2268
2269 Ok(self
2272 .store()
2273 .get_inbound_group_session(room_id, session_id)
2274 .await?
2275 .filter(|s| s.first_known_index() <= message_index)
2276 .is_some())
2277 }
2278
2279 #[instrument(skip(self, event), fields(event_id, sender, session_id))]
2292 pub async fn get_room_event_encryption_info(
2293 &self,
2294 event: &Raw<EncryptedEvent>,
2295 room_id: &RoomId,
2296 ) -> MegolmResult<Arc<EncryptionInfo>> {
2297 let event = event.deserialize()?;
2298
2299 let content: SupportedEventEncryptionSchemes<'_> = match &event.content.scheme {
2300 RoomEventEncryptionScheme::MegolmV1AesSha2(c) => c.into(),
2301 #[cfg(feature = "experimental-algorithms")]
2302 RoomEventEncryptionScheme::MegolmV2AesSha2(c) => c.into(),
2303 RoomEventEncryptionScheme::Unknown(_) => {
2304 return Err(EventError::UnsupportedAlgorithm.into());
2305 }
2306 };
2307
2308 Span::current()
2309 .record("sender", debug(&event.sender))
2310 .record("event_id", debug(&event.event_id))
2311 .record("session_id", content.session_id());
2312
2313 self.get_session_encryption_info(room_id, content.session_id(), &event.sender).await
2314 }
2315
2316 pub async fn get_session_encryption_info(
2331 &self,
2332 room_id: &RoomId,
2333 session_id: &str,
2334 sender: &UserId,
2335 ) -> MegolmResult<Arc<EncryptionInfo>> {
2336 let session = self.get_inbound_group_session_or_error(room_id, session_id).await?;
2337 self.get_encryption_info(&session, sender).await
2338 }
2339
2340 pub async fn update_tracked_users(
2358 &self,
2359 users: impl IntoIterator<Item = &UserId>,
2360 ) -> StoreResult<()> {
2361 self.inner.identity_manager.update_tracked_users(users).await
2362 }
2363
2364 pub async fn mark_all_tracked_users_as_dirty(&self) -> StoreResult<()> {
2369 self.inner
2370 .identity_manager
2371 .mark_all_tracked_users_as_dirty(self.inner.store.cache().await?)
2372 .await
2373 }
2374
2375 async fn wait_if_user_pending(
2376 &self,
2377 user_id: &UserId,
2378 timeout: Option<Duration>,
2379 ) -> StoreResult<()> {
2380 if let Some(timeout) = timeout {
2381 let cache = self.store().cache().await?;
2382 self.inner
2383 .identity_manager
2384 .key_query_manager
2385 .wait_if_user_key_query_pending(cache, timeout, user_id)
2386 .await?;
2387 }
2388 Ok(())
2389 }
2390
2391 #[instrument(skip(self))]
2421 pub async fn get_device(
2422 &self,
2423 user_id: &UserId,
2424 device_id: &DeviceId,
2425 timeout: Option<Duration>,
2426 ) -> StoreResult<Option<Device>> {
2427 self.wait_if_user_pending(user_id, timeout).await?;
2428 self.store().get_device(user_id, device_id).await
2429 }
2430
2431 #[instrument(skip(self))]
2445 pub async fn get_identity(
2446 &self,
2447 user_id: &UserId,
2448 timeout: Option<Duration>,
2449 ) -> StoreResult<Option<UserIdentity>> {
2450 self.wait_if_user_pending(user_id, timeout).await?;
2451 self.store().get_identity(user_id).await
2452 }
2453
2454 #[instrument(skip(self))]
2481 pub async fn get_user_devices(
2482 &self,
2483 user_id: &UserId,
2484 timeout: Option<Duration>,
2485 ) -> StoreResult<UserDevices> {
2486 self.wait_if_user_pending(user_id, timeout).await?;
2487 self.store().get_user_devices(user_id).await
2488 }
2489
2490 pub async fn cross_signing_status(&self) -> CrossSigningStatus {
2495 self.inner.user_identity.lock().await.status().await
2496 }
2497
2498 pub async fn export_cross_signing_keys(&self) -> StoreResult<Option<CrossSigningKeyExport>> {
2506 let master_key = self.store().export_secret(&SecretName::CrossSigningMasterKey).await?;
2507 let self_signing_key =
2508 self.store().export_secret(&SecretName::CrossSigningSelfSigningKey).await?;
2509 let user_signing_key =
2510 self.store().export_secret(&SecretName::CrossSigningUserSigningKey).await?;
2511
2512 Ok(if master_key.is_none() && self_signing_key.is_none() && user_signing_key.is_none() {
2513 None
2514 } else {
2515 Some(CrossSigningKeyExport { master_key, self_signing_key, user_signing_key })
2516 })
2517 }
2518
2519 pub async fn import_cross_signing_keys(
2524 &self,
2525 export: CrossSigningKeyExport,
2526 ) -> Result<CrossSigningStatus, SecretImportError> {
2527 self.store().import_cross_signing_keys(export).await
2528 }
2529
2530 async fn sign_with_master_key(
2531 &self,
2532 message: &str,
2533 ) -> Result<(OwnedDeviceKeyId, Ed25519Signature), SignatureError> {
2534 let identity = &*self.inner.user_identity.lock().await;
2535 let key_id = identity.master_key_id().await.ok_or(SignatureError::MissingSigningKey)?;
2536
2537 let signature = identity.sign(message).await?;
2538
2539 Ok((key_id, signature))
2540 }
2541
2542 pub async fn sign(&self, message: &str) -> Result<Signatures, CryptoStoreError> {
2548 let mut signatures = Signatures::new();
2549
2550 {
2551 let cache = self.inner.store.cache().await?;
2552 let account = cache.account().await?;
2553 let key_id = account.signing_key_id();
2554 let signature = account.sign(message);
2555 signatures.add_signature(self.user_id().to_owned(), key_id, signature);
2556 }
2557
2558 match self.sign_with_master_key(message).await {
2559 Ok((key_id, signature)) => {
2560 signatures.add_signature(self.user_id().to_owned(), key_id, signature);
2561 }
2562 Err(e) => {
2563 warn!(error = ?e, "Couldn't sign the message using the cross signing master key")
2564 }
2565 }
2566
2567 Ok(signatures)
2568 }
2569
2570 pub fn backup_machine(&self) -> &BackupMachine {
2575 &self.inner.backup_machine
2576 }
2577
2578 pub async fn initialize_crypto_store_generation(
2582 &self,
2583 generation: &Mutex<Option<u64>>,
2584 ) -> StoreResult<()> {
2585 let mut gen_guard = generation.lock().await;
2588
2589 let prev_generation =
2590 self.inner.store.get_custom_value(Self::CURRENT_GENERATION_STORE_KEY).await?;
2591
2592 let gen = match prev_generation {
2593 Some(val) => {
2594 u64::from_le_bytes(val.try_into().map_err(|_| {
2597 CryptoStoreError::InvalidLockGeneration("invalid format".to_owned())
2598 })?)
2599 .wrapping_add(1)
2600 }
2601 None => 0,
2602 };
2603
2604 tracing::debug!("Initialising crypto store generation at {}", gen);
2605
2606 self.inner
2607 .store
2608 .set_custom_value(Self::CURRENT_GENERATION_STORE_KEY, gen.to_le_bytes().to_vec())
2609 .await?;
2610
2611 *gen_guard = Some(gen);
2612
2613 Ok(())
2614 }
2615
2616 pub async fn maintain_crypto_store_generation(
2641 &'_ self,
2642 generation: &Mutex<Option<u64>>,
2643 ) -> StoreResult<(bool, u64)> {
2644 let mut gen_guard = generation.lock().await;
2645
2646 let actual_gen = self
2652 .inner
2653 .store
2654 .get_custom_value(Self::CURRENT_GENERATION_STORE_KEY)
2655 .await?
2656 .ok_or_else(|| {
2657 CryptoStoreError::InvalidLockGeneration("counter missing in store".to_owned())
2658 })?;
2659
2660 let actual_gen =
2661 u64::from_le_bytes(actual_gen.try_into().map_err(|_| {
2662 CryptoStoreError::InvalidLockGeneration("invalid format".to_owned())
2663 })?);
2664
2665 let new_gen = match gen_guard.as_ref() {
2666 Some(expected_gen) => {
2667 if actual_gen == *expected_gen {
2668 return Ok((false, actual_gen));
2669 }
2670 actual_gen.max(*expected_gen).wrapping_add(1)
2672 }
2673 None => {
2674 actual_gen.wrapping_add(1)
2677 }
2678 };
2679
2680 tracing::debug!(
2681 "Crypto store generation mismatch: previously known was {:?}, actual is {:?}, next is {}",
2682 *gen_guard,
2683 actual_gen,
2684 new_gen
2685 );
2686
2687 *gen_guard = Some(new_gen);
2689
2690 self.inner
2692 .store
2693 .set_custom_value(Self::CURRENT_GENERATION_STORE_KEY, new_gen.to_le_bytes().to_vec())
2694 .await?;
2695
2696 Ok((true, new_gen))
2697 }
2698
2699 pub fn dehydrated_devices(&self) -> DehydratedDevices {
2701 DehydratedDevices { inner: self.to_owned() }
2702 }
2703
2704 pub async fn room_settings(&self, room_id: &RoomId) -> StoreResult<Option<RoomSettings>> {
2709 self.inner.store.get_room_settings(room_id).await
2712 }
2713
2714 pub async fn set_room_settings(
2725 &self,
2726 room_id: &RoomId,
2727 new_settings: &RoomSettings,
2728 ) -> Result<(), SetRoomSettingsError> {
2729 let store = &self.inner.store;
2730
2731 let _store_transaction = store.transaction().await;
2736
2737 let old_settings = store.get_room_settings(room_id).await?;
2738
2739 if let Some(old_settings) = old_settings {
2752 if old_settings != *new_settings {
2753 return Err(SetRoomSettingsError::EncryptionDowngrade);
2754 } else {
2755 return Ok(());
2757 }
2758 }
2759
2760 match new_settings.algorithm {
2762 EventEncryptionAlgorithm::MegolmV1AesSha2 => (),
2763
2764 #[cfg(feature = "experimental-algorithms")]
2765 EventEncryptionAlgorithm::MegolmV2AesSha2 => (),
2766
2767 _ => {
2768 warn!(
2769 ?room_id,
2770 "Rejecting invalid encryption algorithm {}", new_settings.algorithm
2771 );
2772 return Err(SetRoomSettingsError::InvalidSettings);
2773 }
2774 }
2775
2776 store
2778 .save_changes(Changes {
2779 room_settings: HashMap::from([(room_id.to_owned(), new_settings.clone())]),
2780 ..Default::default()
2781 })
2782 .await?;
2783
2784 Ok(())
2785 }
2786
2787 #[cfg(any(feature = "testing", test))]
2791 pub fn same_as(&self, other: &OlmMachine) -> bool {
2792 Arc::ptr_eq(&self.inner, &other.inner)
2793 }
2794
2795 #[cfg(any(feature = "testing", test))]
2797 pub async fn uploaded_key_count(&self) -> Result<u64, CryptoStoreError> {
2798 let cache = self.inner.store.cache().await?;
2799 let account = cache.account().await?;
2800 Ok(account.uploaded_key_count())
2801 }
2802
2803 #[cfg(test)]
2805 pub(crate) fn identity_manager(&self) -> &IdentityManager {
2806 &self.inner.identity_manager
2807 }
2808
2809 #[cfg(test)]
2811 pub(crate) fn key_for_has_migrated_verification_latch() -> &'static str {
2812 Self::HAS_MIGRATED_VERIFICATION_LATCH
2813 }
2814}
2815
2816fn sender_data_to_verification_state(
2817 sender_data: SenderData,
2818 session_has_been_imported: bool,
2819) -> (VerificationState, Option<OwnedDeviceId>) {
2820 match sender_data {
2821 SenderData::UnknownDevice { owner_check_failed: false, .. } => {
2822 let device_link_problem = if session_has_been_imported {
2823 DeviceLinkProblem::InsecureSource
2824 } else {
2825 DeviceLinkProblem::MissingDevice
2826 };
2827
2828 (VerificationState::Unverified(VerificationLevel::None(device_link_problem)), None)
2829 }
2830 SenderData::UnknownDevice { owner_check_failed: true, .. } => (
2831 VerificationState::Unverified(VerificationLevel::None(
2832 DeviceLinkProblem::InsecureSource,
2833 )),
2834 None,
2835 ),
2836 SenderData::DeviceInfo { device_keys, .. } => (
2837 VerificationState::Unverified(VerificationLevel::UnsignedDevice),
2838 Some(device_keys.device_id),
2839 ),
2840 SenderData::VerificationViolation(KnownSenderData { device_id, .. }) => {
2841 (VerificationState::Unverified(VerificationLevel::VerificationViolation), device_id)
2842 }
2843 SenderData::SenderUnverified(KnownSenderData { device_id, .. }) => {
2844 (VerificationState::Unverified(VerificationLevel::UnverifiedIdentity), device_id)
2845 }
2846 SenderData::SenderVerified(KnownSenderData { device_id, .. }) => {
2847 (VerificationState::Verified, device_id)
2848 }
2849 }
2850}
2851
2852#[derive(Debug, Clone)]
2855pub struct CrossSigningBootstrapRequests {
2856 pub upload_keys_req: Option<OutgoingRequest>,
2863
2864 pub upload_signing_keys_req: UploadSigningKeysRequest,
2868
2869 pub upload_signatures_req: UploadSignaturesRequest,
2874}
2875
2876#[derive(Debug)]
2879pub struct EncryptionSyncChanges<'a> {
2880 pub to_device_events: Vec<Raw<AnyToDeviceEvent>>,
2882 pub changed_devices: &'a DeviceLists,
2885 pub one_time_keys_counts: &'a BTreeMap<OneTimeKeyAlgorithm, UInt>,
2887 pub unused_fallback_keys: Option<&'a [OneTimeKeyAlgorithm]>,
2889 pub next_batch_token: Option<String>,
2891}
2892
2893fn megolm_error_to_utd_info(
2901 raw_event: &Raw<EncryptedEvent>,
2902 error: MegolmError,
2903) -> Result<UnableToDecryptInfo, CryptoStoreError> {
2904 use MegolmError::*;
2905 let reason = match error {
2906 EventError(_) => UnableToDecryptReason::MalformedEncryptedEvent,
2907 Decode(_) => UnableToDecryptReason::MalformedEncryptedEvent,
2908 MissingRoomKey(maybe_withheld) => {
2909 UnableToDecryptReason::MissingMegolmSession { withheld_code: maybe_withheld }
2910 }
2911 Decryption(DecryptionError::UnknownMessageIndex(_, _)) => {
2912 UnableToDecryptReason::UnknownMegolmMessageIndex
2913 }
2914 Decryption(_) => UnableToDecryptReason::MegolmDecryptionFailure,
2915 JsonError(_) => UnableToDecryptReason::PayloadDeserializationFailure,
2916 MismatchedIdentityKeys(_) => UnableToDecryptReason::MismatchedIdentityKeys,
2917 SenderIdentityNotTrusted(level) => UnableToDecryptReason::SenderIdentityNotTrusted(level),
2918
2919 Store(error) => Err(error)?,
2922 };
2923
2924 let session_id = raw_event.deserialize().ok().and_then(|ev| match ev.content.scheme {
2925 RoomEventEncryptionScheme::MegolmV1AesSha2(s) => Some(s.session_id),
2926 #[cfg(feature = "experimental-algorithms")]
2927 RoomEventEncryptionScheme::MegolmV2AesSha2(s) => Some(s.session_id),
2928 RoomEventEncryptionScheme::Unknown(_) => None,
2929 });
2930
2931 Ok(UnableToDecryptInfo { session_id, reason })
2932}
2933
2934#[derive(Debug, thiserror::Error)]
2938pub(crate) enum DecryptToDeviceError {
2939 #[error("An Olm error occurred meaning we failed to decrypt the event")]
2940 OlmError(#[from] OlmError),
2941
2942 #[error("The event was sent from a dehydrated device")]
2943 FromDehydratedDevice,
2944}
2945
2946impl From<CryptoStoreError> for DecryptToDeviceError {
2947 fn from(value: CryptoStoreError) -> Self {
2948 Self::OlmError(value.into())
2949 }
2950}
2951
2952#[cfg(test)]
2953impl From<DecryptToDeviceError> for OlmError {
2954 fn from(value: DecryptToDeviceError) -> Self {
2957 match value {
2958 DecryptToDeviceError::OlmError(olm_error) => olm_error,
2959 DecryptToDeviceError::FromDehydratedDevice => {
2960 panic!("Expected an OlmError but found FromDehydratedDevice")
2961 }
2962 }
2963 }
2964}
2965
2966#[cfg(test)]
2967pub(crate) mod test_helpers;
2968
2969#[cfg(test)]
2970pub(crate) mod tests;