atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git

Blame: bindings/matrix-sdk-crypto-ffi/src/verification.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
use std::sync::Arc;
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
use futures_util::{Stream, StreamExt};
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
use matrix_sdk_common::executor::Handle;
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
use matrix_sdk_crypto::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
    CancelInfo as RustCancelInfo, QrVerification as InnerQr, QrVerificationState, Sas as InnerSas,
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
    SasState as RustSasState, Verification as InnerVerification,
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
    VerificationRequest as InnerVerificationRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
    VerificationRequestState as RustVerificationRequestState,
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
    matrix_sdk_qrcode::QrVerificationData,
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
use ruma::events::key::verification::VerificationMethod;
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
use vodozemac::{base64_decode, base64_encode};
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
use crate::{CryptoStoreError, OutgoingVerificationRequest, SignatureUploadRequest};
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
/// Listener that will be passed over the FFI to report changes to a SAS
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
/// verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
#[matrix_sdk_ffi_macros::export(callback_interface)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
pub trait SasListener: Send {
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
    /// The callback that should be called on the Rust side
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
    /// * `state` - The current state of the SAS verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
    fn on_change(&self, state: SasState);
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
/// An Enum describing the state the SAS verification is in.
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
#[derive(uniffi::Enum)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
pub enum SasState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
    /// The verification has been created, the protocols that should be used
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
    /// have been proposed to the other party.
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
    Created,
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
    /// The verification has been started, the other party proposed the
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
    /// protocols that should be used and that can be accepted.
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
    Started,
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
    /// The verification has been accepted and both sides agreed to a set of
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
    /// protocols that will be used for the verification process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
    Accepted,
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
    /// The public keys have been exchanged and the short auth string can be
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
    /// presented to the user.
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
    KeysExchanged {
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
        /// The emojis that represent the short auth string, will be `None` if
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
        /// the emoji SAS method wasn't one of accepted protocols.
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
        emojis: Option<Vec<i32>>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
        /// The list of decimals that represent the short auth string.
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
        decimals: Vec<i32>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
    /// The verification process has been confirmed from our side, we're waiting
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
    /// for the other side to confirm as well.
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
    Confirmed,
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
    /// The verification process has been successfully concluded.
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
    Done,
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
    /// The verification process has been cancelled.
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
    Cancelled {
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
        /// Information about the reason of the cancellation.
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
        cancel_info: CancelInfo,
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
impl From<RustSasState> for SasState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
    fn from(s: RustSasState) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
        match s {
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
            RustSasState::Created { .. } => Self::Created,
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
            RustSasState::Started { .. } => Self::Started,
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
            RustSasState::Accepted { .. } => Self::Accepted,
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
            RustSasState::KeysExchanged { emojis, decimals } => Self::KeysExchanged {
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
                emojis: emojis.map(|e| e.indices.map(|i| i as i32).to_vec()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
                decimals: [decimals.0.into(), decimals.1.into(), decimals.2.into()].to_vec(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
            RustSasState::Confirmed => Self::Confirmed,
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
            RustSasState::Done { .. } => Self::Done,
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
            RustSasState::Cancelled(c) => Self::Cancelled { cancel_info: c.into() },
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
/// Enum representing the different verification flows we support.
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
#[derive(uniffi::Object)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
pub struct Verification {
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
    pub(crate) inner: InnerVerification,
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
    pub(crate) runtime: Handle,
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
#[matrix_sdk_ffi_macros::export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
impl Verification {
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
    /// Try to represent the `Verification` as an `Sas` verification object,
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
    /// returns `None` if the verification is not a `Sas` verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
    pub fn as_sas(&self) -> Option<Arc<Sas>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
        if let InnerVerification::SasV1(sas) = &self.inner {
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
            Some(Sas { inner: sas.clone(), runtime: self.runtime.to_owned() }.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
            None
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
    /// Try to represent the `Verification` as an `QrCode` verification object,
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
    /// returns `None` if the verification is not a `QrCode` verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
    pub fn as_qr(&self) -> Option<Arc<QrCode>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
        if let InnerVerification::QrV1(qr) = &self.inner {
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
            Some(QrCode { inner: qr.clone(), runtime: self.runtime.to_owned() }.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
            None
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
/// The `m.sas.v1` verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
#[derive(uniffi::Object)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
pub struct Sas {
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
    pub(crate) inner: Box<InnerSas>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
    pub(crate) runtime: Handle,
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
#[matrix_sdk_ffi_macros::export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
impl Sas {
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
    /// Get the user id of the other side.
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
    pub fn other_user_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
        self.inner.other_user_id().to_string()
7ff8adafe9e4atagen2026-10-22 12:30 UTC121
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC122
7ff8adafe9e4atagen2026-10-22 12:30 UTC123
    /// Get the device ID of the other side.
7ff8adafe9e4atagen2026-10-22 12:30 UTC124
    pub fn other_device_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC125
        self.inner.other_device_id().to_string()
7ff8adafe9e4atagen2026-10-22 12:30 UTC126
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC127
7ff8adafe9e4atagen2026-10-22 12:30 UTC128
    /// Get the unique ID that identifies this SAS verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC129
    pub fn flow_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC130
        self.inner.flow_id().as_str().to_owned()
7ff8adafe9e4atagen2026-10-22 12:30 UTC131
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC132
7ff8adafe9e4atagen2026-10-22 12:30 UTC133
    /// Get the room id if the verification is happening inside a room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC134
    pub fn room_id(&self) -> Option<String> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC135
        self.inner.room_id().map(|r| r.to_string())
7ff8adafe9e4atagen2026-10-22 12:30 UTC136
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC137
7ff8adafe9e4atagen2026-10-22 12:30 UTC138
    /// Is the SAS flow done.
7ff8adafe9e4atagen2026-10-22 12:30 UTC139
    pub fn is_done(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC140
        self.inner.is_done()
7ff8adafe9e4atagen2026-10-22 12:30 UTC141
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC142
7ff8adafe9e4atagen2026-10-22 12:30 UTC143
    /// Did we initiate the verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC144
    pub fn we_started(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC145
        self.inner.we_started()
7ff8adafe9e4atagen2026-10-22 12:30 UTC146
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC147
7ff8adafe9e4atagen2026-10-22 12:30 UTC148
    /// Accept that we're going forward with the short auth string verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC149
    pub fn accept(&self) -> Option<OutgoingVerificationRequest> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC150
        self.inner.accept().map(|r| r.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC151
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC152
7ff8adafe9e4atagen2026-10-22 12:30 UTC153
    /// Confirm a verification was successful.
7ff8adafe9e4atagen2026-10-22 12:30 UTC154
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC155
    /// This method should be called if a short auth string should be confirmed
7ff8adafe9e4atagen2026-10-22 12:30 UTC156
    /// as matching.
7ff8adafe9e4atagen2026-10-22 12:30 UTC157
    pub fn confirm(&self) -> Result<Option<ConfirmVerificationResult>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC158
        let (requests, signature_request) = self.runtime.block_on(self.inner.confirm())?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC159
7ff8adafe9e4atagen2026-10-22 12:30 UTC160
        let requests = requests.into_iter().map(|r| r.into()).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC161
7ff8adafe9e4atagen2026-10-22 12:30 UTC162
        Ok(Some(ConfirmVerificationResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC163
            requests,
7ff8adafe9e4atagen2026-10-22 12:30 UTC164
            signature_request: signature_request.map(|s| s.into()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC165
        }))
7ff8adafe9e4atagen2026-10-22 12:30 UTC166
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC167
7ff8adafe9e4atagen2026-10-22 12:30 UTC168
    /// Cancel the SAS verification using the given cancel code.
7ff8adafe9e4atagen2026-10-22 12:30 UTC169
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC170
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC171
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC172
    /// * `cancel_code` - The error code for why the verification was cancelled,
7ff8adafe9e4atagen2026-10-22 12:30 UTC173
    ///   manual cancellatio usually happens with `m.user` cancel code. The full
7ff8adafe9e4atagen2026-10-22 12:30 UTC174
    ///   list of cancel codes can be found in the [spec]
7ff8adafe9e4atagen2026-10-22 12:30 UTC175
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC176
    /// [spec]: https://spec.matrix.org/unstable/client-server-api/#mkeyverificationcancel
7ff8adafe9e4atagen2026-10-22 12:30 UTC177
    pub fn cancel(&self, cancel_code: String) -> Option<OutgoingVerificationRequest> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC178
        self.inner.cancel_with_code(cancel_code.into()).map(|r| r.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC179
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC180
7ff8adafe9e4atagen2026-10-22 12:30 UTC181
    /// Get a list of emoji indices of the emoji representation of the short
7ff8adafe9e4atagen2026-10-22 12:30 UTC182
    /// auth string.
7ff8adafe9e4atagen2026-10-22 12:30 UTC183
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC184
    /// *Note*: A SAS verification needs to be started and in the presentable
7ff8adafe9e4atagen2026-10-22 12:30 UTC185
    /// state for this to return the list of emoji indices, otherwise returns
7ff8adafe9e4atagen2026-10-22 12:30 UTC186
    /// `None`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC187
    pub fn get_emoji_indices(&self) -> Option<Vec<i32>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC188
        self.inner.emoji_index().map(|v| v.iter().map(|i| (*i).into()).collect())
7ff8adafe9e4atagen2026-10-22 12:30 UTC189
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC190
7ff8adafe9e4atagen2026-10-22 12:30 UTC191
    /// Get the decimal representation of the short auth string.
7ff8adafe9e4atagen2026-10-22 12:30 UTC192
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC193
    /// *Note*: A SAS verification needs to be started and in the presentable
7ff8adafe9e4atagen2026-10-22 12:30 UTC194
    /// state for this to return the list of decimals, otherwise returns
7ff8adafe9e4atagen2026-10-22 12:30 UTC195
    /// `None`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC196
    pub fn get_decimals(&self) -> Option<Vec<i32>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC197
        self.inner.decimals().map(|v| [v.0.into(), v.1.into(), v.2.into()].to_vec())
7ff8adafe9e4atagen2026-10-22 12:30 UTC198
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC199
7ff8adafe9e4atagen2026-10-22 12:30 UTC200
    /// Set a listener for changes in the SAS verification process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC201
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC202
    /// The given callback will be called whenever the state changes.
7ff8adafe9e4atagen2026-10-22 12:30 UTC203
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC204
    /// This method can be used to react to changes in the state of the
7ff8adafe9e4atagen2026-10-22 12:30 UTC205
    /// verification process, or rather the method can be used to handle
7ff8adafe9e4atagen2026-10-22 12:30 UTC206
    /// each step of the verification process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC207
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC208
    /// This method will spawn a tokio task on the Rust side, once we reach the
7ff8adafe9e4atagen2026-10-22 12:30 UTC209
    /// Done or Cancelled state, the task will stop listening for changes.
7ff8adafe9e4atagen2026-10-22 12:30 UTC210
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC211
    /// # Flowchart
7ff8adafe9e4atagen2026-10-22 12:30 UTC212
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC213
    /// The flow of the verification process is pictured below. Please note
7ff8adafe9e4atagen2026-10-22 12:30 UTC214
    /// that the process can be cancelled at each step of the process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC215
    /// Either side can cancel the process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC216
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC217
    /// ```text
7ff8adafe9e4atagen2026-10-22 12:30 UTC218
    ///                ┌───────┐
7ff8adafe9e4atagen2026-10-22 12:30 UTC219
    ///                │Started│
7ff8adafe9e4atagen2026-10-22 12:30 UTC220
    ///                └───┬───┘
7ff8adafe9e4atagen2026-10-22 12:30 UTC221
    ///                    │
7ff8adafe9e4atagen2026-10-22 12:30 UTC222
    ///               ┌────⌄───┐
7ff8adafe9e4atagen2026-10-22 12:30 UTC223
    ///               │Accepted│
7ff8adafe9e4atagen2026-10-22 12:30 UTC224
    ///               └────┬───┘
7ff8adafe9e4atagen2026-10-22 12:30 UTC225
    ///                    │
7ff8adafe9e4atagen2026-10-22 12:30 UTC226
    ///            ┌───────⌄──────┐
7ff8adafe9e4atagen2026-10-22 12:30 UTC227
    ///            │Keys Exchanged│
7ff8adafe9e4atagen2026-10-22 12:30 UTC228
    ///            └───────┬──────┘
7ff8adafe9e4atagen2026-10-22 12:30 UTC229
    ///                    │
7ff8adafe9e4atagen2026-10-22 12:30 UTC230
    ///            ________⌄________
7ff8adafe9e4atagen2026-10-22 12:30 UTC231
    ///           ╱                 ╲       ┌─────────┐
7ff8adafe9e4atagen2026-10-22 12:30 UTC232
    ///          ╱   Does the short  ╲______│Cancelled│
7ff8adafe9e4atagen2026-10-22 12:30 UTC233
    ///          ╲ auth string match ╱ no   └─────────┘
7ff8adafe9e4atagen2026-10-22 12:30 UTC234
    ///           ╲_________________╱
7ff8adafe9e4atagen2026-10-22 12:30 UTC235
    ///                    │yes
7ff8adafe9e4atagen2026-10-22 12:30 UTC236
    ///                    │
7ff8adafe9e4atagen2026-10-22 12:30 UTC237
    ///               ┌────⌄────┐
7ff8adafe9e4atagen2026-10-22 12:30 UTC238
    ///               │Confirmed│
7ff8adafe9e4atagen2026-10-22 12:30 UTC239
    ///               └────┬────┘
7ff8adafe9e4atagen2026-10-22 12:30 UTC240
    ///                    │
7ff8adafe9e4atagen2026-10-22 12:30 UTC241
    ///                ┌───⌄───┐
7ff8adafe9e4atagen2026-10-22 12:30 UTC242
    ///                │  Done │
7ff8adafe9e4atagen2026-10-22 12:30 UTC243
    ///                └───────┘
7ff8adafe9e4atagen2026-10-22 12:30 UTC244
    /// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC245
    pub fn set_changes_listener(&self, listener: Box<dyn SasListener>) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC246
        let stream = self.inner.changes();
7ff8adafe9e4atagen2026-10-22 12:30 UTC247
7ff8adafe9e4atagen2026-10-22 12:30 UTC248
        self.runtime.spawn(Self::changes_listener(stream, listener));
7ff8adafe9e4atagen2026-10-22 12:30 UTC249
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC250
7ff8adafe9e4atagen2026-10-22 12:30 UTC251
    /// Get the current state of the SAS verification process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC252
    pub fn state(&self) -> SasState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC253
        self.inner.state().into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC254
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC255
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC256
7ff8adafe9e4atagen2026-10-22 12:30 UTC257
impl Sas {
7ff8adafe9e4atagen2026-10-22 12:30 UTC258
    async fn changes_listener(
7ff8adafe9e4atagen2026-10-22 12:30 UTC259
        mut stream: impl Stream<Item = RustSasState> + std::marker::Unpin,
7ff8adafe9e4atagen2026-10-22 12:30 UTC260
        listener: Box<dyn SasListener>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC261
    ) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC262
        while let Some(state) = stream.next().await {
7ff8adafe9e4atagen2026-10-22 12:30 UTC263
            // If we receive a done or a cancelled state we're at the end of our road, we
7ff8adafe9e4atagen2026-10-22 12:30 UTC264
            // break out of the loop to deallocate the stream and finish the
7ff8adafe9e4atagen2026-10-22 12:30 UTC265
            // task.
7ff8adafe9e4atagen2026-10-22 12:30 UTC266
            let should_break =
7ff8adafe9e4atagen2026-10-22 12:30 UTC267
                matches!(state, RustSasState::Done { .. } | RustSasState::Cancelled { .. });
7ff8adafe9e4atagen2026-10-22 12:30 UTC268
7ff8adafe9e4atagen2026-10-22 12:30 UTC269
            listener.on_change(state.into());
7ff8adafe9e4atagen2026-10-22 12:30 UTC270
7ff8adafe9e4atagen2026-10-22 12:30 UTC271
            if should_break {
7ff8adafe9e4atagen2026-10-22 12:30 UTC272
                break;
7ff8adafe9e4atagen2026-10-22 12:30 UTC273
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC274
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC275
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC276
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC277
7ff8adafe9e4atagen2026-10-22 12:30 UTC278
/// Listener that will be passed over the FFI to report changes to a QrCode
7ff8adafe9e4atagen2026-10-22 12:30 UTC279
/// verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC280
#[matrix_sdk_ffi_macros::export(callback_interface)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC281
pub trait QrCodeListener: Send {
7ff8adafe9e4atagen2026-10-22 12:30 UTC282
    /// The callback that should be called on the Rust side
7ff8adafe9e4atagen2026-10-22 12:30 UTC283
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC284
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC285
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC286
    /// * `state` - The current state of the QrCode verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC287
    fn on_change(&self, state: QrCodeState);
7ff8adafe9e4atagen2026-10-22 12:30 UTC288
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC289
7ff8adafe9e4atagen2026-10-22 12:30 UTC290
/// An Enum describing the state the QrCode verification is in.
7ff8adafe9e4atagen2026-10-22 12:30 UTC291
#[derive(uniffi::Enum)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC292
pub enum QrCodeState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC293
    /// The QR verification has been started.
7ff8adafe9e4atagen2026-10-22 12:30 UTC294
    Started,
7ff8adafe9e4atagen2026-10-22 12:30 UTC295
    /// The QR verification has been scanned by the other side.
7ff8adafe9e4atagen2026-10-22 12:30 UTC296
    Scanned,
7ff8adafe9e4atagen2026-10-22 12:30 UTC297
    /// The scanning of the QR code has been confirmed by us.
7ff8adafe9e4atagen2026-10-22 12:30 UTC298
    Confirmed,
7ff8adafe9e4atagen2026-10-22 12:30 UTC299
    /// We have successfully scanned the QR code and are able to send a
7ff8adafe9e4atagen2026-10-22 12:30 UTC300
    /// reciprocation event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC301
    Reciprocated,
7ff8adafe9e4atagen2026-10-22 12:30 UTC302
    /// The verification process has been successfully concluded.
7ff8adafe9e4atagen2026-10-22 12:30 UTC303
    Done,
7ff8adafe9e4atagen2026-10-22 12:30 UTC304
    /// The verification process has been cancelled.
7ff8adafe9e4atagen2026-10-22 12:30 UTC305
    Cancelled {
7ff8adafe9e4atagen2026-10-22 12:30 UTC306
        /// Information about the reason of the cancellation.
7ff8adafe9e4atagen2026-10-22 12:30 UTC307
        cancel_info: CancelInfo,
7ff8adafe9e4atagen2026-10-22 12:30 UTC308
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC309
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC310
7ff8adafe9e4atagen2026-10-22 12:30 UTC311
impl From<QrVerificationState> for QrCodeState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC312
    fn from(value: QrVerificationState) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC313
        match value {
7ff8adafe9e4atagen2026-10-22 12:30 UTC314
            QrVerificationState::Started => Self::Started,
7ff8adafe9e4atagen2026-10-22 12:30 UTC315
            QrVerificationState::Scanned => Self::Scanned,
7ff8adafe9e4atagen2026-10-22 12:30 UTC316
            QrVerificationState::Confirmed => Self::Confirmed,
7ff8adafe9e4atagen2026-10-22 12:30 UTC317
            QrVerificationState::Reciprocated => Self::Reciprocated,
7ff8adafe9e4atagen2026-10-22 12:30 UTC318
            QrVerificationState::Done { .. } => Self::Done,
7ff8adafe9e4atagen2026-10-22 12:30 UTC319
            QrVerificationState::Cancelled(c) => Self::Cancelled { cancel_info: c.into() },
7ff8adafe9e4atagen2026-10-22 12:30 UTC320
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC321
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC322
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC323
7ff8adafe9e4atagen2026-10-22 12:30 UTC324
/// The `m.qr_code.scan.v1`, `m.qr_code.show.v1`, and `m.reciprocate.v1`
7ff8adafe9e4atagen2026-10-22 12:30 UTC325
/// verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC326
#[derive(uniffi::Object)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC327
pub struct QrCode {
7ff8adafe9e4atagen2026-10-22 12:30 UTC328
    pub(crate) inner: Box<InnerQr>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC329
    pub(crate) runtime: Handle,
7ff8adafe9e4atagen2026-10-22 12:30 UTC330
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC331
7ff8adafe9e4atagen2026-10-22 12:30 UTC332
#[matrix_sdk_ffi_macros::export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC333
impl QrCode {
7ff8adafe9e4atagen2026-10-22 12:30 UTC334
    /// Get the user id of the other side.
7ff8adafe9e4atagen2026-10-22 12:30 UTC335
    pub fn other_user_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC336
        self.inner.other_user_id().to_string()
7ff8adafe9e4atagen2026-10-22 12:30 UTC337
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC338
7ff8adafe9e4atagen2026-10-22 12:30 UTC339
    /// Get the device ID of the other side.
7ff8adafe9e4atagen2026-10-22 12:30 UTC340
    pub fn other_device_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC341
        self.inner.other_device_id().to_string()
7ff8adafe9e4atagen2026-10-22 12:30 UTC342
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC343
7ff8adafe9e4atagen2026-10-22 12:30 UTC344
    /// Get the unique ID that identifies this QR code verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC345
    pub fn flow_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC346
        self.inner.flow_id().as_str().to_owned()
7ff8adafe9e4atagen2026-10-22 12:30 UTC347
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC348
7ff8adafe9e4atagen2026-10-22 12:30 UTC349
    /// Get the room id if the verification is happening inside a room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC350
    pub fn room_id(&self) -> Option<String> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC351
        self.inner.room_id().map(|r| r.to_string())
7ff8adafe9e4atagen2026-10-22 12:30 UTC352
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC353
7ff8adafe9e4atagen2026-10-22 12:30 UTC354
    /// Is the QR code verification done.
7ff8adafe9e4atagen2026-10-22 12:30 UTC355
    pub fn is_done(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC356
        self.inner.is_done()
7ff8adafe9e4atagen2026-10-22 12:30 UTC357
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC358
7ff8adafe9e4atagen2026-10-22 12:30 UTC359
    /// Has the verification flow been cancelled.
7ff8adafe9e4atagen2026-10-22 12:30 UTC360
    pub fn is_cancelled(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC361
        self.inner.is_cancelled()
7ff8adafe9e4atagen2026-10-22 12:30 UTC362
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC363
7ff8adafe9e4atagen2026-10-22 12:30 UTC364
    /// Did we initiate the verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC365
    pub fn we_started(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC366
        self.inner.we_started()
7ff8adafe9e4atagen2026-10-22 12:30 UTC367
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC368
7ff8adafe9e4atagen2026-10-22 12:30 UTC369
    /// Get the CancelInfo of this QR code verification object.
7ff8adafe9e4atagen2026-10-22 12:30 UTC370
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC371
    /// Will be `None` if the flow has not been cancelled.
7ff8adafe9e4atagen2026-10-22 12:30 UTC372
    pub fn cancel_info(&self) -> Option<CancelInfo> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC373
        self.inner.cancel_info().map(|c| c.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC374
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC375
7ff8adafe9e4atagen2026-10-22 12:30 UTC376
    /// Has the QR verification been scanned by the other side.
7ff8adafe9e4atagen2026-10-22 12:30 UTC377
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC378
    /// When the verification object is in this state it's required that the
7ff8adafe9e4atagen2026-10-22 12:30 UTC379
    /// user confirms that the other side has scanned the QR code.
7ff8adafe9e4atagen2026-10-22 12:30 UTC380
    pub fn has_been_scanned(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC381
        self.inner.has_been_scanned()
7ff8adafe9e4atagen2026-10-22 12:30 UTC382
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC383
7ff8adafe9e4atagen2026-10-22 12:30 UTC384
    /// Have we successfully scanned the QR code and are able to send a
7ff8adafe9e4atagen2026-10-22 12:30 UTC385
    /// reciprocation event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC386
    pub fn reciprocated(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC387
        self.inner.reciprocated()
7ff8adafe9e4atagen2026-10-22 12:30 UTC388
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC389
7ff8adafe9e4atagen2026-10-22 12:30 UTC390
    /// Cancel the QR code verification using the given cancel code.
7ff8adafe9e4atagen2026-10-22 12:30 UTC391
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC392
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC393
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC394
    /// * `cancel_code` - The error code for why the verification was cancelled,
7ff8adafe9e4atagen2026-10-22 12:30 UTC395
    ///   manual cancellatio usually happens with `m.user` cancel code. The full
7ff8adafe9e4atagen2026-10-22 12:30 UTC396
    ///   list of cancel codes can be found in the [spec]
7ff8adafe9e4atagen2026-10-22 12:30 UTC397
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC398
    /// [spec]: https://spec.matrix.org/unstable/client-server-api/#mkeyverificationcancel
7ff8adafe9e4atagen2026-10-22 12:30 UTC399
    pub fn cancel(&self, cancel_code: String) -> Option<OutgoingVerificationRequest> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC400
        self.inner.cancel_with_code(cancel_code.into()).map(|r| r.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC401
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC402
7ff8adafe9e4atagen2026-10-22 12:30 UTC403
    /// Confirm a verification was successful.
7ff8adafe9e4atagen2026-10-22 12:30 UTC404
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC405
    /// This method should be called if we want to confirm that the other side
7ff8adafe9e4atagen2026-10-22 12:30 UTC406
    /// has scanned our QR code.
7ff8adafe9e4atagen2026-10-22 12:30 UTC407
    pub fn confirm(&self) -> Option<ConfirmVerificationResult> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC408
        self.inner.confirm_scanning().map(|r| ConfirmVerificationResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC409
            requests: vec![r.into()],
7ff8adafe9e4atagen2026-10-22 12:30 UTC410
            signature_request: None,
7ff8adafe9e4atagen2026-10-22 12:30 UTC411
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC412
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC413
7ff8adafe9e4atagen2026-10-22 12:30 UTC414
    /// Generate data that should be encoded as a QR code.
7ff8adafe9e4atagen2026-10-22 12:30 UTC415
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC416
    /// This method should be called right before a QR code should be displayed,
7ff8adafe9e4atagen2026-10-22 12:30 UTC417
    /// the returned data is base64 encoded (without padding) and needs to be
7ff8adafe9e4atagen2026-10-22 12:30 UTC418
    /// decoded on the other side before it can be put through a QR code
7ff8adafe9e4atagen2026-10-22 12:30 UTC419
    /// generator.
7ff8adafe9e4atagen2026-10-22 12:30 UTC420
    pub fn generate_qr_code(&self) -> Option<String> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC421
        self.inner.to_bytes().map(base64_encode).ok()
7ff8adafe9e4atagen2026-10-22 12:30 UTC422
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC423
7ff8adafe9e4atagen2026-10-22 12:30 UTC424
    /// Set a listener for changes in the QrCode verification process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC425
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC426
    /// The given callback will be called whenever the state changes.
7ff8adafe9e4atagen2026-10-22 12:30 UTC427
    pub fn set_changes_listener(&self, listener: Box<dyn QrCodeListener>) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC428
        let stream = self.inner.changes();
7ff8adafe9e4atagen2026-10-22 12:30 UTC429
7ff8adafe9e4atagen2026-10-22 12:30 UTC430
        self.runtime.spawn(Self::changes_listener(stream, listener));
7ff8adafe9e4atagen2026-10-22 12:30 UTC431
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC432
7ff8adafe9e4atagen2026-10-22 12:30 UTC433
    /// Get the current state of the QrCode verification process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC434
    pub fn state(&self) -> QrCodeState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC435
        self.inner.state().into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC436
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC437
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC438
7ff8adafe9e4atagen2026-10-22 12:30 UTC439
impl QrCode {
7ff8adafe9e4atagen2026-10-22 12:30 UTC440
    async fn changes_listener(
7ff8adafe9e4atagen2026-10-22 12:30 UTC441
        mut stream: impl Stream<Item = QrVerificationState> + std::marker::Unpin,
7ff8adafe9e4atagen2026-10-22 12:30 UTC442
        listener: Box<dyn QrCodeListener>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC443
    ) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC444
        while let Some(state) = stream.next().await {
7ff8adafe9e4atagen2026-10-22 12:30 UTC445
            // If we receive a done or a cancelled state we're at the end of our road, we
7ff8adafe9e4atagen2026-10-22 12:30 UTC446
            // break out of the loop to deallocate the stream and finish the
7ff8adafe9e4atagen2026-10-22 12:30 UTC447
            // task.
7ff8adafe9e4atagen2026-10-22 12:30 UTC448
            let should_break = matches!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC449
                state,
7ff8adafe9e4atagen2026-10-22 12:30 UTC450
                QrVerificationState::Done { .. } | QrVerificationState::Cancelled { .. }
7ff8adafe9e4atagen2026-10-22 12:30 UTC451
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC452
7ff8adafe9e4atagen2026-10-22 12:30 UTC453
            listener.on_change(state.into());
7ff8adafe9e4atagen2026-10-22 12:30 UTC454
7ff8adafe9e4atagen2026-10-22 12:30 UTC455
            if should_break {
7ff8adafe9e4atagen2026-10-22 12:30 UTC456
                break;
7ff8adafe9e4atagen2026-10-22 12:30 UTC457
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC458
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC459
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC460
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC461
7ff8adafe9e4atagen2026-10-22 12:30 UTC462
/// Information on why a verification flow has been cancelled and by whom.
7ff8adafe9e4atagen2026-10-22 12:30 UTC463
#[derive(uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC464
pub struct CancelInfo {
7ff8adafe9e4atagen2026-10-22 12:30 UTC465
    /// The textual representation of the cancel reason
7ff8adafe9e4atagen2026-10-22 12:30 UTC466
    pub reason: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC467
    /// The code describing the cancel reason
7ff8adafe9e4atagen2026-10-22 12:30 UTC468
    pub cancel_code: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC469
    /// Was the verification flow cancelled by us
7ff8adafe9e4atagen2026-10-22 12:30 UTC470
    pub cancelled_by_us: bool,
7ff8adafe9e4atagen2026-10-22 12:30 UTC471
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC472
7ff8adafe9e4atagen2026-10-22 12:30 UTC473
impl From<RustCancelInfo> for CancelInfo {
7ff8adafe9e4atagen2026-10-22 12:30 UTC474
    fn from(c: RustCancelInfo) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC475
        Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC476
            reason: c.reason().to_owned(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC477
            cancel_code: c.cancel_code().to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC478
            cancelled_by_us: c.cancelled_by_us(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC479
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC480
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC481
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC482
7ff8adafe9e4atagen2026-10-22 12:30 UTC483
/// A result type for starting SAS verifications.
7ff8adafe9e4atagen2026-10-22 12:30 UTC484
#[derive(uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC485
pub struct StartSasResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC486
    /// The SAS verification object that got created.
7ff8adafe9e4atagen2026-10-22 12:30 UTC487
    pub sas: Arc<Sas>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC488
    /// The request that needs to be sent out to notify the other side that a
7ff8adafe9e4atagen2026-10-22 12:30 UTC489
    /// SAS verification should start.
7ff8adafe9e4atagen2026-10-22 12:30 UTC490
    pub request: OutgoingVerificationRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC491
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC492
7ff8adafe9e4atagen2026-10-22 12:30 UTC493
/// A result type for scanning QR codes.
7ff8adafe9e4atagen2026-10-22 12:30 UTC494
#[derive(uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC495
pub struct ScanResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC496
    /// The QR code verification object that got created.
7ff8adafe9e4atagen2026-10-22 12:30 UTC497
    pub qr: Arc<QrCode>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC498
    /// The request that needs to be sent out to notify the other side that a
7ff8adafe9e4atagen2026-10-22 12:30 UTC499
    /// QR code verification should start.
7ff8adafe9e4atagen2026-10-22 12:30 UTC500
    pub request: OutgoingVerificationRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC501
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC502
7ff8adafe9e4atagen2026-10-22 12:30 UTC503
/// A result type for requesting verifications.
7ff8adafe9e4atagen2026-10-22 12:30 UTC504
#[derive(uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC505
pub struct RequestVerificationResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC506
    /// The verification request object that got created.
7ff8adafe9e4atagen2026-10-22 12:30 UTC507
    pub verification: Arc<VerificationRequest>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC508
    /// The request that needs to be sent out to notify the other side that
7ff8adafe9e4atagen2026-10-22 12:30 UTC509
    /// we're requesting verification to begin.
7ff8adafe9e4atagen2026-10-22 12:30 UTC510
    pub request: OutgoingVerificationRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC511
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC512
7ff8adafe9e4atagen2026-10-22 12:30 UTC513
/// A result type for confirming verifications.
7ff8adafe9e4atagen2026-10-22 12:30 UTC514
#[derive(uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC515
pub struct ConfirmVerificationResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC516
    /// The requests that needs to be sent out to notify the other side that we
7ff8adafe9e4atagen2026-10-22 12:30 UTC517
    /// confirmed the verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC518
    pub requests: Vec<OutgoingVerificationRequest>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC519
    /// A request that will upload signatures of the verified device or user, if
7ff8adafe9e4atagen2026-10-22 12:30 UTC520
    /// the verification is completed and we're able to sign devices or users
7ff8adafe9e4atagen2026-10-22 12:30 UTC521
    pub signature_request: Option<SignatureUploadRequest>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC522
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC523
7ff8adafe9e4atagen2026-10-22 12:30 UTC524
/// Listener that will be passed over the FFI to report changes to a
7ff8adafe9e4atagen2026-10-22 12:30 UTC525
/// verification request.
7ff8adafe9e4atagen2026-10-22 12:30 UTC526
#[matrix_sdk_ffi_macros::export(callback_interface)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC527
pub trait VerificationRequestListener: Send {
7ff8adafe9e4atagen2026-10-22 12:30 UTC528
    /// The callback that should be called on the Rust side
7ff8adafe9e4atagen2026-10-22 12:30 UTC529
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC530
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC531
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC532
    /// * `state` - The current state of the verification request.
7ff8adafe9e4atagen2026-10-22 12:30 UTC533
    fn on_change(&self, state: VerificationRequestState);
7ff8adafe9e4atagen2026-10-22 12:30 UTC534
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC535
7ff8adafe9e4atagen2026-10-22 12:30 UTC536
/// An Enum describing the state the QrCode verification is in.
7ff8adafe9e4atagen2026-10-22 12:30 UTC537
#[derive(uniffi::Enum)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC538
pub enum VerificationRequestState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC539
    /// The verification request was sent
7ff8adafe9e4atagen2026-10-22 12:30 UTC540
    Requested,
7ff8adafe9e4atagen2026-10-22 12:30 UTC541
    /// The verification request is ready to start a verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC542
    Ready {
7ff8adafe9e4atagen2026-10-22 12:30 UTC543
        /// The verification methods supported by the other side.
7ff8adafe9e4atagen2026-10-22 12:30 UTC544
        their_methods: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC545
7ff8adafe9e4atagen2026-10-22 12:30 UTC546
        /// The verification methods supported by the us.
7ff8adafe9e4atagen2026-10-22 12:30 UTC547
        our_methods: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC548
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC549
    /// The verification flow that was started with this request has finished.
7ff8adafe9e4atagen2026-10-22 12:30 UTC550
    Done,
7ff8adafe9e4atagen2026-10-22 12:30 UTC551
    /// The verification process has been cancelled.
7ff8adafe9e4atagen2026-10-22 12:30 UTC552
    Cancelled {
7ff8adafe9e4atagen2026-10-22 12:30 UTC553
        /// Information about the reason of the cancellation.
7ff8adafe9e4atagen2026-10-22 12:30 UTC554
        cancel_info: CancelInfo,
7ff8adafe9e4atagen2026-10-22 12:30 UTC555
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC556
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC557
7ff8adafe9e4atagen2026-10-22 12:30 UTC558
/// The verificatoin request object which then can transition into some concrete
7ff8adafe9e4atagen2026-10-22 12:30 UTC559
/// verification method
7ff8adafe9e4atagen2026-10-22 12:30 UTC560
#[derive(uniffi::Object)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC561
pub struct VerificationRequest {
7ff8adafe9e4atagen2026-10-22 12:30 UTC562
    pub(crate) inner: InnerVerificationRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC563
    pub(crate) runtime: Handle,
7ff8adafe9e4atagen2026-10-22 12:30 UTC564
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC565
7ff8adafe9e4atagen2026-10-22 12:30 UTC566
#[matrix_sdk_ffi_macros::export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC567
impl VerificationRequest {
7ff8adafe9e4atagen2026-10-22 12:30 UTC568
    /// The id of the other user that is participating in this verification
7ff8adafe9e4atagen2026-10-22 12:30 UTC569
    /// request.
7ff8adafe9e4atagen2026-10-22 12:30 UTC570
    pub fn other_user_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC571
        self.inner.other_user().to_string()
7ff8adafe9e4atagen2026-10-22 12:30 UTC572
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC573
7ff8adafe9e4atagen2026-10-22 12:30 UTC574
    /// The id of the other device that is participating in this verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC575
    pub fn other_device_id(&self) -> Option<String> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC576
        self.inner.other_device_id().map(|d| d.to_string())
7ff8adafe9e4atagen2026-10-22 12:30 UTC577
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC578
7ff8adafe9e4atagen2026-10-22 12:30 UTC579
    /// Get the unique ID of this verification request
7ff8adafe9e4atagen2026-10-22 12:30 UTC580
    pub fn flow_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC581
        self.inner.flow_id().as_str().to_owned()
7ff8adafe9e4atagen2026-10-22 12:30 UTC582
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC583
7ff8adafe9e4atagen2026-10-22 12:30 UTC584
    /// Get the room id if the verification is happening inside a room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC585
    pub fn room_id(&self) -> Option<String> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC586
        self.inner.room_id().map(|r| r.to_string())
7ff8adafe9e4atagen2026-10-22 12:30 UTC587
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC588
7ff8adafe9e4atagen2026-10-22 12:30 UTC589
    /// Has the verification flow that was started with this request finished.
7ff8adafe9e4atagen2026-10-22 12:30 UTC590
    pub fn is_done(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC591
        self.inner.is_done()
7ff8adafe9e4atagen2026-10-22 12:30 UTC592
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC593
7ff8adafe9e4atagen2026-10-22 12:30 UTC594
    /// Is the verification request ready to start a verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC595
    pub fn is_ready(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC596
        self.inner.is_ready()
7ff8adafe9e4atagen2026-10-22 12:30 UTC597
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC598
7ff8adafe9e4atagen2026-10-22 12:30 UTC599
    /// Did we initiate the verification request
7ff8adafe9e4atagen2026-10-22 12:30 UTC600
    pub fn we_started(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC601
        self.inner.we_started()
7ff8adafe9e4atagen2026-10-22 12:30 UTC602
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC603
7ff8adafe9e4atagen2026-10-22 12:30 UTC604
    /// Has the verification request been answered by another device.
7ff8adafe9e4atagen2026-10-22 12:30 UTC605
    pub fn is_passive(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC606
        self.inner.is_passive()
7ff8adafe9e4atagen2026-10-22 12:30 UTC607
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC608
7ff8adafe9e4atagen2026-10-22 12:30 UTC609
    /// Has the verification flow that been cancelled.
7ff8adafe9e4atagen2026-10-22 12:30 UTC610
    pub fn is_cancelled(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC611
        self.inner.is_cancelled()
7ff8adafe9e4atagen2026-10-22 12:30 UTC612
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC613
7ff8adafe9e4atagen2026-10-22 12:30 UTC614
    /// Get info about the cancellation if the verification request has been
7ff8adafe9e4atagen2026-10-22 12:30 UTC615
    /// cancelled.
7ff8adafe9e4atagen2026-10-22 12:30 UTC616
    pub fn cancel_info(&self) -> Option<CancelInfo> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC617
        self.inner.cancel_info().map(|v| v.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC618
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC619
7ff8adafe9e4atagen2026-10-22 12:30 UTC620
    /// Get the supported verification methods of the other side.
7ff8adafe9e4atagen2026-10-22 12:30 UTC621
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC622
    /// Will be present only if the other side requested the verification or if
7ff8adafe9e4atagen2026-10-22 12:30 UTC623
    /// we're in the ready state.
7ff8adafe9e4atagen2026-10-22 12:30 UTC624
    pub fn their_supported_methods(&self) -> Option<Vec<String>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC625
        self.inner.their_supported_methods().map(|m| m.iter().map(|m| m.to_string()).collect())
7ff8adafe9e4atagen2026-10-22 12:30 UTC626
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC627
7ff8adafe9e4atagen2026-10-22 12:30 UTC628
    /// Get our own supported verification methods that we advertised.
7ff8adafe9e4atagen2026-10-22 12:30 UTC629
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC630
    /// Will be present only we requested the verification or if we're in the
7ff8adafe9e4atagen2026-10-22 12:30 UTC631
    /// ready state.
7ff8adafe9e4atagen2026-10-22 12:30 UTC632
    pub fn our_supported_methods(&self) -> Option<Vec<String>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC633
        self.inner.our_supported_methods().map(|m| m.iter().map(|m| m.to_string()).collect())
7ff8adafe9e4atagen2026-10-22 12:30 UTC634
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC635
7ff8adafe9e4atagen2026-10-22 12:30 UTC636
    /// Accept a verification requests that we share with the given user with
7ff8adafe9e4atagen2026-10-22 12:30 UTC637
    /// the given flow id.
7ff8adafe9e4atagen2026-10-22 12:30 UTC638
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC639
    /// This will move the verification request into the ready state.
7ff8adafe9e4atagen2026-10-22 12:30 UTC640
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC641
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC642
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC643
    /// * `user_id` - The ID of the user for which we would like to accept the
7ff8adafe9e4atagen2026-10-22 12:30 UTC644
    ///   verification requests.
7ff8adafe9e4atagen2026-10-22 12:30 UTC645
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC646
    /// * `flow_id` - The ID that uniquely identifies the verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC647
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC648
    /// * `methods` - A list of verification methods that we want to advertise
7ff8adafe9e4atagen2026-10-22 12:30 UTC649
    ///   as supported.
7ff8adafe9e4atagen2026-10-22 12:30 UTC650
    pub fn accept(&self, methods: Vec<String>) -> Option<OutgoingVerificationRequest> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC651
        let methods = methods.into_iter().map(VerificationMethod::from).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC652
        self.inner.accept_with_methods(methods).map(|r| r.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC653
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC654
7ff8adafe9e4atagen2026-10-22 12:30 UTC655
    /// Cancel a verification for the given user with the given flow id using
7ff8adafe9e4atagen2026-10-22 12:30 UTC656
    /// the given cancel code.
7ff8adafe9e4atagen2026-10-22 12:30 UTC657
    pub fn cancel(&self) -> Option<OutgoingVerificationRequest> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC658
        self.inner.cancel().map(|r| r.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC659
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC660
7ff8adafe9e4atagen2026-10-22 12:30 UTC661
    /// Transition from a verification request into short auth string based
7ff8adafe9e4atagen2026-10-22 12:30 UTC662
    /// verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC663
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC664
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC665
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC666
    /// * `user_id` - The ID of the user for which we would like to start the
7ff8adafe9e4atagen2026-10-22 12:30 UTC667
    ///   SAS verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC668
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC669
    /// * `flow_id` - The ID of the verification request that initiated the
7ff8adafe9e4atagen2026-10-22 12:30 UTC670
    ///   verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC671
    pub fn start_sas_verification(&self) -> Result<Option<StartSasResult>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC672
        Ok(self.runtime.block_on(self.inner.start_sas())?.map(|(sas, r)| StartSasResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC673
            sas: Arc::new(Sas { inner: Box::new(sas), runtime: self.runtime.clone() }),
7ff8adafe9e4atagen2026-10-22 12:30 UTC674
            request: r.into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC675
        }))
7ff8adafe9e4atagen2026-10-22 12:30 UTC676
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC677
7ff8adafe9e4atagen2026-10-22 12:30 UTC678
    /// Transition from a verification request into QR code verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC679
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC680
    /// This method should be called when one wants to display a QR code so the
7ff8adafe9e4atagen2026-10-22 12:30 UTC681
    /// other side can scan it and move the QR code verification forward.
7ff8adafe9e4atagen2026-10-22 12:30 UTC682
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC683
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC684
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC685
    /// * `user_id` - The ID of the user for which we would like to start the QR
7ff8adafe9e4atagen2026-10-22 12:30 UTC686
    ///   code verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC687
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC688
    /// * `flow_id` - The ID of the verification request that initiated the
7ff8adafe9e4atagen2026-10-22 12:30 UTC689
    ///   verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC690
    pub fn start_qr_verification(&self) -> Result<Option<Arc<QrCode>>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC691
        Ok(self
7ff8adafe9e4atagen2026-10-22 12:30 UTC692
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC693
            .block_on(self.inner.generate_qr_code())?
7ff8adafe9e4atagen2026-10-22 12:30 UTC694
            .map(|qr| QrCode { inner: Box::new(qr), runtime: self.runtime.clone() }.into()))
7ff8adafe9e4atagen2026-10-22 12:30 UTC695
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC696
7ff8adafe9e4atagen2026-10-22 12:30 UTC697
    /// Pass data from a scanned QR code to an active verification request and
7ff8adafe9e4atagen2026-10-22 12:30 UTC698
    /// transition into QR code verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC699
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC700
    /// This requires an active `VerificationRequest` to succeed, returns `None`
7ff8adafe9e4atagen2026-10-22 12:30 UTC701
    /// if no `VerificationRequest` is found or if the QR code data is invalid.
7ff8adafe9e4atagen2026-10-22 12:30 UTC702
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC703
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC704
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC705
    /// * `user_id` - The ID of the user for which we would like to start the QR
7ff8adafe9e4atagen2026-10-22 12:30 UTC706
    ///   code verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC707
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC708
    /// * `flow_id` - The ID of the verification request that initiated the
7ff8adafe9e4atagen2026-10-22 12:30 UTC709
    ///   verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC710
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC711
    /// * `data` - The data that was extracted from the scanned QR code as an
7ff8adafe9e4atagen2026-10-22 12:30 UTC712
    ///   base64 encoded string, without padding.
7ff8adafe9e4atagen2026-10-22 12:30 UTC713
    pub fn scan_qr_code(&self, data: String) -> Option<ScanResult> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC714
        let data = base64_decode(data).ok()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC715
        let data = QrVerificationData::from_bytes(data).ok()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC716
7ff8adafe9e4atagen2026-10-22 12:30 UTC717
        if let Some(qr) = self.runtime.block_on(self.inner.scan_qr_code(data)).ok()? {
7ff8adafe9e4atagen2026-10-22 12:30 UTC718
            let request = qr.reciprocate()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC719
7ff8adafe9e4atagen2026-10-22 12:30 UTC720
            Some(ScanResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC721
                qr: QrCode { inner: Box::new(qr), runtime: self.runtime.clone() }.into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC722
                request: request.into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC723
            })
7ff8adafe9e4atagen2026-10-22 12:30 UTC724
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC725
            None
7ff8adafe9e4atagen2026-10-22 12:30 UTC726
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC727
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC728
7ff8adafe9e4atagen2026-10-22 12:30 UTC729
    /// Set a listener for changes in the verification request
7ff8adafe9e4atagen2026-10-22 12:30 UTC730
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC731
    /// The given callback will be called whenever the state changes.
7ff8adafe9e4atagen2026-10-22 12:30 UTC732
    pub fn set_changes_listener(&self, listener: Box<dyn VerificationRequestListener>) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC733
        let stream = self.inner.changes();
7ff8adafe9e4atagen2026-10-22 12:30 UTC734
7ff8adafe9e4atagen2026-10-22 12:30 UTC735
        self.runtime.spawn(Self::changes_listener(self.inner.to_owned(), stream, listener));
7ff8adafe9e4atagen2026-10-22 12:30 UTC736
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC737
7ff8adafe9e4atagen2026-10-22 12:30 UTC738
    /// Get the current state of the verification request.
7ff8adafe9e4atagen2026-10-22 12:30 UTC739
    pub fn state(&self) -> VerificationRequestState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC740
        Self::convert_verification_request(&self.inner, self.inner.state())
7ff8adafe9e4atagen2026-10-22 12:30 UTC741
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC742
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC743
7ff8adafe9e4atagen2026-10-22 12:30 UTC744
impl VerificationRequest {
7ff8adafe9e4atagen2026-10-22 12:30 UTC745
    fn convert_verification_request(
7ff8adafe9e4atagen2026-10-22 12:30 UTC746
        request: &InnerVerificationRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC747
        value: RustVerificationRequestState,
7ff8adafe9e4atagen2026-10-22 12:30 UTC748
    ) -> VerificationRequestState {
7ff8adafe9e4atagen2026-10-22 12:30 UTC749
        match value {
7ff8adafe9e4atagen2026-10-22 12:30 UTC750
            // The clients do not need to distinguish `Created` and `Requested` state
7ff8adafe9e4atagen2026-10-22 12:30 UTC751
            RustVerificationRequestState::Created { .. } => VerificationRequestState::Requested,
7ff8adafe9e4atagen2026-10-22 12:30 UTC752
            RustVerificationRequestState::Requested { .. } => VerificationRequestState::Requested,
7ff8adafe9e4atagen2026-10-22 12:30 UTC753
            RustVerificationRequestState::Ready {
7ff8adafe9e4atagen2026-10-22 12:30 UTC754
                their_methods,
7ff8adafe9e4atagen2026-10-22 12:30 UTC755
                our_methods,
7ff8adafe9e4atagen2026-10-22 12:30 UTC756
                other_device_data: _,
7ff8adafe9e4atagen2026-10-22 12:30 UTC757
            } => VerificationRequestState::Ready {
7ff8adafe9e4atagen2026-10-22 12:30 UTC758
                their_methods: their_methods.iter().map(|m| m.to_string()).collect(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC759
                our_methods: our_methods.iter().map(|m| m.to_string()).collect(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC760
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC761
            RustVerificationRequestState::Done => VerificationRequestState::Done,
7ff8adafe9e4atagen2026-10-22 12:30 UTC762
            RustVerificationRequestState::Transitioned { .. } => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC763
                let their_methods = request
7ff8adafe9e4atagen2026-10-22 12:30 UTC764
                    .their_supported_methods()
7ff8adafe9e4atagen2026-10-22 12:30 UTC765
                    .expect("The transitioned state should know the other side's methods")
7ff8adafe9e4atagen2026-10-22 12:30 UTC766
                    .into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC767
                    .map(|m| m.to_string())
7ff8adafe9e4atagen2026-10-22 12:30 UTC768
                    .collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC769
                let our_methods = request
7ff8adafe9e4atagen2026-10-22 12:30 UTC770
                    .our_supported_methods()
7ff8adafe9e4atagen2026-10-22 12:30 UTC771
                    .expect("The transitioned state should know our own supported methods")
7ff8adafe9e4atagen2026-10-22 12:30 UTC772
                    .iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC773
                    .map(|m| m.to_string())
7ff8adafe9e4atagen2026-10-22 12:30 UTC774
                    .collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC775
                VerificationRequestState::Ready { their_methods, our_methods }
7ff8adafe9e4atagen2026-10-22 12:30 UTC776
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC777
7ff8adafe9e4atagen2026-10-22 12:30 UTC778
            RustVerificationRequestState::Cancelled(c) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC779
                VerificationRequestState::Cancelled { cancel_info: c.into() }
7ff8adafe9e4atagen2026-10-22 12:30 UTC780
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC781
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC782
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC783
7ff8adafe9e4atagen2026-10-22 12:30 UTC784
    async fn changes_listener(
7ff8adafe9e4atagen2026-10-22 12:30 UTC785
        request: InnerVerificationRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC786
        mut stream: impl Stream<Item = RustVerificationRequestState> + std::marker::Unpin,
7ff8adafe9e4atagen2026-10-22 12:30 UTC787
        listener: Box<dyn VerificationRequestListener>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC788
    ) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC789
        while let Some(state) = stream.next().await {
7ff8adafe9e4atagen2026-10-22 12:30 UTC790
            // If we receive a done or a cancelled state we're at the end of our road, we
7ff8adafe9e4atagen2026-10-22 12:30 UTC791
            // break out of the loop to deallocate the stream and finish the
7ff8adafe9e4atagen2026-10-22 12:30 UTC792
            // task.
7ff8adafe9e4atagen2026-10-22 12:30 UTC793
            let should_break = matches!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC794
                state,
7ff8adafe9e4atagen2026-10-22 12:30 UTC795
                RustVerificationRequestState::Done | RustVerificationRequestState::Cancelled { .. }
7ff8adafe9e4atagen2026-10-22 12:30 UTC796
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC797
7ff8adafe9e4atagen2026-10-22 12:30 UTC798
            let state = Self::convert_verification_request(&request, state);
7ff8adafe9e4atagen2026-10-22 12:30 UTC799
7ff8adafe9e4atagen2026-10-22 12:30 UTC800
            listener.on_change(state);
7ff8adafe9e4atagen2026-10-22 12:30 UTC801
7ff8adafe9e4atagen2026-10-22 12:30 UTC802
            if should_break {
7ff8adafe9e4atagen2026-10-22 12:30 UTC803
                break;
7ff8adafe9e4atagen2026-10-22 12:30 UTC804
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC805
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC806
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC807
}