crypto: Store the device signatures with the devices as well.

master
Damir Jelić 2020-07-21 17:33:47 +02:00
parent a9d645cbcd
commit 2481fbbd27
2 changed files with 91 additions and 5 deletions

View File

@ -36,6 +36,7 @@ pub struct Device {
device_id: Arc<Box<DeviceId>>, device_id: Arc<Box<DeviceId>>,
algorithms: Arc<Vec<Algorithm>>, algorithms: Arc<Vec<Algorithm>>,
keys: Arc<BTreeMap<AlgorithmAndDeviceId, String>>, keys: Arc<BTreeMap<AlgorithmAndDeviceId, String>>,
signatures: Arc<BTreeMap<UserId, BTreeMap<AlgorithmAndDeviceId, String>>>,
display_name: Arc<Option<String>>, display_name: Arc<Option<String>>,
deleted: Arc<AtomicBool>, deleted: Arc<AtomicBool>,
trust_state: Arc<Atomic<TrustState>>, trust_state: Arc<Atomic<TrustState>>,
@ -75,12 +76,14 @@ impl Device {
trust_state: TrustState, trust_state: TrustState,
algorithms: Vec<Algorithm>, algorithms: Vec<Algorithm>,
keys: BTreeMap<AlgorithmAndDeviceId, String>, keys: BTreeMap<AlgorithmAndDeviceId, String>,
signatures: BTreeMap<UserId, BTreeMap<AlgorithmAndDeviceId, String>>,
) -> Self { ) -> Self {
Device { Device {
user_id: Arc::new(user_id), user_id: Arc::new(user_id),
device_id: Arc::new(device_id), device_id: Arc::new(device_id),
display_name: Arc::new(display_name), display_name: Arc::new(display_name),
trust_state: Arc::new(Atomic::new(trust_state)), trust_state: Arc::new(Atomic::new(trust_state)),
signatures: Arc::new(signatures),
algorithms: Arc::new(algorithms), algorithms: Arc::new(algorithms),
keys: Arc::new(keys), keys: Arc::new(keys),
deleted: Arc::new(AtomicBool::new(false)), deleted: Arc::new(AtomicBool::new(false)),
@ -115,6 +118,11 @@ impl Device {
&self.keys &self.keys
} }
/// Get a map containing all the device signatures.
pub fn signatures(&self) -> &BTreeMap<UserId, BTreeMap<AlgorithmAndDeviceId, String>> {
&self.signatures
}
/// Get the trust state of the device. /// Get the trust state of the device.
pub fn trust_state(&self) -> TrustState { pub fn trust_state(&self) -> TrustState {
self.trust_state.load(Ordering::Relaxed) self.trust_state.load(Ordering::Relaxed)
@ -144,6 +152,7 @@ impl Device {
self.algorithms = Arc::new(device_keys.algorithms.clone()); self.algorithms = Arc::new(device_keys.algorithms.clone());
self.keys = Arc::new(device_keys.keys.clone()); self.keys = Arc::new(device_keys.keys.clone());
self.signatures = Arc::new(device_keys.signatures.clone());
self.display_name = display_name; self.display_name = display_name;
Ok(()) Ok(())
@ -180,6 +189,8 @@ impl Device {
#[cfg(test)] #[cfg(test)]
impl From<&OlmMachine> for Device { impl From<&OlmMachine> for Device {
fn from(machine: &OlmMachine) -> Self { fn from(machine: &OlmMachine) -> Self {
let signatures = BTreeMap::new();
Device { Device {
user_id: Arc::new(machine.user_id().clone()), user_id: Arc::new(machine.user_id().clone()),
device_id: Arc::new(machine.device_id().into()), device_id: Arc::new(machine.device_id().into()),
@ -204,6 +215,7 @@ impl From<&OlmMachine> for Device {
), ),
display_name: Arc::new(None), display_name: Arc::new(None),
deleted: Arc::new(AtomicBool::new(false)), deleted: Arc::new(AtomicBool::new(false)),
signatures: Arc::new(signatures),
trust_state: Arc::new(Atomic::new(TrustState::Unset)), 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()), user_id: Arc::new(device_keys.user_id.clone()),
device_id: Arc::new(device_keys.device_id.clone()), device_id: Arc::new(device_keys.device_id.clone()),
algorithms: Arc::new(device_keys.algorithms.clone()), algorithms: Arc::new(device_keys.algorithms.clone()),
signatures: Arc::new(device_keys.signatures.clone()),
keys: Arc::new(device_keys.keys.clone()), keys: Arc::new(device_keys.keys.clone()),
display_name: Arc::new( display_name: Arc::new(
device_keys device_keys

View File

@ -272,6 +272,25 @@ impl SqliteStore {
) )
.await?; .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(()) Ok(())
} }
@ -473,19 +492,55 @@ impl SqliteStore {
.await?; .await?;
let keys: BTreeMap<AlgorithmAndDeviceId, String> = key_rows let keys: BTreeMap<AlgorithmAndDeviceId, String> = key_rows
.iter() .into_iter()
.filter_map(|row| { .filter_map(|row| {
let algorithm: &str = &row.0; let algorithm = KeyAlgorithm::try_from(&*row.0).ok()?;
let algorithm = KeyAlgorithm::try_from(algorithm).ok()?; let key = row.1;
let key = &row.1;
Some(( Some((
AlgorithmAndDeviceId(algorithm, device_id.as_str().into()), AlgorithmAndDeviceId(algorithm, device_id.as_str().into()),
key.to_owned(), key,
)) ))
}) })
.collect(); .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<UserId, BTreeMap<AlgorithmAndDeviceId, String>> =
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( let device = Device::new(
user_id, user_id,
device_id.as_str().into(), device_id.as_str().into(),
@ -493,6 +548,7 @@ impl SqliteStore {
trust_state, trust_state,
algorithms, algorithms,
keys, keys,
signatures,
); );
store.add(device); store.add(device);
@ -562,6 +618,23 @@ impl SqliteStore {
.await?; .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(()) Ok(())
} }