matrix_sdk_crypto/store/
integration_tests.rs

1/// A macro which will run the CryptoStore integration test suite.
2///
3/// You need to provide a `async fn get_store() -> StoreResult<impl StateStore>`
4/// providing a fresh store on the same level you invoke the macro.
5///
6/// ## Usage Example:
7/// ```no_run
8/// # use matrix_sdk_crypto::store::{
9/// #    MemoryStore as MyCryptoStore,
10/// # };
11///
12/// #[cfg(test)]
13/// mod tests {
14///     use super::MyCryptoStore;
15///
16///     async fn get_store(
17///         name: &str,
18///         passphrase: Option<&str>,
19///         clear_data: bool,
20///     ) -> MyCryptoStore {
21///         let store = MyCryptoStore::new();
22///         if clear_data {
23///             store.clear();
24///         }
25///         store
26///     }
27///
28///     cryptostore_integration_tests!();
29/// }
30/// ```
31#[allow(unused_macros)]
32#[macro_export]
33macro_rules! cryptostore_integration_tests {
34    () => {
35        mod cryptostore_integration_tests {
36            use std::collections::{BTreeMap, HashMap};
37            use std::time::Duration;
38
39            use assert_matches::assert_matches;
40            use matrix_sdk_test::async_test;
41            use ruma::{
42                device_id, events::secret::request::SecretName, room_id, serde::Raw,
43                to_device::DeviceIdOrAllDevices, user_id, DeviceId, RoomId, TransactionId, UserId,
44            };
45            use serde_json::value::to_raw_value;
46            use serde_json::json;
47            use matrix_sdk_common::deserialized_responses::WithheldCode;
48            use $crate::{
49                olm::{
50                    Account, Curve25519PublicKey, InboundGroupSession, OlmMessageHash,
51                    PrivateCrossSigningIdentity, SenderData, SenderDataType, Session
52                },
53                store::{
54                    types::{
55                        BackupDecryptionKey, Changes, DehydratedDeviceKey, DeviceChanges,
56                        IdentityChanges, PendingChanges, StoredRoomKeyBundleData, RoomKeyWithheldEntry,
57                        RoomSettings
58                    },
59                    CryptoStore, GossipRequest,
60                },
61                testing::{get_device, get_other_identity, get_own_identity},
62                types::{
63                    events::{
64                        dummy::DummyEventContent,
65                        olm_v1::{DecryptedSecretSendEvent, OlmV1Keys},
66                        room_key_request::MegolmV1AesSha2Content,
67                        room_key_withheld::{
68                            CommonWithheldCodeContent, MegolmV1AesSha2WithheldContent,
69                            RoomKeyWithheldContent,
70                        },
71                        room_key_bundle::RoomKeyBundleContent,
72                        secret_send::SecretSendContent,
73                        ToDeviceEvent,
74                    },
75                    requests::ToDeviceRequest,
76                    DeviceKeys,
77                    EventEncryptionAlgorithm,
78                },
79                vodozemac::megolm::{GroupSession, SessionConfig}, DeviceData, GossippedSecret, LocalTrust,  SecretInfo,
80                TrackedUser,
81            };
82
83            use super::get_store;
84
85            fn alice_id() -> &'static UserId {
86                user_id!("@alice:example.org")
87            }
88
89            fn alice_device_id() -> &'static DeviceId {
90                device_id!("ALICEDEVICE")
91            }
92
93            fn bob_id() -> &'static UserId {
94                user_id!("@bob:example.org")
95            }
96
97            fn bob_device_id() -> &'static DeviceId {
98                device_id!("BOBDEVICE")
99            }
100
101            pub async fn get_loaded_store(name: &str) -> (Account, impl CryptoStore) {
102                let store = get_store(name, None, true).await;
103                let account = get_account();
104
105                store.save_pending_changes(PendingChanges { account: Some(account.deep_clone()), }).await.expect("Can't save account");
106
107                (account, store)
108            }
109
110            fn get_account() -> Account {
111                Account::with_device_id(alice_id(), alice_device_id())
112            }
113
114            pub(crate) async fn get_account_and_session() -> (Account, Session) {
115                let alice = Account::with_device_id(alice_id(), alice_device_id());
116                let mut bob = Account::with_device_id(bob_id(), bob_device_id());
117
118                bob.generate_one_time_keys(1);
119                let one_time_key = *bob.one_time_keys().values().next().unwrap();
120                let sender_key = bob.identity_keys().curve25519;
121                let session = alice.create_outbound_session_helper(
122                    Default::default(),
123                    sender_key,
124                    one_time_key,
125                    false,
126                    alice.device_keys(),
127                );
128
129                (alice, session)
130            }
131
132            #[async_test]
133            async fn test_save_account_via_generic_save() {
134                let store = get_store("save_account_via_generic", None, true).await;
135                assert!(store.get_static_account().is_none());
136                assert!(store.load_account().await.unwrap().is_none());
137                let account = get_account();
138
139                store
140                    .save_pending_changes(PendingChanges { account: Some(account) })
141                    .await
142                    .expect("Can't save account");
143                assert!(store.get_static_account().is_some());
144            }
145
146            #[async_test]
147            async fn test_save_account() {
148                let store = get_store("save_account", None, true).await;
149                assert!(store.get_static_account().is_none());
150                assert!(store.load_account().await.unwrap().is_none());
151                let account = get_account();
152
153                store
154                    .save_pending_changes(PendingChanges { account: Some(account) })
155                    .await
156                    .expect("Can't save account");
157                assert!(store.get_static_account().is_some());
158            }
159
160            #[async_test]
161            async fn test_load_account() {
162                let store = get_store("load_account", None, true).await;
163                let account = get_account();
164
165                store
166                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
167                    .await
168                    .expect("Can't save account");
169
170                let loaded_account = store.load_account().await.expect("Can't load account");
171                let loaded_account = loaded_account.unwrap();
172
173                assert_eq!(account, loaded_account);
174            }
175
176            #[async_test]
177            async fn test_load_account_with_passphrase() {
178                let passphrase = Some("secret_passphrase");
179                let store = get_store("load_account_with_passphrase", passphrase, true).await;
180                let account = get_account();
181
182                store
183                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
184                    .await
185                    .expect("Can't save account");
186
187                let loaded_account = store.load_account().await.expect("Can't load account");
188                let loaded_account = loaded_account.unwrap();
189
190                assert_eq!(account, loaded_account);
191            }
192
193            #[async_test]
194            async fn test_save_and_share_account() {
195                let store = get_store("save_and_share_account", None, true).await;
196                let mut account = get_account();
197
198                store
199                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
200                    .await
201                    .expect("Can't save account");
202
203                account.mark_as_shared();
204                account.update_uploaded_key_count(50);
205
206                store
207                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
208                    .await
209                    .expect("Can't save account");
210
211                let loaded_account = store.load_account().await.expect("Can't load account");
212                let loaded_account = loaded_account.unwrap();
213
214                assert_eq!(account, loaded_account);
215                assert_eq!(account.uploaded_key_count(), loaded_account.uploaded_key_count());
216            }
217
218            #[async_test]
219            async fn test_load_sessions() {
220                let store = get_store("load_sessions", None, true).await;
221                let (account, session) = get_account_and_session().await;
222                store
223                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
224                    .await
225                    .expect("Can't save account");
226
227                let changes = Changes {
228                    sessions: vec![session.clone()],
229                    devices: DeviceChanges { new: vec![DeviceData::from_account(&account)], ..Default::default() },
230                    ..Default::default()
231                };
232
233                store.save_changes(changes).await.unwrap();
234
235                let sessions = store
236                    .get_sessions(&session.sender_key.to_base64())
237                    .await
238                    .expect("Can't load sessions")
239                    .unwrap();
240                let loaded_session = sessions.get(0).cloned().expect("We should find the session in the store.");
241
242                assert_eq!(&session, &loaded_session, "The loaded session should be the same one we put into the store.");
243            }
244
245            #[async_test]
246            async fn test_add_and_save_session() {
247                let store_name = "add_and_save_session";
248
249                // Given we created a session and saved it in the store
250                let (session_id, account, sender_key) = {
251                    let store = get_store(store_name, None, true).await;
252                    let (account, session) = get_account_and_session().await;
253                    let sender_key = session.sender_key.to_base64();
254                    let session_id = session.session_id().to_owned();
255
256                    store
257                        .save_pending_changes(PendingChanges {
258                            account: Some(account.deep_clone()),
259                        })
260                        .await
261                        .expect("Can't save account");
262                    store
263                        .save_changes(Changes {
264                            devices: DeviceChanges {
265                                new: vec![DeviceData::from_account(&account)],
266                                ..Default::default()
267                            },
268                            ..Default::default()
269                        })
270                        .await
271                        .unwrap();
272
273                    let changes = Changes { sessions: vec![session.clone()], ..Default::default() };
274                    store.save_changes(changes).await.unwrap();
275
276                    let sessions = store.get_sessions(&sender_key).await.unwrap().unwrap();
277                    let session = &sessions[0];
278
279                    assert_eq!(session_id, session.session_id());
280
281                    (session_id, account, sender_key)
282                };
283
284                // When we reload the store
285                let store = get_store(store_name, None, false).await;
286
287                // Then the same account and session info was reloaded
288                let loaded_account = store.load_account().await.unwrap().unwrap();
289                assert_eq!(account, loaded_account);
290
291                let sessions = store.get_sessions(&sender_key).await.unwrap().unwrap();
292                let session = &sessions[0];
293
294                assert_eq!(session_id, session.session_id());
295            }
296
297            #[async_test]
298            async fn test_load_outbound_group_session() {
299                let dir = "load_outbound_group_session";
300                let room_id = room_id!("!test:localhost");
301
302                // Given we saved an outbound group session
303                {
304                    let (account, store) = get_loaded_store(dir.clone()).await;
305                    assert!(
306                        store.get_outbound_group_session(&room_id).await.unwrap().is_none(),
307                        "Initially there should be no outbound group session"
308                    );
309
310                    let (session, _) =
311                        account.create_group_session_pair_with_defaults(&room_id).await;
312
313                    let user_id = user_id!("@example:localhost");
314                    let request = ToDeviceRequest::new(
315                        user_id,
316                        DeviceIdOrAllDevices::AllDevices,
317                        "m.dummy",
318                        Raw::from_json(to_raw_value(&DummyEventContent::new()).unwrap()),
319                    );
320
321                    session.add_request(TransactionId::new(), request.into(), Default::default());
322
323                    let changes = Changes {
324                        outbound_group_sessions: vec![session.clone()],
325                        ..Default::default()
326                    };
327
328                    store.save_changes(changes).await.expect("Can't save group session");
329                    assert!(
330                        store.get_outbound_group_session(&room_id).await.unwrap().is_some(),
331                        "Sanity: after we've saved one, there should be an outbound_group_session"
332                    );
333                }
334
335                // When we reload the account
336                let store = get_store(dir, None, false).await;
337                store.load_account().await.unwrap();
338
339                // Then the saved session is restored
340                assert!(
341                    store.get_outbound_group_session(&room_id).await.unwrap().is_some(),
342                    "The outbound_group_session should have been loaded"
343                );
344            }
345
346            /// Test that we can import an inbound group session via [`CryptoStore::save_changes`]
347            #[async_test]
348            async fn test_save_changes_save_inbound_group_session() {
349                let (account, store) = get_loaded_store("save_inbound_group_session").await;
350
351                let room_id = &room_id!("!test:localhost");
352                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
353
354                let changes =
355                    Changes { inbound_group_sessions: vec![session], ..Default::default() };
356
357                store.save_changes(changes).await.expect("Can't save group session");
358            }
359
360            /// Test that we can import a backed-up group session via
361            /// [`CryptoStore::save_inbound_group_sessions`]
362            #[async_test]
363            async fn test_save_inbound_group_session_from_backup() {
364                let (account, store) =
365                    get_loaded_store("save_inbound_group_session_from_backup").await;
366
367                let room_id = &room_id!("!test:localhost");
368                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
369
370                session.mark_as_backed_up();
371                store
372                    .save_inbound_group_sessions(vec![session.clone()], Some(&"bkpver1"))
373                    .await
374                    .expect("could not save sessions");
375
376                let loaded_session = store
377                    .get_inbound_group_session(&session.room_id, session.session_id())
378                    .await
379                    .expect("error when loading session")
380                    .expect("session not found in store");
381                assert_eq!(session, loaded_session);
382                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 1);
383                assert_eq!(store.inbound_group_session_counts(None).await.unwrap().total, 1);
384
385                // It should *not* be returned by a request for backup for the same backup version
386                let to_back_up = store.inbound_group_sessions_for_backup("bkpver1", 1).await.unwrap();
387                assert_eq!(to_back_up.len(), 0, "backup was returned by backup query");
388                assert_eq!(
389                    store.inbound_group_session_counts(Some(&"bkpver1")).await.unwrap().backed_up, 1,
390                    "backed_up count",
391                );
392            }
393
394            /// Test that the behaviour of a key imported from an *old* backup is correct
395            ///
396            /// This currently only works on the MemoryStore, so is ignored. The other stores
397            /// are waiting for more work on https://github.com/element-hq/element-web/issues/26892.
398            #[ignore]
399            #[async_test]
400            async fn test_save_inbound_group_session_from_old_backup() {
401                let (account, store) =
402                    get_loaded_store("save_inbound_group_session_from_old_backup").await;
403
404                let room_id = &room_id!("!test:localhost");
405                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
406
407                session.mark_as_backed_up();
408                store
409                    .save_inbound_group_sessions(vec![session.clone()], Some(&"bkpver1"))
410                    .await
411                    .expect("could not save sessions");
412
413                // The session should be returned by a request for backup from a different backup version.
414                let to_back_up = store.inbound_group_sessions_for_backup("bkpver2", 1).await.unwrap();
415                assert_eq!(to_back_up, vec![session]);
416                assert_eq!(
417                    store.inbound_group_session_counts(Some(&"bkpver2")).await.unwrap().backed_up, 0,
418                    "backed_up count for backup version 2",
419                );
420            }
421
422            /// Test that we can import a not-backed-up group session via
423            /// [`CryptoStore::save_inbound_group_sessions`]
424            #[async_test]
425            async fn test_save_inbound_group_session_from_import() {
426                let (account, store) =
427                    get_loaded_store("save_inbound_group_session_from_import").await;
428
429                let room_id = &room_id!("!test:localhost");
430                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
431
432                store
433                    .save_inbound_group_sessions(vec![session.clone()], None)
434                    .await
435                    .expect("could not save sessions");
436
437                let loaded_session = store
438                    .get_inbound_group_session(&session.room_id, session.session_id())
439                    .await
440                    .expect("error when loading session")
441                    .expect("session not found in store");
442                assert_eq!(session, loaded_session);
443                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 1);
444                assert_eq!(store.inbound_group_session_counts(None).await.unwrap().total, 1);
445                assert_eq!(store.inbound_group_session_counts(None).await.unwrap().backed_up, 0);
446
447                // It should be returned by a request for backup
448                let to_back_up = store.inbound_group_sessions_for_backup("bkpver1", 1).await.unwrap();
449                assert_eq!(to_back_up, vec![session]);
450            }
451
452            #[async_test]
453            async fn test_mark_inbound_group_sessions_as_backed_up() {
454                // Given a store exists with multiple unbacked-up sessions
455                let (account, store) =
456                    get_loaded_store("mark_inbound_group_sessions_as_backed_up").await;
457                let room_id = &room_id!("!test:localhost");
458                let mut sessions: Vec<InboundGroupSession> = Vec::with_capacity(10);
459                for _i in 0..10 {
460                    sessions.push(account.create_group_session_pair_with_defaults(room_id).await.1);
461                }
462                let changes = Changes { inbound_group_sessions: sessions.clone(), ..Default::default() };
463                store.save_changes(changes).await.expect("Can't save group session");
464                assert_eq!(store.inbound_group_sessions_for_backup("bkpver", 100).await.unwrap().len(), 10);
465
466                // When I mark some as backed up
467                store.mark_inbound_group_sessions_as_backed_up("bkpver", &[
468                    session_info(&sessions[1]),
469                    session_info(&sessions[3]),
470                    session_info(&sessions[5]),
471                    session_info(&sessions[7]),
472                    session_info(&sessions[9]),
473                ]).await.expect("Failed to mark sessions as backed up");
474
475                // And ask which still need backing up
476                let to_back_up = store.inbound_group_sessions_for_backup("bkpver", 10).await.unwrap();
477                let needs_backing_up = |i: usize| to_back_up.iter().any(|s| s.session_id() == sessions[i].session_id());
478
479                // Then the sessions we said were backed up no longer need backing up
480                assert!(!needs_backing_up(1));
481                assert!(!needs_backing_up(3));
482                assert!(!needs_backing_up(5));
483                assert!(!needs_backing_up(7));
484                assert!(!needs_backing_up(9));
485
486                // And the sessions we didn't mention still need backing up
487                assert!(needs_backing_up(0));
488                assert!(needs_backing_up(2));
489                assert!(needs_backing_up(4));
490                assert!(needs_backing_up(6));
491                assert!(needs_backing_up(8));
492                assert_eq!(to_back_up.len(), 5);
493            }
494
495            #[async_test]
496            async fn test_reset_inbound_group_session_for_backup() {
497                // Given a store exists where all sessions are backed up to backup_1
498                let (account, store) =
499                    get_loaded_store("reset_inbound_group_session_for_backup").await;
500                let room_id = &room_id!("!test:localhost");
501                let mut sessions: Vec<InboundGroupSession> = Vec::with_capacity(10);
502                for _ in 0..10 {
503                    sessions.push(account.create_group_session_pair_with_defaults(room_id).await.1);
504                }
505                let changes = Changes { inbound_group_sessions: sessions.clone(), ..Default::default() };
506                store.save_changes(changes).await.expect("Can't save group session");
507                assert_eq!(store.inbound_group_sessions_for_backup("backup_1", 100).await.unwrap().len(), 10);
508                store.mark_inbound_group_sessions_as_backed_up(
509                    "backup_1",
510                    &(0..10).map(|i| session_info(&sessions[i])).collect::<Vec<_>>(),
511                ).await.expect("Failed to mark sessions as backed up");
512
513                // Sanity: none need backing up to the same backup
514                {
515                    let to_back_up_old = store.inbound_group_sessions_for_backup("backup_1", 10).await.unwrap();
516                    assert_eq!(to_back_up_old.len(), 0);
517                }
518
519                // Some stores ignore backup_version and just reset when you tell them to. Tell
520                // them here.
521                store.reset_backup_state().await.expect("reset failed");
522
523                // When we ask what needs backing up to a different backup version
524                let to_back_up = store.inbound_group_sessions_for_backup("backup_02", 10).await.unwrap();
525
526                // Then the answer is everything
527                let needs_backing_up = |i: usize| to_back_up.iter().any(|s| s.session_id() == sessions[i].session_id());
528                assert!(needs_backing_up(0));
529                assert!(needs_backing_up(1));
530                assert!(needs_backing_up(8));
531                assert!(needs_backing_up(9));
532                assert_eq!(to_back_up.len(), 10);
533            }
534
535            #[async_test]
536            async fn test_load_inbound_group_session() {
537                let dir = "load_inbound_group_session";
538                let (account, store) = get_loaded_store(dir).await;
539                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 0);
540
541                let room_id = &room_id!("!test:localhost");
542                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
543
544                let export = session.export().await;
545
546                let session = InboundGroupSession::from_export(&export).unwrap();
547
548                let changes =
549                    Changes { inbound_group_sessions: vec![session.clone()], ..Default::default() };
550
551                store.save_changes(changes).await.expect("Can't save group session");
552
553                drop(store);
554
555                let store = get_store(dir, None, false).await;
556
557                store.load_account().await.unwrap();
558
559                let loaded_session = store
560                    .get_inbound_group_session(&session.room_id, session.session_id())
561                    .await
562                    .unwrap()
563                    .unwrap();
564                assert_eq!(session, loaded_session);
565                loaded_session.export().await;
566
567                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 1);
568                assert_eq!(store.inbound_group_session_counts(None).await.unwrap().total, 1);
569            }
570
571            #[async_test]
572            async fn test_get_inbound_group_sessions_by_room_id_empty() {
573                let dir = "get_inbound_group_session_by_room_id_empty";
574                let (_, store) = get_loaded_store(dir).await;
575                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 0);
576
577                let room_id = &room_id!("!testing:localhost");
578                assert_eq!(store.get_inbound_group_sessions_by_room_id(room_id).await.unwrap().len(), 0);
579            }
580
581            #[async_test]
582            async fn test_get_inbound_group_sessions_by_room_id() {
583                let dir = "get_inbound_group_session_by_room_id";
584                let (account, store) = get_loaded_store(dir).await;
585                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 0);
586
587                let room_id = &room_id!("!testing:localhost");
588                let (_, session_1) = account.create_group_session_pair_with_defaults(room_id).await;
589                let (_, session_2) = account.create_group_session_pair_with_defaults(room_id).await;
590
591                let second_room_id = &room_id!("!other_room_testing:localhost");
592                let (_, session_3) = account.create_group_session_pair_with_defaults(second_room_id).await;
593
594                let mut sessions = vec![
595                    session_1,
596                    session_2,
597                    session_3
598                ];
599
600                let changes = Changes {
601                    inbound_group_sessions: sessions.clone(),
602                    ..Default::default()
603                };
604                store.save_changes(changes).await.expect("Can't save group session");
605
606                drop(store);
607
608                // The last session is in a different room, so should not be returned by
609                // get_inbound_group_sessions_by_room_id. Remove it from the list.
610                sessions.pop();
611
612                let store = get_store(dir, None, false).await;
613                // Make sure all the sessions are in the store
614                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 3);
615
616                store.load_account().await.unwrap();
617
618                let loaded_sessions = store
619                    .get_inbound_group_sessions_by_room_id(room_id)
620                    .await
621                    .unwrap();
622
623                assert_eq!(loaded_sessions.len(), 2);
624                assert_session_lists_eq(sessions, loaded_sessions, "room by id sessions");
625            }
626
627            #[async_test]
628            async fn test_fetch_inbound_group_sessions_for_device() {
629                // Given a store exists, containing inbound group sessions from different devices
630                let (account, store) =
631                    get_loaded_store("fetch_inbound_group_sessions_for_device").await;
632
633                let dev1 = Curve25519PublicKey::from_base64(
634                    "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4"
635                ).unwrap();
636                let dev2 = Curve25519PublicKey::from_base64(
637                    "LTpv2DGMhggPAXO02+7f68CNEp6A40F0Yl8B094Y8gc"
638                ).unwrap();
639
640                let dev_1_unknown_a = create_session(&account, &dev1, SenderDataType::UnknownDevice).await;
641                let dev_1_unknown_b = create_session(&account, &dev1, SenderDataType::UnknownDevice).await;
642
643                let dev_1_keys_a = create_session(&account, &dev1, SenderDataType::DeviceInfo).await;
644                let dev_1_keys_b = create_session(&account, &dev1, SenderDataType::DeviceInfo).await;
645                let dev_1_keys_c = create_session(&account, &dev1, SenderDataType::DeviceInfo).await;
646                let dev_1_keys_d = create_session(&account, &dev1, SenderDataType::DeviceInfo).await;
647
648                let dev_2_unknown = create_session(
649                    &account, &dev2, SenderDataType::UnknownDevice).await;
650
651                let dev_2_keys = create_session(
652                    &account, &dev2, SenderDataType::DeviceInfo).await;
653
654                let sessions = vec![
655                    dev_1_unknown_a.clone(),
656                    dev_1_unknown_b.clone(),
657                    dev_1_keys_a.clone(),
658                    dev_1_keys_b.clone(),
659                    dev_1_keys_c.clone(),
660                    dev_1_keys_d.clone(),
661                    dev_2_unknown.clone(),
662                    dev_2_keys.clone(),
663                ];
664
665                let changes = Changes {
666                    inbound_group_sessions: sessions,
667                    ..Default::default()
668                };
669                store.save_changes(changes).await.expect("Can't save group session");
670
671                // When we fetch the list of sessions for device 1, unknown
672                let sessions_1_u = store.get_inbound_group_sessions_for_device_batch(
673                    dev1,
674                    SenderDataType::UnknownDevice,
675                    None,
676                    10
677                ).await.expect("Failed to get sessions for dev1");
678
679                // Then the expected sessions are returned
680                assert_session_lists_eq(sessions_1_u, [dev_1_unknown_a, dev_1_unknown_b], "device 1 sessions");
681
682                // And when we ask for the list of sessions for device 2, with device keys
683                let sessions_2_d = store
684                    .get_inbound_group_sessions_for_device_batch(dev2, SenderDataType::DeviceInfo, None, 10)
685                    .await
686                    .expect("Failed to get sessions for dev2");
687
688                // Then the matching session is returned
689                assert_eq!(sessions_2_d, vec![dev_2_keys], "device 2 sessions");
690
691                // And we can fetch device 1, keys in batches.
692                // We call the batch function repeatedly, to ensure it terminates correctly.
693                let mut sessions_1_k = Vec::new();
694                let mut previous_last_session_id: Option<String> = None;
695                loop {
696                    let mut sessions_1_k_batch = store.get_inbound_group_sessions_for_device_batch(
697                        dev1,
698                        SenderDataType::DeviceInfo,
699                        previous_last_session_id,
700                        2
701                    ).await.expect("Failed to get batch 1");
702
703                    // If there are no results in the batch, we have reached the end of the results.
704                    let Some(last_session) = sessions_1_k_batch.last() else {
705                        break;
706                    };
707
708                    // Check that there are exactly two results in the batch
709                    assert_eq!(sessions_1_k_batch.len(), 2);
710
711                    previous_last_session_id = Some(last_session.session_id().to_owned());
712
713                    // Modify one of the results, to check that that doesn't break iteration
714                    let mut last_session = last_session.clone();
715                    last_session.sender_data = SenderData::unknown();
716                    store.save_inbound_group_sessions(vec![last_session], None).await.unwrap();
717
718                    sessions_1_k.append(&mut sessions_1_k_batch);
719                }
720
721                assert_session_lists_eq(
722                    sessions_1_k,
723                    [dev_1_keys_a, dev_1_keys_b, dev_1_keys_c, dev_1_keys_d],
724                    "device 1 batched results"
725                );
726            }
727
728            /// Assert that two lists of sessions are the same, modulo ordering.
729            ///
730            /// There is no requirement for `get_inbound_group_sessions_for_device_batch` to
731            /// return the results in a specific order. This helper ensures that the two lists
732            /// of inbound group sessions are equivalent, without worrying about the ordering.
733            fn assert_session_lists_eq<I, J>(actual: I, expected: J, message: &str)
734                where I: IntoIterator<Item = InboundGroupSession>, J: IntoIterator<Item = InboundGroupSession>
735            {
736                let sorter = |a: &InboundGroupSession, b: &InboundGroupSession| Ord::cmp(a.session_id(), b.session_id());
737
738                let mut actual = Vec::from_iter(actual);
739                actual.sort_unstable_by(sorter);
740                let mut expected = Vec::from_iter(expected);
741                expected.sort_unstable_by(sorter);
742                assert_eq!(actual, expected, "{}", message);
743            }
744
745            #[async_test]
746            async fn test_tracked_users() {
747                let dir = "test_tracked_users";
748                let (_account, store) = get_loaded_store(dir.clone()).await;
749
750                let alice = user_id!("@alice:example.org");
751                let bob = user_id!("@bob:example.org");
752                let candy = user_id!("@candy:example.org");
753
754                let loaded = store.load_tracked_users().await.unwrap();
755                assert!(loaded.is_empty(), "Initially there are no tracked users");
756
757                let users = vec![(alice, true), (bob, false)];
758                store.save_tracked_users(&users).await.unwrap();
759
760                let check_loaded_users = |loaded: Vec<TrackedUser>| {
761                    let loaded: HashMap<_, _> =
762                        loaded.into_iter().map(|u| (u.user_id.to_owned(), u)).collect();
763
764                    let loaded_alice =
765                        loaded.get(alice).expect("Alice should be in the store as a tracked user");
766                    let loaded_bob =
767                        loaded.get(bob).expect("Bob should be in the store as as tracked user");
768
769                    assert!(!loaded.contains_key(candy), "Candy shouldn't be part of the store");
770                    assert_eq!(loaded.len(), 2, "Candy shouldn't be part of the store");
771
772                    assert!(loaded_alice.dirty, "Alice should be considered to be dirty");
773                    assert!(!loaded_bob.dirty, "Bob should not be considered to be dirty");
774                };
775
776                let loaded = store.load_tracked_users().await.unwrap();
777                check_loaded_users(loaded);
778
779                drop(store);
780
781                let name = dir.clone();let store = get_store(name, None, false).await;
782                let loaded = store.load_tracked_users().await.unwrap();
783                check_loaded_users(loaded);
784            }
785
786            #[async_test]
787            async fn test_device_saving() {
788                let dir = "device_saving";
789                let (_account, store) = get_loaded_store(dir.clone()).await;
790
791                let alice_device_1 = DeviceData::from_account(&Account::with_device_id(
792                    "@alice:localhost".try_into().unwrap(),
793                    "FIRSTDEVICE".into(),
794                ));
795
796                let alice_device_2 = DeviceData::from_account(&Account::with_device_id(
797                    "@alice:localhost".try_into().unwrap(),
798                    "SECONDDEVICE".into(),
799                ));
800
801                let json = json!({
802                    "algorithms": ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
803                    "user_id": "@bob:localhost",
804                    "device_id": "BOBDEVICE",
805                    "extra_property": "somevalue",
806                    "keys": {
807                        "curve25519:BOBDEVICE": "n0zs7qnaPLLf/OTL+dDLcI5kaPexbUeQ8jLQ2q6sO0E",
808                        "ed25519:BOBDEVICE": "RrKiu4+5EHRBWY6Qj6OtQGC0txpmEeanOz2irEZ/IN4",
809                    },
810                    "signatures": {
811                        "@bob:localhost": {
812                            "ed25519:BOBDEVICE": "9NjPewVHfB7Ah32mJ+CBx64mVoiQ8gbh+/2pc9WfAgut/H0Kqd/bbpgJq9Pn518szaXcGqEq0DxDP6CABBX8CQ",
813                        },
814                    },
815                });
816
817                let bob_device_1_keys: DeviceKeys = serde_json::from_value(json).unwrap();
818                let bob_device_1 = DeviceData::new(bob_device_1_keys, LocalTrust::Unset);
819
820                let changes = Changes {
821                    devices: DeviceChanges {
822                        new: vec![alice_device_1.clone(), alice_device_2.clone(), bob_device_1.clone()],
823                        ..Default::default()
824                    },
825                    ..Default::default()
826                };
827
828                store.save_changes(changes).await.unwrap();
829
830                drop(store);
831
832                let store = get_store(dir, None, false).await;
833
834                store.load_account().await.unwrap();
835
836                let loaded_device = store
837                    .get_device(alice_device_1.user_id(), alice_device_1.device_id())
838                    .await
839                    .unwrap()
840                    .unwrap();
841
842                assert_eq!(alice_device_1, loaded_device);
843
844                for algorithm in loaded_device.algorithms() {
845                    assert!(alice_device_1.algorithms().contains(algorithm));
846                }
847                assert_eq!(alice_device_1.algorithms().len(), loaded_device.algorithms().len());
848                assert_eq!(alice_device_1.keys(), loaded_device.keys());
849
850                let user_devices = store.get_user_devices(alice_device_1.user_id()).await.unwrap();
851                assert_eq!(user_devices.len(), 2);
852
853                let bob_device = store
854                    .get_device(bob_device_1.user_id(), bob_device_1.device_id())
855                    .await
856                    .unwrap();
857
858                let bob_device_json = serde_json::to_value(bob_device).unwrap();
859                assert_eq!(bob_device_json["device_keys"]["extra_property"], json!("somevalue"));
860            }
861
862            #[async_test]
863            async fn test_device_deleting() {
864                let dir = "device_deleting";
865                let (_account, store) = get_loaded_store(dir.clone()).await;
866                let device = get_device();
867
868                let changes = Changes {
869                    devices: DeviceChanges { changed: vec![device.clone()], ..Default::default() },
870                    ..Default::default()
871                };
872
873                store.save_changes(changes).await.unwrap();
874
875                let changes = Changes {
876                    devices: DeviceChanges { deleted: vec![device.clone()], ..Default::default() },
877                    ..Default::default()
878                };
879
880                store.save_changes(changes).await.unwrap();
881                drop(store);
882
883                let store = get_store(dir, None, false).await;
884
885                store.load_account().await.unwrap();
886
887                let loaded_device =
888                    store.get_device(device.user_id(), device.device_id()).await.unwrap();
889
890                assert!(loaded_device.is_none());
891            }
892
893            #[async_test]
894            async fn test_user_saving() {
895                let dir = "user_saving";
896
897                let user_id = user_id!("@example:localhost");
898                let device_id: &DeviceId = "WSKKLTJZCL".into();
899
900                let store = get_store(dir, None, true).await;
901
902                let account = Account::with_device_id(&user_id, device_id);
903
904                store.save_pending_changes(PendingChanges { account: Some(account), })
905                    .await
906                    .expect("Can't save account");
907
908                let own_identity = get_own_identity();
909
910                let changes = Changes {
911                    identities: IdentityChanges {
912                        changed: vec![own_identity.clone().into()],
913                        ..Default::default()
914                    },
915                    ..Default::default()
916                };
917
918                store.save_changes(changes).await.expect("Can't save identity");
919
920                drop(store);
921
922                let store = get_store(dir, None, false).await;
923
924                store.load_account().await.unwrap();
925
926                let loaded_user =
927                    store.get_user_identity(own_identity.user_id()).await.unwrap().unwrap();
928
929                assert_eq!(loaded_user.master_key(), own_identity.master_key());
930                assert_eq!(loaded_user.self_signing_key(), own_identity.self_signing_key());
931                assert_eq!(loaded_user.own().unwrap().clone(), own_identity.clone());
932
933                let other_identity = get_other_identity();
934
935                let changes = Changes {
936                    identities: IdentityChanges {
937                        changed: vec![other_identity.clone().into()],
938                        ..Default::default()
939                    },
940                    ..Default::default()
941                };
942
943                store.save_changes(changes).await.unwrap();
944
945                let loaded_user =
946                    store.get_user_identity(other_identity.user_id()).await.unwrap().unwrap();
947
948                assert_eq!(loaded_user.master_key(), other_identity.master_key());
949                assert_eq!(loaded_user.self_signing_key(), other_identity.self_signing_key());
950                assert_eq!(loaded_user.user_id(), other_identity.user_id());
951                assert_eq!(loaded_user.other().unwrap().clone(), other_identity);
952
953                own_identity.mark_as_verified();
954
955                let changes = Changes {
956                    identities: IdentityChanges {
957                        changed: vec![own_identity.into()],
958                        ..Default::default()
959                    },
960                    ..Default::default()
961                };
962
963                store.save_changes(changes).await.unwrap();
964                let loaded_user = store.get_user_identity(&user_id).await.unwrap().unwrap();
965                assert!(loaded_user.own().unwrap().is_verified())
966            }
967
968            #[async_test]
969            async fn test_private_identity_saving() {
970                let (_, store) = get_loaded_store("private_identity_saving").await;
971                assert!(store.load_identity().await.unwrap().is_none());
972                let identity = PrivateCrossSigningIdentity::new(alice_id().to_owned());
973
974                let changes =
975                    Changes { private_identity: Some(identity.clone()), ..Default::default() };
976
977                store.save_changes(changes).await.unwrap();
978                let loaded_identity = store.load_identity().await.unwrap().unwrap();
979                assert_eq!(identity.user_id(), loaded_identity.user_id());
980            }
981
982            #[async_test]
983            async fn test_olm_hash_saving() {
984                let (_, store) = get_loaded_store("olm_hash_saving").await;
985
986                let hash = OlmMessageHash {
987                    sender_key: "test_sender".to_owned(),
988                    hash: "test_hash".to_owned(),
989                };
990
991                let mut changes = Changes::default();
992                changes.message_hashes.push(hash.clone());
993
994                assert!(!store.is_message_known(&hash).await.unwrap());
995                store.save_changes(changes).await.unwrap();
996                assert!(store.is_message_known(&hash).await.unwrap());
997            }
998
999            #[async_test]
1000            async fn test_key_request_saving() {
1001                let (account, store) = get_loaded_store("key_request_saving").await;
1002                let sender_key =
1003                    Curve25519PublicKey::from_base64("Nn0L2hkcCMFKqynTjyGsJbth7QrVmX3lbrksMkrGOAw")
1004                        .unwrap();
1005
1006                let id = TransactionId::new();
1007                let info: SecretInfo = MegolmV1AesSha2Content {
1008                    room_id: room_id!("!test:localhost").to_owned(),
1009                    sender_key: Some(sender_key),
1010                    session_id: "test_session_id".to_owned(),
1011                }
1012                .into();
1013
1014                let request = GossipRequest {
1015                    request_recipient: account.user_id().to_owned(),
1016                    request_id: id.clone(),
1017                    info: info.clone(),
1018                    sent_out: false,
1019                };
1020
1021                assert!(store.get_outgoing_secret_requests(&id).await.unwrap().is_none());
1022
1023                let mut changes = Changes::default();
1024                changes.key_requests.push(request.clone());
1025                store.save_changes(changes).await.unwrap();
1026
1027                let request = Some(request);
1028
1029                let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
1030                assert_eq!(request, stored_request);
1031
1032                let stored_request = store.get_secret_request_by_info(&info).await.unwrap();
1033                assert_eq!(request, stored_request);
1034                assert!(!store.get_unsent_secret_requests().await.unwrap().is_empty());
1035
1036                let request = GossipRequest {
1037                    request_recipient: account.user_id().to_owned(),
1038                    request_id: id.clone(),
1039                    info: info.clone(),
1040                    sent_out: true,
1041                };
1042
1043                let mut changes = Changes::default();
1044                changes.key_requests.push(request.clone());
1045                store.save_changes(changes).await.unwrap();
1046
1047                assert!(store.get_unsent_secret_requests().await.unwrap().is_empty());
1048                let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
1049                assert_eq!(Some(request), stored_request);
1050
1051                store.delete_outgoing_secret_requests(&id).await.unwrap();
1052
1053                let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
1054                assert_eq!(None, stored_request);
1055
1056                let stored_request = store.get_secret_request_by_info(&info).await.unwrap();
1057                assert_eq!(None, stored_request);
1058                assert!(store.get_unsent_secret_requests().await.unwrap().is_empty());
1059            }
1060
1061            #[async_test]
1062            async fn test_gossipped_secret_saving() {
1063                let (account, store) = get_loaded_store("gossipped_secret_saving").await;
1064
1065                let secret = "It is a secret to everybody";
1066
1067                let id = TransactionId::new();
1068                let info: SecretInfo = MegolmV1AesSha2Content {
1069                    room_id: room_id!("!test:localhost").to_owned(),
1070                    sender_key: Some(account.identity_keys().curve25519),
1071                    session_id: "test_session_id".to_owned(),
1072                }
1073                .into();
1074
1075                let gossip_request = GossipRequest {
1076                    request_recipient: account.user_id().to_owned(),
1077                    request_id: id.clone(),
1078                    info: info.clone(),
1079                    sent_out: true,
1080                };
1081
1082                let mut event = DecryptedSecretSendEvent {
1083                    sender: account.user_id().to_owned(),
1084                    recipient: account.user_id().to_owned(),
1085                    keys: OlmV1Keys {
1086                        ed25519: account.identity_keys().ed25519,
1087                    },
1088                    recipient_keys: OlmV1Keys {
1089                        ed25519: account.identity_keys().ed25519,
1090                    },
1091                    sender_device_keys: None,
1092                    content: SecretSendContent::new(id.to_owned(), secret.to_owned()),
1093                };
1094
1095                let value = GossippedSecret {
1096                    secret_name: SecretName::RecoveryKey,
1097                    gossip_request: gossip_request.to_owned(),
1098                    event: event.to_owned(),
1099                };
1100
1101                assert!(
1102                    store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap().is_empty(),
1103                    "No secret should initially be found in the store"
1104                );
1105
1106                let mut changes = Changes::default();
1107                changes.secrets.push(value);
1108                store.save_changes(changes).await.unwrap();
1109
1110                let restored = store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
1111                let first_secret = restored.first().expect("We should have restored a secret now");
1112                assert_eq!(first_secret.event.content.secret, secret);
1113                assert_eq!(restored.len(), 1, "We should only have one secret stored for now");
1114
1115                event.content.request_id = TransactionId::new();
1116                let another_secret = GossippedSecret {
1117                    secret_name: SecretName::RecoveryKey,
1118                    gossip_request,
1119                    event,
1120                };
1121
1122                let mut changes = Changes::default();
1123                changes.secrets.push(another_secret);
1124                store.save_changes(changes).await.unwrap();
1125
1126                let restored = store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
1127                assert_eq!(restored.len(), 2, "We should only have two secrets stored");
1128
1129                let restored = store.get_secrets_from_inbox(&SecretName::CrossSigningMasterKey).await.unwrap();
1130                assert!(restored.is_empty(), "We should not have secrets of a different type stored");
1131
1132                store.delete_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
1133
1134                let restored = store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
1135                assert!(restored.is_empty(), "We should not have any secrets after we have deleted them");
1136            }
1137
1138            #[async_test]
1139            async fn test_withheld_info_storage() {
1140                let (account, store) = get_loaded_store("withheld_info_storage").await;
1141
1142                let user_id = account.user_id().to_owned();
1143                let room_id = room_id!("!DwLygpkclUAfQNnfva:example.com");
1144                let session_id_1 = "GBnDxGP9i3IkPsz3/ihNr6P7qjIXxSRVWZ1MYmSn09w";
1145                let session_id_2 = "IDLtnNCH2kIr3xIf1B7JFkGpQmTjyMca2jww+X6zeOE";
1146
1147                {
1148                    let mut info_list: BTreeMap<_, BTreeMap<_, RoomKeyWithheldEntry>> = BTreeMap::new();
1149
1150                    let content = RoomKeyWithheldContent::MegolmV1AesSha2(
1151                        MegolmV1AesSha2WithheldContent::Unverified(
1152                            CommonWithheldCodeContent::new(
1153                                room_id.to_owned(),
1154                                session_id_1.into(),
1155                                Curve25519PublicKey::from_base64(
1156                                    "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA",
1157                                )
1158                                .unwrap(),
1159                                "DEVICEID".into(),
1160                            )
1161                            .into(),
1162                        ),
1163                    );
1164                    let event = ToDeviceEvent::new(user_id.to_owned(), content);
1165                    info_list
1166                        .entry(room_id.to_owned())
1167                        .or_default()
1168                        .insert(session_id_1.to_owned(), event.into());
1169
1170                    let content = RoomKeyWithheldContent::MegolmV1AesSha2(
1171                        MegolmV1AesSha2WithheldContent::BlackListed(
1172                            CommonWithheldCodeContent::new(
1173                                room_id.to_owned(),
1174                                session_id_2.into(),
1175                                Curve25519PublicKey::from_base64(
1176                                    "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA",
1177                                )
1178                                .unwrap(),
1179                                "DEVICEID".into(),
1180                            )
1181                            .into(),
1182                        ),
1183                    );
1184                    let event = ToDeviceEvent::new(user_id.to_owned(), content);
1185                    info_list
1186                        .entry(room_id.to_owned())
1187                        .or_default()
1188                        .insert(session_id_2.to_owned(), event.into());
1189
1190                    let changes = Changes { withheld_session_info: info_list, ..Default::default() };
1191                    store.save_changes(changes).await.unwrap();
1192                }
1193
1194                // Test `get_withheld_info`
1195
1196                let is_withheld = store.get_withheld_info(room_id, session_id_1).await.unwrap();
1197
1198                assert_matches!(
1199                    is_withheld, Some(event)
1200                    if event.content.algorithm() == EventEncryptionAlgorithm::MegolmV1AesSha2 &&
1201                    event.content.withheld_code() == WithheldCode::Unverified
1202                );
1203
1204                let is_withheld = store.get_withheld_info(room_id, session_id_2).await.unwrap();
1205
1206                assert_matches!(
1207                    is_withheld, Some(event)
1208                    if event.content.algorithm() == EventEncryptionAlgorithm::MegolmV1AesSha2 &&
1209                    event.content.withheld_code() == WithheldCode::Blacklisted
1210                );
1211
1212                let other_room_id = room_id!("!nQRyiRFuyUhXeaQfiR:example.com");
1213
1214                let is_withheld =
1215                    store.get_withheld_info(other_room_id, session_id_2).await.unwrap();
1216
1217                assert!(is_withheld.is_none());
1218
1219                // Test `get_withheld_sessions_by_room_id`
1220                let withhelds = store.get_withheld_sessions_by_room_id(room_id).await.expect("Error getting withheld sessions by room ID");
1221                assert_eq!(withhelds.len(), 2);
1222                let withheld1 = withhelds.iter().find(|entry| entry.content.megolm_session_id() == Some(session_id_1)).expect("Did not find session 1 in withhelds list");
1223                assert_eq!(withheld1.content.withheld_code(), WithheldCode::Unverified)
1224            }
1225
1226            #[async_test]
1227            async fn test_room_settings_saving() {
1228                let (_, store) = get_loaded_store("room_settings_saving").await;
1229
1230                let room_1 = room_id!("!test_1:localhost");
1231                let settings_1 = RoomSettings {
1232                    algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
1233                    #[cfg(feature = "experimental-encrypted-state-events")]
1234                    encrypt_state_events: false,
1235                    only_allow_trusted_devices: true,
1236                    session_rotation_period: Some(Duration::from_secs(10)),
1237                    session_rotation_period_messages: Some(123),
1238                };
1239
1240                let room_2 = room_id!("!test_2:localhost");
1241                let settings_2 = RoomSettings {
1242                    algorithm: EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
1243                    only_allow_trusted_devices: false,
1244                    ..Default::default()
1245                };
1246
1247                let room_3 = room_id!("!test_3:localhost");
1248
1249                let changes = Changes {
1250                    room_settings: HashMap::from([
1251                        (room_1.into(), settings_1.clone()),
1252                        (room_2.into(), settings_2.clone()),
1253                    ]),
1254                    ..Default::default()
1255                };
1256
1257                store.save_changes(changes).await.unwrap();
1258
1259                let loaded_settings_1 = store.get_room_settings(room_1).await.unwrap();
1260                assert_eq!(Some(settings_1), loaded_settings_1);
1261
1262                let loaded_settings_2 = store.get_room_settings(room_2).await.unwrap();
1263                assert_eq!(Some(settings_2), loaded_settings_2);
1264
1265                let loaded_settings_3 = store.get_room_settings(room_3).await.unwrap();
1266                assert_eq!(None, loaded_settings_3);
1267            }
1268
1269            #[async_test]
1270            async fn test_backup_keys_saving() {
1271                let (_account, store) = get_loaded_store("backup_keys_saving").await;
1272
1273                let restored = store.load_backup_keys().await.unwrap();
1274                assert!(restored.decryption_key.is_none(), "Initially no backup decryption key should be present");
1275
1276                let backup_decryption_key = Some(BackupDecryptionKey::new().unwrap());
1277
1278                let changes = Changes { backup_decryption_key, ..Default::default() };
1279                store.save_changes(changes).await.unwrap();
1280
1281                let restored = store.load_backup_keys().await.unwrap();
1282                assert!(restored.decryption_key.is_some(), "We should be able to restore a backup decryption key");
1283                assert!(restored.backup_version.is_none(), "The backup version should still be None");
1284
1285                let changes = Changes { backup_version: Some("some_version".to_owned()), ..Default::default() };
1286                store.save_changes(changes).await.unwrap();
1287
1288                let restored = store.load_backup_keys().await.unwrap();
1289                assert!(restored.decryption_key.is_some(), "The backup decryption key should still be known");
1290                assert!(restored.backup_version.is_some(), "The backup version should now be Some as well");
1291            }
1292
1293            #[async_test]
1294            async fn test_dehydration_pickle_key_saving() {
1295                let (_account, store) = get_loaded_store("dehydration_pickle_key_saving").await;
1296
1297                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1298                assert!(restored.is_none(), "Initially no pickle key should be present");
1299
1300                let dehydrated_device_pickle_key = Some(DehydratedDeviceKey::new().unwrap());
1301                let exported_base64 = dehydrated_device_pickle_key.clone().unwrap().to_base64();
1302
1303                let changes = Changes { dehydrated_device_pickle_key, ..Default::default() };
1304                store.save_changes(changes).await.unwrap();
1305
1306                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1307                assert!(restored.is_some(), "We should be able to restore a pickle key");
1308                assert_eq!(restored.unwrap().to_base64(), exported_base64);
1309
1310                // If None, should not clear the existing saved key
1311                let changes = Changes { dehydrated_device_pickle_key: None, ..Default::default() };
1312                store.save_changes(changes).await.unwrap();
1313
1314                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1315                assert!(restored.is_some(), "We should be able to restore a pickle key");
1316                assert_eq!(restored.unwrap().to_base64(), exported_base64);
1317
1318            }
1319
1320             #[async_test]
1321            async fn test_delete_dehydration_pickle_key() {
1322                let (_account, store) = get_loaded_store("delete_dehydration_pickle_key").await;
1323
1324                let dehydrated_device_pickle_key = DehydratedDeviceKey::new().unwrap();
1325
1326                let changes = Changes { dehydrated_device_pickle_key: Some(dehydrated_device_pickle_key), ..Default::default() };
1327                store.save_changes(changes).await.unwrap();
1328
1329                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1330                assert!(restored.is_some(), "We should be able to restore a pickle key");
1331
1332                store.delete_dehydrated_device_pickle_key().await.unwrap();
1333
1334                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1335                assert!(restored.is_none(), "The previously saved key should be deleted");
1336
1337            }
1338
1339
1340            #[async_test]
1341            async fn test_custom_value_saving() {
1342                let (_, store) = get_loaded_store("custom_value_saving").await;
1343                store.set_custom_value("A", "Hello".as_bytes().to_vec()).await.unwrap();
1344
1345                let loaded_1 = store.get_custom_value("A").await.unwrap();
1346                assert_eq!(Some("Hello".as_bytes().to_vec()), loaded_1);
1347
1348                let loaded_2 = store.get_custom_value("B").await.unwrap();
1349                assert_eq!(None, loaded_2);
1350            }
1351
1352            #[async_test]
1353            async fn test_received_room_key_bundle() {
1354                let store = get_store("received_room_key_bundle", None, true).await;
1355                let test_room = room_id!("!room:example.org");
1356
1357                fn make_bundle_data(sender_user: &UserId, bundle_uri: &str) -> StoredRoomKeyBundleData {
1358                    let jwk = ruma::events::room::JsonWebKeyInit {
1359                        kty: "oct".to_owned(),
1360                        key_ops: vec!["encrypt".to_owned(), "decrypt".to_owned()],
1361                        alg: "A256CTR".to_owned(),
1362                        k: ruma::serde::Base64::new(vec![0u8; 0]),
1363                        ext: true,
1364                    }.into();
1365
1366                    let file = ruma::events::room::EncryptedFileInit {
1367                        url: ruma::OwnedMxcUri::from(bundle_uri),
1368                        key: jwk,
1369                        iv: ruma::serde::Base64::new(vec![0u8; 0]),
1370                        hashes: Default::default(),
1371                        v: "".to_owned(),
1372                    }.into();
1373
1374                    StoredRoomKeyBundleData {
1375                        sender_user: sender_user.to_owned(),
1376                        sender_key: Curve25519PublicKey::from_bytes([0u8; 32]),
1377                        sender_data: SenderData::unknown(),
1378                        bundle_data: RoomKeyBundleContent {
1379                            room_id: room_id!("!room:example.org").to_owned(),
1380                            file,
1381                        },
1382                    }
1383                }
1384
1385                // Add three entries
1386                let changes = Changes {
1387                    received_room_key_bundles: vec![
1388                        make_bundle_data(user_id!("@alice:example.com"), "alice1"),
1389                        make_bundle_data(user_id!("@bob:example.com"), "bob1"),
1390                        make_bundle_data(user_id!("@alice:example.com"), "alice2"),
1391                    ],
1392                    ..Default::default()
1393                };
1394                store.save_changes(changes).await.unwrap();
1395
1396                // Check we get the right one
1397                let bundle = store.get_received_room_key_bundle_data(
1398                    test_room, user_id!("@alice:example.com")
1399                ).await.unwrap().expect("Did not get any bundle data");
1400                assert_eq!(bundle.bundle_data.file.url.to_string(), "alice2");
1401            }
1402
1403            fn session_info(session: &InboundGroupSession) -> (&RoomId, &str) {
1404                (&session.room_id(), &session.session_id())
1405            }
1406
1407            async fn create_session(
1408                account: &Account,
1409                device_curve_key: &Curve25519PublicKey,
1410                sender_data_type: SenderDataType,
1411            ) -> InboundGroupSession {
1412                let sender_data = match sender_data_type {
1413                    SenderDataType::UnknownDevice => {
1414                        SenderData::UnknownDevice { legacy_session: false, owner_check_failed: false }
1415                    }
1416                    SenderDataType::DeviceInfo => SenderData::DeviceInfo {
1417                        device_keys: account.device_keys().clone(),
1418                        legacy_session: false,
1419                    },
1420                    SenderDataType::VerificationViolation => panic!("VerificationViolation not supported"),
1421                    SenderDataType::SenderUnverified=> panic!("SenderUnverified not supported"),
1422                    SenderDataType::SenderVerified => panic!("SenderVerified not supported"),
1423                };
1424
1425                let session_key = GroupSession::new(SessionConfig::default()).session_key();
1426
1427                InboundGroupSession::new(
1428                    device_curve_key.clone(),
1429                    account.device_keys().ed25519_key().unwrap(),
1430                    room_id!("!r:s.co"),
1431                    &session_key,
1432                    sender_data,
1433                    EventEncryptionAlgorithm::MegolmV1AesSha2,
1434                    None,
1435                    false,
1436                )
1437                .unwrap()
1438            }
1439        }
1440    };
1441}
1442
1443#[allow(unused_macros)]
1444#[macro_export]
1445macro_rules! cryptostore_integration_tests_time {
1446    () => {
1447        mod cryptostore_integration_tests_time {
1448            use std::time::Duration;
1449
1450            use matrix_sdk_test::async_test;
1451            use $crate::store::CryptoStore as _;
1452
1453            use super::cryptostore_integration_tests::*;
1454
1455            #[async_test]
1456            async fn test_lease_locks() {
1457                let (_account, store) = get_loaded_store("lease_locks").await;
1458
1459                let acquired0 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
1460                assert!(acquired0);
1461
1462                // Should extend the lease automatically (same holder).
1463                let acquired2 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1464                assert!(acquired2);
1465
1466                // Should extend the lease automatically (same holder + time is ok).
1467                let acquired3 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1468                assert!(acquired3);
1469
1470                // Another attempt at taking the lock should fail, because it's taken.
1471                let acquired4 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1472                assert!(!acquired4);
1473
1474                // Even if we insist.
1475                let acquired5 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1476                assert!(!acquired5);
1477
1478                // That's a nice test we got here, go take a little nap.
1479                tokio::time::sleep(Duration::from_millis(50)).await;
1480
1481                // Still too early.
1482                let acquired55 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1483                assert!(!acquired55);
1484
1485                // Ok you can take another nap then.
1486                tokio::time::sleep(Duration::from_millis(250)).await;
1487
1488                // At some point, we do get the lock.
1489                let acquired6 = store.try_take_leased_lock(0, "key", "bob").await.unwrap();
1490                assert!(acquired6);
1491
1492                tokio::time::sleep(Duration::from_millis(1)).await;
1493
1494                // The other gets it almost immediately too.
1495                let acquired7 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
1496                assert!(acquired7);
1497
1498                tokio::time::sleep(Duration::from_millis(1)).await;
1499
1500                // But when we take a longer lease...
1501                let acquired8 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1502                assert!(acquired8);
1503
1504                // It blocks the other user.
1505                let acquired9 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1506                assert!(!acquired9);
1507
1508                // We can hold onto our lease.
1509                let acquired10 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1510                assert!(acquired10);
1511            }
1512        }
1513    };
1514}