Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions bindings/matrix-sdk-ffi/changelog.d/6711.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[**breaking**] `GrantQrLoginProgress::WaitingForAuth` and
`GrantGeneratedQrLoginProgress::WaitingForAuth` now have a
`continuation_sender: ContinuationMessageSender` field. Applications must call
`continuation_sender.confirm()` once the verification URI has been opened in
the browser and the application is ready to proceed, or
`continuation_sender.cancel()` to abort; previously it proceeded automatically
as soon as this state was reached. This lets applications that suspend or
navigate away while the verification URI is open to resume the process
explicitly.
68 changes: 57 additions & 11 deletions bindings/matrix-sdk-ffi/src/qr_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ use std::sync::Arc;
use matrix_sdk::authentication::oauth::{
OAuth,
qrcode::{
self, CheckCodeSender as SdkCheckCodeSender, CheckCodeSenderError,
DeviceCodeErrorResponseType, GeneratedQrProgress, LoginFailureReason, QrProgress,
self, CheckCodeSender as SdkCheckCodeSender,
ContinuationMessageSender as SdkContinuationMessageSender, DeviceCodeErrorResponseType,
GeneratedQrProgress, LoginFailureReason, QrProgress, SenderError,
},
};
use matrix_sdk_base::crypto::types::qr_login::{self, QrCodeIntent};
Expand Down Expand Up @@ -390,11 +391,11 @@ impl From<qrcode::QRCodeLoginError> for HumanQrLoginError {
}
}

impl From<CheckCodeSenderError> for HumanQrLoginError {
fn from(value: CheckCodeSenderError) -> Self {
impl From<SenderError> for HumanQrLoginError {
fn from(value: SenderError) -> Self {
match value {
CheckCodeSenderError::AlreadySent => HumanQrLoginError::CheckCodeAlreadySent,
CheckCodeSenderError::CannotSend => HumanQrLoginError::CheckCodeCannotBeSent,
SenderError::AlreadySent => HumanQrLoginError::CheckCodeAlreadySent,
SenderError::CannotSend => HumanQrLoginError::CheckCodeCannotBeSent,
}
}
}
Expand Down Expand Up @@ -614,6 +615,12 @@ pub enum GrantQrLoginProgress {
WaitingForAuth {
/// A URI to open in a (secure) system browser to verify the new login.
verification_uri: String,
/// A sender to confirm that the authorization using the verification
/// URI has been started in the browser and that the application is
/// ready to proceed. This allows applications that suspend or navigate
/// away while the verification URI is open to resume the process
/// explicitly.
continuation_sender: Arc<ContinuationMessageSender>,
},
/// We are syncing secrets.
SyncingSecrets,
Expand All @@ -640,8 +647,11 @@ impl From<qrcode::GrantLoginProgress<QrProgress>> for GrantQrLoginProgress {
check_code_string: format!("{check_code:02}"),
}
}
GrantLoginProgress::WaitingForAuth { verification_uri } => {
Self::WaitingForAuth { verification_uri: verification_uri.into() }
GrantLoginProgress::WaitingForAuth { verification_uri, continuation_sender } => {
Self::WaitingForAuth {
verification_uri: verification_uri.into(),
continuation_sender: Arc::new(continuation_sender.into()),
}
}
GrantLoginProgress::SyncingSecrets => Self::SyncingSecrets,
GrantLoginProgress::Done => Self::Done,
Expand All @@ -668,6 +678,12 @@ pub enum GrantGeneratedQrLoginProgress {
WaitingForAuth {
/// A URI to open in a (secure) system browser to verify the new login.
verification_uri: String,
/// A sender to confirm that the authorization using the verification
/// URI has been started in the browser and that the application is
/// ready to proceed. This allows applications that suspend or navigate
/// away while the verification URI is open to resume the process
/// explicitly.
continuation_sender: Arc<ContinuationMessageSender>,
},
/// We are syncing secrets.
SyncingSecrets,
Expand All @@ -692,18 +708,21 @@ impl From<qrcode::GrantLoginProgress<GeneratedQrProgress>> for GrantGeneratedQrL
GrantLoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
inner,
)) => Self::QrScanned { check_code_sender: Arc::new(CheckCodeSender { inner }) },
GrantLoginProgress::WaitingForAuth { verification_uri } => {
Self::WaitingForAuth { verification_uri: verification_uri.into() }
GrantLoginProgress::WaitingForAuth { verification_uri, continuation_sender } => {
Self::WaitingForAuth {
verification_uri: verification_uri.into(),
continuation_sender: Arc::new(continuation_sender.into()),
}
}
GrantLoginProgress::SyncingSecrets => Self::SyncingSecrets,
GrantLoginProgress::Done => Self::Done,
}
}
}

