Make LoginProgres::EstablishingSecureChannel generic in order to reuse it for the other QR login flow

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
This commit is contained in:
Johannes Marbach
2025-09-24 13:18:50 +02:00
committed by Damir Jelić
parent 6191e2c24e
commit 79e1930b22
6 changed files with 32 additions and 22 deletions
+6 -4
View File
@@ -1,7 +1,9 @@
use std::sync::Arc;
use matrix_sdk::{
authentication::oauth::qrcode::{self, DeviceCodeErrorResponseType, LoginFailureReason},
authentication::oauth::qrcode::{
self, DeviceCodeErrorResponseType, LoginFailureReason, QrProgress,
},
crypto::types::qr_login::{LoginQrCodeDecodeError, QrCodeModeData},
};
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
@@ -144,13 +146,13 @@ pub trait QrLoginProgressListener: SyncOutsideWasm + SendOutsideWasm {
fn on_update(&self, state: QrLoginProgress);
}
impl From<qrcode::LoginProgress> for QrLoginProgress {
fn from(value: qrcode::LoginProgress) -> Self {
impl From<qrcode::LoginProgress<QrProgress>> for QrLoginProgress {
fn from(value: qrcode::LoginProgress<QrProgress>) -> Self {
use qrcode::LoginProgress;
match value {
LoginProgress::Starting => Self::Starting,
LoginProgress::EstablishingSecureChannel { check_code } => {
LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
let check_code = check_code.to_digit();
Self::EstablishingSecureChannel {
+3
View File
@@ -20,6 +20,9 @@ All notable changes to this project will be documented in this file.
([#5733](https://github.com/matrix-org/matrix-rust-sdk/pull/5733))
- The Matrix SDK crate now uses the 2024 edition of Rust.
([#5677](https://github.com/matrix-org/matrix-rust-sdk/pull/5677))
- [**breaking**] Make `LoginProgress::EstablishingSecureChannel` generic in order to reuse it
for the currently missing QR login flow.
([#5750](https://github.com/matrix-org/matrix-rust-sdk/pull/5750))
### Bugfix
@@ -431,8 +431,8 @@ impl OAuth {
/// while let Some(state) = progress.next().await {
/// match state {
/// LoginProgress::Starting => (),
/// LoginProgress::EstablishingSecureChannel { check_code } => {
/// let code = check_code.to_digit();
/// LoginProgress::EstablishingSecureChannel(progress) => {
/// let code = progress.check_code.to_digit();
/// println!("Please enter the following code into the other device {code:02}");
/// },
/// LoginProgress::WaitingForToken { user_code } => {
@@ -50,11 +50,11 @@ async fn send_unexpected_message_error(
.await
}
async fn finish_login(
async fn finish_login<Q>(
client: &Client,
mut channel: EstablishedSecureChannel,
registration_data: Option<&ClientRegistrationData>,
state: SharedObservable<LoginProgress>,
state: SharedObservable<LoginProgress<Q>>,
) -> Result<(), QRCodeLoginError> {
let oauth = client.oauth();
@@ -237,17 +237,14 @@ async fn wait_for_tokens(
/// Type telling us about the progress of the QR code login.
#[derive(Clone, Debug, Default)]
pub enum LoginProgress {
pub enum LoginProgress<Q> {
/// We're just starting up, this is the default and initial state.
#[default]
Starting,
/// We have established the secure channel, but we need to let the other
/// side know about the [`CheckCode`] so they can verify that the secure
/// channel is indeed secure.
EstablishingSecureChannel {
/// The check code we need to, out of band, send to the other device.
check_code: CheckCode,
},
EstablishingSecureChannel(Q),
/// We're waiting for the OAuth 2.0 authorization server to give us the
/// access token. This will only happen if the other device allows the
/// OAuth 2.0 authorization server to do so.
@@ -261,13 +258,21 @@ pub enum LoginProgress {
Done,
}
/// Metadata to be used with [`LoginProgress::EstablishingSecureChannel`] when
/// this device is the one scanning the QR code.
#[derive(Clone, Debug)]
pub struct QrProgress {
/// The check code we need to, out of band, send to the other device.
pub check_code: CheckCode,
}
/// Named future for the [`OAuth::login_with_qr_code()`] method.
#[derive(Debug)]
pub struct LoginWithQrCode<'a> {
client: &'a Client,
registration_data: Option<&'a ClientRegistrationData>,
qr_code_data: &'a QrCodeData,
state: SharedObservable<LoginProgress>,
state: SharedObservable<LoginProgress<QrProgress>>,
}
impl LoginWithQrCode<'_> {
@@ -276,7 +281,7 @@ impl LoginWithQrCode<'_> {
/// It's usually necessary to subscribe to this to let the existing device
/// know about the [`CheckCode`] which is used to verify that the two
/// devices are communicating in a secure manner.
pub fn subscribe_to_progress(&self) -> impl Stream<Item = LoginProgress> + use<> {
pub fn subscribe_to_progress(&self) -> impl Stream<Item = LoginProgress<QrProgress>> + use<> {
self.state.subscribe()
}
}
@@ -298,7 +303,7 @@ impl<'a> IntoFuture for LoginWithQrCode<'a> {
// a check code so they can confirm.
let check_code = channel.check_code().to_owned();
self.state.set(LoginProgress::EstablishingSecureChannel { check_code });
self.state.set(LoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
finish_login(self.client, channel, self.registration_data, self.state).await
})
@@ -478,7 +483,7 @@ mod test {
while let Some(update) = updates.next().await {
match update {
LoginProgress::EstablishingSecureChannel { check_code } => {
LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
sender
.take()
.expect("The establishing secure channel update should be received only once")
@@ -566,7 +571,7 @@ mod test {
while let Some(update) = updates.next().await {
match update {
LoginProgress::EstablishingSecureChannel { check_code } => {
LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
sender
.take()
.expect("The establishing secure channel update should be received only once")
@@ -689,7 +694,7 @@ mod test {
while let Some(update) = updates.next().await {
match update {
LoginProgress::EstablishingSecureChannel { check_code } => {
LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
sender
.take()
.expect("The establishing secure channel update should be received only once")
@@ -41,7 +41,7 @@ mod rendezvous_channel;
mod secure_channel;
pub use self::{
login::{LoginProgress, LoginWithQrCode},
login::{LoginProgress, LoginWithQrCode, QrProgress},
messages::{LoginFailureReason, LoginProtocolType, QrAuthMessage},
};
use super::CrossProcessRefreshLockError;
+2 -2
View File
@@ -6,7 +6,7 @@ use futures_util::StreamExt;
use matrix_sdk::{
Client,
authentication::oauth::{
qrcode::{LoginProgress, QrCodeData, QrCodeModeData},
qrcode::{LoginProgress, QrCodeData, QrCodeModeData, QrProgress},
registration::{ApplicationType, ClientMetadata, Localized, OAuthGrantType},
},
ruma::serde::Raw,
@@ -122,7 +122,7 @@ async fn login(proxy: Option<Url>) -> Result<()> {
while let Some(state) = subscriber.next().await {
match state {
LoginProgress::Starting => (),
LoginProgress::EstablishingSecureChannel { check_code } => {
LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
let code = check_code.to_digit();
println!("Please enter the following code into the other device {code:02}");
}