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/machine.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
use std::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
    collections::{BTreeMap, HashMap},
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
    io::Cursor,
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
    mem::ManuallyDrop,
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
    ops::Deref,
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
    sync::Arc,
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
    time::Duration,
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
use js_int::UInt;
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
use matrix_sdk_common::deserialized_responses::AlgorithmInfo;
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
use matrix_sdk_crypto::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
    CollectStrategy, DecryptionSettings, LocalTrust, OlmMachine as InnerMachine,
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
    UserIdentity as SdkUserIdentity,
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
    backups::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
        MegolmV1BackupKey as RustBackupKey, SignatureState,
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
        SignatureVerification as RustSignatureCheckResult,
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
    decrypt_room_key_export, encrypt_room_key_export,
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
    olm::ExportedRoomKey,
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
    store::types::{BackupDecryptionKey, Changes},
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
    types::requests::ToDeviceRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
use ruma::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
    DeviceKeyAlgorithm, EventId, OneTimeKeyAlgorithm, OwnedTransactionId, OwnedUserId, RoomId,
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
    UserId,
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
    api::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
        IncomingResponse,
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
        client::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
            backup::add_backup_keys::v3::Response as KeysBackupResponse,
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
            keys::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
                claim_keys::v3::Response as KeysClaimResponse,
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
                get_keys::v3::Response as KeysQueryResponse,
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
                upload_keys::v3::Response as KeysUploadResponse,
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
                upload_signatures::v3::Response as SignatureUploadResponse,
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
            message::send_message_event::v3::Response as RoomMessageResponse,
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
            sync::sync_events::{DeviceLists as RumaDeviceLists, v3::ToDevice},
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
            to_device::send_event_to_device::v3::Response as ToDeviceResponse,
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
        },
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
    events::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
        AnyMessageLikeEvent, AnySyncMessageLikeEvent, AnyTimelineEvent, MessageLikeEvent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
        key::verification::VerificationMethod, room::message::MessageType,
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
    serde::Raw,
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
    to_device::DeviceIdOrAllDevices,
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
use serde::{Deserialize, Serialize};
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
use serde_json::{Value, value::RawValue};
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
use tokio::runtime::Runtime;
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
use zeroize::Zeroize;
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
use crate::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
    BackupKeys, BackupRecoveryKey, BootstrapCrossSigningResult, CrossSigningKeyExport,
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
    CrossSigningStatus, DecodeError, DecryptedEvent, Device, DeviceLists, EncryptionSettings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
    EventEncryptionAlgorithm, KeyImportError, KeysImportResult, MegolmV1BackupKey,
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
    ProgressListener, Request, RequestType, RequestVerificationResult, RoomKeyCounts, RoomSettings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
    Sas, SignatureUploadRequest, StartSasResult, UserIdentity, Verification, VerificationRequest,
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
    dehydrated_devices::DehydratedDevices,
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
    error::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
        CryptoStoreError, DecryptionError, SecretImportError, SecretsBundleExportError,
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
        SignatureError,
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
    parse_user_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
    responses::{OwnedResponse, response_from_string},
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
/// The return value for the [`OlmMachine::receive_sync_changes()`] method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
/// Will contain various information about the `/sync` changes the
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
/// [`OlmMachine`] processed.
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
#[derive(uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
pub struct SyncChangesResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
    /// The, now possibly decrypted, to-device events the [`OlmMachine`]
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
    /// received, decrypted, and processed.
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
    to_device_events: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
    /// Information about the room keys that were extracted out of the to-device
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
    /// events.
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
    room_key_infos: Vec<RoomKeyInfo>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
