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