atagen

matrix-rust-sdk

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

Blame: crates/matrix-sdk-crypto/src/lib.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
// Copyright 2020 The Matrix.org Foundation C.I.C.
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
// Copyright 2024 Damir Jelić
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
//
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
// Licensed under the Apache License, Version 2.0 (the "License");
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
// you may not use this file except in compliance with the License.
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
// You may obtain a copy of the License at
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
//
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
//     http://www.apache.org/licenses/LICENSE-2.0
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
//
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
// Unless required by applicable law or agreed to in writing, software
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
// distributed under the License is distributed on an "AS IS" BASIS,
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
// See the License for the specific language governing permissions and
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
// limitations under the License.
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
#![doc = include_str!("../README.md")]
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
#![cfg_attr(docsrs, feature(doc_cfg))]
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
#![warn(missing_docs, missing_debug_implementations)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
#![cfg_attr(target_family = "wasm", allow(clippy::arc_with_non_send_sync))]
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
pub mod backups;
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
mod ciphers;
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
pub mod dehydrated_devices;
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
mod error;
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
mod file_encryption;
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
mod gossiping;
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
mod identities;
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
mod machine;
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
pub mod olm;
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
pub mod secret_storage;
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
mod session_manager;
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
pub mod store;
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
pub mod types;
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
mod utilities;
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
mod verification;
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
#[cfg(any(test, feature = "testing"))]
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
/// Testing facilities and helpers for crypto tests
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
pub mod testing {
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
    pub use crate::identities::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
        device::testing::get_device,
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
        user::testing::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
            get_other_identity, get_own_identity, simulate_key_query_response_for_verification,
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
        },
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
    };
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
use std::collections::{BTreeMap, BTreeSet};
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
pub use identities::room_identity_state::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
    IdentityState, IdentityStatusChange, RoomIdentityChange, RoomIdentityProvider,
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
    RoomIdentityState,
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
use ruma::OwnedRoomId;
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
/// Return type for the room key importing.
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
#[derive(Debug, Clone, PartialEq, Eq)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
pub struct RoomKeyImportResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
    /// The number of room keys that were imported.
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
    pub imported_count: usize,
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
    /// The total number of room keys that were found in the export.
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
    pub total_count: usize,
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
    /// The map of keys that were imported.
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
    /// It's a map from room id to a map of the sender key to a set of session
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
    /// ids.
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
    pub keys: BTreeMap<OwnedRoomId, BTreeMap<String, BTreeSet<String>>>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
