matrix_sdk_crypto/olm/group_sessions/
sender_data_finder.rs

1// Copyright 2024 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 ruma::UserId;
16use vodozemac::Curve25519PublicKey;
17
18use super::{InboundGroupSession, SenderData};
19use crate::{
20    error::MismatchedIdentityKeysError, store::Store, types::events::olm_v1::DecryptedRoomKeyEvent,
21    CryptoStoreError, Device, DeviceData, MegolmError, OlmError, SignatureError,
22};
23
24/// Temporary struct that is used to look up [`SenderData`] based on the
25/// information supplied in
26/// [`crate::types::events::olm_v1::DecryptedRoomKeyEvent`].
27///
28/// # Algorithm
29///
30/// When we receive a to-device message establishing a megolm session (i.e. when
31/// [`crate::machine::OlmMachine::add_room_key`] is called):
32///
33/// ┌───────────────────────────────────────────────────────────────────┐
34/// │ A (start - we have a to-device message containing a room key)     │
35/// └───────────────────────────────────────────────────────────────────┘
36///                                     │
37///   __________________________________▼______________________________
38///  ╱                                                                 ╲
39/// ╱ Does the to-device message contain the device_keys property from  ╲yes
40/// ╲ MSC4147?                                                          ╱ │
41///  ╲_________________________________________________________________╱  │
42///                                     │ no                              │
43///                                     ▼                                 │
44/// ┌───────────────────────────────────────────────────────────────────┐ │
45/// │ B (there are no device keys in the to-device message)             │ │
46/// │                                                                   │ │
47/// │ We need to find the device details.                               │ │
48/// └───────────────────────────────────────────────────────────────────┘ │
49///                                     │                                 │
50///   __________________________________▼______________________________   │
51///  ╱                                                                 ╲  │
52/// ╱ Does the store contain a device whose curve key matches the       ╲ ▼
53/// ╲ sender of the to-device message?                                  ╱yes
54///  ╲_________________________________________________________________╱  │
55///                                     │ no                              │
56///                                     ▼                                 │
57/// ╭───────────────────────────────────────────────────────────────────╮ │
58/// │ C (we don't know the sending device)                              │ │
59/// │                                                                   │ │
60/// │ Give up: we have no sender info for this room key.                │ │
61/// ╰───────────────────────────────────────────────────────────────────╯ │
62///                                     ┌─────────────────────────────────┘
63///                                     ▼
64/// ┌───────────────────────────────────────────────────────────────────┐
65/// │ D (we have the device)                                            │
66/// └───────────────────────────────────────────────────────────────────┘
67///                                     │
68///   __________________________________▼______________________________
69///  ╱                                                                 ╲
70/// ╱ Is the session owned by the device?                               ╲yes
71/// ╲___________________________________________________________________╱ │
72///                                     │ no                              │
73///                                     ▼                                 │
74/// ╭───────────────────────────────────────────────────────────────────╮ │
75/// │ E (the device does not own the session)                           │ │
76/// │                                                                   │ │
77/// │ Give up: something is wrong with the session.                     │ │
78/// ╰───────────────────────────────────────────────────────────────────╯ │
79///                                     ┌─────────────────────────────────┘
80///   __________________________________▼______________________________
81///  ╱                                                                 ╲
82/// ╱ Is the device cross-signed by the sender?                         ╲yes
83/// ╲___________________________________________________________________╱ │
84///                                     │ no                              │
85///                                     ▼                                 │
86/// ┌───────────────────────────────────────────────────────────────────┐ │
87/// │ F (we have device keys, but they are not signed by the sender)    │ │
88/// │                                                                   │ │
89/// │ Store the device with the session, in case we can confirm it      │ │
90/// │ later.                                                            │ │
91/// ╰───────────────────────────────────────────────────────────────────╯ │
92///                                     ┌─────────────────────────────────┘
93///                                     ▼
94/// ┌───────────────────────────────────────────────────────────────────┐
95/// │ G (device is cross-signed by the sender)                          │
96/// └───────────────────────────────────────────────────────────────────┘
97///                                     │
98///   __________________________________▼______________________________
99///  ╱                                                                 ╲
100/// ╱ Does the cross-signing key match that used                        ╲yes
101/// ╲ to sign the device?                                               ╱ │
102///  ╲_________________________________________________________________╱  │
103///                                     │ no                              │
104///                                     ▼                                 │
105/// ╭───────────────────────────────────────────────────────────────────╮ │
106/// │ Store the device with the session, in case we get the             │ │
107/// │ right cross-signing key later.                                    │ │
108/// ╰───────────────────────────────────────────────────────────────────╯ │
109///                                     ┌─────────────────────────────────┘
110///                                     ▼
111/// ┌───────────────────────────────────────────────────────────────────┐
112/// │ H (cross-signing key matches that used to sign the device!)       │
113/// │                                                                   │
114/// │ Look up the user_id and master_key for the user sending the       │
115/// │ to-device message.                                                │
116/// │                                                                   │
117/// │ Decide the master_key trust level based on whether we have        │
118/// │ verified this user.                                               │
119/// │                                                                   │
120/// │ Store this information with the session.                          │
121/// ╰───────────────────────────────────────────────────────────────────╯
122///
123/// Note: the sender data may become out-of-date if we later verify the user. We
124/// have no plans to update it if so.
125pub(crate) struct SenderDataFinder<'a> {
126    store: &'a Store,
127    session: &'a InboundGroupSession,
128}
129
130impl<'a> SenderDataFinder<'a> {
131    /// Find the device associated with the to-device message used to
132    /// create the InboundGroupSession we are about to create, and decide
133    /// whether we trust the sender.
134    pub(crate) async fn find_using_event(
135        store: &'a Store,
136        sender_curve_key: Curve25519PublicKey,
137        room_key_event: &'a DecryptedRoomKeyEvent,
138        session: &'a InboundGroupSession,
139    ) -> Result<SenderData, SessionDeviceKeysCheckError> {
140        let finder = Self { store, session };
141        finder.have_event(sender_curve_key, room_key_event).await
142    }
143
144    /// Use the supplied device data to decide whether we trust the sender.
145    pub(crate) async fn find_using_device_data(
146        store: &'a Store,
147        device_data: DeviceData,
148        session: &'a InboundGroupSession,
149    ) -> Result<SenderData, SessionDeviceCheckError> {
150        let finder = Self { store, session };
151        finder.have_device_data(device_data).await
152    }
153
154    /// Find the device using the curve key provided, and decide whether we
155    /// trust the sender.
156    pub(crate) async fn find_using_curve_key(
157        store: &'a Store,
158        sender_curve_key: Curve25519PublicKey,
159        sender_user_id: &'a UserId,
160        session: &'a InboundGroupSession,
161    ) -> Result<SenderData, SessionDeviceCheckError> {
162        let finder = Self { store, session };
163        finder.search_for_device(sender_curve_key, sender_user_id).await
164    }
165
166    /// Step A (start - we have a to-device message containing a room key)
167    async fn have_event(
168        &self,
169        sender_curve_key: Curve25519PublicKey,
170        room_key_event: &'a DecryptedRoomKeyEvent,
171    ) -> Result<SenderData, SessionDeviceKeysCheckError> {
172        // Does the to-device message contain the device_keys property from MSC4147?
173        if let Some(sender_device_keys) = &room_key_event.sender_device_keys {
174            // Yes: use the device keys to continue.
175
176            // Validate the signature of the DeviceKeys supplied. (We've actually already
177            // done this when decrypting the event, but doing it again here is
178            // relatively harmless and is the easiest way of getting hold of a
179            // DeviceData so that we can follow the rest of this logic).
180            let sender_device_data = DeviceData::try_from(sender_device_keys)?;
181            Ok(self.have_device_data(sender_device_data).await?)
182        } else {
183            // No: look for the device in the store
184            Ok(self.search_for_device(sender_curve_key, &room_key_event.sender).await?)
185        }
186    }
187
188    /// Step B (there are no device keys in the to-device message)
189    async fn search_for_device(
190        &self,
191        sender_curve_key: Curve25519PublicKey,
192        sender_user_id: &UserId,
193    ) -> Result<SenderData, SessionDeviceCheckError> {
194        // Does the locally-cached (in the store) devices list contain a device with the
195        // curve key of the sender of the to-device message?
196        if let Some(sender_device) =
197            self.store.get_device_from_curve_key(sender_user_id, sender_curve_key).await?
198        {
199            // Yes: use the device to continue
200            self.have_device(sender_device)
201        } else {
202            // Step C (we don't know the sending device)
203            //
204            // We have no device data for this session so we can't continue in the "fast
205            // lane" (blocking sync).
206            let sender_data = SenderData::UnknownDevice {
207                // This is not a legacy session since we did attempt to look
208                // up its sender data at the time of reception.
209                legacy_session: false,
210                owner_check_failed: false,
211            };
212            Ok(sender_data)
213        }
214    }
215
216    async fn have_device_data(
217        &self,
218        sender_device_data: DeviceData,
219    ) -> Result<SenderData, SessionDeviceCheckError> {
220        let sender_device = self.store.wrap_device_data(sender_device_data).await?;
221        self.have_device(sender_device)
222    }
223
224    /// Step D (we have a device)
225    ///
226    /// Returns Err if the device does not own the session.
227    fn have_device(&self, sender_device: Device) -> Result<SenderData, SessionDeviceCheckError> {
228        // Is the session owned by the device?
229        let device_is_owner = sender_device.is_owner_of_session(self.session)?;
230
231        if !device_is_owner {
232            // Step E (the device does not own the session)
233            // Give up: something is wrong with the session.
234            Ok(SenderData::UnknownDevice { legacy_session: false, owner_check_failed: true })
235        } else {
236            // Steps F, G, and H: we have a device, which may or may not be signed by the
237            // sender.
238            Ok(SenderData::from_device(&sender_device))
239        }
240    }
241}
242
243#[derive(Debug)]
244pub(crate) enum SessionDeviceCheckError {
245    CryptoStoreError(CryptoStoreError),
246    MismatchedIdentityKeys(MismatchedIdentityKeysError),
247}
248
249impl From<CryptoStoreError> for SessionDeviceCheckError {
250    fn from(e: CryptoStoreError) -> Self {
251        Self::CryptoStoreError(e)
252    }
253}
254
255impl From<MismatchedIdentityKeysError> for SessionDeviceCheckError {
256    fn from(e: MismatchedIdentityKeysError) -> Self {
257        Self::MismatchedIdentityKeys(e)
258    }
259}
260
261impl From<SessionDeviceCheckError> for OlmError {
262    fn from(e: SessionDeviceCheckError) -> Self {
263        match e {
264            SessionDeviceCheckError::CryptoStoreError(e) => e.into(),
265            SessionDeviceCheckError::MismatchedIdentityKeys(e) => {
266                OlmError::SessionCreation(e.into())
267            }
268        }
269    }
270}
271
272impl From<SessionDeviceCheckError> for MegolmError {
273    fn from(e: SessionDeviceCheckError) -> Self {
274        match e {
275            SessionDeviceCheckError::CryptoStoreError(e) => e.into(),
276            SessionDeviceCheckError::MismatchedIdentityKeys(e) => e.into(),
277        }
278    }
279}
280
281#[derive(Debug)]
282pub(crate) enum SessionDeviceKeysCheckError {
283    CryptoStoreError(CryptoStoreError),
284    MismatchedIdentityKeys(MismatchedIdentityKeysError),
285    SignatureError(SignatureError),
286}
287
288impl From<CryptoStoreError> for SessionDeviceKeysCheckError {
289    fn from(e: CryptoStoreError) -> Self {
290        Self::CryptoStoreError(e)
291    }
292}
293
294impl From<MismatchedIdentityKeysError> for SessionDeviceKeysCheckError {
295    fn from(e: MismatchedIdentityKeysError) -> Self {
296        Self::MismatchedIdentityKeys(e)
297    }
298}
299
300impl From<SignatureError> for SessionDeviceKeysCheckError {
301    fn from(e: SignatureError) -> Self {
302        Self::SignatureError(e)
303    }
304}
305
306impl From<SessionDeviceCheckError> for SessionDeviceKeysCheckError {
307    fn from(e: SessionDeviceCheckError) -> Self {
308        match e {
309            SessionDeviceCheckError::CryptoStoreError(e) => Self::CryptoStoreError(e),
310            SessionDeviceCheckError::MismatchedIdentityKeys(e) => Self::MismatchedIdentityKeys(e),
311        }
312    }
313}
314
315impl From<SessionDeviceKeysCheckError> for OlmError {
316    fn from(e: SessionDeviceKeysCheckError) -> Self {
317        match e {
318            SessionDeviceKeysCheckError::CryptoStoreError(e) => e.into(),
319            SessionDeviceKeysCheckError::MismatchedIdentityKeys(e) => {
320                OlmError::SessionCreation(e.into())
321            }
322            SessionDeviceKeysCheckError::SignatureError(e) => OlmError::SessionCreation(e.into()),
323        }
324    }
325}
326
327#[cfg(test)]
328mod tests {
329    use std::{ops::Deref as _, sync::Arc};
330
331    use assert_matches2::assert_let;
332    use matrix_sdk_test::async_test;
333    use ruma::{device_id, room_id, user_id, DeviceId, OwnedUserId, RoomId, UserId};
334    use tokio::sync::Mutex;
335    use vodozemac::{megolm::SessionKey, Curve25519PublicKey, Ed25519PublicKey};
336
337    use super::SenderDataFinder;
338    use crate::{
339        error::MismatchedIdentityKeysError,
340        machine::test_helpers::{
341            create_signed_device_of_unverified_user, create_unsigned_device,
342            sign_user_identity_data,
343        },
344        olm::{
345            group_sessions::sender_data_finder::SessionDeviceKeysCheckError, InboundGroupSession,
346            KnownSenderData, PrivateCrossSigningIdentity, SenderData,
347        },
348        store::{types::Changes, CryptoStoreWrapper, MemoryStore, Store},
349        types::{
350            events::{
351                olm_v1::DecryptedRoomKeyEvent,
352                room_key::{MegolmV1AesSha2Content, RoomKeyContent},
353            },
354            EventEncryptionAlgorithm,
355        },
356        verification::VerificationMachine,
357        Account, Device, OtherUserIdentityData, OwnUserIdentityData, UserIdentityData,
358    };
359
360    impl<'a> SenderDataFinder<'a> {
361        fn new(store: &'a Store, session: &'a InboundGroupSession) -> Self {
362            Self { store, session }
363        }
364    }
365
366    #[async_test]
367    async fn test_providing_no_device_data_returns_sender_data_with_no_device_info() {
368        // Given that the device is not in the store and the initial event has no device
369        // info
370        let setup = TestSetup::new(TestOptions::new()).await;
371        let finder = SenderDataFinder::new(&setup.store, &setup.session);
372
373        // When we try to find sender data
374        let sender_data = finder
375            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
376            .await
377            .unwrap();
378
379        // Then we get back no useful information at all
380        assert_let!(SenderData::UnknownDevice { legacy_session, owner_check_failed } = sender_data);
381
382        assert!(!legacy_session);
383        assert!(!owner_check_failed);
384    }
385
386    #[async_test]
387    async fn test_if_the_todevice_event_contains_device_info_it_is_captured() {
388        // Given that the signed device keys are in the event
389        let setup =
390            TestSetup::new(TestOptions::new().device_is_signed().event_contains_device_keys())
391                .await;
392        let finder = SenderDataFinder::new(&setup.store, &setup.session);
393
394        // When we try to find sender data
395        let sender_data = finder
396            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
397            .await
398            .unwrap();
399
400        // Then we get back the device keys that were in the event
401        assert_let!(SenderData::DeviceInfo { device_keys, legacy_session } = sender_data);
402        assert_eq!(&device_keys, setup.sender_device.as_device_keys());
403        assert!(!legacy_session);
404    }
405
406    #[async_test]
407    async fn test_picks_up_device_info_from_the_store_if_missing_from_the_todevice_event() {
408        // Given that the device keys are not in the event but the device is in the
409        // store
410        let setup =
411            TestSetup::new(TestOptions::new().store_contains_device().device_is_signed()).await;
412        let finder = SenderDataFinder::new(&setup.store, &setup.session);
413
414        // When we try to find sender data
415        let sender_data = finder
416            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
417            .await
418            .unwrap();
419
420        // Then we get back the device keys that were in the store
421        assert_let!(SenderData::DeviceInfo { device_keys, legacy_session } = sender_data);
422        assert_eq!(&device_keys, setup.sender_device.as_device_keys());
423        assert!(!legacy_session);
424    }
425
426    #[async_test]
427    async fn test_adds_device_info_even_if_it_is_not_signed() {
428        // Given that the the device is in the store
429        // But it is not signed
430        let setup = TestSetup::new(TestOptions::new().store_contains_device()).await;
431        let finder = SenderDataFinder::new(&setup.store, &setup.session);
432
433        // When we try to find sender data
434        let sender_data = finder
435            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
436            .await
437            .unwrap();
438
439        // Then we store the device info even though it is useless, in case we want to
440        // check it matches up later.
441        assert_let!(SenderData::DeviceInfo { device_keys, legacy_session } = sender_data);
442        assert_eq!(&device_keys, setup.sender_device.as_device_keys());
443        assert!(!legacy_session);
444    }
445
446    #[async_test]
447    async fn test_adds_sender_data_for_own_verified_device_and_user_using_device_from_store() {
448        // Given the device is in the store, and we sent the event
449        let setup = TestSetup::new(
450            TestOptions::new()
451                .store_contains_device()
452                .store_contains_sender_identity()
453                .device_is_signed()
454                .sender_is_ourself(),
455        )
456        .await;
457        let finder = SenderDataFinder::new(&setup.store, &setup.session);
458
459        // When we try to find sender data
460        let sender_data = finder
461            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
462            .await
463            .unwrap();
464
465        // Then we get back the information about the sender
466        assert_let!(
467            SenderData::SenderUnverified(KnownSenderData { user_id, device_id, master_key }) =
468                sender_data
469        );
470        assert_eq!(user_id, setup.sender.user_id);
471        assert_eq!(device_id.unwrap(), setup.sender_device.device_id());
472        assert_eq!(*master_key, setup.sender_master_key());
473    }
474
475    #[async_test]
476    async fn test_adds_sender_data_for_other_verified_device_and_user_using_device_from_store() {
477        // Given the device is in the store, and someone else sent the event
478        let setup = TestSetup::new(
479            TestOptions::new()
480                .store_contains_device()
481                .store_contains_sender_identity()
482                .device_is_signed(),
483        )
484        .await;
485        let finder = SenderDataFinder::new(&setup.store, &setup.session);
486
487        // When we try to find sender data
488        let sender_data = finder
489            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
490            .await
491            .unwrap();
492
493        // Then we get back the information about the sender
494        assert_let!(
495            SenderData::SenderUnverified(KnownSenderData { user_id, device_id, master_key }) =
496                sender_data
497        );
498        assert_eq!(user_id, setup.sender.user_id);
499        assert_eq!(device_id.unwrap(), setup.sender_device.device_id());
500        assert_eq!(*master_key, setup.sender_master_key());
501    }
502
503    #[async_test]
504    async fn test_adds_sender_data_for_own_device_and_user_using_device_from_event() {
505        // Given the device keys are in the event, and we sent the event
506        let setup = TestSetup::new(
507            TestOptions::new()
508                .store_contains_sender_identity()
509                .device_is_signed()
510                .event_contains_device_keys()
511                .sender_is_ourself(),
512        )
513        .await;
514        let finder = SenderDataFinder::new(&setup.store, &setup.session);
515
516        // When we try to find sender data
517        let sender_data = finder
518            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
519            .await
520            .unwrap();
521
522        // Then we get back the information about the sender
523        assert_let!(
524            SenderData::SenderUnverified(KnownSenderData { user_id, device_id, master_key }) =
525                sender_data
526        );
527        assert_eq!(user_id, setup.sender.user_id);
528        assert_eq!(device_id.unwrap(), setup.sender_device.device_id());
529        assert_eq!(*master_key, setup.sender_master_key());
530    }
531
532    #[async_test]
533    async fn test_adds_sender_data_for_other_verified_device_and_user_using_device_from_event() {
534        // Given the device keys are in the event, and someone else sent the event
535        let setup = TestSetup::new(
536            TestOptions::new()
537                .store_contains_sender_identity()
538                .device_is_signed()
539                .event_contains_device_keys(),
540        )
541        .await;
542        let finder = SenderDataFinder::new(&setup.store, &setup.session);
543
544        // When we try to find sender data
545        let sender_data = finder
546            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
547            .await
548            .unwrap();
549
550        // Then we get back the information about the sender
551        assert_let!(
552            SenderData::SenderUnverified(KnownSenderData { user_id, device_id, master_key }) =
553                sender_data
554        );
555        assert_eq!(user_id, setup.sender.user_id);
556        assert_eq!(device_id.unwrap(), setup.sender_device.device_id());
557        assert_eq!(*master_key, setup.sender_master_key());
558    }
559
560    #[async_test]
561    async fn test_if_session_signing_does_not_match_device_return_an_error() {
562        // Given everything is the same as the above test
563        // except the session is not owned by the device
564        let setup = TestSetup::new(
565            TestOptions::new()
566                .store_contains_sender_identity()
567                .device_is_signed()
568                .event_contains_device_keys()
569                .session_signing_key_differs_from_device(),
570        )
571        .await;
572        let finder = SenderDataFinder::new(&setup.store, &setup.session);
573
574        // When we try to find sender data
575        assert_let!(
576            Err(e) =
577                finder.have_event(setup.sender_device_curve_key(), &setup.room_key_event).await
578        );
579
580        assert_let!(SessionDeviceKeysCheckError::MismatchedIdentityKeys(e) = e);
581
582        let key_ed25519 =
583            Box::new(setup.session.signing_keys().iter().next().unwrap().1.ed25519().unwrap());
584        let key_curve25519 = Box::new(setup.session.sender_key());
585
586        let device_ed25519 = setup.sender_device.ed25519_key().map(Box::new);
587        let device_curve25519 = Some(Box::new(setup.sender_device_curve_key()));
588
589        assert_eq!(
590            e,
591            MismatchedIdentityKeysError {
592                key_ed25519,
593                device_ed25519,
594                key_curve25519,
595                device_curve25519
596            }
597        );
598    }
599
600    #[async_test]
601    async fn test_does_not_add_sender_data_for_a_device_missing_keys() {
602        // Given everything is the same as the successful test
603        // except the device does not own the session because
604        // it is imported.
605        let setup = TestSetup::new(
606            TestOptions::new()
607                .store_contains_sender_identity()
608                .session_is_imported()
609                .event_contains_device_keys(),
610        )
611        .await;
612        let finder = SenderDataFinder::new(&setup.store, &setup.session);
613
614        // When we try to find sender data
615        let sender_data = finder
616            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
617            .await
618            .unwrap();
619
620        // Then we fail to find useful sender data
621        assert_let!(SenderData::UnknownDevice { legacy_session, owner_check_failed } = sender_data);
622        assert!(!legacy_session);
623
624        // And report that the owner_check_failed
625        assert!(owner_check_failed);
626    }
627
628    #[async_test]
629    async fn test_notes_master_key_is_verified_for_own_identity() {
630        // Given we can find the device, and we sent the event, and we are verified
631        let setup = TestSetup::new(
632            TestOptions::new()
633                .store_contains_device()
634                .store_contains_sender_identity()
635                .device_is_signed()
636                .event_contains_device_keys()
637                .sender_is_ourself()
638                .sender_is_verified(),
639        )
640        .await;
641        let finder = SenderDataFinder::new(&setup.store, &setup.session);
642
643        // When we try to find sender data
644        let sender_data = finder
645            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
646            .await
647            .unwrap();
648
649        // Then we get back the information about the sender
650        assert_let!(
651            SenderData::SenderVerified(KnownSenderData { user_id, device_id, master_key }) =
652                sender_data
653        );
654        assert_eq!(user_id, setup.sender.user_id);
655        assert_eq!(device_id.unwrap(), setup.sender_device.device_id());
656        assert_eq!(*master_key, setup.sender_master_key());
657    }
658
659    #[async_test]
660    async fn test_notes_master_key_is_verified_for_other_identity() {
661        // Given we can find the device, and someone else sent the event
662        // And the sender is verified
663        let setup = TestSetup::new(
664            TestOptions::new()
665                .store_contains_device()
666                .store_contains_sender_identity()
667                .device_is_signed()
668                .event_contains_device_keys()
669                .sender_is_verified(),
670        )
671        .await;
672        let finder = SenderDataFinder::new(&setup.store, &setup.session);
673
674        // When we try to find sender data
675        let sender_data = finder
676            .have_event(setup.sender_device_curve_key(), &setup.room_key_event)
677            .await
678            .unwrap();
679
680        // Then we get back the information about the sender
681        assert_let!(
682            SenderData::SenderVerified(KnownSenderData { user_id, device_id, master_key }) =
683                sender_data
684        );
685        assert_eq!(user_id, setup.sender.user_id);
686        assert_eq!(device_id.unwrap(), setup.sender_device.device_id());
687        assert_eq!(*master_key, setup.sender_master_key());
688    }
689
690    #[async_test]
691    async fn test_can_add_user_sender_data_based_on_a_provided_device() {
692        // Given the device is not in the store or the event
693        let setup =
694            TestSetup::new(TestOptions::new().store_contains_sender_identity().device_is_signed())
695                .await;
696        let finder = SenderDataFinder::new(&setup.store, &setup.session);
697
698        // When we supply the device keys directly while asking for the sender data
699        let sender_data = finder.have_device_data(setup.sender_device.inner.clone()).await.unwrap();
700
701        // Then it is found using the device we supplied
702        assert_let!(
703            SenderData::SenderUnverified(KnownSenderData { user_id, device_id, master_key }) =
704                sender_data
705        );
706        assert_eq!(user_id, setup.sender.user_id);
707        assert_eq!(device_id.unwrap(), setup.sender_device.device_id());
708        assert_eq!(*master_key, setup.sender_master_key());
709    }
710
711    struct TestOptions {
712        store_contains_device: bool,
713        store_contains_sender_identity: bool,
714        device_is_signed: bool,
715        event_contains_device_keys: bool,
716        sender_is_ourself: bool,
717        sender_is_verified: bool,
718        session_signing_key_differs_from_device: bool,
719        session_is_imported: bool,
720    }
721
722    impl TestOptions {
723        fn new() -> Self {
724            Self {
725                store_contains_device: false,
726                store_contains_sender_identity: false,
727                device_is_signed: false,
728                event_contains_device_keys: false,
729                sender_is_ourself: false,
730                sender_is_verified: false,
731                session_signing_key_differs_from_device: false,
732                session_is_imported: false,
733            }
734        }
735
736        fn store_contains_device(mut self) -> Self {
737            self.store_contains_device = true;
738            self
739        }
740
741        fn store_contains_sender_identity(mut self) -> Self {
742            self.store_contains_sender_identity = true;
743            self
744        }
745
746        fn device_is_signed(mut self) -> Self {
747            self.device_is_signed = true;
748            self
749        }
750
751        fn event_contains_device_keys(mut self) -> Self {
752            self.event_contains_device_keys = true;
753            self
754        }
755
756        fn sender_is_ourself(mut self) -> Self {
757            self.sender_is_ourself = true;
758            self
759        }
760
761        fn sender_is_verified(mut self) -> Self {
762            self.sender_is_verified = true;
763            self
764        }
765
766        fn session_signing_key_differs_from_device(mut self) -> Self {
767            self.session_signing_key_differs_from_device = true;
768            self
769        }
770
771        fn session_is_imported(mut self) -> Self {
772            self.session_is_imported = true;
773            self
774        }
775    }
776
777    struct TestSetup {
778        sender: TestUser,
779        sender_device: Device,
780        store: Store,
781        room_key_event: DecryptedRoomKeyEvent,
782        session: InboundGroupSession,
783    }
784
785    impl TestSetup {
786        async fn new(options: TestOptions) -> Self {
787            let me = TestUser::own().await;
788            let sender = TestUser::other(&me, &options).await;
789
790            let sender_device = if options.device_is_signed {
791                create_signed_device_of_unverified_user(
792                    sender.account.device_keys(),
793                    &*sender.private_identity.lock().await,
794                )
795                .await
796            } else {
797                create_unsigned_device(sender.account.device_keys())
798            };
799
800            let store = create_store(&me);
801
802            save_to_store(&store, &me, &sender, &sender_device, &options).await;
803
804            let room_id = room_id!("!r:s.co");
805            let session_key = create_session_key();
806
807            let room_key_event = create_room_key_event(
808                &sender.user_id,
809                &me.user_id,
810                &sender_device,
811                room_id,
812                &session_key,
813                &options,
814            );
815
816            let signing_key = if options.session_signing_key_differs_from_device {
817                Ed25519PublicKey::from_base64("2/5LWJMow5zhJqakV88SIc7q/1pa8fmkfgAzx72w9G4")
818                    .unwrap()
819            } else {
820                sender_device.inner.ed25519_key().unwrap()
821            };
822
823            let mut session = InboundGroupSession::new(
824                sender_device.inner.curve25519_key().unwrap(),
825                signing_key,
826                room_id,
827                &session_key,
828                SenderData::unknown(),
829                EventEncryptionAlgorithm::MegolmV1AesSha2,
830                None,
831                false,
832            )
833            .unwrap();
834            if options.session_is_imported {
835                session.mark_as_imported();
836            }
837
838            Self { sender, sender_device, store, room_key_event, session }
839        }
840
841        fn sender_device_curve_key(&self) -> Curve25519PublicKey {
842            self.sender_device.curve25519_key().unwrap()
843        }
844
845        fn sender_master_key(&self) -> Ed25519PublicKey {
846            self.sender.user_identity.master_key().get_first_key().unwrap()
847        }
848    }
849
850    fn create_store(me: &TestUser) -> Store {
851        let store_wrapper = Arc::new(CryptoStoreWrapper::new(
852            &me.user_id,
853            me.account.device_id(),
854            MemoryStore::new(),
855        ));
856
857        let verification_machine = VerificationMachine::new(
858            me.account.deref().clone(),
859            Arc::clone(&me.private_identity),
860            Arc::clone(&store_wrapper),
861        );
862
863        Store::new(
864            me.account.static_data.clone(),
865            Arc::clone(&me.private_identity),
866            store_wrapper,
867            verification_machine,
868        )
869    }
870
871    async fn save_to_store(
872        store: &Store,
873        me: &TestUser,
874        sender: &TestUser,
875        sender_device: &Device,
876        options: &TestOptions,
877    ) {
878        let mut changes = Changes::default();
879
880        // If the device should exist in the store, add it
881        if options.store_contains_device {
882            changes.devices.new.push(sender_device.inner.clone())
883        }
884
885        // Add the sender identity to the store
886        if options.store_contains_sender_identity {
887            changes.identities.new.push(sender.user_identity.clone());
888        }
889
890        // If it's different from the sender, add our identity too
891        if !options.sender_is_ourself {
892            changes.identities.new.push(me.user_identity.clone());
893        }
894
895        store.save_changes(changes).await.unwrap();
896    }
897
898    struct TestUser {
899        user_id: OwnedUserId,
900        account: Account,
901        private_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
902        user_identity: UserIdentityData,
903    }
904
905    impl TestUser {
906        async fn new(
907            user_id: &UserId,
908            device_id: &DeviceId,
909            is_me: bool,
910            is_verified: bool,
911            signer: Option<&TestUser>,
912        ) -> Self {
913            let account = Account::with_device_id(user_id, device_id);
914            let user_id = user_id.to_owned();
915            let private_identity = Arc::new(Mutex::new(create_private_identity(&account).await));
916
917            let user_identity =
918                create_user_identity(&*private_identity.lock().await, is_me, is_verified, signer)
919                    .await;
920
921            Self { user_id, account, private_identity, user_identity }
922        }
923
924        async fn own() -> Self {
925            Self::new(user_id!("@myself:s.co"), device_id!("OWNDEVICEID"), true, true, None).await
926        }
927
928        async fn other(me: &TestUser, options: &TestOptions) -> Self {
929            let user_id =
930                if options.sender_is_ourself { &me.user_id } else { user_id!("@other:s.co") };
931
932            Self::new(
933                user_id,
934                device_id!("SENDERDEVICEID"),
935                options.sender_is_ourself,
936                options.sender_is_verified,
937                Some(me),
938            )
939            .await
940        }
941    }
942
943    async fn create_user_identity(
944        private_identity: &PrivateCrossSigningIdentity,
945        is_me: bool,
946        is_verified: bool,
947        signer: Option<&TestUser>,
948    ) -> UserIdentityData {
949        if is_me {
950            let own_user_identity = OwnUserIdentityData::from_private(private_identity).await;
951
952            if is_verified {
953                own_user_identity.mark_as_verified();
954            }
955
956            UserIdentityData::Own(own_user_identity)
957        } else {
958            let mut other_user_identity =
959                OtherUserIdentityData::from_private(private_identity).await;
960
961            if is_verified {
962                sign_other_identity(signer, &mut other_user_identity).await;
963            }
964
965            UserIdentityData::Other(other_user_identity)
966        }
967    }
968
969    async fn sign_other_identity(
970        signer: Option<&TestUser>,
971        other_user_identity: &mut OtherUserIdentityData,
972    ) {
973        if let Some(signer) = signer {
974            let signer_private_identity = signer.private_identity.lock().await;
975            sign_user_identity_data(signer_private_identity.deref(), other_user_identity).await;
976        } else {
977            panic!("You must provide a `signer` if you want an Other to be verified!");
978        }
979    }
980
981    async fn create_private_identity(account: &Account) -> PrivateCrossSigningIdentity {
982        PrivateCrossSigningIdentity::with_account(account).await.0
983    }
984
985    fn create_room_key_event(
986        sender: &UserId,
987        receiver: &UserId,
988        sender_device: &Device,
989        room_id: &RoomId,
990        session_key: &SessionKey,
991        options: &TestOptions,
992    ) -> DecryptedRoomKeyEvent {
993        let device = if options.event_contains_device_keys {
994            Some(sender_device.as_device_keys().clone())
995        } else {
996            None
997        };
998
999        DecryptedRoomKeyEvent::new(
1000            sender,
1001            receiver,
1002            Ed25519PublicKey::from_base64("loz5i40dP+azDtWvsD0L/xpnCjNkmrcvtXVXzCHX8Vw").unwrap(),
1003            device,
1004            RoomKeyContent::MegolmV1AesSha2(Box::new(MegolmV1AesSha2Content::new(
1005                room_id.to_owned(),
1006                "mysession".to_owned(),
1007                clone_session_key(session_key),
1008                false,
1009            ))),
1010        )
1011    }
1012
1013    fn create_session_key() -> SessionKey {
1014        SessionKey::from_base64(
1015            "\
1016            AgAAAADBy9+YIYTIqBjFT67nyi31gIOypZQl8day2hkhRDCZaHoG+cZh4tZLQIAZimJail0\
1017            0zq4DVJVljO6cZ2t8kIto/QVk+7p20Fcf2nvqZyL2ZCda2Ei7VsqWZHTM/gqa2IU9+ktkwz\
1018            +KFhENnHvDhG9f+hjsAPZd5mTTpdO+tVcqtdWhX4dymaJ/2UpAAjuPXQW+nXhQWQhXgXOUa\
1019            JCYurJtvbCbqZGeDMmVIoqukBs2KugNJ6j5WlTPoeFnMl6Guy9uH2iWWxGg8ZgT2xspqVl5\
1020            CwujjC+m7Dh1toVkvu+bAw\
1021            ",
1022        )
1023        .unwrap()
1024    }
1025
1026    fn clone_session_key(session_key: &SessionKey) -> SessionKey {
1027        SessionKey::from_base64(&session_key.to_base64()).unwrap()
1028    }
1029}