mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-06 23:15:08 -04:00
chore: Bump Ruma.
This commit is contained in:
@@ -27,5 +27,8 @@ byteorder = "1.4.3"
|
||||
image = { version = "0.23.14", optional = true }
|
||||
qrcode = { version = "0.12.0", default-features = false }
|
||||
rqrr = { version = "0.4.0", optional = true }
|
||||
ruma-identifiers = { git = "https://github.com/ruma/ruma", rev = "6c4892664" }
|
||||
thiserror = "1.0.25"
|
||||
|
||||
[dependencies.ruma-identifiers]
|
||||
git = "https://github.com/ruma/ruma/"
|
||||
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
|
||||
|
||||
@@ -37,8 +37,8 @@ url = "2"
|
||||
warp = { version = "0.3.1", optional = true, default-features = false }
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma"
|
||||
rev = "6c4892664"
|
||||
git = "https://github.com/ruma/ruma/"
|
||||
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
|
||||
features = ["client-api-c", "appservice-api-s", "unstable-pre-spec"]
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -19,7 +19,14 @@ rustdoc-args = ["--cfg", "feature=\"docs\""]
|
||||
default = []
|
||||
encryption = ["matrix-sdk-crypto"]
|
||||
qrcode = ["matrix-sdk-crypto/qrcode"]
|
||||
sled_state_store = ["sled", "pbkdf2", "hmac", "sha2", "rand", "chacha20poly1305"]
|
||||
sled_state_store = [
|
||||
"sled",
|
||||
"pbkdf2",
|
||||
"hmac",
|
||||
"sha2",
|
||||
"rand",
|
||||
"chacha20poly1305",
|
||||
]
|
||||
sled_cryptostore = ["matrix-sdk-crypto/sled_cryptostore"]
|
||||
|
||||
docs = ["encryption", "sled_cryptostore"]
|
||||
@@ -35,7 +42,6 @@ matrix-sdk-common = { version = "0.4.0", path = "../matrix-sdk-common" }
|
||||
matrix-sdk-crypto = { version = "0.4.0", path = "../matrix-sdk-crypto", optional = true }
|
||||
pbkdf2 = { version = "0.9.0", default-features = false, optional = true }
|
||||
rand = { version = "0.8.4", optional = true }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "6c4892664", features = ["client-api-c", "unstable-pre-spec"] }
|
||||
serde = { version = "1.0.126", features = ["rc"] }
|
||||
serde_json = "1.0.64"
|
||||
sha2 = { version = "0.9.5", optional = true }
|
||||
@@ -44,6 +50,11 @@ thiserror = "1.0.25"
|
||||
tracing = "0.1.26"
|
||||
zeroize = { version = "1.3.0", features = ["zeroize_derive"] }
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma/"
|
||||
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
|
||||
features = ["client-api-c", "unstable-pre-spec"]
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio]
|
||||
version = "1.7.1"
|
||||
default-features = false
|
||||
@@ -60,7 +71,10 @@ clap = "2.33.3"
|
||||
rustyline = "9.0.0"
|
||||
rustyline-derive = "0.5.0"
|
||||
syntect = "4.5.0"
|
||||
tokio = { version = "1.7.1", default-features = false, features = ["rt-multi-thread", "macros"] }
|
||||
tokio = { version = "1.7.1", default-features = false, features = [
|
||||
"rt-multi-thread",
|
||||
"macros",
|
||||
] }
|
||||
tempfile = "3.2.0"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||
|
||||
@@ -650,6 +650,7 @@ impl BaseClient {
|
||||
&self,
|
||||
response: api::sync::sync_events::Response,
|
||||
) -> Result<SyncResponse> {
|
||||
#[allow(unused_variables)]
|
||||
let api::sync::sync_events::Response {
|
||||
next_batch,
|
||||
rooms,
|
||||
@@ -658,6 +659,7 @@ impl BaseClient {
|
||||
to_device,
|
||||
device_lists,
|
||||
device_one_time_keys_count,
|
||||
device_unused_fallback_key_types,
|
||||
..
|
||||
} = response;
|
||||
|
||||
@@ -679,8 +681,13 @@ impl BaseClient {
|
||||
// decrypts to-device events, but leaves room events alone.
|
||||
// This makes sure that we have the decryption keys for the room
|
||||
// events at hand.
|
||||
o.receive_sync_changes(to_device, &device_lists, &device_one_time_keys_count)
|
||||
.await?
|
||||
o.receive_sync_changes(
|
||||
to_device,
|
||||
&device_lists,
|
||||
&device_one_time_keys_count,
|
||||
device_unused_fallback_key_types.as_deref(),
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
to_device
|
||||
}
|
||||
|
||||
@@ -13,11 +13,18 @@ version = "0.4.1"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.50"
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "6c4892664", features = ["client-api-c"] }
|
||||
serde = "1.0.126"
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma/"
|
||||
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
|
||||
features = ["client-api-c"]
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
uuid = { version = "0.8.2", default-features = false, features = ["v4", "serde"] }
|
||||
uuid = { version = "0.8.2", default-features = false, features = [
|
||||
"v4",
|
||||
"serde",
|
||||
] }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio]
|
||||
version = "1.7.1"
|
||||
@@ -36,4 +43,8 @@ features = ["now"]
|
||||
async-lock = "2.4.0"
|
||||
futures-util = { version = "0.3.15", default-features = false, features = ["channel"] }
|
||||
wasm-bindgen-futures = "0.4.24"
|
||||
uuid = { version = "0.8.2", default-features = false, features = ["v4", "wasm-bindgen", "serde"] }
|
||||
uuid = { version = "0.8.2", default-features = false, features = [
|
||||
"v4",
|
||||
"wasm-bindgen",
|
||||
"serde",
|
||||
] }
|
||||
|
||||
@@ -38,10 +38,6 @@ matrix-sdk-common = { version = "0.4.0", path = "../matrix-sdk-common" }
|
||||
olm-rs = { version = "2.1", features = ["serde"] }
|
||||
pbkdf2 = { version = "0.9.0", default-features = false }
|
||||
rand = "0.8.4"
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "6c4892664", features = [
|
||||
"client-api-c",
|
||||
"unstable-pre-spec",
|
||||
] }
|
||||
serde = { version = "1.0.126", features = ["derive", "rc"] }
|
||||
serde_json = "1.0.64"
|
||||
sha2 = "0.9.5"
|
||||
@@ -50,6 +46,11 @@ thiserror = "1.0.25"
|
||||
tracing = "0.1.26"
|
||||
zeroize = { version = "1.3.0", features = ["zeroize_derive"] }
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma/"
|
||||
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
|
||||
features = ["client-api-c", "unstable-pre-spec"]
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3.4", features = [
|
||||
"async",
|
||||
|
||||
@@ -33,12 +33,14 @@ async fn main() -> Result<(), OlmError> {
|
||||
let to_device_events = ToDevice::default();
|
||||
let changed_devices = DeviceLists::default();
|
||||
let one_time_key_counts = BTreeMap::default();
|
||||
let unused_fallback_keys = Some(Vec::new());
|
||||
|
||||
// Push changes that the server sent to us in a sync response.
|
||||
let decrypted_to_device = machine.receive_sync_changes(
|
||||
to_device_events,
|
||||
&changed_devices,
|
||||
&one_time_key_counts
|
||||
&one_time_key_counts,
|
||||
unused_fallback_keys.as_deref(),
|
||||
).await?;
|
||||
|
||||
// Pull requests that we need to send out.
|
||||
|
||||
@@ -30,7 +30,8 @@ use std::{
|
||||
|
||||
use matrix_sdk_common::{locks::RwLock, uuid::Uuid};
|
||||
use ruma::{
|
||||
api::client::r0::backup::RoomKeyBackup, DeviceKeyAlgorithm, DeviceKeyId, RoomId, UserId,
|
||||
api::client::r0::backup::RoomKeyBackup, serde::Raw, DeviceKeyAlgorithm, DeviceKeyId, RoomId,
|
||||
UserId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
@@ -369,6 +370,11 @@ impl BackupMachine {
|
||||
.or_default()
|
||||
.insert(session_id.clone());
|
||||
|
||||
let session = Raw::from_json(
|
||||
serde_json::value::to_raw_value(&session)
|
||||
.expect("Can't serialize a backed up room key"),
|
||||
);
|
||||
|
||||
backup
|
||||
.entry(room_id)
|
||||
.or_insert_with(|| RoomKeyBackup::new(BTreeMap::new()))
|
||||
|
||||
@@ -213,4 +213,6 @@ pub(crate) enum SessionCreationError {
|
||||
DeviceMissingCurveKey(Box<UserId>, Box<DeviceId>),
|
||||
#[error("Error creating new Olm session for {0} {1}: {2:?}")]
|
||||
OlmError(Box<UserId>, Box<DeviceId>, OlmSessionError),
|
||||
#[error("Error deserializing the one-time key: {0}")]
|
||||
InvalidJson(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ use futures_util::future::join_all;
|
||||
use matrix_sdk_common::executor::spawn;
|
||||
use ruma::{
|
||||
api::client::r0::keys::get_keys::Response as KeysQueryResponse, encryption::DeviceKeys,
|
||||
DeviceId, UserId,
|
||||
serde::Raw, DeviceId, UserId,
|
||||
};
|
||||
use tracing::{debug, info, trace, warn};
|
||||
|
||||
@@ -205,7 +205,7 @@ impl IdentityManager {
|
||||
own_user_id: Arc<UserId>,
|
||||
own_device_id: Arc<DeviceId>,
|
||||
user_id: Box<UserId>,
|
||||
device_map: BTreeMap<Box<DeviceId>, DeviceKeys>,
|
||||
device_map: BTreeMap<Box<DeviceId>, Raw<DeviceKeys>>,
|
||||
) -> StoreResult<DeviceChanges> {
|
||||
let own_device_id = (&*own_device_id).to_owned();
|
||||
|
||||
@@ -213,18 +213,31 @@ impl IdentityManager {
|
||||
|
||||
let current_devices: HashSet<Box<DeviceId>> = device_map.keys().cloned().collect();
|
||||
|
||||
let tasks = device_map.into_iter().filter_map(|(device_id, device_keys)| {
|
||||
if user_id != device_keys.user_id || device_id != device_keys.device_id {
|
||||
let tasks = device_map.into_iter().filter_map(|(device_id, device_keys)| match device_keys
|
||||
.deserialize()
|
||||
{
|
||||
Ok(device_keys) => {
|
||||
if user_id != device_keys.user_id || device_id != device_keys.device_id {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
device_id = device_id.as_str(),
|
||||
device_key_user = device_keys.user_id.as_str(),
|
||||
device_key_device_id = device_keys.device_id.as_str(),
|
||||
"Mismatch in the device keys payload",
|
||||
);
|
||||
None
|
||||
} else {
|
||||
Some(spawn(Self::update_or_create_device(store.clone(), device_keys)))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
device_id = device_id.as_str(),
|
||||
device_key_user = device_keys.user_id.as_str(),
|
||||
device_key_device_id = device_keys.device_id.as_str(),
|
||||
"Mismatch in the device keys payload",
|
||||
error =? e,
|
||||
"Device keys failed to deserialize",
|
||||
);
|
||||
None
|
||||
} else {
|
||||
Some(spawn(Self::update_or_create_device(store.clone(), device_keys)))
|
||||
}
|
||||
});
|
||||
|
||||
@@ -272,7 +285,7 @@ impl IdentityManager {
|
||||
/// they are new, one of their properties has changed or they got deleted.
|
||||
async fn handle_devices_from_key_query(
|
||||
&self,
|
||||
device_keys_map: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceId>, DeviceKeys>>,
|
||||
device_keys_map: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceId>, Raw<DeviceKeys>>>,
|
||||
) -> StoreResult<DeviceChanges> {
|
||||
let mut changes = DeviceChanges::default();
|
||||
|
||||
@@ -312,93 +325,122 @@ impl IdentityManager {
|
||||
let mut changes = IdentityChanges::default();
|
||||
let mut changed_identity = None;
|
||||
|
||||
// TODO this is a bit chunky, refactor this into smaller methods.
|
||||
|
||||
for (user_id, master_key) in &response.master_keys {
|
||||
let master_key = MasterPubkey::from(master_key);
|
||||
match master_key.deserialize() {
|
||||
Ok(master_key) => {
|
||||
let master_key = MasterPubkey::from(master_key);
|
||||
|
||||
let self_signing = if let Some(s) = response.self_signing_keys.get(user_id) {
|
||||
SelfSigningPubkey::from(s)
|
||||
} else {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
"A user identity didn't contain a self signing pubkey"
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let self_signing = if let Some(s) =
|
||||
response.self_signing_keys.get(user_id).and_then(|k| k.deserialize().ok())
|
||||
{
|
||||
SelfSigningPubkey::from(s)
|
||||
} else {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
"A user identity didn't contain a self signing pubkey \
|
||||
or the key was invalid"
|
||||
);
|
||||
continue;
|
||||
};
|
||||
|
||||
let result = if let Some(mut i) = self.store.get_user_identity(user_id).await? {
|
||||
match &mut i {
|
||||
ReadOnlyUserIdentities::Own(ref mut identity) => {
|
||||
let user_signing = if let Some(s) = response.user_signing_keys.get(user_id)
|
||||
let result = if let Some(mut i) = self.store.get_user_identity(user_id).await? {
|
||||
match &mut i {
|
||||
ReadOnlyUserIdentities::Own(ref mut identity) => {
|
||||
let user_signing = if let Some(s) = response
|
||||
.user_signing_keys
|
||||
.get(user_id)
|
||||
.and_then(|k| k.deserialize().ok())
|
||||
{
|
||||
UserSigningPubkey::from(s)
|
||||
} else {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
"User identity for our own user didn't \
|
||||
contain a user signing pubkey",
|
||||
);
|
||||
continue;
|
||||
};
|
||||
|
||||
identity
|
||||
.update(master_key, self_signing, user_signing)
|
||||
.map(|_| (i, false))
|
||||
}
|
||||
ReadOnlyUserIdentities::Other(ref mut identity) => {
|
||||
identity.update(master_key, self_signing).map(|_| (i, false))
|
||||
}
|
||||
}
|
||||
} else if user_id == self.user_id() {
|
||||
if let Some(s) = response
|
||||
.user_signing_keys
|
||||
.get(user_id)
|
||||
.and_then(|k| k.deserialize().ok())
|
||||
{
|
||||
UserSigningPubkey::from(s)
|
||||
let user_signing = UserSigningPubkey::from(s);
|
||||
|
||||
if master_key.user_id() != user_id
|
||||
|| self_signing.user_id() != user_id
|
||||
|| user_signing.user_id() != user_id
|
||||
{
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
"User ID mismatch in one of the cross signing keys",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
ReadOnlyOwnUserIdentity::new(master_key, self_signing, user_signing)
|
||||
.map(|i| (ReadOnlyUserIdentities::Own(i), true))
|
||||
} else {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
"User identity for our own user didn't \
|
||||
contain a user signing pubkey",
|
||||
"User identity for our own user didn't contain a \
|
||||
user signing pubkey or the key isn't valid",
|
||||
);
|
||||
continue;
|
||||
};
|
||||
|
||||
identity.update(master_key, self_signing, user_signing).map(|_| (i, false))
|
||||
}
|
||||
ReadOnlyUserIdentities::Other(ref mut identity) => {
|
||||
identity.update(master_key, self_signing).map(|_| (i, false))
|
||||
}
|
||||
}
|
||||
} else if user_id == self.user_id() {
|
||||
if let Some(s) = response.user_signing_keys.get(user_id) {
|
||||
let user_signing = UserSigningPubkey::from(s);
|
||||
|
||||
if master_key.user_id() != user_id
|
||||
|| self_signing.user_id() != user_id
|
||||
|| user_signing.user_id() != user_id
|
||||
{
|
||||
}
|
||||
} else if master_key.user_id() != user_id || self_signing.user_id() != user_id {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
user = user_id.as_str(),
|
||||
"User ID mismatch in one of the cross signing keys",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
ReadOnlyOwnUserIdentity::new(master_key, self_signing, user_signing)
|
||||
.map(|i| (ReadOnlyUserIdentities::Own(i), true))
|
||||
} else {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
"User identity for our own user didn't contain a \
|
||||
user signing pubkey",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
} else if master_key.user_id() != user_id || self_signing.user_id() != user_id {
|
||||
warn!(user = user_id.as_str(), "User ID mismatch in one of the cross signing keys",);
|
||||
continue;
|
||||
} else {
|
||||
ReadOnlyUserIdentity::new(master_key, self_signing)
|
||||
.map(|i| (ReadOnlyUserIdentities::Other(i), true))
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok((i, new)) => {
|
||||
if let Some(identity) = i.own() {
|
||||
let private_identity = self.store.private_identity();
|
||||
let private_identity = private_identity.lock().await;
|
||||
|
||||
let result = private_identity.clear_if_differs(identity).await;
|
||||
|
||||
if result.any_cleared() {
|
||||
changed_identity = Some((&*private_identity).clone());
|
||||
info!(cleared =? result, "Removed some or all of our private cross signing keys");
|
||||
}
|
||||
}
|
||||
|
||||
if new {
|
||||
trace!(user_id = user_id.as_str(), identity =? i, "Created new user identity");
|
||||
changes.new.push(i);
|
||||
} else {
|
||||
trace!(user_id = user_id.as_str(), identity =? i, "Updated a user identity");
|
||||
changes.changed.push(i);
|
||||
ReadOnlyUserIdentity::new(master_key, self_signing)
|
||||
.map(|i| (ReadOnlyUserIdentities::Other(i), true))
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok((i, new)) => {
|
||||
if let Some(identity) = i.own() {
|
||||
let private_identity = self.store.private_identity();
|
||||
let private_identity = private_identity.lock().await;
|
||||
|
||||
let result = private_identity.clear_if_differs(identity).await;
|
||||
|
||||
if result.any_cleared() {
|
||||
changed_identity = Some((&*private_identity).clone());
|
||||
info!(cleared =? result, "Removed some or all of our private cross signing keys");
|
||||
}
|
||||
}
|
||||
|
||||
if new {
|
||||
trace!(user_id = user_id.as_str(), identity =? i, "Created new user identity");
|
||||
changes.new.push(i);
|
||||
} else {
|
||||
trace!(user_id = user_id.as_str(), identity =? i, "Updated a user identity");
|
||||
changes.changed.push(i);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
user_id = user_id.as_str(),
|
||||
error =? e,
|
||||
"Couldn't update or create new user identity"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
@@ -956,17 +956,19 @@ pub(crate) mod test {
|
||||
|
||||
fn device(response: &KeyQueryResponse) -> (ReadOnlyDevice, ReadOnlyDevice) {
|
||||
let mut devices = response.device_keys.values().next().unwrap().values();
|
||||
let first = ReadOnlyDevice::try_from(devices.next().unwrap()).unwrap();
|
||||
let second = ReadOnlyDevice::try_from(devices.next().unwrap()).unwrap();
|
||||
let first =
|
||||
ReadOnlyDevice::try_from(&devices.next().unwrap().deserialize().unwrap()).unwrap();
|
||||
let second =
|
||||
ReadOnlyDevice::try_from(&devices.next().unwrap().deserialize().unwrap()).unwrap();
|
||||
(first, second)
|
||||
}
|
||||
|
||||
fn own_identity(response: &KeyQueryResponse) -> ReadOnlyOwnUserIdentity {
|
||||
let user_id = user_id!("@example:localhost");
|
||||
|
||||
let master_key = response.master_keys.get(user_id).unwrap();
|
||||
let user_signing = response.user_signing_keys.get(user_id).unwrap();
|
||||
let self_signing = response.self_signing_keys.get(user_id).unwrap();
|
||||
let master_key = response.master_keys.get(user_id).unwrap().deserialize().unwrap();
|
||||
let user_signing = response.user_signing_keys.get(user_id).unwrap().deserialize().unwrap();
|
||||
let self_signing = response.self_signing_keys.get(user_id).unwrap().deserialize().unwrap();
|
||||
|
||||
ReadOnlyOwnUserIdentity::new(master_key.into(), self_signing.into(), user_signing.into())
|
||||
.unwrap()
|
||||
@@ -980,8 +982,8 @@ pub(crate) mod test {
|
||||
let user_id = user_id!("@example2:localhost");
|
||||
let response = other_key_query();
|
||||
|
||||
let master_key = response.master_keys.get(user_id).unwrap();
|
||||
let self_signing = response.self_signing_keys.get(user_id).unwrap();
|
||||
let master_key = response.master_keys.get(user_id).unwrap().deserialize().unwrap();
|
||||
let self_signing = response.self_signing_keys.get(user_id).unwrap().deserialize().unwrap();
|
||||
|
||||
ReadOnlyUserIdentity::new(master_key.into(), self_signing.into()).unwrap()
|
||||
}
|
||||
@@ -991,9 +993,9 @@ pub(crate) mod test {
|
||||
let user_id = user_id!("@example:localhost");
|
||||
let response = own_key_query();
|
||||
|
||||
let master_key = response.master_keys.get(user_id).unwrap();
|
||||
let user_signing = response.user_signing_keys.get(user_id).unwrap();
|
||||
let self_signing = response.self_signing_keys.get(user_id).unwrap();
|
||||
let master_key = response.master_keys.get(user_id).unwrap().deserialize().unwrap();
|
||||
let user_signing = response.user_signing_keys.get(user_id).unwrap().deserialize().unwrap();
|
||||
let self_signing = response.self_signing_keys.get(user_id).unwrap().deserialize().unwrap();
|
||||
|
||||
ReadOnlyOwnUserIdentity::new(master_key.into(), self_signing.into(), user_signing.into())
|
||||
.unwrap();
|
||||
|
||||
@@ -46,9 +46,10 @@ use ruma::{
|
||||
secret::request::SecretName,
|
||||
AnyMessageEventContent, AnyRoomEvent, AnyToDeviceEvent, EventContent,
|
||||
},
|
||||
serde::Raw,
|
||||
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UInt, UserId,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use serde_json::{value::to_raw_value, Value};
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
|
||||
#[cfg(feature = "backups_v1")]
|
||||
@@ -562,7 +563,13 @@ impl OlmMachine {
|
||||
/// [`OlmMachine`]: struct.OlmMachine.html
|
||||
async fn keys_for_upload(&self) -> Option<upload_keys::Request> {
|
||||
let (device_keys, one_time_keys) = self.account.keys_for_upload().await?;
|
||||
Some(assign!(upload_keys::Request::new(), { device_keys, one_time_keys }))
|
||||
|
||||
let device_keys = device_keys
|
||||
.map(|d| Raw::from_json(to_raw_value(&d).expect("Coulnd't serialize device keys")));
|
||||
|
||||
Some(
|
||||
assign!(upload_keys::Request::new(), { device_keys, one_time_keys, fallback_keys: BTreeMap::new(), }),
|
||||
)
|
||||
}
|
||||
|
||||
/// Decrypt a to-device event.
|
||||
@@ -859,8 +866,12 @@ impl OlmMachine {
|
||||
self.verification_machine.get_requests(user_id)
|
||||
}
|
||||
|
||||
fn update_one_time_key_count(&self, key_count: &BTreeMap<DeviceKeyAlgorithm, UInt>) {
|
||||
self.account.update_uploaded_key_count(key_count);
|
||||
async fn update_key_counts(
|
||||
&self,
|
||||
one_time_key_count: &BTreeMap<DeviceKeyAlgorithm, UInt>,
|
||||
#[allow(unused_variables)] unused_fallback_keys: Option<&[DeviceKeyAlgorithm]>,
|
||||
) {
|
||||
self.account.update_uploaded_key_count(one_time_key_count);
|
||||
}
|
||||
|
||||
async fn handle_to_device_event(&self, event: &AnyToDeviceEvent) {
|
||||
@@ -913,6 +924,7 @@ impl OlmMachine {
|
||||
to_device_events: ToDevice,
|
||||
changed_devices: &DeviceLists,
|
||||
one_time_keys_counts: &BTreeMap<DeviceKeyAlgorithm, UInt>,
|
||||
unused_fallback_keys: Option<&[DeviceKeyAlgorithm]>,
|
||||
) -> OlmResult<ToDevice> {
|
||||
// Remove verification objects that have expired or are done.
|
||||
let mut events = self.verification_machine.garbage_collect();
|
||||
@@ -922,7 +934,7 @@ impl OlmMachine {
|
||||
let mut changes =
|
||||
Changes { account: Some(self.account.inner.clone()), ..Default::default() };
|
||||
|
||||
self.update_one_time_key_count(one_time_keys_counts);
|
||||
self.update_key_counts(one_time_keys_counts, unused_fallback_keys).await;
|
||||
|
||||
for user_id in &changed_devices.changed {
|
||||
if let Err(e) = self.identity_manager.mark_user_as_changed(user_id).await {
|
||||
@@ -1568,8 +1580,10 @@ pub(crate) mod test {
|
||||
AnyMessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent, AnyToDeviceEvent,
|
||||
AnyToDeviceEventContent, SyncMessageEvent, ToDeviceEvent, Unsigned,
|
||||
},
|
||||
room_id, uint, user_id, DeviceId, DeviceKeyAlgorithm, DeviceKeyId,
|
||||
MilliSecondsSinceUnixEpoch, UserId,
|
||||
room_id,
|
||||
serde::Raw,
|
||||
uint, user_id, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch,
|
||||
UserId,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
@@ -1581,7 +1595,7 @@ pub(crate) mod test {
|
||||
};
|
||||
|
||||
/// These keys need to be periodically uploaded to the server.
|
||||
type OneTimeKeys = BTreeMap<Box<DeviceKeyId>, OneTimeKey>;
|
||||
type OneTimeKeys = BTreeMap<Box<DeviceKeyId>, Raw<OneTimeKey>>;
|
||||
|
||||
fn alice_id() -> &'static UserId {
|
||||
user_id!("@alice:example.org")
|
||||
@@ -1635,7 +1649,7 @@ pub(crate) mod test {
|
||||
let response = keys_upload_response();
|
||||
machine.receive_keys_upload_response(&response).await.unwrap();
|
||||
|
||||
(machine, request.one_time_keys.unwrap())
|
||||
(machine, request.one_time_keys)
|
||||
}
|
||||
|
||||
async fn get_machine_after_query() -> (OlmMachine, OneTimeKeys) {
|
||||
@@ -1836,7 +1850,7 @@ pub(crate) mod test {
|
||||
&machine.user_id,
|
||||
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, machine.device_id()),
|
||||
ed25519_key,
|
||||
&mut json!(&mut request.one_time_keys.as_mut().unwrap().values_mut().next()),
|
||||
&mut json!(&mut request.one_time_keys.values_mut().next()),
|
||||
);
|
||||
assert!(ret.is_ok());
|
||||
|
||||
@@ -1852,7 +1866,7 @@ pub(crate) mod test {
|
||||
let mut response = keys_upload_response();
|
||||
response.one_time_key_counts.insert(
|
||||
DeviceKeyAlgorithm::SignedCurve25519,
|
||||
(request.one_time_keys.unwrap().len() as u64).try_into().unwrap(),
|
||||
(request.one_time_keys.len() as u64).try_into().unwrap(),
|
||||
);
|
||||
|
||||
machine.receive_keys_upload_response(&response).await.unwrap();
|
||||
|
||||
@@ -43,7 +43,11 @@ use ruma::{
|
||||
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UInt, UserId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, value::RawValue as RawJsonValue, Value};
|
||||
use serde_json::{
|
||||
json,
|
||||
value::{to_raw_value, RawValue as RawJsonValue},
|
||||
Value,
|
||||
};
|
||||
use sha2::{Digest, Sha256};
|
||||
use tracing::{debug, info, trace, warn};
|
||||
|
||||
@@ -661,14 +665,14 @@ impl ReadOnlyAccount {
|
||||
/// Returns None if no keys need to be uploaded.
|
||||
pub(crate) async fn keys_for_upload(
|
||||
&self,
|
||||
) -> Option<(Option<DeviceKeys>, Option<BTreeMap<Box<DeviceKeyId>, OneTimeKey>>)> {
|
||||
) -> Option<(Option<DeviceKeys>, BTreeMap<Box<DeviceKeyId>, Raw<OneTimeKey>>)> {
|
||||
if !self.should_upload_keys().await {
|
||||
return None;
|
||||
}
|
||||
|
||||
let device_keys = if !self.shared() { Some(self.device_keys().await) } else { None };
|
||||
|
||||
let one_time_keys = self.signed_one_time_keys().await.ok();
|
||||
let one_time_keys = self.signed_one_time_keys().await.ok().unwrap_or_default();
|
||||
|
||||
Some((device_keys, one_time_keys))
|
||||
}
|
||||
@@ -845,15 +849,20 @@ impl ReadOnlyAccount {
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the json value can't be serialized.
|
||||
pub async fn sign_json(&self, json: Value) -> String {
|
||||
pub async fn sign_json(&self, mut json: Value) -> String {
|
||||
let object = json.as_object_mut().expect("Canonical json value isn't an object");
|
||||
object.remove("unsigned");
|
||||
object.remove("signatures");
|
||||
|
||||
let canonical_json: CanonicalJsonValue =
|
||||
json.try_into().expect("Can't canonicalize the json value");
|
||||
|
||||
self.sign(&canonical_json.to_string()).await
|
||||
}
|
||||
|
||||
pub(crate) async fn signed_one_time_keys_helper(
|
||||
&self,
|
||||
) -> Result<BTreeMap<Box<DeviceKeyId>, OneTimeKey>, ()> {
|
||||
) -> Result<BTreeMap<Box<DeviceKeyId>, Raw<OneTimeKey>>, ()> {
|
||||
let one_time_keys = self.one_time_keys().await;
|
||||
let mut one_time_key_map = BTreeMap::new();
|
||||
|
||||
@@ -881,7 +890,10 @@ impl ReadOnlyAccount {
|
||||
DeviceKeyAlgorithm::SignedCurve25519,
|
||||
key_id.as_str().into(),
|
||||
),
|
||||
OneTimeKey::SignedKey(signed_key),
|
||||
Raw::from_json(
|
||||
to_raw_value(&OneTimeKey::SignedKey(signed_key))
|
||||
.expect("Couldn't serialize a new signed key"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -893,7 +905,7 @@ impl ReadOnlyAccount {
|
||||
/// If no one-time keys need to be uploaded returns an empty error.
|
||||
pub(crate) async fn signed_one_time_keys(
|
||||
&self,
|
||||
) -> Result<BTreeMap<Box<DeviceKeyId>, OneTimeKey>, ()> {
|
||||
) -> Result<BTreeMap<Box<DeviceKeyId>, Raw<OneTimeKey>>, ()> {
|
||||
let _ = self.generate_one_time_keys().await?;
|
||||
self.signed_one_time_keys_helper().await
|
||||
}
|
||||
@@ -929,6 +941,7 @@ impl ReadOnlyAccount {
|
||||
inner: Arc::new(Mutex::new(session)),
|
||||
session_id: session_id.into(),
|
||||
sender_key: their_identity_key.into(),
|
||||
created_using_fallback_key: their_one_time_key.fallback,
|
||||
creation_time: Arc::new(now),
|
||||
last_use_time: Arc::new(now),
|
||||
})
|
||||
@@ -948,7 +961,7 @@ impl ReadOnlyAccount {
|
||||
pub(crate) async fn create_outbound_session(
|
||||
&self,
|
||||
device: ReadOnlyDevice,
|
||||
key_map: &BTreeMap<Box<DeviceKeyId>, OneTimeKey>,
|
||||
key_map: &BTreeMap<Box<DeviceKeyId>, Raw<OneTimeKey>>,
|
||||
) -> Result<Session, SessionCreationError> {
|
||||
let one_time_key = key_map.values().next().ok_or_else(|| {
|
||||
SessionCreationError::OneTimeKeyMissing(
|
||||
@@ -957,23 +970,24 @@ impl ReadOnlyAccount {
|
||||
)
|
||||
})?;
|
||||
|
||||
let one_time_key = match one_time_key {
|
||||
OneTimeKey::SignedKey(k) => k,
|
||||
OneTimeKey::Key(_) => {
|
||||
let one_time_key: SignedKey = match one_time_key.deserialize() {
|
||||
Ok(OneTimeKey::SignedKey(k)) => k,
|
||||
Ok(OneTimeKey::Key(_)) => {
|
||||
return Err(SessionCreationError::OneTimeKeyNotSigned(
|
||||
device.user_id().to_owned(),
|
||||
device.device_id().into(),
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
Ok(_) => {
|
||||
return Err(SessionCreationError::OneTimeKeyUnknown(
|
||||
device.user_id().to_owned(),
|
||||
device.device_id().into(),
|
||||
));
|
||||
}
|
||||
Err(e) => return Err(SessionCreationError::InvalidJson(e)),
|
||||
};
|
||||
|
||||
device.verify_one_time_key(one_time_key).map_err(|e| {
|
||||
device.verify_one_time_key(&one_time_key).map_err(|e| {
|
||||
SessionCreationError::InvalidSignature(
|
||||
device.user_id().to_owned(),
|
||||
device.device_id().into(),
|
||||
@@ -988,7 +1002,7 @@ impl ReadOnlyAccount {
|
||||
)
|
||||
})?;
|
||||
|
||||
self.create_outbound_session_helper(curve_key, one_time_key).await.map_err(|e| {
|
||||
self.create_outbound_session_helper(curve_key, &one_time_key).await.map_err(|e| {
|
||||
SessionCreationError::OlmError(
|
||||
device.user_id().to_owned(),
|
||||
device.device_id().into(),
|
||||
@@ -1029,6 +1043,7 @@ impl ReadOnlyAccount {
|
||||
inner: Arc::new(Mutex::new(session)),
|
||||
session_id: session_id.into(),
|
||||
sender_key: their_identity_key.into(),
|
||||
created_using_fallback_key: false,
|
||||
creation_time: Arc::new(now),
|
||||
last_use_time: Arc::new(now),
|
||||
})
|
||||
@@ -1178,15 +1193,19 @@ mod test {
|
||||
let one_time_keys = account
|
||||
.keys_for_upload()
|
||||
.await
|
||||
.and_then(|(_, k)| k)
|
||||
.map(|(_, k)| k)
|
||||
.expect("Initial keys can't be generated");
|
||||
|
||||
assert!(!one_time_keys.is_empty());
|
||||
|
||||
let second_one_time_keys = account
|
||||
.keys_for_upload()
|
||||
.await
|
||||
.and_then(|(_, k)| k)
|
||||
.map(|(_, k)| k)
|
||||
.expect("Second round of one-time keys isn't generated");
|
||||
|
||||
assert!(!second_one_time_keys.is_empty());
|
||||
|
||||
let device_key_ids: BTreeSet<&DeviceKeyId> =
|
||||
one_time_keys.keys().map(Deref::deref).collect();
|
||||
let second_device_key_ids: BTreeSet<&DeviceKeyId> =
|
||||
@@ -1197,16 +1216,16 @@ mod test {
|
||||
account.mark_keys_as_published().await;
|
||||
account.update_uploaded_key_count(50);
|
||||
|
||||
let third_one_time_keys = account.keys_for_upload().await.and_then(|(_, k)| k);
|
||||
let third_one_time_keys = account.keys_for_upload().await.map(|(_, k)| k).unwrap();
|
||||
|
||||
assert!(third_one_time_keys.is_none());
|
||||
assert!(third_one_time_keys.is_empty());
|
||||
|
||||
account.update_uploaded_key_count(0);
|
||||
|
||||
let fourth_one_time_keys = account
|
||||
.keys_for_upload()
|
||||
.await
|
||||
.and_then(|(_, k)| k)
|
||||
.map(|(_, k)| k)
|
||||
.expect("Fourth round of one-time keys isn't generated");
|
||||
|
||||
let fourth_device_key_ids: BTreeSet<&DeviceKeyId> =
|
||||
|
||||
@@ -379,7 +379,7 @@ impl InboundGroupSession {
|
||||
);
|
||||
|
||||
if let Some(decrypted_content) =
|
||||
decrypted_object.get_mut("content").map(|c| c.as_object_mut()).flatten()
|
||||
decrypted_object.get_mut("content").and_then(|c| c.as_object_mut())
|
||||
{
|
||||
if !decrypted_content.contains_key("m.relates_to") {
|
||||
let content = serde_json::to_value(&event.content)?;
|
||||
|
||||
@@ -49,6 +49,7 @@ pub struct Session {
|
||||
pub(crate) inner: Arc<Mutex<OlmSession>>,
|
||||
pub(crate) session_id: Arc<str>,
|
||||
pub(crate) sender_key: Arc<str>,
|
||||
pub(crate) created_using_fallback_key: bool,
|
||||
pub(crate) creation_time: Arc<Instant>,
|
||||
pub(crate) last_use_time: Arc<Instant>,
|
||||
}
|
||||
@@ -183,6 +184,7 @@ impl Session {
|
||||
PickledSession {
|
||||
pickle: SessionPickle::from(pickle),
|
||||
sender_key: self.sender_key.to_string(),
|
||||
created_using_fallback_key: self.created_using_fallback_key,
|
||||
creation_time: *self.creation_time,
|
||||
last_use_time: *self.last_use_time,
|
||||
}
|
||||
@@ -221,6 +223,7 @@ impl Session {
|
||||
our_identity_keys,
|
||||
inner: Arc::new(Mutex::new(session)),
|
||||
session_id: session_id.into(),
|
||||
created_using_fallback_key: pickle.created_using_fallback_key,
|
||||
sender_key: pickle.sender_key.into(),
|
||||
creation_time: Arc::new(pickle.creation_time),
|
||||
last_use_time: Arc::new(pickle.last_use_time),
|
||||
@@ -244,6 +247,9 @@ pub struct PickledSession {
|
||||
pub pickle: SessionPickle,
|
||||
/// The curve25519 key of the other user that we share this session with.
|
||||
pub sender_key: String,
|
||||
/// Was the session created using a fallback key.
|
||||
#[serde(default)]
|
||||
pub created_using_fallback_key: bool,
|
||||
/// The relative time elapsed since the session was created.
|
||||
#[serde(deserialize_with = "deserialize_instant", serialize_with = "serialize_instant")]
|
||||
pub creation_time: Instant,
|
||||
|
||||
@@ -477,11 +477,10 @@ impl GroupSessionManager {
|
||||
|
||||
let devices: Vec<Device> = devices
|
||||
.into_iter()
|
||||
.map(|(_, d)| {
|
||||
.flat_map(|(_, d)| {
|
||||
d.into_iter()
|
||||
.filter(|d| matches!(outbound.is_shared_with(d), ShareState::NotShared))
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let key_content = outbound.as_content().await;
|
||||
|
||||
@@ -124,7 +124,7 @@ impl SessionManager {
|
||||
///
|
||||
/// If the device was wedged this will queue up a dummy to-device message.
|
||||
async fn check_if_unwedged(&self, user_id: &UserId, device_id: &DeviceId) -> OlmResult<()> {
|
||||
if self.wedged_devices.get(user_id).map(|d| d.remove(device_id)).flatten().is_some() {
|
||||
if self.wedged_devices.get(user_id).and_then(|d| d.remove(device_id)).is_some() {
|
||||
if let Some(device) = self.store.get_device(user_id, device_id).await? {
|
||||
let content = AnyToDeviceEventContent::Dummy(ToDeviceDummyEventContent::new());
|
||||
let (_, content) = device.encrypt(content).await?;
|
||||
@@ -298,9 +298,6 @@ impl SessionManager {
|
||||
}
|
||||
};
|
||||
|
||||
changes.sessions.push(session);
|
||||
new_sessions.entry(user_id).or_default().insert(device_id);
|
||||
|
||||
self.key_request_machine.retry_keyshare(user_id, device_id);
|
||||
|
||||
if let Err(e) = self.check_if_unwedged(user_id, device_id).await {
|
||||
@@ -309,6 +306,9 @@ impl SessionManager {
|
||||
user_id, device_id, e
|
||||
);
|
||||
}
|
||||
|
||||
changes.sessions.push(session);
|
||||
new_sessions.entry(user_id).or_default().insert(device_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -347,8 +347,8 @@ impl Store {
|
||||
let devices = self.inner.get_user_devices(user_id).await?;
|
||||
|
||||
let own_identity =
|
||||
self.inner.get_user_identity(&self.user_id).await?.map(|i| i.own().cloned()).flatten();
|
||||
let device_owner_identity = self.inner.get_user_identity(user_id).await.ok().flatten();
|
||||
self.inner.get_user_identity(&self.user_id).await?.and_then(|i| i.own().cloned());
|
||||
let device_owner_identity = self.inner.get_user_identity(user_id).await?;
|
||||
|
||||
Ok(UserDevices {
|
||||
inner: devices,
|
||||
@@ -364,7 +364,7 @@ impl Store {
|
||||
device_id: &DeviceId,
|
||||
) -> Result<Option<Device>> {
|
||||
let own_identity =
|
||||
self.inner.get_user_identity(&self.user_id).await?.map(|i| i.own().cloned()).flatten();
|
||||
self.inner.get_user_identity(&self.user_id).await?.and_then(|i| i.own().cloned());
|
||||
let device_owner_identity = self.inner.get_user_identity(user_id).await?;
|
||||
|
||||
Ok(self.inner.get_device(user_id, device_id).await?.map(|d| Device {
|
||||
|
||||
@@ -18,6 +18,10 @@ appservice = []
|
||||
http = "0.2.4"
|
||||
lazy_static = "1.4.0"
|
||||
matrix-sdk-test-macros = { version = "0.1.0", path = "../matrix-sdk-test-macros" }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "6c4892664", features = ["client-api-c"] }
|
||||
serde = "1.0.126"
|
||||
serde_json = "1.0.64"
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma/"
|
||||
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
|
||||
features = ["client-api-c"]
|
||||
|
||||
@@ -75,8 +75,8 @@ version = "0.11.3"
|
||||
default_features = false
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma"
|
||||
rev = "6c4892664"
|
||||
git = "https://github.com/ruma/ruma/"
|
||||
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
|
||||
features = ["client-api-c", "compat", "unstable-pre-spec"]
|
||||
|
||||
[dependencies.tokio-stream]
|
||||
|
||||
@@ -526,15 +526,21 @@ impl Client {
|
||||
/// # anyhow::Result::<()>::Ok(()) });
|
||||
#[cfg(feature = "encryption")]
|
||||
pub async fn bootstrap_cross_signing(&self, auth_data: Option<AuthData<'_>>) -> Result<()> {
|
||||
use serde_json::value::to_raw_value;
|
||||
|
||||
let olm = self.olm_machine().await.ok_or(Error::AuthenticationRequired)?;
|
||||
|
||||
let (request, signature_request) = olm.bootstrap_cross_signing(false).await?;
|
||||
|
||||
let to_raw = |k| {
|
||||
Raw::from_json(to_raw_value(&k).expect("Can't serialize newly created cross signing keys"))
|
||||
};
|
||||
|
||||
let request = assign!(UploadSigningKeysRequest::new(), {
|
||||
auth: auth_data,
|
||||
master_key: request.master_key,
|
||||
self_signing_key: request.self_signing_key,
|
||||
user_signing_key: request.user_signing_key,
|
||||
master_key: request.master_key.map(to_raw),
|
||||
self_signing_key: request.self_signing_key.map(to_raw),
|
||||
user_signing_key: request.user_signing_key.map(to_raw),
|
||||
});
|
||||
|
||||
self.send(request, None).await?;
|
||||
@@ -887,9 +893,9 @@ impl Client {
|
||||
request: &upload_keys::Request,
|
||||
) -> Result<upload_keys::Response> {
|
||||
debug!(
|
||||
"Uploading encryption keys device keys: {}, one-time-keys: {}",
|
||||
request.device_keys.is_some(),
|
||||
request.one_time_keys.as_ref().map_or(0, |k| k.len())
|
||||
device_keys = request.device_keys.is_some(),
|
||||
one_time_key_count = request.one_time_keys.len(),
|
||||
"Uploading public encryption keys",
|
||||
);
|
||||
|
||||
let response = self.send(request.clone(), None).await?;
|
||||
|
||||
Reference in New Issue
Block a user