impl RoomKeyImportResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
    pub(crate) fn new(
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
        imported_count: usize,
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
        total_count: usize,
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
        keys: BTreeMap<OwnedRoomId, BTreeMap<String, BTreeSet<String>>>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
    ) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
        Self { imported_count, total_count, keys }
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
pub use error::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
    EventError, MegolmError, OlmError, SessionCreationError, SessionRecipientCollectionError,
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
    SetRoomSettingsError, SignatureError,
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
pub use file_encryption::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
    AttachmentDecryptor, AttachmentEncryptor, DecryptorError, KeyExportError, MediaEncryptionInfo,
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
    decrypt_room_key_export, encrypt_room_key_export,
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
pub use gossiping::{GossipRequest, GossippedSecret};
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
pub use identities::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
    Device, DeviceData, LocalTrust, OtherUserIdentity, OtherUserIdentityData, OwnUserIdentity,
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
    OwnUserIdentityData, UserDevices, UserIdentity, UserIdentityData,
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
pub use machine::{CrossSigningBootstrapRequests, EncryptionSyncChanges, OlmMachine};
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
use matrix_sdk_common::deserialized_responses::{DecryptedRoomEvent, UnableToDecryptInfo};
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
#[cfg(feature = "qrcode")]
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
pub use matrix_sdk_qrcode;
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
pub use olm::{Account, CrossSigningStatus, EncryptionSettings, Session};
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
use serde::{Deserialize, Serialize};
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
pub use session_manager::CollectStrategy;
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
pub use store::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
    CryptoStoreError, SecretImportError, SecretInfo,
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
    types::{CrossSigningKeyExport, TrackedUser},
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
pub use verification::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
    AcceptSettings, AcceptedProtocols, CancelInfo, Emoji, EmojiShortAuthString, Sas, SasState,
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
    Verification, VerificationRequest, VerificationRequestState, format_emojis,
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
#[cfg(feature = "qrcode")]
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
pub use verification::{QrVerification, QrVerificationState, ScanError};
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
#[doc(no_inline)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
pub use vodozemac;
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
/// The version of the matrix-sdk-cypto crate being used
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
#[cfg(test)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
matrix_sdk_test_utils::init_tracing_for_tests!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
#[cfg(feature = "uniffi")]
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
uniffi::setup_scaffolding!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC121
7ff8adafe9e4atagen2026-10-22 12:30 UTC122
/// The trust level in the sender's device that is required to decrypt an
7ff8adafe9e4atagen2026-10-22 12:30 UTC123
/// event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC124
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC125
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
7ff8adafe9e4atagen2026-10-22 12:30 UTC126
pub enum TrustRequirement {
7ff8adafe9e4atagen2026-10-22 12:30 UTC127
    /// Decrypt events from everyone regardless of trust.
7ff8adafe9e4atagen2026-10-22 12:30 UTC128
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC129
    /// Not recommended, per the guidance of [MSC4153].
7ff8adafe9e4atagen2026-10-22 12:30 UTC130
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC131
    /// [MSC4153]: https://github.com/matrix-org/matrix-doc/pull/4153
7ff8adafe9e4atagen2026-10-22 12:30 UTC132
    Untrusted,
7ff8adafe9e4atagen2026-10-22 12:30 UTC133
7ff8adafe9e4atagen2026-10-22 12:30 UTC134
    /// Only decrypt events from cross-signed devices or legacy sessions (Megolm
7ff8adafe9e4atagen2026-10-22 12:30 UTC135
    /// sessions created before we started collecting trust information).
7ff8adafe9e4atagen2026-10-22 12:30 UTC136
    CrossSignedOrLegacy,
7ff8adafe9e4atagen2026-10-22 12:30 UTC137
7ff8adafe9e4atagen2026-10-22 12:30 UTC138
    /// Only decrypt events from cross-signed devices.
7ff8adafe9e4atagen2026-10-22 12:30 UTC139
    CrossSigned,
7ff8adafe9e4atagen2026-10-22 12:30 UTC140
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC141
7ff8adafe9e4atagen2026-10-22 12:30 UTC142
/// Settings for decrypting messages
7ff8adafe9e4atagen2026-10-22 12:30 UTC143
#[derive(Clone, Debug, Deserialize, Serialize)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC144
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
7ff8adafe9e4atagen2026-10-22 12:30 UTC145
pub struct DecryptionSettings {
7ff8adafe9e4atagen2026-10-22 12:30 UTC146
    /// The trust level in the sender's device that is required to decrypt the
7ff8adafe9e4atagen2026-10-22 12:30 UTC147
    /// event. If the sender's device is not sufficiently trusted,
7ff8adafe9e4atagen2026-10-22 12:30 UTC148
    /// [`MegolmError::SenderIdentityNotTrusted`] will be returned.
7ff8adafe9e4atagen2026-10-22 12:30 UTC149
    pub sender_device_trust_requirement: TrustRequirement,
7ff8adafe9e4atagen2026-10-22 12:30 UTC150
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC151
7ff8adafe9e4atagen2026-10-22 12:30 UTC152
/// The result of an attempt to decrypt a room event: either a successful
7ff8adafe9e4atagen2026-10-22 12:30 UTC153
/// decryption, or information on a failure.
7ff8adafe9e4atagen2026-10-22 12:30 UTC154
#[derive(Clone, Debug, Serialize, Deserialize)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC155
pub enum RoomEventDecryptionResult {
7ff8adafe9e4atagen2026-10-22 12:30 UTC156
    /// A successfully-decrypted encrypted event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC157
    Decrypted(DecryptedRoomEvent),
7ff8adafe9e4atagen2026-10-22 12:30 UTC158
7ff8adafe9e4atagen2026-10-22 12:30 UTC159
    /// We were unable to decrypt the event
7ff8adafe9e4atagen2026-10-22 12:30 UTC160
    UnableToDecrypt(UnableToDecryptInfo),
7ff8adafe9e4atagen2026-10-22 12:30 UTC161
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC162
7ff8adafe9e4atagen2026-10-22 12:30 UTC163
#[cfg_attr(doc, aquamarine::aquamarine)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC164
/// A step by step guide that explains how to include [end-to-end-encryption]
7ff8adafe9e4atagen2026-10-22 12:30 UTC165
/// support in a [Matrix] client library.
7ff8adafe9e4atagen2026-10-22 12:30 UTC166
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC167
/// This crate implements a [sans-network-io](https://sans-io.readthedocs.io/)
7ff8adafe9e4atagen2026-10-22 12:30 UTC168
/// state machine that allows you to add [end-to-end-encryption] support to a
7ff8adafe9e4atagen2026-10-22 12:30 UTC169
/// [Matrix] client library.
7ff8adafe9e4atagen2026-10-22 12:30 UTC170
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC171
/// This guide aims to provide a comprehensive understanding of end-to-end
7ff8adafe9e4atagen2026-10-22 12:30 UTC172
/// encryption in Matrix without any prior knowledge requirements. However, it
7ff8adafe9e4atagen2026-10-22 12:30 UTC173
/// is recommended that the reader has a basic understanding of Matrix and its
7ff8adafe9e4atagen2026-10-22 12:30 UTC174
/// [client-server specification] for a more informed and efficient learning
7ff8adafe9e4atagen2026-10-22 12:30 UTC175
/// experience.
7ff8adafe9e4atagen2026-10-22 12:30 UTC176
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC177
/// The [introductory](#introduction) section provides a simplified explanation
7ff8adafe9e4atagen2026-10-22 12:30 UTC178
/// of end-to-end encryption and its implementation in Matrix for those who may
7ff8adafe9e4atagen2026-10-22 12:30 UTC179
/// not have prior knowledge. If you already have a solid understanding of
7ff8adafe9e4atagen2026-10-22 12:30 UTC180
/// end-to-end encryption, including the [Olm] and [Megolm] protocols, you may
7ff8adafe9e4atagen2026-10-22 12:30 UTC181
/// choose to skip directly to the [Getting Started](#getting-started) section.
7ff8adafe9e4atagen2026-10-22 12:30 UTC182
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC183
/// # Table of Contents
7ff8adafe9e4atagen2026-10-22 12:30 UTC184
/// 1. [Introduction](#introduction)
7ff8adafe9e4atagen2026-10-22 12:30 UTC185
/// 2. [Getting started](#getting-started)
7ff8adafe9e4atagen2026-10-22 12:30 UTC186
/// 3. [Decrypting room events](#decryption)
7ff8adafe9e4atagen2026-10-22 12:30 UTC187
/// 4. [Encrypting room events](#encryption)
7ff8adafe9e4atagen2026-10-22 12:30 UTC188
/// 5. [Interactively verifying devices and user identities](#verification)
7ff8adafe9e4atagen2026-10-22 12:30 UTC189
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC190
/// # Introduction
7ff8adafe9e4atagen2026-10-22 12:30 UTC191
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC192
/// Welcome to the first part of this guide, where we will introduce the
7ff8adafe9e4atagen2026-10-22 12:30 UTC193
/// fundamental concepts of end-to-end encryption and its implementation in
7ff8adafe9e4atagen2026-10-22 12:30 UTC194
/// Matrix.
7ff8adafe9e4atagen2026-10-22 12:30 UTC195
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC196
/// This section will provide a clear and concise overview of what
7ff8adafe9e4atagen2026-10-22 12:30 UTC197
/// end-to-end encryption is and why it is important for secure communication.
7ff8adafe9e4atagen2026-10-22 12:30 UTC198
/// You will also learn about how Matrix uses end-to-end encryption to protect
7ff8adafe9e4atagen2026-10-22 12:30 UTC199
/// the privacy and security of its users' communications. Whether you are new
7ff8adafe9e4atagen2026-10-22 12:30 UTC200
/// to the topic or simply want to improve your understanding, this section will
7ff8adafe9e4atagen2026-10-22 12:30 UTC201
/// serve as a solid foundation for the rest of the guide.
7ff8adafe9e4atagen2026-10-22 12:30 UTC202
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC203
/// Let's dive in!
7ff8adafe9e4atagen2026-10-22 12:30 UTC204
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC205
/// ## Notation
7ff8adafe9e4atagen2026-10-22 12:30 UTC206
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC207
/// ## End-to-end-encryption
7ff8adafe9e4atagen2026-10-22 12:30 UTC208
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC209
/// End-to-end encryption (E2EE) is a method of secure communication where only
7ff8adafe9e4atagen2026-10-22 12:30 UTC210
/// the communicating devices, also known as "the ends," can read the data being
7ff8adafe9e4atagen2026-10-22 12:30 UTC211
/// transmitted. This means that the data is encrypted on one device, and can
7ff8adafe9e4atagen2026-10-22 12:30 UTC212
/// only be decrypted on the other device. The server is used only as a
7ff8adafe9e4atagen2026-10-22 12:30 UTC213
/// transport mechanism to deliver messages between devices.
7ff8adafe9e4atagen2026-10-22 12:30 UTC214
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC215
/// The following chart displays how communication between two clients using a
7ff8adafe9e4atagen2026-10-22 12:30 UTC216
/// server in the middle usually works.
7ff8adafe9e4atagen2026-10-22 12:30 UTC217
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC218
/// ```mermaid
7ff8adafe9e4atagen2026-10-22 12:30 UTC219
/// flowchart LR
7ff8adafe9e4atagen2026-10-22 12:30 UTC220
///     alice[Alice]
7ff8adafe9e4atagen2026-10-22 12:30 UTC221
///     bob[Bob]
7ff8adafe9e4atagen2026-10-22 12:30 UTC222
///     subgraph Homeserver
7ff8adafe9e4atagen2026-10-22 12:30 UTC223
///         direction LR
7ff8adafe9e4atagen2026-10-22 12:30 UTC224
///         outbox[Alice outbox]
7ff8adafe9e4atagen2026-10-22 12:30 UTC225
///         inbox[Bob inbox]
7ff8adafe9e4atagen2026-10-22 12:30 UTC226
///         outbox -. unencrypted .-> inbox
7ff8adafe9e4atagen2026-10-22 12:30 UTC227
///     end
7ff8adafe9e4atagen2026-10-22 12:30 UTC228
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC229
///     alice -- encrypted --> outbox
7ff8adafe9e4atagen2026-10-22 12:30 UTC230
///     inbox -- encrypted --> bob
7ff8adafe9e4atagen2026-10-22 12:30 UTC231
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC232
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC233
/// The next chart, instead, displays how the same flow is happening in a
7ff8adafe9e4atagen2026-10-22 12:30 UTC234
/// end-to-end-encrypted world.
7ff8adafe9e4atagen2026-10-22 12:30 UTC235
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC236
/// ```mermaid
7ff8adafe9e4atagen2026-10-22 12:30 UTC237
/// flowchart LR
7ff8adafe9e4atagen2026-10-22 12:30 UTC238
///     alice[Alice]
7ff8adafe9e4atagen2026-10-22 12:30 UTC239
///     bob[Bob]
7ff8adafe9e4atagen2026-10-22 12:30 UTC240
///     subgraph Homeserver
7ff8adafe9e4atagen2026-10-22 12:30 UTC241
///         direction LR
7ff8adafe9e4atagen2026-10-22 12:30 UTC242
///         outbox[Alice outbox]
7ff8adafe9e4atagen2026-10-22 12:30 UTC243
///         inbox[Bob inbox]
7ff8adafe9e4atagen2026-10-22 12:30 UTC244
///         outbox == encrypted ==> inbox
7ff8adafe9e4atagen2026-10-22 12:30 UTC245
///     end
7ff8adafe9e4atagen2026-10-22 12:30 UTC246
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC247
///     alice == encrypted ==> outbox
7ff8adafe9e4atagen2026-10-22 12:30 UTC248
///     inbox == encrypted ==> bob
7ff8adafe9e4atagen2026-10-22 12:30 UTC249
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC250
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC251
/// Note that the path from the outbox to the inbox is now encrypted as well.
7ff8adafe9e4atagen2026-10-22 12:30 UTC252
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC253
/// Alice and Bob have created a secure communication channel
7ff8adafe9e4atagen2026-10-22 12:30 UTC254
/// through which they can exchange messages confidentially, without the risk of
7ff8adafe9e4atagen2026-10-22 12:30 UTC255
/// the server accessing the contents of their messages.
7ff8adafe9e4atagen2026-10-22 12:30 UTC256
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC257
/// ## Publishing cryptographic identities of devices
7ff8adafe9e4atagen2026-10-22 12:30 UTC258
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC259
/// If Alice and Bob want to establish a secure channel over which they can
7ff8adafe9e4atagen2026-10-22 12:30 UTC260
/// exchange messages, they first need learn about each others cryptographic
7ff8adafe9e4atagen2026-10-22 12:30 UTC261
/// identities. This is achieved by using the homeserver as a public key
7ff8adafe9e4atagen2026-10-22 12:30 UTC262
/// directory.
7ff8adafe9e4atagen2026-10-22 12:30 UTC263
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC264
/// A public key directory is used to store and distribute public keys of users
7ff8adafe9e4atagen2026-10-22 12:30 UTC265
/// in an end-to-end encrypted system. The basic idea behind a public key
7ff8adafe9e4atagen2026-10-22 12:30 UTC266
/// directory is that it allows users to easily discover and download the public
7ff8adafe9e4atagen2026-10-22 12:30 UTC267
/// keys of other users with whom they wish to establish an end-to-end encrypted
7ff8adafe9e4atagen2026-10-22 12:30 UTC268
/// communication.
7ff8adafe9e4atagen2026-10-22 12:30 UTC269
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC270
/// Each user generates a pair of public and private keys. The user then uploads
7ff8adafe9e4atagen2026-10-22 12:30 UTC271
/// their public key to the public key directory. Other users can then search
7ff8adafe9e4atagen2026-10-22 12:30 UTC272
/// the directory to find the public key of the user they wish to communicate
7ff8adafe9e4atagen2026-10-22 12:30 UTC273
/// with, and download it to their own device.
7ff8adafe9e4atagen2026-10-22 12:30 UTC274
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC275
/// ```mermaid
7ff8adafe9e4atagen2026-10-22 12:30 UTC276
/// flowchart LR
7ff8adafe9e4atagen2026-10-22 12:30 UTC277
///     alice[Alice]
7ff8adafe9e4atagen2026-10-22 12:30 UTC278
///     subgraph homeserver[Homeserver]
7ff8adafe9e4atagen2026-10-22 12:30 UTC279
///         direction LR
7ff8adafe9e4atagen2026-10-22 12:30 UTC280
///         directory[(Public key directory)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC281
///     end
7ff8adafe9e4atagen2026-10-22 12:30 UTC282
///     bob[Bob]
7ff8adafe9e4atagen2026-10-22 12:30 UTC283
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC284
///     alice -- upload keys --> directory
7ff8adafe9e4atagen2026-10-22 12:30 UTC285
///     directory -- download keys --> bob
7ff8adafe9e4atagen2026-10-22 12:30 UTC286
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC287
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC288
/// Once a user has the other user's public key, they can use it to establish an
7ff8adafe9e4atagen2026-10-22 12:30 UTC289
/// end-to-end encrypted channel using a [key-agreement protocol].
7ff8adafe9e4atagen2026-10-22 12:30 UTC290
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC291
/// ## Using the Triple Diffie-Hellman key-agreement protocol
7ff8adafe9e4atagen2026-10-22 12:30 UTC292
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC293
/// In the triple Diffie-Hellman key agreement protocol (3DH in short), each
7ff8adafe9e4atagen2026-10-22 12:30 UTC294
/// user generates a long-term identity key pair and a set of one-time prekeys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC295
/// When two users want to establish a shared secret key, they exchange their
7ff8adafe9e4atagen2026-10-22 12:30 UTC296
/// public identity keys and one of their prekeys. These public keys are then
7ff8adafe9e4atagen2026-10-22 12:30 UTC297
/// used in a [Diffie-Hellman] key exchange to compute a shared secret key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC298
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC299
/// The use of one-time prekeys ensures that the shared secret key is different
7ff8adafe9e4atagen2026-10-22 12:30 UTC300
/// for each session, even if the same identity keys are used.
7ff8adafe9e4atagen2026-10-22 12:30 UTC301
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC302
/// ```mermaid
7ff8adafe9e4atagen2026-10-22 12:30 UTC303
/// flowchart LR
7ff8adafe9e4atagen2026-10-22 12:30 UTC304
/// subgraph alice_keys[Alice Keys]
7ff8adafe9e4atagen2026-10-22 12:30 UTC305
///     direction TB
7ff8adafe9e4atagen2026-10-22 12:30 UTC306
///     alice_key[Alice's identity key]
7ff8adafe9e4atagen2026-10-22 12:30 UTC307
///     alice_base_key[Alice's one-time key]
7ff8adafe9e4atagen2026-10-22 12:30 UTC308
/// end
7ff8adafe9e4atagen2026-10-22 12:30 UTC309
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC310
/// subgraph bob_keys[Bob Keys]
7ff8adafe9e4atagen2026-10-22 12:30 UTC311
///     direction TB
7ff8adafe9e4atagen2026-10-22 12:30 UTC312
///     bob_key[Bob's identity key]
7ff8adafe9e4atagen2026-10-22 12:30 UTC313
///     bob_one_time[Bob's one-time key]
7ff8adafe9e4atagen2026-10-22 12:30 UTC314
/// end
7ff8adafe9e4atagen2026-10-22 12:30 UTC315
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC316
/// alice_key <--> bob_one_time
7ff8adafe9e4atagen2026-10-22 12:30 UTC317
/// alice_base_key <--> bob_one_time
7ff8adafe9e4atagen2026-10-22 12:30 UTC318
/// alice_base_key <--> bob_key
7ff8adafe9e4atagen2026-10-22 12:30 UTC319
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC320
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC321
/// Similar to [X3DH] (Extended Triple Diffie-Hellman) key agreement protocol
7ff8adafe9e4atagen2026-10-22 12:30 UTC322
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC323
/// ## Speeding up encryption for large groups
7ff8adafe9e4atagen2026-10-22 12:30 UTC324
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC325
/// In the previous section we learned how to utilize a key agreement protocol
7ff8adafe9e4atagen2026-10-22 12:30 UTC326
/// to establish secure 1-to-1 encrypted communication channels. These channels
7ff8adafe9e4atagen2026-10-22 12:30 UTC327
/// allow us to encrypt a message for each device separately.
7ff8adafe9e4atagen2026-10-22 12:30 UTC328
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC329
/// One critical property of these channels is that, if you want to send a
7ff8adafe9e4atagen2026-10-22 12:30 UTC330
/// message to a group of devices, we'll need to encrypt the message for each
7ff8adafe9e4atagen2026-10-22 12:30 UTC331
/// device individually.
7ff8adafe9e4atagen2026-10-22 12:30 UTC332
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC333
/// TODO Explain how megolm fits into this
7ff8adafe9e4atagen2026-10-22 12:30 UTC334
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC335
/// # Getting started
7ff8adafe9e4atagen2026-10-22 12:30 UTC336
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC337
/// Before we start writing any code, let us get familiar with the basic
7ff8adafe9e4atagen2026-10-22 12:30 UTC338
/// principle upon which this library is built.
7ff8adafe9e4atagen2026-10-22 12:30 UTC339
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC340
/// The central piece of the library is the [`OlmMachine`] which acts as a state
7ff8adafe9e4atagen2026-10-22 12:30 UTC341
/// machine which consumes data that gets received from the homeserver and
7ff8adafe9e4atagen2026-10-22 12:30 UTC342
/// outputs data which should be sent to the homeserver.
7ff8adafe9e4atagen2026-10-22 12:30 UTC343
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC344
/// ## Push/pull mechanism
7ff8adafe9e4atagen2026-10-22 12:30 UTC345
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC346
/// The [`OlmMachine`] at the heart of it acts as a state machine that operates
7ff8adafe9e4atagen2026-10-22 12:30 UTC347
/// in a push/pull manner. HTTP responses which were received from the
7ff8adafe9e4atagen2026-10-22 12:30 UTC348
/// homeserver get forwarded into the [`OlmMachine`] and in turn the internal
7ff8adafe9e4atagen2026-10-22 12:30 UTC349
/// state gets updated which produces HTTP requests that need to be sent to the
7ff8adafe9e4atagen2026-10-22 12:30 UTC350
/// homeserver.
7ff8adafe9e4atagen2026-10-22 12:30 UTC351
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC352
/// In a manner, we're pulling data from the server, we update our internal
7ff8adafe9e4atagen2026-10-22 12:30 UTC353
/// state based on the data and in turn push data back to the server.
7ff8adafe9e4atagen2026-10-22 12:30 UTC354
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC355
/// ```mermaid
7ff8adafe9e4atagen2026-10-22 12:30 UTC356
/// flowchart LR
7ff8adafe9e4atagen2026-10-22 12:30 UTC357
///     homeserver[Homeserver]
7ff8adafe9e4atagen2026-10-22 12:30 UTC358
///     client[OlmMachine]
7ff8adafe9e4atagen2026-10-22 12:30 UTC359
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC360
///     homeserver -- pull --> client
7ff8adafe9e4atagen2026-10-22 12:30 UTC361
///     client -- push --> homeserver
7ff8adafe9e4atagen2026-10-22 12:30 UTC362
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC363
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC364
/// ## Initializing the state machine
7ff8adafe9e4atagen2026-10-22 12:30 UTC365
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC366
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC367
/// use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC368
/// use matrix_sdk_crypto::OlmMachine;
7ff8adafe9e4atagen2026-10-22 12:30 UTC369
/// use ruma::user_id;
7ff8adafe9e4atagen2026-10-22 12:30 UTC370
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC371
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC372
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC373
/// let user_id = user_id!("@alice:localhost");
7ff8adafe9e4atagen2026-10-22 12:30 UTC374
/// let device_id = "DEVICEID".into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC375
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC376
/// let machine = OlmMachine::new(user_id, device_id).await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC377
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC378
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC379
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC380
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC381
/// This will create a [`OlmMachine`] that does not persist any data TODO
7ff8adafe9e4atagen2026-10-22 12:30 UTC382
/// ```ignore
7ff8adafe9e4atagen2026-10-22 12:30 UTC383
/// use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC384
/// use matrix_sdk_crypto::OlmMachine;
7ff8adafe9e4atagen2026-10-22 12:30 UTC385
/// use matrix_sdk_sqlite::SqliteCryptoStore;
7ff8adafe9e4atagen2026-10-22 12:30 UTC386
/// use ruma::user_id;
7ff8adafe9e4atagen2026-10-22 12:30 UTC387
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC388
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC389
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC390
/// let user_id = user_id!("@alice:localhost");
7ff8adafe9e4atagen2026-10-22 12:30 UTC391
/// let device_id = "DEVICEID".into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC392
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC393
/// let store = SqliteCryptoStore::open("/home/example/matrix-client/", None).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC394
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC395
/// let machine = OlmMachine::with_store(user_id, device_id, store).await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC396
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC397
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC398
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC399
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC400
/// # Decryption
7ff8adafe9e4atagen2026-10-22 12:30 UTC401
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC402
/// In the world of encrypted communication, it is common to start with the
7ff8adafe9e4atagen2026-10-22 12:30 UTC403
/// encryption step when implementing a protocol. However, in the case of adding
7ff8adafe9e4atagen2026-10-22 12:30 UTC404
/// end-to-end encryption support to a Matrix client library, a simpler approach
7ff8adafe9e4atagen2026-10-22 12:30 UTC405
/// is to first focus on the decryption process. This is because there are
7ff8adafe9e4atagen2026-10-22 12:30 UTC406
/// already Matrix clients in existence that support encryption, which means
7ff8adafe9e4atagen2026-10-22 12:30 UTC407
/// that our client library can simply receive encrypted messages and then
7ff8adafe9e4atagen2026-10-22 12:30 UTC408
/// decrypt them.
7ff8adafe9e4atagen2026-10-22 12:30 UTC409
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC410
/// In this section, we will guide you through the minimal steps
7ff8adafe9e4atagen2026-10-22 12:30 UTC411
/// necessary to get the decryption process up and running using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC412
/// matrix-sdk-crypto Rust crate. By the end of this section you should have a
7ff8adafe9e4atagen2026-10-22 12:30 UTC413
/// Matrix client that is able to decrypt room events that other clients have
7ff8adafe9e4atagen2026-10-22 12:30 UTC414
/// sent.
7ff8adafe9e4atagen2026-10-22 12:30 UTC415
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC416
/// To enable decryption the following three steps are needed:
7ff8adafe9e4atagen2026-10-22 12:30 UTC417
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC418
/// 1. [The cryptographic identity of your device needs to be published to the
7ff8adafe9e4atagen2026-10-22 12:30 UTC419
///    homeserver](#uploading-identity-and-one-time-keys).
7ff8adafe9e4atagen2026-10-22 12:30 UTC420
/// 2. [Decryption keys coming in from other devices need to be processed and
7ff8adafe9e4atagen2026-10-22 12:30 UTC421
///    stored](#receiving-room-keys-and-related-changes).
7ff8adafe9e4atagen2026-10-22 12:30 UTC422
/// 3. [Individual messages need to be decrypted](#decrypting-room-events).
7ff8adafe9e4atagen2026-10-22 12:30 UTC423
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC424
/// The simplified flowchart
7ff8adafe9e4atagen2026-10-22 12:30 UTC425
/// ```mermaid
7ff8adafe9e4atagen2026-10-22 12:30 UTC426
/// graph TD
7ff8adafe9e4atagen2026-10-22 12:30 UTC427
///     sync[Sync with the homeserver]
7ff8adafe9e4atagen2026-10-22 12:30 UTC428
///     receive_changes[Push E2EE related changes into the state machine]
7ff8adafe9e4atagen2026-10-22 12:30 UTC429
///     send_outgoing_requests[Send all outgoing requests to the homeserver]
7ff8adafe9e4atagen2026-10-22 12:30 UTC430
///     decrypt[Process the rest of the sync]
7ff8adafe9e4atagen2026-10-22 12:30 UTC431
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC432
///     sync --> receive_changes;
7ff8adafe9e4atagen2026-10-22 12:30 UTC433
///     receive_changes --> send_outgoing_requests;
7ff8adafe9e4atagen2026-10-22 12:30 UTC434
///     send_outgoing_requests --> decrypt;
7ff8adafe9e4atagen2026-10-22 12:30 UTC435
///     decrypt -- repeat --> sync;
7ff8adafe9e4atagen2026-10-22 12:30 UTC436
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC437
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC438
/// ## Uploading identity and one-time keys.
7ff8adafe9e4atagen2026-10-22 12:30 UTC439
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC440
/// To enable end-to-end encryption in a Matrix client, the first step is to
7ff8adafe9e4atagen2026-10-22 12:30 UTC441
/// announce the support for it to other users in the network. This is done by
7ff8adafe9e4atagen2026-10-22 12:30 UTC442
/// publishing the client's long-term device keys and a set of one-time prekeys
7ff8adafe9e4atagen2026-10-22 12:30 UTC443
/// to the Matrix homeserver. The homeserver then makes this information
7ff8adafe9e4atagen2026-10-22 12:30 UTC444
/// available to other devices in the network.
7ff8adafe9e4atagen2026-10-22 12:30 UTC445
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC446
/// The long-term device keys and one-time prekeys allow other devices to
7ff8adafe9e4atagen2026-10-22 12:30 UTC447
/// encrypt messages specifically for your device.
7ff8adafe9e4atagen2026-10-22 12:30 UTC448
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC449
/// To achieve this, you will need to extract any requests that need to be sent
7ff8adafe9e4atagen2026-10-22 12:30 UTC450
/// to the homeserver from the [`OlmMachine`] and send them to the homeserver.
7ff8adafe9e4atagen2026-10-22 12:30 UTC451
/// The following snippet showcases how to achieve this using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC452
/// [`OlmMachine::outgoing_requests()`] method:
7ff8adafe9e4atagen2026-10-22 12:30 UTC453
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC454
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC455
/// # use std::collections::BTreeMap;
7ff8adafe9e4atagen2026-10-22 12:30 UTC456
/// # use ruma::api::client::keys::upload_keys::v3::Response;
7ff8adafe9e4atagen2026-10-22 12:30 UTC457
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC458
/// # use matrix_sdk_crypto::{OlmMachine, types::requests::OutgoingRequest};
7ff8adafe9e4atagen2026-10-22 12:30 UTC459
/// # async fn send_request(request: OutgoingRequest) -> Result<Response> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC460
/// #     let response = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC461
/// #     Ok(response)
7ff8adafe9e4atagen2026-10-22 12:30 UTC462
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC463
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC464
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC465
/// # let machine: OlmMachine = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC466
/// // Get all the outgoing requests.
7ff8adafe9e4atagen2026-10-22 12:30 UTC467
/// let outgoing_requests = machine.outgoing_requests().await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC468
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC469
/// // Send each request to the server and push the response into the state machine.
7ff8adafe9e4atagen2026-10-22 12:30 UTC470
/// // You can safely send these requests out in parallel.
7ff8adafe9e4atagen2026-10-22 12:30 UTC471
/// for request in outgoing_requests {
7ff8adafe9e4atagen2026-10-22 12:30 UTC472
///     let request_id = request.request_id();
7ff8adafe9e4atagen2026-10-22 12:30 UTC473
///     // Send the request to the server and await a response.
7ff8adafe9e4atagen2026-10-22 12:30 UTC474
///     let response = send_request(request).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC475
///     // Push the response into the state machine.
7ff8adafe9e4atagen2026-10-22 12:30 UTC476
///     machine.mark_request_as_sent(&request_id, &response).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC477
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC478
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC479
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC480
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC481
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC482
/// #### 🔒 Locking rule
7ff8adafe9e4atagen2026-10-22 12:30 UTC483
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC484
/// It's important to note that the outgoing requests method in the
7ff8adafe9e4atagen2026-10-22 12:30 UTC485
/// [`OlmMachine`], while thread-safe, may return the same request multiple
7ff8adafe9e4atagen2026-10-22 12:30 UTC486
/// times if it is called multiple times before the request has been marked as
7ff8adafe9e4atagen2026-10-22 12:30 UTC487
/// sent. To prevent this issue, it is advisable to encapsulate the outgoing
7ff8adafe9e4atagen2026-10-22 12:30 UTC488
/// request handling logic into a separate helper method and protect it from
7ff8adafe9e4atagen2026-10-22 12:30 UTC489
/// being called multiple times concurrently using a lock.
7ff8adafe9e4atagen2026-10-22 12:30 UTC490
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC491
/// This helps to ensure that the request is only handled once and prevents
7ff8adafe9e4atagen2026-10-22 12:30 UTC492
/// multiple identical requests from being sent.
7ff8adafe9e4atagen2026-10-22 12:30 UTC493
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC494
/// Additionally, if an error occurs while sending a request using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC495
/// [`OlmMachine::outgoing_requests()`] method, the request will be
7ff8adafe9e4atagen2026-10-22 12:30 UTC496
/// naturally retried the next time the method is called.
7ff8adafe9e4atagen2026-10-22 12:30 UTC497
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC498
/// A more complete example, which uses a helper method, might look like this:
7ff8adafe9e4atagen2026-10-22 12:30 UTC499
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC500
/// # use std::collections::BTreeMap;
7ff8adafe9e4atagen2026-10-22 12:30 UTC501
/// # use ruma::api::client::keys::upload_keys::v3::Response;
7ff8adafe9e4atagen2026-10-22 12:30 UTC502
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC503
/// # use matrix_sdk_crypto::{OlmMachine, types::requests::OutgoingRequest};
7ff8adafe9e4atagen2026-10-22 12:30 UTC504
/// # async fn send_request(request: &OutgoingRequest) -> Result<Response> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC505
/// #     let response = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC506
/// #     Ok(response)
7ff8adafe9e4atagen2026-10-22 12:30 UTC507
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC508
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC509
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC510
/// struct Client {
7ff8adafe9e4atagen2026-10-22 12:30 UTC511
///     outgoing_requests_lock: tokio::sync::Mutex<()>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC512
///     olm_machine: OlmMachine,
7ff8adafe9e4atagen2026-10-22 12:30 UTC513
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC514
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC515
/// async fn process_outgoing_requests(client: &Client) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC516
///     // Let's acquire a lock so we know that we don't send out the same request out multiple
7ff8adafe9e4atagen2026-10-22 12:30 UTC517
///     // times.
7ff8adafe9e4atagen2026-10-22 12:30 UTC518
///     let guard = client.outgoing_requests_lock.lock().await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC519
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC520
///     for request in client.olm_machine.outgoing_requests().await? {
7ff8adafe9e4atagen2026-10-22 12:30 UTC521
///         let request_id = request.request_id();
7ff8adafe9e4atagen2026-10-22 12:30 UTC522
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC523
///         match send_request(&request).await {
7ff8adafe9e4atagen2026-10-22 12:30 UTC524
///             Ok(response) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC525
///                 client.olm_machine.mark_request_as_sent(&request_id, &response).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC526
///             }
7ff8adafe9e4atagen2026-10-22 12:30 UTC527
///             Err(error) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC528
///                 // It's OK to ignore transient HTTP errors since requests will be retried.
7ff8adafe9e4atagen2026-10-22 12:30 UTC529
///                 eprintln!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC530
///                     "Error while sending out a end-to-end encryption \
7ff8adafe9e4atagen2026-10-22 12:30 UTC531
///                     related request: {error:?}"
7ff8adafe9e4atagen2026-10-22 12:30 UTC532
///                 );
7ff8adafe9e4atagen2026-10-22 12:30 UTC533
///             }
7ff8adafe9e4atagen2026-10-22 12:30 UTC534
///         }
7ff8adafe9e4atagen2026-10-22 12:30 UTC535
///     }
7ff8adafe9e4atagen2026-10-22 12:30 UTC536
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC537
///     Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC538
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC539
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC540
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC541
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC542
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC543
/// Once we have the helper method that processes our outgoing requests we can
7ff8adafe9e4atagen2026-10-22 12:30 UTC544
/// structure our sync method as follows:
7ff8adafe9e4atagen2026-10-22 12:30 UTC545
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC546
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC547
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC548
/// # use matrix_sdk_crypto::OlmMachine;
7ff8adafe9e4atagen2026-10-22 12:30 UTC549
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC550
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC551
/// # struct Client {
7ff8adafe9e4atagen2026-10-22 12:30 UTC552
/// #     outgoing_requests_lock: tokio::sync::Mutex<()>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC553
/// #     olm_machine: OlmMachine,
7ff8adafe9e4atagen2026-10-22 12:30 UTC554
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC555
/// # async fn process_outgoing_requests(client: &Client) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC556
/// #    unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC557
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC558
/// # async fn send_out_sync_request(client: &Client) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC559
/// #    unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC560
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC561
/// async fn sync(client: &Client) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC562
///     // This is happening at the top of the method so we advertise our
7ff8adafe9e4atagen2026-10-22 12:30 UTC563
///     // end-to-end encryption capabilities as soon as possible.
7ff8adafe9e4atagen2026-10-22 12:30 UTC564
///     process_outgoing_requests(client).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC565
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC566
///     // We can sync with the homeserver now.
7ff8adafe9e4atagen2026-10-22 12:30 UTC567
///     let response = send_out_sync_request(client).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC568
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC569
///     // Process the sync response here.
7ff8adafe9e4atagen2026-10-22 12:30 UTC570
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC571
///     Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC572
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC573
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC574
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC575
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC576
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC577
/// ## Receiving room keys and related changes
7ff8adafe9e4atagen2026-10-22 12:30 UTC578
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC579
/// The next step in our implementation is to forward messages that were sent
7ff8adafe9e4atagen2026-10-22 12:30 UTC580
/// directly to the client's device, and state updates about the one-time
7ff8adafe9e4atagen2026-10-22 12:30 UTC581
/// prekeys, to the [`OlmMachine`]. This is achieved using
7ff8adafe9e4atagen2026-10-22 12:30 UTC582
/// the [`OlmMachine::receive_sync_changes()`] method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC583
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC584
/// The method performs two tasks:
7ff8adafe9e4atagen2026-10-22 12:30 UTC585
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC586
/// 1. It processes and, if necessary, decrypts each [to-device] event that was
7ff8adafe9e4atagen2026-10-22 12:30 UTC587
///    pushed into it, and returns the decrypted events. The original events are
7ff8adafe9e4atagen2026-10-22 12:30 UTC588
///    replaced with their decrypted versions.
7ff8adafe9e4atagen2026-10-22 12:30 UTC589
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC590
/// 2. It produces internal state changes that may trigger the creation of new
7ff8adafe9e4atagen2026-10-22 12:30 UTC591
///    outgoing requests. For example, if the server informs the client that its
7ff8adafe9e4atagen2026-10-22 12:30 UTC592
///    one-time prekeys have been depleted, the OlmMachine will create an
7ff8adafe9e4atagen2026-10-22 12:30 UTC593
///    outgoing request to replenish them.
7ff8adafe9e4atagen2026-10-22 12:30 UTC594
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC595
/// Our updated sync method now looks like this:
7ff8adafe9e4atagen2026-10-22 12:30 UTC596
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC597
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC598
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC599
/// # use matrix_sdk_crypto::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC600
///     DecryptionSettings, EncryptionSyncChanges, OlmMachine, TrustRequirement
7ff8adafe9e4atagen2026-10-22 12:30 UTC601
/// };
7ff8adafe9e4atagen2026-10-22 12:30 UTC602
/// # use ruma::api::client::sync::sync_events::v3::Response;
7ff8adafe9e4atagen2026-10-22 12:30 UTC603
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC604
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC605
/// # struct Client {
7ff8adafe9e4atagen2026-10-22 12:30 UTC606
/// #     outgoing_requests_lock: tokio::sync::Mutex<()>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC607
/// #     olm_machine: OlmMachine,
7ff8adafe9e4atagen2026-10-22 12:30 UTC608
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC609
/// # async fn process_outgoing_requests(client: &Client) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC610
/// #    unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC611
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC612
/// # async fn send_out_sync_request(client: &Client) -> Result<Response> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC613
/// #    unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC614
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC615
/// async fn sync(client: &Client) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC616
///     process_outgoing_requests(client).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC617
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC618
///     let response = send_out_sync_request(client).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC619
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC620
///     let sync_changes = EncryptionSyncChanges {
7ff8adafe9e4atagen2026-10-22 12:30 UTC621
///         to_device_events: response.to_device.events,
7ff8adafe9e4atagen2026-10-22 12:30 UTC622
///         changed_devices: &response.device_lists,
7ff8adafe9e4atagen2026-10-22 12:30 UTC623
///         one_time_keys_counts: &response.device_one_time_keys_count,
7ff8adafe9e4atagen2026-10-22 12:30 UTC624
///         unused_fallback_keys: response.device_unused_fallback_key_types.as_deref(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC625
///         next_batch_token: Some(response.next_batch),
7ff8adafe9e4atagen2026-10-22 12:30 UTC626
///     };
7ff8adafe9e4atagen2026-10-22 12:30 UTC627
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC628
///     let decryption_settings = DecryptionSettings {
7ff8adafe9e4atagen2026-10-22 12:30 UTC629
///         sender_device_trust_requirement: TrustRequirement::Untrusted
7ff8adafe9e4atagen2026-10-22 12:30 UTC630
///     };
7ff8adafe9e4atagen2026-10-22 12:30 UTC631
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC632
///     // Push the sync changes into the OlmMachine, make sure that this is
7ff8adafe9e4atagen2026-10-22 12:30 UTC633
///     // happening before the `next_batch` token of the sync is persisted.
7ff8adafe9e4atagen2026-10-22 12:30 UTC634
///     let to_device_events = client
7ff8adafe9e4atagen2026-10-22 12:30 UTC635
///         .olm_machine
7ff8adafe9e4atagen2026-10-22 12:30 UTC636
///         .receive_sync_changes(sync_changes, &decryption_settings)
7ff8adafe9e4atagen2026-10-22 12:30 UTC637
///         .await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC638
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC639
///     // Send the outgoing requests out that the sync changes produced.
7ff8adafe9e4atagen2026-10-22 12:30 UTC640
///     process_outgoing_requests(client).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC641
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC642
///     // Process the rest of the sync response here.
7ff8adafe9e4atagen2026-10-22 12:30 UTC643
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC644
///     Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC645
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC646
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC647
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC648
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC649
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC650
/// It is important to note that the names of the fields in the response shown
7ff8adafe9e4atagen2026-10-22 12:30 UTC651
/// in the example match the names of the fields specified in the [sync]
7ff8adafe9e4atagen2026-10-22 12:30 UTC652
/// response specification.
7ff8adafe9e4atagen2026-10-22 12:30 UTC653
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC654
/// It is critical to note that due to the ephemeral nature of to-device
7ff8adafe9e4atagen2026-10-22 12:30 UTC655
/// events[[1]], it is important to process these events before persisting the
7ff8adafe9e4atagen2026-10-22 12:30 UTC656
/// `next_batch` sync token. This is because if the `next_batch` sync token is
7ff8adafe9e4atagen2026-10-22 12:30 UTC657
/// persisted before processing the to-device events, some messages might be
7ff8adafe9e4atagen2026-10-22 12:30 UTC658
/// lost, leading to decryption failures.
7ff8adafe9e4atagen2026-10-22 12:30 UTC659
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC660
/// ## Decrypting room events
7ff8adafe9e4atagen2026-10-22 12:30 UTC661
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC662
/// The final step in the decryption process is to decrypt the room events that
7ff8adafe9e4atagen2026-10-22 12:30 UTC663
/// are received from the server. To do this, the encrypted events must be
7ff8adafe9e4atagen2026-10-22 12:30 UTC664
/// passed to the [`OlmMachine`], which will use the keys that were previously
7ff8adafe9e4atagen2026-10-22 12:30 UTC665
/// exchanged between devices to decrypt the events. The decrypted events can
7ff8adafe9e4atagen2026-10-22 12:30 UTC666
/// then be processed and displayed to the user in the Matrix client.
7ff8adafe9e4atagen2026-10-22 12:30 UTC667
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC668
/// Room message [events] can be decrypted using the
7ff8adafe9e4atagen2026-10-22 12:30 UTC669
/// [`OlmMachine::decrypt_room_event()`] method:
7ff8adafe9e4atagen2026-10-22 12:30 UTC670
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC671
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC672
/// # use std::collections::BTreeMap;
7ff8adafe9e4atagen2026-10-22 12:30 UTC673
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC674
/// # use matrix_sdk_crypto::{OlmMachine, DecryptionSettings, TrustRequirement};
7ff8adafe9e4atagen2026-10-22 12:30 UTC675
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC676
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC677
/// # let encrypted = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC678
/// # let room_id = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC679
/// # let machine: OlmMachine = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC680
/// # let settings = DecryptionSettings { sender_device_trust_requirement: TrustRequirement::Untrusted };
7ff8adafe9e4atagen2026-10-22 12:30 UTC681
/// // Decrypt your room events now.
7ff8adafe9e4atagen2026-10-22 12:30 UTC682
/// let decrypted = machine
7ff8adafe9e4atagen2026-10-22 12:30 UTC683
///     .decrypt_room_event(encrypted, room_id, &settings)
7ff8adafe9e4atagen2026-10-22 12:30 UTC684
///     .await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC685
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC686
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC687
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC688
/// It's worth mentioning that the [`OlmMachine::decrypt_room_event()`] method
7ff8adafe9e4atagen2026-10-22 12:30 UTC689
/// is designed to be thread-safe and can be safely called concurrently. This
7ff8adafe9e4atagen2026-10-22 12:30 UTC690
/// means that room message [events] can be processed in parallel, improving the
7ff8adafe9e4atagen2026-10-22 12:30 UTC691
/// overall efficiency of the end-to-end encryption implementation.
7ff8adafe9e4atagen2026-10-22 12:30 UTC692
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC693
/// By allowing room message [events] to be processed concurrently, the client's
7ff8adafe9e4atagen2026-10-22 12:30 UTC694
/// implementation can take full advantage of the capabilities of modern
7ff8adafe9e4atagen2026-10-22 12:30 UTC695
/// hardware and achieve better performance, especially when dealing with a
7ff8adafe9e4atagen2026-10-22 12:30 UTC696
/// large number of messages at once.
7ff8adafe9e4atagen2026-10-22 12:30 UTC697
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC698
/// # Encryption
7ff8adafe9e4atagen2026-10-22 12:30 UTC699
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC700
/// In this section of the guide, we will focus on enabling the encryption of
7ff8adafe9e4atagen2026-10-22 12:30 UTC701
/// messages in our Matrix client library. Up until this point, we have been
7ff8adafe9e4atagen2026-10-22 12:30 UTC702
/// discussing the process of decrypting messages that have been encrypted by
7ff8adafe9e4atagen2026-10-22 12:30 UTC703
/// other devices. Now, we will shift our focus to the process of encrypting
7ff8adafe9e4atagen2026-10-22 12:30 UTC704
/// messages on the client side, so that they can be securely transmitted over
7ff8adafe9e4atagen2026-10-22 12:30 UTC705
/// the Matrix network to other devices.
7ff8adafe9e4atagen2026-10-22 12:30 UTC706
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC707
/// This section will guide you through the steps required to set up the
7ff8adafe9e4atagen2026-10-22 12:30 UTC708
/// encryption process, including establishing the necessary sessions and
7ff8adafe9e4atagen2026-10-22 12:30 UTC709
/// encrypting messages using the Megolm group session. The specific steps are
7ff8adafe9e4atagen2026-10-22 12:30 UTC710
/// outlined below:
7ff8adafe9e4atagen2026-10-22 12:30 UTC711
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC712
/// 1. [Cryptographic devices of other users need to be
7ff8adafe9e4atagen2026-10-22 12:30 UTC713
///    discovered](#tracking-users)
7ff8adafe9e4atagen2026-10-22 12:30 UTC714
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC715
/// 2. [Secure channels between the devices need to be
7ff8adafe9e4atagen2026-10-22 12:30 UTC716
///    established](#establishing-end-to-end-encrypted-channels)
7ff8adafe9e4atagen2026-10-22 12:30 UTC717
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC718
/// 3. [A room key needs to be exchanged with the group](#exchanging-room-keys)
7ff8adafe9e4atagen2026-10-22 12:30 UTC719
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC720
/// 4. [Individual messages need to be encrypted using the room
7ff8adafe9e4atagen2026-10-22 12:30 UTC721
///    key](#encrypting-room-events)
7ff8adafe9e4atagen2026-10-22 12:30 UTC722
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC723
/// The process for enabling encryption in a two-device scenario is also
7ff8adafe9e4atagen2026-10-22 12:30 UTC724
/// depicted in the following sequence diagram:
7ff8adafe9e4atagen2026-10-22 12:30 UTC725
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC726
/// ```mermaid
7ff8adafe9e4atagen2026-10-22 12:30 UTC727
/// sequenceDiagram
7ff8adafe9e4atagen2026-10-22 12:30 UTC728
/// actor Alice
7ff8adafe9e4atagen2026-10-22 12:30 UTC729
/// participant Homeserver
7ff8adafe9e4atagen2026-10-22 12:30 UTC730
/// actor Bob
7ff8adafe9e4atagen2026-10-22 12:30 UTC731
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC732
/// Alice->>Homeserver: Download Bob's one-time prekey
7ff8adafe9e4atagen2026-10-22 12:30 UTC733
/// Homeserver->>Alice: Bob's one-time prekey
7ff8adafe9e4atagen2026-10-22 12:30 UTC734
/// Alice->>Alice: Encrypt the room key
7ff8adafe9e4atagen2026-10-22 12:30 UTC735
/// Alice->>Homeserver: Send the room key to each of Bob's devices
7ff8adafe9e4atagen2026-10-22 12:30 UTC736
/// Homeserver->>Bob: Deliver the room key
7ff8adafe9e4atagen2026-10-22 12:30 UTC737
/// Alice->>Alice: Encrypt the message
7ff8adafe9e4atagen2026-10-22 12:30 UTC738
/// Alice->>Homeserver: Send the encrypted message
7ff8adafe9e4atagen2026-10-22 12:30 UTC739
/// Homeserver->>Bob: Deliver the encrypted message
7ff8adafe9e4atagen2026-10-22 12:30 UTC740
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC741
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC742
/// In the following subsections, we will provide a step-by-step guide on how to
7ff8adafe9e4atagen2026-10-22 12:30 UTC743
/// enable the encryption of messages using the OlmMachine. We will outline the
7ff8adafe9e4atagen2026-10-22 12:30 UTC744
/// specific method calls and usage patterns that are required to establish the
7ff8adafe9e4atagen2026-10-22 12:30 UTC745
/// necessary sessions, encrypt messages, and send them over the Matrix network.
7ff8adafe9e4atagen2026-10-22 12:30 UTC746
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC747
/// ## Tracking users
7ff8adafe9e4atagen2026-10-22 12:30 UTC748
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC749
/// The first step in the process of encrypting a message and sending it to a
7ff8adafe9e4atagen2026-10-22 12:30 UTC750
/// device is to discover the devices that the recipient user has. This can be
7ff8adafe9e4atagen2026-10-22 12:30 UTC751
/// achieved by sending a request to the homeserver to retrieve a list of the
7ff8adafe9e4atagen2026-10-22 12:30 UTC752
/// recipient's device keys. The response to this request will include the
7ff8adafe9e4atagen2026-10-22 12:30 UTC753
/// device keys for all of the devices that belong to the recipient, as well as
7ff8adafe9e4atagen2026-10-22 12:30 UTC754
/// information about their current status and whether or not they support
7ff8adafe9e4atagen2026-10-22 12:30 UTC755
/// end-to-end encryption.
7ff8adafe9e4atagen2026-10-22 12:30 UTC756
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC757
/// The process for discovering and keeping track of devices for a user is
7ff8adafe9e4atagen2026-10-22 12:30 UTC758
/// outlined in the Matrix specification in the "[Tracking the device list for a
7ff8adafe9e4atagen2026-10-22 12:30 UTC759
/// user]" section.
7ff8adafe9e4atagen2026-10-22 12:30 UTC760
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC761
/// A simplified sequence diagram of the process can also be found below.
7ff8adafe9e4atagen2026-10-22 12:30 UTC762
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC763
/// ```mermaid
7ff8adafe9e4atagen2026-10-22 12:30 UTC764
/// sequenceDiagram
7ff8adafe9e4atagen2026-10-22 12:30 UTC765
/// actor Alice
7ff8adafe9e4atagen2026-10-22 12:30 UTC766
/// participant Homeserver
7ff8adafe9e4atagen2026-10-22 12:30 UTC767
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC768
/// Alice->>Homeserver: Sync with the homeserver
7ff8adafe9e4atagen2026-10-22 12:30 UTC769
/// Homeserver->>Alice: Users whose device list has changed
7ff8adafe9e4atagen2026-10-22 12:30 UTC770
/// Alice->>Alice: Mark user's devicel list as outdated
7ff8adafe9e4atagen2026-10-22 12:30 UTC771
/// Alice->>Homeserver: Ask the server for the new device list of all the outdated users
7ff8adafe9e4atagen2026-10-22 12:30 UTC772
/// Alice->>Alice: Update the local device list and mark the users as up-to-date
7ff8adafe9e4atagen2026-10-22 12:30 UTC773
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC774
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC775
/// The OlmMachine refers to users whose devices we are tracking as "tracked
7ff8adafe9e4atagen2026-10-22 12:30 UTC776
/// users" and utilizes the [`OlmMachine::update_tracked_users()`] method to
7ff8adafe9e4atagen2026-10-22 12:30 UTC777
/// start considering users to be tracked. Keeping the above diagram in mind, we
7ff8adafe9e4atagen2026-10-22 12:30 UTC778
/// can now update our sync method as follows:
7ff8adafe9e4atagen2026-10-22 12:30 UTC779
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC780
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC781
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC782
/// # use std::ops::Deref;
7ff8adafe9e4atagen2026-10-22 12:30 UTC783
/// # use matrix_sdk_crypto::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC784
/// #     DecryptionSettings, EncryptionSyncChanges, OlmMachine, TrustRequirement
7ff8adafe9e4atagen2026-10-22 12:30 UTC785
/// # };
7ff8adafe9e4atagen2026-10-22 12:30 UTC786
/// # use ruma::api::client::sync::sync_events::v3::{Response, State, JoinedRoom};
7ff8adafe9e4atagen2026-10-22 12:30 UTC787
/// # use ruma::{OwnedUserId, serde::Raw, events::AnySyncStateEvent};
7ff8adafe9e4atagen2026-10-22 12:30 UTC788
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC789
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC790
/// # struct Client {
7ff8adafe9e4atagen2026-10-22 12:30 UTC791
/// #     outgoing_requests_lock: tokio::sync::Mutex<()>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC792
/// #     olm_machine: OlmMachine,
7ff8adafe9e4atagen2026-10-22 12:30 UTC793
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC794
/// # async fn process_outgoing_requests(client: &Client) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC795
/// #    unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC796
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC797
/// # async fn send_out_sync_request(client: &Client) -> Result<Response> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC798
/// #    unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC799
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC800
/// # fn is_member_event_of_a_joined_user(event: &Raw<AnySyncStateEvent>) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC801
/// #     true
7ff8adafe9e4atagen2026-10-22 12:30 UTC802
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC803
/// # fn get_user_id(event: &Raw<AnySyncStateEvent>) -> OwnedUserId {
7ff8adafe9e4atagen2026-10-22 12:30 UTC804
/// #     unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC805
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC806
/// # fn is_room_encrypted(room: &JoinedRoom) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC807
/// #     true
7ff8adafe9e4atagen2026-10-22 12:30 UTC808
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC809
/// async fn sync(client: &Client) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC810
///     process_outgoing_requests(client).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC811
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC812
///     let response = send_out_sync_request(client).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC813
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC814
///     let sync_changes = EncryptionSyncChanges {
7ff8adafe9e4atagen2026-10-22 12:30 UTC815
///         to_device_events: response.to_device.events,
7ff8adafe9e4atagen2026-10-22 12:30 UTC816
///         changed_devices: &response.device_lists,
7ff8adafe9e4atagen2026-10-22 12:30 UTC817
///         one_time_keys_counts: &response.device_one_time_keys_count,
7ff8adafe9e4atagen2026-10-22 12:30 UTC818
///         unused_fallback_keys: response.device_unused_fallback_key_types.as_deref(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC819
///         next_batch_token: Some(response.next_batch),
7ff8adafe9e4atagen2026-10-22 12:30 UTC820
///     };
7ff8adafe9e4atagen2026-10-22 12:30 UTC821
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC822
///     let decryption_settings = DecryptionSettings {
7ff8adafe9e4atagen2026-10-22 12:30 UTC823
///         sender_device_trust_requirement: TrustRequirement::Untrusted
7ff8adafe9e4atagen2026-10-22 12:30 UTC824
///     };
7ff8adafe9e4atagen2026-10-22 12:30 UTC825
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC826
///     // Push the sync changes into the OlmMachine, make sure that this is
7ff8adafe9e4atagen2026-10-22 12:30 UTC827
///     // happening before the `next_batch` token of the sync is persisted.
7ff8adafe9e4atagen2026-10-22 12:30 UTC828
///     let to_device_events = client
7ff8adafe9e4atagen2026-10-22 12:30 UTC829
///         .olm_machine
7ff8adafe9e4atagen2026-10-22 12:30 UTC830
///         .receive_sync_changes(sync_changes, &decryption_settings)
7ff8adafe9e4atagen2026-10-22 12:30 UTC831
///         .await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC832
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC833
///     // Send the outgoing requests out that the sync changes produced.
7ff8adafe9e4atagen2026-10-22 12:30 UTC834
///     process_outgoing_requests(client).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC835
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC836
///     // Collect all the joined and invited users of our end-to-end encrypted rooms here.
7ff8adafe9e4atagen2026-10-22 12:30 UTC837
///     let mut users = Vec::new();
7ff8adafe9e4atagen2026-10-22 12:30 UTC838
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC839
///     for (_, room) in &response.rooms.join {
7ff8adafe9e4atagen2026-10-22 12:30 UTC840
///         // For simplicity reasons we're only looking at the state field of a joined room, but
7ff8adafe9e4atagen2026-10-22 12:30 UTC841
///         // the events in the timeline are important as well.
7ff8adafe9e4atagen2026-10-22 12:30 UTC842
///         if let State::Before(state) = &room.state {
7ff8adafe9e4atagen2026-10-22 12:30 UTC843
///            for event in &state.events {
7ff8adafe9e4atagen2026-10-22 12:30 UTC844
///                 if is_member_event_of_a_joined_user(event) && is_room_encrypted(room) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC845
///                     let user_id = get_user_id(event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC846
///                     users.push(user_id);
7ff8adafe9e4atagen2026-10-22 12:30 UTC847
///                 }
7ff8adafe9e4atagen2026-10-22 12:30 UTC848
///             }
7ff8adafe9e4atagen2026-10-22 12:30 UTC849
///         }
7ff8adafe9e4atagen2026-10-22 12:30 UTC850
///     }
7ff8adafe9e4atagen2026-10-22 12:30 UTC851
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC852
///     // Mark all the users that we consider to be in a end-to-end encrypted room with us to be
7ff8adafe9e4atagen2026-10-22 12:30 UTC853
///     // tracked. We need to know about all the devices each user has so we can later encrypt
7ff8adafe9e4atagen2026-10-22 12:30 UTC854
///     // messages for each of their devices.
7ff8adafe9e4atagen2026-10-22 12:30 UTC855
///     client.olm_machine.update_tracked_users(users.iter().map(Deref::deref)).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC856
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC857
///     // Process the rest of the sync response here.
7ff8adafe9e4atagen2026-10-22 12:30 UTC858
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC859
///     Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC860
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC861
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC862
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC863
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC864
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC865
/// Now that we have discovered the devices of the users we'd like to
7ff8adafe9e4atagen2026-10-22 12:30 UTC866
/// communicate with in an end-to-end encrypted manner, we can start considering
7ff8adafe9e4atagen2026-10-22 12:30 UTC867
/// encrypting messages for those devices. This concludes the sync processing
7ff8adafe9e4atagen2026-10-22 12:30 UTC868
/// method, we are now ready to move on to the next section, which will explain
7ff8adafe9e4atagen2026-10-22 12:30 UTC869
/// how to begin the encryption process.
7ff8adafe9e4atagen2026-10-22 12:30 UTC870
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC871
/// ## Establishing end-to-end encrypted channels
7ff8adafe9e4atagen2026-10-22 12:30 UTC872
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC873
/// In the [Triple
7ff8adafe9e4atagen2026-10-22 12:30 UTC874
/// Diffie-Hellman](#using-the-triple-diffie-hellman-key-agreement-protocol)
7ff8adafe9e4atagen2026-10-22 12:30 UTC875
/// section, we described the need for two Curve25519 keys from the recipient
7ff8adafe9e4atagen2026-10-22 12:30 UTC876
/// device to establish a 1-to-1 secure channel: the long-term identity key of a
7ff8adafe9e4atagen2026-10-22 12:30 UTC877
/// device and a one-time prekey. In the previous section, we started tracking
7ff8adafe9e4atagen2026-10-22 12:30 UTC878
/// the device keys, including the long-term identity key that we need. The next
7ff8adafe9e4atagen2026-10-22 12:30 UTC879
/// step is to download the one-time prekey on an on-demand basis and establish
7ff8adafe9e4atagen2026-10-22 12:30 UTC880
/// the 1-to-1 secure channel.
7ff8adafe9e4atagen2026-10-22 12:30 UTC881
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC882
/// To accomplish this, we can use the [`OlmMachine::get_missing_sessions()`]
7ff8adafe9e4atagen2026-10-22 12:30 UTC883
/// method in bulk, which will claim the one-time prekey for all the devices of
7ff8adafe9e4atagen2026-10-22 12:30 UTC884
/// a user that we're not already sharing a 1-to-1 encrypted channel with.
7ff8adafe9e4atagen2026-10-22 12:30 UTC885
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC886
/// #### 🔒 Locking rule
7ff8adafe9e4atagen2026-10-22 12:30 UTC887
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC888
/// As with the [`OlmMachine::outgoing_requests()`] method, it is necessary to
7ff8adafe9e4atagen2026-10-22 12:30 UTC889
/// protect this method with a lock, otherwise we will be creating more 1-to-1
7ff8adafe9e4atagen2026-10-22 12:30 UTC890
/// encrypted channels than necessary.
7ff8adafe9e4atagen2026-10-22 12:30 UTC891
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC892
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC893
/// # use std::collections::{BTreeMap, HashSet};
7ff8adafe9e4atagen2026-10-22 12:30 UTC894
/// # use std::ops::Deref;
7ff8adafe9e4atagen2026-10-22 12:30 UTC895
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC896
/// # use ruma::UserId;
7ff8adafe9e4atagen2026-10-22 12:30 UTC897
/// # use ruma::api::client::keys::claim_keys::v3::{Response, Request};
7ff8adafe9e4atagen2026-10-22 12:30 UTC898
/// # use matrix_sdk_crypto::OlmMachine;
7ff8adafe9e4atagen2026-10-22 12:30 UTC899
/// # async fn send_request(request: &Request) -> Result<Response> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC900
/// #     let response = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC901
/// #     Ok(response)
7ff8adafe9e4atagen2026-10-22 12:30 UTC902
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC903
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC904
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC905
/// # let users: HashSet<&UserId> = HashSet::new();
7ff8adafe9e4atagen2026-10-22 12:30 UTC906
/// # let machine: OlmMachine = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC907
/// // Mark all the users that are part of an encrypted room as tracked
7ff8adafe9e4atagen2026-10-22 12:30 UTC908
/// if let Some((request_id, request)) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC909
///     machine.get_missing_sessions(users.iter().map(Deref::deref)).await?
7ff8adafe9e4atagen2026-10-22 12:30 UTC910
/// {
7ff8adafe9e4atagen2026-10-22 12:30 UTC911
///     let response = send_request(&request).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC912
///     machine.mark_request_as_sent(&request_id, &response).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC913
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC914
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC915
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC916
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC917
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC918
/// With the ability to exchange messages directly with devices, we can now
7ff8adafe9e4atagen2026-10-22 12:30 UTC919
/// start sharing room keys over the 1-to-1 encrypted channel.
7ff8adafe9e4atagen2026-10-22 12:30 UTC920
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC921
/// ## Exchanging room keys
7ff8adafe9e4atagen2026-10-22 12:30 UTC922
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC923
/// To exchange a room key with our group, we will once again take a bulk
7ff8adafe9e4atagen2026-10-22 12:30 UTC924
/// approach. The [`OlmMachine::share_room_key()`] method is used to accomplish
7ff8adafe9e4atagen2026-10-22 12:30 UTC925
/// this step. This method will create a new room key, if necessary, and encrypt
7ff8adafe9e4atagen2026-10-22 12:30 UTC926
/// it for each device belonging to the users provided as an argument. It will
7ff8adafe9e4atagen2026-10-22 12:30 UTC927
/// then output an array of sendToDevice requests that we must send to the
7ff8adafe9e4atagen2026-10-22 12:30 UTC928
/// server, and mark the requests as sent.
7ff8adafe9e4atagen2026-10-22 12:30 UTC929
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC930
/// #### 🔒 Locking rule
7ff8adafe9e4atagen2026-10-22 12:30 UTC931
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC932
/// Like some of the previous methods, OlmMachine::share_room_key() needs to be
7ff8adafe9e4atagen2026-10-22 12:30 UTC933
/// protected by a lock to prevent the possibility of creating and sending
7ff8adafe9e4atagen2026-10-22 12:30 UTC934
/// multiple room keys simultaneously for the same group. The lock can be
7ff8adafe9e4atagen2026-10-22 12:30 UTC935
/// implemented on a per-room basis, which allows for parallel room key
7ff8adafe9e4atagen2026-10-22 12:30 UTC936
/// exchanges across different rooms.
7ff8adafe9e4atagen2026-10-22 12:30 UTC937
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC938
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC939
/// # use std::collections::{BTreeMap, HashSet};
7ff8adafe9e4atagen2026-10-22 12:30 UTC940
/// # use std::ops::Deref;
7ff8adafe9e4atagen2026-10-22 12:30 UTC941
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC942
/// # use ruma::UserId;
7ff8adafe9e4atagen2026-10-22 12:30 UTC943
/// # use ruma::api::client::keys::claim_keys::v3::{Response, Request};
7ff8adafe9e4atagen2026-10-22 12:30 UTC944
/// # use matrix_sdk_crypto::{OlmMachine, types::requests::ToDeviceRequest, EncryptionSettings};
7ff8adafe9e4atagen2026-10-22 12:30 UTC945
/// # async fn send_request(request: &ToDeviceRequest) -> Result<Response> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC946
/// #     let response = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC947
/// #     Ok(response)
7ff8adafe9e4atagen2026-10-22 12:30 UTC948
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC949
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC950
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC951
/// # let users: HashSet<&UserId> = HashSet::new();
7ff8adafe9e4atagen2026-10-22 12:30 UTC952
/// # let room_id = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC953
/// # let settings = EncryptionSettings::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC954
/// # let machine: OlmMachine = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC955
/// // Let's share a room key with our group.
7ff8adafe9e4atagen2026-10-22 12:30 UTC956
/// let requests = machine.share_room_key(
7ff8adafe9e4atagen2026-10-22 12:30 UTC957
///     room_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC958
///     users.iter().map(Deref::deref),
7ff8adafe9e4atagen2026-10-22 12:30 UTC959
///     EncryptionSettings::default(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC960
/// ).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC961
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC962
/// // Make sure each request is sent out
7ff8adafe9e4atagen2026-10-22 12:30 UTC963
/// for request in requests {
7ff8adafe9e4atagen2026-10-22 12:30 UTC964
///     let request_id = &request.txn_id;
7ff8adafe9e4atagen2026-10-22 12:30 UTC965
///     let response = send_request(&request).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC966
///     machine.mark_request_as_sent(&request_id, &response).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC967
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC968
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC969
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC970
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC971
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC972
/// In order to ensure that room keys are rotated and exchanged when needed, the
7ff8adafe9e4atagen2026-10-22 12:30 UTC973
/// [`OlmMachine::share_room_key()`] method should be called before sending
7ff8adafe9e4atagen2026-10-22 12:30 UTC974
/// each room message in an end-to-end encrypted room. If a room key has
7ff8adafe9e4atagen2026-10-22 12:30 UTC975
/// already been exchanged, the method becomes a no-op.
7ff8adafe9e4atagen2026-10-22 12:30 UTC976
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC977
/// ## Encrypting room events
7ff8adafe9e4atagen2026-10-22 12:30 UTC978
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC979
/// After the room key has been successfully shared, a plaintext can be
7ff8adafe9e4atagen2026-10-22 12:30 UTC980
/// encrypted.
7ff8adafe9e4atagen2026-10-22 12:30 UTC981
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC982
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC983
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC984
/// # use matrix_sdk_crypto::{DecryptionSettings, OlmMachine, TrustRequirement};
7ff8adafe9e4atagen2026-10-22 12:30 UTC985
/// # use ruma::events::{AnyMessageLikeEventContent, room::message::RoomMessageEventContent};
7ff8adafe9e4atagen2026-10-22 12:30 UTC986
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC987
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC988
/// # let room_id = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC989
/// # let event = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC990
/// # let machine: OlmMachine = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC991
/// # let settings = DecryptionSettings { sender_device_trust_requirement: TrustRequirement::Untrusted };
7ff8adafe9e4atagen2026-10-22 12:30 UTC992
/// let content = AnyMessageLikeEventContent::RoomMessage(RoomMessageEventContent::text_plain("It's a secret to everybody."));
7ff8adafe9e4atagen2026-10-22 12:30 UTC993
/// let encrypted_content = machine.encrypt_room_event(room_id, content).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC994
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC995
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC996
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC997
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC998
/// ## Appendix: Combining the session creation and room key exchange
7ff8adafe9e4atagen2026-10-22 12:30 UTC999
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1000
/// The steps from the previous three sections should combined into a single
7ff8adafe9e4atagen2026-10-22 12:30 UTC1001
/// method that is used to send messages.
7ff8adafe9e4atagen2026-10-22 12:30 UTC1002
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1003
/// ```no_run
7ff8adafe9e4atagen2026-10-22 12:30 UTC1004
/// # use std::collections::{BTreeMap, HashSet};
7ff8adafe9e4atagen2026-10-22 12:30 UTC1005
/// # use std::ops::Deref;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1006
/// # use anyhow::Result;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1007
/// # use serde_json::json;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1008
/// # use ruma::{UserId, RoomId, serde::Raw};
7ff8adafe9e4atagen2026-10-22 12:30 UTC1009
/// # use ruma::api::client::keys::claim_keys::v3::{Response, Request};
7ff8adafe9e4atagen2026-10-22 12:30 UTC1010
/// # use matrix_sdk_crypto::{EncryptionSettings, OlmMachine, types::requests::ToDeviceRequest};
7ff8adafe9e4atagen2026-10-22 12:30 UTC1011
/// # use tokio::sync::MutexGuard;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1012
/// # async fn send_request(request: &Request) -> Result<Response> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1013
/// #     let response = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1014
/// #     Ok(response)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1015
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1016
/// # async fn send_to_device_request(request: &ToDeviceRequest) -> Result<Response> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1017
/// #     let response = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1018
/// #     Ok(response)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1019
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1020
/// # async fn acquire_per_room_lock(room_id: &RoomId) -> MutexGuard<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1021
/// #     unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1022
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1023
/// # async fn get_joined_members(room_id: &RoomId) -> Vec<&UserId> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1024
/// #    unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1025
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1026
/// # fn is_room_encrypted(room_id: &RoomId) -> bool {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1027
/// #     true
7ff8adafe9e4atagen2026-10-22 12:30 UTC1028
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1029
/// # #[tokio::main]
7ff8adafe9e4atagen2026-10-22 12:30 UTC1030
/// # async fn main() -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1031
/// # let users: HashSet<&UserId> = HashSet::new();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1032
/// # let machine: OlmMachine = unimplemented!();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1033
/// struct Client {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1034
///     session_establishment_lock: tokio::sync::Mutex<()>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1035
///     olm_machine: OlmMachine,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1036
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1037
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1038
/// async fn establish_sessions(client: &Client, users: &[&UserId]) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1039
///     if let Some((request_id, request)) =
7ff8adafe9e4atagen2026-10-22 12:30 UTC1040
///         client.olm_machine.get_missing_sessions(users.iter().map(Deref::deref)).await?
7ff8adafe9e4atagen2026-10-22 12:30 UTC1041
///     {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1042
///         let response = send_request(&request).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1043
///         client.olm_machine.mark_request_as_sent(&request_id, &response).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1044
///     }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1045
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1046
///     Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1047
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1048
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1049
/// async fn share_room_key(machine: &OlmMachine, room_id: &RoomId, users: &[&UserId]) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1050
///     let _lock = acquire_per_room_lock(room_id).await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1051
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1052
///     let requests = machine.share_room_key(
7ff8adafe9e4atagen2026-10-22 12:30 UTC1053
///             room_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1054
///             users.iter().map(Deref::deref),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1055
///             EncryptionSettings::default(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC1056
///     ).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1057
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1058
///     // Make sure each request is sent out
7ff8adafe9e4atagen2026-10-22 12:30 UTC1059
///     for request in requests {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1060
///         let request_id = &request.txn_id;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1061
///         let response = send_to_device_request(&request).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1062
///         machine.mark_request_as_sent(&request_id, &response).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1063
///     }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1064
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1065
///     Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1066
/// }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1067
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1068
/// async fn send_message(client: &Client, room_id: &RoomId, message: &str) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1069
///     let mut content = json!({
7ff8adafe9e4atagen2026-10-22 12:30 UTC1070
///         "body": message,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1071
///             "msgtype": "m.text",
7ff8adafe9e4atagen2026-10-22 12:30 UTC1072
///     });
7ff8adafe9e4atagen2026-10-22 12:30 UTC1073
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1074
///     if is_room_encrypted(room_id) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1075
///         let content = Raw::new(&json!({
7ff8adafe9e4atagen2026-10-22 12:30 UTC1076
///             "body": message,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1077
///             "msgtype": "m.text",
7ff8adafe9e4atagen2026-10-22 12:30 UTC1078
///         }))?.cast_unchecked();
7ff8adafe9e4atagen2026-10-22 12:30 UTC1079
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1080
///         let users = get_joined_members(room_id).await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1081
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1082
///         establish_sessions(client, &users).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1083
///         share_room_key(&client.olm_machine, room_id, &users).await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1084
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1085
///         let encrypted = client
7ff8adafe9e4atagen2026-10-22 12:30 UTC1086
///             .olm_machine
7ff8adafe9e4atagen2026-10-22 12:30 UTC1087
///             .encrypt_room_event_raw(room_id, "m.room.message", &content)
7ff8adafe9e4atagen2026-10-22 12:30 UTC1088
///             .await?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1089
///     }
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
/// # Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC1094
/// # }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1095
/// ```
7ff8adafe9e4atagen2026-10-22 12:30 UTC1096
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1097
/// TODO
7ff8adafe9e4atagen2026-10-22 12:30 UTC1098
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1099
/// [Matrix]: https://matrix.org/
7ff8adafe9e4atagen2026-10-22 12:30 UTC1100
/// [Olm]: https://gitlab.matrix.org/matrix-org/olm/-/blob/master/docs/olm.md
7ff8adafe9e4atagen2026-10-22 12:30 UTC1101
/// [Diffie-Hellman]: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
7ff8adafe9e4atagen2026-10-22 12:30 UTC1102
/// [Megolm]: https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md
7ff8adafe9e4atagen2026-10-22 12:30 UTC1103
/// [end-to-end-encryption]: https://en.wikipedia.org/wiki/End-to-end_encryption
7ff8adafe9e4atagen2026-10-22 12:30 UTC1104
/// [homeserver]: https://spec.matrix.org/unstable/#architecture
7ff8adafe9e4atagen2026-10-22 12:30 UTC1105
/// [key-agreement protocol]: https://en.wikipedia.org/wiki/Key-agreement_protocol
7ff8adafe9e4atagen2026-10-22 12:30 UTC1106
/// [client-server specification]: https://spec.matrix.org/latest/client-server-api
7ff8adafe9e4atagen2026-10-22 12:30 UTC1107
/// [forward secrecy]: https://en.wikipedia.org/wiki/Forward_secrecy
7ff8adafe9e4atagen2026-10-22 12:30 UTC1108
/// [replay attacks]: https://en.wikipedia.org/wiki/Replay_attack
7ff8adafe9e4atagen2026-10-22 12:30 UTC1109
/// [Tracking the device list for a user]: https://spec.matrix.org/unstable/client-server-api/#tracking-the-device-list-for-a-user
7ff8adafe9e4atagen2026-10-22 12:30 UTC1110
/// [X3DH]: https://signal.org/docs/specifications/x3dh/
7ff8adafe9e4atagen2026-10-22 12:30 UTC1111
/// [to-device]: https://spec.matrix.org/unstable/client-server-api/#send-to-device-messaging
7ff8adafe9e4atagen2026-10-22 12:30 UTC1112
/// [sync]: https://spec.matrix.org/unstable/client-server-api/#get_matrixclientv3sync
7ff8adafe9e4atagen2026-10-22 12:30 UTC1113
/// [events]: https://spec.matrix.org/unstable/client-server-api/#events
7ff8adafe9e4atagen2026-10-22 12:30 UTC1114
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC1115
/// [1]: https://spec.matrix.org/unstable/client-server-api/#server-behaviour-4
7ff8adafe9e4atagen2026-10-22 12:30 UTC1116
pub mod tutorial {}
7ff8adafe9e4atagen2026-10-22 12:30 UTC1117
7ff8adafe9e4atagen2026-10-22 12:30 UTC1118
#[cfg(test)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC1119
mod test {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1120
    use insta::assert_json_snapshot;
7ff8adafe9e4atagen2026-10-22 12:30 UTC1121
7ff8adafe9e4atagen2026-10-22 12:30 UTC1122
    use crate::{DecryptionSettings, TrustRequirement};
7ff8adafe9e4atagen2026-10-22 12:30 UTC1123
7ff8adafe9e4atagen2026-10-22 12:30 UTC1124
    #[test]
7ff8adafe9e4atagen2026-10-22 12:30 UTC1125
    fn snapshot_trust_requirement() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1126
        assert_json_snapshot!(TrustRequirement::Untrusted);
7ff8adafe9e4atagen2026-10-22 12:30 UTC1127
        assert_json_snapshot!(TrustRequirement::CrossSignedOrLegacy);
7ff8adafe9e4atagen2026-10-22 12:30 UTC1128
        assert_json_snapshot!(TrustRequirement::CrossSigned);
7ff8adafe9e4atagen2026-10-22 12:30 UTC1129
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1130
7ff8adafe9e4atagen2026-10-22 12:30 UTC1131
    #[test]
7ff8adafe9e4atagen2026-10-22 12:30 UTC1132
    fn snapshot_decryption_settings() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1133
        assert_json_snapshot!(DecryptionSettings {
7ff8adafe9e4atagen2026-10-22 12:30 UTC1134
            sender_device_trust_requirement: TrustRequirement::Untrusted,
7ff8adafe9e4atagen2026-10-22 12:30 UTC1135
        });
7ff8adafe9e4atagen2026-10-22 12:30 UTC1136
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC1137
}