LoginWithQrCodeBuilder

Struct LoginWithQrCodeBuilder 

Source
pub struct LoginWithQrCodeBuilder<'a> { /* private fields */ }
Available on crate feature e2e-encryption only.
Expand description

Builder for QR login futures.

Implementations§

Source§

impl<'a> LoginWithQrCodeBuilder<'a>

Source

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(&registration_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());
Source

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(&registration_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§

Source§

impl<'a> Debug for LoginWithQrCodeBuilder<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

impl<T> Identity for T
where T: ?Sized,

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> Any for T
where T: Any,

Source§

impl<T> AsyncTraitDeps for T

Source§

impl<T> JsonCastable<CanonicalJsonValue> for T

Source§

impl<T> JsonCastable<Value> for T

Source§

impl<T> SendOutsideWasm for T
where T: Send,

Source§

impl<T> SyncOutsideWasm for T
where T: Sync,