1use std::{
16 collections::HashMap,
17 fmt,
18 path::Path,
19 sync::{Arc, RwLock},
20};
21
22use async_trait::async_trait;
23use matrix_sdk_base::cross_process_lock::CrossProcessLockGeneration;
24use matrix_sdk_crypto::{
25 Account, DeviceData, GossipRequest, GossippedSecret, SecretInfo, TrackedUser, UserIdentityData,
26 olm::{
27 InboundGroupSession, OutboundGroupSession, PickledInboundGroupSession,
28 PrivateCrossSigningIdentity, SenderDataType, Session, StaticAccountData,
29 },
30 store::{
31 CryptoStore,
32 types::{
33 BackupKeys, Changes, DehydratedDeviceKey, PendingChanges, RoomKeyCounts,
34 RoomKeyWithheldEntry, RoomPendingKeyBundleDetails, RoomSettings,
35 StoredRoomKeyBundleData,
36 },
37 },
38};
39use matrix_sdk_store_encryption::StoreCipher;
40use ruma::{
41 DeviceId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, RoomId, TransactionId, UserId,
42 events::secret::request::SecretName,
43};
44use rusqlite::{OptionalExtension, named_params, params_from_iter};
45use tokio::{
46 fs,
47 sync::{Mutex, OwnedMutexGuard},
48};
49use tracing::{debug, instrument, warn};
50use vodozemac::Curve25519PublicKey;
51
52use crate::{
53 OpenStoreError, Secret, SqliteStoreConfig,
54 connection::{Connection as SqliteAsyncConn, Pool as SqlitePool},
55 error::{Error, Result},
56 utils::{
57 EncryptableStore, Key, SqliteAsyncConnExt, SqliteKeyValueStoreAsyncConnExt,
58 SqliteKeyValueStoreConnExt, repeat_vars,
59 },
60};
61
62const DATABASE_NAME: &str = "matrix-sdk-crypto.sqlite3";
64
65#[derive(Clone)]
67pub struct SqliteCryptoStore {
68 store_cipher: Option<Arc<StoreCipher>>,
69
70 pool: SqlitePool,
72
73 write_connection: Arc<Mutex<SqliteAsyncConn>>,
78
79 static_account: Arc<RwLock<Option<StaticAccountData>>>,
81 save_changes_lock: Arc<Mutex<()>>,
82}
83
84#[cfg(not(tarpaulin_include))]
85impl fmt::Debug for SqliteCryptoStore {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 f.debug_struct("SqliteCryptoStore").finish_non_exhaustive()
88 }
89}
90
91impl EncryptableStore for SqliteCryptoStore {
92 fn get_cypher(&self) -> Option<&StoreCipher> {
93 self.store_cipher.as_deref()
94 }
95}
96
97impl SqliteCryptoStore {
98 pub async fn open(
101 path: impl AsRef<Path>,
102 passphrase: Option<&str>,
103 ) -> Result<Self, OpenStoreError> {
104 Self::open_with_config(SqliteStoreConfig::new(path).passphrase(passphrase)).await
105 }
106
107 pub async fn open_with_key(
110 path: impl AsRef<Path>,
111 key: Option<&[u8; 32]>,
112 ) -> Result<Self, OpenStoreError> {
113 Self::open_with_config(SqliteStoreConfig::new(path).key(key)).await
114 }
115
116 pub async fn open_with_config(config: SqliteStoreConfig) -> Result<Self, OpenStoreError> {
118 fs::create_dir_all(&config.path).await.map_err(OpenStoreError::CreateDir)?;
119
120 let pool = config.build_pool_of_connections(DATABASE_NAME)?;
121
122 let this = Self::open_with_pool(pool, config.secret).await?;
123 this.pool.get().await?.apply_runtime_config(config.runtime_config).await?;
124
125 Ok(this)
126 }
127
128 async fn open_with_pool(
131 pool: SqlitePool,
132 secret: Option<Secret>,
133 ) -> Result<Self, OpenStoreError> {
134 let conn = pool.get().await?;
135
136 let version = conn.db_version().await?;
137 debug!("Opened sqlite store with version {}", version);
138 run_migrations(&conn, version).await?;
139
140 conn.wal_checkpoint().await;
141
142 let store_cipher = match secret {
143 Some(s) => Some(Arc::new(conn.get_or_create_store_cipher(s).await?)),
144 None => None,
145 };
146
147 Ok(SqliteCryptoStore {
148 store_cipher,
149 pool,
150 write_connection: Arc::new(Mutex::new(conn)),
152 static_account: Arc::new(RwLock::new(None)),
153 save_changes_lock: Default::default(),
154 })
155 }
156
157 fn deserialize_and_unpickle_inbound_group_session(
158 &self,
159 value: Vec<u8>,
160 backed_up: bool,
161 ) -> Result<InboundGroupSession> {
162 let mut pickle: PickledInboundGroupSession = self.deserialize_value(&value)?;
163
164 pickle.backed_up = backed_up;
169
170 Ok(InboundGroupSession::from_pickle(pickle)?)
171 }
172
173 fn deserialize_key_request(&self, value: &[u8], sent_out: bool) -> Result<GossipRequest> {
174 let mut request: GossipRequest = self.deserialize_value(value)?;
175 request.sent_out = sent_out;
178 Ok(request)
179 }
180
181 fn get_static_account(&self) -> Option<StaticAccountData> {
182 self.static_account.read().unwrap().clone()
183 }
184
185 #[instrument(skip_all)]
187 async fn read(&self) -> Result<SqliteAsyncConn> {
188 Ok(self.pool.get().await?)
189 }
190
191 #[instrument(skip_all)]
193 async fn write(&self) -> OwnedMutexGuard<SqliteAsyncConn> {
194 self.write_connection.clone().lock_owned().await
195 }
196}
197
198const DEHYDRATED_DEVICE_PICKLE_KEY: &str = "dehydrated_device_pickle_key";
200
201async fn run_migrations(conn: &SqliteAsyncConn, version: u8) -> Result<()> {
203 if version < 1 {
204 debug!("Creating database");
205 conn.execute_batch("PRAGMA journal_mode = wal;").await?;
208 conn.with_transaction(|txn| {
209 txn.execute_batch(include_str!("../migrations/crypto_store/001_init.sql"))?;
210 txn.set_db_version(1)
211 })
212 .await?;
213 }
214
215 if version < 2 {
216 debug!("Upgrading database to version 2");
217 conn.with_transaction(|txn| {
218 txn.execute_batch(include_str!("../migrations/crypto_store/002_reset_olm_hash.sql"))?;
219 txn.set_db_version(2)
220 })
221 .await?;
222 }
223
224 if version < 3 {
225 debug!("Upgrading database to version 3");
226 conn.with_transaction(|txn| {
227 txn.execute_batch(include_str!("../migrations/crypto_store/003_room_settings.sql"))?;
228 txn.set_db_version(3)
229 })
230 .await?;
231 }
232
233 if version < 4 {
234 debug!("Upgrading database to version 4");
235 conn.with_transaction(|txn| {
236 txn.execute_batch(include_str!(
237 "../migrations/crypto_store/004_drop_outbound_group_sessions.sql"
238 ))?;
239 txn.set_db_version(4)
240 })
241 .await?;
242 }
243
244 if version < 5 {
245 debug!("Upgrading database to version 5");
246 conn.with_transaction(|txn| {
247 txn.execute_batch(include_str!("../migrations/crypto_store/005_withheld_code.sql"))?;
248 txn.set_db_version(5)
249 })
250 .await?;
251 }
252
253 if version < 6 {
254 debug!("Upgrading database to version 6");
255 conn.with_transaction(|txn| {
256 txn.execute_batch(include_str!(
257 "../migrations/crypto_store/006_drop_outbound_group_sessions.sql"
258 ))?;
259 txn.set_db_version(6)
260 })
261 .await?;
262 }
263
264 if version < 7 {
265 debug!("Upgrading database to version 7");
266 conn.with_transaction(|txn| {
267 txn.execute_batch(include_str!("../migrations/crypto_store/007_lock_leases.sql"))?;
268 txn.set_db_version(7)
269 })
270 .await?;
271 }
272
273 if version < 8 {
274 debug!("Upgrading database to version 8");
275 conn.with_transaction(|txn| {
276 txn.execute_batch(include_str!("../migrations/crypto_store/008_secret_inbox.sql"))?;
277 txn.set_db_version(8)
278 })
279 .await?;
280 }
281
282 if version < 9 {
283 debug!("Upgrading database to version 9");
284 conn.with_transaction(|txn| {
285 txn.execute_batch(include_str!(
286 "../migrations/crypto_store/009_inbound_group_session_sender_key_sender_data_type.sql"
287 ))?;
288 txn.set_db_version(9)
289 })
290 .await?;
291 }
292
293 if version < 10 {
294 debug!("Upgrading database to version 10");
295 conn.with_transaction(|txn| {
296 txn.execute_batch(include_str!(
297 "../migrations/crypto_store/010_received_room_key_bundles.sql"
298 ))?;
299 txn.set_db_version(10)
300 })
301 .await?;
302 }
303
304 if version < 11 {
305 debug!("Upgrading database to version 11");
306 conn.with_transaction(|txn| {
307 txn.execute_batch(include_str!(
308 "../migrations/crypto_store/011_received_room_key_bundles_with_curve_key.sql"
309 ))?;
310 txn.set_db_version(11)
311 })
312 .await?;
313 }
314
315 if version < 12 {
316 debug!("Upgrading database to version 12");
317 conn.with_transaction(|txn| {
318 txn.execute_batch(include_str!(
319 "../migrations/crypto_store/012_withheld_code_by_room.sql"
320 ))?;
321 txn.set_db_version(12)
322 })
323 .await?;
324 }
325
326 if version < 13 {
327 debug!("Upgrading database to version 13");
328 conn.with_transaction(|txn| {
329 txn.execute_batch(include_str!(
330 "../migrations/crypto_store/013_lease_locks_with_generation.sql"
331 ))?;
332 txn.set_db_version(13)
333 })
334 .await?;
335 }
336
337 if version < 14 {
338 debug!("Upgrading database to version 14");
339 conn.with_transaction(|txn| {
340 txn.execute_batch(include_str!(
341 "../migrations/crypto_store/014_room_key_backups_fully_downloaded.sql"
342 ))?;
343 txn.set_db_version(14)
344 })
345 .await?;
346 }
347
348 if version < 15 {
349 debug!("Upgrading database to version 15");
350 conn.with_transaction(|txn| {
351 txn.execute_batch(include_str!(
352 "../migrations/crypto_store/015_rooms_pending_key_bundle.sql"
353 ))?;
354 txn.set_db_version(15)
355 })
356 .await?;
357 }
358
359 Ok(())
360}
361
362trait SqliteConnectionExt {
363 fn set_session(
364 &self,
365 session_id: &[u8],
366 sender_key: &[u8],
367 data: &[u8],
368 ) -> rusqlite::Result<()>;
369
370 fn set_inbound_group_session(
371 &self,
372 room_id: &[u8],
373 session_id: &[u8],
374 data: &[u8],
375 backed_up: bool,
376 sender_key: Option<&[u8]>,
377 sender_data_type: Option<u8>,
378 ) -> rusqlite::Result<()>;
379
380 fn set_outbound_group_session(&self, room_id: &[u8], data: &[u8]) -> rusqlite::Result<()>;
381
382 fn set_device(&self, user_id: &[u8], device_id: &[u8], data: &[u8]) -> rusqlite::Result<()>;
383 fn delete_device(&self, user_id: &[u8], device_id: &[u8]) -> rusqlite::Result<()>;
384
385 fn set_identity(&self, user_id: &[u8], data: &[u8]) -> rusqlite::Result<()>;
386
387 fn add_olm_hash(&self, data: &[u8]) -> rusqlite::Result<()>;
388
389 fn set_key_request(
390 &self,
391 request_id: &[u8],
392 sent_out: bool,
393 data: &[u8],
394 ) -> rusqlite::Result<()>;
395
396 fn set_direct_withheld(
397 &self,
398 session_id: &[u8],
399 room_id: &[u8],
400 data: &[u8],
401 ) -> rusqlite::Result<()>;
402
403 fn set_room_settings(&self, room_id: &[u8], data: &[u8]) -> rusqlite::Result<()>;
404
405 fn set_secret(&self, request_id: &[u8], data: &[u8]) -> rusqlite::Result<()>;
406
407 fn set_received_room_key_bundle(
408 &self,
409 room_id: &[u8],
410 user_id: &[u8],
411 data: &[u8],
412 ) -> rusqlite::Result<()>;
413
414 fn set_has_downloaded_all_room_keys(&self, room_id: &[u8]) -> rusqlite::Result<()>;
415
416 fn set_room_pending_key_bundle(
417 &self,
418 room_id: &[u8],
419 details: Option<&[u8]>,
420 ) -> rusqlite::Result<()>;
421}
422
423impl SqliteConnectionExt for rusqlite::Connection {
424 fn set_session(
425 &self,
426 session_id: &[u8],
427 sender_key: &[u8],
428 data: &[u8],
429 ) -> rusqlite::Result<()> {
430 self.execute(
431 "INSERT INTO session (session_id, sender_key, data)
432 VALUES (?1, ?2, ?3)
433 ON CONFLICT (session_id) DO UPDATE SET data = ?3",
434 (session_id, sender_key, data),
435 )?;
436 Ok(())
437 }
438
439 fn set_inbound_group_session(
440 &self,
441 room_id: &[u8],
442 session_id: &[u8],
443 data: &[u8],
444 backed_up: bool,
445 sender_key: Option<&[u8]>,
446 sender_data_type: Option<u8>,
447 ) -> rusqlite::Result<()> {
448 self.execute(
449 "INSERT INTO inbound_group_session (session_id, room_id, data, backed_up, sender_key, sender_data_type) \
450 VALUES (?1, ?2, ?3, ?4, ?5, ?6)
451 ON CONFLICT (session_id) DO UPDATE SET data = ?3, backed_up = ?4, sender_key = ?5, sender_data_type = ?6",
452 (session_id, room_id, data, backed_up, sender_key, sender_data_type),
453 )?;
454 Ok(())
455 }
456
457 fn set_outbound_group_session(&self, room_id: &[u8], data: &[u8]) -> rusqlite::Result<()> {
458 self.execute(
459 "INSERT INTO outbound_group_session (room_id, data) \
460 VALUES (?1, ?2)
461 ON CONFLICT (room_id) DO UPDATE SET data = ?2",
462 (room_id, data),
463 )?;
464 Ok(())
465 }
466
467 fn set_device(&self, user_id: &[u8], device_id: &[u8], data: &[u8]) -> rusqlite::Result<()> {
468 self.execute(
469 "INSERT INTO device (user_id, device_id, data) \
470 VALUES (?1, ?2, ?3)
471 ON CONFLICT (user_id, device_id) DO UPDATE SET data = ?3",
472 (user_id, device_id, data),
473 )?;
474 Ok(())
475 }
476
477 fn delete_device(&self, user_id: &[u8], device_id: &[u8]) -> rusqlite::Result<()> {
478 self.execute(
479 "DELETE FROM device WHERE user_id = ? AND device_id = ?",
480 (user_id, device_id),
481 )?;
482 Ok(())
483 }
484
485 fn set_identity(&self, user_id: &[u8], data: &[u8]) -> rusqlite::Result<()> {
486 self.execute(
487 "INSERT INTO identity (user_id, data) \
488 VALUES (?1, ?2)
489 ON CONFLICT (user_id) DO UPDATE SET data = ?2",
490 (user_id, data),
491 )?;
492 Ok(())
493 }
494
495 fn add_olm_hash(&self, data: &[u8]) -> rusqlite::Result<()> {
496 self.execute("INSERT INTO olm_hash (data) VALUES (?) ON CONFLICT DO NOTHING", (data,))?;
497 Ok(())
498 }
499
500 fn set_key_request(
501 &self,
502 request_id: &[u8],
503 sent_out: bool,
504 data: &[u8],
505 ) -> rusqlite::Result<()> {
506 self.execute(
507 "INSERT INTO key_requests (request_id, sent_out, data)
508 VALUES (?1, ?2, ?3)
509 ON CONFLICT (request_id) DO UPDATE SET sent_out = ?2, data = ?3",
510 (request_id, sent_out, data),
511 )?;
512 Ok(())
513 }
514
515 fn set_direct_withheld(
516 &self,
517 session_id: &[u8],
518 room_id: &[u8],
519 data: &[u8],
520 ) -> rusqlite::Result<()> {
521 self.execute(
522 "INSERT INTO direct_withheld_info (session_id, room_id, data)
523 VALUES (?1, ?2, ?3)
524 ON CONFLICT (session_id) DO UPDATE SET room_id = ?2, data = ?3",
525 (session_id, room_id, data),
526 )?;
527 Ok(())
528 }
529
530 fn set_room_settings(&self, room_id: &[u8], data: &[u8]) -> rusqlite::Result<()> {
531 self.execute(
532 "INSERT INTO room_settings (room_id, data)
533 VALUES (?1, ?2)
534 ON CONFLICT (room_id) DO UPDATE SET data = ?2",
535 (room_id, data),
536 )?;
537 Ok(())
538 }
539
540 fn set_secret(&self, secret_name: &[u8], data: &[u8]) -> rusqlite::Result<()> {
541 self.execute(
542 "INSERT INTO secrets (secret_name, data)
543 VALUES (?1, ?2)",
544 (secret_name, data),
545 )?;
546
547 Ok(())
548 }
549
550 fn set_received_room_key_bundle(
551 &self,
552 room_id: &[u8],
553 sender_user_id: &[u8],
554 data: &[u8],
555 ) -> rusqlite::Result<()> {
556 self.execute(
557 "INSERT INTO received_room_key_bundle(room_id, sender_user_id, bundle_data)
558 VALUES (?1, ?2, ?3)
559 ON CONFLICT (room_id, sender_user_id) DO UPDATE SET bundle_data = ?3",
560 (room_id, sender_user_id, data),
561 )?;
562 Ok(())
563 }
564
565 fn set_room_pending_key_bundle(
566 &self,
567 room_id: &[u8],
568 data: Option<&[u8]>,
569 ) -> rusqlite::Result<()> {
570 if let Some(data) = data {
571 self.execute(
572 "INSERT INTO rooms_pending_key_bundle (room_id, data)
573 VALUES (?1, ?2)
574 ON CONFLICT (room_id) DO UPDATE SET data = ?2",
575 (room_id, data),
576 )?;
577 } else {
578 self.execute("DELETE FROM rooms_pending_key_bundle WHERE room_id = ?1", (room_id,))?;
579 }
580 Ok(())
581 }
582
583 fn set_has_downloaded_all_room_keys(&self, room_id: &[u8]) -> rusqlite::Result<()> {
584 self.execute(
585 "INSERT INTO room_key_backups_fully_downloaded(room_id)
586 VALUES (?1)
587 ON CONFLICT(room_id) DO NOTHING",
588 (room_id,),
589 )?;
590 Ok(())
591 }
592}
593
594#[async_trait]
595trait SqliteObjectCryptoStoreExt: SqliteAsyncConnExt {
596 async fn get_sessions_for_sender_key(&self, sender_key: Key) -> Result<Vec<Vec<u8>>> {
597 Ok(self
598 .prepare("SELECT data FROM session WHERE sender_key = ?", |mut stmt| {
599 stmt.query((sender_key,))?.mapped(|row| row.get(0)).collect()
600 })
601 .await?)
602 }
603
604 async fn get_inbound_group_session(
605 &self,
606 session_id: Key,
607 ) -> Result<Option<(Vec<u8>, Vec<u8>, bool)>> {
608 Ok(self
609 .query_row(
610 "SELECT room_id, data, backed_up FROM inbound_group_session WHERE session_id = ?",
611 (session_id,),
612 |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)),
613 )
614 .await
615 .optional()?)
616 }
617
618 async fn get_inbound_group_sessions(&self) -> Result<Vec<(Vec<u8>, bool)>> {
619 Ok(self
620 .prepare("SELECT data, backed_up FROM inbound_group_session", |mut stmt| {
621 stmt.query(())?.mapped(|row| Ok((row.get(0)?, row.get(1)?))).collect()
622 })
623 .await?)
624 }
625
626 async fn get_inbound_group_session_counts(
627 &self,
628 _backup_version: Option<&str>,
629 ) -> Result<RoomKeyCounts> {
630 let total = self
631 .query_row("SELECT count(*) FROM inbound_group_session", (), |row| row.get(0))
632 .await?;
633 let backed_up = self
634 .query_row(
635 "SELECT count(*) FROM inbound_group_session WHERE backed_up = TRUE",
636 (),
637 |row| row.get(0),
638 )
639 .await?;
640 Ok(RoomKeyCounts { total, backed_up })
641 }
642
643 async fn get_inbound_group_sessions_by_room_id(
644 &self,
645 room_id: Key,
646 ) -> Result<Vec<(Vec<u8>, bool)>> {
647 Ok(self
648 .prepare(
649 "SELECT data, backed_up FROM inbound_group_session WHERE room_id = :room_id",
650 move |mut stmt| {
651 stmt.query(named_params! {
652 ":room_id": room_id,
653 })?
654 .mapped(|row| Ok((row.get(0)?, row.get(1)?)))
655 .collect()
656 },
657 )
658 .await?)
659 }
660
661 async fn get_inbound_group_sessions_for_device_batch(
662 &self,
663 sender_key: Key,
664 sender_data_type: SenderDataType,
665 after_session_id: Option<Key>,
666 limit: usize,
667 ) -> Result<Vec<(Vec<u8>, bool)>> {
668 Ok(self
669 .prepare(
670 "
671 SELECT data, backed_up
672 FROM inbound_group_session
673 WHERE sender_key = :sender_key
674 AND sender_data_type = :sender_data_type
675 AND session_id > :after_session_id
676 ORDER BY session_id
677 LIMIT :limit
678 ",
679 move |mut stmt| {
680 let sender_data_type = sender_data_type as u8;
681
682 let after_session_id = after_session_id.unwrap_or(Key::Plain(Vec::new()));
685
686 stmt.query(named_params! {
687 ":sender_key": sender_key,
688 ":sender_data_type": sender_data_type,
689 ":after_session_id": after_session_id,
690 ":limit": limit,
691 })?
692 .mapped(|row| Ok((row.get(0)?, row.get(1)?)))
693 .collect()
694 },
695 )
696 .await?)
697 }
698
699 async fn get_inbound_group_sessions_for_backup(&self, limit: usize) -> Result<Vec<Vec<u8>>> {
700 Ok(self
701 .prepare(
702 "SELECT data FROM inbound_group_session WHERE backed_up = FALSE LIMIT ?",
703 move |mut stmt| stmt.query((limit,))?.mapped(|row| row.get(0)).collect(),
704 )
705 .await?)
706 }
707
708 async fn mark_inbound_group_sessions_as_backed_up(&self, session_ids: Vec<Key>) -> Result<()> {
709 if session_ids.is_empty() {
710 warn!("No sessions to mark as backed up!");
712 return Ok(());
713 }
714
715 let session_ids_len = session_ids.len();
716
717 self.chunk_large_query_over(session_ids, None, move |txn, session_ids| {
718 let sql_params = repeat_vars(session_ids_len);
721 let query = format!("UPDATE inbound_group_session SET backed_up = TRUE where session_id IN ({sql_params})");
722 txn.prepare(&query)?.execute(params_from_iter(session_ids.iter()))?;
723 Ok(Vec::<()>::new())
724 }).await?;
725
726 Ok(())
727 }
728
729 async fn reset_inbound_group_session_backup_state(&self) -> Result<()> {
730 self.execute("UPDATE inbound_group_session SET backed_up = FALSE", ()).await?;
731 Ok(())
732 }
733
734 async fn get_outbound_group_session(&self, room_id: Key) -> Result<Option<Vec<u8>>> {
735 Ok(self
736 .query_row(
737 "SELECT data FROM outbound_group_session WHERE room_id = ?",
738 (room_id,),
739 |row| row.get(0),
740 )
741 .await
742 .optional()?)
743 }
744
745 async fn get_device(&self, user_id: Key, device_id: Key) -> Result<Option<Vec<u8>>> {
746 Ok(self
747 .query_row(
748 "SELECT data FROM device WHERE user_id = ? AND device_id = ?",
749 (user_id, device_id),
750 |row| row.get(0),
751 )
752 .await
753 .optional()?)
754 }
755
756 async fn get_user_devices(&self, user_id: Key) -> Result<Vec<Vec<u8>>> {
757 Ok(self
758 .prepare("SELECT data FROM device WHERE user_id = ?", |mut stmt| {
759 stmt.query((user_id,))?.mapped(|row| row.get(0)).collect()
760 })
761 .await?)
762 }
763
764 async fn get_user_identity(&self, user_id: Key) -> Result<Option<Vec<u8>>> {
765 Ok(self
766 .query_row("SELECT data FROM identity WHERE user_id = ?", (user_id,), |row| row.get(0))
767 .await
768 .optional()?)
769 }
770
771 async fn has_olm_hash(&self, data: Vec<u8>) -> Result<bool> {
772 Ok(self
773 .query_row("SELECT count(*) FROM olm_hash WHERE data = ?", (data,), |row| {
774 row.get::<_, i32>(0)
775 })
776 .await?
777 > 0)
778 }
779
780 async fn get_tracked_users(&self) -> Result<Vec<Vec<u8>>> {
781 Ok(self
782 .prepare("SELECT data FROM tracked_user", |mut stmt| {
783 stmt.query(())?.mapped(|row| row.get(0)).collect()
784 })
785 .await?)
786 }
787
788 async fn add_tracked_users(&self, users: Vec<(Key, Vec<u8>)>) -> Result<()> {
789 Ok(self
790 .prepare(
791 "INSERT INTO tracked_user (user_id, data) \
792 VALUES (?1, ?2) \
793 ON CONFLICT (user_id) DO UPDATE SET data = ?2",
794 |mut stmt| {
795 for (user_id, data) in users {
796 stmt.execute((user_id, data))?;
797 }
798
799 Ok(())
800 },
801 )
802 .await?)
803 }
804
805 async fn get_outgoing_secret_request(
806 &self,
807 request_id: Key,
808 ) -> Result<Option<(Vec<u8>, bool)>> {
809 Ok(self
810 .query_row(
811 "SELECT data, sent_out FROM key_requests WHERE request_id = ?",
812 (request_id,),
813 |row| Ok((row.get(0)?, row.get(1)?)),
814 )
815 .await
816 .optional()?)
817 }
818
819 async fn get_outgoing_secret_requests(&self) -> Result<Vec<(Vec<u8>, bool)>> {
820 Ok(self
821 .prepare("SELECT data, sent_out FROM key_requests", |mut stmt| {
822 stmt.query(())?.mapped(|row| Ok((row.get(0)?, row.get(1)?))).collect()
823 })
824 .await?)
825 }
826
827 async fn get_unsent_secret_requests(&self) -> Result<Vec<Vec<u8>>> {
828 Ok(self
829 .prepare("SELECT data FROM key_requests WHERE sent_out = FALSE", |mut stmt| {
830 stmt.query(())?.mapped(|row| row.get(0)).collect()
831 })
832 .await?)
833 }
834
835 async fn delete_key_request(&self, request_id: Key) -> Result<()> {
836 self.execute("DELETE FROM key_requests WHERE request_id = ?", (request_id,)).await?;
837 Ok(())
838 }
839
840 async fn get_secrets_from_inbox(&self, secret_name: Key) -> Result<Vec<Vec<u8>>> {
841 Ok(self
842 .prepare("SELECT data FROM secrets WHERE secret_name = ?", |mut stmt| {
843 stmt.query((secret_name,))?.mapped(|row| row.get(0)).collect()
844 })
845 .await?)
846 }
847
848 async fn delete_secrets_from_inbox(&self, secret_name: Key) -> Result<()> {
849 self.execute("DELETE FROM secrets WHERE secret_name = ?", (secret_name,)).await?;
850 Ok(())
851 }
852
853 async fn get_direct_withheld_info(
854 &self,
855 session_id: Key,
856 room_id: Key,
857 ) -> Result<Option<Vec<u8>>> {
858 Ok(self
859 .query_row(
860 "SELECT data FROM direct_withheld_info WHERE session_id = ?1 AND room_id = ?2",
861 (session_id, room_id),
862 |row| row.get(0),
863 )
864 .await
865 .optional()?)
866 }
867
868 async fn get_withheld_sessions_by_room_id(&self, room_id: Key) -> Result<Vec<Vec<u8>>> {
869 Ok(self
870 .prepare("SELECT data FROM direct_withheld_info WHERE room_id = ?1", |mut stmt| {
871 stmt.query((room_id,))?.mapped(|row| row.get(0)).collect()
872 })
873 .await?)
874 }
875
876 async fn get_room_settings(&self, room_id: Key) -> Result<Option<Vec<u8>>> {
877 Ok(self
878 .query_row("SELECT data FROM room_settings WHERE room_id = ?", (room_id,), |row| {
879 row.get(0)
880 })
881 .await
882 .optional()?)
883 }
884
885 async fn get_received_room_key_bundle(
886 &self,
887 room_id: Key,
888 sender_user: Key,
889 ) -> Result<Option<Vec<u8>>> {
890 Ok(self
891 .query_row(
892 "SELECT bundle_data FROM received_room_key_bundle WHERE room_id = ? AND sender_user_id = ?",
893 (room_id, sender_user),
894 |row| { row.get(0) },
895 )
896 .await
897 .optional()?)
898 }
899
900 async fn get_room_pending_key_bundle(&self, room_id: Key) -> Result<Option<Vec<u8>>> {
901 Ok(self
902 .query_row(
903 "SELECT data FROM rooms_pending_key_bundle WHERE room_id = ?",
904 (room_id,),
905 |row| row.get(0),
906 )
907 .await
908 .optional()?)
909 }
910
911 async fn get_all_rooms_pending_key_bundle(&self) -> Result<Vec<Vec<u8>>> {
912 Ok(self
913 .query_many("SELECT data FROM rooms_pending_key_bundle", (), |row| row.get(0))
914 .await?)
915 }
916
917 async fn has_downloaded_all_room_keys(&self, room_id: Key) -> Result<bool> {
918 Ok(self
919 .query_row(
920 "SELECT EXISTS (SELECT 1 FROM room_key_backups_fully_downloaded WHERE room_id = ?)",
921 (room_id,),
922 |row| row.get(0),
923 )
924 .await?)
925 }
926}
927
928#[async_trait]
929impl SqliteObjectCryptoStoreExt for SqliteAsyncConn {}
930
931#[async_trait]
932impl CryptoStore for SqliteCryptoStore {
933 type Error = Error;
934
935 async fn load_account(&self) -> Result<Option<Account>> {
936 let conn = self.read().await?;
937 if let Some(pickle) = conn.get_kv("account").await? {
938 let pickle = self.deserialize_value(&pickle)?;
939
940 let account = Account::from_pickle(pickle).map_err(|_| Error::Unpickle)?;
941
942 *self.static_account.write().unwrap() = Some(account.static_data().clone());
943
944 Ok(Some(account))
945 } else {
946 Ok(None)
947 }
948 }
949
950 async fn load_identity(&self) -> Result<Option<PrivateCrossSigningIdentity>> {
951 let conn = self.read().await?;
952 if let Some(i) = conn.get_kv("identity").await? {
953 let pickle = self.deserialize_value(&i)?;
954 Ok(Some(PrivateCrossSigningIdentity::from_pickle(pickle).map_err(|_| Error::Unpickle)?))
955 } else {
956 Ok(None)
957 }
958 }
959
960 async fn save_pending_changes(&self, changes: PendingChanges) -> Result<()> {
961 let _guard = self.save_changes_lock.lock().await;
966
967 let pickled_account = if let Some(account) = changes.account {
968 *self.static_account.write().unwrap() = Some(account.static_data().clone());
969 Some(account.pickle())
970 } else {
971 None
972 };
973
974 let this = self.clone();
975 self.write()
976 .await
977 .with_transaction(move |txn| {
978 if let Some(pickled_account) = pickled_account {
979 let serialized_account = this.serialize_value(&pickled_account)?;
980 txn.set_kv("account", &serialized_account)?;
981 }
982
983 Ok::<_, Error>(())
984 })
985 .await?;
986
987 Ok(())
988 }
989
990 async fn save_changes(&self, changes: Changes) -> Result<()> {
991 let _guard = self.save_changes_lock.lock().await;
996
997 let pickled_private_identity =
998 if let Some(i) = changes.private_identity { Some(i.pickle().await) } else { None };
999
1000 let mut session_changes = Vec::new();
1001
1002 for session in changes.sessions {
1003 let session_id = self.encode_key("session", session.session_id());
1004 let sender_key = self.encode_key("session", session.sender_key().to_base64());
1005 let pickle = session.pickle().await;
1006 session_changes.push((session_id, sender_key, pickle));
1007 }
1008
1009 let mut inbound_session_changes = Vec::new();
1010 for session in changes.inbound_group_sessions {
1011 let room_id = self.encode_key("inbound_group_session", session.room_id().as_bytes());
1012 let session_id = self.encode_key("inbound_group_session", session.session_id());
1013 let pickle = session.pickle().await;
1014 let sender_key =
1015 self.encode_key("inbound_group_session", session.sender_key().to_base64());
1016 inbound_session_changes.push((room_id, session_id, pickle, sender_key));
1017 }
1018
1019 let mut outbound_session_changes = Vec::new();
1020 for session in changes.outbound_group_sessions {
1021 let room_id = self.encode_key("outbound_group_session", session.room_id().as_bytes());
1022 let pickle = session.pickle().await;
1023 outbound_session_changes.push((room_id, pickle));
1024 }
1025
1026 let this = self.clone();
1027 self.write()
1028 .await
1029 .with_transaction(move |txn| {
1030 if let Some(pickled_private_identity) = &pickled_private_identity {
1031 let serialized_private_identity =
1032 this.serialize_value(pickled_private_identity)?;
1033 txn.set_kv("identity", &serialized_private_identity)?;
1034 }
1035
1036 if let Some(token) = &changes.next_batch_token {
1037 let serialized_token = this.serialize_value(token)?;
1038 txn.set_kv("next_batch_token", &serialized_token)?;
1039 }
1040
1041 if let Some(decryption_key) = &changes.backup_decryption_key {
1042 let serialized_decryption_key = this.serialize_value(decryption_key)?;
1043 txn.set_kv("recovery_key_v1", &serialized_decryption_key)?;
1044 }
1045
1046 if let Some(backup_version) = &changes.backup_version {
1047 let serialized_backup_version = this.serialize_value(backup_version)?;
1048 txn.set_kv("backup_version_v1", &serialized_backup_version)?;
1049 }
1050
1051 if let Some(pickle_key) = &changes.dehydrated_device_pickle_key {
1052 let serialized_pickle_key = this.serialize_value(pickle_key)?;
1053 txn.set_kv(DEHYDRATED_DEVICE_PICKLE_KEY, &serialized_pickle_key)?;
1054 }
1055
1056 for device in changes.devices.new.iter().chain(&changes.devices.changed) {
1057 let user_id = this.encode_key("device", device.user_id().as_bytes());
1058 let device_id = this.encode_key("device", device.device_id().as_bytes());
1059 let data = this.serialize_value(&device)?;
1060 txn.set_device(&user_id, &device_id, &data)?;
1061 }
1062
1063 for device in &changes.devices.deleted {
1064 let user_id = this.encode_key("device", device.user_id().as_bytes());
1065 let device_id = this.encode_key("device", device.device_id().as_bytes());
1066 txn.delete_device(&user_id, &device_id)?;
1067 }
1068
1069 for identity in changes.identities.changed.iter().chain(&changes.identities.new) {
1070 let user_id = this.encode_key("identity", identity.user_id().as_bytes());
1071 let data = this.serialize_value(&identity)?;
1072 txn.set_identity(&user_id, &data)?;
1073 }
1074
1075 for (session_id, sender_key, pickle) in &session_changes {
1076 let serialized_session = this.serialize_value(&pickle)?;
1077 txn.set_session(session_id, sender_key, &serialized_session)?;
1078 }
1079
1080 for (room_id, session_id, pickle, sender_key) in &inbound_session_changes {
1081 let serialized_session = this.serialize_value(&pickle)?;
1082 txn.set_inbound_group_session(
1083 room_id,
1084 session_id,
1085 &serialized_session,
1086 pickle.backed_up,
1087 Some(sender_key),
1088 Some(pickle.sender_data.to_type() as u8),
1089 )?;
1090 }
1091
1092 for (room_id, pickle) in &outbound_session_changes {
1093 let serialized_session = this.serialize_json(&pickle)?;
1094 txn.set_outbound_group_session(room_id, &serialized_session)?;
1095 }
1096
1097 for hash in &changes.message_hashes {
1098 let hash = rmp_serde::to_vec(hash)?;
1099 txn.add_olm_hash(&hash)?;
1100 }
1101
1102 for request in changes.key_requests {
1103 let request_id = this.encode_key("key_requests", request.request_id.as_bytes());
1104 let serialized_request = this.serialize_value(&request)?;
1105 txn.set_key_request(&request_id, request.sent_out, &serialized_request)?;
1106 }
1107
1108 for (room_id, data) in changes.withheld_session_info {
1109 for (session_id, event) in data {
1110 let session_id = this.encode_key("direct_withheld_info", session_id);
1111 let room_id = this.encode_key("direct_withheld_info", &room_id);
1112 let serialized_info = this.serialize_json(&event)?;
1113 txn.set_direct_withheld(&session_id, &room_id, &serialized_info)?;
1114 }
1115 }
1116
1117 for (room_id, settings) in changes.room_settings {
1118 let room_id = this.encode_key("room_settings", room_id.as_bytes());
1119 let value = this.serialize_value(&settings)?;
1120 txn.set_room_settings(&room_id, &value)?;
1121 }
1122
1123 for secret in changes.secrets {
1124 let secret_name = this.encode_key("secrets", secret.secret_name.to_string());
1125 let value = this.serialize_json(&secret)?;
1126 txn.set_secret(&secret_name, &value)?;
1127 }
1128
1129 for bundle in changes.received_room_key_bundles {
1130 let room_id =
1131 this.encode_key("received_room_key_bundle", &bundle.bundle_data.room_id);
1132 let user_id = this.encode_key("received_room_key_bundle", &bundle.sender_user);
1133 let value = this.serialize_value(&bundle)?;
1134 txn.set_received_room_key_bundle(&room_id, &user_id, &value)?;
1135 }
1136
1137 for room in changes.room_key_backups_fully_downloaded {
1138 let room_id = this.encode_key("room_key_backups_fully_downloaded", &room);
1139 txn.set_has_downloaded_all_room_keys(&room_id)?;
1140 }
1141
1142 for (room, details) in changes.rooms_pending_key_bundle {
1143 let room_id = this.encode_key("rooms_pending_key_bundle", &room);
1144 let value = details.as_ref().map(|d| this.serialize_value(d)).transpose()?;
1145 txn.set_room_pending_key_bundle(&room_id, value.as_deref())?;
1146 }
1147
1148 Ok::<_, Error>(())
1149 })
1150 .await?;
1151
1152 Ok(())
1153 }
1154
1155 async fn save_inbound_group_sessions(
1156 &self,
1157 sessions: Vec<InboundGroupSession>,
1158 backed_up_to_version: Option<&str>,
1159 ) -> matrix_sdk_crypto::store::Result<(), Self::Error> {
1160 sessions.iter().for_each(|s| {
1162 let backed_up = s.backed_up();
1163 if backed_up != backed_up_to_version.is_some() {
1164 warn!(
1165 backed_up,
1166 backed_up_to_version,
1167 "Session backed-up flag does not correspond to backup version setting",
1168 );
1169 }
1170 });
1171
1172 self.save_changes(Changes { inbound_group_sessions: sessions, ..Changes::default() }).await
1175 }
1176
1177 async fn get_sessions(&self, sender_key: &str) -> Result<Option<Vec<Session>>> {
1178 let device_keys = self.get_own_device().await?.as_device_keys().clone();
1179
1180 let sessions: Vec<_> = self
1181 .read()
1182 .await?
1183 .get_sessions_for_sender_key(self.encode_key("session", sender_key.as_bytes()))
1184 .await?
1185 .into_iter()
1186 .map(|bytes| {
1187 let pickle = self.deserialize_value(&bytes)?;
1188 Session::from_pickle(device_keys.clone(), pickle).map_err(|_| Error::AccountUnset)
1189 })
1190 .collect::<Result<_>>()?;
1191
1192 if sessions.is_empty() { Ok(None) } else { Ok(Some(sessions)) }
1193 }
1194
1195 #[instrument(skip(self))]
1196 async fn get_inbound_group_session(
1197 &self,
1198 room_id: &RoomId,
1199 session_id: &str,
1200 ) -> Result<Option<InboundGroupSession>> {
1201 let session_id = self.encode_key("inbound_group_session", session_id);
1202 let Some((room_id_from_db, value, backed_up)) =
1203 self.read().await?.get_inbound_group_session(session_id).await?
1204 else {
1205 return Ok(None);
1206 };
1207
1208 let room_id = self.encode_key("inbound_group_session", room_id.as_bytes());
1209 if *room_id != room_id_from_db {
1210 warn!("expected room_id for session_id doesn't match what's in the DB");
1211 return Ok(None);
1212 }
1213
1214 Ok(Some(self.deserialize_and_unpickle_inbound_group_session(value, backed_up)?))
1215 }
1216
1217 async fn get_inbound_group_sessions(&self) -> Result<Vec<InboundGroupSession>> {
1218 self.read()
1219 .await?
1220 .get_inbound_group_sessions()
1221 .await?
1222 .into_iter()
1223 .map(|(value, backed_up)| {
1224 self.deserialize_and_unpickle_inbound_group_session(value, backed_up)
1225 })
1226 .collect()
1227 }
1228
1229 async fn get_inbound_group_sessions_by_room_id(
1230 &self,
1231 room_id: &RoomId,
1232 ) -> Result<Vec<InboundGroupSession>> {
1233 let room_id = self.encode_key("inbound_group_session", room_id.as_bytes());
1234 self.read()
1235 .await?
1236 .get_inbound_group_sessions_by_room_id(room_id)
1237 .await?
1238 .into_iter()
1239 .map(|(value, backed_up)| {
1240 self.deserialize_and_unpickle_inbound_group_session(value, backed_up)
1241 })
1242 .collect()
1243 }
1244
1245 async fn get_inbound_group_sessions_for_device_batch(
1246 &self,
1247 sender_key: Curve25519PublicKey,
1248 sender_data_type: SenderDataType,
1249 after_session_id: Option<String>,
1250 limit: usize,
1251 ) -> Result<Vec<InboundGroupSession>, Self::Error> {
1252 let after_session_id =
1253 after_session_id.map(|session_id| self.encode_key("inbound_group_session", session_id));
1254 let sender_key = self.encode_key("inbound_group_session", sender_key.to_base64());
1255
1256 self.read()
1257 .await?
1258 .get_inbound_group_sessions_for_device_batch(
1259 sender_key,
1260 sender_data_type,
1261 after_session_id,
1262 limit,
1263 )
1264 .await?
1265 .into_iter()
1266 .map(|(value, backed_up)| {
1267 self.deserialize_and_unpickle_inbound_group_session(value, backed_up)
1268 })
1269 .collect()
1270 }
1271
1272 async fn inbound_group_session_counts(
1273 &self,
1274 backup_version: Option<&str>,
1275 ) -> Result<RoomKeyCounts> {
1276 Ok(self.read().await?.get_inbound_group_session_counts(backup_version).await?)
1277 }
1278
1279 async fn inbound_group_sessions_for_backup(
1280 &self,
1281 _backup_version: &str,
1282 limit: usize,
1283 ) -> Result<Vec<InboundGroupSession>> {
1284 self.read()
1285 .await?
1286 .get_inbound_group_sessions_for_backup(limit)
1287 .await?
1288 .into_iter()
1289 .map(|value| self.deserialize_and_unpickle_inbound_group_session(value, false))
1290 .collect()
1291 }
1292
1293 async fn mark_inbound_group_sessions_as_backed_up(
1294 &self,
1295 _backup_version: &str,
1296 session_ids: &[(&RoomId, &str)],
1297 ) -> Result<()> {
1298 Ok(self
1299 .write()
1300 .await
1301 .mark_inbound_group_sessions_as_backed_up(
1302 session_ids
1303 .iter()
1304 .map(|(_, s)| self.encode_key("inbound_group_session", s))
1305 .collect(),
1306 )
1307 .await?)
1308 }
1309
1310 async fn reset_backup_state(&self) -> Result<()> {
1311 Ok(self.write().await.reset_inbound_group_session_backup_state().await?)
1312 }
1313
1314 async fn load_backup_keys(&self) -> Result<BackupKeys> {
1315 let conn = self.read().await?;
1316
1317 let backup_version = conn
1318 .get_kv("backup_version_v1")
1319 .await?
1320 .map(|value| self.deserialize_value(&value))
1321 .transpose()?;
1322
1323 let decryption_key = conn
1324 .get_kv("recovery_key_v1")
1325 .await?
1326 .map(|value| self.deserialize_value(&value))
1327 .transpose()?;
1328
1329 Ok(BackupKeys { backup_version, decryption_key })
1330 }
1331
1332 async fn load_dehydrated_device_pickle_key(&self) -> Result<Option<DehydratedDeviceKey>> {
1333 let conn = self.read().await?;
1334
1335 conn.get_kv(DEHYDRATED_DEVICE_PICKLE_KEY)
1336 .await?
1337 .map(|value| self.deserialize_value(&value))
1338 .transpose()
1339 }
1340
1341 async fn delete_dehydrated_device_pickle_key(&self) -> Result<(), Self::Error> {
1342 Ok(self.write().await.clear_kv(DEHYDRATED_DEVICE_PICKLE_KEY).await?)
1343 }
1344 async fn get_outbound_group_session(
1345 &self,
1346 room_id: &RoomId,
1347 ) -> Result<Option<OutboundGroupSession>> {
1348 let room_id = self.encode_key("outbound_group_session", room_id.as_bytes());
1349 let Some(value) = self.read().await?.get_outbound_group_session(room_id).await? else {
1350 return Ok(None);
1351 };
1352
1353 let account_info = self.get_static_account().ok_or(Error::AccountUnset)?;
1354
1355 let pickle = self.deserialize_json(&value)?;
1356 let session = OutboundGroupSession::from_pickle(
1357 account_info.device_id,
1358 account_info.identity_keys,
1359 pickle,
1360 )
1361 .map_err(|_| Error::Unpickle)?;
1362
1363 return Ok(Some(session));
1364 }
1365
1366 async fn load_tracked_users(&self) -> Result<Vec<TrackedUser>> {
1367 self.read()
1368 .await?
1369 .get_tracked_users()
1370 .await?
1371 .iter()
1372 .map(|value| self.deserialize_value(value))
1373 .collect()
1374 }
1375
1376 async fn save_tracked_users(&self, tracked_users: &[(&UserId, bool)]) -> Result<()> {
1377 let users: Vec<(Key, Vec<u8>)> = tracked_users
1378 .iter()
1379 .map(|(u, d)| {
1380 let user_id = self.encode_key("tracked_users", u.as_bytes());
1381 let data =
1382 self.serialize_value(&TrackedUser { user_id: (*u).into(), dirty: *d })?;
1383 Ok((user_id, data))
1384 })
1385 .collect::<Result<_>>()?;
1386
1387 Ok(self.write().await.add_tracked_users(users).await?)
1388 }
1389
1390 async fn get_device(
1391 &self,
1392 user_id: &UserId,
1393 device_id: &DeviceId,
1394 ) -> Result<Option<DeviceData>> {
1395 let user_id = self.encode_key("device", user_id.as_bytes());
1396 let device_id = self.encode_key("device", device_id.as_bytes());
1397 Ok(self
1398 .read()
1399 .await?
1400 .get_device(user_id, device_id)
1401 .await?
1402 .map(|value| self.deserialize_value(&value))
1403 .transpose()?)
1404 }
1405
1406 async fn get_user_devices(
1407 &self,
1408 user_id: &UserId,
1409 ) -> Result<HashMap<OwnedDeviceId, DeviceData>> {
1410 let user_id = self.encode_key("device", user_id.as_bytes());
1411 self.read()
1412 .await?
1413 .get_user_devices(user_id)
1414 .await?
1415 .into_iter()
1416 .map(|value| {
1417 let device: DeviceData = self.deserialize_value(&value)?;
1418 Ok((device.device_id().to_owned(), device))
1419 })
1420 .collect()
1421 }
1422
1423 async fn get_own_device(&self) -> Result<DeviceData> {
1424 let account_info = self.get_static_account().ok_or(Error::AccountUnset)?;
1425
1426 Ok(self
1427 .get_device(&account_info.user_id, &account_info.device_id)
1428 .await?
1429 .expect("We should be able to find our own device."))
1430 }
1431
1432 async fn get_user_identity(&self, user_id: &UserId) -> Result<Option<UserIdentityData>> {
1433 let user_id = self.encode_key("identity", user_id.as_bytes());
1434 Ok(self
1435 .read()
1436 .await?
1437 .get_user_identity(user_id)
1438 .await?
1439 .map(|value| self.deserialize_value(&value))
1440 .transpose()?)
1441 }
1442
1443 async fn is_message_known(
1444 &self,
1445 message_hash: &matrix_sdk_crypto::olm::OlmMessageHash,
1446 ) -> Result<bool> {
1447 let value = rmp_serde::to_vec(message_hash)?;
1448 Ok(self.read().await?.has_olm_hash(value).await?)
1449 }
1450
1451 async fn get_outgoing_secret_requests(
1452 &self,
1453 request_id: &TransactionId,
1454 ) -> Result<Option<GossipRequest>> {
1455 let request_id = self.encode_key("key_requests", request_id.as_bytes());
1456 Ok(self
1457 .read()
1458 .await?
1459 .get_outgoing_secret_request(request_id)
1460 .await?
1461 .map(|(value, sent_out)| self.deserialize_key_request(&value, sent_out))
1462 .transpose()?)
1463 }
1464
1465 async fn get_secret_request_by_info(
1466 &self,
1467 key_info: &SecretInfo,
1468 ) -> Result<Option<GossipRequest>> {
1469 let requests = self.read().await?.get_outgoing_secret_requests().await?;
1470 for (request, sent_out) in requests {
1471 let request = self.deserialize_key_request(&request, sent_out)?;
1472 if request.info == *key_info {
1473 return Ok(Some(request));
1474 }
1475 }
1476 Ok(None)
1477 }
1478
1479 async fn get_unsent_secret_requests(&self) -> Result<Vec<GossipRequest>> {
1480 self.read()
1481 .await?
1482 .get_unsent_secret_requests()
1483 .await?
1484 .iter()
1485 .map(|value| {
1486 let request = self.deserialize_key_request(value, false)?;
1487 Ok(request)
1488 })
1489 .collect()
1490 }
1491
1492 async fn delete_outgoing_secret_requests(&self, request_id: &TransactionId) -> Result<()> {
1493 let request_id = self.encode_key("key_requests", request_id.as_bytes());
1494 Ok(self.write().await.delete_key_request(request_id).await?)
1495 }
1496
1497 async fn get_secrets_from_inbox(
1498 &self,
1499 secret_name: &SecretName,
1500 ) -> Result<Vec<GossippedSecret>> {
1501 let secret_name = self.encode_key("secrets", secret_name.to_string());
1502
1503 self.read()
1504 .await?
1505 .get_secrets_from_inbox(secret_name)
1506 .await?
1507 .into_iter()
1508 .map(|value| self.deserialize_json(value.as_ref()))
1509 .collect()
1510 }
1511
1512 async fn delete_secrets_from_inbox(&self, secret_name: &SecretName) -> Result<()> {
1513 let secret_name = self.encode_key("secrets", secret_name.to_string());
1514 self.write().await.delete_secrets_from_inbox(secret_name).await
1515 }
1516
1517 async fn get_withheld_info(
1518 &self,
1519 room_id: &RoomId,
1520 session_id: &str,
1521 ) -> Result<Option<RoomKeyWithheldEntry>> {
1522 let room_id = self.encode_key("direct_withheld_info", room_id);
1523 let session_id = self.encode_key("direct_withheld_info", session_id);
1524
1525 self.read()
1526 .await?
1527 .get_direct_withheld_info(session_id, room_id)
1528 .await?
1529 .map(|value| {
1530 let info = self.deserialize_json::<RoomKeyWithheldEntry>(&value)?;
1531 Ok(info)
1532 })
1533 .transpose()
1534 }
1535
1536 async fn get_withheld_sessions_by_room_id(
1537 &self,
1538 room_id: &RoomId,
1539 ) -> matrix_sdk_crypto::store::Result<Vec<RoomKeyWithheldEntry>, Self::Error> {
1540 let room_id = self.encode_key("direct_withheld_info", room_id);
1541
1542 self.read()
1543 .await?
1544 .get_withheld_sessions_by_room_id(room_id)
1545 .await?
1546 .into_iter()
1547 .map(|value| self.deserialize_json(&value))
1548 .collect()
1549 }
1550
1551 async fn get_room_settings(&self, room_id: &RoomId) -> Result<Option<RoomSettings>> {
1552 let room_id = self.encode_key("room_settings", room_id.as_bytes());
1553 let Some(value) = self.read().await?.get_room_settings(room_id).await? else {
1554 return Ok(None);
1555 };
1556
1557 let settings = self.deserialize_value(&value)?;
1558
1559 return Ok(Some(settings));
1560 }
1561
1562 async fn get_received_room_key_bundle_data(
1563 &self,
1564 room_id: &RoomId,
1565 user_id: &UserId,
1566 ) -> Result<Option<StoredRoomKeyBundleData>> {
1567 let room_id = self.encode_key("received_room_key_bundle", room_id);
1568 let user_id = self.encode_key("received_room_key_bundle", user_id);
1569 self.read()
1570 .await?
1571 .get_received_room_key_bundle(room_id, user_id)
1572 .await?
1573 .map(|value| self.deserialize_value(&value))
1574 .transpose()
1575 }
1576
1577 async fn has_downloaded_all_room_keys(&self, room_id: &RoomId) -> Result<bool> {
1578 let room_id = self.encode_key("room_key_backups_fully_downloaded", room_id);
1579 self.read().await?.has_downloaded_all_room_keys(room_id).await
1580 }
1581
1582 async fn get_pending_key_bundle_details_for_room(
1583 &self,
1584 room_id: &RoomId,
1585 ) -> Result<Option<RoomPendingKeyBundleDetails>> {
1586 let room_id = self.encode_key("rooms_pending_key_bundle", room_id.as_bytes());
1587 let Some(value) = self.read().await?.get_room_pending_key_bundle(room_id).await? else {
1588 return Ok(None);
1589 };
1590
1591 let details = self.deserialize_value(&value)?;
1592 Ok(Some(details))
1593 }
1594
1595 async fn get_all_rooms_pending_key_bundles(&self) -> Result<Vec<RoomPendingKeyBundleDetails>> {
1596 let details = self.read().await?.get_all_rooms_pending_key_bundle().await?;
1597 let room_ids = details
1598 .into_iter()
1599 .map(|value| self.deserialize_value(&value))
1600 .collect::<Result<_, _>>()?;
1601 Ok(room_ids)
1602 }
1603
1604 async fn get_custom_value(&self, key: &str) -> Result<Option<Vec<u8>>> {
1605 let Some(serialized) = self.read().await?.get_kv(key).await? else {
1606 return Ok(None);
1607 };
1608 let value = if let Some(cipher) = &self.store_cipher {
1609 let encrypted = rmp_serde::from_slice(&serialized)?;
1610 cipher.decrypt_value_data(encrypted)?
1611 } else {
1612 serialized
1613 };
1614
1615 Ok(Some(value))
1616 }
1617
1618 async fn set_custom_value(&self, key: &str, value: Vec<u8>) -> Result<()> {
1619 let serialized = if let Some(cipher) = &self.store_cipher {
1620 let encrypted = cipher.encrypt_value_data(value)?;
1621 rmp_serde::to_vec_named(&encrypted)?
1622 } else {
1623 value
1624 };
1625
1626 self.write().await.set_kv(key, serialized).await?;
1627 Ok(())
1628 }
1629
1630 async fn remove_custom_value(&self, key: &str) -> Result<()> {
1631 let key = key.to_owned();
1632 self.write()
1633 .await
1634 .interact(move |conn| conn.execute("DELETE FROM kv WHERE key = ?1", (&key,)))
1635 .await
1636 .unwrap()?;
1637 Ok(())
1638 }
1639
1640 #[instrument(skip(self))]
1641 async fn try_take_leased_lock(
1642 &self,
1643 lease_duration_ms: u32,
1644 key: &str,
1645 holder: &str,
1646 ) -> Result<Option<CrossProcessLockGeneration>> {
1647 let key = key.to_owned();
1648 let holder = holder.to_owned();
1649
1650 let now: u64 = MilliSecondsSinceUnixEpoch::now().get().into();
1651 let expiration = now + lease_duration_ms as u64;
1652
1653 let generation = self
1655 .write()
1656 .await
1657 .with_transaction(move |txn| {
1658 txn.query_row(
1659 "INSERT INTO lease_locks (key, holder, expiration)
1660 VALUES (?1, ?2, ?3)
1661 ON CONFLICT (key)
1662 DO
1663 UPDATE SET
1664 holder = excluded.holder,
1665 expiration = excluded.expiration,
1666 generation =
1667 CASE holder
1668 WHEN excluded.holder THEN generation
1669 ELSE generation + 1
1670 END
1671 WHERE
1672 holder = excluded.holder
1673 OR expiration < ?4
1674 RETURNING generation
1675 ",
1676 (key, holder, expiration, now),
1677 |row| row.get(0),
1678 )
1679 .optional()
1680 })
1681 .await?;
1682
1683 Ok(generation)
1684 }
1685
1686 async fn next_batch_token(&self) -> Result<Option<String>, Self::Error> {
1687 let conn = self.read().await?;
1688 if let Some(token) = conn.get_kv("next_batch_token").await? {
1689 let maybe_token: Option<String> = self.deserialize_value(&token)?;
1690 Ok(maybe_token)
1691 } else {
1692 Ok(None)
1693 }
1694 }
1695
1696 async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1697 Ok(Some(self.pool.get().await?.get_db_size().await?))
1698 }
1699}
1700
1701#[cfg(test)]
1702mod tests {
1703 use std::{path::Path, sync::LazyLock};
1704
1705 use matrix_sdk_common::deserialized_responses::WithheldCode;
1706 use matrix_sdk_crypto::{
1707 cryptostore_integration_tests, cryptostore_integration_tests_time, olm::SenderDataType,
1708 store::CryptoStore,
1709 };
1710 use matrix_sdk_test::async_test;
1711 use ruma::{device_id, room_id, user_id};
1712 use similar_asserts::assert_eq;
1713 use tempfile::{TempDir, tempdir};
1714 use tokio::fs;
1715
1716 use super::SqliteCryptoStore;
1717 use crate::SqliteStoreConfig;
1718
1719 static TMP_DIR: LazyLock<TempDir> = LazyLock::new(|| tempdir().unwrap());
1720
1721 struct TestDb {
1722 _dir: TempDir,
1725 database: SqliteCryptoStore,
1726 }
1727
1728 fn copy_db(data_path: &str) -> TempDir {
1729 let db_name = super::DATABASE_NAME;
1730
1731 let manifest_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
1732 let database_path = manifest_path.join(data_path).join(db_name);
1733
1734 let tmpdir = tempdir().unwrap();
1735 let destination = tmpdir.path().join(db_name);
1736
1737 std::fs::copy(&database_path, destination).unwrap();
1739
1740 tmpdir
1741 }
1742
1743 async fn get_test_db(data_path: &str, passphrase: Option<&str>) -> TestDb {
1744 let tmpdir = copy_db(data_path);
1745
1746 let database = SqliteCryptoStore::open(tmpdir.path(), passphrase)
1747 .await
1748 .expect("Can't open the test store");
1749
1750 TestDb { _dir: tmpdir, database }
1751 }
1752
1753 #[async_test]
1754 async fn test_pool_size() {
1755 let store_open_config =
1756 SqliteStoreConfig::new(TMP_DIR.path().join("test_pool_size")).pool_max_size(42);
1757
1758 let store = SqliteCryptoStore::open_with_config(store_open_config).await.unwrap();
1759
1760 assert_eq!(store.pool.status().max_size, 42);
1761 }
1762
1763 #[async_test]
1766 async fn test_open_test_vector_store() {
1767 let TestDb { _dir: _, database } = get_test_db("testing/data/storage", None).await;
1768
1769 let account = database
1770 .load_account()
1771 .await
1772 .unwrap()
1773 .expect("The test database is prefilled with data, we should find an account");
1774
1775 let user_id = account.user_id();
1776 let device_id = account.device_id();
1777
1778 assert_eq!(
1779 user_id.as_str(),
1780 "@pjtest:synapse-oidc.element.dev",
1781 "The user ID should match to the one we expect."
1782 );
1783
1784 assert_eq!(
1785 device_id.as_str(),
1786 "v4TqgcuIH6",
1787 "The device ID should match to the one we expect."
1788 );
1789
1790 let device = database
1791 .get_device(user_id, device_id)
1792 .await
1793 .unwrap()
1794 .expect("Our own device should be found in the store.");
1795
1796 assert_eq!(device.device_id(), device_id);
1797 assert_eq!(device.user_id(), user_id);
1798
1799 assert_eq!(
1800 device.ed25519_key().expect("The device should have a Ed25519 key.").to_base64(),
1801 "+cxl1Gl3du5i7UJwfWnoRDdnafFF+xYdAiTYYhYLr8s"
1802 );
1803
1804 assert_eq!(
1805 device.curve25519_key().expect("The device should have a Curve25519 key.").to_base64(),
1806 "4SL9eEUlpyWSUvjljC5oMjknHQQJY7WZKo5S1KL/5VU"
1807 );
1808
1809 let identity = database
1810 .get_user_identity(user_id)
1811 .await
1812 .unwrap()
1813 .expect("The store should contain an identity.");
1814
1815 assert_eq!(identity.user_id(), user_id);
1816
1817 let identity = identity
1818 .own()
1819 .expect("The identity should be of the correct type, it should be our own identity.");
1820
1821 let master_key = identity
1822 .master_key()
1823 .get_first_key()
1824 .expect("Our own identity should have a master key");
1825
1826 assert_eq!(master_key.to_base64(), "iCUEtB1RwANeqRa5epDrblLk4mer/36sylwQ5hYY3oE");
1827 }
1828
1829 #[async_test]
1832 async fn test_open_test_vector_encrypted_store() {
1833 let TestDb { _dir: _, database } = get_test_db(
1834 "testing/data/storage/alice",
1835 Some(concat!(
1836 "/rCia2fYAJ+twCZ1Xm2mxFCYcmJdyzkdJjwtgXsziWpYS/UeNxnixuSieuwZXm+x1VsJHmWpl",
1837 "H+QIQBZpEGZtC9/S/l8xK+WOCesmET0o6yJ/KP73ofDtjBlnNpPwuHLKFpyTbyicpCgQ4UT+5E",
1838 "UBuJ08TY9Ujdf1D13k5kr5tSZUefDKKCuG1fCRqlU8ByRas1PMQsZxT2W8t7QgBrQiiGmhpo/O",
1839 "Ti4hfx97GOxncKcxTzppiYQNoHs/f15+XXQD7/oiCcqRIuUlXNsU6hRpFGmbYx2Pi1eyQViQCt",
1840 "B5dAEiSD0N8U81wXYnpynuTPtnL+hfnOJIn7Sy7mkERQeKg"
1841 )),
1842 )
1843 .await;
1844
1845 let account = database
1846 .load_account()
1847 .await
1848 .unwrap()
1849 .expect("The test database is prefilled with data, we should find an account");
1850
1851 let user_id = account.user_id();
1852 let device_id = account.device_id();
1853
1854 assert_eq!(
1855 user_id.as_str(),
1856 "@alice:localhost",
1857 "The user ID should match to the one we expect."
1858 );
1859
1860 assert_eq!(
1861 device_id.as_str(),
1862 "JVVORTHFXY",
1863 "The device ID should match to the one we expect."
1864 );
1865
1866 let tracked_users =
1867 database.load_tracked_users().await.expect("Should be tracking some users");
1868
1869 assert_eq!(tracked_users.len(), 6);
1870
1871 let known_users = vec![
1872 user_id!("@alice:localhost"),
1873 user_id!("@dehydration3:localhost"),
1874 user_id!("@eve:localhost"),
1875 user_id!("@bob:localhost"),
1876 user_id!("@malo:localhost"),
1877 user_id!("@carl:localhost"),
1878 ];
1879
1880 for user_id in known_users {
1882 database.get_user_identity(user_id).await.expect("Should load this identity").unwrap();
1883 }
1884
1885 let carl_identity =
1886 database.get_user_identity(user_id!("@carl:localhost")).await.unwrap().unwrap();
1887
1888 assert_eq!(
1889 carl_identity.master_key().get_first_key().unwrap().to_base64(),
1890 "CdhKYYDeBDQveOioXEGWhTPCyzc63Irpar3CNyfun2Q"
1891 );
1892 assert!(!carl_identity.was_previously_verified());
1893
1894 let bob_identity =
1895 database.get_user_identity(user_id!("@bob:localhost")).await.unwrap().unwrap();
1896
1897 assert_eq!(
1898 bob_identity.master_key().get_first_key().unwrap().to_base64(),
1899 "COh2GYOJWSjem5QPRCaGp9iWV83IELG1IzLKW2S3pFY"
1900 );
1901 assert!(bob_identity.was_previously_verified());
1903
1904 let known_devices = vec![
1905 (device_id!("OPXQHCZSKW"), user_id!("@alice:localhost")),
1906 (
1908 device_id!("EvW+9IrGR10KVgVeZP25/KaPfx4R86FofVMcaz7VOho"),
1909 user_id!("@alice:localhost"),
1910 ),
1911 (device_id!("HEEFRFQENV"), user_id!("@alice:localhost")),
1912 (device_id!("JVVORTHFXY"), user_id!("@alice:localhost")),
1913 (device_id!("NQUWWSKKHS"), user_id!("@alice:localhost")),
1914 (device_id!("ORBLPFYCPG"), user_id!("@alice:localhost")),
1915 (device_id!("YXOWENSEGM"), user_id!("@dehydration3:localhost")),
1916 (device_id!("VXLFMYCHXC"), user_id!("@bob:localhost")),
1917 (device_id!("FDGDQAEWOW"), user_id!("@bob:localhost")),
1918 (device_id!("VXLFMYCHXC"), user_id!("@bob:localhost")),
1919 (device_id!("FDGDQAEWOW"), user_id!("@bob:localhost")),
1920 (device_id!("QKUKWJTTQC"), user_id!("@malo:localhost")),
1921 (device_id!("LOUXJECTFG"), user_id!("@malo:localhost")),
1922 (device_id!("MKKMAEVLPB"), user_id!("@carl:localhost")),
1923 ];
1924
1925 for (device_id, user_id) in known_devices {
1926 database.get_device(user_id, device_id).await.expect("Should load the device").unwrap();
1927 }
1928
1929 let known_sender_key_to_session_count = vec![
1930 ("FfYcYfDF4nWy+LHdK6CEpIMlFAQDORc30WUkghL06kM", 1),
1931 ("EvW+9IrGR10KVgVeZP25/KaPfx4R86FofVMcaz7VOho", 1),
1932 ("hAGsoA4a9M6wwEUX5Q1jux1i+tUngLi01n5AmhDoHTY", 1),
1933 ("aKqtSJymLzuoglWFwPGk1r/Vm2LE2hFESzXxn4RNjRM", 0),
1934 ("zHK1psCrgeMn0kaz8hcdvA3INyar9jg1yfrSp0p1pHo", 1),
1935 ("1QmBA316Wj5jIFRwNOti6N6Xh/vW0bsYCcR4uPfy8VQ", 1),
1936 ("g5ef2vZF3VXgSPyODIeXpyHIRkuthvLhGvd6uwYggWU", 1),
1937 ("o7hfupPd1VsNkRIvdlH6ujrEJFSKjFCGbxhAd31XxjI", 1),
1938 ("Z3RxKQLxY7xpP+ZdOGR2SiNE37SrvmRhW7GPu1UGdm8", 1),
1939 ("GDomaav8NiY3J+dNEeApJm+O0FooJ3IpVaIyJzCN4w4", 1),
1940 ("7m7fqkHyEr47V5s/KjaxtJMOr3pSHrrns2q2lWpAQi8", 0),
1941 ("9psAkPUIF8vNbWbnviX3PlwRcaeO53EHJdNtKpTY1X0", 0),
1942 ("mqanh+ztw5oRtpqYQgLGW864i6NY2zpoKMIlrcyC+Aw", 0),
1943 ("fJU/TJdbsv7tVbbpHw1Ke73ziElnM32cNhP2WIg4T10", 0),
1944 ("sUIeFeFcCZoa5IC6nJ6Vrbvztcyx09m8BBg57XKRClg", 1),
1945 ];
1946
1947 for (id, count) in known_sender_key_to_session_count {
1948 let olm_sessions =
1949 database.get_sessions(id).await.expect("Should have some olm sessions");
1950
1951 println!("### Session id: {id:?}");
1952 assert_eq!(olm_sessions.map_or(0, |v| v.len()), count);
1953 }
1954
1955 let inbound_group_sessions = database.get_inbound_group_sessions().await.unwrap();
1956 assert_eq!(inbound_group_sessions.len(), 15);
1957 let known_inbound_group_sessions = vec![
1958 (
1959 "5hNAxrLai3VI0LKBwfh3wLfksfBFWds0W1a5X5/vSXA",
1960 room_id!("!SRstFdydzrGwJYtVfm:localhost"),
1961 ),
1962 (
1963 "M6d2eU3y54gaYTbvGSlqa/xc1Az35l56Cp9sxzHWO4g",
1964 room_id!("!SRstFdydzrGwJYtVfm:localhost"),
1965 ),
1966 (
1967 "IrydwXkRk2N2AqUMIVmLL3oJgMq14R9KId0P/uSD100",
1968 room_id!("!SRstFdydzrGwJYtVfm:localhost"),
1969 ),
1970 (
1971 "Y74+l9jTo7N5UF+GQwdpgJGe4sn1+QtWITq7BxulHIE",
1972 room_id!("!SRstFdydzrGwJYtVfm:localhost"),
1973 ),
1974 (
1975 "HpJxQR57WbQGdY6w2Q+C16znVvbXGa+JvQdRoMpWbXg",
1976 room_id!("!SRstFdydzrGwJYtVfm:localhost"),
1977 ),
1978 (
1979 "Xetvi+ydFkZt8dpONGFbEusQb/Chc2V0XlLByZhsbgE",
1980 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
1981 ),
1982 (
1983 "wv/WN/39akyerIXczTaIpjAuLnwgXKRtbXFSEHiJqxo",
1984 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
1985 ),
1986 (
1987 "nA4gQwL//Cm8OdlyjABl/jChbPT/cP5V4Sd8iuE6H0s",
1988 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
1989 ),
1990 (
1991 "bAAgqFeRDTjfEqL6Qf/c9mk55zoNDCSlboAIRd6b0hw",
1992 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
1993 ),
1994 (
1995 "exPbsMMdGfAG2qmDdFtpAn+koVprfzS0Zip/RA9QRCE",
1996 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
1997 ),
1998 (
1999 "h+om7oSw/ZV94fcKaoe8FGXJwQXWOfKQfzbGgNWQILI",
2000 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
2001 ),
2002 (
2003 "ul3VXonpgk4lO2L3fEWubP/nxsTmLHqu5v8ZM9vHEcw",
2004 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
2005 ),
2006 (
2007 "JXY15UxC3az2mwg8uX4qwgxfvCM4aygiIWMcdNiVQoc",
2008 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
2009 ),
2010 (
2011 "OGB9lObr9kWUvha9tB5sMfOF/Mztk24JwQz/nwg3iFQ",
2012 room_id!("!OgRiTRMaUzLdpCeDBM:localhost"),
2013 ),
2014 (
2015 "SFkHcbxjUOYF7mUAYI/oEMDZFaXszQbCN6Jza7iemj0",
2016 room_id!("!OgRiTRMaUzLdpCeDBM:localhost"),
2017 ),
2018 ];
2019
2020 for (session_id, room_id) in &known_inbound_group_sessions {
2022 database
2023 .get_inbound_group_session(room_id, session_id)
2024 .await
2025 .expect("Should be able to load inbound group session")
2026 .unwrap();
2027 }
2028
2029 let bob_sender_verified = database
2030 .get_inbound_group_session(
2031 room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"),
2032 "exPbsMMdGfAG2qmDdFtpAn+koVprfzS0Zip/RA9QRCE",
2033 )
2034 .await
2035 .unwrap()
2036 .unwrap();
2037
2038 assert_eq!(bob_sender_verified.sender_data.to_type(), SenderDataType::SenderVerified);
2039 assert!(bob_sender_verified.backed_up());
2040 assert!(!bob_sender_verified.has_been_imported());
2041
2042 let alice_unknown_device = database
2043 .get_inbound_group_session(
2044 room_id!("!SRstFdydzrGwJYtVfm:localhost"),
2045 "IrydwXkRk2N2AqUMIVmLL3oJgMq14R9KId0P/uSD100",
2046 )
2047 .await
2048 .unwrap()
2049 .unwrap();
2050
2051 assert_eq!(alice_unknown_device.sender_data.to_type(), SenderDataType::UnknownDevice);
2052 assert!(alice_unknown_device.backed_up());
2053 assert!(alice_unknown_device.has_been_imported());
2054
2055 let carl_tofu_session = database
2056 .get_inbound_group_session(
2057 room_id!("!OgRiTRMaUzLdpCeDBM:localhost"),
2058 "OGB9lObr9kWUvha9tB5sMfOF/Mztk24JwQz/nwg3iFQ",
2059 )
2060 .await
2061 .unwrap()
2062 .unwrap();
2063
2064 assert_eq!(carl_tofu_session.sender_data.to_type(), SenderDataType::SenderUnverified);
2065 assert!(carl_tofu_session.backed_up());
2066 assert!(!carl_tofu_session.has_been_imported());
2067
2068 database
2070 .get_outbound_group_session(room_id!("!OgRiTRMaUzLdpCeDBM:localhost"))
2071 .await
2072 .unwrap()
2073 .unwrap();
2074 database
2075 .get_outbound_group_session(room_id!("!ZIwZcFqZVAYLAqVjfV:localhost"))
2076 .await
2077 .unwrap()
2078 .unwrap();
2079 database
2080 .get_outbound_group_session(room_id!("!SRstFdydzrGwJYtVfm:localhost"))
2081 .await
2082 .unwrap()
2083 .unwrap();
2084
2085 let withheld_info = database
2086 .get_withheld_info(
2087 room_id!("!OgRiTRMaUzLdpCeDBM:localhost"),
2088 "SASgZ+EklvAF4QxJclMlDRlmL0fAMjAJJIKFMdb4Ht0",
2089 )
2090 .await
2091 .expect("This session should be withheld")
2092 .unwrap();
2093
2094 assert_eq!(withheld_info.content.withheld_code(), WithheldCode::Unverified);
2095
2096 let backup_keys = database.load_backup_keys().await.expect("backup key should be cached");
2097 assert_eq!(backup_keys.backup_version.unwrap(), "6");
2098 assert!(backup_keys.decryption_key.is_some());
2099 }
2100
2101 async fn get_store(
2102 name: &str,
2103 passphrase: Option<&str>,
2104 clear_data: bool,
2105 ) -> SqliteCryptoStore {
2106 let tmpdir_path = TMP_DIR.path().join(name);
2107
2108 if clear_data {
2109 let _ = fs::remove_dir_all(&tmpdir_path).await;
2110 }
2111
2112 SqliteCryptoStore::open(tmpdir_path.to_str().unwrap(), passphrase)
2113 .await
2114 .expect("Can't create a secret protected store")
2115 }
2116
2117 cryptostore_integration_tests!();
2118 cryptostore_integration_tests_time!();
2119}
2120
2121#[cfg(test)]
2122mod encrypted_tests {
2123 use std::sync::LazyLock;
2124
2125 use matrix_sdk_crypto::{cryptostore_integration_tests, cryptostore_integration_tests_time};
2126 use tempfile::{TempDir, tempdir};
2127 use tokio::fs;
2128
2129 use super::SqliteCryptoStore;
2130
2131 static TMP_DIR: LazyLock<TempDir> = LazyLock::new(|| tempdir().unwrap());
2132
2133 async fn get_store(
2134 name: &str,
2135 passphrase: Option<&str>,
2136 clear_data: bool,
2137 ) -> SqliteCryptoStore {
2138 let tmpdir_path = TMP_DIR.path().join(name);
2139 let pass = passphrase.unwrap_or("default_test_password");
2140
2141 if clear_data {
2142 let _ = fs::remove_dir_all(&tmpdir_path).await;
2143 }
2144
2145 SqliteCryptoStore::open(tmpdir_path.to_str().unwrap(), Some(pass))
2146 .await
2147 .expect("Can't create a secret protected store")
2148 }
2149
2150 cryptostore_integration_tests!();
2151 cryptostore_integration_tests_time!();
2152}