diff --git a/crates/matrix-sdk/CHANGELOG.md b/crates/matrix-sdk/CHANGELOG.md index be5a51a8e..703be0e1f 100644 --- a/crates/matrix-sdk/CHANGELOG.md +++ b/crates/matrix-sdk/CHANGELOG.md @@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file. ### Features +- [**breaking**] `matrix_sdk::error::Error` has a new variant `Timeout` which occurs when + a cross-signing reset does not succeed after some period of time. + ([#6325](https://github.com/matrix-org/matrix-rust-sdk/pull/6325)) - The `beacon_info` start event ([MSC3672](https://github.com/matrix-org/matrix-spec-proposals/pull/3672)) is now included when computing the latest event for a room, so live location sharing sessions can be surfaced as a room's most recent activity. diff --git a/crates/matrix-sdk/src/encryption/mod.rs b/crates/matrix-sdk/src/encryption/mod.rs index bfe143511..98cdce7a4 100644 --- a/crates/matrix-sdk/src/encryption/mod.rs +++ b/crates/matrix-sdk/src/encryption/mod.rs @@ -25,6 +25,7 @@ use std::{ path::PathBuf, str::FromStr, sync::Arc, + time::Duration, }; use eyeball::{SharedObservable, Subscriber}; @@ -48,6 +49,7 @@ use matrix_sdk_base::{ }, }, }, + sleep::sleep, }; use matrix_sdk_common::{executor::spawn, locks::Mutex as StdMutex}; use ruma::{ @@ -298,27 +300,50 @@ impl CrossSigningResetHandle { /// authentication to be done on the side of the OAuth 2.0 server or by /// providing additional [`AuthData`] the homeserver requires. pub async fn auth(&self, auth: Option) -> Result<()> { - let mut upload_request = self.upload_request.clone(); - upload_request.auth = auth; + // Poll to see whether the reset has been authorized twice per second. + const RETRY_EVERY: Duration = Duration::from_millis(500); - while let Err(e) = self.client.send(upload_request.clone()).await { - if *self.is_cancelled.lock().await { - return Ok(()); - } + // Give up after two minutes of polling. + const TIMEOUT: Duration = Duration::from_mins(2); - match e.as_uiaa_response() { - Some(uiaa_info) => { - if uiaa_info.auth_error.is_some() { - return Err(e.into()); - } + tokio::time::timeout(TIMEOUT, async { + let mut upload_request = self.upload_request.clone(); + upload_request.auth = auth; + + debug!( + "Repeatedly PUTting to keys/device_signing/upload until it works \ + or we hit a permanent failure." + ); + while let Err(e) = self.client.send(upload_request.clone()).await { + if *self.is_cancelled.lock().await { + return Ok(()); } - None => return Err(e.into()), + + match e.as_uiaa_response() { + Some(uiaa_info) => { + if uiaa_info.auth_error.is_some() { + return Err(e.into()); + } + } + None => return Err(e.into()), + } + + debug!( + "PUT to keys/device_signing/upload failed with 401. Retrying after \ + a short delay." + ); + sleep(RETRY_EVERY).await; } - } - self.client.send(self.signatures_request.clone()).await?; + self.client.send(self.signatures_request.clone()).await?; - Ok(()) + Ok(()) + }) + .await + .unwrap_or_else(|_| { + warn!("Timed out waiting for keys/device_signing/upload to succeed."); + Err(Error::Timeout) + }) } /// Cancel the ongoing identity reset process diff --git a/crates/matrix-sdk/src/error.rs b/crates/matrix-sdk/src/error.rs index 582380616..6ea097f50 100644 --- a/crates/matrix-sdk/src/error.rs +++ b/crates/matrix-sdk/src/error.rs @@ -417,6 +417,10 @@ pub enum Error { /// An error happened while attempting to change power levels. #[error("power levels error: {0}")] PowerLevels(#[from] PowerLevelsError), + + /// We timed out attempting to complete an operation. + #[error("timed out")] + Timeout, } #[rustfmt::skip] // stop rustfmt breaking the `` in docs across multiple lines