Skip to main content

matrix_sdk_crypto/olm/
account.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},
17    fmt,
18    ops::{Deref, Not as _},
19    sync::Arc,
20    time::Duration,
21};
22
23use hkdf::Hkdf;
24use js_option::JsOption;
25use matrix_sdk_common::deserialized_responses::{
26    AlgorithmInfo, DeviceLinkProblem, EncryptionInfo, VerificationLevel, VerificationState,
27};
28use ruma::{
29    CanonicalJsonValue, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch,
30    OneTimeKeyAlgorithm, OneTimeKeyId, OwnedDeviceId, OwnedDeviceKeyId, OwnedOneTimeKeyId,
31    OwnedUserId, RoomId, SecondsSinceUnixEpoch, UInt, UserId,
32    api::client::{
33        dehydrated_device::{DehydratedDeviceData, DehydratedDeviceV2},
34        keys::{upload_keys, upload_signatures::v3::Request as SignatureUploadRequest},
35    },
36    canonical_json::to_canonical_value,
37    events::{AnyToDeviceEvent, room::history_visibility::HistoryVisibility},
38    serde::Raw,
39};
40use serde::{Deserialize, Serialize, de::Error};
41use serde_json::value::{RawValue as RawJsonValue, to_raw_value};
42use sha2::{Digest, Sha256};
43use tokio::sync::Mutex;
44use tracing::{Span, debug, field::debug, info, instrument, trace, warn};
45use vodozemac::{
46    Curve25519PublicKey, Ed25519Signature, KeyId, PickleError, base64_encode,
47    olm::{
48        Account as InnerAccount, AccountPickle, IdentityKeys, OlmMessage,
49        OneTimeKeyGenerationResult, PreKeyMessage, SessionConfig,
50    },
51};
52
53use super::{
54    EncryptionSettings, InboundGroupSession, OutboundGroupSession, PrivateCrossSigningIdentity,
55    Session, SessionCreationError as MegolmSessionCreationError, utility::SignJson,
56};
57#[cfg(feature = "experimental-algorithms")]
58use crate::types::events::room::encrypted::OlmV2Curve25519AesSha2Content;
59use crate::{
60    DecryptionSettings, Device, OlmError, SignatureError, TrustRequirement,
61    dehydrated_devices::DehydrationError,
62    error::{EventError, OlmResult, SessionCreationError},
63    identities::DeviceData,
64    olm::SenderData,
65    store::{
66        Store,
67        types::{Changes, DeviceChanges},
68    },
69    types::{
70        CrossSigningKey, DeviceKeys, EventEncryptionAlgorithm, OneTimeKey, SignedKey,
71        events::{
72            olm_v1::AnyDecryptedOlmEvent,
73            room::encrypted::{
74                EncryptedToDeviceEvent, OlmV1Curve25519AesSha2Content,
75                ToDeviceEncryptedEventContent,
76            },
77        },
78        requests::UploadSigningKeysRequest,
79    },
80};
81
82#[derive(Debug)]
83enum PrekeyBundle {
84    Olm3DH { key: SignedKey },
85}
86
87#[derive(Debug, Clone)]
88pub(crate) enum SessionType {
89    New(Session),
90    Existing(Session),
91}
92
93#[derive(Debug)]
94pub struct InboundCreationResult {
95    pub session: Session,
96    pub plaintext: String,
97}
98
99impl SessionType {
100    #[cfg(test)]
101    pub fn session(self) -> Session {
102        match self {
103            SessionType::New(s) => s,
104            SessionType::Existing(s) => s,
105        }
106    }
107}
108
109/// A struct witnessing a successful decryption of an Olm-encrypted to-device
110/// event.
111///
112/// Contains the decrypted event plaintext along with some associated metadata,
113/// such as the identity (Curve25519) key of the to-device event sender.
114#[derive(Debug)]
115pub(crate) struct OlmDecryptionInfo {
116    pub session: SessionType,
117    pub message_hash: OlmMessageHash,
118    pub inbound_group_session: Option<InboundGroupSession>,
119    pub result: DecryptionResult,
120}
121
122#[derive(Debug)]
123pub(crate) struct DecryptionResult {
124    // AnyDecryptedOlmEvent is pretty big at 512 bytes, box it to reduce stack size
125    pub event: Box<AnyDecryptedOlmEvent>,
126    pub raw_event: Raw<AnyToDeviceEvent>,
127    pub sender_key: Curve25519PublicKey,
128    pub encryption_info: EncryptionInfo,
129}
130
131/// A hash of a successfully decrypted Olm message.
132///
133/// Can be used to check if a message has been replayed to us.
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct OlmMessageHash {
136    /// The curve25519 key of the sender that sent us the Olm message.
137    pub sender_key: String,
138    /// The hash of the message.
139    pub hash: String,
140}
141
142impl OlmMessageHash {
143    fn new(sender_key: Curve25519PublicKey, ciphertext: &OlmMessage) -> Self {
144        let (message_type, ciphertext) = ciphertext.clone().to_parts();
145        let sender_key = sender_key.to_base64();
146
147        let sha = Sha256::new()
148            .chain_update(sender_key.as_bytes())
149            .chain_update([message_type as u8])
150            .chain_update(ciphertext)
151            .finalize();
152
153        Self { sender_key, hash: base64_encode(sha.as_slice()) }
154    }
155}
156
157/// Account data that's static for the lifetime of a Client.
158///
159/// This data never changes once it's set, so it can be freely passed and cloned
160/// everywhere.
161#[derive(Clone)]
162#[cfg_attr(not(tarpaulin_include), derive(Debug))]
163pub struct StaticAccountData {
164    /// The user_id this account belongs to.
165    pub user_id: OwnedUserId,
166    /// The device_id of this entry.
167    pub device_id: OwnedDeviceId,
168    /// The associated identity keys.
169    pub identity_keys: Arc<IdentityKeys>,
170    /// Whether the account is for a dehydrated device.
171    pub dehydrated: bool,
172    // The creation time of the account in milliseconds since epoch.
173    creation_local_time: MilliSecondsSinceUnixEpoch,
174}
175
176impl StaticAccountData {
177    const ALGORITHMS: &'static [&'static EventEncryptionAlgorithm] = &[
178        &EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
179        #[cfg(feature = "experimental-algorithms")]
180        &EventEncryptionAlgorithm::OlmV2Curve25519AesSha2,
181        &EventEncryptionAlgorithm::MegolmV1AesSha2,
182        #[cfg(feature = "experimental-algorithms")]
183        &EventEncryptionAlgorithm::MegolmV2AesSha2,
184    ];
185
186    /// Create a group session pair.
187    ///
188    /// This session pair can be used to encrypt and decrypt messages meant for
189    /// a large group of participants.
190    ///
191    /// The outbound session is used to encrypt messages while the inbound one
192    /// is used to decrypt messages encrypted by the outbound one.
193    ///
194    /// # Arguments
195    ///
196    /// * `room_id` - The ID of the room where the group session will be used.
197    ///
198    /// * `settings` - Settings determining the algorithm and rotation period of
199    ///   the outbound group session.
200    pub async fn create_group_session_pair(
201        &self,
202        room_id: &RoomId,
203        settings: EncryptionSettings,
204        own_sender_data: SenderData,
205    ) -> Result<(OutboundGroupSession, InboundGroupSession), MegolmSessionCreationError> {
206        trace!(?room_id, algorithm = settings.algorithm.as_str(), "Creating a new room key");
207
208        let visibility = settings.history_visibility.clone();
209        let algorithm = settings.algorithm.to_owned();
210
211        let outbound = OutboundGroupSession::new(
212            self.device_id.clone(),
213            self.identity_keys.clone(),
214            room_id,
215            settings,
216        )?;
217
218        let identity_keys = &self.identity_keys;
219
220        let sender_key = identity_keys.curve25519;
221        let signing_key = identity_keys.ed25519;
222        let shared_history = shared_history_from_history_visibility(&visibility);
223
224        let inbound = InboundGroupSession::new(
225            sender_key,
226            signing_key,
227            room_id,
228            &outbound.session_key().await,
229            own_sender_data,
230            None,
231            algorithm,
232            Some(visibility),
233            shared_history,
234        )?;
235
236        Ok((outbound, inbound))
237    }
238
239    #[cfg(any(test, feature = "testing"))]
240    #[allow(dead_code)]
241    /// Testing only facility to create a group session pair with default
242    /// settings.
243    pub async fn create_group_session_pair_with_defaults(
244        &self,
245        room_id: &RoomId,
246    ) -> (OutboundGroupSession, InboundGroupSession) {
247        self.create_group_session_pair(
248            room_id,
249            EncryptionSettings::default(),
250            SenderData::unknown(),
251        )
252        .await
253        .expect("Can't create default group session pair")
254    }
255
256    /// Get the key ID of our Ed25519 signing key.
257    pub fn signing_key_id(&self) -> OwnedDeviceKeyId {
258        DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id())
259    }
260
261    /// Check if the given JSON is signed by this Account key.
262    ///
263    /// This method should only be used if an object's signature needs to be
264    /// checked multiple times, and you'd like to avoid performing the
265    /// canonicalization step each time.
266    ///
267    /// **Note**: Use this method with caution, the `canonical_json` needs to be
268    /// correctly canonicalized and make sure that the object you are checking
269    /// the signature for is allowed to be signed by our own device.
270    pub fn has_signed_raw(
271        &self,
272        signatures: &crate::types::Signatures,
273        canonical_json: &str,
274    ) -> Result<(), SignatureError> {
275        use crate::olm::utility::VerifyJson;
276
277        let signing_key = self.identity_keys.ed25519;
278
279        signing_key.verify_canonicalized_json(
280            &self.user_id,
281            &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
282            signatures,
283            canonical_json,
284        )
285    }
286
287    /// Generate the unsigned `DeviceKeys` from this `StaticAccountData`.
288    pub fn unsigned_device_keys(&self) -> DeviceKeys {
289        let identity_keys = self.identity_keys();
290        let keys = BTreeMap::from([
291            (
292                DeviceKeyId::from_parts(DeviceKeyAlgorithm::Curve25519, &self.device_id),
293                identity_keys.curve25519.into(),
294            ),
295            (
296                DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.device_id),
297                identity_keys.ed25519.into(),
298            ),
299        ]);
300
301        let mut ret = DeviceKeys::new(
302            self.user_id.clone(),
303            self.device_id.clone(),
304            Self::ALGORITHMS.iter().map(|a| (**a).clone()).collect(),
305            keys,
306            Default::default(),
307        );
308        if self.dehydrated {
309            ret.dehydrated = JsOption::Some(true);
310        }
311        ret
312    }
313
314    /// Get the user id of the owner of the account.
315    pub fn user_id(&self) -> &UserId {
316        &self.user_id
317    }
318
319    /// Get the device ID that owns this account.
320    pub fn device_id(&self) -> &DeviceId {
321        &self.device_id
322    }
323
324    /// Get the public parts of the identity keys for the account.
325    pub fn identity_keys(&self) -> IdentityKeys {
326        *self.identity_keys
327    }
328
329    /// Get the local timestamp creation of the account in secs since epoch.
330    pub fn creation_local_time(&self) -> MilliSecondsSinceUnixEpoch {
331        self.creation_local_time
332    }
333}
334
335/// Account holding identity keys for which sessions can be created.
336///
337/// An account is the central identity for encrypted communication between two
338/// devices.
339pub struct Account {
340    pub(crate) static_data: StaticAccountData,
341    /// `vodozemac` account.
342    inner: Box<InnerAccount>,
343    /// Is this account ready to encrypt messages? (i.e. has it shared keys with
344    /// a homeserver)
345    shared: bool,
346    /// The number of signed one-time keys we have uploaded to the server. If
347    /// this is None, no action will be taken. After a sync request the client
348    /// needs to set this for us, depending on the count we will suggest the
349    /// client to upload new keys.
350    uploaded_signed_key_count: u64,
351    /// The timestamp of the last time we generated a fallback key. Fallback
352    /// keys are rotated in a time-based manner. This field records when we
353    /// either generated our first fallback key or rotated one.
354    ///
355    /// Will be `None` if we never created a fallback key, or if we're migrating
356    /// from a `AccountPickle` that didn't use time-based fallback key
357    /// rotation.
358    fallback_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
359}
360
361impl Deref for Account {
362    type Target = StaticAccountData;
363
364    fn deref(&self) -> &Self::Target {
365        &self.static_data
366    }
367}
368
369/// A pickled version of an `Account`.
370///
371/// Holds all the information that needs to be stored in a database to restore
372/// an account.
373#[derive(Serialize, Deserialize)]
374#[allow(missing_debug_implementations)]
375pub struct PickledAccount {
376    /// The user id of the account owner.
377    pub user_id: OwnedUserId,
378    /// The device ID of the account owner.
379    pub device_id: OwnedDeviceId,
380    /// The pickled version of the Olm account.
381    pub pickle: AccountPickle,
382    /// Was the account shared.
383    pub shared: bool,
384    /// Whether this is for a dehydrated device
385    #[serde(default)]
386    pub dehydrated: bool,
387    /// The number of uploaded one-time keys we have on the server.
388    pub uploaded_signed_key_count: u64,
389    /// The local time creation of this account (milliseconds since epoch), used
390    /// as creation time of own device
391    #[serde(default = "default_account_creation_time")]
392    pub creation_local_time: MilliSecondsSinceUnixEpoch,
393    /// The timestamp of the last time we generated a fallback key.
394    #[serde(default)]
395    pub fallback_key_creation_timestamp: Option<MilliSecondsSinceUnixEpoch>,
396}
397
398fn default_account_creation_time() -> MilliSecondsSinceUnixEpoch {
399    MilliSecondsSinceUnixEpoch(UInt::default())
400}
401
402#[cfg(not(tarpaulin_include))]
403impl fmt::Debug for Account {
404    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
405        f.debug_struct("Account")
406            .field("identity_keys", &self.identity_keys())
407            .field("shared", &self.shared())
408            .finish()
409    }
410}
411
412pub type OneTimeKeys = BTreeMap<OwnedOneTimeKeyId, Raw<ruma::encryption::OneTimeKey>>;
413pub type FallbackKeys = OneTimeKeys;
414
415impl Account {
416    pub(crate) fn new_helper(
417        mut account: InnerAccount,
418        user_id: &UserId,
419        device_id: &DeviceId,
420    ) -> Self {
421        let identity_keys = account.identity_keys();
422
423        // Let's generate some initial one-time keys while we're here. Since we know
424        // that this is a completely new [`Account`] we're certain that the
425        // server does not yet have any one-time keys of ours.
426        //
427        // This ensures we upload one-time keys along with our device keys right
428        // away, rather than waiting for the key counts to be echoed back to us
429        // from the server.
430        //
431        // It would be nice to do this for the fallback key as well but we can't assume
432        // that the server supports fallback keys. Maybe one of these days we
433        // will be able to do so.
434        account.generate_one_time_keys(account.max_number_of_one_time_keys());
435
436        Self {
437            static_data: StaticAccountData {
438                user_id: user_id.into(),
439                device_id: device_id.into(),
440                identity_keys: Arc::new(identity_keys),
441                dehydrated: false,
442                creation_local_time: MilliSecondsSinceUnixEpoch::now(),
443            },
444            inner: Box::new(account),
445            shared: false,
446            uploaded_signed_key_count: 0,
447            fallback_creation_timestamp: None,
448        }
449    }
450
451    /// Create a fresh new account, this will generate the identity key-pair.
452    pub fn with_device_id(user_id: &UserId, device_id: &DeviceId) -> Self {
453        let account = InnerAccount::new();
454
455        Self::new_helper(account, user_id, device_id)
456    }
457
458    /// Create a new random Olm Account, the long-term Curve25519 identity key
459    /// encoded as base64 will be used for the device ID.
460    pub fn new(user_id: &UserId) -> Self {
461        let account = InnerAccount::new();
462        let device_id: OwnedDeviceId =
463            base64_encode(account.identity_keys().curve25519.as_bytes()).into();
464
465        Self::new_helper(account, user_id, &device_id)
466    }
467
468    /// Create a new random Olm Account for a dehydrated device
469    pub fn new_dehydrated(user_id: &UserId) -> Self {
470        let account = InnerAccount::new();
471        let device_id: OwnedDeviceId =
472            base64_encode(account.identity_keys().curve25519.as_bytes()).into();
473
474        let mut ret = Self::new_helper(account, user_id, &device_id);
475        ret.static_data.dehydrated = true;
476        ret
477    }
478
479    /// Get the immutable data for this account.
480    pub fn static_data(&self) -> &StaticAccountData {
481        &self.static_data
482    }
483
484    /// Update the uploaded key count.
485    ///
486    /// # Arguments
487    ///
488    /// * `new_count` - The new count that was reported by the server.
489    pub fn update_uploaded_key_count(&mut self, new_count: u64) {
490        self.uploaded_signed_key_count = new_count;
491    }
492
493    /// Get the currently known uploaded key count.
494    pub fn uploaded_key_count(&self) -> u64 {
495        self.uploaded_signed_key_count
496    }
497
498    /// Has the account been shared with the server.
499    pub fn shared(&self) -> bool {
500        self.shared
501    }
502
503    /// Mark the account as shared.
504    ///
505    /// Messages shouldn't be encrypted with the session before it has been
506    /// shared.
507    pub fn mark_as_shared(&mut self) {
508        self.shared = true;
509    }
510
511    /// Get the one-time keys of the account.
512    ///
513    /// This can be empty, keys need to be generated first.
514    pub fn one_time_keys(&self) -> HashMap<KeyId, Curve25519PublicKey> {
515        self.inner.one_time_keys()
516    }
517
518    /// Generate count number of one-time keys.
519    pub fn generate_one_time_keys(&mut self, count: usize) -> OneTimeKeyGenerationResult {
520        self.inner.generate_one_time_keys(count)
521    }
522
523    /// Get the maximum number of one-time keys the account can hold.
524    pub fn max_one_time_keys(&self) -> usize {
525        self.inner.max_number_of_one_time_keys()
526    }
527
528    pub(crate) fn update_key_counts(
529        &mut self,
530        one_time_key_counts: &BTreeMap<OneTimeKeyAlgorithm, UInt>,
531        unused_fallback_keys: Option<&[OneTimeKeyAlgorithm]>,
532    ) {
533        if let Some(count) = one_time_key_counts.get(&OneTimeKeyAlgorithm::SignedCurve25519) {
534            let count: u64 = (*count).into();
535            let old_count = self.uploaded_key_count();
536
537            // Some servers might always return the key counts in the sync
538            // response, we don't want to the logs with noop changes if they do
539            // so.
540            if count != old_count {
541                debug!(
542                    "Updated uploaded one-time key count {} -> {count}.",
543                    self.uploaded_key_count(),
544                );
545            }
546
547            self.update_uploaded_key_count(count);
548            self.generate_one_time_keys_if_needed();
549        }
550
551        // If the server supports fallback keys or if it did so in the past, shown by
552        // the existence of a fallback creation timestamp, generate a new one if
553        // we don't have one, or if the current fallback key expired.
554        if unused_fallback_keys.is_some() || self.fallback_creation_timestamp.is_some() {
555            self.generate_fallback_key_if_needed();
556        }
557    }
558
559    /// Generate new one-time keys that need to be uploaded to the server.
560    ///
561    /// Returns None if no keys need to be uploaded, otherwise the number of
562    /// newly generated one-time keys. May return 0 if some one-time keys are
563    /// already generated but weren't uploaded.
564    ///
565    /// Generally `Some` means that keys should be uploaded, while `None` means
566    /// that keys should not be uploaded.
567    #[instrument(skip_all)]
568    pub fn generate_one_time_keys_if_needed(&mut self) -> Option<u64> {
569        // Only generate one-time keys if there aren't any, otherwise the caller
570        // might have failed to upload them the last time this method was
571        // called.
572        if !self.one_time_keys().is_empty() {
573            return Some(0);
574        }
575
576        let count = self.uploaded_key_count();
577        let max_keys = self.max_one_time_keys();
578
579        if count >= max_keys as u64 {
580            return None;
581        }
582
583        let key_count = (max_keys as u64) - count;
584        let key_count: usize = key_count.try_into().unwrap_or(max_keys);
585
586        let result = self.generate_one_time_keys(key_count);
587
588        debug!(
589            count = key_count,
590            discarded_keys = ?result.removed,
591            created_keys = ?result.created,
592            "Generated new one-time keys"
593        );
594
595        Some(key_count as u64)
596    }
597
598    /// Generate a new fallback key iff a unpublished one isn't already inside
599    /// of vodozemac and if the currently active one expired.
600    ///
601    /// The former is checked using [`Account::fallback_key().is_empty()`],
602    /// which is a hashmap that gets cleared by the
603    /// [`Account::mark_keys_as_published()`] call.
604    pub(crate) fn generate_fallback_key_if_needed(&mut self) {
605        if self.inner.fallback_key().is_empty() && self.fallback_key_expired() {
606            let removed_fallback_key = self.inner.generate_fallback_key();
607            self.fallback_creation_timestamp = Some(MilliSecondsSinceUnixEpoch::now());
608
609            debug!(
610                ?removed_fallback_key,
611                "The fallback key either expired or we didn't have one: generated a new fallback key.",
612            );
613        }
614    }
615
616    /// Check if our most recent fallback key has expired.
617    ///
618    /// We consider the fallback key to be expired if it's older than a week.
619    /// This is the lower bound for the recommended signed pre-key bundle
620    /// rotation interval in the X3DH spec[1].
621    ///
622    /// [1]: https://signal.org/docs/specifications/x3dh/#publishing-keys
623    fn fallback_key_expired(&self) -> bool {
624        const FALLBACK_KEY_MAX_AGE: Duration = Duration::from_secs(3600 * 24 * 7);
625
626        if let Some(time) = self.fallback_creation_timestamp {
627            // `to_system_time()` returns `None` if the the UNIX_EPOCH + `time` doesn't fit
628            // into a i64. This will likely never happen, but let's rotate the
629            // key in case the values are messed up for some other reason.
630            let Some(system_time) = time.to_system_time() else {
631                return true;
632            };
633
634            // `elapsed()` errors if the `system_time` is in the future, this should mean
635            // that our clock has changed to the past, let's rotate just in case
636            // and then we'll get to a normal time.
637            let Ok(elapsed) = system_time.elapsed() else {
638                return true;
639            };
640
641            // Alright, our times are normal and we know how much time elapsed since the
642            // last time we created/rotated a fallback key.
643            //
644            // If the key is older than a week, then we rotate it.
645            elapsed > FALLBACK_KEY_MAX_AGE
646        } else {
647            // We never created a fallback key, or we're migrating to the time-based
648            // fallback key rotation, so let's generate a new fallback key.
649            true
650        }
651    }
652
653    fn fallback_key(&self) -> HashMap<KeyId, Curve25519PublicKey> {
654        self.inner.fallback_key()
655    }
656
657    /// Get a tuple of device, one-time, and fallback keys that need to be
658    /// uploaded.
659    ///
660    /// If no keys need to be uploaded the `DeviceKeys` will be `None` and the
661    /// one-time and fallback keys maps will be empty.
662    pub fn keys_for_upload(&self) -> (Option<DeviceKeys>, OneTimeKeys, FallbackKeys) {
663        let device_keys = self.shared().not().then(|| self.device_keys());
664
665        let one_time_keys = self.signed_one_time_keys();
666        let fallback_keys = self.signed_fallback_keys();
667
668        (device_keys, one_time_keys, fallback_keys)
669    }
670
671    /// Mark the current set of one-time keys as being published.
672    pub fn mark_keys_as_published(&mut self) {
673        self.inner.mark_keys_as_published();
674    }
675
676    /// Sign the given string using the accounts signing key.
677    ///
678    /// Returns the signature as a base64 encoded string.
679    pub fn sign(&self, string: &str) -> Ed25519Signature {
680        self.inner.sign(string)
681    }
682
683    /// Get a serializable version of the `Account` so it can be persisted.
684    pub fn pickle(&self) -> PickledAccount {
685        let pickle = self.inner.pickle();
686
687        PickledAccount {
688            user_id: self.user_id().to_owned(),
689            device_id: self.device_id().to_owned(),
690            pickle,
691            shared: self.shared(),
692            dehydrated: self.static_data.dehydrated,
693            uploaded_signed_key_count: self.uploaded_key_count(),
694            creation_local_time: self.static_data.creation_local_time,
695            fallback_key_creation_timestamp: self.fallback_creation_timestamp,
696        }
697    }
698
699    pub(crate) fn dehydrate(&self, pickle_key: &[u8; 32]) -> Raw<DehydratedDeviceData> {
700        let dehydration_result = self
701            .inner
702            .to_dehydrated_device(pickle_key)
703            .expect("We should be able to convert a freshly created Account into a libolm pickle");
704
705        let data = DehydratedDeviceData::V2(DehydratedDeviceV2::new(
706            dehydration_result.ciphertext,
707            dehydration_result.nonce,
708        ));
709        Raw::from_json(to_raw_value(&data).expect("Couldn't serialize our dehydrated device data"))
710    }
711
712    pub(crate) fn rehydrate(
713        pickle_key: &[u8; 32],
714        user_id: &UserId,
715        device_id: &DeviceId,
716        device_data: Raw<DehydratedDeviceData>,
717    ) -> Result<Self, DehydrationError> {
718        let data = device_data.deserialize()?;
719
720        match data {
721            DehydratedDeviceData::V1(d) => {
722                let pickle_key = expand_legacy_pickle_key(pickle_key, device_id);
723                let account =
724                    InnerAccount::from_libolm_pickle(&d.device_pickle, pickle_key.as_ref())?;
725                Ok(Self::new_helper(account, user_id, device_id))
726            }
727            DehydratedDeviceData::V2(d) => {
728                let account =
729                    InnerAccount::from_dehydrated_device(&d.device_pickle, &d.nonce, pickle_key)?;
730                Ok(Self::new_helper(account, user_id, device_id))
731            }
732            _ => Err(DehydrationError::Json(serde_json::Error::custom(format!(
733                "Unsupported dehydrated device algorithm {:?}",
734                data.algorithm()
735            )))),
736        }
737    }
738
739    /// Produce a dehydrated device using a format described in an older version
740    /// of MSC3814.
741    #[cfg(test)]
742    pub(crate) fn legacy_dehydrate(&self, pickle_key: &[u8; 32]) -> Raw<DehydratedDeviceData> {
743        use ruma::api::client::dehydrated_device::DehydratedDeviceV1;
744
745        let pickle_key = expand_legacy_pickle_key(pickle_key, &self.device_id);
746        let device_pickle = self
747            .inner
748            .to_libolm_pickle(pickle_key.as_ref())
749            .expect("We should be able to convert a freshly created Account into a libolm pickle");
750
751        let data = DehydratedDeviceData::V1(DehydratedDeviceV1::new(device_pickle));
752        Raw::from_json(to_raw_value(&data).expect("Couldn't serialize our dehydrated device data"))
753    }
754
755    /// Restore an account from a previously pickled one.
756    ///
757    /// # Arguments
758    ///
759    /// * `pickle` - The pickled version of the Account.
760    ///
761    /// * `pickle_mode` - The mode that was used to pickle the account, either
762    ///   an unencrypted mode or an encrypted using passphrase.
763    pub fn from_pickle(pickle: PickledAccount) -> Result<Self, PickleError> {
764        let account: vodozemac::olm::Account = pickle.pickle.into();
765        let identity_keys = account.identity_keys();
766
767        Ok(Self {
768            static_data: StaticAccountData {
769                user_id: pickle.user_id.clone(),
770                device_id: pickle.device_id.clone(),
771                identity_keys: Arc::new(identity_keys),
772                dehydrated: pickle.dehydrated,
773                creation_local_time: pickle.creation_local_time,
774            },
775            inner: Box::new(account),
776            shared: pickle.shared,
777            uploaded_signed_key_count: pickle.uploaded_signed_key_count,
778            fallback_creation_timestamp: pickle.fallback_key_creation_timestamp,
779        })
780    }
781
782    /// Sign the device keys of the account and return them so they can be
783    /// uploaded.
784    pub fn device_keys(&self) -> DeviceKeys {
785        let mut device_keys = self.unsigned_device_keys();
786
787        // Create a copy of the device keys containing only fields that will
788        // get signed.
789        let json_device_keys =
790            to_canonical_value(&device_keys).expect("device key is always safe to serialize");
791        let signature = self
792            .sign_json(json_device_keys)
793            .expect("Newly created device keys can always be signed");
794
795        device_keys.signatures.add_signature(
796            self.user_id().to_owned(),
797            DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.static_data.device_id),
798            signature,
799        );
800
801        device_keys
802    }
803
804    /// Bootstraps cross-signing, generating new cross-signing keys and creating
805    /// the necessary upload and signature requests.
806    ///
807    /// # Returns
808    /// A tuple containing:
809    /// - [`PrivateCrossSigningIdentity`]: The newly-generated cross-signing
810    ///   identity (including a signature from this device).
811    /// - [`UploadSigningKeysRequest`]: The request to upload the
812    ///   newly-generated cross-signing keys to the server.
813    /// - [`SignatureUploadRequest`]: The request to upload the signature of
814    ///   this device to the server.
815    pub async fn bootstrap_cross_signing(
816        &self,
817    ) -> Result<
818        (PrivateCrossSigningIdentity, UploadSigningKeysRequest, SignatureUploadRequest),
819        SignatureError,
820    > {
821        let identity = PrivateCrossSigningIdentity::for_account(self)?;
822
823        let signature_request = identity.sign_account(self.static_data()).await?;
824
825        let upload_request = identity.as_upload_request().await;
826
827        Ok((identity, upload_request, signature_request))
828    }
829
830    /// Sign the given CrossSigning Key in place
831    pub fn sign_cross_signing_key(
832        &self,
833        cross_signing_key: &mut CrossSigningKey,
834    ) -> Result<(), SignatureError> {
835        let signature = self.sign_json(to_canonical_value(&cross_signing_key)?)?;
836
837        cross_signing_key.signatures.add_signature(
838            self.user_id().to_owned(),
839            DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
840            signature,
841        );
842
843        Ok(())
844    }
845
846    /// Convert a JSON value to the canonical representation and sign the JSON
847    /// string.
848    ///
849    /// # Arguments
850    ///
851    /// * `json` - The value that should be converted into a canonical JSON
852    ///   string.
853    pub fn sign_json(&self, json: CanonicalJsonValue) -> Result<Ed25519Signature, SignatureError> {
854        self.inner.sign_json(json)
855    }
856
857    /// Sign and prepare one-time keys to be uploaded.
858    ///
859    /// If no one-time keys need to be uploaded, returns an empty `BTreeMap`.
860    pub fn signed_one_time_keys(&self) -> OneTimeKeys {
861        let one_time_keys = self.one_time_keys();
862
863        if one_time_keys.is_empty() {
864            BTreeMap::new()
865        } else {
866            self.signed_keys(one_time_keys, false)
867        }
868    }
869
870    /// Sign and prepare fallback keys to be uploaded.
871    ///
872    /// If no fallback keys need to be uploaded returns an empty BTreeMap.
873    pub fn signed_fallback_keys(&self) -> FallbackKeys {
874        let fallback_key = self.fallback_key();
875
876        if fallback_key.is_empty() { BTreeMap::new() } else { self.signed_keys(fallback_key, true) }
877    }
878
879    fn signed_keys(
880        &self,
881        keys: HashMap<KeyId, Curve25519PublicKey>,
882        fallback: bool,
883    ) -> OneTimeKeys {
884        let mut keys_map = BTreeMap::new();
885
886        for (key_id, key) in keys {
887            let signed_key = self.sign_key(key, fallback);
888
889            keys_map.insert(
890                OneTimeKeyId::from_parts(
891                    OneTimeKeyAlgorithm::SignedCurve25519,
892                    key_id.to_base64().as_str().into(),
893                ),
894                signed_key.into_raw(),
895            );
896        }
897
898        keys_map
899    }
900
901    fn sign_key(&self, key: Curve25519PublicKey, fallback: bool) -> SignedKey {
902        let mut key = if fallback {
903            SignedKey::new_fallback(key.to_owned())
904        } else {
905            SignedKey::new(key.to_owned())
906        };
907
908        let signature = self
909            .sign_json(to_canonical_value(&key).expect("Can't serialize a signed key"))
910            .expect("Newly created one-time keys can always be signed");
911
912        key.signatures_mut().add_signature(
913            self.user_id().to_owned(),
914            DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
915            signature,
916        );
917
918        key
919    }
920
921    /// Create a new session with another account given a one-time key.
922    ///
923    /// Returns the newly created session or a `OlmSessionError` if creating a
924    /// session failed.
925    ///
926    /// # Arguments
927    ///
928    /// * `config` - The session config that should be used when creating the
929    ///   Session.
930    ///
931    /// * `identity_key` - The other account's identity/curve25519 key.
932    ///
933    /// * `one_time_key` - A signed one-time key that the other account created
934    ///   and shared with us.
935    ///
936    /// * `fallback_used` - Was the one-time key a fallback key.
937    ///
938    /// * `our_device_keys` - Our own `DeviceKeys`, including cross-signing
939    ///   signatures if applicable, for embedding in encrypted messages.
940    pub fn create_outbound_session_helper(
941        &self,
942        config: SessionConfig,
943        identity_key: Curve25519PublicKey,
944        one_time_key: Curve25519PublicKey,
945        fallback_used: bool,
946        our_device_keys: DeviceKeys,
947    ) -> Result<Session, vodozemac::olm::SessionCreationError> {
948        let session = self.inner.create_outbound_session(config, identity_key, one_time_key)?;
949
950        let now = SecondsSinceUnixEpoch::now();
951        let session_id = session.session_id();
952
953        Ok(Session {
954            inner: Arc::new(Mutex::new(session)),
955            session_id: session_id.into(),
956            sender_key: identity_key,
957            our_device_keys,
958            created_using_fallback_key: fallback_used,
959            creation_time: now,
960            last_use_time: now,
961        })
962    }
963
964    #[instrument(
965        skip_all,
966        fields(
967            user_id = ?device.user_id(),
968            device_id = ?device.device_id(),
969            algorithms = ?device.algorithms()
970        )
971    )]
972    fn find_pre_key_bundle(
973        device: &DeviceData,
974        key_map: &OneTimeKeys,
975    ) -> Result<PrekeyBundle, SessionCreationError> {
976        let mut keys = key_map.iter();
977
978        let first_key = keys.next().ok_or_else(|| {
979            SessionCreationError::OneTimeKeyMissing(
980                device.user_id().to_owned(),
981                device.device_id().into(),
982            )
983        })?;
984
985        let first_key_id = first_key.0.to_owned();
986        let first_key = OneTimeKey::deserialize(first_key_id.algorithm(), first_key.1)?;
987
988        let result = match first_key {
989            OneTimeKey::SignedKey(key) => Ok(PrekeyBundle::Olm3DH { key }),
990        };
991
992        trace!(?result, "Finished searching for a valid pre-key bundle");
993
994        result
995    }
996
997    /// Create a new session with another account given a one-time key and a
998    /// device.
999    ///
1000    /// Returns the newly created session or a `OlmSessionError` if creating a
1001    /// session failed.
1002    ///
1003    /// # Arguments
1004    /// * `device` - The other account's device.
1005    ///
1006    /// * `key_map` - A map from the algorithm and device ID to the one-time key
1007    ///   that the other account created and shared with us.
1008    ///
1009    /// * `our_device_keys` - Our own `DeviceKeys`, including cross-signing
1010    ///   signatures if applicable, for embedding in encrypted messages.
1011    #[allow(clippy::result_large_err)]
1012    pub fn create_outbound_session(
1013        &self,
1014        device: &DeviceData,
1015        key_map: &OneTimeKeys,
1016        our_device_keys: DeviceKeys,
1017    ) -> Result<Session, SessionCreationError> {
1018        let pre_key_bundle = Self::find_pre_key_bundle(device, key_map)?;
1019
1020        match pre_key_bundle {
1021            PrekeyBundle::Olm3DH { key } => {
1022                device.verify_one_time_key(&key).map_err(|error| {
1023                    SessionCreationError::InvalidSignature {
1024                        signing_key: device.ed25519_key().map(Box::new),
1025                        one_time_key: key.clone().into(),
1026                        error: error.into(),
1027                    }
1028                })?;
1029
1030                let identity_key = device.curve25519_key().ok_or_else(|| {
1031                    SessionCreationError::DeviceMissingCurveKey(
1032                        device.user_id().to_owned(),
1033                        device.device_id().into(),
1034                    )
1035                })?;
1036
1037                let is_fallback = key.fallback();
1038                let one_time_key = key.key();
1039                let config = device.olm_session_config();
1040
1041                Ok(self.create_outbound_session_helper(
1042                    config,
1043                    identity_key,
1044                    one_time_key,
1045                    is_fallback,
1046                    our_device_keys,
1047                )?)
1048            }
1049        }
1050    }
1051
1052    /// Create a new session with another account given a pre-key Olm message.
1053    ///
1054    /// Returns the newly created session or a `OlmSessionError` if creating a
1055    /// session failed.
1056    ///
1057    /// # Arguments
1058    ///
1059    /// * `their_identity_key` - The other account's identity/curve25519 key.
1060    ///
1061    /// * `our_device_keys` - Our own `DeviceKeys`, including cross-signing
1062    ///   signatures if applicable, for embedding in encrypted messages.
1063    ///
1064    /// * `message` - A pre-key Olm message that was sent to us by the other
1065    ///   account.
1066    pub fn create_inbound_session(
1067        &mut self,
1068        their_identity_key: Curve25519PublicKey,
1069        our_device_keys: DeviceKeys,
1070        message: &PreKeyMessage,
1071    ) -> Result<InboundCreationResult, SessionCreationError> {
1072        Span::current().record("session_id", debug(message.session_id()));
1073        trace!("Creating a new Olm session from a pre-key message");
1074
1075        #[cfg(not(feature = "experimental-algorithms"))]
1076        let config = SessionConfig::version_1();
1077
1078        #[cfg(feature = "experimental-algorithms")]
1079        let config = SessionConfig::version_2();
1080
1081        let result = self.inner.create_inbound_session(config, their_identity_key, message)?;
1082        let now = SecondsSinceUnixEpoch::now();
1083        let session_id = result.session.session_id();
1084
1085        debug!(session=?result.session, "Decrypted an Olm message from a new Olm session");
1086
1087        let session = Session {
1088            inner: Arc::new(Mutex::new(result.session)),
1089            session_id: session_id.into(),
1090            sender_key: their_identity_key,
1091            our_device_keys,
1092            created_using_fallback_key: false,
1093            creation_time: now,
1094            last_use_time: now,
1095        };
1096
1097        let plaintext = String::from_utf8_lossy(&result.plaintext).to_string();
1098
1099        Ok(InboundCreationResult { session, plaintext })
1100    }
1101
1102    #[cfg(any(test, feature = "testing"))]
1103    #[allow(dead_code)]
1104    /// Testing only helper to create a session for the given Account
1105    pub async fn create_session_for_test_helper(
1106        &mut self,
1107        other: &mut Account,
1108    ) -> (Session, Session) {
1109        use ruma::events::dummy::ToDeviceDummyEventContent;
1110
1111        other.generate_one_time_keys(1);
1112        let one_time_map = other.signed_one_time_keys();
1113        let device = DeviceData::from_account(other);
1114
1115        let mut our_session =
1116            self.create_outbound_session(&device, &one_time_map, self.device_keys()).unwrap();
1117
1118        other.mark_keys_as_published();
1119
1120        let message = our_session
1121            .encrypt(&device, "m.dummy", ToDeviceDummyEventContent::new(), None)
1122            .await
1123            .unwrap()
1124            .deserialize()
1125            .unwrap();
1126
1127        #[cfg(feature = "experimental-algorithms")]
1128        let content = if let ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) = message {
1129            c
1130        } else {
1131            panic!("Invalid encrypted event algorithm {}", message.algorithm());
1132        };
1133
1134        #[cfg(not(feature = "experimental-algorithms"))]
1135        let ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(content) = message else {
1136            panic!("Invalid encrypted event algorithm {}", message.algorithm());
1137        };
1138
1139        let OlmMessage::PreKey(prekey) = content.ciphertext else {
1140            panic!("Wrong Olm message type");
1141        };
1142
1143        let our_device = DeviceData::from_account(self);
1144        let other_session = other
1145            .create_inbound_session(
1146                our_device.curve25519_key().unwrap(),
1147                other.device_keys(),
1148                &prekey,
1149            )
1150            .unwrap();
1151
1152        (our_session, other_session.session)
1153    }
1154
1155    async fn decrypt_olm_helper(
1156        &mut self,
1157        store: &Store,
1158        sender: &UserId,
1159        sender_key: Curve25519PublicKey,
1160        ciphertext: &OlmMessage,
1161        decryption_settings: &DecryptionSettings,
1162    ) -> OlmResult<OlmDecryptionInfo> {
1163        let message_hash = OlmMessageHash::new(sender_key, ciphertext);
1164
1165        match self
1166            .decrypt_and_parse_olm_message(
1167                store,
1168                sender,
1169                sender_key,
1170                ciphertext,
1171                decryption_settings,
1172            )
1173            .await
1174        {
1175            Ok((session, result)) => {
1176                Ok(OlmDecryptionInfo { session, message_hash, result, inbound_group_session: None })
1177            }
1178            Err(OlmError::SessionWedged(user_id, sender_key)) => {
1179                if store.is_message_known(&message_hash).await? {
1180                    info!(?sender_key, "An Olm message got replayed, decryption failed");
1181                    Err(OlmError::ReplayedMessage(user_id, sender_key))
1182                } else {
1183                    Err(OlmError::SessionWedged(user_id, sender_key))
1184                }
1185            }
1186            Err(e) => Err(e),
1187        }
1188    }
1189
1190    #[cfg(feature = "experimental-algorithms")]
1191    async fn decrypt_olm_v2(
1192        &mut self,
1193        store: &Store,
1194        sender: &UserId,
1195        content: &OlmV2Curve25519AesSha2Content,
1196        decryption_settings: &DecryptionSettings,
1197    ) -> OlmResult<OlmDecryptionInfo> {
1198        self.decrypt_olm_helper(
1199            store,
1200            sender,
1201            content.sender_key,
1202            &content.ciphertext,
1203            decryption_settings,
1204        )
1205        .await
1206    }
1207
1208    #[instrument(skip_all, fields(sender, sender_key = ?content.sender_key))]
1209    async fn decrypt_olm_v1(
1210        &mut self,
1211        store: &Store,
1212        sender: &UserId,
1213        content: &OlmV1Curve25519AesSha2Content,
1214        decryption_settings: &DecryptionSettings,
1215    ) -> OlmResult<OlmDecryptionInfo> {
1216        if content.recipient_key != self.static_data.identity_keys.curve25519 {
1217            warn!("Olm event doesn't contain a ciphertext for our key");
1218
1219            Err(EventError::MissingCiphertext.into())
1220        } else {
1221            Box::pin(self.decrypt_olm_helper(
1222                store,
1223                sender,
1224                content.sender_key,
1225                &content.ciphertext,
1226                decryption_settings,
1227            ))
1228            .await
1229        }
1230    }
1231
1232    #[instrument(skip_all, fields(algorithm = ?event.content.algorithm()))]
1233    pub(crate) async fn decrypt_to_device_event(
1234        &mut self,
1235        store: &Store,
1236        event: &EncryptedToDeviceEvent,
1237        decryption_settings: &DecryptionSettings,
1238    ) -> OlmResult<OlmDecryptionInfo> {
1239        trace!("Decrypting a to-device event");
1240
1241        match &event.content {
1242            ToDeviceEncryptedEventContent::OlmV1Curve25519AesSha2(c) => {
1243                self.decrypt_olm_v1(store, &event.sender, c, decryption_settings).await
1244            }
1245            #[cfg(feature = "experimental-algorithms")]
1246            ToDeviceEncryptedEventContent::OlmV2Curve25519AesSha2(c) => {
1247                self.decrypt_olm_v2(store, &event.sender, c, decryption_settings).await
1248            }
1249            ToDeviceEncryptedEventContent::Unknown(_) => {
1250                warn!(
1251                    "Error decrypting an to-device event, unsupported \
1252                    encryption algorithm"
1253                );
1254
1255                Err(EventError::UnsupportedAlgorithm.into())
1256            }
1257        }
1258    }
1259
1260    /// Handles a response to a /keys/upload request.
1261    pub fn receive_keys_upload_response(
1262        &mut self,
1263        response: &upload_keys::v3::Response,
1264    ) -> OlmResult<()> {
1265        if !self.shared() {
1266            debug!("Marking account as shared");
1267        }
1268        self.mark_as_shared();
1269
1270        debug!("Marking one-time keys as published");
1271        // First mark the current keys as published, as updating the key counts might
1272        // generate some new keys if we're still below the limit.
1273        self.mark_keys_as_published();
1274        self.update_key_counts(&response.one_time_key_counts, None);
1275
1276        Ok(())
1277    }
1278
1279    /// Try to decrypt an olm message, creating a new session if necessary.
1280    async fn decrypt_olm_message(
1281        &mut self,
1282        store: &Store,
1283        sender: &UserId,
1284        sender_key: Curve25519PublicKey,
1285        message: &OlmMessage,
1286    ) -> Result<(SessionType, String), OlmError> {
1287        let existing_sessions = store.get_sessions(&sender_key.to_base64()).await?;
1288
1289        match message {
1290            OlmMessage::Normal(_) => {
1291                let mut errors_by_olm_session = Vec::new();
1292
1293                if let Some(sessions) = existing_sessions {
1294                    // Try to decrypt the message using each Session we share with the
1295                    // given curve25519 sender key.
1296                    for session in sessions.lock().await.iter_mut() {
1297                        match session.decrypt(message).await {
1298                            Ok(p) => {
1299                                // success!
1300                                return Ok((SessionType::Existing(session.clone()), p));
1301                            }
1302
1303                            Err(e) => {
1304                                // An error here is completely normal, after all we don't know
1305                                // which session was used to encrypt a message.
1306                                // We keep hold of the error, so that if *all* sessions fail to
1307                                // decrypt, we can log something useful.
1308                                errors_by_olm_session.push((session.session_id().to_owned(), e));
1309                            }
1310                        }
1311                    }
1312                }
1313
1314                warn!(
1315                    ?errors_by_olm_session,
1316                    "Failed to decrypt a non-pre-key message with all available sessions"
1317                );
1318                Err(OlmError::SessionWedged(sender.to_owned(), sender_key))
1319            }
1320
1321            OlmMessage::PreKey(prekey_message) => {
1322                // First try to decrypt using an existing session.
1323                if let Some(sessions) = existing_sessions {
1324                    for session in sessions.lock().await.iter_mut() {
1325                        if prekey_message.session_id() != session.session_id() {
1326                            // wrong session
1327                            continue;
1328                        }
1329
1330                        if let Ok(p) = session.decrypt(message).await {
1331                            // success!
1332                            return Ok((SessionType::Existing(session.clone()), p));
1333                        }
1334
1335                        // The message was intended for this session, but we weren't able to
1336                        // decrypt it.
1337                        //
1338                        // There's no point trying any other sessions, nor should we try to
1339                        // create a new one since we have already previously created a `Session`
1340                        // with the same keys.
1341                        //
1342                        // (Attempts to create a new session would likely fail anyway since the
1343                        // corresponding one-time key would've been already used up in the
1344                        // previous session creation operation. The one exception where this
1345                        // would not be so is if the fallback key was used for creating the
1346                        // session in lieu of an OTK.)
1347
1348                        warn!(
1349                            session_id = session.session_id(),
1350                            "Failed to decrypt a pre-key message with the corresponding session"
1351                        );
1352
1353                        return Err(OlmError::SessionWedged(
1354                            session.our_device_keys.user_id.to_owned(),
1355                            session.sender_key(),
1356                        ));
1357                    }
1358                }
1359
1360                let device_keys = store.get_own_device().await?.as_device_keys().clone();
1361                let result =
1362                    match self.create_inbound_session(sender_key, device_keys, prekey_message) {
1363                        Ok(r) => r,
1364                        Err(e) => {
1365                            warn!(
1366                                "Failed to create a new Olm session from a pre-key message: {e:?}"
1367                            );
1368                            return Err(OlmError::SessionWedged(sender.to_owned(), sender_key));
1369                        }
1370                    };
1371
1372                // We need to add the new session to the session cache, otherwise
1373                // we might try to create the same session again.
1374                // TODO: separate the session cache from the storage so we only add
1375                // it to the cache but don't store it.
1376                let mut changes =
1377                    Changes { sessions: vec![result.session.clone()], ..Default::default() };
1378
1379                // Any new Olm session will bump the Olm wedging index for the
1380                // sender's device, if we have their device, which will cause us
1381                // to re-send existing Megolm sessions to them the next time we
1382                // use the session.  If we don't have their device, this means
1383                // that we haven't tried to send them any Megolm sessions yet,
1384                // so we don't need to worry about it.
1385                if let Some(device) = store.get_device_from_curve_key(sender, sender_key).await? {
1386                    let mut device_data = device.inner;
1387                    device_data.olm_wedging_index.increment();
1388
1389                    changes.devices =
1390                        DeviceChanges { changed: vec![device_data], ..Default::default() };
1391                }
1392
1393                store.save_changes(changes).await?;
1394
1395                Ok((SessionType::New(result.session), result.plaintext))
1396            }
1397        }
1398    }
1399
1400    /// Decrypt an Olm message, creating a new Olm session if necessary, and
1401    /// parse the result.
1402    #[instrument(skip(self, store), fields(session, session_id))]
1403    async fn decrypt_and_parse_olm_message(
1404        &mut self,
1405        store: &Store,
1406        sender: &UserId,
1407        sender_key: Curve25519PublicKey,
1408        message: &OlmMessage,
1409        decryption_settings: &DecryptionSettings,
1410    ) -> OlmResult<(SessionType, DecryptionResult)> {
1411        let (session, plaintext) =
1412            self.decrypt_olm_message(store, sender, sender_key, message).await?;
1413
1414        trace!("Successfully decrypted an Olm message");
1415
1416        match self
1417            .parse_decrypted_to_device_event(
1418                store,
1419                sender,
1420                sender_key,
1421                plaintext,
1422                decryption_settings,
1423            )
1424            .await
1425        {
1426            Ok(result) => Ok((session, result)),
1427            Err(e) => {
1428                // We might have created a new session but decryption might still
1429                // have failed, store it for the error case here, this is fine
1430                // since we don't expect this to happen often or at all.
1431                match session {
1432                    SessionType::New(s) | SessionType::Existing(s) => {
1433                        store.save_sessions(&[s]).await?;
1434                    }
1435                }
1436
1437                warn!(
1438                    error = ?e,
1439                    "A to-device message was successfully decrypted but \
1440                    parsing and checking the event fields failed"
1441                );
1442
1443                Err(e)
1444            }
1445        }
1446    }
1447
1448    /// Parse the decrypted plaintext as JSON and verify that it wasn't
1449    /// forwarded by a third party.
1450    ///
1451    /// These checks are mandated by the spec[1]:
1452    ///
1453    /// > Other properties are included in order to prevent an attacker from
1454    /// > publishing someone else's Curve25519 keys as their own and
1455    /// > subsequently claiming to have sent messages which they didn't.
1456    /// > sender must correspond to the user who sent the event, recipient to
1457    /// > the local user, and recipient_keys to the local Ed25519 key.
1458    ///
1459    /// # Arguments
1460    ///
1461    /// * `sender` -  The `sender` field from the top level of the received
1462    ///   event.
1463    /// * `sender_key` - The `sender_key` from the cleartext `content` of the
1464    ///   received event (which should also have been used to find or establish
1465    ///   the Olm session that was used to decrypt the event -- so it is
1466    ///   guaranteed to be correct).
1467    /// * `plaintext` - The decrypted content of the event.
1468    async fn parse_decrypted_to_device_event(
1469        &self,
1470        store: &Store,
1471        sender: &UserId,
1472        sender_key: Curve25519PublicKey,
1473        plaintext: String,
1474        decryption_settings: &DecryptionSettings,
1475    ) -> OlmResult<DecryptionResult> {
1476        let event: Box<AnyDecryptedOlmEvent> = serde_json::from_str(&plaintext)?;
1477        let identity_keys = &self.static_data.identity_keys;
1478
1479        if event.recipient() != self.static_data.user_id {
1480            Err(EventError::MismatchedSender(
1481                event.recipient().to_owned(),
1482                self.static_data.user_id.clone(),
1483            )
1484            .into())
1485        }
1486        // Check that the `sender` in the decrypted to-device event matches that at the
1487        // top level of the encrypted event.
1488        else if event.sender() != sender {
1489            Err(EventError::MismatchedSender(event.sender().to_owned(), sender.to_owned()).into())
1490        } else if identity_keys.ed25519 != event.recipient_keys().ed25519 {
1491            Err(EventError::MismatchedKeys(
1492                identity_keys.ed25519.into(),
1493                event.recipient_keys().ed25519.into(),
1494            )
1495            .into())
1496        } else {
1497            let sender_device = Self::get_event_sender_device(store, sender_key, &event).await?;
1498            let encryption_info = Self::get_olm_encryption_info(sender_key, sender, &sender_device);
1499
1500            let result = DecryptionResult {
1501                event,
1502                raw_event: Raw::from_json(RawJsonValue::from_string(plaintext)?),
1503                sender_key,
1504                encryption_info,
1505            };
1506
1507            // Return an error if the sender is unverified (and we care)
1508            if !self.is_from_verified_device_or_allowed_type(decryption_settings, &result) {
1509                Err(OlmError::UnverifiedSenderDevice)
1510            } else {
1511                // Sender is ok - return the decrypted event
1512                Ok(result)
1513            }
1514        }
1515    }
1516
1517    /// Look up the [`Device`] that sent us a successfully-decrypted event.
1518    ///
1519    /// We first look for the sender device in our store; if it is found then we
1520    /// return that (having checked that the keys match). If the device is
1521    /// not found in the store, we return the details
1522    /// from `sender_device_keys`, if present. If the device is not in the
1523    /// store, and the event lacks `sender_device_keys`, an error is returned.
1524    ///
1525    /// Also validates the `sender_device_keys` field, if present, regardless of
1526    /// whether it is used.
1527    ///
1528    /// `m.room_key` events are special-cased and return `None`: we look up
1529    /// their devices later on.
1530    async fn get_event_sender_device(
1531        store: &Store,
1532        sender_key: Curve25519PublicKey,
1533        event: &AnyDecryptedOlmEvent,
1534    ) -> OlmResult<Option<Device>> {
1535        // If the event contained sender_device_keys, check them now.
1536        // WARN: If you move or modify this check, ensure that the code below is still
1537        // valid. The processing of the historic room key bundle depends on this being
1538        // here.
1539        let sender_device_keys = Self::check_sender_device_keys(event, sender_key)?;
1540        if let AnyDecryptedOlmEvent::RoomKey(_) = event {
1541            // If this event is an `m.room_key` event, defer the check for
1542            // the Ed25519 key of the sender until we decrypt room events.
1543            // This ensures that we receive the room key even if we don't
1544            // have access to the device.
1545            return Ok(None);
1546        }
1547
1548        // MSC4268 requires room key bundle events to have a `sender_device_keys` field.
1549        // Enforce that now.
1550        if let AnyDecryptedOlmEvent::RoomKeyBundle(_) = event {
1551            sender_device_keys.ok_or(EventError::MissingSigningKey).inspect_err(|_| {
1552                warn!("The room key bundle was missing the sender device keys in the event")
1553            })?;
1554        }
1555
1556        // For event types other than `m.room_key`, we need to look up the device in the
1557        // database irrespective of whether the `sender_device_keys` field is
1558        // present in the event, because it may have been marked as "locally
1559        // trusted" in the database.
1560        let store_device = store.get_device_from_curve_key(event.sender(), sender_key).await?;
1561
1562        match (store_device, sender_device_keys) {
1563            // If the device is in the database, it had better have an Ed25519 key which
1564            // matches that in the event.
1565            (Some(device), _) => {
1566                let key = device.ed25519_key().ok_or(EventError::MissingSigningKey)?;
1567                if key != event.keys().ed25519 {
1568                    return Err(EventError::MismatchedKeys(
1569                        key.into(),
1570                        event.keys().ed25519.into(),
1571                    )
1572                    .into());
1573                }
1574                Ok(Some(device))
1575            }
1576
1577            (None, Some(sender_device_keys)) => {
1578                // We have already validated the signature on `sender_device_keys`, so this
1579                // try_into cannot fail.
1580                let sender_device_data = sender_device_keys.try_into().expect("Conversion of DeviceKeys to DeviceData failed despite the signature already having been checked");
1581                Ok(Some(store.wrap_device_data(sender_device_data).await?))
1582            }
1583
1584            (None, None) => Err(OlmError::EventError(EventError::MissingSigningKey)),
1585        }
1586    }
1587
1588    /// Return true if:
1589    ///
1590    /// * the sending device is verified, or
1591    /// * the event type is one of those we allow to be sent from unverified
1592    ///   devices, or
1593    /// * we are not in "exclude_insecure_devices" mode, so everything is
1594    ///   allowed.
1595    ///
1596    /// Return false if:
1597    ///
1598    /// * we are in "exclude_insecure_devices" mode AND the sending device is
1599    ///   unverified.
1600    fn is_from_verified_device_or_allowed_type(
1601        &self,
1602        decryption_settings: &DecryptionSettings,
1603        result: &DecryptionResult,
1604    ) -> bool {
1605        let event_type = result.event.event_type();
1606
1607        // If we're in "exclude insecure devices" mode, we prevent most
1608        // to-device events with unverified senders from being allowed
1609        // through here, but there are some exceptions:
1610        //
1611        // * m.room_key - we hold on to these until later, so if the sender becomes
1612        //   verified later we can still use the key.
1613        //
1614        // * m.room_key_request, m.room_key.withheld, m.key.verification.*,
1615        //   m.secret.request - these are allowed as plaintext events, so we also allow
1616        //   them encrypted from insecure devices. Note: the list of allowed types here
1617        //   should match with what is allowed in handle_to_device_event.
1618        match event_type {
1619            "m.room_key"
1620            | "m.room_key.withheld"
1621            | "m.room_key_request"
1622            | "m.secret.request"
1623            | "m.key.verification.key"
1624            | "m.key.verification.mac"
1625            | "m.key.verification.done"
1626            | "m.key.verification.ready"
1627            | "m.key.verification.start"
1628            | "m.key.verification.accept"
1629            | "m.key.verification.cancel"
1630            | "m.key.verification.request" => {
1631                // This is one of the exception types - we allow it even if the sender device is
1632                // not verified.
1633                true
1634            }
1635            _ => {
1636                // This is not an exception type - check for "exclude insecure devices" mode,
1637                // and whether the sender is verified.
1638                satisfies_sender_trust_requirement(
1639                    &result.encryption_info,
1640                    &decryption_settings.sender_device_trust_requirement,
1641                )
1642            }
1643        }
1644    }
1645
1646    /// Gets the EncryptionInfo for a successfully decrypted to-device message
1647    /// that have passed the mismatched sender_key/user_id validation.
1648    ///
1649    /// `sender_device` is optional because for some to-device messages we defer
1650    /// the check for the ed25519 key, in that case the
1651    /// `verification_state` will have a `MissingDevice` link problem.
1652    fn get_olm_encryption_info(
1653        sender_key: Curve25519PublicKey,
1654        sender_id: &UserId,
1655        sender_device: &Option<Device>,
1656    ) -> EncryptionInfo {
1657        let verification_state = sender_device
1658            .as_ref()
1659            .map(|device| {
1660                if device.is_verified() {
1661                    // The device is locally verified or signed by a verified user
1662                    VerificationState::Verified
1663                } else if device.is_cross_signed_by_owner() {
1664                    // The device is not verified, but it is signed by its owner
1665                    if device
1666                        .device_owner_identity
1667                        .as_ref()
1668                        .expect("A device cross-signed by the owner must have an owner identity")
1669                        .was_previously_verified()
1670                    {
1671                        VerificationState::Unverified(VerificationLevel::VerificationViolation)
1672                    } else {
1673                        VerificationState::Unverified(VerificationLevel::UnverifiedIdentity)
1674                    }
1675                } else {
1676                    // No identity or not signed
1677                    VerificationState::Unverified(VerificationLevel::UnsignedDevice)
1678                }
1679            })
1680            .unwrap_or(VerificationState::Unverified(VerificationLevel::None(
1681                DeviceLinkProblem::MissingDevice,
1682            )));
1683
1684        EncryptionInfo {
1685            sender: sender_id.to_owned(),
1686            sender_device: sender_device.as_ref().map(|d| d.device_id().to_owned()),
1687            forwarder: None,
1688            algorithm_info: AlgorithmInfo::OlmV1Curve25519AesSha2 {
1689                curve25519_public_key_base64: sender_key.to_base64(),
1690            },
1691            verification_state,
1692        }
1693    }
1694
1695    /// If the plaintext of the decrypted message includes a
1696    /// `sender_device_keys` property per [MSC4147], check that it is valid.
1697    ///
1698    /// In particular, we check that:
1699    ///
1700    ///  * The Curve25519 key in the `sender_device_keys` matches that used to
1701    ///    establish the Olm session that was used to decrypt the event.
1702    ///
1703    ///  * The `sender_device_keys` contains a valid self-signature by the
1704    ///    Ed25519 key in the device data.
1705    ///
1706    ///  * The Ed25519 key in the device data matches that in the `keys` field
1707    ///    in the event, for consistency and sanity.
1708    ///
1709    ///  * The `user_id` property in the `sender_device_keys` matches the event
1710    ///    sender.
1711    ///
1712    /// The first two checks are sufficient to bind together the Ed25519 and
1713    /// Curve25519 keys:
1714    ///
1715    ///  * Only the holder of the secret part of the Curve25519 key that was
1716    ///    used to construct the Olm session (the 'owner' of that key) can
1717    ///    encrypt the device data in that Olm session. By including the Ed25519
1718    ///    key in the device data, the owner of the Curve25519 key is claiming
1719    ///    ownership of the Ed25519 key.
1720    ///
1721    ///  * Only the owner of the Ed25519 key can construct the self-signature on
1722    ///    the device data. By including the Curve25519 key in the device data
1723    ///    and then signing it, the owner of the Ed25519 key is claiming
1724    ///    ownership of the Curve25519 key.
1725    ///
1726    ///  * Since we now have claims in both directions, the two key owners must
1727    ///    either be the same entity, or working in sufficiently close
1728    ///    collaboration that they can be treated as such.
1729    ///
1730    /// # Arguments
1731    ///
1732    /// * `event` - The decrypted and deserialized plaintext of the event.
1733    /// * `sender_key` - The Curve25519 key that the sender used to establish
1734    ///   the Olm session that was used to decrypt the event.
1735    ///
1736    /// # Returns
1737    ///
1738    /// A reference to the `sender_device_keys` in the event, if it exists and
1739    /// is valid.
1740    ///
1741    /// [MSC4147]: https://github.com/matrix-org/matrix-spec-proposals/pull/4147
1742    fn check_sender_device_keys(
1743        event: &AnyDecryptedOlmEvent,
1744        sender_key: Curve25519PublicKey,
1745    ) -> OlmResult<Option<&DeviceKeys>> {
1746        let Some(sender_device_keys) = event.sender_device_keys() else {
1747            return Ok(None);
1748        };
1749
1750        if sender_device_keys.user_id != event.sender() {
1751            warn!(
1752                "Received a to-device message with sender_device_keys with incorrect user_id: expected {:?}, got {:?}",
1753                event.sender(),
1754                sender_device_keys.user_id
1755            );
1756            return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1757        }
1758
1759        // Check the signature within the device_keys structure
1760        sender_device_keys.check_self_signature().map_err(|err| {
1761            warn!(
1762                "Received a to-device message with sender_device_keys with \
1763                 invalid signature: {err:?}",
1764            );
1765            OlmError::EventError(EventError::InvalidSenderDeviceKeys)
1766        })?;
1767
1768        // Check that the Ed25519 key in the sender_device_keys matches the `ed25519`
1769        // key in the `keys` field in the event.
1770        if sender_device_keys.ed25519_key() != Some(event.keys().ed25519) {
1771            warn!(
1772                "Received a to-device message with sender_device_keys with incorrect \
1773                 ed25519 key: expected {:?}, got {:?}",
1774                event.keys().ed25519,
1775                sender_device_keys.ed25519_key(),
1776            );
1777            return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1778        }
1779
1780        // Check that the Curve25519 key in the sender_device_keys matches the key that
1781        // was used for the Olm session.
1782        if sender_device_keys.curve25519_key() != Some(sender_key) {
1783            warn!(
1784                "Received a to-device message with sender_device_keys with incorrect \
1785                 curve25519 key: expected {sender_key:?}, got {:?}",
1786                sender_device_keys.curve25519_key(),
1787            );
1788            return Err(OlmError::EventError(EventError::InvalidSenderDeviceKeys));
1789        }
1790
1791        Ok(Some(sender_device_keys))
1792    }
1793
1794    /// Internal use only.
1795    ///
1796    /// Cloning should only be done for testing purposes or when we are certain
1797    /// that we don't want the inner state to be shared.
1798    #[doc(hidden)]
1799    pub fn deep_clone(&self) -> Self {
1800        // `vodozemac::Account` isn't really cloneable, but... Don't tell anyone.
1801        Self::from_pickle(self.pickle()).unwrap()
1802    }
1803}
1804
1805impl PartialEq for Account {
1806    fn eq(&self, other: &Self) -> bool {
1807        self.identity_keys() == other.identity_keys() && self.shared() == other.shared()
1808    }
1809}
1810
1811/// Calculate the shared history flag from the history visibility as defined in
1812/// [MSC3061]
1813///
1814/// The MSC defines that the shared history flag should be set to true when the
1815/// history visibility setting is set to `shared` or `world_readable`:
1816///
1817/// > A room key is flagged as having been used for shared history when it was
1818/// > used to encrypt a message while the room's history visibility setting
1819/// > was set to world_readable or shared.
1820///
1821/// In all other cases, even if we encounter a custom history visibility, we
1822/// should return false:
1823///
1824/// > If the client does not have an m.room.history_visibility state event for
1825/// > the room, or its value is not understood, the client should treat it as if
1826/// > its value is joined for the purposes of determining whether the key is
1827/// > used for shared history.
1828///
1829/// [MSC3061]: https://github.com/matrix-org/matrix-spec-proposals/pull/3061
1830pub(crate) fn shared_history_from_history_visibility(
1831    history_visibility: &HistoryVisibility,
1832) -> bool {
1833    match history_visibility {
1834        HistoryVisibility::Shared | HistoryVisibility::WorldReadable => true,
1835        HistoryVisibility::Invited | HistoryVisibility::Joined | _ => false,
1836    }
1837}
1838
1839/// Expand the pickle key for an older version of dehydrated devices
1840///
1841/// The `org.matrix.msc3814.v1.olm` variant of dehydrated devices used the
1842/// libolm Account pickle format for the dehydrated device. The libolm pickle
1843/// encryption scheme uses HKDF to deterministically expand an input key
1844/// material, usually 32 bytes, into a AES key, MAC key, and the initialization
1845/// vector (IV).
1846///
1847/// This means that the same input key material will always end up producing the
1848/// same AES key, and IV.
1849///
1850/// This encryption scheme is used in the Olm double ratchet and was designed to
1851/// minimize the size of the ciphertext. As a tradeof, it requires a unique
1852/// input key material for each plaintext that gets encrypted, otherwise IV
1853/// reuse happens.
1854///
1855/// To combat the IV reuse, we're going to create a per-dehydrated-device unique
1856/// pickle key by expanding the key itself with the device ID used as the salt.
1857fn expand_legacy_pickle_key(key: &[u8; 32], device_id: &DeviceId) -> Box<[u8; 32]> {
1858    let kdf: Hkdf<Sha256> = Hkdf::new(Some(device_id.as_bytes()), key);
1859    let mut key = Box::new([0u8; 32]);
1860
1861    kdf.expand(b"dehydrated-device-pickle-key", key.as_mut_slice())
1862        .expect("We should be able to expand the 32 byte pickle key");
1863
1864    key
1865}
1866
1867/// Does the to-device event satisfy the sender trust requirement from the
1868/// decryption settings?
1869fn satisfies_sender_trust_requirement(
1870    encryption_info: &EncryptionInfo,
1871    trust_requirement: &TrustRequirement,
1872) -> bool {
1873    trace!(
1874        verification_state = ?encryption_info.verification_state,
1875        ?trust_requirement, "check_to_device_sender_trust_requirement",
1876    );
1877
1878    match (&encryption_info.verification_state, trust_requirement) {
1879        // If we don't care, everything is OK.
1880        (_, TrustRequirement::Untrusted) => true,
1881
1882        // Verified is OK whatever our requirements are.
1883        (VerificationState::Verified, _) => true,
1884
1885        // We do care, and we are not fully verified: check more deeply.
1886        // (Note that for to-device messages the legacy trust requirement is not relevant.)
1887        (
1888            VerificationState::Unverified(verification_level),
1889            TrustRequirement::CrossSignedOrLegacy | TrustRequirement::CrossSigned,
1890        ) => match verification_level {
1891            // The device is signed but the identity is only pinned - this is fine.
1892            VerificationLevel::UnverifiedIdentity => true,
1893
1894            // The device is unsigned or missing, or the user is in verification violation,
1895            // or the sender is mismatched: this is not fine.
1896            VerificationLevel::UnsignedDevice
1897            | VerificationLevel::None(_)
1898            | VerificationLevel::VerificationViolation
1899            | VerificationLevel::MismatchedSender => false,
1900        },
1901    }
1902}
1903
1904#[cfg(test)]
1905mod tests {
1906    use std::{
1907        collections::{BTreeMap, BTreeSet},
1908        ops::Deref,
1909        time::Duration,
1910    };
1911
1912    use anyhow::Result;
1913    use matrix_sdk_test::async_test;
1914    use ruma::{
1915        DeviceId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OneTimeKeyId, UserId, device_id,
1916        events::room::history_visibility::HistoryVisibility, room_id, user_id,
1917    };
1918    use serde_json::json;
1919
1920    use super::Account;
1921    use crate::{
1922        DeviceData, EncryptionSettings,
1923        olm::{SignedJsonObject, account::shared_history_from_history_visibility},
1924        types::{DeviceKeys, SignedKey},
1925    };
1926
1927    fn user_id() -> &'static UserId {
1928        user_id!("@alice:localhost")
1929    }
1930
1931    fn device_id() -> &'static DeviceId {
1932        device_id!("DEVICEID")
1933    }
1934
1935    #[test]
1936    fn test_one_time_key_creation() -> Result<()> {
1937        let mut account = Account::with_device_id(user_id(), device_id());
1938
1939        let (_, one_time_keys, _) = account.keys_for_upload();
1940        assert!(!one_time_keys.is_empty());
1941
1942        let (_, second_one_time_keys, _) = account.keys_for_upload();
1943        assert!(!second_one_time_keys.is_empty());
1944
1945        let one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1946            one_time_keys.keys().map(Deref::deref).collect();
1947        let second_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1948            second_one_time_keys.keys().map(Deref::deref).collect();
1949
1950        assert_eq!(one_time_key_ids, second_one_time_key_ids);
1951
1952        account.mark_keys_as_published();
1953        account.update_uploaded_key_count(50);
1954        account.generate_one_time_keys_if_needed();
1955
1956        let (_, third_one_time_keys, _) = account.keys_for_upload();
1957        assert!(third_one_time_keys.is_empty());
1958
1959        account.update_uploaded_key_count(0);
1960        account.generate_one_time_keys_if_needed();
1961
1962        let (_, fourth_one_time_keys, _) = account.keys_for_upload();
1963        assert!(!fourth_one_time_keys.is_empty());
1964
1965        let fourth_one_time_key_ids: BTreeSet<&OneTimeKeyId> =
1966            fourth_one_time_keys.keys().map(Deref::deref).collect();
1967
1968        assert_ne!(one_time_key_ids, fourth_one_time_key_ids);
1969        Ok(())
1970    }
1971
1972    #[test]
1973    fn test_fallback_key_creation() -> Result<()> {
1974        let mut account = Account::with_device_id(user_id(), device_id());
1975
1976        let (_, _, fallback_keys) = account.keys_for_upload();
1977
1978        // We don't create fallback keys since we don't know if the server
1979        // supports them, we need to receive a sync response to decide if we're
1980        // going to create them or not.
1981        assert!(
1982            fallback_keys.is_empty(),
1983            "We should not upload fallback keys until we know if the server supports them."
1984        );
1985
1986        let one_time_keys = BTreeMap::from([(OneTimeKeyAlgorithm::SignedCurve25519, 50u8.into())]);
1987
1988        // A `None` here means that the server doesn't support fallback keys, no
1989        // fallback key gets uploaded.
1990        account.update_key_counts(&one_time_keys, None);
1991        let (_, _, fallback_keys) = account.keys_for_upload();
1992        assert!(
1993            fallback_keys.is_empty(),
1994            "We should not upload a fallback key if we're certain that the server doesn't support \
1995             them."
1996        );
1997
1998        // The empty array means that the server supports fallback keys but
1999        // there isn't a unused fallback key on the server. This time we upload
2000        // a fallback key.
2001        let unused_fallback_keys = &[];
2002        account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()));
2003        let (_, _, fallback_keys) = account.keys_for_upload();
2004        assert!(
2005            !fallback_keys.is_empty(),
2006            "We should upload the initial fallback key if the server supports them."
2007        );
2008        account.mark_keys_as_published();
2009
2010        // There's no unused fallback key on the server, but our initial fallback key
2011        // did not yet expire.
2012        let unused_fallback_keys = &[];
2013        account.update_key_counts(&one_time_keys, Some(unused_fallback_keys.as_ref()));
2014        let (_, _, fallback_keys) = account.keys_for_upload();
2015        assert!(
2016            fallback_keys.is_empty(),
2017            "We should not upload new fallback keys unless our current fallback key expires."
2018        );
2019
2020        let fallback_key_timestamp =
2021            account.fallback_creation_timestamp.unwrap().to_system_time().unwrap()
2022                - Duration::from_secs(3600 * 24 * 30);
2023
2024        account.fallback_creation_timestamp =
2025            Some(MilliSecondsSinceUnixEpoch::from_system_time(fallback_key_timestamp).unwrap());
2026
2027        account.update_key_counts(&one_time_keys, None);
2028        let (_, _, fallback_keys) = account.keys_for_upload();
2029        assert!(
2030            !fallback_keys.is_empty(),
2031            "Now that our fallback key has expired, we should try to upload a new one, even if the \
2032             server supposedly doesn't support fallback keys anymore"
2033        );
2034
2035        Ok(())
2036    }
2037
2038    #[test]
2039    fn test_fallback_key_signing() -> Result<()> {
2040        let key = vodozemac::Curve25519PublicKey::from_base64(
2041            "7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs",
2042        )?;
2043        let account = Account::with_device_id(user_id(), device_id());
2044
2045        let key = account.sign_key(key, true);
2046
2047        let canonical_key = key.to_canonical_json()?;
2048
2049        assert_eq!(
2050            canonical_key,
2051            "{\"fallback\":true,\"key\":\"7PUPP6Ijt5R8qLwK2c8uK5hqCNF9tOzWYgGaAay5JBs\"}"
2052        );
2053
2054        account
2055            .has_signed_raw(key.signatures(), &canonical_key)
2056            .expect("Couldn't verify signature");
2057
2058        let device = DeviceData::from_account(&account);
2059        device.verify_one_time_key(&key).expect("The device can verify its own signature");
2060
2061        Ok(())
2062    }
2063
2064    #[test]
2065    fn test_account_and_device_creation_timestamp() -> Result<()> {
2066        let now = MilliSecondsSinceUnixEpoch::now();
2067        let account = Account::with_device_id(user_id(), device_id());
2068        let then = MilliSecondsSinceUnixEpoch::now();
2069
2070        assert!(account.creation_local_time() >= now);
2071        assert!(account.creation_local_time() <= then);
2072
2073        let device = DeviceData::from_account(&account);
2074        assert_eq!(account.creation_local_time(), device.first_time_seen_ts());
2075
2076        Ok(())
2077    }
2078
2079    #[async_test]
2080    async fn test_fallback_key_signature_verification() -> Result<()> {
2081        let fallback_key = json!({
2082            "fallback": true,
2083            "key": "XPFqtLvBepBmW6jSAbBuJbhEpprBhQOX1IjUu+cnMF4",
2084            "signatures": {
2085                "@dkasak_c:matrix.org": {
2086                    "ed25519:EXPDYDPWZH": "RJCBMJPL5hvjxgq8rmLmqkNOuPsaan7JeL1wsE+gW6R39G894lb2sBmzapHeKCn/KFjmkonPLkICApRDS+zyDw"
2087                }
2088            }
2089        });
2090
2091        let device_keys = json!({
2092            "algorithms": [
2093                "m.olm.v1.curve25519-aes-sha2",
2094                "m.megolm.v1.aes-sha2"
2095            ],
2096            "device_id": "EXPDYDPWZH",
2097            "keys": {
2098                "curve25519:EXPDYDPWZH": "k7f3igo0Vrdm88JSSA5d3OCuUfHYELChB2b57aOROB8",
2099                "ed25519:EXPDYDPWZH": "GdjYI8fxs175gSpYRJkyN6FRfvcyTsNOhJ2OR/Ggp+E"
2100            },
2101            "signatures": {
2102                "@dkasak_c:matrix.org": {
2103                    "ed25519:EXPDYDPWZH": "kzrtfQMbJXWXQ1uzhybtwFnGk0JJBS4Mg8VPMusMu6U8MPJccwoHVZKo5+owuHTzIodI+GZYqLmMSzvfvsChAA"
2104                }
2105            },
2106            "user_id": "@dkasak_c:matrix.org",
2107            "unsigned": {}
2108        });
2109
2110        let device_keys: DeviceKeys = serde_json::from_value(device_keys).unwrap();
2111        let device = DeviceData::try_from(&device_keys).unwrap();
2112        let fallback_key: SignedKey = serde_json::from_value(fallback_key).unwrap();
2113
2114        device
2115            .verify_one_time_key(&fallback_key)
2116            .expect("The fallback key should pass the signature verification");
2117
2118        Ok(())
2119    }
2120
2121    #[test]
2122    fn test_shared_history_flag_from_history_visibility() {
2123        assert!(
2124            shared_history_from_history_visibility(&HistoryVisibility::WorldReadable),
2125            "The world readable visibility should set the shared history flag to true"
2126        );
2127
2128        assert!(
2129            shared_history_from_history_visibility(&HistoryVisibility::Shared),
2130            "The shared visibility should set the shared history flag to true"
2131        );
2132
2133        assert!(
2134            !shared_history_from_history_visibility(&HistoryVisibility::Joined),
2135            "The joined visibility should set the shared history flag to false"
2136        );
2137
2138        assert!(
2139            !shared_history_from_history_visibility(&HistoryVisibility::Invited),
2140            "The invited visibility should set the shared history flag to false"
2141        );
2142
2143        let visibility = HistoryVisibility::from("custom_visibility");
2144        assert!(
2145            !shared_history_from_history_visibility(&visibility),
2146            "A custom visibility should set the shared history flag to false"
2147        );
2148    }
2149
2150    #[async_test]
2151    async fn test_shared_history_set_when_creating_group_sessions() {
2152        let account = Account::new(user_id());
2153        let room_id = room_id!("!room:id");
2154        let settings = EncryptionSettings {
2155            history_visibility: HistoryVisibility::Shared,
2156            ..Default::default()
2157        };
2158
2159        let (_, session) = account
2160            .create_group_session_pair(room_id, settings, Default::default())
2161            .await
2162            .expect("We should be able to create a group session pair");
2163
2164        assert!(
2165            session.shared_history(),
2166            "The shared history flag should have been set when we created the new session"
2167        );
2168    }
2169}