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