From ce460ea15964ff8bd438b5022c9dbb35781b594b Mon Sep 17 00:00:00 2001 From: timokoesters Date: Thu, 30 Jul 2020 14:05:08 +0200 Subject: [PATCH] fix: send device list updates when user is in no rooms --- src/client_server.rs | 52 ++++++++++++++++++++++++++++++++++--------- src/database.rs | 20 ++++++++++++++--- src/database/users.rs | 27 +++++++++++++++++----- 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/client_server.rs b/src/client_server.rs index 16bf73d5..46791f77 100644 --- a/src/client_server.rs +++ b/src/client_server.rs @@ -672,7 +672,11 @@ pub fn set_displayname_route( displayname: body.displayname.clone(), ..serde_json::from_value::>( db.rooms - .room_state_get(&room_id, &EventType::RoomMember, &sender_id.to_string())? + .room_state_get( + &room_id, + &EventType::RoomMember, + &sender_id.to_string(), + )? .ok_or_else(|| { Error::bad_database( "Tried to send displayname update for user not in the room.", @@ -770,7 +774,11 @@ pub fn set_avatar_url_route( avatar_url: body.avatar_url.clone(), ..serde_json::from_value::>( db.rooms - .room_state_get(&room_id, &EventType::RoomMember, &sender_id.to_string())? + .room_state_get( + &room_id, + &EventType::RoomMember, + &sender_id.to_string(), + )? .ok_or_else(|| { Error::bad_database( "Tried to send avatar url update for user not in the room.", @@ -1884,12 +1892,11 @@ pub fn ban_user_route( third_party_invite: None, }), |event| { - let mut event = serde_json::from_value::>( - event.content, - ) - .expect("Raw::from_value always works") - .deserialize() - .map_err(|_| Error::bad_database("Invalid member event in database."))?; + let mut event = + serde_json::from_value::>(event.content) + .expect("Raw::from_value always works") + .deserialize() + .map_err(|_| Error::bad_database("Invalid member event in database."))?; event.membership = ruma::events::room::member::MembershipState::Ban; Ok(event) }, @@ -2211,6 +2218,7 @@ pub async fn get_public_rooms_filtered_route( Ok::<_, Error>(chunk) }) .filter_map(|r| r.ok()) // Filter out buggy rooms + // We need to collect all, so we can sort by member count .collect::>(); chunk.sort_by(|l, r| r.num_joined_members.cmp(&l.num_joined_members)); @@ -2618,6 +2626,13 @@ pub async fn sync_events_route( let mut presence_updates = HashMap::new(); let mut device_list_updates = HashSet::new(); + // Look for device list updates of this account + device_list_updates.extend( + db.users + .keys_changed(&sender_id.to_string(), since, None) + .filter_map(|r| r.ok()), + ); + for room_id in db.rooms.rooms_joined(&sender_id) { let room_id = room_id?; @@ -2869,7 +2884,7 @@ pub async fn sync_events_route( // Look for device list updates in this room device_list_updates.extend( db.users - .keys_changed(&room_id, since, None) + .keys_changed(&room_id.to_string(), since, None) .filter_map(|r| r.ok()), ); @@ -3652,11 +3667,28 @@ pub fn get_key_changes_route( let sender_id = body.sender_id.as_ref().expect("user is authenticated"); let mut device_list_updates = HashSet::new(); + + device_list_updates.extend( + db.users + .keys_changed( + &sender_id.to_string(), + body.from + .parse() + .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from`."))?, + Some( + body.to + .parse() + .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `to`."))?, + ), + ) + .filter_map(|r| r.ok()), + ); + for room_id in db.rooms.rooms_joined(sender_id).filter_map(|r| r.ok()) { device_list_updates.extend( db.users .keys_changed( - &room_id, + &room_id.to_string(), body.from.parse().map_err(|_| { Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from`.") })?, diff --git a/src/database.rs b/src/database.rs index 47876695..844a1f47 100644 --- a/src/database.rs +++ b/src/database.rs @@ -126,16 +126,17 @@ impl Database { } pub async fn watch(&self, user_id: &UserId, device_id: &DeviceId) { - let mut userid_prefix = user_id.to_string().as_bytes().to_vec(); + let userid_bytes = user_id.to_string().as_bytes().to_vec(); + + let mut userid_prefix = userid_bytes.clone(); userid_prefix.push(0xff); + let mut userdeviceid_prefix = userid_prefix.clone(); userdeviceid_prefix.extend_from_slice(device_id.as_bytes()); userdeviceid_prefix.push(0xff); let mut futures = futures::stream::FuturesUnordered::new(); - futures.push(self.users.keychangeid_userid.watch_prefix(b"")); - // Return when *any* user changed his key // TODO: only send for user they share a room with futures.push( @@ -171,6 +172,9 @@ impl Database { .watch_prefix(&roomid_prefix), ); + // Key changes + futures.push(self.users.keychangeid_userid.watch_prefix(&roomid_prefix)); + // Room account data let mut roomuser_prefix = roomid_prefix.clone(); roomuser_prefix.extend_from_slice(&userid_prefix); @@ -191,6 +195,16 @@ impl Database { .watch_prefix(&globaluserdata_prefix), ); + // More key changes (used when user is not joined to any rooms) + futures.push(self.users.keychangeid_userid.watch_prefix(&userid_prefix)); + + // One time keys + futures.push( + self.users + .userid_lastonetimekeyupdate + .watch_prefix(&userid_bytes), + ); + // Wait until one of them finds something futures.next().await; } diff --git a/src/database/users.rs b/src/database/users.rs index 1ec677ca..f031534a 100644 --- a/src/database/users.rs +++ b/src/database/users.rs @@ -9,7 +9,7 @@ use ruma::{ }, }, events::{AnyToDeviceEvent, EventType}, - DeviceId, Raw, RoomId, UserId, + DeviceId, Raw, UserId, }; use std::{collections::BTreeMap, convert::TryFrom, mem, time::SystemTime}; @@ -23,7 +23,7 @@ pub struct Users { pub(super) onetimekeyid_onetimekeys: sled::Tree, // OneTimeKeyId = UserId + AlgorithmAndDeviceId pub(super) userid_lastonetimekeyupdate: sled::Tree, // LastOneTimeKeyUpdate = Count - pub(super) keychangeid_userid: sled::Tree, // KeyChangeId = RoomId + Count + pub(super) keychangeid_userid: sled::Tree, // KeyChangeId = UserId/RoomId + Count pub(super) keyid_key: sled::Tree, // KeyId = UserId + KeyId (depends on key type) pub(super) userid_masterkeyid: sled::Tree, pub(super) userid_selfsigningkeyid: sled::Tree, @@ -305,8 +305,7 @@ impl Users { } pub fn last_one_time_keys_update(&self, user_id: &UserId) -> Result { - self - .userid_lastonetimekeyupdate + self.userid_lastonetimekeyupdate .get(&user_id.to_string().as_bytes())? .map(|bytes| { utils::u64_from_bytes(&bytes).map_err(|_| { @@ -417,6 +416,11 @@ impl Users { self.keychangeid_userid.insert(key, &*user_id.to_string())?; } + let mut key = user_id.to_string().as_bytes().to_vec(); + key.push(0xff); + key.extend_from_slice(&count); + self.keychangeid_userid.insert(key, &*user_id.to_string())?; + Ok(()) } @@ -524,6 +528,11 @@ impl Users { self.keychangeid_userid.insert(key, &*user_id.to_string())?; } + let mut key = user_id.to_string().as_bytes().to_vec(); + key.push(0xff); + key.extend_from_slice(&count); + self.keychangeid_userid.insert(key, &*user_id.to_string())?; + Ok(()) } @@ -576,16 +585,22 @@ impl Users { .insert(key, &*target_id.to_string())?; } + let mut key = target_id.to_string().as_bytes().to_vec(); + key.push(0xff); + key.extend_from_slice(&count); + self.keychangeid_userid + .insert(key, &*target_id.to_string())?; + Ok(()) } pub fn keys_changed( &self, - room_id: &RoomId, + user_or_room_id: &str, from: u64, to: Option, ) -> impl Iterator> { - let mut prefix = room_id.to_string().as_bytes().to_vec(); + let mut prefix = user_or_room_id.as_bytes().to_vec(); prefix.push(0xff); let mut start = prefix.clone();