#[derive(Debug, uniffi::Object)]
/// Used to pass back the [`CheckCode`] entered by the user to verify that the
/// secure channel is indeed secure.
#[derive(Debug, uniffi::Object)]
pub struct CheckCodeSender {
inner: SdkCheckCodeSender,
}
Expand All @@ -721,3 +740,30 @@ impl CheckCodeSender {
self.inner.send(code).await.map_err(HumanQrLoginError::from)
}
}

/// Struct used to let the QR code granting logic know that it can continue with
/// the process since applications might suspend things while the verification
/// URI is open.
#[derive(Debug, Clone, uniffi::Object)]
pub struct ContinuationMessageSender {
inner: SdkContinuationMessageSender,
}

#[matrix_sdk_ffi_macros::export]
impl ContinuationMessageSender {
/// Confirm the continuation of the login granting process.
pub async fn confirm(&self) -> Result<(), HumanQrLoginError> {
self.inner.confirm().await.map_err(HumanQrLoginError::from)
}

/// Cancel the login granting process.
pub async fn cancel(&self) -> Result<(), HumanQrLoginError> {
self.inner.cancel().await.map_err(HumanQrLoginError::from)
}
}

impl From<SdkContinuationMessageSender> for ContinuationMessageSender {
fn from(value: SdkContinuationMessageSender) -> Self {
Self { inner: value }
}
}
11 changes: 11 additions & 0 deletions crates/matrix-sdk/changelog.d/6711.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[**breaking**] `GrantLoginProgress::WaitingForAuth` now has a
`continuation_sender: ContinuationMessageSender` field. Applications must call
`continuation_sender.confirm()` once the verification URI has been opened in
the browser and the application is ready to proceed, or
`continuation_sender.cancel()` to abort; previously it proceeded automatically
as soon as this state was reached. This lets applications that suspend or
navigate away while the verification URI is open to resume the process
explicitly.

[**breaking**] `qrcode::CheckCodeSenderError` has been renamed to
`qrcode::SenderError`, since it is now shared with `ContinuationMessageSender`.
16 changes: 12 additions & 4 deletions crates/matrix-sdk/src/authentication/oauth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1619,8 +1619,12 @@ impl<'a> GrantLoginWithQrCodeBuilder<'a> {
/// GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
/// println!("Please enter the checkcode on your other device: {:?}", check_code);
/// }
/// GrantLoginProgress::WaitingForAuth { verification_uri } => {
/// println!("Please open {verification_uri} to confirm the new login")
/// GrantLoginProgress::WaitingForAuth { verification_uri, continuation_sender } => {
/// println!("Please open {verification_uri} to confirm the new login");
///
/// // Once the new login has been confirmed in the browser, we can let the
/// // client continue with the process.
/// continuation_sender.confirm().await?;
/// },
/// GrantLoginProgress::Done => break,
/// }
Expand Down Expand Up @@ -1696,8 +1700,12 @@ impl<'a> GrantLoginWithQrCodeBuilder<'a> {
/// let check_code = s.trim().parse::<u8>()?;
/// checkcode_sender.send(check_code).await?;
/// }
/// GrantLoginProgress::WaitingForAuth { verification_uri } => {
/// println!("Please open {verification_uri} to confirm the new login")
/// GrantLoginProgress::WaitingForAuth { verification_uri, continuation_sender } => {
/// println!("Please open {verification_uri} to confirm the new login");
///
/// // Once the new login has been confirmed in the browser, we can let the
/// // client continue with the process.
/// continuation_sender.confirm().await?;
/// },
/// GrantLoginProgress::Done => break,
/// }
Expand Down
Loading
Loading