diff --git a/matrix_sdk/examples/get_profiles.rs b/matrix_sdk/examples/get_profiles.rs index 46324875..8aea2206 100644 --- a/matrix_sdk/examples/get_profiles.rs +++ b/matrix_sdk/examples/get_profiles.rs @@ -15,12 +15,10 @@ struct UserProfile { /// This function calls the GET profile endpoint /// Spec: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-profile-userid /// Ruma: https://docs.rs/ruma-client-api/0.9.0/ruma_client_api/r0/profile/get_profile/index.html -async fn get_profile(client: Client, mxid: UserId) -> MatrixResult { +async fn get_profile(client: Client, mxid: &UserId) -> MatrixResult { // First construct the request you want to make // See https://docs.rs/ruma-client-api/0.9.0/ruma_client_api/index.html for all available Endpoints - let request = profile::get_profile::Request { - user_id: mxid.clone(), - }; + let request = profile::get_profile::Request::new(mxid); // Start the request using matrix_sdk::Client::send let resp = client.send(request).await?; @@ -72,7 +70,7 @@ async fn main() -> Result<(), matrix_sdk::Error> { let client = login(homeserver_url, &username, &password).await?; let user_id = UserId::try_from(username).expect("Couldn't parse the MXID"); - let profile = get_profile(client, user_id).await?; + let profile = get_profile(client, &user_id).await?; println!("{:#?}", profile); Ok(()) } diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index 7e593a16..632da862 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(feature = "encryption")] +use std::{collections::BTreeMap, io::Write, path::PathBuf}; use std::{ collections::HashMap, convert::{TryFrom, TryInto}, @@ -23,8 +25,6 @@ use std::{ result::Result as StdResult, sync::Arc, }; -#[cfg(feature = "encryption")] -use std::{io::Write, path::PathBuf}; #[cfg(feature = "encryption")] use dashmap::DashMap; @@ -85,6 +85,7 @@ use matrix_sdk_common::{ Request as RumaToDeviceRequest, Response as ToDeviceResponse, }, }, + identifiers::DeviceIdBox, locks::Mutex, }; @@ -496,12 +497,15 @@ impl Client { ) -> Result { info!("Logging in to {} as {:?}", self.homeserver, user); - let request = login::Request { - user: login::UserInfo::MatrixId(user), - login_info: login::LoginInfo::Password { password }, - device_id: device_id.map(|d| d.into()), - initial_device_display_name, - }; + let request = assign!( + login::Request::new( + login::UserInfo::MatrixId(user), + login::LoginInfo::Password { password }, + ), { + device_id: device_id.map(|d| d.into()), + initial_device_display_name, + } + ); let response = self.send(request).await?; self.base_client.receive_login_response(&response).await?; @@ -741,11 +745,11 @@ impl Client { ) -> Result { let limit = limit.map(|n| UInt::try_from(n).ok()).flatten(); - let request = get_public_rooms::Request { + let request = assign!(get_public_rooms::Request::new(), { limit, since, server, - }; + }); self.send(request).await } @@ -896,11 +900,8 @@ impl Client { room_id: &RoomId, typing: impl Into, ) -> Result { - let request = TypingRequest { - room_id: room_id.clone(), - user_id: self.user_id().await.ok_or(Error::AuthenticationRequired)?, - state: typing.into(), - }; + let user_id = self.user_id().await.ok_or(Error::AuthenticationRequired)?; + let request = TypingRequest::new(&user_id, room_id, typing.into()); self.send(request).await } @@ -919,11 +920,8 @@ impl Client { room_id: &RoomId, event_id: &EventId, ) -> Result { - let request = create_receipt::Request { - room_id: room_id.clone(), - event_id: event_id.clone(), - receipt_type: create_receipt::ReceiptType::Read, - }; + let request = + create_receipt::Request::new(room_id, create_receipt::ReceiptType::Read, event_id); self.send(request).await } @@ -1116,9 +1114,7 @@ impl Client { encryptor.read_to_end(&mut data).unwrap(); let keys = encryptor.finish(); - let upload = self - .upload("application/octet-stream".to_owned(), data, None) - .await?; + let upload = self.upload("application/octet-stream", data).await?; let content = EncryptedFile { url: upload.content_uri, @@ -1143,9 +1139,7 @@ impl Client { let mut data = Vec::new(); reader.read_to_end(&mut data).unwrap(); - let upload = self - .upload("application/octet-stream".to_owned(), data, None) - .await?; + let upload = self.upload("application/octet-stream", data).await?; let content = AnyMessageEventContent::RoomMessage(MessageEventContent::File( FileMessageEventContent { @@ -1160,17 +1154,8 @@ impl Client { self.room_send(room_id, content, txn_id).await } - async fn upload( - &self, - content_type: String, - data: Vec, - filename: Option, - ) -> Result { - let request = create_content::Request { - content_type, - file: data, - filename, - }; + async fn upload(&self, content_type: &str, data: Vec) -> Result { + let request = create_content::Request::new(content_type, data); self.send(request).await } @@ -1202,9 +1187,8 @@ impl Client { /// // First construct the request you want to make /// // See https://docs.rs/ruma-client-api/latest/ruma_client_api/index.html /// // for all available Endpoints - /// let request = profile::get_profile::Request { - /// user_id: user_id!("@example:localhost"), - /// }; + /// let user_id = user_id!("@example:localhost"); + /// let request = profile::get_profile::Request::new(&user_id); /// /// // Start the request using Client::send() /// let response = client.send(request).await.unwrap(); @@ -1224,11 +1208,8 @@ impl Client { #[cfg(feature = "encryption")] async fn send_to_device(&self, request: ToDeviceRequest) -> Result { let txn_id_string = request.txn_id_string(); - let request = RumaToDeviceRequest { - event_type: request.event_type, - txn_id: &txn_id_string, - messages: request.messages, - }; + let request = + RumaToDeviceRequest::new(request.event_type, &txn_id_string, request.messages); self.send(request).await } @@ -1257,7 +1238,7 @@ impl Client { /// # }); /// ``` pub async fn devices(&self) -> Result { - let request = get_devices::Request {}; + let request = get_devices::Request::new(); self.send(request).await } @@ -1377,7 +1358,10 @@ impl Client { for r in self.base_client.outgoing_requests().await { match r.request() { OutgoingRequests::KeysQuery(request) => { - if let Err(e) = self.keys_query(r.request_id(), request).await { + if let Err(e) = self + .keys_query(r.request_id(), request.device_keys.clone()) + .await + { warn!("Error while querying device keys {:?}", e); } } @@ -1524,13 +1508,9 @@ impl Client { async fn keys_query( &self, request_id: &Uuid, - request: &get_keys::IncomingRequest, + device_keys: BTreeMap>, ) -> Result { - let request = get_keys::Request { - timeout: None, - device_keys: request.device_keys.clone(), - token: None, - }; + let request = assign!(get_keys::Request::new(), { device_keys }); let response = self.send(request).await?; self.base_client diff --git a/matrix_sdk/src/device.rs b/matrix_sdk/src/device.rs index 03ca9c44..c9c14e44 100644 --- a/matrix_sdk/src/device.rs +++ b/matrix_sdk/src/device.rs @@ -62,11 +62,8 @@ impl Device { /// ``` pub async fn start_verification(&self) -> Result { let (sas, request) = self.inner.start_verification().await?; - let request = ToDeviceRequest { - event_type: request.event_type, - txn_id: &request.txn_id.to_string(), - messages: request.messages, - }; + let txn_id_string = request.txn_id_string(); + let request = ToDeviceRequest::new(request.event_type, &txn_id_string, request.messages); self.http_client.send(request).await?; diff --git a/matrix_sdk/src/sas.rs b/matrix_sdk/src/sas.rs index 975548ce..4f885f70 100644 --- a/matrix_sdk/src/sas.rs +++ b/matrix_sdk/src/sas.rs @@ -28,11 +28,8 @@ impl Sas { /// Accept the interactive verification flow. pub async fn accept(&self) -> Result<()> { if let Some(req) = self.inner.accept() { - let request = ToDeviceRequest { - event_type: req.event_type, - txn_id: &req.txn_id.to_string(), - messages: req.messages, - }; + let txn_id_string = req.txn_id_string(); + let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages); self.http_client.send(request).await?; } @@ -42,11 +39,8 @@ impl Sas { /// Confirm that the short auth strings match on both sides. pub async fn confirm(&self) -> Result<()> { if let Some(req) = self.inner.confirm().await? { - let request = ToDeviceRequest { - event_type: req.event_type, - txn_id: &req.txn_id.to_string(), - messages: req.messages, - }; + let txn_id_string = req.txn_id_string(); + let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages); self.http_client.send(request).await?; } @@ -57,11 +51,8 @@ impl Sas { /// Cancel the interactive verification flow. pub async fn cancel(&self) -> Result<()> { if let Some(req) = self.inner.cancel() { - let request = ToDeviceRequest { - event_type: req.event_type, - txn_id: &req.txn_id.to_string(), - messages: req.messages, - }; + let txn_id_string = req.txn_id_string(); + let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages); self.http_client.send(request).await?; } diff --git a/matrix_sdk_common/Cargo.toml b/matrix_sdk_common/Cargo.toml index 84f48454..e6bf1e3c 100644 --- a/matrix_sdk_common/Cargo.toml +++ b/matrix_sdk_common/Cargo.toml @@ -18,7 +18,7 @@ js_int = "0.1.9" [dependencies.ruma] version = "0.0.1" git = "https://github.com/ruma/ruma" -rev = "409fbcc9d745fb7290327cb7f5defc714229ab30" +rev = "4a9b1aeb3c87bd8574391d7084ec5bf109f7d363" features = ["client-api", "unstable-pre-spec"] [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/matrix_sdk_crypto/src/lib.rs b/matrix_sdk_crypto/src/lib.rs index f4cf7634..25265b73 100644 --- a/matrix_sdk_crypto/src/lib.rs +++ b/matrix_sdk_crypto/src/lib.rs @@ -44,5 +44,7 @@ pub use identities::{ pub use machine::OlmMachine; pub(crate) use olm::Account; pub use olm::EncryptionSettings; -pub use requests::{IncomingResponse, OutgoingRequest, OutgoingRequests, ToDeviceRequest}; +pub use requests::{ + IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, ToDeviceRequest, +}; pub use verification::Sas; diff --git a/matrix_sdk_crypto/src/machine.rs b/matrix_sdk_crypto/src/machine.rs index 3fe74fd8..39f19393 100644 --- a/matrix_sdk_crypto/src/machine.rs +++ b/matrix_sdk_crypto/src/machine.rs @@ -30,12 +30,13 @@ use matrix_sdk_common::{ api::r0::{ keys::{ claim_keys::{Request as KeysClaimRequest, Response as KeysClaimResponse}, - get_keys::{IncomingRequest as KeysQueryRequest, Response as KeysQueryResponse}, + get_keys::Response as KeysQueryResponse, upload_keys, }, sync::sync_events::Response as SyncResponse, to_device::DeviceIdOrAllDevices, }, + assign, encryption::DeviceKeys, events::{ forwarded_room_key::ForwardedRoomKeyEventContent, room::encrypted::EncryptedEventContent, @@ -60,7 +61,7 @@ use super::{ Account, EncryptionSettings, ExportedRoomKey, GroupSessionKey, IdentityKeys, InboundGroupSession, OlmMessage, OutboundGroupSession, }, - requests::{IncomingResponse, OutgoingRequest, ToDeviceRequest}, + requests::{IncomingResponse, KeysQueryRequest, OutgoingRequest, ToDeviceRequest}, store::{CryptoStore, MemoryStore, Result as StoreResult}, verification::{Sas, VerificationMachine}, }; @@ -415,10 +416,9 @@ impl OlmMachine { } else { Ok(Some(( Uuid::new_v4(), - KeysClaimRequest { + assign!(KeysClaimRequest::new(missing), { timeout: Some(OlmMachine::KEY_CLAIM_TIMEOUT), - one_time_keys: missing, - }, + }), ))) } } @@ -700,11 +700,7 @@ impl OlmMachine { /// [`OlmMachine`]: struct.OlmMachine.html async fn keys_for_upload(&self) -> Option { let (device_keys, one_time_keys) = self.account.keys_for_upload().await?; - - Some(upload_keys::Request { - device_keys, - one_time_keys, - }) + Some(assign!(upload_keys::Request::new(), { device_keys, one_time_keys })) } /// Try to decrypt an Olm message. @@ -1428,11 +1424,7 @@ impl OlmMachine { device_keys.insert(user, Vec::new()); } - Some(KeysQueryRequest { - timeout: None, - device_keys, - token: None, - }) + Some(KeysQueryRequest::new(device_keys)) } } @@ -1778,10 +1770,7 @@ pub(crate) mod test { let mut one_time_keys = BTreeMap::new(); one_time_keys.insert(bob.user_id.clone(), bob_keys); - let response = claim_keys::Response { - failures: BTreeMap::new(), - one_time_keys, - }; + let response = claim_keys::Response::new(one_time_keys); alice.receive_keys_claim_response(&response).await.unwrap(); @@ -2052,10 +2041,7 @@ pub(crate) mod test { let mut one_time_keys = BTreeMap::new(); one_time_keys.insert(bob_machine.user_id.clone(), bob_keys); - let response = claim_keys::Response { - failures: BTreeMap::new(), - one_time_keys, - }; + let response = claim_keys::Response::new(one_time_keys); alice_machine .receive_keys_claim_response(&response) diff --git a/matrix_sdk_crypto/src/requests.rs b/matrix_sdk_crypto/src/requests.rs index 342f0b32..f4cef39e 100644 --- a/matrix_sdk_crypto/src/requests.rs +++ b/matrix_sdk_crypto/src/requests.rs @@ -12,19 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{collections::BTreeMap, sync::Arc}; +use std::{collections::BTreeMap, sync::Arc, time::Duration}; use matrix_sdk_common::{ api::r0::{ keys::{ claim_keys::Response as KeysClaimResponse, - get_keys::{IncomingRequest as KeysQueryRequest, Response as KeysQueryResponse}, + get_keys::Response as KeysQueryResponse, upload_keys::{Request as KeysUploadRequest, Response as KeysUploadResponse}, }, to_device::{send_event_to_device::Response as ToDeviceResponse, DeviceIdOrAllDevices}, }, events::EventType, - identifiers::UserId, + identifiers::{DeviceIdBox, UserId}, uuid::Uuid, }; @@ -56,6 +56,35 @@ impl ToDeviceRequest { } } +/// Customized version of `ruma_client_api::r0::keys::get_keys::Request`, without any references. +#[derive(Clone, Debug)] +pub struct KeysQueryRequest { + /// The time (in milliseconds) to wait when downloading keys from remote + /// servers. 10 seconds is the recommended default. + pub timeout: Option, + + /// The keys to be downloaded. An empty list indicates all devices for + /// the corresponding user. + pub device_keys: BTreeMap>, + + /// If the client is fetching keys as a result of a device update + /// received in a sync request, this should be the 'since' token of that + /// sync request, or any later sync token. This allows the server to + /// ensure its response contains the keys advertised by the notification + /// in that sync. + pub token: Option, +} + +impl KeysQueryRequest { + pub(crate) fn new(device_keys: BTreeMap>) -> Self { + Self { + timeout: None, + device_keys, + token: None, + } + } +} + /// Enum over the different outgoing requests we can have. #[derive(Debug)] pub enum OutgoingRequests {