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