diff --git a/matrix_sdk_crypto/src/device.rs b/matrix_sdk_crypto/src/device.rs index 17804bca..bcd84fbd 100644 --- a/matrix_sdk_crypto/src/device.rs +++ b/matrix_sdk_crypto/src/device.rs @@ -36,6 +36,7 @@ pub struct Device { device_id: Arc>, algorithms: Arc>, keys: Arc>, + signatures: Arc>>, display_name: Arc>, deleted: Arc, trust_state: Arc>, @@ -75,12 +76,14 @@ impl Device { trust_state: TrustState, algorithms: Vec, keys: BTreeMap, + signatures: BTreeMap>, ) -> Self { Device { user_id: Arc::new(user_id), device_id: Arc::new(device_id), display_name: Arc::new(display_name), trust_state: Arc::new(Atomic::new(trust_state)), + signatures: Arc::new(signatures), algorithms: Arc::new(algorithms), keys: Arc::new(keys), deleted: Arc::new(AtomicBool::new(false)), @@ -115,6 +118,11 @@ impl Device { &self.keys } + /// Get a map containing all the device signatures. + pub fn signatures(&self) -> &BTreeMap> { + &self.signatures + } + /// Get the trust state of the device. pub fn trust_state(&self) -> TrustState { self.trust_state.load(Ordering::Relaxed) @@ -144,6 +152,7 @@ impl Device { self.algorithms = Arc::new(device_keys.algorithms.clone()); self.keys = Arc::new(device_keys.keys.clone()); + self.signatures = Arc::new(device_keys.signatures.clone()); self.display_name = display_name; Ok(()) @@ -180,6 +189,8 @@ impl Device { #[cfg(test)] impl From<&OlmMachine> for Device { fn from(machine: &OlmMachine) -> Self { + let signatures = BTreeMap::new(); + Device { user_id: Arc::new(machine.user_id().clone()), device_id: Arc::new(machine.device_id().into()), @@ -204,6 +215,7 @@ impl From<&OlmMachine> for Device { ), display_name: Arc::new(None), deleted: Arc::new(AtomicBool::new(false)), + signatures: Arc::new(signatures), trust_state: Arc::new(Atomic::new(TrustState::Unset)), } } @@ -217,6 +229,7 @@ impl TryFrom<&DeviceKeys> for Device { user_id: Arc::new(device_keys.user_id.clone()), device_id: Arc::new(device_keys.device_id.clone()), algorithms: Arc::new(device_keys.algorithms.clone()), + signatures: Arc::new(device_keys.signatures.clone()), keys: Arc::new(device_keys.keys.clone()), display_name: Arc::new( device_keys diff --git a/matrix_sdk_crypto/src/store/sqlite.rs b/matrix_sdk_crypto/src/store/sqlite.rs index 76aec6ab..ba545a0c 100644 --- a/matrix_sdk_crypto/src/store/sqlite.rs +++ b/matrix_sdk_crypto/src/store/sqlite.rs @@ -272,6 +272,25 @@ impl SqliteStore { ) .await?; + connection + .execute( + r#" + CREATE TABLE IF NOT EXISTS device_signatures ( + "id" INTEGER NOT NULL PRIMARY KEY, + "device_id" INTEGER NOT NULL, + "user_id" TEXT NOT NULL, + "key_algorithm" TEXT NOT NULL, + "signature" TEXT NOT NULL, + FOREIGN KEY ("device_id") REFERENCES "devices" ("id") + ON DELETE CASCADE + UNIQUE(device_id, user_id, key_algorithm) + ); + + CREATE INDEX IF NOT EXISTS "device_keys_device_id" ON "device_keys" ("device_id"); + "#, + ) + .await?; + Ok(()) } @@ -473,19 +492,55 @@ impl SqliteStore { .await?; let keys: BTreeMap = key_rows - .iter() + .into_iter() .filter_map(|row| { - let algorithm: &str = &row.0; - let algorithm = KeyAlgorithm::try_from(algorithm).ok()?; - let key = &row.1; + let algorithm = KeyAlgorithm::try_from(&*row.0).ok()?; + let key = row.1; Some(( AlgorithmAndDeviceId(algorithm, device_id.as_str().into()), - key.to_owned(), + key, )) }) .collect(); + let signature_rows: Vec<(String, String, String)> = query_as( + "SELECT user_id, key_algorithm, signature + FROM device_signatures WHERE device_id = ?", + ) + .bind(device_row_id) + .fetch_all(&mut *connection) + .await?; + + let mut signatures: BTreeMap> = + BTreeMap::new(); + + for row in signature_rows { + let user_id = if let Ok(u) = UserId::try_from(&*row.0) { + u + } else { + continue; + }; + + let key_algorithm = if let Ok(k) = KeyAlgorithm::try_from(&*row.1) { + k + } else { + continue; + }; + + let signature = row.2; + + if !signatures.contains_key(&user_id) { + let _ = signatures.insert(user_id.clone(), BTreeMap::new()); + } + let user_map = signatures.get_mut(&user_id).unwrap(); + + user_map.insert( + AlgorithmAndDeviceId(key_algorithm, device_id.as_str().into()), + signature.to_owned(), + ); + } + let device = Device::new( user_id, device_id.as_str().into(), @@ -493,6 +548,7 @@ impl SqliteStore { trust_state, algorithms, keys, + signatures, ); store.add(device); @@ -562,6 +618,23 @@ impl SqliteStore { .await?; } + for (user_id, signature_map) in device.signatures() { + for (key_id, signature) in signature_map { + query( + "INSERT OR IGNORE INTO device_signatures ( + device_id, user_id, key_algorithm, signature + ) VALUES (?1, ?2, ?3, ?4) + ", + ) + .bind(device_row_id) + .bind(user_id.as_str()) + .bind(key_id.0.to_string()) + .bind(signature) + .execute(&mut *connection) + .await?; + } + } + Ok(()) }