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