/// Information on a room key that has been received or imported.
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
#[derive(uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
pub struct RoomKeyInfo {
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
    /// The [messaging algorithm] that this key is used for. Will be one of the
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
    /// `m.megolm.*` algorithms.
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
    /// [messaging algorithm]: https://spec.matrix.org/v1.6/client-server-api/#messaging-algorithms
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
    pub algorithm: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
    /// The room where the key is used.
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
    pub room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
    /// The Curve25519 key of the device which initiated the session originally.
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
    pub sender_key: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
    /// The ID of the session that the key is for.
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
    pub session_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
impl From<matrix_sdk_crypto::store::types::RoomKeyInfo> for RoomKeyInfo {
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
    fn from(value: matrix_sdk_crypto::store::types::RoomKeyInfo) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
        Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
            algorithm: value.algorithm.to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
            room_id: value.room_id.to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
            sender_key: value.sender_key.to_base64(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
            session_id: value.session_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
/// A high level state machine that handles E2EE for Matrix.
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
#[derive(uniffi::Object)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
pub struct OlmMachine {
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
    pub(crate) inner: ManuallyDrop<InnerMachine>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
    pub(crate) runtime: Runtime,
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
7ff8adafe9e4atagen2026-10-22 12:30 UTC121
impl Drop for OlmMachine {
7ff8adafe9e4atagen2026-10-22 12:30 UTC122
    fn drop(&mut self) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC123
        // Dropping the inner OlmMachine must happen within a tokio context
7ff8adafe9e4atagen2026-10-22 12:30 UTC124
        // because deadpool drops sqlite connections in the DB pool on tokio's
7ff8adafe9e4atagen2026-10-22 12:30 UTC125
        // blocking threadpool to avoid blocking async worker threads.
7ff8adafe9e4atagen2026-10-22 12:30 UTC126
        let _guard = self.runtime.enter();
7ff8adafe9e4atagen2026-10-22 12:30 UTC127
        // SAFETY: self.inner is never used again, which is the only requirement
7ff8adafe9e4atagen2026-10-22 12:30 UTC128
        //         for ManuallyDrop::drop to be used safely.
7ff8adafe9e4atagen2026-10-22 12:30 UTC129
        unsafe {
7ff8adafe9e4atagen2026-10-22 12:30 UTC130
            ManuallyDrop::drop(&mut self.inner);
7ff8adafe9e4atagen2026-10-22 12:30 UTC131
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC132
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC133
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC134
7ff8adafe9e4atagen2026-10-22 12:30 UTC135
/// A pair of outgoing room key requests, both of those are sendToDevice
7ff8adafe9e4atagen2026-10-22 12:30 UTC136
/// requests.
7ff8adafe9e4atagen2026-10-22 12:30 UTC137
#[derive(uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC138
pub struct KeyRequestPair {
7ff8adafe9e4atagen2026-10-22 12:30 UTC139
    /// The optional cancellation, this is None if no previous key request was
7ff8adafe9e4atagen2026-10-22 12:30 UTC140
    /// sent out for this key, thus it doesn't need to be cancelled.
7ff8adafe9e4atagen2026-10-22 12:30 UTC141
    pub cancellation: Option<Request>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC142
    /// The actual key request.
7ff8adafe9e4atagen2026-10-22 12:30 UTC143
    pub key_request: Request,
7ff8adafe9e4atagen2026-10-22 12:30 UTC144
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC145
7ff8adafe9e4atagen2026-10-22 12:30 UTC146
/// The result of a signature verification of a signed JSON object.
7ff8adafe9e4atagen2026-10-22 12:30 UTC147
#[derive(Clone, Debug, PartialEq, Eq, uniffi::Record)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC148
pub struct SignatureVerification {
7ff8adafe9e4atagen2026-10-22 12:30 UTC149
    /// The result of the signature verification using the public key of our own
7ff8adafe9e4atagen2026-10-22 12:30 UTC150
    /// device.
7ff8adafe9e4atagen2026-10-22 12:30 UTC151
    pub device_signature: SignatureState,
7ff8adafe9e4atagen2026-10-22 12:30 UTC152
    /// The result of the signature verification using the public key of our own
7ff8adafe9e4atagen2026-10-22 12:30 UTC153
    /// user identity.
7ff8adafe9e4atagen2026-10-22 12:30 UTC154
    pub user_identity_signature: SignatureState,
7ff8adafe9e4atagen2026-10-22 12:30 UTC155
    /// The result of the signature verification using public keys of other
7ff8adafe9e4atagen2026-10-22 12:30 UTC156
    /// devices we own.
7ff8adafe9e4atagen2026-10-22 12:30 UTC157
    pub other_devices_signatures: HashMap<String, SignatureState>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC158
    /// Is the signed JSON object trusted.
7ff8adafe9e4atagen2026-10-22 12:30 UTC159
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC160
    /// This flag tells us if the result has a valid signature from any of the
7ff8adafe9e4atagen2026-10-22 12:30 UTC161
    /// following:
7ff8adafe9e4atagen2026-10-22 12:30 UTC162
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC163
    /// * Our own device
7ff8adafe9e4atagen2026-10-22 12:30 UTC164
    /// * Our own user identity, provided the identity is trusted as well
7ff8adafe9e4atagen2026-10-22 12:30 UTC165
    /// * Any of our own devices, provided the device is trusted as well
7ff8adafe9e4atagen2026-10-22 12:30 UTC166
    pub trusted: bool,
7ff8adafe9e4atagen2026-10-22 12:30 UTC167
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC168
7ff8adafe9e4atagen2026-10-22 12:30 UTC169
impl From<RustSignatureCheckResult> for SignatureVerification {
7ff8adafe9e4atagen2026-10-22 12:30 UTC170
    fn from(r: RustSignatureCheckResult) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC171
        let trusted = r.trusted();
7ff8adafe9e4atagen2026-10-22 12:30 UTC172
7ff8adafe9e4atagen2026-10-22 12:30 UTC173
        Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC174
            device_signature: r.device_signature,
7ff8adafe9e4atagen2026-10-22 12:30 UTC175
            user_identity_signature: r.user_identity_signature,
7ff8adafe9e4atagen2026-10-22 12:30 UTC176
            other_devices_signatures: r
7ff8adafe9e4atagen2026-10-22 12:30 UTC177
                .other_signatures
7ff8adafe9e4atagen2026-10-22 12:30 UTC178
                .into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC179
                .map(|(k, v)| (k.to_string(), v))
7ff8adafe9e4atagen2026-10-22 12:30 UTC180
                .collect(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC181
            trusted,
7ff8adafe9e4atagen2026-10-22 12:30 UTC182
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC183
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC184
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC185
7ff8adafe9e4atagen2026-10-22 12:30 UTC186
#[matrix_sdk_ffi_macros::export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC187
impl OlmMachine {
7ff8adafe9e4atagen2026-10-22 12:30 UTC188
    /// Create a new `OlmMachine`
7ff8adafe9e4atagen2026-10-22 12:30 UTC189
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC190
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC191
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC192
    /// * `user_id` - The unique ID of the user that owns this machine.
7ff8adafe9e4atagen2026-10-22 12:30 UTC193
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC194
    /// * `device_id` - The unique ID of the device that owns this machine.
7ff8adafe9e4atagen2026-10-22 12:30 UTC195
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC196
    /// * `path` - The path where the state of the machine should be persisted.
7ff8adafe9e4atagen2026-10-22 12:30 UTC197
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC198
    /// * `passphrase` - The passphrase that should be used to encrypt the data
7ff8adafe9e4atagen2026-10-22 12:30 UTC199
    ///   at rest in the crypto store. **Warning**, if no passphrase is given,
7ff8adafe9e4atagen2026-10-22 12:30 UTC200
    ///   the store and all its data will remain unencrypted.
7ff8adafe9e4atagen2026-10-22 12:30 UTC201
    #[uniffi::constructor]
7ff8adafe9e4atagen2026-10-22 12:30 UTC202
    pub fn new(
7ff8adafe9e4atagen2026-10-22 12:30 UTC203
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC204
        device_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC205
        path: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC206
        mut passphrase: Option<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC207
    ) -> Result<Arc<Self>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC208
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC209
        let device_id = device_id.as_str().into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC210
        let runtime = Runtime::new().expect("Couldn't create a tokio runtime");
7ff8adafe9e4atagen2026-10-22 12:30 UTC211
7ff8adafe9e4atagen2026-10-22 12:30 UTC212
        let store = runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC213
            .block_on(matrix_sdk_sqlite::SqliteCryptoStore::open(path, passphrase.as_deref()))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC214
7ff8adafe9e4atagen2026-10-22 12:30 UTC215
        passphrase.zeroize();
7ff8adafe9e4atagen2026-10-22 12:30 UTC216
7ff8adafe9e4atagen2026-10-22 12:30 UTC217
        let inner = runtime.block_on(InnerMachine::with_store(
7ff8adafe9e4atagen2026-10-22 12:30 UTC218
            &user_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC219
            device_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC220
            Arc::new(store),
7ff8adafe9e4atagen2026-10-22 12:30 UTC221
            None,
7ff8adafe9e4atagen2026-10-22 12:30 UTC222
        ))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC223
7ff8adafe9e4atagen2026-10-22 12:30 UTC224
        Ok(Arc::new(OlmMachine { inner: ManuallyDrop::new(inner), runtime }))
7ff8adafe9e4atagen2026-10-22 12:30 UTC225
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC226
7ff8adafe9e4atagen2026-10-22 12:30 UTC227
    /// Get the user ID of the owner of this `OlmMachine`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC228
    pub fn user_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC229
        self.inner.user_id().to_string()
7ff8adafe9e4atagen2026-10-22 12:30 UTC230
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC231
7ff8adafe9e4atagen2026-10-22 12:30 UTC232
    /// Get the device ID of the device of this `OlmMachine`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC233
    pub fn device_id(&self) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC234
        self.inner.device_id().to_string()
7ff8adafe9e4atagen2026-10-22 12:30 UTC235
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC236
7ff8adafe9e4atagen2026-10-22 12:30 UTC237
    /// Get our own identity keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC238
    pub fn identity_keys(&self) -> HashMap<String, String> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC239
        let identity_keys = self.inner.identity_keys();
7ff8adafe9e4atagen2026-10-22 12:30 UTC240
        let curve_key = identity_keys.curve25519.to_base64();
7ff8adafe9e4atagen2026-10-22 12:30 UTC241
        let ed25519_key = identity_keys.ed25519.to_base64();
7ff8adafe9e4atagen2026-10-22 12:30 UTC242
7ff8adafe9e4atagen2026-10-22 12:30 UTC243
        HashMap::from([("ed25519".to_owned(), ed25519_key), ("curve25519".to_owned(), curve_key)])
7ff8adafe9e4atagen2026-10-22 12:30 UTC244
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC245
7ff8adafe9e4atagen2026-10-22 12:30 UTC246
    /// Get the status of the private cross signing keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC247
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC248
    /// This can be used to check which private cross signing keys we have
7ff8adafe9e4atagen2026-10-22 12:30 UTC249
    /// stored locally.
7ff8adafe9e4atagen2026-10-22 12:30 UTC250
    pub fn cross_signing_status(&self) -> CrossSigningStatus {
7ff8adafe9e4atagen2026-10-22 12:30 UTC251
        self.runtime.block_on(self.inner.cross_signing_status()).into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC252
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC253
7ff8adafe9e4atagen2026-10-22 12:30 UTC254
    /// Get a cross signing user identity for the given user ID.
7ff8adafe9e4atagen2026-10-22 12:30 UTC255
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC256
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC257
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC258
    /// * `user_id` - The unique id of the user that the identity belongs to
7ff8adafe9e4atagen2026-10-22 12:30 UTC259
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC260
    /// * `timeout` - The time in seconds we should wait before returning if the
7ff8adafe9e4atagen2026-10-22 12:30 UTC261
    ///   user's device list has been marked as stale. Passing a 0 as the
7ff8adafe9e4atagen2026-10-22 12:30 UTC262
    ///   timeout means that we won't wait at all. **Note**, this assumes that
7ff8adafe9e4atagen2026-10-22 12:30 UTC263
    ///   the requests from [`OlmMachine::outgoing_requests`] are being
7ff8adafe9e4atagen2026-10-22 12:30 UTC264
    ///   processed and sent out. Namely, this waits for a `/keys/query`
7ff8adafe9e4atagen2026-10-22 12:30 UTC265
    ///   response to be received.
7ff8adafe9e4atagen2026-10-22 12:30 UTC266
    pub fn get_identity(
7ff8adafe9e4atagen2026-10-22 12:30 UTC267
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC268
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC269
        timeout: u32,
7ff8adafe9e4atagen2026-10-22 12:30 UTC270
    ) -> Result<Option<UserIdentity>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC271
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC272
7ff8adafe9e4atagen2026-10-22 12:30 UTC273
        let timeout = if timeout == 0 { None } else { Some(Duration::from_secs(timeout.into())) };
7ff8adafe9e4atagen2026-10-22 12:30 UTC274
7ff8adafe9e4atagen2026-10-22 12:30 UTC275
        Ok(
7ff8adafe9e4atagen2026-10-22 12:30 UTC276
            if let Some(identity) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC277
                self.runtime.block_on(self.inner.get_identity(&user_id, timeout))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC278
            {
7ff8adafe9e4atagen2026-10-22 12:30 UTC279
                Some(self.runtime.block_on(UserIdentity::from_rust(identity))?)
7ff8adafe9e4atagen2026-10-22 12:30 UTC280
            } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC281
                None
7ff8adafe9e4atagen2026-10-22 12:30 UTC282
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC283
        )
7ff8adafe9e4atagen2026-10-22 12:30 UTC284
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC285
7ff8adafe9e4atagen2026-10-22 12:30 UTC286
    /// Check if a user identity is considered to be verified by us.
7ff8adafe9e4atagen2026-10-22 12:30 UTC287
    pub fn is_identity_verified(&self, user_id: String) -> Result<bool, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC288
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC289
7ff8adafe9e4atagen2026-10-22 12:30 UTC290
        Ok(
7ff8adafe9e4atagen2026-10-22 12:30 UTC291
            if let Some(identity) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC292
                self.runtime.block_on(self.inner.get_identity(&user_id, None))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC293
            {
7ff8adafe9e4atagen2026-10-22 12:30 UTC294
                identity.is_verified()
7ff8adafe9e4atagen2026-10-22 12:30 UTC295
            } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC296
                false
7ff8adafe9e4atagen2026-10-22 12:30 UTC297
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC298
        )
7ff8adafe9e4atagen2026-10-22 12:30 UTC299
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC300
7ff8adafe9e4atagen2026-10-22 12:30 UTC301
    /// Manually the user with the given user ID.
7ff8adafe9e4atagen2026-10-22 12:30 UTC302
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC303
    /// This method will attempt to sign the user identity using either our
7ff8adafe9e4atagen2026-10-22 12:30 UTC304
    /// private cross signing key, for other user identities, or our device keys
7ff8adafe9e4atagen2026-10-22 12:30 UTC305
    /// for our own user identity.
7ff8adafe9e4atagen2026-10-22 12:30 UTC306
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC307
    /// This method can fail if we don't have the private part of our
7ff8adafe9e4atagen2026-10-22 12:30 UTC308
    /// user-signing key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC309
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC310
    /// Returns a request that needs to be sent out for the user identity to be
7ff8adafe9e4atagen2026-10-22 12:30 UTC311
    /// marked as verified.
7ff8adafe9e4atagen2026-10-22 12:30 UTC312
    pub fn verify_identity(
7ff8adafe9e4atagen2026-10-22 12:30 UTC313
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC314
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC315
    ) -> Result<SignatureUploadRequest, SignatureError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC316
        let user_id = UserId::parse(user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC317
7ff8adafe9e4atagen2026-10-22 12:30 UTC318
        let user_identity = self.runtime.block_on(self.inner.get_identity(&user_id, None))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC319
7ff8adafe9e4atagen2026-10-22 12:30 UTC320
        if let Some(user_identity) = user_identity {
7ff8adafe9e4atagen2026-10-22 12:30 UTC321
            Ok(match user_identity {
7ff8adafe9e4atagen2026-10-22 12:30 UTC322
                SdkUserIdentity::Own(i) => self.runtime.block_on(i.verify())?,
7ff8adafe9e4atagen2026-10-22 12:30 UTC323
                SdkUserIdentity::Other(i) => self.runtime.block_on(i.verify())?,
7ff8adafe9e4atagen2026-10-22 12:30 UTC324
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC325
            .into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC326
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC327
            Err(SignatureError::UnknownUserIdentity(user_id.to_string()))
7ff8adafe9e4atagen2026-10-22 12:30 UTC328
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC329
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC330
7ff8adafe9e4atagen2026-10-22 12:30 UTC331
    /// Get a `Device` from the store.
7ff8adafe9e4atagen2026-10-22 12:30 UTC332
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC333
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC334
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC335
    /// * `user_id` - The id of the device owner.
7ff8adafe9e4atagen2026-10-22 12:30 UTC336
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC337
    /// * `device_id` - The id of the device itself.
7ff8adafe9e4atagen2026-10-22 12:30 UTC338
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC339
    /// * `timeout` - The time in seconds we should wait before returning if the
7ff8adafe9e4atagen2026-10-22 12:30 UTC340
    ///   user's device list has been marked as stale. Passing a 0 as the
7ff8adafe9e4atagen2026-10-22 12:30 UTC341
    ///   timeout means that we won't wait at all. **Note**, this assumes that
7ff8adafe9e4atagen2026-10-22 12:30 UTC342
    ///   the requests from [`OlmMachine::outgoing_requests`] are being
7ff8adafe9e4atagen2026-10-22 12:30 UTC343
    ///   processed and sent out. Namely, this waits for a `/keys/query`
7ff8adafe9e4atagen2026-10-22 12:30 UTC344
    ///   response to be received.
7ff8adafe9e4atagen2026-10-22 12:30 UTC345
    pub fn get_device(
7ff8adafe9e4atagen2026-10-22 12:30 UTC346
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC347
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC348
        device_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC349
        timeout: u32,
7ff8adafe9e4atagen2026-10-22 12:30 UTC350
    ) -> Result<Option<Device>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC351
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC352
7ff8adafe9e4atagen2026-10-22 12:30 UTC353
        let timeout = if timeout == 0 { None } else { Some(Duration::from_secs(timeout.into())) };
7ff8adafe9e4atagen2026-10-22 12:30 UTC354
7ff8adafe9e4atagen2026-10-22 12:30 UTC355
        Ok(self
7ff8adafe9e4atagen2026-10-22 12:30 UTC356
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC357
            .block_on(self.inner.get_device(&user_id, device_id.as_str().into(), timeout))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC358
            .map(|d| d.into()))
7ff8adafe9e4atagen2026-10-22 12:30 UTC359
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC360
7ff8adafe9e4atagen2026-10-22 12:30 UTC361
    /// Manually verify the device of the given user with the given device ID.
7ff8adafe9e4atagen2026-10-22 12:30 UTC362
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC363
    /// This method will attempt to sign the device using our private cross
7ff8adafe9e4atagen2026-10-22 12:30 UTC364
    /// signing key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC365
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC366
    /// This method will always fail if the device belongs to someone else, we
7ff8adafe9e4atagen2026-10-22 12:30 UTC367
    /// can only sign our own devices.
7ff8adafe9e4atagen2026-10-22 12:30 UTC368
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC369
    /// It can also fail if we don't have the private part of our self-signing
7ff8adafe9e4atagen2026-10-22 12:30 UTC370
    /// key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC371
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC372
    /// Returns a request that needs to be sent out for the device to be marked
7ff8adafe9e4atagen2026-10-22 12:30 UTC373
    /// as verified.
7ff8adafe9e4atagen2026-10-22 12:30 UTC374
    pub fn verify_device(
7ff8adafe9e4atagen2026-10-22 12:30 UTC375
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC376
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC377
        device_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC378
    ) -> Result<SignatureUploadRequest, SignatureError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC379
        let user_id = UserId::parse(user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC380
        let device = self.runtime.block_on(self.inner.get_device(
7ff8adafe9e4atagen2026-10-22 12:30 UTC381
            &user_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC382
            device_id.as_str().into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC383
            None,
7ff8adafe9e4atagen2026-10-22 12:30 UTC384
        ))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC385
7ff8adafe9e4atagen2026-10-22 12:30 UTC386
        if let Some(device) = device {
7ff8adafe9e4atagen2026-10-22 12:30 UTC387
            Ok(self.runtime.block_on(device.verify())?.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC388
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC389
            Err(SignatureError::UnknownDevice(user_id, device_id))
7ff8adafe9e4atagen2026-10-22 12:30 UTC390
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC391
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC392
7ff8adafe9e4atagen2026-10-22 12:30 UTC393
    /// Set local trust state for the device of the given user without creating
7ff8adafe9e4atagen2026-10-22 12:30 UTC394
    /// or uploading any signatures if verified
7ff8adafe9e4atagen2026-10-22 12:30 UTC395
    pub fn set_local_trust(
7ff8adafe9e4atagen2026-10-22 12:30 UTC396
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC397
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC398
        device_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC399
        trust_state: LocalTrust,
7ff8adafe9e4atagen2026-10-22 12:30 UTC400
    ) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC401
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC402
7ff8adafe9e4atagen2026-10-22 12:30 UTC403
        let device = self.runtime.block_on(self.inner.get_device(
7ff8adafe9e4atagen2026-10-22 12:30 UTC404
            &user_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC405
            device_id.as_str().into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC406
            None,
7ff8adafe9e4atagen2026-10-22 12:30 UTC407
        ))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC408
7ff8adafe9e4atagen2026-10-22 12:30 UTC409
        if let Some(device) = device {
7ff8adafe9e4atagen2026-10-22 12:30 UTC410
            self.runtime.block_on(device.set_local_trust(trust_state))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC411
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC412
7ff8adafe9e4atagen2026-10-22 12:30 UTC413
        Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC414
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC415
7ff8adafe9e4atagen2026-10-22 12:30 UTC416
    /// Get all devices of an user.
7ff8adafe9e4atagen2026-10-22 12:30 UTC417
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC418
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC419
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC420
    /// * `user_id` - The id of the device owner.
7ff8adafe9e4atagen2026-10-22 12:30 UTC421
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC422
    /// * `timeout` - The time in seconds we should wait before returning if the
7ff8adafe9e4atagen2026-10-22 12:30 UTC423
    ///   user's device list has been marked as stale. Passing a 0 as the
7ff8adafe9e4atagen2026-10-22 12:30 UTC424
    ///   timeout means that we won't wait at all. **Note**, this assumes that
7ff8adafe9e4atagen2026-10-22 12:30 UTC425
    ///   the requests from [`OlmMachine::outgoing_requests`] are being
7ff8adafe9e4atagen2026-10-22 12:30 UTC426
    ///   processed and sent out. Namely, this waits for a `/keys/query`
7ff8adafe9e4atagen2026-10-22 12:30 UTC427
    ///   response to be received.
7ff8adafe9e4atagen2026-10-22 12:30 UTC428
    pub fn get_user_devices(
7ff8adafe9e4atagen2026-10-22 12:30 UTC429
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC430
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC431
        timeout: u32,
7ff8adafe9e4atagen2026-10-22 12:30 UTC432
    ) -> Result<Vec<Device>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC433
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC434
7ff8adafe9e4atagen2026-10-22 12:30 UTC435
        let timeout = if timeout == 0 { None } else { Some(Duration::from_secs(timeout.into())) };
7ff8adafe9e4atagen2026-10-22 12:30 UTC436
        Ok(self
7ff8adafe9e4atagen2026-10-22 12:30 UTC437
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC438
            .block_on(self.inner.get_user_devices(&user_id, timeout))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC439
            .devices()
7ff8adafe9e4atagen2026-10-22 12:30 UTC440
            .map(|d| d.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC441
            .collect())
7ff8adafe9e4atagen2026-10-22 12:30 UTC442
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC443
7ff8adafe9e4atagen2026-10-22 12:30 UTC444
    /// Get the list of outgoing requests that need to be sent to the
7ff8adafe9e4atagen2026-10-22 12:30 UTC445
    /// homeserver.
7ff8adafe9e4atagen2026-10-22 12:30 UTC446
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC447
    /// After the request was sent out and a successful response was received
7ff8adafe9e4atagen2026-10-22 12:30 UTC448
    /// the response body should be passed back to the state machine using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC449
    /// [mark_request_as_sent()](Self::mark_request_as_sent) method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC450
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC451
    /// **Note**: This method call should be locked per call.
7ff8adafe9e4atagen2026-10-22 12:30 UTC452
    pub fn outgoing_requests(&self) -> Result<Vec<Request>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC453
        Ok(self
7ff8adafe9e4atagen2026-10-22 12:30 UTC454
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC455
            .block_on(self.inner.outgoing_requests())?
7ff8adafe9e4atagen2026-10-22 12:30 UTC456
            .into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC457
            .map(|r| r.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC458
            .collect())
7ff8adafe9e4atagen2026-10-22 12:30 UTC459
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC460
7ff8adafe9e4atagen2026-10-22 12:30 UTC461
    /// Mark a request that was sent to the server as sent.
7ff8adafe9e4atagen2026-10-22 12:30 UTC462
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC463
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC464
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC465
    /// * `request_id` - The unique ID of the request that was sent out. This
7ff8adafe9e4atagen2026-10-22 12:30 UTC466
    ///   needs to be an UUID.
7ff8adafe9e4atagen2026-10-22 12:30 UTC467
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC468
    /// * `request_type` - The type of the request that was sent out.
7ff8adafe9e4atagen2026-10-22 12:30 UTC469
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC470
    /// * `response_body` - The body of the response that was received.
7ff8adafe9e4atagen2026-10-22 12:30 UTC471
    pub fn mark_request_as_sent(
7ff8adafe9e4atagen2026-10-22 12:30 UTC472
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC473
        request_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC474
        request_type: RequestType,
7ff8adafe9e4atagen2026-10-22 12:30 UTC475
        response_body: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC476
    ) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC477
        let id: OwnedTransactionId = request_id.into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC478
7ff8adafe9e4atagen2026-10-22 12:30 UTC479
        let response = response_from_string(&response_body);
7ff8adafe9e4atagen2026-10-22 12:30 UTC480
7ff8adafe9e4atagen2026-10-22 12:30 UTC481
        let response: OwnedResponse = match request_type {
7ff8adafe9e4atagen2026-10-22 12:30 UTC482
            RequestType::KeysUpload => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC483
                KeysUploadResponse::try_from_http_response(response).map(Into::into)
7ff8adafe9e4atagen2026-10-22 12:30 UTC484
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC485
            RequestType::KeysQuery => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC486
                KeysQueryResponse::try_from_http_response(response).map(Into::into)
7ff8adafe9e4atagen2026-10-22 12:30 UTC487
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC488
            RequestType::ToDevice => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC489
                ToDeviceResponse::try_from_http_response(response).map(Into::into)
7ff8adafe9e4atagen2026-10-22 12:30 UTC490
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC491
            RequestType::KeysClaim => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC492
                KeysClaimResponse::try_from_http_response(response).map(Into::into)
7ff8adafe9e4atagen2026-10-22 12:30 UTC493
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC494
            RequestType::SignatureUpload => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC495
                SignatureUploadResponse::try_from_http_response(response).map(Into::into)
7ff8adafe9e4atagen2026-10-22 12:30 UTC496
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC497
            RequestType::KeysBackup => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC498
                KeysBackupResponse::try_from_http_response(response).map(Into::into)
7ff8adafe9e4atagen2026-10-22 12:30 UTC499
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC500
            RequestType::RoomMessage => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC501
                RoomMessageResponse::try_from_http_response(response).map(Into::into)
7ff8adafe9e4atagen2026-10-22 12:30 UTC502
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC503
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC504
        .expect("Can't convert json string to response");
7ff8adafe9e4atagen2026-10-22 12:30 UTC505
7ff8adafe9e4atagen2026-10-22 12:30 UTC506
        self.runtime.block_on(self.inner.mark_request_as_sent(&id, &response))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC507
7ff8adafe9e4atagen2026-10-22 12:30 UTC508
        Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC509
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC510
7ff8adafe9e4atagen2026-10-22 12:30 UTC511
    /// Let the state machine know about E2EE related sync changes that we
7ff8adafe9e4atagen2026-10-22 12:30 UTC512
    /// received from the server.
7ff8adafe9e4atagen2026-10-22 12:30 UTC513
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC514
    /// This needs to be called after every sync, ideally before processing
7ff8adafe9e4atagen2026-10-22 12:30 UTC515
    /// any other sync changes.
7ff8adafe9e4atagen2026-10-22 12:30 UTC516
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC517
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC518
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC519
    /// * `events` - A serialized array of to-device events we received in the
7ff8adafe9e4atagen2026-10-22 12:30 UTC520
    ///   current sync response.
7ff8adafe9e4atagen2026-10-22 12:30 UTC521
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC522
    /// * `device_changes` - The list of devices that have changed in some way
7ff8adafe9e4atagen2026-10-22 12:30 UTC523
    ///   since the previous sync.
7ff8adafe9e4atagen2026-10-22 12:30 UTC524
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC525
    /// * `key_counts` - The map of uploaded one-time key types and counts.
7ff8adafe9e4atagen2026-10-22 12:30 UTC526
    pub fn receive_sync_changes(
7ff8adafe9e4atagen2026-10-22 12:30 UTC527
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC528
        events: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC529
        device_changes: DeviceLists,
7ff8adafe9e4atagen2026-10-22 12:30 UTC530
        key_counts: HashMap<String, i32>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC531
        unused_fallback_keys: Option<Vec<String>>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC532
        next_batch_token: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC533
        decryption_settings: &DecryptionSettings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC534
    ) -> Result<SyncChangesResult, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC535
        let to_device: ToDevice = serde_json::from_str(&events)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC536
        let device_changes: RumaDeviceLists = device_changes.into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC537
        let key_counts: BTreeMap<OneTimeKeyAlgorithm, UInt> = key_counts
7ff8adafe9e4atagen2026-10-22 12:30 UTC538
            .into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC539
            .map(|(k, v)| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC540
                (
7ff8adafe9e4atagen2026-10-22 12:30 UTC541
                    OneTimeKeyAlgorithm::from(k),
7ff8adafe9e4atagen2026-10-22 12:30 UTC542
                    v.clamp(0, i32::MAX)
7ff8adafe9e4atagen2026-10-22 12:30 UTC543
                        .try_into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC544
                        .expect("Couldn't convert key counts into an UInt"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC545
                )
7ff8adafe9e4atagen2026-10-22 12:30 UTC546
            })
7ff8adafe9e4atagen2026-10-22 12:30 UTC547
            .collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC548
7ff8adafe9e4atagen2026-10-22 12:30 UTC549
        let unused_fallback_keys: Option<Vec<OneTimeKeyAlgorithm>> =
7ff8adafe9e4atagen2026-10-22 12:30 UTC550
            unused_fallback_keys.map(|u| u.into_iter().map(OneTimeKeyAlgorithm::from).collect());
7ff8adafe9e4atagen2026-10-22 12:30 UTC551
7ff8adafe9e4atagen2026-10-22 12:30 UTC552
        let (to_device_events, room_key_infos) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC553
            self.runtime.block_on(self.inner.receive_sync_changes(
7ff8adafe9e4atagen2026-10-22 12:30 UTC554
                matrix_sdk_crypto::EncryptionSyncChanges {
7ff8adafe9e4atagen2026-10-22 12:30 UTC555
                    to_device_events: to_device.events,
7ff8adafe9e4atagen2026-10-22 12:30 UTC556
                    changed_devices: &device_changes,
7ff8adafe9e4atagen2026-10-22 12:30 UTC557
                    one_time_keys_counts: &key_counts,
7ff8adafe9e4atagen2026-10-22 12:30 UTC558
                    unused_fallback_keys: unused_fallback_keys.as_deref(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC559
                    next_batch_token: Some(next_batch_token),
7ff8adafe9e4atagen2026-10-22 12:30 UTC560
                },
7ff8adafe9e4atagen2026-10-22 12:30 UTC561
                decryption_settings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC562
            ))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC563
7ff8adafe9e4atagen2026-10-22 12:30 UTC564
        let to_device_events = to_device_events
7ff8adafe9e4atagen2026-10-22 12:30 UTC565
            .into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC566
            .map(|event| event.to_raw().json().get().to_owned())
7ff8adafe9e4atagen2026-10-22 12:30 UTC567
            .collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC568
        let room_key_infos = room_key_infos.into_iter().map(|info| info.into()).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC569
7ff8adafe9e4atagen2026-10-22 12:30 UTC570
        Ok(SyncChangesResult { to_device_events, room_key_infos })
7ff8adafe9e4atagen2026-10-22 12:30 UTC571
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC572
7ff8adafe9e4atagen2026-10-22 12:30 UTC573
    /// Add the given list of users to be tracked, triggering a key query
7ff8adafe9e4atagen2026-10-22 12:30 UTC574
    /// request for them.
7ff8adafe9e4atagen2026-10-22 12:30 UTC575
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC576
    /// The OlmMachine maintains a list of users whose devices we are keeping
7ff8adafe9e4atagen2026-10-22 12:30 UTC577
    /// track of: these are known as "tracked users". These must be users
7ff8adafe9e4atagen2026-10-22 12:30 UTC578
    /// that we share a room with, so that the server sends us updates for
7ff8adafe9e4atagen2026-10-22 12:30 UTC579
    /// their device lists.
7ff8adafe9e4atagen2026-10-22 12:30 UTC580
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC581
    /// *Note*: Only users that aren't already tracked will be considered for an
7ff8adafe9e4atagen2026-10-22 12:30 UTC582
    /// update. It's safe to call this with already tracked users, it won't
7ff8adafe9e4atagen2026-10-22 12:30 UTC583
    /// result in excessive `/keys/query` requests.
7ff8adafe9e4atagen2026-10-22 12:30 UTC584
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC585
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC586
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC587
    /// `users` - The users that should be queued up for a key query.
7ff8adafe9e4atagen2026-10-22 12:30 UTC588
    pub fn update_tracked_users(&self, users: Vec<String>) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC589
        let users: Vec<OwnedUserId> =
7ff8adafe9e4atagen2026-10-22 12:30 UTC590
            users.into_iter().filter_map(|u| UserId::parse(u).ok()).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC591
7ff8adafe9e4atagen2026-10-22 12:30 UTC592
        self.runtime.block_on(self.inner.update_tracked_users(users.iter().map(Deref::deref)))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC593
7ff8adafe9e4atagen2026-10-22 12:30 UTC594
        Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC595
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC596
7ff8adafe9e4atagen2026-10-22 12:30 UTC597
    /// Check if the given user is considered to be tracked.
7ff8adafe9e4atagen2026-10-22 12:30 UTC598
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC599
    /// A user can be marked for tracking using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC600
    /// [`OlmMachine::update_tracked_users()`] method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC601
    pub fn is_user_tracked(&self, user_id: String) -> Result<bool, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC602
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC603
        Ok(self.runtime.block_on(self.inner.tracked_users())?.contains(&user_id))
7ff8adafe9e4atagen2026-10-22 12:30 UTC604
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC605
7ff8adafe9e4atagen2026-10-22 12:30 UTC606
    /// Generate one-time key claiming requests for all the users we are missing
7ff8adafe9e4atagen2026-10-22 12:30 UTC607
    /// sessions for.
7ff8adafe9e4atagen2026-10-22 12:30 UTC608
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC609
    /// After the request was sent out and a successful response was received
7ff8adafe9e4atagen2026-10-22 12:30 UTC610
    /// the response body should be passed back to the state machine using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC611
    /// [mark_request_as_sent()](Self::mark_request_as_sent) method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC612
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC613
    /// This method should be called every time before a call to
7ff8adafe9e4atagen2026-10-22 12:30 UTC614
    /// [`share_room_key()`](Self::share_room_key) is made.
7ff8adafe9e4atagen2026-10-22 12:30 UTC615
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC616
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC617
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC618
    /// * `users` - The list of users for which we would like to establish 1:1
7ff8adafe9e4atagen2026-10-22 12:30 UTC619
    ///   Olm sessions for.
7ff8adafe9e4atagen2026-10-22 12:30 UTC620
    pub fn get_missing_sessions(
7ff8adafe9e4atagen2026-10-22 12:30 UTC621
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC622
        users: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC623
    ) -> Result<Option<Request>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC624
        let users: Vec<OwnedUserId> =
7ff8adafe9e4atagen2026-10-22 12:30 UTC625
            users.into_iter().filter_map(|u| UserId::parse(u).ok()).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC626
7ff8adafe9e4atagen2026-10-22 12:30 UTC627
        Ok(self
7ff8adafe9e4atagen2026-10-22 12:30 UTC628
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC629
            .block_on(self.inner.get_missing_sessions(users.iter().map(Deref::deref)))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC630
            .map(|r| r.into()))
7ff8adafe9e4atagen2026-10-22 12:30 UTC631
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC632
7ff8adafe9e4atagen2026-10-22 12:30 UTC633
    /// Get the stored room settings, such as the encryption algorithm or
7ff8adafe9e4atagen2026-10-22 12:30 UTC634
    /// whether to encrypt only for trusted devices.
7ff8adafe9e4atagen2026-10-22 12:30 UTC635
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC636
    /// These settings can be modified via
7ff8adafe9e4atagen2026-10-22 12:30 UTC637
    /// [set_room_algorithm()](Self::set_room_algorithm) and
7ff8adafe9e4atagen2026-10-22 12:30 UTC638
    /// [set_room_only_allow_trusted_devices()](Self::set_room_only_allow_trusted_devices)
7ff8adafe9e4atagen2026-10-22 12:30 UTC639
    /// methods.
7ff8adafe9e4atagen2026-10-22 12:30 UTC640
    pub fn get_room_settings(
7ff8adafe9e4atagen2026-10-22 12:30 UTC641
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC642
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC643
    ) -> Result<Option<RoomSettings>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC644
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC645
        let settings = self
7ff8adafe9e4atagen2026-10-22 12:30 UTC646
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC647
            .block_on(self.inner.store().get_room_settings(&room_id))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC648
            .map(|v| v.try_into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC649
            .transpose()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC650
        Ok(settings)
7ff8adafe9e4atagen2026-10-22 12:30 UTC651
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC652
7ff8adafe9e4atagen2026-10-22 12:30 UTC653
    /// Set the room algorithm used for encrypting messages to one of the
7ff8adafe9e4atagen2026-10-22 12:30 UTC654
    /// available variants
7ff8adafe9e4atagen2026-10-22 12:30 UTC655
    pub fn set_room_algorithm(
7ff8adafe9e4atagen2026-10-22 12:30 UTC656
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC657
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC658
        algorithm: EventEncryptionAlgorithm,
7ff8adafe9e4atagen2026-10-22 12:30 UTC659
    ) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC660
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC661
        self.runtime.block_on(async move {
7ff8adafe9e4atagen2026-10-22 12:30 UTC662
            let mut settings =
7ff8adafe9e4atagen2026-10-22 12:30 UTC663
                self.inner.store().get_room_settings(&room_id).await?.unwrap_or_default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC664
            settings.algorithm = algorithm.into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC665
            self.inner
7ff8adafe9e4atagen2026-10-22 12:30 UTC666
                .store()
7ff8adafe9e4atagen2026-10-22 12:30 UTC667
                .save_changes(Changes {
7ff8adafe9e4atagen2026-10-22 12:30 UTC668
                    room_settings: HashMap::from([(room_id, settings)]),
7ff8adafe9e4atagen2026-10-22 12:30 UTC669
                    ..Default::default()
7ff8adafe9e4atagen2026-10-22 12:30 UTC670
                })
7ff8adafe9e4atagen2026-10-22 12:30 UTC671
                .await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC672
            Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC673
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC674
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC675
7ff8adafe9e4atagen2026-10-22 12:30 UTC676
    /// Set flag whether this room should encrypt messages for untrusted
7ff8adafe9e4atagen2026-10-22 12:30 UTC677
    /// devices, or whether they should be excluded from the conversation.
7ff8adafe9e4atagen2026-10-22 12:30 UTC678
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC679
    /// Note that per-room setting may be overridden by a global
7ff8adafe9e4atagen2026-10-22 12:30 UTC680
    /// [set_only_allow_trusted_devices()](Self::set_only_allow_trusted_devices)
7ff8adafe9e4atagen2026-10-22 12:30 UTC681
    /// method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC682
    pub fn set_room_only_allow_trusted_devices(
7ff8adafe9e4atagen2026-10-22 12:30 UTC683
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC684
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC685
        only_allow_trusted_devices: bool,
7ff8adafe9e4atagen2026-10-22 12:30 UTC686
    ) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC687
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC688
        self.runtime.block_on(async move {
7ff8adafe9e4atagen2026-10-22 12:30 UTC689
            let mut settings =
7ff8adafe9e4atagen2026-10-22 12:30 UTC690
                self.inner.store().get_room_settings(&room_id).await?.unwrap_or_default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC691
            settings.only_allow_trusted_devices = only_allow_trusted_devices;
7ff8adafe9e4atagen2026-10-22 12:30 UTC692
            self.inner
7ff8adafe9e4atagen2026-10-22 12:30 UTC693
                .store()
7ff8adafe9e4atagen2026-10-22 12:30 UTC694
                .save_changes(Changes {
7ff8adafe9e4atagen2026-10-22 12:30 UTC695
                    room_settings: HashMap::from([(room_id, settings)]),
7ff8adafe9e4atagen2026-10-22 12:30 UTC696
                    ..Default::default()
7ff8adafe9e4atagen2026-10-22 12:30 UTC697
                })
7ff8adafe9e4atagen2026-10-22 12:30 UTC698
                .await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC699
            Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC700
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC701
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC702
7ff8adafe9e4atagen2026-10-22 12:30 UTC703
    /// Check whether there is a global flag to only encrypt messages for
7ff8adafe9e4atagen2026-10-22 12:30 UTC704
    /// trusted devices or for everyone.
7ff8adafe9e4atagen2026-10-22 12:30 UTC705
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC706
    /// Note that if the global flag is false, individual rooms may still be
7ff8adafe9e4atagen2026-10-22 12:30 UTC707
    /// encrypting only for trusted devices, depending on the per-room
7ff8adafe9e4atagen2026-10-22 12:30 UTC708
    /// `only_allow_trusted_devices` flag.
7ff8adafe9e4atagen2026-10-22 12:30 UTC709
    pub fn get_only_allow_trusted_devices(&self) -> Result<bool, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC710
        let block = self.runtime.block_on(self.inner.store().get_only_allow_trusted_devices())?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC711
        Ok(block)
7ff8adafe9e4atagen2026-10-22 12:30 UTC712
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC713
7ff8adafe9e4atagen2026-10-22 12:30 UTC714
    /// Set global flag whether to encrypt messages for untrusted devices, or
7ff8adafe9e4atagen2026-10-22 12:30 UTC715
    /// whether they should be excluded from the conversation.
7ff8adafe9e4atagen2026-10-22 12:30 UTC716
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC717
    /// Note that if enabled, it will override any per-room settings.
7ff8adafe9e4atagen2026-10-22 12:30 UTC718
    pub fn set_only_allow_trusted_devices(
7ff8adafe9e4atagen2026-10-22 12:30 UTC719
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC720
        only_allow_trusted_devices: bool,
7ff8adafe9e4atagen2026-10-22 12:30 UTC721
    ) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC722
        self.runtime.block_on(
7ff8adafe9e4atagen2026-10-22 12:30 UTC723
            self.inner.store().set_only_allow_trusted_devices(only_allow_trusted_devices),
7ff8adafe9e4atagen2026-10-22 12:30 UTC724
        )?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC725
        Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC726
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC727
7ff8adafe9e4atagen2026-10-22 12:30 UTC728
    /// Share a room key with the given list of users for the given room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC729
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC730
    /// After the request was sent out and a successful response was received
7ff8adafe9e4atagen2026-10-22 12:30 UTC731
    /// the response body should be passed back to the state machine using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC732
    /// [mark_request_as_sent()](Self::mark_request_as_sent) method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC733
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC734
    /// This method should be called every time before a call to
7ff8adafe9e4atagen2026-10-22 12:30 UTC735
    /// [`encrypt()`](Self::encrypt) with the given `room_id` is made.
7ff8adafe9e4atagen2026-10-22 12:30 UTC736
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC737
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC738
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC739
    /// * `room_id` - The unique id of the room, note that this doesn't strictly
7ff8adafe9e4atagen2026-10-22 12:30 UTC740
    ///   need to be a Matrix room, it just needs to be an unique identifier for
7ff8adafe9e4atagen2026-10-22 12:30 UTC741
    ///   the group that will participate in the conversation.
7ff8adafe9e4atagen2026-10-22 12:30 UTC742
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC743
    /// * `users` - The list of users which are considered to be members of the
7ff8adafe9e4atagen2026-10-22 12:30 UTC744
    ///   room and should receive the room key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC745
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC746
    /// * `settings` - The settings that should be used for the room key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC747
    pub fn share_room_key(
7ff8adafe9e4atagen2026-10-22 12:30 UTC748
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC749
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC750
        users: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC751
        settings: EncryptionSettings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC752
    ) -> Result<Vec<Request>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC753
        let users: Vec<OwnedUserId> =
7ff8adafe9e4atagen2026-10-22 12:30 UTC754
            users.into_iter().filter_map(|u| UserId::parse(u).ok()).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC755
7ff8adafe9e4atagen2026-10-22 12:30 UTC756
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC757
        let requests = self.runtime.block_on(self.inner.share_room_key(
7ff8adafe9e4atagen2026-10-22 12:30 UTC758
            &room_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC759
            users.iter().map(Deref::deref),
7ff8adafe9e4atagen2026-10-22 12:30 UTC760
            settings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC761
        ))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC762
7ff8adafe9e4atagen2026-10-22 12:30 UTC763
        Ok(requests.into_iter().map(|r| r.as_ref().into()).collect())
7ff8adafe9e4atagen2026-10-22 12:30 UTC764
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC765
7ff8adafe9e4atagen2026-10-22 12:30 UTC766
    /// Encrypt the given event with the given type and content for the given
7ff8adafe9e4atagen2026-10-22 12:30 UTC767
    /// room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC768
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC769
    /// **Note**: A room key needs to be shared with the group of users that are
7ff8adafe9e4atagen2026-10-22 12:30 UTC770
    /// members in the given room. If this is not done this method will panic.
7ff8adafe9e4atagen2026-10-22 12:30 UTC771
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC772
    /// The usual flow to encrypt an event using this state machine is as
7ff8adafe9e4atagen2026-10-22 12:30 UTC773
    /// follows:
7ff8adafe9e4atagen2026-10-22 12:30 UTC774
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC775
    /// 1. Get the one-time key claim request to establish 1:1 Olm sessions for
7ff8adafe9e4atagen2026-10-22 12:30 UTC776
    ///    the room members of the room we wish to participate in. This is done
7ff8adafe9e4atagen2026-10-22 12:30 UTC777
    ///    using the [`get_missing_sessions()`](Self::get_missing_sessions)
7ff8adafe9e4atagen2026-10-22 12:30 UTC778
    ///    method. This method call should be locked per call.
7ff8adafe9e4atagen2026-10-22 12:30 UTC779
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC780
    /// 2. Share a room key with all the room members using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC781
    ///    [`share_room_key()`](Self::share_room_key). This method call should
7ff8adafe9e4atagen2026-10-22 12:30 UTC782
    ///    be locked per room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC783
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC784
    /// 3. Encrypt the event using this method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC785
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC786
    /// 4. Send the encrypted event to the server.
7ff8adafe9e4atagen2026-10-22 12:30 UTC787
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC788
    /// After the room key is shared steps 1 and 2 will become noops, unless
7ff8adafe9e4atagen2026-10-22 12:30 UTC789
    /// there's some changes in the room membership or in the list of devices a
7ff8adafe9e4atagen2026-10-22 12:30 UTC790
    /// member has.
7ff8adafe9e4atagen2026-10-22 12:30 UTC791
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC792
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC793
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC794
    /// * `room_id` - The unique id of the room where the event will be sent to.
7ff8adafe9e4atagen2026-10-22 12:30 UTC795
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC796
    /// * `even_type` - The type of the event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC797
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC798
    /// * `content` - The serialized content of the event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC799
    pub fn encrypt(
7ff8adafe9e4atagen2026-10-22 12:30 UTC800
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC801
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC802
        event_type: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC803
        content: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC804
    ) -> Result<String, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC805
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC806
        let content = serde_json::from_str(&content)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC807
7ff8adafe9e4atagen2026-10-22 12:30 UTC808
        let result = self
7ff8adafe9e4atagen2026-10-22 12:30 UTC809
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC810
            .block_on(self.inner.encrypt_room_event_raw(&room_id, &event_type, &content))
7ff8adafe9e4atagen2026-10-22 12:30 UTC811
            .expect("Encrypting an event produced an error");
7ff8adafe9e4atagen2026-10-22 12:30 UTC812
7ff8adafe9e4atagen2026-10-22 12:30 UTC813
        Ok(serde_json::to_string(&result.content)?)
7ff8adafe9e4atagen2026-10-22 12:30 UTC814
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC815
7ff8adafe9e4atagen2026-10-22 12:30 UTC816
    /// Encrypt the given event with the given type and content for the given
7ff8adafe9e4atagen2026-10-22 12:30 UTC817
    /// device. This method is used to send an event to a specific device.
7ff8adafe9e4atagen2026-10-22 12:30 UTC818
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC819
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC820
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC821
    /// * `user_id` - The ID of the user who owns the target device.
7ff8adafe9e4atagen2026-10-22 12:30 UTC822
    /// * `device_id` - The ID of the device to which the message will be sent.
7ff8adafe9e4atagen2026-10-22 12:30 UTC823
    /// * `event_type` - The event type.
7ff8adafe9e4atagen2026-10-22 12:30 UTC824
    /// * `content` - The serialized content of the event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC825
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC826
    /// # Returns
7ff8adafe9e4atagen2026-10-22 12:30 UTC827
    /// A `Result` containing the request to be sent out if the encryption was
7ff8adafe9e4atagen2026-10-22 12:30 UTC828
    /// successful. If the device is not found, the result will be `Ok(None)`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC829
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC830
    /// The caller should ensure that there is an olm session (see
7ff8adafe9e4atagen2026-10-22 12:30 UTC831
    /// `get_missing_sessions`) with the target device before calling this
7ff8adafe9e4atagen2026-10-22 12:30 UTC832
    /// method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC833
    pub fn create_encrypted_to_device_request(
7ff8adafe9e4atagen2026-10-22 12:30 UTC834
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC835
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC836
        device_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC837
        event_type: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC838
        content: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC839
        share_strategy: CollectStrategy,
7ff8adafe9e4atagen2026-10-22 12:30 UTC840
    ) -> Result<Option<Request>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC841
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC842
        let device_id = device_id.as_str().into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC843
        let content = serde_json::from_str(&content)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC844
7ff8adafe9e4atagen2026-10-22 12:30 UTC845
        let device = self.runtime.block_on(self.inner.get_device(&user_id, device_id, None))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC846
7ff8adafe9e4atagen2026-10-22 12:30 UTC847
        if let Some(device) = device {
7ff8adafe9e4atagen2026-10-22 12:30 UTC848
            let encrypted_content = self.runtime.block_on(device.encrypt_event_raw(
7ff8adafe9e4atagen2026-10-22 12:30 UTC849
                &event_type,
7ff8adafe9e4atagen2026-10-22 12:30 UTC850
                &content,
7ff8adafe9e4atagen2026-10-22 12:30 UTC851
                share_strategy,
7ff8adafe9e4atagen2026-10-22 12:30 UTC852
            ))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC853
7ff8adafe9e4atagen2026-10-22 12:30 UTC854
            let request = ToDeviceRequest::new(
7ff8adafe9e4atagen2026-10-22 12:30 UTC855
                user_id.as_ref(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC856
                DeviceIdOrAllDevices::DeviceId(device_id.to_owned()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC857
                "m.room.encrypted",
7ff8adafe9e4atagen2026-10-22 12:30 UTC858
                encrypted_content.cast(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC859
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC860
7ff8adafe9e4atagen2026-10-22 12:30 UTC861
            Ok(Some(request.into()))
7ff8adafe9e4atagen2026-10-22 12:30 UTC862
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC863
            Ok(None)
7ff8adafe9e4atagen2026-10-22 12:30 UTC864
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC865
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC866
7ff8adafe9e4atagen2026-10-22 12:30 UTC867
    /// Decrypt the given event that was sent in the given room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC868
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC869
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC870
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC871
    /// * `event` - The serialized encrypted version of the event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC872
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC873
    /// * `room_id` - The unique id of the room where the event was sent to.
7ff8adafe9e4atagen2026-10-22 12:30 UTC874
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC875
    /// * `handle_verification_events` - if the supplied event is a verification
7ff8adafe9e4atagen2026-10-22 12:30 UTC876
    ///   event, use it to update the verification state. **Note**: it is
7ff8adafe9e4atagen2026-10-22 12:30 UTC877
    ///   recommended to avoid setting this flag to true and use the explicit
7ff8adafe9e4atagen2026-10-22 12:30 UTC878
    ///   [`OlmMachine::receive_verification_event`] method instead:
7ff8adafe9e4atagen2026-10-22 12:30 UTC879
    ///   verification events sometimes need preparation before we can handle
7ff8adafe9e4atagen2026-10-22 12:30 UTC880
    ///   them: see the documentation for
7ff8adafe9e4atagen2026-10-22 12:30 UTC881
    ///   [`OlmMachine::receive_verification_event`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC882
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC883
    /// * `strict_shields` - If `true`, messages will be decorated with strict
7ff8adafe9e4atagen2026-10-22 12:30 UTC884
    ///   warnings (use `false` to match legacy behaviour where unsafe keys have
7ff8adafe9e4atagen2026-10-22 12:30 UTC885
    ///   lower severity warnings and unverified identities are not decorated).
7ff8adafe9e4atagen2026-10-22 12:30 UTC886
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC887
    /// * `decryption_settings` - The setting for decrypting messages.
7ff8adafe9e4atagen2026-10-22 12:30 UTC888
    pub fn decrypt_room_event(
7ff8adafe9e4atagen2026-10-22 12:30 UTC889
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC890
        event: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC891
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC892
        handle_verification_events: bool,
7ff8adafe9e4atagen2026-10-22 12:30 UTC893
        strict_shields: bool,
7ff8adafe9e4atagen2026-10-22 12:30 UTC894
        decryption_settings: DecryptionSettings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC895
    ) -> Result<DecryptedEvent, DecryptionError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC896
        // Element Android wants only the content and the type and will create a
7ff8adafe9e4atagen2026-10-22 12:30 UTC897
        // decrypted event with those two itself, this struct makes sure we
7ff8adafe9e4atagen2026-10-22 12:30 UTC898
        // throw away all the other fields.
7ff8adafe9e4atagen2026-10-22 12:30 UTC899
        #[derive(Deserialize, Serialize)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC900
        struct Event<'a> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC901
            #[serde(rename = "type")]
7ff8adafe9e4atagen2026-10-22 12:30 UTC902
            event_type: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC903
            #[serde(borrow)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC904
            content: &'a RawValue,
7ff8adafe9e4atagen2026-10-22 12:30 UTC905
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC906
7ff8adafe9e4atagen2026-10-22 12:30 UTC907
        let event: Raw<_> = serde_json::from_str(&event)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC908
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC909
7ff8adafe9e4atagen2026-10-22 12:30 UTC910
        let decrypted = self.runtime.block_on(self.inner.decrypt_room_event(
7ff8adafe9e4atagen2026-10-22 12:30 UTC911
            &event,
7ff8adafe9e4atagen2026-10-22 12:30 UTC912
            &room_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC913
            &decryption_settings,
7ff8adafe9e4atagen2026-10-22 12:30 UTC914
        ))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC915
7ff8adafe9e4atagen2026-10-22 12:30 UTC916
        if handle_verification_events
7ff8adafe9e4atagen2026-10-22 12:30 UTC917
            && let Ok(AnyTimelineEvent::MessageLike(e)) = decrypted.event.deserialize()
7ff8adafe9e4atagen2026-10-22 12:30 UTC918
        {
7ff8adafe9e4atagen2026-10-22 12:30 UTC919
            match &e {
7ff8adafe9e4atagen2026-10-22 12:30 UTC920
                AnyMessageLikeEvent::RoomMessage(MessageLikeEvent::Original(original_event)) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC921
                    if let MessageType::VerificationRequest(_) = &original_event.content.msgtype {
7ff8adafe9e4atagen2026-10-22 12:30 UTC922
                        self.runtime.block_on(self.inner.receive_verification_event(&e))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC923
                    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC924
                }
7ff8adafe9e4atagen2026-10-22 12:30 UTC925
                _ if e.event_type().to_string().starts_with("m.key.verification") => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC926
                    self.runtime.block_on(self.inner.receive_verification_event(&e))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC927
                }
7ff8adafe9e4atagen2026-10-22 12:30 UTC928
                _ => (),
7ff8adafe9e4atagen2026-10-22 12:30 UTC929
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC930
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC931
7ff8adafe9e4atagen2026-10-22 12:30 UTC932
        let encryption_info = decrypted.encryption_info;
7ff8adafe9e4atagen2026-10-22 12:30 UTC933
7ff8adafe9e4atagen2026-10-22 12:30 UTC934
        let event_json: Event<'_> = serde_json::from_str(decrypted.event.json().get())?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC935
7ff8adafe9e4atagen2026-10-22 12:30 UTC936
        Ok(match &encryption_info.algorithm_info {
7ff8adafe9e4atagen2026-10-22 12:30 UTC937
            AlgorithmInfo::MegolmV1AesSha2 {
7ff8adafe9e4atagen2026-10-22 12:30 UTC938
                curve25519_key,
7ff8adafe9e4atagen2026-10-22 12:30 UTC939
                sender_claimed_keys,
7ff8adafe9e4atagen2026-10-22 12:30 UTC940
                session_id: _,
7ff8adafe9e4atagen2026-10-22 12:30 UTC941
            } => DecryptedEvent {
7ff8adafe9e4atagen2026-10-22 12:30 UTC942
                clear_event: serde_json::to_string(&event_json)?,
7ff8adafe9e4atagen2026-10-22 12:30 UTC943
                sender_curve25519_key: curve25519_key.to_owned(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC944
                claimed_ed25519_key: sender_claimed_keys.get(&DeviceKeyAlgorithm::Ed25519).cloned(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC945
                forwarding_curve25519_chain: vec![],
7ff8adafe9e4atagen2026-10-22 12:30 UTC946
                shield_state: if strict_shields {
7ff8adafe9e4atagen2026-10-22 12:30 UTC947
                    encryption_info.verification_state.to_shield_state_strict().into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC948
                } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC949
                    encryption_info.verification_state.to_shield_state_lax().into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC950
                },
7ff8adafe9e4atagen2026-10-22 12:30 UTC951
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC952
            AlgorithmInfo::OlmV1Curve25519AesSha2 { .. } => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC953
                // cannot happen because `decrypt_room_event` would have fail to decrypt olm for
7ff8adafe9e4atagen2026-10-22 12:30 UTC954
                // a room (EventError::UnsupportedAlgorithm)
7ff8adafe9e4atagen2026-10-22 12:30 UTC955
                panic!("Unsupported olm algorithm in room")
7ff8adafe9e4atagen2026-10-22 12:30 UTC956
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC957
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC958
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC959
7ff8adafe9e4atagen2026-10-22 12:30 UTC960
    /// Request or re-request a room key that was used to encrypt the given
7ff8adafe9e4atagen2026-10-22 12:30 UTC961
    /// event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC962
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC963
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC964
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC965
    /// * `event` - The undecryptable event that we would wish to request a room
7ff8adafe9e4atagen2026-10-22 12:30 UTC966
    ///   key for.
7ff8adafe9e4atagen2026-10-22 12:30 UTC967
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC968
    /// * `room_id` - The id of the room the event was sent to.
7ff8adafe9e4atagen2026-10-22 12:30 UTC969
    pub fn request_room_key(
7ff8adafe9e4atagen2026-10-22 12:30 UTC970
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC971
        event: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC972
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC973
    ) -> Result<KeyRequestPair, DecryptionError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC974
        let event: Raw<_> = serde_json::from_str(&event)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC975
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC976
7ff8adafe9e4atagen2026-10-22 12:30 UTC977
        let (cancel, request) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC978
            self.runtime.block_on(self.inner.request_room_key(&event, &room_id))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC979
7ff8adafe9e4atagen2026-10-22 12:30 UTC980
        let cancellation = cancel.map(|r| r.into());
7ff8adafe9e4atagen2026-10-22 12:30 UTC981
        let key_request = request.into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC982
7ff8adafe9e4atagen2026-10-22 12:30 UTC983
        Ok(KeyRequestPair { cancellation, key_request })
7ff8adafe9e4atagen2026-10-22 12:30 UTC984
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC985
7ff8adafe9e4atagen2026-10-22 12:30 UTC986
    /// Export all of our room keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC987
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC988
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC989
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC990
    /// * `passphrase` - The passphrase that should be used to encrypt the key
7ff8adafe9e4atagen2026-10-22 12:30 UTC991
    ///   export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC992
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC993
    /// * `rounds` - The number of rounds that should be used when expanding the
7ff8adafe9e4atagen2026-10-22 12:30 UTC994
    ///   passphrase into an key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC995
    pub fn export_room_keys(
7ff8adafe9e4atagen2026-10-22 12:30 UTC996
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC997
        passphrase: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC998
        rounds: i32,
7ff8adafe9e4atagen2026-10-22 12:30 UTC999
    ) -> Result<String, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1000
        let keys = self.runtime.block_on(self.inner.store().export_room_keys(|_| true))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1001
7ff8adafe9e4atagen2026-10-22 12:30 UTC1002
        let encrypted = encrypt_room_key_export(&keys, &passphrase, rounds as u32)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1003
            .map_err(CryptoStoreError::Serialization)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1004
7ff8adafe9e4atagen2026-10-22 12:30 UTC1005
        Ok(encrypted)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1006
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1007
7ff8adafe9e4atagen2026-10-22 12:30 UTC1008
    /// Import room keys from the given serialized key export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1009
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1010
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1011
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1012
    /// * `keys` - The serialized version of the key export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1013
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1014
    /// * `passphrase` - The passphrase that was used to encrypt the key export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1015
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1016
    /// * `progress_listener` - A callback that can be used to introspect the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1017
    ///   progress of the key import.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1018
    pub fn import_room_keys(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1019
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1020
        keys: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1021
        passphrase: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1022
        progress_listener: Box<dyn ProgressListener>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1023
    ) -> Result<KeysImportResult, KeyImportError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1024
        let keys = Cursor::new(keys);
7ff8adafe9e4atagen2026-10-22 12:30 UTC1025
        let keys = decrypt_room_key_export(keys, &passphrase)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1026
        self.import_room_keys_helper(keys, None, progress_listener)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1027
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1028
7ff8adafe9e4atagen2026-10-22 12:30 UTC1029
    /// Import room keys from the given serialized unencrypted key export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1030
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1031
    /// This method is the same as [`OlmMachine::import_room_keys`] but the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1032
    /// decryption step is skipped and should be performed by the caller. This
7ff8adafe9e4atagen2026-10-22 12:30 UTC1033
    /// should be used if the room keys are coming from the server-side backup,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1034
    /// the method will mark all imported room keys as backed up.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1035
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1036
    /// **Note**: This has been deprecated. Use
7ff8adafe9e4atagen2026-10-22 12:30 UTC1037
    /// [`OlmMachine::import_room_keys_from_backup`] instead.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1038
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1039
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1040
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1041
    /// * `keys` - The serialized version of the unencrypted key export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1042
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1043
    /// * `progress_listener` - A callback that can be used to introspect the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1044
    ///   progress of the key import.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1045
    pub fn import_decrypted_room_keys(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1046
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1047
        keys: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1048
        progress_listener: Box<dyn ProgressListener>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1049
    ) -> Result<KeysImportResult, KeyImportError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1050
        // Assume that the keys came from the current backup version.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1051
        let backup_version = self.runtime.block_on(self.inner.backup_machine().backup_version());
7ff8adafe9e4atagen2026-10-22 12:30 UTC1052
        let keys: Vec<Value> = serde_json::from_str(&keys)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1053
        let keys = keys.into_iter().map(serde_json::from_value).filter_map(|k| k.ok()).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1054
        self.import_room_keys_helper(keys, backup_version.as_deref(), progress_listener)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1055
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1056
7ff8adafe9e4atagen2026-10-22 12:30 UTC1057
    /// Import room keys from the given serialized unencrypted key export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1058
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1059
    /// This method is the same as [`OlmMachine::import_room_keys`] but the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1060
    /// decryption step is skipped and should be performed by the caller. This
7ff8adafe9e4atagen2026-10-22 12:30 UTC1061
    /// should be used if the room keys are coming from the server-side backup.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1062
    /// The method will mark all imported room keys as backed up.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1063
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1064
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1065
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1066
    /// * `keys` - The serialized version of the unencrypted key export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1067
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1068
    /// * `backup_version` - The version of the backup that these keys came
7ff8adafe9e4atagen2026-10-22 12:30 UTC1069
    ///   from.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1070
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1071
    /// * `progress_listener` - A callback that can be used to introspect the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1072
    ///   progress of the key import.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1073
    pub fn import_room_keys_from_backup(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1074
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1075
        keys: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1076
        backup_version: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1077
        progress_listener: Box<dyn ProgressListener>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1078
    ) -> Result<KeysImportResult, KeyImportError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1079
        let keys: Vec<Value> = serde_json::from_str(&keys)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1080
        let keys = keys.into_iter().map(serde_json::from_value).filter_map(|k| k.ok()).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1081
        self.import_room_keys_helper(keys, Some(&backup_version), progress_listener)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1082
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1083
7ff8adafe9e4atagen2026-10-22 12:30 UTC1084
    /// Discard the currently active room key for the given room if there is
7ff8adafe9e4atagen2026-10-22 12:30 UTC1085
    /// one.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1086
    pub fn discard_room_key(&self, room_id: String) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1087
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1088
7ff8adafe9e4atagen2026-10-22 12:30 UTC1089
        self.runtime.block_on(self.inner.discard_room_key(&room_id))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1090
7ff8adafe9e4atagen2026-10-22 12:30 UTC1091
        Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1092
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1093
7ff8adafe9e4atagen2026-10-22 12:30 UTC1094
    /// Receive an unencrypted verification event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1095
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1096
    /// This method can be used to pass verification events that are happening
7ff8adafe9e4atagen2026-10-22 12:30 UTC1097
    /// in unencrypted rooms to the `OlmMachine`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1098
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1099
    /// **Note**: This has been deprecated.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1100
    pub fn receive_unencrypted_verification_event(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1101
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1102
        event: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1103
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1104
    ) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1105
        self.receive_verification_event(event, room_id)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1106
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1107
7ff8adafe9e4atagen2026-10-22 12:30 UTC1108
    /// Receive a verification event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1109
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1110
    /// This method can be used to pass verification events that are happening
7ff8adafe9e4atagen2026-10-22 12:30 UTC1111
    /// in rooms to the `OlmMachine`. The event should be in the decrypted form.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1112
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1113
    /// **Note**: If the supplied event is an `m.room.message` event with
7ff8adafe9e4atagen2026-10-22 12:30 UTC1114
    /// `msgtype: m.key.verification.request`, then the device information for
7ff8adafe9e4atagen2026-10-22 12:30 UTC1115
    /// the sending user must be up-to-date before calling this method
7ff8adafe9e4atagen2026-10-22 12:30 UTC1116
    /// (otherwise, the request will be ignored). It is hard to guarantee this
7ff8adafe9e4atagen2026-10-22 12:30 UTC1117
    /// is the case, but you can maximize your chances by explicitly making a
7ff8adafe9e4atagen2026-10-22 12:30 UTC1118
    /// request to /keys/query for the user's device info, and processing the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1119
    /// response with [`OlmMachine::mark_request_as_sent`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC1120
    pub fn receive_verification_event(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1121
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1122
        event: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1123
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1124
    ) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1125
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1126
        let event: AnySyncMessageLikeEvent = serde_json::from_str(&event)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1127
7ff8adafe9e4atagen2026-10-22 12:30 UTC1128
        let event = event.into_full_event(room_id);
7ff8adafe9e4atagen2026-10-22 12:30 UTC1129
7ff8adafe9e4atagen2026-10-22 12:30 UTC1130
        self.runtime.block_on(self.inner.receive_verification_event(&event))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1131
7ff8adafe9e4atagen2026-10-22 12:30 UTC1132
        Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1133
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1134
7ff8adafe9e4atagen2026-10-22 12:30 UTC1135
    /// Get all the verification requests that we share with the given user.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1136
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1137
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1138
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1139
    /// * `user_id` - The ID of the user for which we would like to fetch the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1140
    ///   verification requests.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1141
    pub fn get_verification_requests(&self, user_id: String) -> Vec<Arc<VerificationRequest>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1142
        let Ok(user_id) = UserId::parse(user_id) else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1143
            return vec![];
7ff8adafe9e4atagen2026-10-22 12:30 UTC1144
        };
7ff8adafe9e4atagen2026-10-22 12:30 UTC1145
7ff8adafe9e4atagen2026-10-22 12:30 UTC1146
        self.inner
7ff8adafe9e4atagen2026-10-22 12:30 UTC1147
            .get_verification_requests(&user_id)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1148
            .into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1149
            .map(|v| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1150
                VerificationRequest { inner: v, runtime: self.runtime.handle().to_owned() }.into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1151
            })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1152
            .collect()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1153
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1154
7ff8adafe9e4atagen2026-10-22 12:30 UTC1155
    /// Get a verification requests that we share with the given user with the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1156
    /// given flow id.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1157
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1158
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1159
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1160
    /// * `user_id` - The ID of the user for which we would like to fetch the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1161
    ///   verification requests.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1162
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1163
    /// * `flow_id` - The ID that uniquely identifies the verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1164
    pub fn get_verification_request(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1165
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1166
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1167
        flow_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1168
    ) -> Option<Arc<VerificationRequest>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1169
        let user_id = UserId::parse(user_id).ok()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1170
7ff8adafe9e4atagen2026-10-22 12:30 UTC1171
        self.inner.get_verification_request(&user_id, flow_id).map(|v| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1172
            VerificationRequest { inner: v, runtime: self.runtime.handle().to_owned() }.into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1173
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1174
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1175
7ff8adafe9e4atagen2026-10-22 12:30 UTC1176
    /// Get an m.key.verification.request content for the given user.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1177
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1178
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1179
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1180
    /// * `user_id` - The ID of the user which we would like to request to
7ff8adafe9e4atagen2026-10-22 12:30 UTC1181
    ///   verify.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1182
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1183
    /// * `methods` - The list of verification methods we want to advertise to
7ff8adafe9e4atagen2026-10-22 12:30 UTC1184
    ///   support.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1185
    pub fn verification_request_content(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1186
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1187
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1188
        methods: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1189
    ) -> Result<Option<String>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1190
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1191
7ff8adafe9e4atagen2026-10-22 12:30 UTC1192
        let identity = self.runtime.block_on(self.inner.get_identity(&user_id, None))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1193
7ff8adafe9e4atagen2026-10-22 12:30 UTC1194
        let methods = methods.into_iter().map(VerificationMethod::from).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1195
7ff8adafe9e4atagen2026-10-22 12:30 UTC1196
        Ok(if let Some(identity) = identity.and_then(|i| i.other()) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1197
            let content = identity.verification_request_content(Some(methods));
7ff8adafe9e4atagen2026-10-22 12:30 UTC1198
            Some(serde_json::to_string(&content)?)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1199
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1200
            None
7ff8adafe9e4atagen2026-10-22 12:30 UTC1201
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1202
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1203
7ff8adafe9e4atagen2026-10-22 12:30 UTC1204
    /// Request a verification flow to begin with the given user in the given
7ff8adafe9e4atagen2026-10-22 12:30 UTC1205
    /// room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1206
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1207
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1208
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1209
    /// * `user_id` - The ID of the user which we would like to request to
7ff8adafe9e4atagen2026-10-22 12:30 UTC1210
    ///   verify.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1211
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1212
    /// * `room_id` - The ID of the room that represents a DM with the given
7ff8adafe9e4atagen2026-10-22 12:30 UTC1213
    ///   user.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1214
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1215
    /// * `event_id` - The event ID of the `m.key.verification.request` event
7ff8adafe9e4atagen2026-10-22 12:30 UTC1216
    ///   that we sent out to request the verification to begin. The content for
7ff8adafe9e4atagen2026-10-22 12:30 UTC1217
    ///   this request can be created using the [verification_request_content()]
7ff8adafe9e4atagen2026-10-22 12:30 UTC1218
    ///   method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1219
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1220
    /// * `methods` - The list of verification methods we advertised as
7ff8adafe9e4atagen2026-10-22 12:30 UTC1221
    ///   supported in the `m.key.verification.request` event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1222
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1223
    /// [verification_request_content()]: Self::verification_request_content
7ff8adafe9e4atagen2026-10-22 12:30 UTC1224
    pub fn request_verification(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1225
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1226
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1227
        room_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1228
        event_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1229
        methods: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1230
    ) -> Result<Option<Arc<VerificationRequest>>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1231
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1232
        let event_id = EventId::parse(event_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1233
        let room_id = RoomId::parse(room_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1234
7ff8adafe9e4atagen2026-10-22 12:30 UTC1235
        let identity = self.runtime.block_on(self.inner.get_identity(&user_id, None))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1236
7ff8adafe9e4atagen2026-10-22 12:30 UTC1237
        let methods = methods.into_iter().map(VerificationMethod::from).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1238
7ff8adafe9e4atagen2026-10-22 12:30 UTC1239
        Ok(if let Some(identity) = identity.and_then(|i| i.other()) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1240
            let request = identity.request_verification(&room_id, &event_id, Some(methods));
7ff8adafe9e4atagen2026-10-22 12:30 UTC1241
7ff8adafe9e4atagen2026-10-22 12:30 UTC1242
            Some(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1243
                VerificationRequest { inner: request, runtime: self.runtime.handle().to_owned() }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1244
                    .into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1245
            )
7ff8adafe9e4atagen2026-10-22 12:30 UTC1246
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1247
            None
7ff8adafe9e4atagen2026-10-22 12:30 UTC1248
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1249
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1250
7ff8adafe9e4atagen2026-10-22 12:30 UTC1251
    /// Request a verification flow to begin with the given user's device.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1252
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1253
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1254
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1255
    /// * `user_id` - The ID of the user which we would like to request to
7ff8adafe9e4atagen2026-10-22 12:30 UTC1256
    ///   verify.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1257
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1258
    /// * `device_id` - The ID of the device that we wish to verify.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1259
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1260
    /// * `methods` - The list of verification methods we advertised as
7ff8adafe9e4atagen2026-10-22 12:30 UTC1261
    ///   supported in the `m.key.verification.request` event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1262
    pub fn request_verification_with_device(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1263
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1264
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1265
        device_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1266
        methods: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1267
    ) -> Result<Option<RequestVerificationResult>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1268
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1269
        let device_id = device_id.as_str().into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1270
7ff8adafe9e4atagen2026-10-22 12:30 UTC1271
        let methods = methods.into_iter().map(VerificationMethod::from).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1272
7ff8adafe9e4atagen2026-10-22 12:30 UTC1273
        Ok(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1274
            if let Some(device) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC1275
                self.runtime.block_on(self.inner.get_device(&user_id, device_id, None))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC1276
            {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1277
                let (verification, request) = device.request_verification_with_methods(methods);
7ff8adafe9e4atagen2026-10-22 12:30 UTC1278
7ff8adafe9e4atagen2026-10-22 12:30 UTC1279
                Some(RequestVerificationResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1280
                    verification: VerificationRequest {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1281
                        inner: verification,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1282
                        runtime: self.runtime.handle().to_owned(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1283
                    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1284
                    .into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1285
                    request: request.into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1286
                })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1287
            } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1288
                None
7ff8adafe9e4atagen2026-10-22 12:30 UTC1289
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC1290
        )
7ff8adafe9e4atagen2026-10-22 12:30 UTC1291
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1292
7ff8adafe9e4atagen2026-10-22 12:30 UTC1293
    /// Request a verification flow to begin with our other devices.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1294
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1295
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1296
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1297
    /// `methods` - The list of verification methods we want to advertise to
7ff8adafe9e4atagen2026-10-22 12:30 UTC1298
    /// support.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1299
    pub fn request_self_verification(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1300
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1301
        methods: Vec<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1302
    ) -> Result<Option<RequestVerificationResult>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1303
        let identity =
7ff8adafe9e4atagen2026-10-22 12:30 UTC1304
            self.runtime.block_on(self.inner.get_identity(self.inner.user_id(), None))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1305
7ff8adafe9e4atagen2026-10-22 12:30 UTC1306
        let methods = methods.into_iter().map(VerificationMethod::from).collect();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1307
7ff8adafe9e4atagen2026-10-22 12:30 UTC1308
        Ok(if let Some(identity) = identity.and_then(|i| i.own()) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1309
            let (verification, request) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC1310
                self.runtime.block_on(identity.request_verification_with_methods(methods))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1311
            Some(RequestVerificationResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1312
                verification: VerificationRequest {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1313
                    inner: verification,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1314
                    runtime: self.runtime.handle().to_owned(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1315
                }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1316
                .into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1317
                request: request.into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1318
            })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1319
        } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1320
            None
7ff8adafe9e4atagen2026-10-22 12:30 UTC1321
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1322
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1323
7ff8adafe9e4atagen2026-10-22 12:30 UTC1324
    /// Get a verification flow object for the given user with the given flow
7ff8adafe9e4atagen2026-10-22 12:30 UTC1325
    /// id.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1326
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1327
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1328
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1329
    /// * `user_id` - The ID of the user for which we would like to fetch the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1330
    ///   verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1331
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1332
    /// * `flow_id` - The ID that uniquely identifies the verification flow.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1333
    pub fn get_verification(&self, user_id: String, flow_id: String) -> Option<Arc<Verification>> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1334
        let user_id = UserId::parse(user_id).ok()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1335
7ff8adafe9e4atagen2026-10-22 12:30 UTC1336
        self.inner
7ff8adafe9e4atagen2026-10-22 12:30 UTC1337
            .get_verification(&user_id, &flow_id)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1338
            .map(|v| Verification { inner: v, runtime: self.runtime.handle().to_owned() }.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1339
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1340
7ff8adafe9e4atagen2026-10-22 12:30 UTC1341
    /// Start short auth string verification with a device without going
7ff8adafe9e4atagen2026-10-22 12:30 UTC1342
    /// through a verification request first.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1343
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1344
    /// **Note**: This has been largely deprecated and the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1345
    /// [request_verification_with_device()] method should be used instead.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1346
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1347
    /// # Arguments
7ff8adafe9e4atagen2026-10-22 12:30 UTC1348
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1349
    /// * `user_id` - The ID of the user for which we would like to start the
7ff8adafe9e4atagen2026-10-22 12:30 UTC1350
    ///   SAS verification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1351
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1352
    /// * `device_id` - The ID of device we would like to verify.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1353
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1354
    /// [request_verification_with_device()]: Self::request_verification_with_device
7ff8adafe9e4atagen2026-10-22 12:30 UTC1355
    pub fn start_sas_with_device(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1356
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1357
        user_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1358
        device_id: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1359
    ) -> Result<Option<StartSasResult>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1360
        let user_id = parse_user_id(&user_id)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1361
        let device_id = device_id.as_str().into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1362
7ff8adafe9e4atagen2026-10-22 12:30 UTC1363
        Ok(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1364
            if let Some(device) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC1365
                self.runtime.block_on(self.inner.get_device(&user_id, device_id, None))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC1366
            {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1367
                let (sas, request) = self.runtime.block_on(device.start_verification())?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1368
7ff8adafe9e4atagen2026-10-22 12:30 UTC1369
                Some(StartSasResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1370
                    sas: Sas { inner: Box::new(sas), runtime: self.runtime.handle().to_owned() }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1371
                        .into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1372
                    request: request.into(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1373
                })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1374
            } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1375
                None
7ff8adafe9e4atagen2026-10-22 12:30 UTC1376
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC1377
        )
7ff8adafe9e4atagen2026-10-22 12:30 UTC1378
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1379
7ff8adafe9e4atagen2026-10-22 12:30 UTC1380
    /// Create a new private cross signing identity and create a request to
7ff8adafe9e4atagen2026-10-22 12:30 UTC1381
    /// upload the public part of it to the server.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1382
    pub fn bootstrap_cross_signing(&self) -> Result<BootstrapCrossSigningResult, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1383
        Ok(self.runtime.block_on(self.inner.bootstrap_cross_signing(true))?.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1384
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1385
7ff8adafe9e4atagen2026-10-22 12:30 UTC1386
    /// Export all our private cross signing keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1387
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1388
    /// The export will contain the seed for the ed25519 keys as a base64
7ff8adafe9e4atagen2026-10-22 12:30 UTC1389
    /// encoded string.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1390
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1391
    /// This method returns `None` if we don't have any private cross signing
7ff8adafe9e4atagen2026-10-22 12:30 UTC1392
    /// keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1393
    pub fn export_cross_signing_keys(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1394
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1395
    ) -> Result<Option<CrossSigningKeyExport>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1396
        Ok(self.runtime.block_on(self.inner.export_cross_signing_keys())?.map(|e| e.into()))
7ff8adafe9e4atagen2026-10-22 12:30 UTC1397
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1398
7ff8adafe9e4atagen2026-10-22 12:30 UTC1399
    /// Import our private cross signing keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1400
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1401
    /// The export needs to contain the seed for the ed25519 keys as a base64
7ff8adafe9e4atagen2026-10-22 12:30 UTC1402
    /// encoded string.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1403
    pub fn import_cross_signing_keys(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1404
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1405
        export: CrossSigningKeyExport,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1406
    ) -> Result<(), SecretImportError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1407
        self.runtime.block_on(self.inner.import_cross_signing_keys(export.into()))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1408
7ff8adafe9e4atagen2026-10-22 12:30 UTC1409
        Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1410
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1411
7ff8adafe9e4atagen2026-10-22 12:30 UTC1412
    /// Export all the secrets we have in the store into a serialized
7ff8adafe9e4atagen2026-10-22 12:30 UTC1413
    /// SecretsBundle.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1414
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1415
    /// This method will export all the private cross-signing keys and, if
7ff8adafe9e4atagen2026-10-22 12:30 UTC1416
    /// available, the private part of a backup key and its accompanying
7ff8adafe9e4atagen2026-10-22 12:30 UTC1417
    /// version.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1418
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1419
    /// The method will fail if we don't have all three private cross-signing
7ff8adafe9e4atagen2026-10-22 12:30 UTC1420
    /// keys available.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1421
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1422
    /// **Warning**: Only export this and share it with a trusted recipient,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1423
    /// i.e. if an existing device is sharing this with a new device.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1424
    pub fn export_secrets_bundle(&self) -> Result<String, SecretsBundleExportError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1425
        let bundle = self.runtime.block_on(self.inner.store().export_secrets_bundle())?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1426
7ff8adafe9e4atagen2026-10-22 12:30 UTC1427
        Ok(serde_json::to_string(&bundle)?)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1428
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1429
7ff8adafe9e4atagen2026-10-22 12:30 UTC1430
    /// Request missing local secrets from our devices (cross signing private
7ff8adafe9e4atagen2026-10-22 12:30 UTC1431
    /// keys, megolm backup). This will ask the sdk to create outgoing
7ff8adafe9e4atagen2026-10-22 12:30 UTC1432
    /// request to get the missing secrets.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1433
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1434
    /// The requests will be processed as soon as `outgoing_requests()` is
7ff8adafe9e4atagen2026-10-22 12:30 UTC1435
    /// called to process them.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1436
    pub fn query_missing_secrets_from_other_sessions(&self) -> Result<bool, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1437
        Ok(self.runtime.block_on(self.inner.query_missing_secrets_from_other_sessions())?)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1438
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1439
7ff8adafe9e4atagen2026-10-22 12:30 UTC1440
    /// Activate the given backup key to be used with the given backup version.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1441
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1442
    /// **Warning**: The caller needs to make sure that the given `BackupKey` is
7ff8adafe9e4atagen2026-10-22 12:30 UTC1443
    /// trusted, otherwise we might be encrypting room keys that a malicious
7ff8adafe9e4atagen2026-10-22 12:30 UTC1444
    /// party could decrypt.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1445
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1446
    /// The [`OlmMachine::verify_backup`] method can be used to so.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1447
    pub fn enable_backup_v1(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1448
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1449
        key: MegolmV1BackupKey,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1450
        version: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1451
    ) -> Result<(), DecodeError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1452
        let backup_key = RustBackupKey::from_base64(&key.public_key)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1453
        backup_key.set_version(version);
7ff8adafe9e4atagen2026-10-22 12:30 UTC1454
7ff8adafe9e4atagen2026-10-22 12:30 UTC1455
        self.runtime.block_on(self.inner.backup_machine().enable_backup_v1(backup_key))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1456
7ff8adafe9e4atagen2026-10-22 12:30 UTC1457
        Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1458
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1459
7ff8adafe9e4atagen2026-10-22 12:30 UTC1460
    /// Are we able to encrypt room keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1461
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1462
    /// This returns true if we have an active `BackupKey` and backup version
7ff8adafe9e4atagen2026-10-22 12:30 UTC1463
    /// registered with the state machine.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1464
    pub fn backup_enabled(&self) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1465
        self.runtime.block_on(self.inner.backup_machine().enabled())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1466
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1467
7ff8adafe9e4atagen2026-10-22 12:30 UTC1468
    /// Disable and reset our backup state.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1469
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1470
    /// This will remove any pending backup request, remove the backup key and
7ff8adafe9e4atagen2026-10-22 12:30 UTC1471
    /// reset the backup state of each room key we have.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1472
    pub fn disable_backup(&self) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1473
        Ok(self.runtime.block_on(self.inner.backup_machine().disable_backup())?)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1474
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1475
7ff8adafe9e4atagen2026-10-22 12:30 UTC1476
    /// Encrypt a batch of room keys and return a request that needs to be sent
7ff8adafe9e4atagen2026-10-22 12:30 UTC1477
    /// out to backup the room keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1478
    pub fn backup_room_keys(&self) -> Result<Option<Request>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1479
        let request = self.runtime.block_on(self.inner.backup_machine().backup())?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1480
7ff8adafe9e4atagen2026-10-22 12:30 UTC1481
        let request = request.map(|r| r.into());
7ff8adafe9e4atagen2026-10-22 12:30 UTC1482
7ff8adafe9e4atagen2026-10-22 12:30 UTC1483
        Ok(request)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1484
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1485
7ff8adafe9e4atagen2026-10-22 12:30 UTC1486
    /// Get the number of backed up room keys and the total number of room keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1487
    pub fn room_key_counts(&self) -> Result<RoomKeyCounts, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1488
        Ok(self.runtime.block_on(self.inner.backup_machine().room_key_counts())?.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1489
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1490
7ff8adafe9e4atagen2026-10-22 12:30 UTC1491
    /// Store the recovery key in the crypto store.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1492
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1493
    /// This is useful if the client wants to support gossiping of the backup
7ff8adafe9e4atagen2026-10-22 12:30 UTC1494
    /// key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1495
    pub fn save_recovery_key(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1496
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1497
        key: Option<Arc<BackupRecoveryKey>>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1498
        version: Option<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1499
    ) -> Result<(), CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1500
        let key = key.map(|k| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1501
            // We need to clone here due to FFI limitations but RecoveryKey does
7ff8adafe9e4atagen2026-10-22 12:30 UTC1502
            // not want to expose clone since it's private key material.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1503
            let mut encoded = k.to_base64();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1504
            let key = BackupDecryptionKey::from_base64(&encoded)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1505
                .expect("Encoding and decoding from base64 should always work");
7ff8adafe9e4atagen2026-10-22 12:30 UTC1506
            encoded.zeroize();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1507
            key
7ff8adafe9e4atagen2026-10-22 12:30 UTC1508
        });
7ff8adafe9e4atagen2026-10-22 12:30 UTC1509
        Ok(self.runtime.block_on(self.inner.backup_machine().save_decryption_key(key, version))?)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1510
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1511
7ff8adafe9e4atagen2026-10-22 12:30 UTC1512
    /// Get the backup keys we have saved in our crypto store.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1513
    pub fn get_backup_keys(&self) -> Result<Option<Arc<BackupKeys>>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1514
        Ok(self
7ff8adafe9e4atagen2026-10-22 12:30 UTC1515
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC1516
            .block_on(self.inner.backup_machine().get_backup_keys())?
7ff8adafe9e4atagen2026-10-22 12:30 UTC1517
            .try_into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1518
            .ok()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1519
            .map(Arc::new))
7ff8adafe9e4atagen2026-10-22 12:30 UTC1520
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1521
7ff8adafe9e4atagen2026-10-22 12:30 UTC1522
    /// Sign the given message using our device key and if available cross
7ff8adafe9e4atagen2026-10-22 12:30 UTC1523
    /// signing master key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1524
    pub fn sign(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1525
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1526
        message: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1527
    ) -> Result<HashMap<String, HashMap<String, String>>, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1528
        Ok(self
7ff8adafe9e4atagen2026-10-22 12:30 UTC1529
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC1530
            .block_on(self.inner.sign(&message))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC1531
            .into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1532
            .map(|(k, v)| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1533
                (
7ff8adafe9e4atagen2026-10-22 12:30 UTC1534
                    k.to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1535
                    v.into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1536
                        .map(|(k, v)| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1537
                            (
7ff8adafe9e4atagen2026-10-22 12:30 UTC1538
                                k.to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1539
                                match v {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1540
                                    Ok(s) => s.to_base64(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1541
                                    Err(i) => i.source,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1542
                                },
7ff8adafe9e4atagen2026-10-22 12:30 UTC1543
                            )
7ff8adafe9e4atagen2026-10-22 12:30 UTC1544
                        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1545
                        .collect(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1546
                )
7ff8adafe9e4atagen2026-10-22 12:30 UTC1547
            })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1548
            .collect())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1549
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1550
7ff8adafe9e4atagen2026-10-22 12:30 UTC1551
    /// Check if the given backup has been verified by us or by another of our
7ff8adafe9e4atagen2026-10-22 12:30 UTC1552
    /// devices that we trust.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1553
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1554
    /// The `backup_info` should be a JSON encoded object with the following
7ff8adafe9e4atagen2026-10-22 12:30 UTC1555
    /// format:
7ff8adafe9e4atagen2026-10-22 12:30 UTC1556
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1557
    /// ```json
7ff8adafe9e4atagen2026-10-22 12:30 UTC1558
    /// {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1559
    ///     "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
7ff8adafe9e4atagen2026-10-22 12:30 UTC1560
    ///     "auth_data": {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1561
    ///         "public_key":"XjhWTCjW7l59pbfx9tlCBQolfnIQWARoKOzjTOPSlWM",
7ff8adafe9e4atagen2026-10-22 12:30 UTC1562
    ///         "signatures": {}
7ff8adafe9e4atagen2026-10-22 12:30 UTC1563
    ///     }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1564
    /// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1565
    /// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC1566
    pub fn verify_backup(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1567
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1568
        backup_info: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1569
    ) -> Result<SignatureVerification, CryptoStoreError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1570
        let backup_info = serde_json::from_str(&backup_info)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1571
7ff8adafe9e4atagen2026-10-22 12:30 UTC1572
        Ok(self
7ff8adafe9e4atagen2026-10-22 12:30 UTC1573
            .runtime
7ff8adafe9e4atagen2026-10-22 12:30 UTC1574
            .block_on(self.inner.backup_machine().verify_backup(backup_info, false))?
7ff8adafe9e4atagen2026-10-22 12:30 UTC1575
            .into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1576
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1577
7ff8adafe9e4atagen2026-10-22 12:30 UTC1578
    /// Manage dehydrated devices.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1579
    pub fn dehydrated_devices(&self) -> Arc<DehydratedDevices> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1580
        DehydratedDevices {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1581
            inner: ManuallyDrop::new(self.inner.dehydrated_devices()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1582
            runtime: self.runtime.handle().to_owned(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1583
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1584
        .into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1585
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1586
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC1587
7ff8adafe9e4atagen2026-10-22 12:30 UTC1588
impl OlmMachine {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1589
    fn import_room_keys_helper(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1590
        &self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1591
        keys: Vec<ExportedRoomKey>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1592
        from_backup_version: Option<&str>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1593
        progress_listener: Box<dyn ProgressListener>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1594
    ) -> Result<KeysImportResult, KeyImportError> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1595
        let listener = |progress: usize, total: usize| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1596
            progress_listener.on_progress(progress as i32, total as i32)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1597
        };
7ff8adafe9e4atagen2026-10-22 12:30 UTC1598
7ff8adafe9e4atagen2026-10-22 12:30 UTC1599
        let result = self.runtime.block_on(self.inner.store().import_room_keys(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1600
            keys,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1601
            from_backup_version,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1602
            listener,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1603
        ))?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1604
7ff8adafe9e4atagen2026-10-22 12:30 UTC1605
        Ok(KeysImportResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1606
            imported: result.imported_count as i64,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1607
            total: result.total_count as i64,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1608
            keys: result
7ff8adafe9e4atagen2026-10-22 12:30 UTC1609
                .keys
7ff8adafe9e4atagen2026-10-22 12:30 UTC1610
                .into_iter()
7ff8adafe9e4atagen2026-10-22 12:30 UTC1611
                .map(|(r, m)| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1612
                    (
7ff8adafe9e4atagen2026-10-22 12:30 UTC1613
                        r.to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1614
                        m.into_iter().map(|(s, k)| (s, k.into_iter().collect())).collect(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1615
                    )
7ff8adafe9e4atagen2026-10-22 12:30 UTC1616
                })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1617
                .collect(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1618
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC1619
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1620
}