feat: /devices route

next
Timo Kösters 2021-04-21 10:51:34 +02:00
parent e815486030
commit 71ed1b295a
No known key found for this signature in database
GPG Key ID: 24DA7517711A2BA4
4 changed files with 66 additions and 0 deletions

View File

@ -123,6 +123,7 @@ impl Database {
userid_avatarurl: db.open_tree("userid_avatarurl")?, userid_avatarurl: db.open_tree("userid_avatarurl")?,
userdeviceid_token: db.open_tree("userdeviceid_token")?, userdeviceid_token: db.open_tree("userdeviceid_token")?,
userdeviceid_metadata: db.open_tree("userdeviceid_metadata")?, userdeviceid_metadata: db.open_tree("userdeviceid_metadata")?,
userid_devicelistversion: db.open_tree("userid_devicelistversion")?,
token_userdeviceid: db.open_tree("token_userdeviceid")?, token_userdeviceid: db.open_tree("token_userdeviceid")?,
onetimekeyid_onetimekeys: db.open_tree("onetimekeyid_onetimekeys")?, onetimekeyid_onetimekeys: db.open_tree("onetimekeyid_onetimekeys")?,
userid_lastonetimekeyupdate: db.open_tree("userid_lastonetimekeyupdate")?, userid_lastonetimekeyupdate: db.open_tree("userid_lastonetimekeyupdate")?,

View File

@ -22,6 +22,7 @@ pub struct Users {
pub(super) userid_avatarurl: sled::Tree, pub(super) userid_avatarurl: sled::Tree,
pub(super) userdeviceid_token: sled::Tree, pub(super) userdeviceid_token: sled::Tree,
pub(super) userdeviceid_metadata: sled::Tree, // This is also used to check if a device exists pub(super) userdeviceid_metadata: sled::Tree, // This is also used to check if a device exists
pub(super) userid_devicelistversion: sled::Tree, // DevicelistVersion = u64
pub(super) token_userdeviceid: sled::Tree, pub(super) token_userdeviceid: sled::Tree,
pub(super) onetimekeyid_onetimekeys: sled::Tree, // OneTimeKeyId = UserId + DeviceKeyId pub(super) onetimekeyid_onetimekeys: sled::Tree, // OneTimeKeyId = UserId + DeviceKeyId
@ -189,6 +190,10 @@ impl Users {
userdeviceid.push(0xff); userdeviceid.push(0xff);
userdeviceid.extend_from_slice(device_id.as_bytes()); userdeviceid.extend_from_slice(device_id.as_bytes());
self.userid_devicelistversion
.update_and_fetch(&user_id.as_bytes(), utils::increment)?
.expect("utils::increment will always put in a value");
self.userdeviceid_metadata.insert( self.userdeviceid_metadata.insert(
userdeviceid, userdeviceid,
serde_json::to_string(&Device { serde_json::to_string(&Device {
@ -227,6 +232,10 @@ impl Users {
// TODO: Remove onetimekeys // TODO: Remove onetimekeys
self.userid_devicelistversion
.update_and_fetch(&user_id.as_bytes(), utils::increment)?
.expect("utils::increment will always put in a value");
self.userdeviceid_metadata.remove(&userdeviceid)?; self.userdeviceid_metadata.remove(&userdeviceid)?;
Ok(()) Ok(())
@ -811,6 +820,10 @@ impl Users {
// Only existing devices should be able to call this. // Only existing devices should be able to call this.
assert!(self.userdeviceid_metadata.get(&userdeviceid)?.is_some()); assert!(self.userdeviceid_metadata.get(&userdeviceid)?.is_some());
self.userid_devicelistversion
.update_and_fetch(&user_id.as_bytes(), utils::increment)?
.expect("utils::increment will always put in a value");
self.userdeviceid_metadata.insert( self.userdeviceid_metadata.insert(
userdeviceid, userdeviceid,
serde_json::to_string(device) serde_json::to_string(device)
@ -840,6 +853,16 @@ impl Users {
}) })
} }
pub fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>> {
self.userid_devicelistversion
.get(user_id.as_bytes())?
.map_or(Ok(None), |bytes| {
utils::u64_from_bytes(&bytes)
.map_err(|_| Error::bad_database("Invalid devicelistversion in db."))
.map(Some)
})
}
pub fn all_devices_metadata(&self, user_id: &UserId) -> impl Iterator<Item = Result<Device>> { pub fn all_devices_metadata(&self, user_id: &UserId) -> impl Iterator<Item = Result<Device>> {
let mut key = user_id.as_bytes().to_vec(); let mut key = user_id.as_bytes().to_vec();
key.push(0xff); key.push(0xff);

View File

@ -171,6 +171,7 @@ fn setup_rocket() -> (rocket::Rocket, Config) {
server_server::create_join_event_template_route, server_server::create_join_event_template_route,
server_server::create_join_event_route, server_server::create_join_event_route,
server_server::create_invite_route, server_server::create_invite_route,
server_server::get_devices_route,
server_server::get_room_information_route, server_server::get_room_information_route,
server_server::get_profile_information_route, server_server::get_profile_information_route,
], ],

View File

@ -8,6 +8,7 @@ use ruma::{
api::{ api::{
client::error::ErrorKind, client::error::ErrorKind,
federation::{ federation::{
device::get_devices::{self, v1::UserDevice},
directory::{get_public_rooms, get_public_rooms_filtered}, directory::{get_public_rooms, get_public_rooms_filtered},
discovery::{ discovery::{
get_remote_server_keys, get_server_keys, get_server_version, ServerSigningKeys, get_remote_server_keys, get_server_keys, get_server_version, ServerSigningKeys,
@ -1979,6 +1980,46 @@ pub async fn create_invite_route<'a>(
.into()) .into())
} }
#[cfg_attr(
feature = "conduit_bin",
get("/_matrix/federation/v1/user/devices/<_>", data = "<body>")
)]
#[tracing::instrument(skip(db, body))]
pub fn get_devices_route<'a>(
db: State<'a, Database>,
body: Ruma<get_devices::v1::Request<'_>>,
) -> ConduitResult<get_devices::v1::Response> {
if !db.globals.allow_federation() {
return Err(Error::bad_config("Federation is disabled."));
}
Ok(get_devices::v1::Response {
user_id: body.user_id.clone(),
stream_id: db
.users
.get_devicelist_version(&body.user_id)?
.unwrap_or(0)
.try_into()
.expect("version will not grow that large"),
devices: db
.users
.all_devices_metadata(&body.user_id)
.filter_map(|r| r.ok())
.filter_map(|metadata| {
Some(UserDevice {
keys: db
.users
.get_device_keys(&body.user_id, &metadata.device_id)
.ok()??,
device_id: metadata.device_id,
device_display_name: metadata.display_name,
})
})
.collect(),
}
.into())
}
#[cfg_attr( #[cfg_attr(
feature = "conduit_bin", feature = "conduit_bin",
get("/_matrix/federation/v1/query/directory", data = "<body>") get("/_matrix/federation/v1/query/directory", data = "<body>")