pub struct LoginWithQrCodeBuilder<'a> { /* private fields */ }e2e-encryption only.Expand description
Builder for QR login futures.
Implementations§
Source§impl<'a> LoginWithQrCodeBuilder<'a>
impl<'a> LoginWithQrCodeBuilder<'a>
Sourcepub fn scan(self, data: &'a QrCodeData) -> LoginWithQrCode<'a>
pub fn scan(self, data: &'a QrCodeData) -> LoginWithQrCode<'a>
This method allows you to log in with a scanned QR code.
The existing device needs to display the QR code which this device can scan and call this method to log in.
A successful login using this method will automatically mark the device as verified and transfer all end-to-end encryption related secrets, like the private cross-signing keys and the backup key from the existing device to the new device.
For the reverse flow where this device generates the QR code for the
existing device to scan, use LoginWithQrCodeBuilder::generate.
§Arguments
data- The data scanned from a QR code.
§Example
use anyhow::bail;
use futures_util::StreamExt;
use matrix_sdk::{
authentication::oauth::{
registration::ClientMetadata,
qrcode::{LoginProgress, QrCodeData, QrCodeModeData, QrProgress},
},
ruma::serde::Raw,
Client,
};
// You'll need to use a different library to scan and extract the raw bytes from the QR
// code.
let qr_code_data = QrCodeData::from_bytes(bytes)?;
// Fetch the homeserver out of the parsed QR code data.
let QrCodeModeData::Reciprocate{ server_name } = qr_code_data.mode_data else {
bail!("The QR code is invalid, we did not receive a homeserver in the QR code.");
};
// Build the client as usual.
let client = Client::builder()
.server_name_or_homeserver_url(server_name)
.handle_refresh_tokens()
.build()
.await?;
let oauth = client.oauth();
let client_metadata: Raw<ClientMetadata> = client_metadata();
let registration_data = client_metadata.into();
// Subscribing to the progress is necessary since we need to input the check
// code on the existing device.
let login = oauth.login_with_qr_code(Some(®istration_data)).scan(&qr_code_data);
let mut progress = login.subscribe_to_progress();
// Create a task which will show us the progress and tell us the check
// code to input in the existing device.
let task = tokio::spawn(async move {
while let Some(state) = progress.next().await {
match state {
LoginProgress::Starting | LoginProgress::SyncingSecrets => (),
LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
let code = check_code.to_digit();
println!("Please enter the following code into the other device {code:02}");
},
LoginProgress::WaitingForToken { user_code } => {
println!("Please use your other device to confirm the log in {user_code}")
},
LoginProgress::Done => break,
}
}
});
// Now run the future to complete the login.
login.await?;
task.abort();
println!("Successfully logged in: {:?} {:?}", client.user_id(), client.device_id());Sourcepub fn generate(self) -> LoginWithGeneratedQrCode<'a>
pub fn generate(self) -> LoginWithGeneratedQrCode<'a>
This method allows you to log in by generating a QR code.
This device needs to call this method to generate and display the QR code which the existing device can scan and grant the log in.
A successful login using this method will automatically mark the device as verified and transfer all end-to-end encryption related secrets, like the private cross-signing keys and the backup key from the existing device to the new device.
For the reverse flow where the existing device generates the QR code
for this device to scan, use LoginWithQrCodeBuilder::scan.
§Example
use anyhow::bail;
use futures_util::StreamExt;
use matrix_sdk::{
authentication::oauth::{
registration::ClientMetadata,
qrcode::{GeneratedQrProgress, LoginProgress, QrCodeData, QrCodeModeData},
},
ruma::serde::Raw,
Client,
};
use std::{error::Error, io::stdin};
// Build the client as usual.
let client = Client::builder()
.server_name_or_homeserver_url("matrix.org")
.handle_refresh_tokens()
.build()
.await?;
let oauth = client.oauth();
let client_metadata: Raw<ClientMetadata> = client_metadata();
let registration_data = client_metadata.into();
// Subscribing to the progress is necessary since we need to display the
// QR code and prompt for the check code.
let login = oauth.login_with_qr_code(Some(®istration_data)).generate();
let mut progress = login.subscribe_to_progress();
// Create a task which will show us the progress and allows us to display
// the QR code and prompt for the check code.
let task = tokio::spawn(async move {
while let Some(state) = progress.next().await {
match state {
LoginProgress::Starting | LoginProgress::SyncingSecrets => (),
LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
println!("Please use your other device to scan the QR code {:?}", qr)
}
LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(cctx)) => {
println!("Please enter the code displayed on your other device");
let mut s = String::new();
stdin().read_line(&mut s)?;
let check_code = s.trim().parse::<u8>()?;
cctx.send(check_code).await?
}
LoginProgress::WaitingForToken { user_code } => {
println!("Please use your other device to confirm the log in {user_code}")
},
LoginProgress::Done => break,
}
}
Ok::<(), Box<dyn Error + Send + Sync>>(())
});
// Now run the future to complete the login.
login.await?;
task.abort();
println!("Successfully logged in: {:?} {:?}", client.user_id(), client.device_id());Trait Implementations§
Auto Trait Implementations§
impl<'a> Freeze for LoginWithQrCodeBuilder<'a>
impl<'a> !RefUnwindSafe for LoginWithQrCodeBuilder<'a>
impl<'a> Send for LoginWithQrCodeBuilder<'a>
impl<'a> Sync for LoginWithQrCodeBuilder<'a>
impl<'a> Unpin for LoginWithQrCodeBuilder<'a>
impl<'a> !UnwindSafe for LoginWithQrCodeBuilder<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more