use std::time::Duration; use axum::extract::State; use conduwuit::{Err, Result}; use futures::{FutureExt, StreamExt, TryFutureExt}; use ruma::{ api::federation::{ device::get_devices::{self, v1::UserDevice}, keys::{claim_keys, get_keys}, }, assign, }; use crate::{ Ruma, client::{claim_keys_helper, get_keys_helper}, }; /// # `GET /_matrix/federation/v1/user/devices/{userId}` /// /// Gets information on all devices of the user. pub(crate) async fn get_devices_route( State(services): State, body: Ruma, ) -> Result { if !services.globals.user_is_local(&body.user_id) { return Err!(Request(InvalidParam("Tried to access user from other server."))); } let stream_id = services .users .get_devicelist_version(&body.user_id) .await .unwrap_or(0) .try_into() .expect("device list version should fit into a UInt"); let devices = services .users .all_devices_metadata(&body.user_id) .filter_map(async |metadata| { let device_id = metadata.device_id.clone(); let device_id_clone = device_id.clone(); let device_id_string = device_id.as_str().to_owned(); let device_display_name = if services.globals.allow_device_name_federation() { metadata.display_name.clone() } else { Some(device_id_string) }; services .users .get_device_keys(&body.user_id, &device_id_clone) .map_ok(|keys| assign!(UserDevice::new(device_id, keys), { device_display_name })) .map(Result::ok) .await }) .collect() .await; let master_key = services .users .get_master_key(None, &body.user_id, &|u| u.server_name() == body.identity) .await .ok(); let self_signing_key = services .users .get_self_signing_key(None, &body.user_id, &|u| u.server_name() == body.identity) .await .ok(); Ok(assign!(get_devices::v1::Response::new(body.user_id.clone(), stream_id), { devices, master_key, self_signing_key })) } /// # `POST /_matrix/federation/v1/user/keys/query` /// /// Gets devices and identity keys for the given users. pub(crate) async fn get_keys_route( State(services): State, body: Ruma, ) -> Result { if body .device_keys .iter() .any(|(u, _)| !services.globals.user_is_local(u)) { return Err!(Request(InvalidParam("User does not belong to this server."))); } let result = get_keys_helper( &services, None, &body.device_keys, |u| u.server_name() == body.identity, services.globals.allow_device_name_federation(), Duration::from_secs(0), ) .await?; Ok(assign!(get_keys::v1::Response::new(result.device_keys), { master_keys: result.master_keys, self_signing_keys: result.self_signing_keys, })) } /// # `POST /_matrix/federation/v1/user/keys/claim` /// /// Claims one-time keys. pub(crate) async fn claim_keys_route( State(services): State, body: Ruma, ) -> Result { if body .one_time_keys .iter() .any(|(u, _)| !services.globals.user_is_local(u)) { return Err!(Request(InvalidParam("Tried to access user from other server."))); } let result = claim_keys_helper(&services, &body.one_time_keys, Duration::from_secs(0)).await?; Ok(claim_keys::v1::Response::new(result.one_time_keys)) }