Skip to main content

matrix_sdk_crypto/machine/
mod.rs

1// Copyright 2020 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[cfg(feature = "experimental-encrypted-state-events")]
16use std::borrow::Borrow;
17use std::{
18    collections::{BTreeMap, HashMap, HashSet},
19    sync::Arc,
20    time::Duration,
21};
22
23use itertools::Itertools;
24#[cfg(feature = "experimental-send-custom-to-device")]
25use matrix_sdk_common::deserialized_responses::WithheldCode;
26use matrix_sdk_common::{
27    BoxFuture,
28    deserialized_responses::{
29        AlgorithmInfo, DecryptedRoomEvent, DeviceLinkProblem, EncryptionInfo, ForwarderInfo,
30        ProcessedToDeviceEvent, ToDeviceUnableToDecryptInfo, ToDeviceUnableToDecryptReason,
31        UnableToDecryptInfo, UnableToDecryptReason, UnsignedDecryptionResult,
32        UnsignedEventLocation, VerificationLevel, VerificationState,
33    },
34    locks::RwLock as StdRwLock,
35    timer,
36};
37#[cfg(feature = "experimental-encrypted-state-events")]
38use ruma::events::{AnyStateEventContent, StateEventContent};
39use ruma::{
40    DeviceId, DeviceKeyAlgorithm, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OwnedDeviceId,
41    OwnedDeviceKeyId, OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UInt, UserId,
42    api::client::{
43        dehydrated_device::DehydratedDeviceData,
44        keys::{
45            claim_keys::v3::Request as KeysClaimRequest,
46            get_keys::v3::Response as KeysQueryResponse,
47            upload_keys::v3::{Request as UploadKeysRequest, Response as UploadKeysResponse},
48            upload_signatures::v3::Request as UploadSignaturesRequest,
49        },
50        sync::sync_events::DeviceLists,
51    },
52    assign,
53    events::{
54        AnyMessageLikeEvent, AnyMessageLikeEventContent, AnyTimelineEvent, AnyToDeviceEvent,
55        MessageLikeEventContent, secret::request::SecretName,
56    },
57    serde::{JsonObject, Raw},
58};
59use serde::Serialize;
60use serde_json::{Value, value::to_raw_value};
61use tokio::sync::Mutex;
62use tracing::{
63    Span, debug, enabled, error,
64    field::{debug, display},
65    info, instrument, trace, warn,
66};
67use vodozemac::{Curve25519PublicKey, Ed25519Signature, megolm::DecryptionError};
68
69#[cfg(feature = "experimental-send-custom-to-device")]
70use crate::session_manager::split_devices_for_share_strategy;
71use crate::{
72    CollectStrategy, CryptoStoreError, DecryptionSettings, DeviceData, LocalTrust,
73    RoomEventDecryptionResult, SignatureError, TrustRequirement,
74    backups::{BackupMachine, MegolmV1BackupKey},
75    dehydrated_devices::{DehydratedDevices, DehydrationError},
76    error::{EventError, MegolmError, MegolmResult, OlmError, OlmResult, SetRoomSettingsError},
77    gossiping::GossipMachine,
78    identities::{Device, IdentityManager, UserDevices, user::UserIdentity},
79    olm::{
80        Account, CrossSigningStatus, EncryptionSettings, IdentityKeys, InboundGroupSession,
81        KnownSenderData, OlmDecryptionInfo, PrivateCrossSigningIdentity, SenderData,
82        SenderDataFinder, SessionType, StaticAccountData,
83    },
84    session_manager::{GroupSessionManager, SessionManager},
85    store::{
86        CryptoStoreWrapper, IntoCryptoStore, MemoryStore, Result as StoreResult, SecretImportError,
87        Store, StoreTransaction,
88        caches::StoreCache,
89        types::{
90            Changes, CrossSigningKeyExport, DeviceChanges, IdentityChanges, PendingChanges,
91            RoomKeyInfo, RoomSettings, StoredRoomKeyBundleData,
92        },
93    },
94    types::{
95        EventEncryptionAlgorithm, Signatures,
96        events::{
97            ToDeviceEvent, ToDeviceEvents,
98            olm_v1::{AnyDecryptedOlmEvent, DecryptedRoomKeyBundleEvent, DecryptedRoomKeyEvent},
99            room::encrypted::{
100                EncryptedEvent, EncryptedToDeviceEvent, RoomEncryptedEventContent,
101                RoomEventEncryptionScheme, SupportedEventEncryptionSchemes,
102                ToDeviceEncryptedEventContent,
103            },
104            room_key::{MegolmV1AesSha2Content, RoomKeyContent},
105            room_key_bundle::RoomKeyBundleContent,
106            room_key_withheld::{
107                MegolmV1AesSha2WithheldContent, RoomKeyWithheldContent, RoomKeyWithheldEvent,
108            },
109        },
110        requests::{
111            AnyIncomingResponse, KeysQueryRequest, OutgoingRequest, ToDeviceRequest,
112            UploadSigningKeysRequest,
113        },
114    },
115    utilities::timestamp_to_iso8601,
116    verification::{Verification, VerificationMachine, VerificationRequest},
117};
118
119#[derive(Debug, Serialize)]
120/// The result of encrypting a room event.
121pub struct RawEncryptionResult {
122    /// The encrypted event content.
123    pub content: Raw<RoomEncryptedEventContent>,
124    /// Information about the encryption that was performed.
125    pub encryption_info: EncryptionInfo,
126}
127
128/// State machine implementation of the Olm/Megolm encryption protocol used for
129/// Matrix end to end encryption.
130#[derive(Clone)]
131pub struct OlmMachine {
132    pub(crate) inner: Arc<OlmMachineInner>,
133}
134
135pub struct OlmMachineInner {
136    /// The unique user id that owns this account.
137    user_id: OwnedUserId,
138    /// The unique device ID of the device that holds this account.
139    device_id: OwnedDeviceId,
140    /// The private part of our cross signing identity.
141    /// Used to sign devices and other users, might be missing if some other
142    /// device bootstrapped cross signing or cross signing isn't bootstrapped at
143    /// all.
144    user_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
145    /// Store for the encryption keys.
146    /// Persists all the encryption keys so a client can resume the session
147    /// without the need to create new keys.
148    store: Store,
149    /// A state machine that handles Olm sessions creation.
150    session_manager: SessionManager,
151    /// A state machine that keeps track of our outbound group sessions.
152    pub(crate) group_session_manager: GroupSessionManager,
153    /// A state machine that is responsible to handle and keep track of SAS
154    /// verification flows.
155    verification_machine: VerificationMachine,
156    /// The state machine that is responsible to handle outgoing and incoming
157    /// key requests.
158    pub(crate) key_request_machine: GossipMachine,
159    /// State machine handling public user identities and devices, keeping track
160    /// of when a key query needs to be done and handling one.
161    identity_manager: IdentityManager,
162    /// A state machine that handles creating room key backups.
163    backup_machine: BackupMachine,
164}
165
166#[cfg(not(tarpaulin_include))]
167impl std::fmt::Debug for OlmMachine {
168    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169        f.debug_struct("OlmMachine")
170            .field("user_id", &self.user_id())
171            .field("device_id", &self.device_id())
172            .finish()
173    }
174}
175
176impl OlmMachine {
177    const CURRENT_GENERATION_STORE_KEY: &'static str = "generation-counter";
178    const HAS_MIGRATED_VERIFICATION_LATCH: &'static str = "HAS_MIGRATED_VERIFICATION_LATCH";
179
180    /// Create a new memory based OlmMachine.
181    ///
182    /// The created machine will keep the encryption keys only in memory and
183    /// once the object is dropped the keys will be lost.
184    ///
185    /// # Arguments
186    ///
187    /// * `user_id` - The unique id of the user that owns this machine.
188    ///
189    /// * `device_id` - The unique id of the device that owns this machine.
190    pub async fn new(user_id: &UserId, device_id: &DeviceId) -> Self {
191        OlmMachine::with_store(user_id, device_id, MemoryStore::new(), None)
192            .await
193            .expect("Reading and writing to the memory store always succeeds")
194    }
195
196    pub(crate) async fn rehydrate(
197        &self,
198        pickle_key: &[u8; 32],
199        device_id: &DeviceId,
200        device_data: Raw<DehydratedDeviceData>,
201    ) -> Result<OlmMachine, DehydrationError> {
202        let account = Account::rehydrate(pickle_key, self.user_id(), device_id, device_data)?;
203        let static_account = account.static_data().clone();
204
205        let store =
206            Arc::new(CryptoStoreWrapper::new(self.user_id(), device_id, MemoryStore::new()));
207        let device = DeviceData::from_account(&account);
208        store.save_pending_changes(PendingChanges { account: Some(account) }).await?;
209        store
210            .save_changes(Changes {
211                devices: DeviceChanges { new: vec![device], ..Default::default() },
212                ..Default::default()
213            })
214            .await?;
215
216        let (verification_machine, store, identity_manager) =
217            Self::new_helper_prelude(store, static_account, self.store().private_identity());
218
219        Ok(Self::new_helper(
220            device_id,
221            store,
222            verification_machine,
223            identity_manager,
224            self.store().private_identity(),
225            None,
226        ))
227    }
228
229    fn new_helper_prelude(
230        store_wrapper: Arc<CryptoStoreWrapper>,
231        account: StaticAccountData,
232        user_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
233    ) -> (VerificationMachine, Store, IdentityManager) {
234        let verification_machine =
235            VerificationMachine::new(account.clone(), user_identity.clone(), store_wrapper.clone());
236        let store = Store::new(account, user_identity, store_wrapper, verification_machine.clone());
237
238        let identity_manager = IdentityManager::new(store.clone());
239
240        (verification_machine, store, identity_manager)
241    }
242
243    fn new_helper(
244        device_id: &DeviceId,
245        store: Store,
246        verification_machine: VerificationMachine,
247        identity_manager: IdentityManager,
248        user_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
249        maybe_backup_key: Option<MegolmV1BackupKey>,
250    ) -> Self {
251        let group_session_manager = GroupSessionManager::new(store.clone());
252
253        let users_for_key_claim = Arc::new(StdRwLock::new(BTreeMap::new()));
254        let key_request_machine = GossipMachine::new(
255            store.clone(),
256            identity_manager.clone(),
257            group_session_manager.session_cache(),
258            users_for_key_claim.clone(),
259        );
260
261        let session_manager =
262            SessionManager::new(users_for_key_claim, key_request_machine.clone(), store.clone());
263
264        let backup_machine = BackupMachine::new(store.clone(), maybe_backup_key);
265
266        let inner = Arc::new(OlmMachineInner {
267            user_id: store.user_id().to_owned(),
268            device_id: device_id.to_owned(),
269            user_identity,
270            store,
271            session_manager,
272            group_session_manager,
273            verification_machine,
274            key_request_machine,
275            identity_manager,
276            backup_machine,
277        });
278
279        Self { inner }
280    }
281
282    /// Create a new OlmMachine with the given [`CryptoStore`].
283    ///
284    /// If the store already contains encryption keys for the given user/device
285    /// pair those will be re-used. Otherwise new ones will be created and
286    /// stored.
287    ///
288    /// # Arguments
289    ///
290    /// * `user_id` - The unique id of the user that owns this machine.
291    ///
292    /// * `device_id` - The unique id of the device that owns this machine.
293    ///
294    /// * `store` - A `CryptoStore` implementation that will be used to store
295    /// the encryption keys.
296    ///
297    /// * `custom_account` - A custom [`vodozemac::olm::Account`] to be used for
298    ///   the identity and one-time keys of this [`OlmMachine`]. If no account
299    ///   is provided, a new default one or one from the store will be used. If
300    ///   an account is provided and one already exists in the store for this
301    ///   [`UserId`]/[`DeviceId`] combination, an error will be raised. This is
302    ///   useful if one wishes to create identity keys before knowing the
303    ///   user/device IDs, e.g., to use the identity key as the device ID.
304    ///
305    /// [`CryptoStore`]: crate::store::CryptoStore
306    #[instrument(skip(store, custom_account), fields(ed25519_key, curve25519_key))]
307    pub async fn with_store(
308        user_id: &UserId,
309        device_id: &DeviceId,
310        store: impl IntoCryptoStore,
311        custom_account: Option<vodozemac::olm::Account>,
312    ) -> StoreResult<Self> {
313        let store = store.into_crypto_store();
314
315        let static_account = match store.load_account().await? {
316            Some(account) => {
317                if user_id != account.user_id()
318                    || device_id != account.device_id()
319                    || custom_account.is_some()
320                {
321                    return Err(CryptoStoreError::MismatchedAccount {
322                        expected: (account.user_id().to_owned(), account.device_id().to_owned()),
323                        got: (user_id.to_owned(), device_id.to_owned()),
324                    });
325                }
326
327                Span::current()
328                    .record("ed25519_key", display(account.identity_keys().ed25519))
329                    .record("curve25519_key", display(account.identity_keys().curve25519));
330                debug!("Restored an Olm account");
331
332                account.static_data().clone()
333            }
334
335            None => {
336                let account = if let Some(account) = custom_account {
337                    Account::new_helper(account, user_id, device_id)
338                } else {
339                    Account::with_device_id(user_id, device_id)
340                };
341
342                let static_account = account.static_data().clone();
343
344                Span::current()
345                    .record("ed25519_key", display(account.identity_keys().ed25519))
346                    .record("curve25519_key", display(account.identity_keys().curve25519));
347
348                let device = DeviceData::from_account(&account);
349
350                // We just created this device from our own Olm `Account`. Since we are the
351                // owners of the private keys of this device we can safely mark
352                // the device as verified.
353                device.set_trust_state(LocalTrust::Verified);
354
355                let changes = Changes {
356                    devices: DeviceChanges { new: vec![device], ..Default::default() },
357                    ..Default::default()
358                };
359                store.save_changes(changes).await?;
360                store.save_pending_changes(PendingChanges { account: Some(account) }).await?;
361
362                debug!("Created a new Olm account");
363
364                static_account
365            }
366        };
367
368        let identity = match store.load_identity().await? {
369            Some(i) => {
370                let master_key = i
371                    .master_public_key()
372                    .await
373                    .and_then(|m| m.get_first_key().map(|m| m.to_owned()));
374                debug!(?master_key, "Restored the cross signing identity");
375                i
376            }
377            None => {
378                debug!("Creating an empty cross signing identity stub");
379                PrivateCrossSigningIdentity::empty(user_id)
380            }
381        };
382
383        // FIXME: This is a workaround for `regenerate_olm` clearing the backup
384        // state. Ideally, backups should not get automatically enabled since
385        // the `OlmMachine` doesn't get enough info from the homeserver for this
386        // to work reliably.
387        let saved_keys = store.load_backup_keys().await?;
388        let maybe_backup_key = saved_keys.decryption_key.and_then(|k| {
389            if let Some(version) = saved_keys.backup_version {
390                let megolm_v1_backup_key = k.megolm_v1_public_key();
391                megolm_v1_backup_key.set_version(version);
392                Some(megolm_v1_backup_key)
393            } else {
394                None
395            }
396        });
397
398        let identity = Arc::new(Mutex::new(identity));
399        let store = Arc::new(CryptoStoreWrapper::new(user_id, device_id, store));
400
401        let (verification_machine, store, identity_manager) =
402            Self::new_helper_prelude(store, static_account, identity.clone());
403
404        // FIXME: We might want in the future a more generic high-level data migration
405        // mechanism (at the store wrapper layer).
406        Self::migration_post_verified_latch_support(&store, &identity_manager).await?;
407
408        Ok(Self::new_helper(
409            device_id,
410            store,
411            verification_machine,
412            identity_manager,
413            identity,
414            maybe_backup_key,
415        ))
416    }
417
418    // The sdk now support verified identity change detection.
419    // This introduces a new local flag (`verified_latch` on
420    // `OtherUserIdentityData`). In order to ensure that this flag is up-to-date and
421    // for the sake of simplicity we force a re-download of tracked users by marking
422    // them as dirty.
423    //
424    // pub(crate) visibility for testing.
425    pub(crate) async fn migration_post_verified_latch_support(
426        store: &Store,
427        identity_manager: &IdentityManager,
428    ) -> Result<(), CryptoStoreError> {
429        let maybe_migrate_for_identity_verified_latch =
430            store.get_custom_value(Self::HAS_MIGRATED_VERIFICATION_LATCH).await?.is_none();
431
432        if maybe_migrate_for_identity_verified_latch {
433            identity_manager.mark_all_tracked_users_as_dirty(store.cache().await?).await?;
434
435            store.set_custom_value(Self::HAS_MIGRATED_VERIFICATION_LATCH, vec![0]).await?
436        }
437        Ok(())
438    }
439
440    /// Get the crypto store associated with this `OlmMachine` instance.
441    pub fn store(&self) -> &Store {
442        &self.inner.store
443    }
444
445    /// The unique user id that owns this `OlmMachine` instance.
446    pub fn user_id(&self) -> &UserId {
447        &self.inner.user_id
448    }
449
450    /// The unique device ID that identifies this `OlmMachine`.
451    pub fn device_id(&self) -> &DeviceId {
452        &self.inner.device_id
453    }
454
455    /// The time at which the `Account` backing this `OlmMachine` was created.
456    ///
457    /// An [`Account`] is created when an `OlmMachine` is first instantiated
458    /// against a given [`Store`], at which point it creates identity keys etc.
459    /// This method returns the timestamp, according to the local clock, at
460    /// which that happened.
461    pub fn device_creation_time(&self) -> MilliSecondsSinceUnixEpoch {
462        self.inner.store.static_account().creation_local_time()
463    }
464
465    /// Get the public parts of our Olm identity keys.
466    pub fn identity_keys(&self) -> IdentityKeys {
467        let account = self.inner.store.static_account();
468        account.identity_keys()
469    }
470
471    /// Get the display name of our own device
472    pub async fn display_name(&self) -> StoreResult<Option<String>> {
473        self.store().device_display_name().await
474    }
475
476    /// Get the list of "tracked users".
477    ///
478    /// See [`update_tracked_users`](#method.update_tracked_users) for more
479    /// information.
480    pub async fn tracked_users(&self) -> StoreResult<HashSet<OwnedUserId>> {
481        let cache = self.store().cache().await?;
482        Ok(self.inner.identity_manager.key_query_manager.synced(&cache).await?.tracked_users())
483    }
484
485    /// Enable or disable room key requests.
486    ///
487    /// Room key requests allow the device to request room keys that it might
488    /// have missed in the original share using `m.room_key_request`
489    /// events.
490    ///
491    /// See also [`OlmMachine::set_room_key_forwarding_enabled`] and
492    /// [`OlmMachine::are_room_key_requests_enabled`].
493    #[cfg(feature = "automatic-room-key-forwarding")]
494    pub fn set_room_key_requests_enabled(&self, enable: bool) {
495        self.inner.key_request_machine.set_room_key_requests_enabled(enable)
496    }
497
498    /// Query whether we should send outgoing `m.room_key_request`s on
499    /// decryption failure.
500    ///
501    /// See also [`OlmMachine::set_room_key_requests_enabled`].
502    pub fn are_room_key_requests_enabled(&self) -> bool {
503        self.inner.key_request_machine.are_room_key_requests_enabled()
504    }
505
506    /// Enable or disable room key forwarding.
507    ///
508    /// If room key forwarding is enabled, we will automatically reply to
509    /// incoming `m.room_key_request` messages from verified devices by
510    /// forwarding the requested key (if we have it).
511    ///
512    /// See also [`OlmMachine::set_room_key_requests_enabled`] and
513    /// [`OlmMachine::is_room_key_forwarding_enabled`].
514    #[cfg(feature = "automatic-room-key-forwarding")]
515    pub fn set_room_key_forwarding_enabled(&self, enable: bool) {
516        self.inner.key_request_machine.set_room_key_forwarding_enabled(enable)
517    }
518
519    /// Is room key forwarding enabled?
520    ///
521    /// See also [`OlmMachine::set_room_key_forwarding_enabled`].
522    pub fn is_room_key_forwarding_enabled(&self) -> bool {
523        self.inner.key_request_machine.is_room_key_forwarding_enabled()
524    }
525
526    /// Get the outgoing requests that need to be sent out.
527    ///
528    /// This returns a list of [`OutgoingRequest`]. Those requests need to be
529    /// sent out to the server and the responses need to be passed back to
530    /// the state machine using [`mark_request_as_sent`].
531    ///
532    /// [`mark_request_as_sent`]: #method.mark_request_as_sent
533    pub async fn outgoing_requests(&self) -> StoreResult<Vec<OutgoingRequest>> {
534        let mut requests = Vec::new();
535
536        {
537            let store_cache = self.inner.store.cache().await?;
538            let account = store_cache.account().await?;
539            if let Some(r) = self.keys_for_upload(&account).await.map(|r| OutgoingRequest {
540                request_id: TransactionId::new(),
541                request: Arc::new(r.into()),
542            }) {
543                requests.push(r);
544            }
545        }
546
547        for request in self
548            .inner
549            .identity_manager
550            .users_for_key_query()
551            .await?
552            .into_iter()
553            .map(|(request_id, r)| OutgoingRequest { request_id, request: Arc::new(r.into()) })
554        {
555            requests.push(request);
556        }
557
558        requests.append(&mut self.inner.verification_machine.outgoing_messages());
559        requests.append(&mut self.inner.key_request_machine.outgoing_to_device_requests().await?);
560
561        Ok(requests)
562    }
563
564    /// Generate an "out-of-band" key query request for the given set of users.
565    ///
566    /// This can be useful if we need the results from [`get_identity`] or
567    /// [`get_user_devices`] to be as up-to-date as possible.
568    ///
569    /// Note that this request won't be awaited by other calls waiting for a
570    /// user's or device's keys, since this is an out-of-band query.
571    ///
572    /// # Arguments
573    ///
574    /// * `users` - list of users whose keys should be queried
575    ///
576    /// # Returns
577    ///
578    /// A request to be sent out to the server. Once sent, the response should
579    /// be passed back to the state machine using [`mark_request_as_sent`].
580    ///
581    /// [`mark_request_as_sent`]: OlmMachine::mark_request_as_sent
582    /// [`get_identity`]: OlmMachine::get_identity
583    /// [`get_user_devices`]: OlmMachine::get_user_devices
584    pub fn query_keys_for_users<'a>(
585        &self,
586        users: impl IntoIterator<Item = &'a UserId>,
587    ) -> (OwnedTransactionId, KeysQueryRequest) {
588        self.inner.identity_manager.build_key_query_for_users(users)
589    }
590
591    /// Mark the request with the given request id as sent.
592    ///
593    /// # Arguments
594    ///
595    /// * `request_id` - The unique id of the request that was sent out. This is
596    ///   needed to couple the response with the now sent out request.
597    ///
598    /// * `response` - The response that was received from the server after the
599    ///   outgoing request was sent out.
600    pub async fn mark_request_as_sent<'a>(
601        &self,
602        request_id: &TransactionId,
603        response: impl Into<AnyIncomingResponse<'a>>,
604    ) -> OlmResult<()> {
605        match response.into() {
606            AnyIncomingResponse::KeysUpload(response) => {
607                Box::pin(self.receive_keys_upload_response(response)).await?;
608            }
609            AnyIncomingResponse::KeysQuery(response) => {
610                Box::pin(self.receive_keys_query_response(request_id, response)).await?;
611            }
612            AnyIncomingResponse::KeysClaim(response) => {
613                Box::pin(
614                    self.inner.session_manager.receive_keys_claim_response(request_id, response),
615                )
616                .await?;
617            }
618            AnyIncomingResponse::ToDevice(_) => {
619                Box::pin(self.mark_to_device_request_as_sent(request_id)).await?;
620            }
621            AnyIncomingResponse::SigningKeysUpload(_) => {
622                Box::pin(self.receive_cross_signing_upload_response()).await?;
623            }
624            AnyIncomingResponse::SignatureUpload(_) => {
625                self.inner.verification_machine.mark_request_as_sent(request_id);
626            }
627            AnyIncomingResponse::RoomMessage(_) => {
628                self.inner.verification_machine.mark_request_as_sent(request_id);
629            }
630            AnyIncomingResponse::KeysBackup(_) => {
631                Box::pin(self.inner.backup_machine.mark_request_as_sent(request_id)).await?;
632            }
633        }
634
635        Ok(())
636    }
637
638    /// Mark the cross signing identity as shared.
639    async fn receive_cross_signing_upload_response(&self) -> StoreResult<()> {
640        let identity = self.inner.user_identity.lock().await;
641        identity.mark_as_shared();
642
643        let changes = Changes { private_identity: Some(identity.clone()), ..Default::default() };
644
645        self.store().save_changes(changes).await
646    }
647
648    /// Create a new cross signing identity and get the upload request to push
649    /// the new public keys to the server.
650    ///
651    /// **Warning**: if called with `reset`, this will delete any existing cross
652    /// signing keys that might exist on the server and thus will reset the
653    /// trust between all the devices.
654    ///
655    /// # Returns
656    ///
657    /// A triple of requests which should be sent out to the server, in the
658    /// order they appear in the return tuple.
659    ///
660    /// The first request's response, if present, should be passed back to the
661    /// state machine using [`mark_request_as_sent`].
662    ///
663    /// These requests may require user interactive auth.
664    ///
665    /// [`mark_request_as_sent`]: #method.mark_request_as_sent
666    pub async fn bootstrap_cross_signing(
667        &self,
668        reset: bool,
669    ) -> StoreResult<CrossSigningBootstrapRequests> {
670        // Don't hold the lock, otherwise we might deadlock in
671        // `bootstrap_cross_signing()` on `account` if a sync task is already
672        // running (which locks `account`), or we will deadlock
673        // in `upload_device_keys()` which locks private identity again.
674        let identity = self.inner.user_identity.lock().await.clone();
675
676        let (upload_signing_keys_req, upload_signatures_req) = if reset || identity.is_empty().await
677        {
678            info!("Creating new cross signing identity");
679
680            let (identity, upload_signing_keys_req, upload_signatures_req) = {
681                let cache = self.inner.store.cache().await?;
682                let account = cache.account().await?;
683                account.bootstrap_cross_signing().await
684            };
685
686            let public = identity.to_public_identity().await.expect(
687                "Couldn't create a public version of the identity from a new private identity",
688            );
689
690            *self.inner.user_identity.lock().await = identity.clone();
691
692            self.store()
693                .save_changes(Changes {
694                    identities: IdentityChanges { new: vec![public.into()], ..Default::default() },
695                    private_identity: Some(identity),
696                    ..Default::default()
697                })
698                .await?;
699
700            (upload_signing_keys_req, upload_signatures_req)
701        } else {
702            info!("Trying to upload the existing cross signing identity");
703            let upload_signing_keys_req = identity.as_upload_request().await;
704
705            // TODO remove this expect.
706            let upload_signatures_req = identity
707                .sign_account(self.inner.store.static_account())
708                .await
709                .expect("Can't sign device keys");
710
711            (upload_signing_keys_req, upload_signatures_req)
712        };
713
714        // If there are any *device* keys to upload (i.e. the account isn't shared),
715        // upload them before we upload the signatures, since the signatures may
716        // reference keys to be uploaded.
717        let upload_keys_req =
718            self.upload_device_keys().await?.map(|(_, request)| OutgoingRequest::from(request));
719
720        Ok(CrossSigningBootstrapRequests {
721            upload_signing_keys_req,
722            upload_keys_req,
723            upload_signatures_req,
724        })
725    }
726
727    /// Upload the device keys for this [`OlmMachine`].
728    ///
729    /// **Warning**: Do not use this method if
730    /// [`OlmMachine::outgoing_requests()`] is already in use. This method
731    /// is intended for explicitly uploading the device keys before starting
732    /// a sync and before using [`OlmMachine::outgoing_requests()`].
733    ///
734    /// # Returns
735    ///
736    /// A tuple containing a transaction ID and a request if the device keys
737    /// need to be uploaded. Otherwise, returns `None`.
738    pub async fn upload_device_keys(
739        &self,
740    ) -> StoreResult<Option<(OwnedTransactionId, UploadKeysRequest)>> {
741        let cache = self.store().cache().await?;
742        let account = cache.account().await?;
743
744        Ok(self.keys_for_upload(&account).await.map(|request| (TransactionId::new(), request)))
745    }
746
747    /// Receive a successful `/keys/upload` response.
748    ///
749    /// # Arguments
750    ///
751    /// * `response` - The response of the `/keys/upload` request that the
752    ///   client performed.
753    async fn receive_keys_upload_response(&self, response: &UploadKeysResponse) -> OlmResult<()> {
754        self.inner
755            .store
756            .with_transaction(|mut tr| async {
757                let account = tr.account().await?;
758                account.receive_keys_upload_response(response)?;
759                Ok((tr, ()))
760            })
761            .await
762    }
763
764    /// Get a key claiming request for the user/device pairs that we are
765    /// missing Olm sessions for.
766    ///
767    /// Returns None if no key claiming request needs to be sent out.
768    ///
769    /// Sessions need to be established between devices so group sessions for a
770    /// room can be shared with them.
771    ///
772    /// This should be called every time a group session needs to be shared as
773    /// well as between sync calls. After a sync some devices may request room
774    /// keys without us having a valid Olm session with them, making it
775    /// impossible to server the room key request, thus it's necessary to check
776    /// for missing sessions between sync as well.
777    ///
778    /// **Note**: Care should be taken that only one such request at a time is
779    /// in flight, e.g. using a lock.
780    ///
781    /// The response of a successful key claiming requests needs to be passed to
782    /// the `OlmMachine` with the [`mark_request_as_sent`].
783    ///
784    /// # Arguments
785    ///
786    /// `users` - The list of users that we should check if we lack a session
787    /// with one of their devices. This can be an empty iterator when calling
788    /// this method between sync requests.
789    ///
790    /// [`mark_request_as_sent`]: #method.mark_request_as_sent
791    #[instrument(skip_all)]
792    pub async fn get_missing_sessions(
793        &self,
794        users: impl Iterator<Item = &UserId>,
795    ) -> StoreResult<Option<(OwnedTransactionId, KeysClaimRequest)>> {
796        self.inner.session_manager.get_missing_sessions(users).await
797    }
798
799    /// Receive a successful `/keys/query` response.
800    ///
801    /// Returns a list of newly discovered devices and devices that changed.
802    ///
803    /// # Arguments
804    ///
805    /// * `response` - The response of the `/keys/query` request that the client
806    ///   performed.
807    async fn receive_keys_query_response(
808        &self,
809        request_id: &TransactionId,
810        response: &KeysQueryResponse,
811    ) -> OlmResult<(DeviceChanges, IdentityChanges)> {
812        self.inner.identity_manager.receive_keys_query_response(request_id, response).await
813    }
814
815    /// Get a request to upload E2EE keys to the server.
816    ///
817    /// Returns None if no keys need to be uploaded.
818    ///
819    /// The response of a successful key upload requests needs to be passed to
820    /// the [`OlmMachine`] with the [`receive_keys_upload_response`].
821    ///
822    /// [`receive_keys_upload_response`]: #method.receive_keys_upload_response
823    async fn keys_for_upload(&self, account: &Account) -> Option<UploadKeysRequest> {
824        let (mut device_keys, one_time_keys, fallback_keys) = account.keys_for_upload();
825
826        // When uploading the device keys, if all private cross-signing keys are
827        // available locally, sign the device using these cross-signing keys.
828        // This will mark the device as verified if the user identity (i.e., the
829        // cross-signing keys) is also marked as verified.
830        //
831        // This approach eliminates the need to upload signatures in a separate request,
832        // ensuring that other users/devices will never encounter this device
833        // without a signature from their user identity. Consequently, they will
834        // never see the device as unverified.
835        if let Some(device_keys) = &mut device_keys {
836            let private_identity = self.store().private_identity();
837            let guard = private_identity.lock().await;
838
839            if guard.status().await.is_complete() {
840                guard.sign_device_keys(device_keys).await.expect(
841                    "We should be able to sign our device keys since we confirmed that we \
842                     have a complete set of private cross-signing keys",
843                );
844            }
845        }
846
847        if device_keys.is_none() && one_time_keys.is_empty() && fallback_keys.is_empty() {
848            None
849        } else {
850            let device_keys = device_keys.map(|d| d.to_raw());
851
852            Some(assign!(UploadKeysRequest::new(), {
853                device_keys, one_time_keys, fallback_keys
854            }))
855        }
856    }
857
858    /// Decrypt and handle a to-device event.
859    ///
860    /// If decryption (or checking the sender device) fails, returns an
861    /// `Err(DecryptToDeviceError::OlmError)`.
862    ///
863    /// If we are in strict "exclude insecure devices" mode and the sender
864    /// device is not verified, and the decrypted event type is not on the
865    /// allow list, returns `Err(DecryptToDeviceError::UnverifiedSender)`
866    ///
867    /// (The allow list of types that are processed even if the sender is
868    /// unverified is: `m.room_key`, `m.room_key.withheld`,
869    /// `m.room_key_request`, `m.secret.request` and `m.key.verification.*`.)
870    ///
871    /// If the sender device is dehydrated, does no handling and immediately
872    /// returns `Err(DecryptToDeviceError::FromDehydratedDevice)`.
873    ///
874    /// Otherwise, handles the decrypted event and returns it (decrypted) as
875    /// `Ok(OlmDecryptionInfo)`.
876    ///
877    /// # Arguments
878    ///
879    /// * `event` - The to-device event that should be decrypted.
880    async fn decrypt_to_device_event(
881        &self,
882        transaction: &mut StoreTransaction,
883        event: &EncryptedToDeviceEvent,
884        changes: &mut Changes,
885        decryption_settings: &DecryptionSettings,
886    ) -> Result<OlmDecryptionInfo, DecryptToDeviceError> {
887        // Decrypt the event
888        let mut decrypted = transaction
889            .account()
890            .await?
891            .decrypt_to_device_event(&self.inner.store, event, decryption_settings)
892            .await?;
893
894        // Return early if the sending device is a dehydrated device
895        self.check_to_device_event_is_not_from_dehydrated_device(&decrypted, &event.sender).await?;
896
897        // Device is not dehydrated: handle it as normal e.g. create a Megolm session
898        self.handle_decrypted_to_device_event(transaction.cache(), &mut decrypted, changes).await?;
899
900        Ok(decrypted)
901    }
902
903    #[instrument(
904        skip_all,
905        // This function is only ever called by add_room_key via
906        // handle_decrypted_to_device_event, so sender, sender_key, and algorithm are
907        // already recorded.
908        fields(room_id = ? content.room_id, session_id, message_index, shared_history = content.shared_history)
909    )]
910    async fn handle_key(
911        &self,
912        sender_key: Curve25519PublicKey,
913        event: &DecryptedRoomKeyEvent,
914        content: &MegolmV1AesSha2Content,
915    ) -> OlmResult<Option<InboundGroupSession>> {
916        let session =
917            InboundGroupSession::from_room_key_content(sender_key, event.keys.ed25519, content);
918
919        match session {
920            Ok(mut session) => {
921                Span::current().record("session_id", session.session_id());
922                Span::current().record("message_index", session.first_known_index());
923
924                let sender_data =
925                    SenderDataFinder::find_using_event(self.store(), sender_key, event, &session)
926                        .await?;
927                session.sender_data = sender_data;
928
929                Ok(self.store().merge_received_group_session(session).await?)
930            }
931            Err(e) => {
932                Span::current().record("session_id", &content.session_id);
933                warn!("Received a room key event which contained an invalid session key: {e}");
934
935                Ok(None)
936            }
937        }
938    }
939
940    /// Create a group session from a room key and add it to our crypto store.
941    #[instrument(skip_all, fields(algorithm = ?event.content.algorithm()))]
942    async fn add_room_key(
943        &self,
944        sender_key: Curve25519PublicKey,
945        event: &DecryptedRoomKeyEvent,
946    ) -> OlmResult<Option<InboundGroupSession>> {
947        match &event.content {
948            RoomKeyContent::MegolmV1AesSha2(content) => {
949                self.handle_key(sender_key, event, content).await
950            }
951            #[cfg(feature = "experimental-algorithms")]
952            RoomKeyContent::MegolmV2AesSha2(content) => {
953                self.handle_key(sender_key, event, content).await
954            }
955            RoomKeyContent::Unknown(_) => {
956                warn!("Received a room key with an unsupported algorithm");
957                Ok(None)
958            }
959        }
960    }
961
962    /// Handle a received, decrypted, `io.element.msc4268.room_key_bundle`
963    /// to-device event.
964    #[instrument()]
965    async fn receive_room_key_bundle_data(
966        &self,
967        sender_key: Curve25519PublicKey,
968        event: &DecryptedRoomKeyBundleEvent,
969        changes: &mut Changes,
970    ) -> OlmResult<()> {
971        let Some(sender_device_keys) = &event.sender_device_keys else {
972            warn!("Received a room key bundle with no sender device keys: ignoring");
973            return Ok(());
974        };
975
976        // NOTE: We already checked that `sender_device_keys` matches the actual sender
977        // of the message when we decrypted the message, which included doing
978        // `DeviceData::try_from` on it, so it can't fail.
979
980        let sender_device_data =
981            DeviceData::try_from(sender_device_keys).expect("failed to verify sender device keys");
982        let sender_device = self.store().wrap_device_data(sender_device_data).await?;
983
984        changes.received_room_key_bundles.push(StoredRoomKeyBundleData {
985            sender_user: event.sender.clone(),
986            sender_data: SenderData::from_device(&sender_device),
987            sender_key,
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            | MegolmV1AesSha2WithheldContent::Unauthorised(c)
1000            | MegolmV1AesSha2WithheldContent::Unavailable(c),
1001        ) = &event.content
1002        {
1003            changes
1004                .withheld_session_info
1005                .entry(c.room_id.to_owned())
1006                .or_default()
1007                .insert(c.session_id.to_owned(), event.to_owned().into());
1008        }
1009    }
1010
1011    #[cfg(test)]
1012    pub(crate) async fn create_outbound_group_session_with_defaults_test_helper(
1013        &self,
1014        room_id: &RoomId,
1015    ) -> OlmResult<()> {
1016        let (_, session) = self
1017            .inner
1018            .group_session_manager
1019            .create_outbound_group_session(
1020                room_id,
1021                EncryptionSettings::default(),
1022                SenderData::unknown(),
1023            )
1024            .await?;
1025
1026        self.store().save_inbound_group_sessions(&[session]).await?;
1027
1028        Ok(())
1029    }
1030
1031    #[cfg(test)]
1032    #[allow(dead_code)]
1033    pub(crate) async fn create_inbound_session_test_helper(
1034        &self,
1035        room_id: &RoomId,
1036    ) -> OlmResult<InboundGroupSession> {
1037        let (_, session) = self
1038            .inner
1039            .group_session_manager
1040            .create_outbound_group_session(
1041                room_id,
1042                EncryptionSettings::default(),
1043                SenderData::unknown(),
1044            )
1045            .await?;
1046
1047        Ok(session)
1048    }
1049
1050    /// Encrypt a room message for the given room.
1051    ///
1052    /// Beware that a room key needs to be shared before this method
1053    /// can be called using the [`OlmMachine::share_room_key`] method.
1054    ///
1055    /// # Arguments
1056    ///
1057    /// * `room_id` - The id of the room for which the message should be
1058    ///   encrypted.
1059    ///
1060    /// * `content` - The plaintext content of the message that should be
1061    ///   encrypted.
1062    ///
1063    /// # Panics
1064    ///
1065    /// Panics if a room key for the given room wasn't shared beforehand.
1066    pub async fn encrypt_room_event(
1067        &self,
1068        room_id: &RoomId,
1069        content: impl MessageLikeEventContent,
1070    ) -> MegolmResult<RawEncryptionResult> {
1071        let event_type = content.event_type().to_string();
1072        let content = Raw::new(&content)?.cast_unchecked();
1073        self.encrypt_room_event_raw(room_id, &event_type, &content).await
1074    }
1075
1076    /// Encrypt a raw JSON content for the given room.
1077    ///
1078    /// This method is equivalent to the [`OlmMachine::encrypt_room_event()`]
1079    /// method but operates on an arbitrary JSON value instead of strongly-typed
1080    /// event content struct.
1081    ///
1082    /// # Arguments
1083    ///
1084    /// * `room_id` - The id of the room for which the message should be
1085    ///   encrypted.
1086    ///
1087    /// * `content` - The plaintext content of the message that should be
1088    ///   encrypted as a raw JSON value.
1089    ///
1090    /// * `event_type` - The plaintext type of the event.
1091    ///
1092    /// # Panics
1093    ///
1094    /// Panics if a group session for the given room wasn't shared beforehand.
1095    pub async fn encrypt_room_event_raw(
1096        &self,
1097        room_id: &RoomId,
1098        event_type: &str,
1099        content: &Raw<AnyMessageLikeEventContent>,
1100    ) -> MegolmResult<RawEncryptionResult> {
1101        self.inner.group_session_manager.encrypt(room_id, event_type, content).await.map(|result| {
1102            RawEncryptionResult {
1103                content: result.content,
1104                encryption_info: self
1105                    .own_encryption_info(result.algorithm, result.session_id.to_string()),
1106            }
1107        })
1108    }
1109
1110    fn own_encryption_info(
1111        &self,
1112        algorithm: EventEncryptionAlgorithm,
1113        session_id: String,
1114    ) -> EncryptionInfo {
1115        let identity_keys = self.identity_keys();
1116
1117        let algorithm_info = match algorithm {
1118            EventEncryptionAlgorithm::MegolmV1AesSha2 => AlgorithmInfo::MegolmV1AesSha2 {
1119                curve25519_key: identity_keys.curve25519.to_base64(),
1120                sender_claimed_keys: BTreeMap::from([(
1121                    DeviceKeyAlgorithm::Ed25519,
1122                    identity_keys.ed25519.to_base64(),
1123                )]),
1124                session_id: Some(session_id),
1125            },
1126            EventEncryptionAlgorithm::OlmV1Curve25519AesSha2 => {
1127                AlgorithmInfo::OlmV1Curve25519AesSha2 {
1128                    curve25519_public_key_base64: identity_keys.curve25519.to_base64(),
1129                }
1130            }
1131            _ => unreachable!(
1132                "Only MegolmV1AesSha2 and OlmV1Curve25519AesSha2 are supported on this level"
1133            ),
1134        };
1135
1136        EncryptionInfo {
1137            sender: self.inner.user_id.clone(),
1138            sender_device: Some(self.inner.device_id.clone()),
1139            forwarder: None,
1140            algorithm_info,
1141            verification_state: VerificationState::Verified,
1142        }
1143    }
1144
1145    /// Encrypt a state event for the given room.
1146    ///
1147    /// # Arguments
1148    ///
1149    /// * `room_id` - The id of the room for which the event should be
1150    ///   encrypted.
1151    ///
1152    /// * `content` - The plaintext content of the event that should be
1153    ///   encrypted.
1154    ///
1155    /// * `state_key` - The associated state key of the event.
1156    #[cfg(feature = "experimental-encrypted-state-events")]
1157    pub async fn encrypt_state_event<C, K>(
1158        &self,
1159        room_id: &RoomId,
1160        content: C,
1161        state_key: K,
1162    ) -> MegolmResult<Raw<RoomEncryptedEventContent>>
1163    where
1164        C: StateEventContent,
1165        C::StateKey: Borrow<K>,
1166        K: AsRef<str>,
1167    {
1168        let event_type = content.event_type().to_string();
1169        let content = Raw::new(&content)?.cast_unchecked();
1170        self.encrypt_state_event_raw(room_id, &event_type, state_key.as_ref(), &content).await
1171    }
1172
1173    /// Encrypt a state event for the given state event using its raw JSON
1174    /// content and state key.
1175    ///
1176    /// This method is equivalent to [`OlmMachine::encrypt_state_event`]
1177    /// method but operates on an arbitrary JSON value instead of strongly-typed
1178    /// event content struct.
1179    ///
1180    /// # Arguments
1181    ///
1182    /// * `room_id` - The id of the room for which the message should be
1183    ///   encrypted.
1184    ///
1185    /// * `event_type` - The type of the event.
1186    ///
1187    /// * `state_key` - The associated state key of the event.
1188    ///
1189    /// * `content` - The plaintext content of the event that should be
1190    ///   encrypted as a raw JSON value.
1191    #[cfg(feature = "experimental-encrypted-state-events")]
1192    pub async fn encrypt_state_event_raw(
1193        &self,
1194        room_id: &RoomId,
1195        event_type: &str,
1196        state_key: &str,
1197        content: &Raw<AnyStateEventContent>,
1198    ) -> MegolmResult<Raw<RoomEncryptedEventContent>> {
1199        self.inner
1200            .group_session_manager
1201            .encrypt_state(room_id, event_type, state_key, content)
1202            .await
1203    }
1204
1205    /// Forces the currently active room key, which is used to encrypt messages,
1206    /// to be rotated.
1207    ///
1208    /// A new room key will be crated and shared with all the room members the
1209    /// next time a message will be sent. You don't have to call this method,
1210    /// room keys will be rotated automatically when necessary. This method is
1211    /// still useful for debugging purposes.
1212    ///
1213    /// Returns true if a session was invalidated, false if there was no session
1214    /// to invalidate.
1215    pub async fn discard_room_key(&self, room_id: &RoomId) -> StoreResult<bool> {
1216        self.inner.group_session_manager.invalidate_group_session(room_id).await
1217    }
1218
1219    /// Get to-device requests to share a room key with users in a room.
1220    ///
1221    /// # Arguments
1222    ///
1223    /// `room_id` - The room id of the room where the room key will be
1224    /// used.
1225    ///
1226    /// `users` - The list of users that should receive the room key.
1227    ///
1228    /// `settings` - Encryption settings that affect when are room keys rotated
1229    /// and who are they shared with.
1230    ///
1231    /// # Returns
1232    ///
1233    /// List of the to-device requests that need to be sent out to the server
1234    /// and the responses need to be passed back to the state machine with
1235    /// [`mark_request_as_sent`], using the to-device `txn_id` as `request_id`.
1236    ///
1237    /// [`mark_request_as_sent`]: #method.mark_request_as_sent
1238    pub async fn share_room_key(
1239        &self,
1240        room_id: &RoomId,
1241        users: impl Iterator<Item = &UserId>,
1242        encryption_settings: impl Into<EncryptionSettings>,
1243    ) -> OlmResult<Vec<Arc<ToDeviceRequest>>> {
1244        self.inner.group_session_manager.share_room_key(room_id, users, encryption_settings).await
1245    }
1246
1247    /// Encrypts the given content using Olm for each of the given devices.
1248    ///
1249    /// The 1-to-1 session must be established prior to this
1250    /// call by using the [`OlmMachine::get_missing_sessions`] method or the
1251    /// encryption will fail.
1252    ///
1253    /// The caller is responsible for sending the encrypted
1254    /// event to the target device, and should do it ASAP to avoid out-of-order
1255    /// messages.
1256    ///
1257    /// # Returns
1258    /// A list of `ToDeviceRequest` to send out the event, and the list of
1259    /// devices where encryption did not succeed (device excluded or no olm)
1260    #[cfg(feature = "experimental-send-custom-to-device")]
1261    pub async fn encrypt_content_for_devices(
1262        &self,
1263        devices: Vec<DeviceData>,
1264        event_type: &str,
1265        content: &Value,
1266        share_strategy: CollectStrategy,
1267    ) -> OlmResult<(Vec<ToDeviceRequest>, Vec<(DeviceData, WithheldCode)>)> {
1268        let mut changes = Changes::default();
1269
1270        let (allowed_devices, mut blocked_devices) =
1271            split_devices_for_share_strategy(&self.inner.store, devices, share_strategy).await?;
1272
1273        let result = self
1274            .inner
1275            .group_session_manager
1276            .encrypt_content_for_devices(allowed_devices, event_type, content.clone(), &mut changes)
1277            .await;
1278
1279        // Persist any changes we might have collected.
1280        if !changes.is_empty() {
1281            let session_count = changes.sessions.len();
1282
1283            self.inner.store.save_changes(changes).await?;
1284
1285            trace!(
1286                session_count = session_count,
1287                "Stored the changed sessions after encrypting a custom to-device event"
1288            );
1289        }
1290
1291        result.map(|(to_device_requests, mut withheld)| {
1292            withheld.append(&mut blocked_devices);
1293            (to_device_requests, withheld)
1294        })
1295    }
1296    /// Collect the devices belonging to the given user, and send the details of
1297    /// a room key bundle to those devices.
1298    ///
1299    /// Returns a list of to-device requests which must be sent.
1300    pub async fn share_room_key_bundle_data(
1301        &self,
1302        user_id: &UserId,
1303        collect_strategy: &CollectStrategy,
1304        bundle_data: RoomKeyBundleContent,
1305    ) -> OlmResult<Vec<ToDeviceRequest>> {
1306        self.inner
1307            .group_session_manager
1308            .share_room_key_bundle_data(user_id, collect_strategy, bundle_data)
1309            .await
1310    }
1311
1312    /// Receive an unencrypted verification event.
1313    ///
1314    /// This method can be used to pass verification events that are happening
1315    /// in unencrypted rooms to the `OlmMachine`.
1316    ///
1317    /// **Note**: This does not need to be called for encrypted events since
1318    /// those will get passed to the `OlmMachine` during decryption.
1319    #[deprecated(note = "Use OlmMachine::receive_verification_event instead", since = "0.7.0")]
1320    pub async fn receive_unencrypted_verification_event(
1321        &self,
1322        event: &AnyMessageLikeEvent,
1323    ) -> StoreResult<()> {
1324        self.inner.verification_machine.receive_any_event(event).await
1325    }
1326
1327    /// Receive a verification event.
1328    ///
1329    /// The event should be in the decrypted form.
1330    ///
1331    /// **Note**: If the supplied event is an `m.room.message` event with
1332    /// `msgtype: m.key.verification.request`, then the device information for
1333    /// the sending user must be up-to-date before calling this method
1334    /// (otherwise, the request will be ignored). It is hard to guarantee this
1335    /// is the case, but you can maximize your chances by explicitly making a
1336    /// request for this user's device info by calling
1337    /// [`OlmMachine::query_keys_for_users`], sending the request, and
1338    /// processing the response with [`OlmMachine::mark_request_as_sent`].
1339    pub async fn receive_verification_event(&self, event: &AnyMessageLikeEvent) -> StoreResult<()> {
1340        self.inner.verification_machine.receive_any_event(event).await
1341    }
1342
1343    /// Receive and properly handle a decrypted to-device event.
1344    ///
1345    /// # Arguments
1346    ///
1347    /// * `decrypted` - The decrypted event and some associated metadata.
1348    #[instrument(
1349        skip_all,
1350        fields(
1351            sender_key = ?decrypted.result.sender_key,
1352            event_type = decrypted.result.event.event_type(),
1353        ),
1354    )]
1355    async fn handle_decrypted_to_device_event(
1356        &self,
1357        cache: &StoreCache,
1358        decrypted: &mut OlmDecryptionInfo,
1359        changes: &mut Changes,
1360    ) -> OlmResult<()> {
1361        debug!(
1362            sender_device_keys =
1363                ?decrypted.result.event.sender_device_keys().map(|k| (k.curve25519_key(), k.ed25519_key())).unwrap_or((None, None)),
1364            "Received a decrypted to-device event",
1365        );
1366
1367        match &*decrypted.result.event {
1368            AnyDecryptedOlmEvent::RoomKey(e) => {
1369                let session = self.add_room_key(decrypted.result.sender_key, e).await?;
1370                decrypted.inbound_group_session = session;
1371            }
1372            AnyDecryptedOlmEvent::ForwardedRoomKey(e) => {
1373                let session = self
1374                    .inner
1375                    .key_request_machine
1376                    .receive_forwarded_room_key(decrypted.result.sender_key, e)
1377                    .await?;
1378                decrypted.inbound_group_session = session;
1379            }
1380            AnyDecryptedOlmEvent::SecretSend(e) => {
1381                let name = self
1382                    .inner
1383                    .key_request_machine
1384                    .receive_secret_event(cache, decrypted.result.sender_key, e, changes)
1385                    .await?;
1386
1387                // Set the secret name so other consumers of the event know
1388                // what this event is about.
1389                if let Ok(ToDeviceEvents::SecretSend(mut e)) =
1390                    decrypted.result.raw_event.deserialize_as()
1391                {
1392                    e.content.secret_name = name;
1393                    decrypted.result.raw_event = Raw::from_json(to_raw_value(&e)?);
1394                }
1395
1396                if enabled!(tracing::Level::DEBUG) {
1397                    let cross_signing_status = self.cross_signing_status().await;
1398                    let backup_enabled = self.backup_machine().enabled().await;
1399                    debug!(
1400                        ?cross_signing_status,
1401                        backup_enabled, "Status after receiving secret event"
1402                    );
1403                }
1404            }
1405            AnyDecryptedOlmEvent::Dummy(_) => {
1406                debug!("Received an `m.dummy` event");
1407            }
1408            AnyDecryptedOlmEvent::RoomKeyBundle(e) => {
1409                debug!("Received a room key bundle event {:?}", e);
1410                self.receive_room_key_bundle_data(decrypted.result.sender_key, e, changes).await?;
1411            }
1412            AnyDecryptedOlmEvent::Custom(_) => {
1413                warn!("Received an unexpected encrypted to-device event");
1414            }
1415        }
1416
1417        Ok(())
1418    }
1419
1420    async fn handle_verification_event(&self, event: &ToDeviceEvents) {
1421        if let Err(e) = self.inner.verification_machine.receive_any_event(event).await {
1422            error!("Error handling a verification event: {e:?}");
1423        }
1424    }
1425
1426    /// Mark an outgoing to-device requests as sent.
1427    async fn mark_to_device_request_as_sent(&self, request_id: &TransactionId) -> StoreResult<()> {
1428        self.inner.verification_machine.mark_request_as_sent(request_id);
1429        self.inner.key_request_machine.mark_outgoing_request_as_sent(request_id).await?;
1430        self.inner.group_session_manager.mark_request_as_sent(request_id).await?;
1431        self.inner.session_manager.mark_outgoing_request_as_sent(request_id);
1432        Ok(())
1433    }
1434
1435    /// Get a verification object for the given user id with the given flow id.
1436    pub fn get_verification(&self, user_id: &UserId, flow_id: &str) -> Option<Verification> {
1437        self.inner.verification_machine.get_verification(user_id, flow_id)
1438    }
1439
1440    /// Get a verification request object with the given flow id.
1441    pub fn get_verification_request(
1442        &self,
1443        user_id: &UserId,
1444        flow_id: impl AsRef<str>,
1445    ) -> Option<VerificationRequest> {
1446        self.inner.verification_machine.get_request(user_id, flow_id)
1447    }
1448
1449    /// Get all the verification requests of a given user.
1450    pub fn get_verification_requests(&self, user_id: &UserId) -> Vec<VerificationRequest> {
1451        self.inner.verification_machine.get_requests(user_id)
1452    }
1453
1454    /// Given a to-device event that has either been decrypted or arrived in
1455    /// plaintext, handle it.
1456    ///
1457    /// Here, we only process events that are allowed to arrive in plaintext.
1458    async fn handle_to_device_event(&self, changes: &mut Changes, event: &ToDeviceEvents) {
1459        use crate::types::events::ToDeviceEvents::*;
1460
1461        match event {
1462            // These are handled here because we accept them either plaintext or
1463            // encrypted.
1464            //
1465            // Note: this list should match the allowed types in
1466            // check_to_device_is_from_verified_device_or_allowed_type
1467            RoomKeyRequest(e) => self.inner.key_request_machine.receive_incoming_key_request(e),
1468            SecretRequest(e) => self.inner.key_request_machine.receive_incoming_secret_request(e),
1469            RoomKeyWithheld(e) => self.add_withheld_info(changes, e),
1470            KeyVerificationAccept(..)
1471            | KeyVerificationCancel(..)
1472            | KeyVerificationKey(..)
1473            | KeyVerificationMac(..)
1474            | KeyVerificationRequest(..)
1475            | KeyVerificationReady(..)
1476            | KeyVerificationDone(..)
1477            | KeyVerificationStart(..) => {
1478                self.handle_verification_event(event).await;
1479            }
1480
1481            // We don't process custom or dummy events at all
1482            Custom(_) | Dummy(_) => {}
1483
1484            // Encrypted events are handled elsewhere
1485            RoomEncrypted(_) => {}
1486
1487            // These are handled in `handle_decrypted_to_device_event` because we
1488            // only accept them if they arrive encrypted.
1489            SecretSend(_) | RoomKey(_) | ForwardedRoomKey(_) => {}
1490        }
1491    }
1492
1493    fn record_message_id(event: &Raw<AnyToDeviceEvent>) {
1494        use serde::Deserialize;
1495
1496        #[derive(Deserialize)]
1497        struct ContentStub<'a> {
1498            #[serde(borrow, rename = "org.matrix.msgid")]
1499            message_id: Option<&'a str>,
1500        }
1501        #[derive(Deserialize)]
1502        struct ToDeviceStub<'a> {
1503            sender: &'a str,
1504            #[serde(rename = "type")]
1505            event_type: &'a str,
1506            #[serde(borrow)]
1507            content: ContentStub<'a>,
1508        }
1509
1510        if let Ok(event) = event.deserialize_as_unchecked::<ToDeviceStub<'_>>() {
1511            Span::current().record("sender", event.sender);
1512            Span::current().record("event_type", event.event_type);
1513            Span::current().record("message_id", event.content.message_id);
1514        }
1515    }
1516
1517    /// Decrypt the supplied to-device event (if needed, and if we can) and
1518    /// handle it.
1519    ///
1520    /// Return the same event, decrypted if possible and needed.
1521    ///
1522    /// If we can identify that this to-device event came from a dehydrated
1523    /// device, this method does not process it, and returns `None`.
1524    #[instrument(skip_all, fields(sender, event_type, message_id))]
1525    async fn receive_to_device_event(
1526        &self,
1527        transaction: &mut StoreTransaction,
1528        changes: &mut Changes,
1529        raw_event: Raw<AnyToDeviceEvent>,
1530        decryption_settings: &DecryptionSettings,
1531    ) -> Option<ProcessedToDeviceEvent> {
1532        Self::record_message_id(&raw_event);
1533
1534        let event: ToDeviceEvents = match raw_event.deserialize_as() {
1535            Ok(e) => e,
1536            Err(e) => {
1537                // Skip invalid events.
1538                warn!("Received an invalid to-device event: {e}");
1539                return Some(ProcessedToDeviceEvent::Invalid(raw_event));
1540            }
1541        };
1542
1543        debug!("Received a to-device event");
1544
1545        match event {
1546            ToDeviceEvents::RoomEncrypted(e) => {
1547                self.receive_encrypted_to_device_event(
1548                    transaction,
1549                    changes,
1550                    raw_event,
1551                    e,
1552                    decryption_settings,
1553                )
1554                .await
1555            }
1556            e => {
1557                self.handle_to_device_event(changes, &e).await;
1558                Some(ProcessedToDeviceEvent::PlainText(raw_event))
1559            }
1560        }
1561    }
1562
1563    /// Decrypt the supplied encrypted to-device event (if we can) and handle
1564    /// it.
1565    ///
1566    /// Return the same event, decrypted if possible.
1567    ///
1568    /// If we are in strict "exclude insecure devices" mode and the sender
1569    /// device is not verified, and the decrypted event type is not on the
1570    /// allow list, or if this event comes from a dehydrated device, this method
1571    /// does not process it, and returns `None`.
1572    ///
1573    /// (The allow list of types that are processed even if the sender is
1574    /// unverified is: `m.room_key`, `m.room_key.withheld`,
1575    /// `m.room_key_request`, `m.secret.request` and `m.key.verification.*`.)
1576    async fn receive_encrypted_to_device_event(
1577        &self,
1578        transaction: &mut StoreTransaction,
1579        changes: &mut Changes,
1580        mut raw_event: Raw<AnyToDeviceEvent>,
1581        e: ToDeviceEvent<ToDeviceEncryptedEventContent>,
1582        decryption_settings: &DecryptionSettings,
1583    ) -> Option<ProcessedToDeviceEvent> {
1584        let decrypted = match self
1585            .decrypt_to_device_event(transaction, &e, changes, decryption_settings)
1586            .await
1587        {
1588            Ok(decrypted) => decrypted,
1589            Err(DecryptToDeviceError::OlmError(err)) => {
1590                let reason = if let OlmError::UnverifiedSenderDevice = &err {
1591                    ToDeviceUnableToDecryptReason::UnverifiedSenderDevice
1592                } else {
1593                    ToDeviceUnableToDecryptReason::DecryptionFailure
1594                };
1595
1596                if let OlmError::SessionWedged(sender, curve_key) = err
1597                    && let Err(e) =
1598                        self.inner.session_manager.mark_device_as_wedged(&sender, curve_key).await
1599                {
1600                    error!(
1601                        error = ?e,
1602                        "Couldn't mark device to be unwedged",
1603                    );
1604                }
1605
1606                return Some(ProcessedToDeviceEvent::UnableToDecrypt {
1607                    encrypted_event: raw_event,
1608                    utd_info: ToDeviceUnableToDecryptInfo { reason },
1609                });
1610            }
1611            Err(DecryptToDeviceError::FromDehydratedDevice) => return None,
1612        };
1613
1614        // New sessions modify the account so we need to save that
1615        // one as well.
1616        match decrypted.session {
1617            SessionType::New(s) | SessionType::Existing(s) => {
1618                changes.sessions.push(s);
1619            }
1620        }
1621
1622        changes.message_hashes.push(decrypted.message_hash);
1623
1624        if let Some(group_session) = decrypted.inbound_group_session {
1625            changes.inbound_group_sessions.push(group_session);
1626        }
1627
1628        match decrypted.result.raw_event.deserialize_as() {
1629            Ok(event) => {
1630                self.handle_to_device_event(changes, &event).await;
1631
1632                raw_event = event
1633                    .serialize_zeroized()
1634                    .expect("Zeroizing and reserializing our events should always work")
1635                    .cast();
1636            }
1637            Err(e) => {
1638                warn!("Received an invalid encrypted to-device event: {e}");
1639                raw_event = decrypted.result.raw_event;
1640            }
1641        }
1642
1643        Some(ProcessedToDeviceEvent::Decrypted {
1644            raw: raw_event,
1645            encryption_info: decrypted.result.encryption_info,
1646        })
1647    }
1648
1649    /// Return an error if the supplied to-device event was sent from a
1650    /// dehydrated device.
1651    async fn check_to_device_event_is_not_from_dehydrated_device(
1652        &self,
1653        decrypted: &OlmDecryptionInfo,
1654        sender_user_id: &UserId,
1655    ) -> Result<(), DecryptToDeviceError> {
1656        if self.to_device_event_is_from_dehydrated_device(decrypted, sender_user_id).await? {
1657            warn!(
1658                sender = ?sender_user_id,
1659                session = ?decrypted.session,
1660                "Received a to-device event from a dehydrated device. This is unexpected: ignoring event"
1661            );
1662            Err(DecryptToDeviceError::FromDehydratedDevice)
1663        } else {
1664            Ok(())
1665        }
1666    }
1667
1668    /// Decide whether a decrypted to-device event was sent from a dehydrated
1669    /// device.
1670    ///
1671    /// This accepts an [`OlmDecryptionInfo`] because it deals with a decrypted
1672    /// event.
1673    async fn to_device_event_is_from_dehydrated_device(
1674        &self,
1675        decrypted: &OlmDecryptionInfo,
1676        sender_user_id: &UserId,
1677    ) -> OlmResult<bool> {
1678        // Does the to-device message include device info?
1679        if let Some(device_keys) = decrypted.result.event.sender_device_keys() {
1680            // There is no need to check whether the device keys are signed correctly - any
1681            // to-device message that claims to be from a dehydrated device is weird, so we
1682            // will drop it.
1683
1684            // Does the included device info say the device is dehydrated?
1685            if device_keys.dehydrated.unwrap_or(false) {
1686                return Ok(true);
1687            }
1688            // If not, fall through and check our existing list of devices
1689            // below, just in case the sender is sending us incorrect
1690            // information embedded in the to-device message, but we know
1691            // better.
1692        }
1693
1694        // Do we already know about this device?
1695        Ok(self
1696            .store()
1697            .get_device_from_curve_key(sender_user_id, decrypted.result.sender_key)
1698            .await?
1699            .is_some_and(|d| d.is_dehydrated()))
1700    }
1701
1702    /// Handle a to-device and one-time key counts from a sync response.
1703    ///
1704    /// This will decrypt and handle to-device events returning the decrypted
1705    /// versions of them.
1706    ///
1707    /// To decrypt an event from the room timeline, call [`decrypt_room_event`].
1708    ///
1709    /// # Arguments
1710    ///
1711    /// * `sync_changes` - an [`EncryptionSyncChanges`] value, constructed from
1712    ///   a sync response.
1713    ///
1714    /// [`decrypt_room_event`]: #method.decrypt_room_event
1715    ///
1716    /// # Returns
1717    ///
1718    /// A tuple of (decrypted to-device events, updated room keys).
1719    #[instrument(skip_all)]
1720    pub async fn receive_sync_changes(
1721        &self,
1722        sync_changes: EncryptionSyncChanges<'_>,
1723        decryption_settings: &DecryptionSettings,
1724    ) -> OlmResult<(Vec<ProcessedToDeviceEvent>, Vec<RoomKeyInfo>)> {
1725        let mut store_transaction = self.inner.store.transaction().await;
1726
1727        let (events, changes) = self
1728            .preprocess_sync_changes(&mut store_transaction, sync_changes, decryption_settings)
1729            .await?;
1730
1731        // Technically save_changes also does the same work, so if it's slow we could
1732        // refactor this to do it only once.
1733        let room_key_updates: Vec<_> =
1734            changes.inbound_group_sessions.iter().map(RoomKeyInfo::from).collect();
1735
1736        self.store().save_changes(changes).await?;
1737        store_transaction.commit().await?;
1738
1739        Ok((events, room_key_updates))
1740    }
1741
1742    /// Initial processing of the changes specified within a sync response.
1743    ///
1744    /// Returns the to-device events (decrypted where needed and where possible)
1745    /// and the processed set of changes.
1746    ///
1747    /// If any of the to-device events in the supplied changes were sent from
1748    /// dehydrated devices, these are not processed, and are omitted from
1749    /// the returned list, as per MSC3814.
1750    ///
1751    /// If we are in strict "exclude insecure devices" mode and the sender
1752    /// device of any event is not verified, and the decrypted event type is not
1753    /// on the allow list, these events are not processed and are omitted from
1754    /// the returned list.
1755    ///
1756    /// (The allow list of types that are processed even if the sender is
1757    /// unverified is: `m.room_key`, `m.room_key.withheld`,
1758    /// `m.room_key_request`, `m.secret.request` and `m.key.verification.*`.)
1759    pub(crate) async fn preprocess_sync_changes(
1760        &self,
1761        transaction: &mut StoreTransaction,
1762        sync_changes: EncryptionSyncChanges<'_>,
1763        decryption_settings: &DecryptionSettings,
1764    ) -> OlmResult<(Vec<ProcessedToDeviceEvent>, Changes)> {
1765        // Remove verification objects that have expired or are done.
1766        let mut events: Vec<ProcessedToDeviceEvent> = self
1767            .inner
1768            .verification_machine
1769            .garbage_collect()
1770            .iter()
1771            // These are `fake` to device events just serving as local echo
1772            // in order that our own client can react quickly to cancelled transaction.
1773            // Just use PlainText for that.
1774            .map(|e| ProcessedToDeviceEvent::PlainText(e.clone()))
1775            .collect();
1776        // The account is automatically saved by the store transaction created by the
1777        // caller.
1778        let mut changes = Default::default();
1779
1780        {
1781            let account = transaction.account().await?;
1782            account.update_key_counts(
1783                sync_changes.one_time_keys_counts,
1784                sync_changes.unused_fallback_keys,
1785            )
1786        }
1787
1788        if let Err(e) = self
1789            .inner
1790            .identity_manager
1791            .receive_device_changes(
1792                transaction.cache(),
1793                sync_changes.changed_devices.changed.iter().map(|u| u.as_ref()),
1794            )
1795            .await
1796        {
1797            error!(error = ?e, "Error marking a tracked user as changed");
1798        }
1799
1800        for raw_event in sync_changes.to_device_events {
1801            let processed_event = Box::pin(self.receive_to_device_event(
1802                transaction,
1803                &mut changes,
1804                raw_event,
1805                decryption_settings,
1806            ))
1807            .await;
1808
1809            if let Some(processed_event) = processed_event {
1810                events.push(processed_event);
1811            }
1812        }
1813
1814        let changed_sessions = self
1815            .inner
1816            .key_request_machine
1817            .collect_incoming_key_requests(transaction.cache())
1818            .await?;
1819
1820        changes.sessions.extend(changed_sessions);
1821        changes.next_batch_token = sync_changes.next_batch_token;
1822
1823        Ok((events, changes))
1824    }
1825
1826    /// Request a room key from our devices.
1827    ///
1828    /// This method will return a request cancellation and a new key request if
1829    /// the key was already requested, otherwise it will return just the key
1830    /// request.
1831    ///
1832    /// The request cancellation *must* be sent out before the request is sent
1833    /// out, otherwise devices will ignore the key request.
1834    ///
1835    /// # Arguments
1836    ///
1837    /// * `room_id` - The id of the room where the key is used in.
1838    ///
1839    /// * `sender_key` - The curve25519 key of the sender that owns the key.
1840    ///
1841    /// * `session_id` - The id that uniquely identifies the session.
1842    pub async fn request_room_key(
1843        &self,
1844        event: &Raw<EncryptedEvent>,
1845        room_id: &RoomId,
1846    ) -> MegolmResult<(Option<OutgoingRequest>, OutgoingRequest)> {
1847        let event = event.deserialize()?;
1848        self.inner.key_request_machine.request_key(room_id, &event).await
1849    }
1850
1851    /// Find whether an event decrypted via the supplied session is verified,
1852    /// and provide explanation of what is missing/wrong if not.
1853    ///
1854    /// Stores the updated [`SenderData`] for the session in the store
1855    /// if we find an updated value for it.
1856    ///
1857    /// # Arguments
1858    ///
1859    /// * `session` - The inbound Megolm session that was used to decrypt the
1860    ///   event.
1861    /// * `sender` - The `sender` of that event (as claimed by the envelope of
1862    ///   the event).
1863    async fn get_room_event_verification_state(
1864        &self,
1865        session: &InboundGroupSession,
1866        sender: &UserId,
1867    ) -> MegolmResult<(VerificationState, Option<OwnedDeviceId>)> {
1868        let sender_data = self.get_or_update_sender_data(session, sender).await?;
1869
1870        // If the user ID in the sender data doesn't match that in the event envelope,
1871        // this event is not from who it appears to be from.
1872        //
1873        // If `sender_data.user_id()` returns `None`, that means we don't have any
1874        // information about the owner of the session (i.e. we have
1875        // `SenderData::UnknownDevice`); in that case we fall through to the
1876        // logic in `sender_data_to_verification_state` which will pick an appropriate
1877        // `DeviceLinkProblem` for `VerificationLevel::None`.
1878        let (verification_state, device_id) = match sender_data.user_id() {
1879            Some(i) if i != sender => {
1880                (VerificationState::Unverified(VerificationLevel::MismatchedSender), None)
1881            }
1882
1883            Some(_) | None => {
1884                sender_data_to_verification_state(sender_data, session.has_been_imported())
1885            }
1886        };
1887
1888        Ok((verification_state, device_id))
1889    }
1890
1891    /// Get an up-to-date [`SenderData`] for the given session, suitable for
1892    /// determining if messages decrypted using that session are verified.
1893    ///
1894    /// Checks both the stored verification state of the session and a
1895    /// recalculated verification state based on our current knowledge, and
1896    /// returns the more trusted of the two.
1897    ///
1898    /// Stores the updated [`SenderData`] for the session in the store
1899    /// if we find an updated value for it.
1900    ///
1901    /// # Arguments
1902    ///
1903    /// * `session` - The Megolm session that was used to decrypt the event.
1904    /// * `sender` - The claimed sender of that event.
1905    async fn get_or_update_sender_data(
1906        &self,
1907        session: &InboundGroupSession,
1908        sender: &UserId,
1909    ) -> MegolmResult<SenderData> {
1910        let sender_data = if session.sender_data.should_recalculate() {
1911            // The session is not sure of the sender yet. Try to find a matching device
1912            // belonging to the claimed sender of the recently-received event.
1913            //
1914            // It's worth noting that this could in theory result in unintuitive changes,
1915            // like a session which initially appears to belong to Alice turning into a
1916            // session which belongs to Bob [1]. This could mean that a session initially
1917            // successfully decrypts events from Alice, but then stops decrypting those same
1918            // events once we get an update.
1919            //
1920            // That's ok though: if we get good evidence that the session belongs to Bob,
1921            // it's correct to update the session even if we previously had weak
1922            // evidence it belonged to Alice.
1923            //
1924            // [1] For example: maybe Alice and Bob both publish devices with the *same*
1925            // keys (presumably because they are colluding). Initially we think
1926            // the session belongs to Alice, but then we do a device lookup for
1927            // Bob, we find a matching device with a cross-signature, so prefer
1928            // that.
1929            let calculated_sender_data = SenderDataFinder::find_using_curve_key(
1930                self.store(),
1931                session.sender_key(),
1932                sender,
1933                session,
1934            )
1935            .await?;
1936
1937            // Is the newly-calculated sender data more trusted?
1938            if calculated_sender_data.compare_trust_level(&session.sender_data).is_gt() {
1939                // Yes - save it to the store
1940                let mut new_session = session.clone();
1941                new_session.sender_data = calculated_sender_data.clone();
1942                self.store().save_inbound_group_sessions(&[new_session]).await?;
1943
1944                // and use it now.
1945                calculated_sender_data
1946            } else {
1947                // No - use the existing data.
1948                session.sender_data.clone()
1949            }
1950        } else {
1951            session.sender_data.clone()
1952        };
1953
1954        Ok(sender_data)
1955    }
1956
1957    /// Request missing local secrets from our devices (cross signing private
1958    /// keys, megolm backup). This will ask the sdk to create outgoing
1959    /// request to get the missing secrets.
1960    ///
1961    /// The requests will be processed as soon as `outgoing_requests()` is
1962    /// called to process them.
1963    ///
1964    /// # Returns
1965    ///
1966    /// A bool result saying if actual secrets were missing and have been
1967    /// requested
1968    ///
1969    /// # Examples
1970    //
1971    /// ```
1972    /// # async {
1973    /// # use matrix_sdk_crypto::OlmMachine;
1974    /// # let machine: OlmMachine = unimplemented!();
1975    /// if machine.query_missing_secrets_from_other_sessions().await.unwrap() {
1976    ///     let to_send = machine.outgoing_requests().await.unwrap();
1977    ///     // send the to device requests
1978    /// };
1979    /// # anyhow::Ok(()) };
1980    /// ```
1981    pub async fn query_missing_secrets_from_other_sessions(&self) -> StoreResult<bool> {
1982        let identity = self.inner.user_identity.lock().await;
1983        let mut secrets = identity.get_missing_secrets().await;
1984
1985        if self.store().load_backup_keys().await?.decryption_key.is_none() {
1986            secrets.push(SecretName::RecoveryKey);
1987        }
1988
1989        if secrets.is_empty() {
1990            debug!("No missing requests to query");
1991            return Ok(false);
1992        }
1993
1994        let secret_requests = GossipMachine::request_missing_secrets(self.user_id(), secrets);
1995
1996        // Check if there are already in-flight requests for these secrets?
1997        let unsent_request = self.store().get_unsent_secret_requests().await?;
1998        let not_yet_requested = secret_requests
1999            .into_iter()
2000            .filter(|request| !unsent_request.iter().any(|unsent| unsent.info == request.info))
2001            .collect_vec();
2002
2003        if not_yet_requested.is_empty() {
2004            debug!("The missing secrets have already been requested");
2005            Ok(false)
2006        } else {
2007            debug!("Requesting missing secrets");
2008
2009            let changes = Changes { key_requests: not_yet_requested, ..Default::default() };
2010
2011            self.store().save_changes(changes).await?;
2012            Ok(true)
2013        }
2014    }
2015
2016    /// Get some metadata pertaining to a given group session.
2017    ///
2018    /// This includes the session owner's Matrix user ID, their device ID, info
2019    /// regarding the cryptographic algorithm and whether the session, and by
2020    /// extension the events decrypted by the session, are trusted.
2021    async fn get_encryption_info(
2022        &self,
2023        session: &InboundGroupSession,
2024        sender: &UserId,
2025    ) -> MegolmResult<Arc<EncryptionInfo>> {
2026        let (verification_state, device_id) =
2027            self.get_room_event_verification_state(session, sender).await?;
2028
2029        Ok(Arc::new(EncryptionInfo {
2030            sender: sender.to_owned(),
2031            sender_device: device_id,
2032            forwarder: session.forwarder_data.as_ref().and_then(|data| {
2033                // Per the comment on `KnownSenderData::device_id`, we should never encounter a
2034                // `None` value here, but must still deal with an `Optional` for backwards
2035                // compatibility. The approach below allows us to avoid unwrapping.
2036                data.device_id().map(|device_id| ForwarderInfo {
2037                    device_id: device_id.to_owned(),
2038                    user_id: data.user_id().to_owned(),
2039                })
2040            }),
2041            algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
2042                curve25519_key: session.sender_key().to_base64(),
2043                sender_claimed_keys: session
2044                    .signing_keys()
2045                    .iter()
2046                    .map(|(k, v)| (k.to_owned(), v.to_base64()))
2047                    .collect(),
2048                session_id: Some(session.session_id().to_owned()),
2049            },
2050            verification_state,
2051        }))
2052    }
2053
2054    async fn decrypt_megolm_events(
2055        &self,
2056        room_id: &RoomId,
2057        event: &EncryptedEvent,
2058        content: &SupportedEventEncryptionSchemes<'_>,
2059        decryption_settings: &DecryptionSettings,
2060    ) -> MegolmResult<(JsonObject, Arc<EncryptionInfo>)> {
2061        let session =
2062            self.get_inbound_group_session_or_error(room_id, content.session_id()).await?;
2063
2064        // This function is only ever called by decrypt_room_event, so
2065        // room_id, sender, algorithm and session_id are recorded already
2066        //
2067        // While we already record the sender key in some cases from the event, the
2068        // sender key in the event is deprecated, so let's record it now.
2069        Span::current().record("sender_key", debug(session.sender_key()));
2070
2071        let result = session.decrypt(event).await;
2072        match result {
2073            Ok((decrypted_event, _)) => {
2074                let encryption_info = self.get_encryption_info(&session, &event.sender).await?;
2075
2076                self.check_sender_trust_requirement(
2077                    &session,
2078                    &encryption_info,
2079                    &decryption_settings.sender_device_trust_requirement,
2080                )?;
2081
2082                Ok((decrypted_event, encryption_info))
2083            }
2084            Err(error) => Err(
2085                if let MegolmError::Decryption(DecryptionError::UnknownMessageIndex(_, _)) = error {
2086                    let withheld_code = self
2087                        .inner
2088                        .store
2089                        .get_withheld_info(room_id, content.session_id())
2090                        .await?
2091                        .map(|e| e.content.withheld_code());
2092
2093                    if withheld_code.is_some() {
2094                        // Partially withheld, report with a withheld code if we have one.
2095                        MegolmError::MissingRoomKey(withheld_code)
2096                    } else {
2097                        error
2098                    }
2099                } else {
2100                    error
2101                },
2102            ),
2103        }
2104    }
2105
2106    /// Check that a Megolm event satisfies the sender trust
2107    /// requirement from the decryption settings.
2108    ///
2109    /// If the requirement is not satisfied, returns
2110    /// [`MegolmError::SenderIdentityNotTrusted`].
2111    fn check_sender_trust_requirement(
2112        &self,
2113        session: &InboundGroupSession,
2114        encryption_info: &EncryptionInfo,
2115        trust_requirement: &TrustRequirement,
2116    ) -> MegolmResult<()> {
2117        trace!(
2118            verification_state = ?encryption_info.verification_state,
2119            ?trust_requirement, "check_sender_trust_requirement",
2120        );
2121
2122        // VerificationState::Verified is acceptable for all TrustRequirement levels, so
2123        // let's get that out of the way
2124        let verification_level = match &encryption_info.verification_state {
2125            VerificationState::Verified => return Ok(()),
2126            VerificationState::Unverified(verification_level) => verification_level,
2127        };
2128
2129        let ok = match trust_requirement {
2130            TrustRequirement::Untrusted => true,
2131
2132            TrustRequirement::CrossSignedOrLegacy => {
2133                // `VerificationLevel::UnsignedDevice` and `VerificationLevel::None` correspond
2134                // to `SenderData::DeviceInfo` and `SenderData::UnknownDevice`
2135                // respectively, and those cases may be acceptable if the reason
2136                // for the lack of data is that the sessions were established
2137                // before we started collecting SenderData.
2138                let legacy_session = match session.sender_data {
2139                    SenderData::DeviceInfo { legacy_session, .. } => legacy_session,
2140                    SenderData::UnknownDevice { legacy_session, .. } => legacy_session,
2141                    _ => false,
2142                };
2143
2144                // In the CrossSignedOrLegacy case the following rules apply:
2145                //
2146                // 1. Identities we have not yet verified can be decrypted regardless of the
2147                //    legacy state of the session.
2148                // 2. Devices that aren't signed by the owning identity of the device can only
2149                //    be decrypted if it's a legacy session.
2150                // 3. If we have no information about the device, we should only decrypt if it's
2151                //    a legacy session.
2152                // 4. Anything else, should throw an error.
2153                match (verification_level, legacy_session) {
2154                    // Case 1
2155                    (VerificationLevel::UnverifiedIdentity, _) => true,
2156
2157                    // Case 2
2158                    (VerificationLevel::UnsignedDevice, true) => true,
2159
2160                    // Case 3
2161                    (VerificationLevel::None(_), true) => true,
2162
2163                    // Case 4
2164                    (VerificationLevel::VerificationViolation, _)
2165                    | (VerificationLevel::MismatchedSender, _)
2166                    | (VerificationLevel::UnsignedDevice, false)
2167                    | (VerificationLevel::None(_), false) => false,
2168                }
2169            }
2170
2171            // If cross-signing of identities is required, the only acceptable unverified case
2172            // is when the identity is signed but not yet verified by us.
2173            TrustRequirement::CrossSigned => match verification_level {
2174                VerificationLevel::UnverifiedIdentity => true,
2175
2176                VerificationLevel::VerificationViolation
2177                | VerificationLevel::MismatchedSender
2178                | VerificationLevel::UnsignedDevice
2179                | VerificationLevel::None(_) => false,
2180            },
2181        };
2182
2183        if ok {
2184            Ok(())
2185        } else {
2186            Err(MegolmError::SenderIdentityNotTrusted(verification_level.clone()))
2187        }
2188    }
2189
2190    /// Attempt to retrieve an inbound group session from the store.
2191    ///
2192    /// If the session is not found, checks for withheld reports, and returns a
2193    /// [`MegolmError::MissingRoomKey`] error.
2194    async fn get_inbound_group_session_or_error(
2195        &self,
2196        room_id: &RoomId,
2197        session_id: &str,
2198    ) -> MegolmResult<InboundGroupSession> {
2199        match self.store().get_inbound_group_session(room_id, session_id).await? {
2200            Some(session) => Ok(session),
2201            None => {
2202                let withheld_code = self
2203                    .inner
2204                    .store
2205                    .get_withheld_info(room_id, session_id)
2206                    .await?
2207                    .map(|e| e.content.withheld_code());
2208                Err(MegolmError::MissingRoomKey(withheld_code))
2209            }
2210        }
2211    }
2212
2213    /// Attempt to decrypt an event from a room timeline, returning information
2214    /// on the failure if it fails.
2215    ///
2216    /// # Arguments
2217    ///
2218    /// * `event` - The event that should be decrypted.
2219    ///
2220    /// * `room_id` - The ID of the room where the event was sent to.
2221    ///
2222    /// # Returns
2223    ///
2224    /// The decrypted event, if it was successfully decrypted. Otherwise,
2225    /// information on the failure, unless the failure was due to an
2226    /// internal error, in which case, an `Err` result.
2227    pub async fn try_decrypt_room_event(
2228        &self,
2229        raw_event: &Raw<EncryptedEvent>,
2230        room_id: &RoomId,
2231        decryption_settings: &DecryptionSettings,
2232    ) -> Result<RoomEventDecryptionResult, CryptoStoreError> {
2233        match self.decrypt_room_event_inner(raw_event, room_id, true, decryption_settings).await {
2234            Ok(decrypted) => Ok(RoomEventDecryptionResult::Decrypted(decrypted)),
2235            Err(err) => Ok(RoomEventDecryptionResult::UnableToDecrypt(megolm_error_to_utd_info(
2236                raw_event, err,
2237            )?)),
2238        }
2239    }
2240
2241    /// Decrypt an event from a room timeline.
2242    ///
2243    /// # Arguments
2244    ///
2245    /// * `event` - The event that should be decrypted.
2246    ///
2247    /// * `room_id` - The ID of the room where the event was sent to.
2248    pub async fn decrypt_room_event(
2249        &self,
2250        event: &Raw<EncryptedEvent>,
2251        room_id: &RoomId,
2252        decryption_settings: &DecryptionSettings,
2253    ) -> MegolmResult<DecryptedRoomEvent> {
2254        self.decrypt_room_event_inner(event, room_id, true, decryption_settings).await
2255    }
2256
2257    #[instrument(name = "decrypt_room_event", skip_all, fields(?room_id, event_id, origin_server_ts, sender, algorithm, session_id, message_index, sender_key))]
2258    async fn decrypt_room_event_inner(
2259        &self,
2260        event: &Raw<EncryptedEvent>,
2261        room_id: &RoomId,
2262        decrypt_unsigned: bool,
2263        decryption_settings: &DecryptionSettings,
2264    ) -> MegolmResult<DecryptedRoomEvent> {
2265        let _timer = timer!(tracing::Level::TRACE, "_method");
2266
2267        let event = event.deserialize()?;
2268
2269        Span::current()
2270            .record("sender", debug(&event.sender))
2271            .record("event_id", debug(&event.event_id))
2272            .record(
2273                "origin_server_ts",
2274                timestamp_to_iso8601(event.origin_server_ts)
2275                    .unwrap_or_else(|| "<out of range>".to_owned()),
2276            )
2277            .record("algorithm", debug(event.content.algorithm()));
2278
2279        let content: SupportedEventEncryptionSchemes<'_> = match &event.content.scheme {
2280            RoomEventEncryptionScheme::MegolmV1AesSha2(c) => {
2281                Span::current().record("sender_key", debug(c.sender_key));
2282                c.into()
2283            }
2284            #[cfg(feature = "experimental-algorithms")]
2285            RoomEventEncryptionScheme::MegolmV2AesSha2(c) => c.into(),
2286            RoomEventEncryptionScheme::Unknown(_) => {
2287                warn!("Received an encrypted room event with an unsupported algorithm");
2288                return Err(EventError::UnsupportedAlgorithm.into());
2289            }
2290        };
2291
2292        Span::current().record("session_id", content.session_id());
2293        Span::current().record("message_index", content.message_index());
2294
2295        let result =
2296            self.decrypt_megolm_events(room_id, &event, &content, decryption_settings).await;
2297
2298        if let Err(e) = &result {
2299            #[cfg(feature = "automatic-room-key-forwarding")]
2300            match e {
2301                // Optimisation should we request if we received a withheld code?
2302                // Maybe for some code there is no point
2303                MegolmError::MissingRoomKey(_)
2304                | MegolmError::Decryption(DecryptionError::UnknownMessageIndex(_, _)) => {
2305                    self.inner
2306                        .key_request_machine
2307                        .create_outgoing_key_request(room_id, &event)
2308                        .await?;
2309                }
2310                _ => {}
2311            }
2312
2313            warn!("Failed to decrypt a room event: {e}");
2314        }
2315
2316        let (mut decrypted_event, encryption_info) = result?;
2317
2318        let mut unsigned_encryption_info = None;
2319        if decrypt_unsigned {
2320            // Try to decrypt encrypted unsigned events.
2321            unsigned_encryption_info = self
2322                .decrypt_unsigned_events(&mut decrypted_event, room_id, decryption_settings)
2323                .await;
2324        }
2325
2326        let decrypted_event =
2327            serde_json::from_value::<Raw<AnyTimelineEvent>>(decrypted_event.into())?;
2328
2329        #[cfg(feature = "experimental-encrypted-state-events")]
2330        self.verify_packed_state_key(&event, &decrypted_event)?;
2331
2332        Ok(DecryptedRoomEvent { event: decrypted_event, encryption_info, unsigned_encryption_info })
2333    }
2334
2335    /// If the passed event is a state event, verify its outer packed state key
2336    /// matches the inner state key once unpacked.
2337    ///
2338    /// * `original` - The original encrypted event received over the wire.
2339    /// * `decrypted` - The decrypted event.
2340    ///
2341    /// # Errors
2342    ///
2343    /// Returns an error if any of the following are true:
2344    ///
2345    /// * The original event's state key failed to unpack;
2346    /// * The decrypted event could not be deserialised;
2347    /// * The unpacked event type does not match the type of the decrypted
2348    ///   event;
2349    /// * The unpacked event state key does not match the state key of the
2350    ///   decrypted event.
2351    #[cfg(feature = "experimental-encrypted-state-events")]
2352    fn verify_packed_state_key(
2353        &self,
2354        original: &EncryptedEvent,
2355        decrypted: &Raw<AnyTimelineEvent>,
2356    ) -> MegolmResult<()> {
2357        use serde::Deserialize;
2358
2359        // Helper for deserializing.
2360        #[derive(Deserialize)]
2361        struct PayloadDeserializationHelper {
2362            state_key: Option<String>,
2363            #[serde(rename = "type")]
2364            event_type: String,
2365        }
2366
2367        // Deserialize the decrypted event.
2368        let PayloadDeserializationHelper {
2369            state_key: inner_state_key,
2370            event_type: inner_event_type,
2371        } = decrypted
2372            .deserialize_as_unchecked()
2373            .map_err(|_| MegolmError::StateKeyVerificationFailed)?;
2374
2375        // Ensure we have a state key on the outer event iff there is one in the inner.
2376        let (raw_state_key, inner_state_key) = match (&original.state_key, &inner_state_key) {
2377            (Some(raw_state_key), Some(inner_state_key)) => (raw_state_key, inner_state_key),
2378            (None, None) => return Ok(()),
2379            _ => return Err(MegolmError::StateKeyVerificationFailed),
2380        };
2381
2382        // Unpack event type and state key from the raw state key.
2383        let (outer_event_type, outer_state_key) =
2384            raw_state_key.split_once(":").ok_or(MegolmError::StateKeyVerificationFailed)?;
2385
2386        // Check event types match, discard if not.
2387        if outer_event_type != inner_event_type {
2388            return Err(MegolmError::StateKeyVerificationFailed);
2389        }
2390
2391        // Check state keys match, discard if not.
2392        if outer_state_key != inner_state_key {
2393            return Err(MegolmError::StateKeyVerificationFailed);
2394        }
2395        Ok(())
2396    }
2397
2398    /// Try to decrypt the events bundled in the `unsigned` object of the given
2399    /// event.
2400    ///
2401    /// # Arguments
2402    ///
2403    /// * `main_event` - The event that may contain bundled encrypted events in
2404    ///   its `unsigned` object.
2405    ///
2406    /// * `room_id` - The ID of the room where the event was sent to.
2407    async fn decrypt_unsigned_events(
2408        &self,
2409        main_event: &mut JsonObject,
2410        room_id: &RoomId,
2411        decryption_settings: &DecryptionSettings,
2412    ) -> Option<BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>> {
2413        let unsigned = main_event.get_mut("unsigned")?.as_object_mut()?;
2414        let mut unsigned_encryption_info: Option<
2415            BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>,
2416        > = None;
2417
2418        // Search for an encrypted event in `m.replace`, an edit.
2419        let location = UnsignedEventLocation::RelationsReplace;
2420        let replace = location.find_mut(unsigned);
2421        if let Some(decryption_result) =
2422            self.decrypt_unsigned_event(replace, room_id, decryption_settings).await
2423        {
2424            unsigned_encryption_info
2425                .get_or_insert_with(Default::default)
2426                .insert(location, decryption_result);
2427        }
2428
2429        // Search for an encrypted event in `latest_event` in `m.thread`, the
2430        // latest event of a thread.
2431        let location = UnsignedEventLocation::RelationsThreadLatestEvent;
2432        let thread_latest_event = location.find_mut(unsigned);
2433        if let Some(decryption_result) =
2434            self.decrypt_unsigned_event(thread_latest_event, room_id, decryption_settings).await
2435        {
2436            unsigned_encryption_info
2437                .get_or_insert_with(Default::default)
2438                .insert(location, decryption_result);
2439        }
2440
2441        unsigned_encryption_info
2442    }
2443
2444    /// Try to decrypt the given bundled event.
2445    ///
2446    /// # Arguments
2447    ///
2448    /// * `event` - The bundled event that may be encrypted
2449    ///
2450    /// * `room_id` - The ID of the room where the event was sent to.
2451    fn decrypt_unsigned_event<'a>(
2452        &'a self,
2453        event: Option<&'a mut Value>,
2454        room_id: &'a RoomId,
2455        decryption_settings: &'a DecryptionSettings,
2456    ) -> BoxFuture<'a, Option<UnsignedDecryptionResult>> {
2457        Box::pin(async move {
2458            let event = event?;
2459
2460            let is_encrypted = event
2461                .get("type")
2462                .and_then(|type_| type_.as_str())
2463                .is_some_and(|s| s == "m.room.encrypted");
2464            if !is_encrypted {
2465                return None;
2466            }
2467
2468            let raw_event = serde_json::from_value(event.clone()).ok()?;
2469            match self
2470                .decrypt_room_event_inner(&raw_event, room_id, false, decryption_settings)
2471                .await
2472            {
2473                Ok(decrypted_event) => {
2474                    // Replace the encrypted event.
2475                    *event = serde_json::to_value(decrypted_event.event).ok()?;
2476                    Some(UnsignedDecryptionResult::Decrypted(decrypted_event.encryption_info))
2477                }
2478                Err(err) => {
2479                    // For now, we throw away crypto store errors and just treat the unsigned event
2480                    // as unencrypted. Crypto store errors represent problems with the application
2481                    // rather than normal UTD errors, so they should probably be propagated
2482                    // rather than swallowed.
2483                    let utd_info = megolm_error_to_utd_info(&raw_event, err).ok()?;
2484                    Some(UnsignedDecryptionResult::UnableToDecrypt(utd_info))
2485                }
2486            }
2487        })
2488    }
2489
2490    /// Check if we have the room key for the given event in the store.
2491    ///
2492    /// # Arguments
2493    ///
2494    /// * `event` - The event to get information for.
2495    /// * `room_id` - The ID of the room where the event was sent to.
2496    pub async fn is_room_key_available(
2497        &self,
2498        event: &Raw<EncryptedEvent>,
2499        room_id: &RoomId,
2500    ) -> Result<bool, CryptoStoreError> {
2501        let event = event.deserialize()?;
2502
2503        let (session_id, message_index) = match &event.content.scheme {
2504            RoomEventEncryptionScheme::MegolmV1AesSha2(c) => {
2505                (&c.session_id, c.ciphertext.message_index())
2506            }
2507            #[cfg(feature = "experimental-algorithms")]
2508            RoomEventEncryptionScheme::MegolmV2AesSha2(c) => {
2509                (&c.session_id, c.ciphertext.message_index())
2510            }
2511            RoomEventEncryptionScheme::Unknown(_) => {
2512                // We don't support this encryption algorithm, so clearly don't have its key.
2513                return Ok(false);
2514            }
2515        };
2516
2517        // Check that we have the session in the store, and that its first known index
2518        // predates the index of our message.
2519        Ok(self
2520            .store()
2521            .get_inbound_group_session(room_id, session_id)
2522            .await?
2523            .filter(|s| s.first_known_index() <= message_index)
2524            .is_some())
2525    }
2526
2527    /// Get encryption info for a decrypted timeline event.
2528    ///
2529    /// This recalculates the [`EncryptionInfo`] data that is returned by
2530    /// [`OlmMachine::decrypt_room_event`], based on the current
2531    /// verification status of the sender, etc.
2532    ///
2533    /// Returns an error for an unencrypted event.
2534    ///
2535    /// # Arguments
2536    ///
2537    /// * `event` - The event to get information for.
2538    /// * `room_id` - The ID of the room where the event was sent to.
2539    #[instrument(skip(self, event), fields(event_id, sender, session_id))]
2540    pub async fn get_room_event_encryption_info(
2541        &self,
2542        event: &Raw<EncryptedEvent>,
2543        room_id: &RoomId,
2544    ) -> MegolmResult<Arc<EncryptionInfo>> {
2545        let event = event.deserialize()?;
2546
2547        let content: SupportedEventEncryptionSchemes<'_> = match &event.content.scheme {
2548            RoomEventEncryptionScheme::MegolmV1AesSha2(c) => c.into(),
2549            #[cfg(feature = "experimental-algorithms")]
2550            RoomEventEncryptionScheme::MegolmV2AesSha2(c) => c.into(),
2551            RoomEventEncryptionScheme::Unknown(_) => {
2552                return Err(EventError::UnsupportedAlgorithm.into());
2553            }
2554        };
2555
2556        Span::current()
2557            .record("sender", debug(&event.sender))
2558            .record("event_id", debug(&event.event_id))
2559            .record("session_id", content.session_id());
2560
2561        self.get_session_encryption_info(room_id, content.session_id(), &event.sender).await
2562    }
2563
2564    /// Get encryption info for an event decrypted with a megolm session.
2565    ///
2566    /// This recalculates the [`EncryptionInfo`] data that is returned by
2567    /// [`OlmMachine::decrypt_room_event`], based on the current
2568    /// verification status of the sender, etc.
2569    ///
2570    /// Returns an error if the session can't be found.
2571    ///
2572    /// # Arguments
2573    ///
2574    /// * `room_id` - The ID of the room where the session is being used.
2575    /// * `session_id` - The ID of the session to get information for.
2576    /// * `sender` - The (claimed) sender of the event where the session was
2577    ///   used.
2578    pub async fn get_session_encryption_info(
2579        &self,
2580        room_id: &RoomId,
2581        session_id: &str,
2582        sender: &UserId,
2583    ) -> MegolmResult<Arc<EncryptionInfo>> {
2584        let session = self.get_inbound_group_session_or_error(room_id, session_id).await?;
2585        self.get_encryption_info(&session, sender).await
2586    }
2587
2588    /// Update the list of tracked users.
2589    ///
2590    /// The OlmMachine maintains a list of users whose devices we are keeping
2591    /// track of: these are known as "tracked users". These must be users
2592    /// that we share a room with, so that the server sends us updates for
2593    /// their device lists.
2594    ///
2595    /// # Arguments
2596    ///
2597    /// * `users` - An iterator over user ids that should be added to the list
2598    ///   of tracked users
2599    ///
2600    /// Any users that hadn't been seen before will be flagged for a key query
2601    /// immediately, and whenever [`OlmMachine::receive_sync_changes()`]
2602    /// receives a "changed" notification for that user in the future.
2603    ///
2604    /// Users that were already in the list are unaffected.
2605    pub async fn update_tracked_users(
2606        &self,
2607        users: impl IntoIterator<Item = &UserId>,
2608    ) -> StoreResult<()> {
2609        self.inner.identity_manager.update_tracked_users(users).await
2610    }
2611
2612    /// Mark all tracked users as dirty.
2613    ///
2614    /// All users *whose device lists we are tracking* are flagged as needing a
2615    /// key query. Users whose devices we are not tracking are ignored.
2616    pub async fn mark_all_tracked_users_as_dirty(&self) -> StoreResult<()> {
2617        self.inner
2618            .identity_manager
2619            .mark_all_tracked_users_as_dirty(self.inner.store.cache().await?)
2620            .await
2621    }
2622
2623    async fn wait_if_user_pending(
2624        &self,
2625        user_id: &UserId,
2626        timeout: Option<Duration>,
2627    ) -> StoreResult<()> {
2628        if let Some(timeout) = timeout {
2629            let cache = self.store().cache().await?;
2630            self.inner
2631                .identity_manager
2632                .key_query_manager
2633                .wait_if_user_key_query_pending(cache, timeout, user_id)
2634                .await?;
2635        }
2636        Ok(())
2637    }
2638
2639    /// Get a specific device of a user.
2640    ///
2641    /// # Arguments
2642    ///
2643    /// * `user_id` - The unique id of the user that the device belongs to.
2644    ///
2645    /// * `device_id` - The unique id of the device.
2646    ///
2647    /// * `timeout` - The amount of time we should wait before returning if the
2648    /// user's device list has been marked as stale. **Note**, this assumes that
2649    /// the requests from [`OlmMachine::outgoing_requests`] are being
2650    /// processed and sent out.
2651    ///
2652    /// Returns a `Device` if one is found and the crypto store didn't throw an
2653    /// error.
2654    ///
2655    /// # Examples
2656    ///
2657    /// ```
2658    /// # use matrix_sdk_crypto::OlmMachine;
2659    /// # use ruma::{device_id, owned_user_id};
2660    /// # let alice = owned_user_id!("@alice:example.org");
2661    /// # futures_executor::block_on(async {
2662    /// # let machine = OlmMachine::new(&alice, device_id!("DEVICEID")).await;
2663    /// let device = machine.get_device(&alice, device_id!("DEVICEID"), None).await;
2664    ///
2665    /// println!("{:?}", device);
2666    /// # });
2667    /// ```
2668    #[instrument(skip(self))]
2669    pub async fn get_device(
2670        &self,
2671        user_id: &UserId,
2672        device_id: &DeviceId,
2673        timeout: Option<Duration>,
2674    ) -> StoreResult<Option<Device>> {
2675        self.wait_if_user_pending(user_id, timeout).await?;
2676        self.store().get_device(user_id, device_id).await
2677    }
2678
2679    /// Get the cross signing user identity of a user.
2680    ///
2681    /// # Arguments
2682    ///
2683    /// * `user_id` - The unique id of the user that the identity belongs to
2684    ///
2685    /// * `timeout` - The amount of time we should wait before returning if the
2686    /// user's device list has been marked as stale. **Note**, this assumes that
2687    /// the requests from [`OlmMachine::outgoing_requests`] are being
2688    /// processed and sent out.
2689    ///
2690    /// Returns a [`UserIdentity`] enum if one is found and the crypto store
2691    /// didn't throw an error.
2692    #[instrument(skip(self))]
2693    pub async fn get_identity(
2694        &self,
2695        user_id: &UserId,
2696        timeout: Option<Duration>,
2697    ) -> StoreResult<Option<UserIdentity>> {
2698        self.wait_if_user_pending(user_id, timeout).await?;
2699        self.store().get_identity(user_id).await
2700    }
2701
2702    /// Get a map holding all the devices of an user.
2703    ///
2704    /// # Arguments
2705    ///
2706    /// * `user_id` - The unique id of the user that the devices belong to.
2707    ///
2708    /// * `timeout` - The amount of time we should wait before returning if the
2709    /// user's device list has been marked as stale. **Note**, this assumes that
2710    /// the requests from [`OlmMachine::outgoing_requests`] are being
2711    /// processed and sent out.
2712    ///
2713    /// # Examples
2714    ///
2715    /// ```
2716    /// # use matrix_sdk_crypto::OlmMachine;
2717    /// # use ruma::{device_id, owned_user_id};
2718    /// # let alice = owned_user_id!("@alice:example.org");
2719    /// # futures_executor::block_on(async {
2720    /// # let machine = OlmMachine::new(&alice, device_id!("DEVICEID")).await;
2721    /// let devices = machine.get_user_devices(&alice, None).await.unwrap();
2722    ///
2723    /// for device in devices.devices() {
2724    ///     println!("{:?}", device);
2725    /// }
2726    /// # });
2727    /// ```
2728    #[instrument(skip(self))]
2729    pub async fn get_user_devices(
2730        &self,
2731        user_id: &UserId,
2732        timeout: Option<Duration>,
2733    ) -> StoreResult<UserDevices> {
2734        self.wait_if_user_pending(user_id, timeout).await?;
2735        self.store().get_user_devices(user_id).await
2736    }
2737
2738    /// Get the status of the private cross signing keys.
2739    ///
2740    /// This can be used to check which private cross signing keys we have
2741    /// stored locally.
2742    pub async fn cross_signing_status(&self) -> CrossSigningStatus {
2743        self.inner.user_identity.lock().await.status().await
2744    }
2745
2746    /// Export all the private cross signing keys we have.
2747    ///
2748    /// The export will contain the seed for the ed25519 keys as a unpadded
2749    /// base64 encoded string.
2750    ///
2751    /// This method returns `None` if we don't have any private cross signing
2752    /// keys.
2753    pub async fn export_cross_signing_keys(&self) -> StoreResult<Option<CrossSigningKeyExport>> {
2754        let master_key = self.store().export_secret(&SecretName::CrossSigningMasterKey).await?;
2755        let self_signing_key =
2756            self.store().export_secret(&SecretName::CrossSigningSelfSigningKey).await?;
2757        let user_signing_key =
2758            self.store().export_secret(&SecretName::CrossSigningUserSigningKey).await?;
2759
2760        Ok(if master_key.is_none() && self_signing_key.is_none() && user_signing_key.is_none() {
2761            None
2762        } else {
2763            Some(CrossSigningKeyExport { master_key, self_signing_key, user_signing_key })
2764        })
2765    }
2766
2767    /// Import our private cross signing keys.
2768    ///
2769    /// The export needs to contain the seed for the ed25519 keys as an unpadded
2770    /// base64 encoded string.
2771    pub async fn import_cross_signing_keys(
2772        &self,
2773        export: CrossSigningKeyExport,
2774    ) -> Result<CrossSigningStatus, SecretImportError> {
2775        self.store().import_cross_signing_keys(export).await
2776    }
2777
2778    async fn sign_with_master_key(
2779        &self,
2780        message: &str,
2781    ) -> Result<(OwnedDeviceKeyId, Ed25519Signature), SignatureError> {
2782        let identity = &*self.inner.user_identity.lock().await;
2783        let key_id = identity.master_key_id().await.ok_or(SignatureError::MissingSigningKey)?;
2784
2785        let signature = identity.sign(message).await?;
2786
2787        Ok((key_id, signature))
2788    }
2789
2790    /// Sign the given message using our device key and if available cross
2791    /// signing master key.
2792    ///
2793    /// Presently, this should only be used for signing the server-side room
2794    /// key backups.
2795    pub async fn sign(&self, message: &str) -> Result<Signatures, CryptoStoreError> {
2796        let mut signatures = Signatures::new();
2797
2798        {
2799            let cache = self.inner.store.cache().await?;
2800            let account = cache.account().await?;
2801            let key_id = account.signing_key_id();
2802            let signature = account.sign(message);
2803            signatures.add_signature(self.user_id().to_owned(), key_id, signature);
2804        }
2805
2806        match self.sign_with_master_key(message).await {
2807            Ok((key_id, signature)) => {
2808                signatures.add_signature(self.user_id().to_owned(), key_id, signature);
2809            }
2810            Err(e) => {
2811                warn!(error = ?e, "Couldn't sign the message using the cross signing master key")
2812            }
2813        }
2814
2815        Ok(signatures)
2816    }
2817
2818    /// Get a reference to the backup related state machine.
2819    ///
2820    /// This state machine can be used to incrementally backup all room keys to
2821    /// the server.
2822    pub fn backup_machine(&self) -> &BackupMachine {
2823        &self.inner.backup_machine
2824    }
2825
2826    /// Syncs the database and in-memory generation counter.
2827    ///
2828    /// This requires that the crypto store lock has been acquired already.
2829    pub async fn initialize_crypto_store_generation(
2830        &self,
2831        generation: &Mutex<Option<u64>>,
2832    ) -> StoreResult<()> {
2833        // Avoid reentrant initialization by taking the lock for the entire's function
2834        // scope.
2835        let mut gen_guard = generation.lock().await;
2836
2837        let prev_generation =
2838            self.inner.store.get_custom_value(Self::CURRENT_GENERATION_STORE_KEY).await?;
2839
2840        let generation = match prev_generation {
2841            Some(val) => {
2842                // There was a value in the store. We need to signal that we're a different
2843                // process, so we don't just reuse the value but increment it.
2844                u64::from_le_bytes(val.try_into().map_err(|_| {
2845                    CryptoStoreError::InvalidLockGeneration("invalid format".to_owned())
2846                })?)
2847                .wrapping_add(1)
2848            }
2849            None => 0,
2850        };
2851
2852        tracing::debug!("Initialising crypto store generation at {generation}");
2853
2854        self.inner
2855            .store
2856            .set_custom_value(Self::CURRENT_GENERATION_STORE_KEY, generation.to_le_bytes().to_vec())
2857            .await?;
2858
2859        *gen_guard = Some(generation);
2860
2861        Ok(())
2862    }
2863
2864    /// If needs be, update the local and on-disk crypto store generation.
2865    ///
2866    /// ## Requirements
2867    ///
2868    /// - This assumes that `initialize_crypto_store_generation` has been called
2869    ///   beforehand.
2870    /// - This requires that the crypto store lock has been acquired.
2871    ///
2872    /// # Arguments
2873    ///
2874    /// * `generation` - The in-memory generation counter (or rather, the
2875    ///   `Mutex` wrapping it). This defines the "expected" generation on entry,
2876    ///   and, if we determine an update is needed, is updated to hold the "new"
2877    ///   generation.
2878    ///
2879    /// # Returns
2880    ///
2881    /// A tuple containing:
2882    ///
2883    /// * A `bool`, set to `true` if another process has updated the generation
2884    ///   number in the `Store` since our expected value, and as such we've
2885    ///   incremented and updated it in the database. Otherwise, `false`.
2886    ///
2887    /// * The (possibly updated) generation counter.
2888    pub async fn maintain_crypto_store_generation(
2889        &'_ self,
2890        generation: &Mutex<Option<u64>>,
2891    ) -> StoreResult<(bool, u64)> {
2892        let mut gen_guard = generation.lock().await;
2893
2894        // The database value must be there:
2895        // - either we could initialize beforehand, thus write into the database,
2896        // - or we couldn't, and then another process was holding onto the database's
2897        //   lock, thus
2898        // has written a generation counter in there.
2899        let actual_gen = self
2900            .inner
2901            .store
2902            .get_custom_value(Self::CURRENT_GENERATION_STORE_KEY)
2903            .await?
2904            .ok_or_else(|| {
2905                CryptoStoreError::InvalidLockGeneration("counter missing in store".to_owned())
2906            })?;
2907
2908        let actual_gen =
2909            u64::from_le_bytes(actual_gen.try_into().map_err(|_| {
2910                CryptoStoreError::InvalidLockGeneration("invalid format".to_owned())
2911            })?);
2912
2913        let new_gen = match gen_guard.as_ref() {
2914            Some(expected_gen) => {
2915                if actual_gen == *expected_gen {
2916                    return Ok((false, actual_gen));
2917                }
2918                // Increment the biggest, and store it everywhere.
2919                actual_gen.max(*expected_gen).wrapping_add(1)
2920            }
2921            None => {
2922                // Some other process hold onto the lock when initializing, so we must reload.
2923                // Increment database value, and store it everywhere.
2924                actual_gen.wrapping_add(1)
2925            }
2926        };
2927
2928        tracing::debug!(
2929            "Crypto store generation mismatch: previously known was {:?}, actual is {:?}, next is {}",
2930            *gen_guard,
2931            actual_gen,
2932            new_gen
2933        );
2934
2935        // Update known value.
2936        *gen_guard = Some(new_gen);
2937
2938        // Update value in database.
2939        self.inner
2940            .store
2941            .set_custom_value(Self::CURRENT_GENERATION_STORE_KEY, new_gen.to_le_bytes().to_vec())
2942            .await?;
2943
2944        Ok((true, new_gen))
2945    }
2946
2947    /// Manage dehydrated devices.
2948    pub fn dehydrated_devices(&self) -> DehydratedDevices {
2949        DehydratedDevices { inner: self.to_owned() }
2950    }
2951
2952    /// Get the stored encryption settings for the given room, such as the
2953    /// encryption algorithm or whether to encrypt only for trusted devices.
2954    ///
2955    /// These settings can be modified via [`OlmMachine::set_room_settings`].
2956    pub async fn room_settings(&self, room_id: &RoomId) -> StoreResult<Option<RoomSettings>> {
2957        // There's not much to do here: it's just exposed for symmetry with
2958        // `set_room_settings`.
2959        self.inner.store.get_room_settings(room_id).await
2960    }
2961
2962    /// Store encryption settings for the given room.
2963    ///
2964    /// This method checks if the new settings are "safe" -- ie, that they do
2965    /// not represent a downgrade in encryption security from any previous
2966    /// settings. Attempts to downgrade security will result in a
2967    /// [`SetRoomSettingsError::EncryptionDowngrade`].
2968    ///
2969    /// If the settings are valid, they will be persisted to the crypto store.
2970    /// These settings are not used directly by this library, but the saved
2971    /// settings can be retrieved via [`OlmMachine::room_settings`].
2972    pub async fn set_room_settings(
2973        &self,
2974        room_id: &RoomId,
2975        new_settings: &RoomSettings,
2976    ) -> Result<(), SetRoomSettingsError> {
2977        let store = &self.inner.store;
2978
2979        // We want to make sure that we do not race against a second concurrent call to
2980        // `set_room_settings`. By way of an easy way to do so, we start a
2981        // StoreTransaction. There's no need to commit() it: we're just using it as a
2982        // lock guard.
2983        let _store_transaction = store.transaction().await;
2984
2985        let old_settings = store.get_room_settings(room_id).await?;
2986
2987        // We want to make sure that the change to the room settings does not represent
2988        // a downgrade in security. The [E2EE implementation guide] recommends:
2989        //
2990        //  > This flag should **not** be cleared if a later `m.room.encryption` event
2991        //  > changes the configuration.
2992        //
2993        // (However, it doesn't really address how to handle changes to the rotation
2994        // parameters, etc.) For now at least, we are very conservative here:
2995        // any new settings are rejected if they differ from the existing settings.
2996        // merit improvement (cf https://github.com/element-hq/element-meta/issues/69).
2997        //
2998        // [E2EE implementation guide]: https://matrix.org/docs/matrix-concepts/end-to-end-encryption/#handling-an-m-room-encryption-state-event
2999        if let Some(old_settings) = old_settings {
3000            if old_settings != *new_settings {
3001                return Err(SetRoomSettingsError::EncryptionDowngrade);
3002            } else {
3003                // nothing to do here
3004                return Ok(());
3005            }
3006        }
3007
3008        // Make sure that the new settings are valid
3009        match new_settings.algorithm {
3010            EventEncryptionAlgorithm::MegolmV1AesSha2 => (),
3011
3012            #[cfg(feature = "experimental-algorithms")]
3013            EventEncryptionAlgorithm::MegolmV2AesSha2 => (),
3014
3015            _ => {
3016                warn!(
3017                    ?room_id,
3018                    "Rejecting invalid encryption algorithm {}", new_settings.algorithm
3019                );
3020                return Err(SetRoomSettingsError::InvalidSettings);
3021            }
3022        }
3023
3024        // The new settings are acceptable, so let's save them.
3025        store
3026            .save_changes(Changes {
3027                room_settings: HashMap::from([(room_id.to_owned(), new_settings.clone())]),
3028                ..Default::default()
3029            })
3030            .await?;
3031
3032        Ok(())
3033    }
3034
3035    /// Returns whether this `OlmMachine` is the same another one.
3036    ///
3037    /// Useful for testing purposes only.
3038    #[cfg(any(feature = "testing", test))]
3039    pub fn same_as(&self, other: &OlmMachine) -> bool {
3040        Arc::ptr_eq(&self.inner, &other.inner)
3041    }
3042
3043    /// Testing purposes only.
3044    #[cfg(any(feature = "testing", test))]
3045    pub async fn uploaded_key_count(&self) -> Result<u64, CryptoStoreError> {
3046        let cache = self.inner.store.cache().await?;
3047        let account = cache.account().await?;
3048        Ok(account.uploaded_key_count())
3049    }
3050
3051    /// Returns the identity manager.
3052    #[cfg(test)]
3053    pub(crate) fn identity_manager(&self) -> &IdentityManager {
3054        &self.inner.identity_manager
3055    }
3056
3057    /// Returns a store key, only useful for testing purposes.
3058    #[cfg(test)]
3059    pub(crate) fn key_for_has_migrated_verification_latch() -> &'static str {
3060        Self::HAS_MIGRATED_VERIFICATION_LATCH
3061    }
3062}
3063
3064fn sender_data_to_verification_state(
3065    sender_data: SenderData,
3066    session_has_been_imported: bool,
3067) -> (VerificationState, Option<OwnedDeviceId>) {
3068    match sender_data {
3069        SenderData::UnknownDevice { owner_check_failed: false, .. } => {
3070            let device_link_problem = if session_has_been_imported {
3071                DeviceLinkProblem::InsecureSource
3072            } else {
3073                DeviceLinkProblem::MissingDevice
3074            };
3075
3076            (VerificationState::Unverified(VerificationLevel::None(device_link_problem)), None)
3077        }
3078        SenderData::UnknownDevice { owner_check_failed: true, .. } => (
3079            VerificationState::Unverified(VerificationLevel::None(
3080                DeviceLinkProblem::InsecureSource,
3081            )),
3082            None,
3083        ),
3084        SenderData::DeviceInfo { device_keys, .. } => (
3085            VerificationState::Unverified(VerificationLevel::UnsignedDevice),
3086            Some(device_keys.device_id),
3087        ),
3088        SenderData::VerificationViolation(KnownSenderData { device_id, .. }) => {
3089            (VerificationState::Unverified(VerificationLevel::VerificationViolation), device_id)
3090        }
3091        SenderData::SenderUnverified(KnownSenderData { device_id, .. }) => {
3092            (VerificationState::Unverified(VerificationLevel::UnverifiedIdentity), device_id)
3093        }
3094        SenderData::SenderVerified(KnownSenderData { device_id, .. }) => {
3095            (VerificationState::Verified, device_id)
3096        }
3097    }
3098}
3099
3100/// A set of requests to be executed when bootstrapping cross-signing using
3101/// [`OlmMachine::bootstrap_cross_signing`].
3102#[derive(Debug, Clone)]
3103pub struct CrossSigningBootstrapRequests {
3104    /// An optional request to upload a device key.
3105    ///
3106    /// Should be sent first, if present.
3107    ///
3108    /// If present, its result must be processed back with
3109    /// `OlmMachine::mark_request_as_sent`.
3110    pub upload_keys_req: Option<OutgoingRequest>,
3111
3112    /// Request to upload the cross-signing keys.
3113    ///
3114    /// Should be sent second.
3115    pub upload_signing_keys_req: UploadSigningKeysRequest,
3116
3117    /// Request to upload key signatures, including those for the cross-signing
3118    /// keys, and maybe some for the optional uploaded key too.
3119    ///
3120    /// Should be sent last.
3121    pub upload_signatures_req: UploadSignaturesRequest,
3122}
3123
3124/// Data contained from a sync response and that needs to be processed by the
3125/// OlmMachine.
3126#[derive(Debug)]
3127pub struct EncryptionSyncChanges<'a> {
3128    /// The list of to-device events received in the sync.
3129    pub to_device_events: Vec<Raw<AnyToDeviceEvent>>,
3130    /// The mapping of changed and left devices, per user, as returned in the
3131    /// sync response.
3132    pub changed_devices: &'a DeviceLists,
3133    /// The number of one time keys, as returned in the sync response.
3134    pub one_time_keys_counts: &'a BTreeMap<OneTimeKeyAlgorithm, UInt>,
3135    /// An optional list of fallback keys.
3136    pub unused_fallback_keys: Option<&'a [OneTimeKeyAlgorithm]>,
3137    /// A next-batch token obtained from a to-device sync query.
3138    pub next_batch_token: Option<String>,
3139}
3140
3141/// Convert a [`MegolmError`] into an [`UnableToDecryptInfo`] or a
3142/// [`CryptoStoreError`].
3143///
3144/// Most `MegolmError` codes are converted into a suitable
3145/// `UnableToDecryptInfo`. The exception is [`MegolmError::Store`], which
3146/// represents a problem with our datastore rather than with the message itself,
3147/// and is therefore returned as a `CryptoStoreError`.
3148fn megolm_error_to_utd_info(
3149    raw_event: &Raw<EncryptedEvent>,
3150    error: MegolmError,
3151) -> Result<UnableToDecryptInfo, CryptoStoreError> {
3152    use MegolmError::*;
3153    let reason = match error {
3154        EventError(_) => UnableToDecryptReason::MalformedEncryptedEvent,
3155        Decode(_) => UnableToDecryptReason::MalformedEncryptedEvent,
3156        MissingRoomKey(maybe_withheld) => {
3157            UnableToDecryptReason::MissingMegolmSession { withheld_code: maybe_withheld }
3158        }
3159        Decryption(DecryptionError::UnknownMessageIndex(_, _)) => {
3160            UnableToDecryptReason::UnknownMegolmMessageIndex
3161        }
3162        Decryption(_) => UnableToDecryptReason::MegolmDecryptionFailure,
3163        JsonError(_) => UnableToDecryptReason::PayloadDeserializationFailure,
3164        MismatchedIdentityKeys(_) => UnableToDecryptReason::MismatchedIdentityKeys,
3165        SenderIdentityNotTrusted(level) => UnableToDecryptReason::SenderIdentityNotTrusted(level),
3166        #[cfg(feature = "experimental-encrypted-state-events")]
3167        StateKeyVerificationFailed => UnableToDecryptReason::StateKeyVerificationFailed,
3168
3169        // Pass through crypto store errors, which indicate a problem with our
3170        // application, rather than a UTD.
3171        Store(error) => Err(error)?,
3172    };
3173
3174    let session_id = raw_event.deserialize().ok().and_then(|ev| match ev.content.scheme {
3175        RoomEventEncryptionScheme::MegolmV1AesSha2(s) => Some(s.session_id),
3176        #[cfg(feature = "experimental-algorithms")]
3177        RoomEventEncryptionScheme::MegolmV2AesSha2(s) => Some(s.session_id),
3178        RoomEventEncryptionScheme::Unknown(_) => None,
3179    });
3180
3181    Ok(UnableToDecryptInfo { session_id, reason })
3182}
3183
3184/// An error that can occur during [`OlmMachine::decrypt_to_device_event`]:
3185///
3186/// * because decryption failed, or
3187///
3188/// * because the sender device was not verified when we are in strict "exclude
3189///   insecure devices" mode, or
3190///
3191/// * because the sender device was a dehydrated device, which should never send
3192///   any to-device messages.
3193#[derive(Debug, thiserror::Error)]
3194pub(crate) enum DecryptToDeviceError {
3195    #[error("An Olm error occurred meaning we failed to decrypt the event")]
3196    OlmError(#[from] OlmError),
3197
3198    #[error("The event was sent from a dehydrated device")]
3199    FromDehydratedDevice,
3200}
3201
3202impl From<CryptoStoreError> for DecryptToDeviceError {
3203    fn from(value: CryptoStoreError) -> Self {
3204        Self::OlmError(value.into())
3205    }
3206}
3207
3208#[cfg(test)]
3209impl From<DecryptToDeviceError> for OlmError {
3210    /// Unwrap the `OlmError` inside this error, or panic if this does not
3211    /// contain an `OlmError`.
3212    fn from(value: DecryptToDeviceError) -> Self {
3213        match value {
3214            DecryptToDeviceError::OlmError(olm_error) => olm_error,
3215            DecryptToDeviceError::FromDehydratedDevice => {
3216                panic!("Expected an OlmError but found FromDehydratedDevice")
3217            }
3218        }
3219    }
3220}
3221
3222#[cfg(test)]
3223pub(crate) mod test_helpers;
3224
3225#[cfg(test)]
3226pub(crate) mod tests;