Skip to content

Commit f2c344b

Browse files
committed
fix(crypto): Use the DeviceKeys as the inner type for a ReadOnlyDevice
1 parent 7b6132b commit f2c344b

File tree

6 files changed

+97
-71
lines changed

6 files changed

+97
-71
lines changed

crates/matrix-sdk-crypto/src/identities/device.rs

Lines changed: 24 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,7 @@ use crate::{OlmMachine, ReadOnlyAccount};
5353
/// A read-only version of a `Device`.
5454
#[derive(Clone, Serialize, Deserialize)]
5555
pub struct ReadOnlyDevice {
56-
user_id: Arc<UserId>,
57-
device_id: Arc<DeviceId>,
58-
algorithms: Arc<[EventEncryptionAlgorithm]>,
59-
keys: Arc<BTreeMap<DeviceKeyId, String>>,
60-
pub(crate) signatures: Arc<BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>>,
61-
display_name: Arc<Option<String>>,
56+
pub(crate) inner: Arc<DeviceKeys>,
6257
#[serde(
6358
serialize_with = "atomic_bool_serializer",
6459
deserialize_with = "atomic_bool_deserializer"
@@ -76,7 +71,7 @@ impl std::fmt::Debug for ReadOnlyDevice {
7671
f.debug_struct("ReadOnlyDevice")
7772
.field("user_id", self.user_id())
7873
.field("device_id", &self.device_id())
79-
.field("display_name", self.display_name())
74+
.field("display_name", &self.display_name())
8075
.field("keys", self.keys())
8176
.field("deleted", &self.deleted.load(Ordering::SeqCst))
8277
.field("trust_state", &self.trust_state)
@@ -360,56 +355,46 @@ impl From<i64> for LocalTrust {
360355
}
361356

362357
impl ReadOnlyDevice {
363-
/// Create a new Device.
364-
pub fn new(
365-
user_id: UserId,
366-
device_id: Box<DeviceId>,
367-
display_name: Option<String>,
368-
trust_state: LocalTrust,
369-
algorithms: Vec<EventEncryptionAlgorithm>,
370-
keys: BTreeMap<DeviceKeyId, String>,
371-
signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
372-
) -> Self {
358+
/// Create a new Device, this constructor skips signature verification of
359+
/// the keys, `TryFrom` should be used for completely new devices we
360+
/// receive.
361+
#[cfg(feature = "sled_cryptostore")]
362+
pub(crate) fn new(device_keys: DeviceKeys, trust_state: LocalTrust) -> Self {
373363
Self {
374-
user_id: Arc::new(user_id),
375-
device_id: device_id.into(),
376-
display_name: Arc::new(display_name),
364+
inner: device_keys.into(),
377365
trust_state: Arc::new(Atomic::new(trust_state)),
378-
signatures: Arc::new(signatures),
379-
algorithms: algorithms.into(),
380-
keys: Arc::new(keys),
381366
deleted: Arc::new(AtomicBool::new(false)),
382367
}
383368
}
384369

385370
/// The user id of the device owner.
386371
pub fn user_id(&self) -> &UserId {
387-
&self.user_id
372+
&self.inner.user_id
388373
}
389374

390375
/// The unique ID of the device.
391376
pub fn device_id(&self) -> &DeviceId {
392-
&self.device_id
377+
&self.inner.device_id
393378
}
394379

395380
/// Get the human readable name of the device.
396-
pub fn display_name(&self) -> &Option<String> {
397-
&self.display_name
381+
pub fn display_name(&self) -> Option<&str> {
382+
self.inner.unsigned.device_display_name.as_deref()
398383
}
399384

400385
/// Get the key of the given key algorithm belonging to this device.
401386
pub fn get_key(&self, algorithm: DeviceKeyAlgorithm) -> Option<&String> {
402-
self.keys.get(&DeviceKeyId::from_parts(algorithm, &self.device_id))
387+
self.inner.keys.get(&DeviceKeyId::from_parts(algorithm, self.device_id()))
403388
}
404389

405390
/// Get a map containing all the device keys.
406391
pub fn keys(&self) -> &BTreeMap<DeviceKeyId, String> {
407-
&self.keys
392+
&self.inner.keys
408393
}
409394

410395
/// Get a map containing all the device signatures.
411396
pub fn signatures(&self) -> &BTreeMap<UserId, BTreeMap<DeviceKeyId, String>> {
412-
&self.signatures
397+
&self.inner.signatures
413398
}
414399

415400
/// Get the trust state of the device.
@@ -439,7 +424,7 @@ impl ReadOnlyDevice {
439424

440425
/// Get the list of algorithms this device supports.
441426
pub fn algorithms(&self) -> &[EventEncryptionAlgorithm] {
442-
&self.algorithms
427+
&self.inner.algorithms
443428
}
444429

445430
/// Is the device deleted.
@@ -528,13 +513,7 @@ impl ReadOnlyDevice {
528513
/// Update a device with a new device keys struct.
529514
pub(crate) fn update_device(&mut self, device_keys: &DeviceKeys) -> Result<(), SignatureError> {
530515
self.verify_device_keys(device_keys)?;
531-
532-
let display_name = Arc::new(device_keys.unsigned.device_display_name.clone());
533-
534-
self.algorithms = device_keys.algorithms.as_slice().into();
535-
self.keys = Arc::new(device_keys.keys.clone());
536-
self.signatures = Arc::new(device_keys.signatures.clone());
537-
self.display_name = display_name;
516+
self.inner = device_keys.clone().into();
538517

539518
Ok(())
540519
}
@@ -546,21 +525,15 @@ impl ReadOnlyDevice {
546525
let utility = Utility::new();
547526

548527
utility.verify_json(
549-
&self.user_id,
528+
self.user_id(),
550529
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()),
551530
signing_key,
552531
json,
553532
)
554533
}
555534

556-
pub(crate) fn as_device_keys(&self) -> DeviceKeys {
557-
DeviceKeys::new(
558-
self.user_id().clone(),
559-
self.device_id().into(),
560-
self.algorithms().to_vec(),
561-
self.keys().clone(),
562-
self.signatures().to_owned(),
563-
)
535+
pub(crate) fn as_device_keys(&self) -> &DeviceKeys {
536+
&self.inner
564537
}
565538

566539
pub(crate) fn verify_device_keys(
@@ -600,12 +573,7 @@ impl TryFrom<&DeviceKeys> for ReadOnlyDevice {
600573

601574
fn try_from(device_keys: &DeviceKeys) -> Result<Self, Self::Error> {
602575
let device = Self {
603-
user_id: Arc::new(device_keys.user_id.clone()),
604-
device_id: device_keys.device_id.clone().into(),
605-
algorithms: device_keys.algorithms.as_slice().into(),
606-
signatures: Arc::new(device_keys.signatures.clone()),
607-
keys: Arc::new(device_keys.keys.clone()),
608-
display_name: Arc::new(device_keys.unsigned.device_display_name.clone()),
576+
inner: device_keys.clone().into(),
609577
deleted: Arc::new(AtomicBool::new(false)),
610578
trust_state: Arc::new(Atomic::new(LocalTrust::Unset)),
611579
};
@@ -669,9 +637,9 @@ pub(crate) mod test {
669637

670638
assert_eq!(&user_id, device.user_id());
671639
assert_eq!(device_id, device.device_id());
672-
assert_eq!(device.algorithms.len(), 2);
640+
assert_eq!(device.algorithms().len(), 2);
673641
assert_eq!(LocalTrust::Unset, device.local_trust_state());
674-
assert_eq!("Alice's mobile phone", device.display_name().as_ref().unwrap());
642+
assert_eq!("Alice's mobile phone", device.display_name().unwrap());
675643
assert_eq!(
676644
device.get_key(DeviceKeyAlgorithm::Curve25519).unwrap(),
677645
"xfgbLIC5WAl1OIkpOzoxpCe8FsRDT6nch7NQsOb15nc"
@@ -686,7 +654,7 @@ pub(crate) mod test {
686654
fn update_a_device() {
687655
let mut device = get_device();
688656

689-
assert_eq!("Alice's mobile phone", device.display_name().as_ref().unwrap());
657+
assert_eq!("Alice's mobile phone", device.display_name().unwrap());
690658

691659
let display_name = "Alice's work computer".to_owned();
692660

crates/matrix-sdk-crypto/src/identities/user.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ impl SelfSigningPubkey {
589589
/// Returns an empty result if the signature check succeeded, otherwise a
590590
/// SignatureError indicating why the check failed.
591591
pub(crate) fn verify_device(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> {
592-
self.verify_device_keys(device.as_device_keys())
592+
self.verify_device_keys(device.as_device_keys().to_owned())
593593
}
594594
}
595595

@@ -1078,10 +1078,10 @@ pub(crate) mod test {
10781078

10791079
assert!(!device.verified());
10801080

1081-
let mut device_keys = device.as_device_keys();
1081+
let mut device_keys = device.as_device_keys().to_owned();
10821082

10831083
identity.sign_device_keys(&mut device_keys).await.unwrap();
1084-
device.inner.signatures = Arc::new(device_keys.signatures);
1084+
device.inner.update_device(&device_keys).expect("Couldn't update newly signed device keys");
10851085
assert!(device.verified());
10861086
}
10871087
}

crates/matrix-sdk-crypto/src/olm/signing/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ impl PrivateCrossSigningIdentity {
423423
&self,
424424
device: &ReadOnlyDevice,
425425
) -> Result<SignatureUploadRequest, SignatureError> {
426-
let mut device_keys = device.as_device_keys();
426+
let mut device_keys = device.as_device_keys().to_owned();
427427
device_keys.signatures.clear();
428428
self.sign_device_keys(&mut device_keys).await
429429
}
@@ -654,8 +654,6 @@ impl PrivateCrossSigningIdentity {
654654

655655
#[cfg(test)]
656656
mod test {
657-
use std::sync::Arc;
658-
659657
use matrix_sdk_test::async_test;
660658
use ruma::{user_id, UserId};
661659

@@ -757,9 +755,9 @@ mod test {
757755
let self_signing = identity.self_signing_key.lock().await;
758756
let self_signing = self_signing.as_ref().unwrap();
759757

760-
let mut device_keys = device.as_device_keys();
758+
let mut device_keys = device.as_device_keys().to_owned();
761759
self_signing.sign_device(&mut device_keys).await.unwrap();
762-
device.signatures = Arc::new(device_keys.signatures);
760+
device.update_device(&device_keys).unwrap();
763761

764762
let public_key = &self_signing.public_key;
765763
public_key.verify_device(&device).unwrap()

crates/matrix-sdk-crypto/src/store/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ impl Store {
288288
.inner
289289
.get_device(self.user_id(), self.device_id())
290290
.await?
291-
.and_then(|d| d.display_name().to_owned()))
291+
.and_then(|d| d.display_name().map(|d| d.to_string())))
292292
}
293293

294294
/// Get the read-only version of a specific device.

crates/matrix-sdk-crypto/src/store/sled.rs

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// limitations under the License.
1414

1515
use std::{
16-
collections::{HashMap, HashSet},
16+
collections::{BTreeMap, HashMap, HashSet},
1717
convert::{TryFrom, TryInto},
1818
path::{Path, PathBuf},
1919
sync::{Arc, RwLock},
@@ -23,9 +23,11 @@ use dashmap::DashSet;
2323
use matrix_sdk_common::{async_trait, locks::Mutex, uuid};
2424
use olm_rs::{account::IdentityKeys, PicklingMode};
2525
use ruma::{
26+
encryption::DeviceKeys,
2627
events::{room_key_request::RequestedKeyInfo, secret::request::SecretName},
27-
DeviceId, DeviceIdBox, RoomId, UserId,
28+
DeviceId, DeviceIdBox, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UserId,
2829
};
30+
use serde::{Deserialize, Serialize};
2931
pub use sled::Error;
3032
use sled::{
3133
transaction::{ConflictableTransactionError, TransactionError},
@@ -42,12 +44,13 @@ use crate::{
4244
gossiping::{GossipRequest, SecretInfo},
4345
identities::{ReadOnlyDevice, ReadOnlyUserIdentities},
4446
olm::{OutboundGroupSession, PickledInboundGroupSession, PrivateCrossSigningIdentity},
47+
LocalTrust,
4548
};
4649

4750
/// This needs to be 32 bytes long since AES-GCM requires it, otherwise we will
4851
/// panic once we try to pickle a Signing object.
4952
const DEFAULT_PICKLE: &str = "DEFAULT_PICKLE_PASSPHRASE_123456";
50-
const DATABASE_VERSION: u8 = 1;
53+
const DATABASE_VERSION: u8 = 2;
5154

5255
trait EncodeKey {
5356
const SEPARATOR: u8 = 0xff;
@@ -97,6 +100,12 @@ impl EncodeKey for &UserId {
97100
}
98101
}
99102

103+
impl EncodeKey for &ReadOnlyDevice {
104+
fn encode(&self) -> Vec<u8> {
105+
(self.user_id().as_str(), self.device_id().as_str()).encode()
106+
}
107+
}
108+
100109
impl EncodeKey for &RoomId {
101110
fn encode(&self) -> Vec<u8> {
102111
self.as_str().encode()
@@ -266,6 +275,57 @@ impl SledStore {
266275
self.outbound_group_sessions.clear()?;
267276
}
268277

278+
if version <= 1 {
279+
#[derive(Serialize, Deserialize)]
280+
pub struct OldReadOnlyDevice {
281+
user_id: UserId,
282+
device_id: DeviceIdBox,
283+
algorithms: Vec<EventEncryptionAlgorithm>,
284+
keys: BTreeMap<DeviceKeyId, String>,
285+
signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
286+
display_name: Option<String>,
287+
deleted: bool,
288+
trust_state: LocalTrust,
289+
}
290+
291+
#[allow(clippy::from_over_into)]
292+
impl Into<ReadOnlyDevice> for OldReadOnlyDevice {
293+
fn into(self) -> ReadOnlyDevice {
294+
let mut device_keys = DeviceKeys::new(
295+
self.user_id,
296+
self.device_id,
297+
self.algorithms,
298+
self.keys,
299+
self.signatures,
300+
);
301+
device_keys.unsigned.device_display_name = self.display_name;
302+
303+
ReadOnlyDevice::new(device_keys, self.trust_state)
304+
}
305+
}
306+
307+
let devices: Vec<ReadOnlyDevice> = self
308+
.devices
309+
.iter()
310+
.map(|d| serde_json::from_slice(&d?.1).map_err(CryptoStoreError::Serialization))
311+
.map(|d| {
312+
let d: OldReadOnlyDevice = d?;
313+
Ok(d.into())
314+
})
315+
.collect::<Result<Vec<ReadOnlyDevice>, CryptoStoreError>>()?;
316+
317+
self.devices.transaction(move |tree| {
318+
for device in &devices {
319+
let key = device.encode();
320+
let device =
321+
serde_json::to_vec(device).map_err(ConflictableTransactionError::Abort)?;
322+
tree.insert(key, device)?;
323+
}
324+
325+
Ok(())
326+
})?;
327+
}
328+
269329
self.inner.insert("store_version", DATABASE_VERSION.to_be_bytes().as_ref())?;
270330
self.inner.flush()?;
271331

@@ -504,14 +564,14 @@ impl SledStore {
504564
}
505565

506566
for device in device_changes.new.iter().chain(&device_changes.changed) {
507-
let key = (device.user_id().as_str(), device.device_id().as_str()).encode();
567+
let key = device.encode();
508568
let device = serde_json::to_vec(&device)
509569
.map_err(ConflictableTransactionError::Abort)?;
510570
devices.insert(key, device)?;
511571
}
512572

513573
for device in &device_changes.deleted {
514-
let key = (device.user_id().as_str(), device.device_id().as_str()).encode();
574+
let key = device.encode();
515575
devices.remove(key)?;
516576
}
517577

crates/matrix-sdk/examples/emoji_verification.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ async fn print_devices(user_id: &UserId, client: &Client) {
5858
println!(
5959
" {:<10} {:<30} {:<}",
6060
device.device_id(),
61-
device.display_name().as_deref().unwrap_or_default(),
61+
device.display_name().unwrap_or("-"),
6262
device.verified()
6363
);
6464
}

0 commit comments

Comments
 (0)