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