Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/matrix-sdk-crypto/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ All notable changes to this project will be documented in this file.
been eliminated entirely.
([#5963](https://github.com/matrix-org/matrix-rust-sdk/pull/5963))

- [**breaking**] `CryptoStore::get_secrets_from_inbox` now returns a `Vec` of
the secrets as strings, rather than a `Vec` of `GossippedSecret` structs.
([#6164](https://github.com/matrix-org/matrix-rust-sdk/pull/6164))

## [0.16.0] - 2025-12-04

### Features
Expand Down
2 changes: 1 addition & 1 deletion crates/matrix-sdk-crypto/src/gossiping/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ impl GossipMachine {
// So we put the secret into our inbox. Later users can inspect the contents of
// the inbox and decide if they want to activate the backup.
info!("Received a backup decryption key, storing it into the secret inbox.");
changes.secrets.push(secret);
changes.secrets.push(secret.into());
}

Ok(())
Expand Down
11 changes: 7 additions & 4 deletions crates/matrix-sdk-crypto/src/store/crypto_store_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ use super::{
types::RoomKeyBundleInfo,
};
use crate::{
CryptoStoreError, GossippedSecret, OwnUserIdentityData, Session, UserIdentityData,
CryptoStoreError, OwnUserIdentityData, Session, UserIdentityData,
olm::InboundGroupSession,
store,
store::{Changes, DynCryptoStore, IntoCryptoStore, RoomKeyInfo, RoomKeyWithheldInfo},
store::{
Changes, DynCryptoStore, IntoCryptoStore, RoomKeyInfo, RoomKeyWithheldInfo,
types::SecretsInboxItem,
},
};

/// A wrapper for crypto store implementations that adds update notifiers.
Expand All @@ -43,7 +46,7 @@ pub(crate) struct CryptoStoreWrapper {

/// The sender side of a broadcast channel which sends out secrets we
/// received as a `m.secret.send` event.
secrets_broadcaster: broadcast::Sender<GossippedSecret>,
secrets_broadcaster: broadcast::Sender<SecretsInboxItem>,

/// The sender side of a broadcast channel which sends out devices and user
/// identities which got updated or newly created.
Expand Down Expand Up @@ -340,7 +343,7 @@ impl CryptoStoreWrapper {

/// Receive notifications of gossipped secrets being received and stored in
/// the secret inbox as a [`Stream`].
pub fn secrets_stream(&self) -> impl Stream<Item = GossippedSecret> + use<> {
pub fn secrets_stream(&self) -> impl Stream<Item = SecretsInboxItem> + use<> {
let stream = BroadcastStream::new(self.secrets_broadcaster.subscribe());
Self::filter_errors_out_of_stream(stream, "secrets_stream")
}
Expand Down
9 changes: 6 additions & 3 deletions crates/matrix-sdk-crypto/src/store/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ macro_rules! cryptostore_integration_tests {
() => {
mod cryptostore_integration_tests {
use std::collections::{BTreeMap, HashMap, HashSet};
use std::ops::Deref;
use std::time::Duration;

use assert_matches::assert_matches;
Expand Down Expand Up @@ -1104,23 +1105,25 @@ macro_rules! cryptostore_integration_tests {
);

let mut changes = Changes::default();
changes.secrets.push(value);
changes.secrets.push(value.into());
store.save_changes(changes).await.unwrap();

let restored = store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
let first_secret = restored.first().expect("We should have restored a secret now");
assert_eq!(first_secret.event.content.secret, secret);
assert_eq!(first_secret.deref(), secret);
assert_eq!(restored.len(), 1, "We should only have one secret stored for now");

let secret2 = "It is another secret to everybody";
event.content.request_id = TransactionId::new();
event.content.secret = secret2.to_string();
let another_secret = GossippedSecret {
secret_name: SecretName::RecoveryKey,
gossip_request,
event,
};

let mut changes = Changes::default();
changes.secrets.push(another_secret);
changes.secrets.push(another_secret.into());
store.save_changes(changes).await.unwrap();

let restored = store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
Expand Down
16 changes: 9 additions & 7 deletions crates/matrix-sdk-crypto/src/store/memorystore.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
// Copyright 2020, 2026 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,6 +33,7 @@ use ruma::{
use tokio::sync::{Mutex, RwLock};
use tracing::warn;
use vodozemac::Curve25519PublicKey;
use zeroize::Zeroizing;

use super::{
Account, CryptoStore, InboundGroupSession, Session,
Expand All @@ -43,7 +44,7 @@ use super::{
},
};
use crate::{
gossiping::{GossipRequest, GossippedSecret, SecretInfo},
gossiping::{GossipRequest, SecretInfo},
identities::{DeviceData, UserIdentityData},
olm::{
OutboundGroupSession, PickledAccount, PickledInboundGroupSession, PickledSession,
Expand Down Expand Up @@ -104,7 +105,7 @@ pub struct MemoryStore {
direct_withheld_info: StdRwLock<HashMap<OwnedRoomId, HashMap<String, RoomKeyWithheldEntry>>>,
custom_values: StdRwLock<HashMap<String, Vec<u8>>>,
leases: StdRwLock<HashMap<String, Lease>>,
secret_inbox: StdRwLock<HashMap<String, Vec<GossippedSecret>>>,
secret_inbox: StdRwLock<HashMap<String, Vec<Zeroizing<String>>>>,
backup_keys: RwLock<BackupKeys>,
dehydrated_device_pickle_key: RwLock<Option<DehydratedDeviceKey>>,
next_batch_token: RwLock<Option<String>>,
Expand Down Expand Up @@ -306,7 +307,7 @@ impl CryptoStore for MemoryStore {
{
let mut secret_inbox = self.secret_inbox.write();
for secret in changes.secrets {
secret_inbox.entry(secret.secret_name.to_string()).or_default().push(secret);
secret_inbox.entry(secret.secret_name.to_string()).or_default().push(secret.secret);
}
}

Expand Down Expand Up @@ -749,7 +750,7 @@ impl CryptoStore for MemoryStore {
async fn get_secrets_from_inbox(
&self,
secret_name: &SecretName,
) -> Result<Vec<GossippedSecret>> {
) -> Result<Vec<Zeroizing<String>>> {
Ok(self.secret_inbox.write().entry(secret_name.to_string()).or_default().to_owned())
}

Expand Down Expand Up @@ -1322,10 +1323,11 @@ mod integration_tests {
DeviceId, OwnedDeviceId, RoomId, TransactionId, UserId, events::secret::request::SecretName,
};
use vodozemac::Curve25519PublicKey;
use zeroize::Zeroizing;

use super::MemoryStore;
use crate::{
Account, DeviceData, GossipRequest, GossippedSecret, SecretInfo, Session, UserIdentityData,
Account, DeviceData, GossipRequest, SecretInfo, Session, UserIdentityData,
cryptostore_integration_tests, cryptostore_integration_tests_time,
olm::{
InboundGroupSession, OlmMessageHash, OutboundGroupSession, PrivateCrossSigningIdentity,
Expand Down Expand Up @@ -1593,7 +1595,7 @@ mod integration_tests {
async fn get_secrets_from_inbox(
&self,
secret_name: &SecretName,
) -> Result<Vec<GossippedSecret>, Self::Error> {
) -> Result<Vec<Zeroizing<String>>, Self::Error> {
self.0.get_secrets_from_inbox(secret_name).await
}

Expand Down
6 changes: 3 additions & 3 deletions crates/matrix-sdk-crypto/src/store/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
// Copyright 2020, 2026 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -76,7 +76,7 @@ use crate::{
Account, ExportedRoomKey, ForwarderData, InboundGroupSession, PrivateCrossSigningIdentity,
SenderData, Session, StaticAccountData,
},
store::types::RoomKeyWithheldEntry,
store::types::{RoomKeyWithheldEntry, SecretsInboxItem},
types::{
BackupSecrets, CrossSigningSecrets, MegolmBackupV1Curve25519AesSha2Secrets, RoomKeyExport,
SecretsBundle,
Expand Down Expand Up @@ -1381,7 +1381,7 @@ impl Store {
/// }
/// # });
/// ```
pub fn secrets_stream(&self) -> impl Stream<Item = GossippedSecret> + use<> {
pub fn secrets_stream(&self) -> impl Stream<Item = SecretsInboxItem> + use<> {
self.inner.store.secrets_stream()
}

Expand Down
9 changes: 5 additions & 4 deletions crates/matrix-sdk-crypto/src/store/traits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 The Matrix.org Foundation C.I.C.
// Copyright 2023, 2026 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -20,6 +20,7 @@ use ruma::{
DeviceId, OwnedDeviceId, RoomId, TransactionId, UserId, events::secret::request::SecretName,
};
use vodozemac::Curve25519PublicKey;
use zeroize::Zeroizing;

use super::{
CryptoStoreError, Result,
Expand All @@ -31,7 +32,7 @@ use super::{
#[cfg(doc)]
use crate::olm::SenderData;
use crate::{
Account, DeviceData, GossipRequest, GossippedSecret, SecretInfo, UserIdentityData,
Account, DeviceData, GossipRequest, SecretInfo, UserIdentityData,
olm::{
InboundGroupSession, OlmMessageHash, OutboundGroupSession, PrivateCrossSigningIdentity,
SenderDataType, Session,
Expand Down Expand Up @@ -331,7 +332,7 @@ pub trait CryptoStore: AsyncTraitDeps {
async fn get_secrets_from_inbox(
&self,
secret_name: &SecretName,
) -> Result<Vec<GossippedSecret>, Self::Error>;
) -> Result<Vec<Zeroizing<String>>, Self::Error>;

/// Delete all the secrets with the given [`SecretName`] we have currently
/// stored.
Expand Down Expand Up @@ -609,7 +610,7 @@ impl<T: CryptoStore> CryptoStore for EraseCryptoStoreError<T> {
async fn get_secrets_from_inbox(
&self,
secret_name: &SecretName,
) -> Result<Vec<GossippedSecret>> {
) -> Result<Vec<Zeroizing<String>>> {
self.0.get_secrets_from_inbox(secret_name).await.map_err(Into::into)
}

Expand Down
55 changes: 50 additions & 5 deletions crates/matrix-sdk-crypto/src/store/types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
// Copyright 2020, 2026 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -19,13 +19,17 @@

use std::{
collections::{BTreeMap, HashMap, HashSet},
ops::Deref,
time::Duration,
};

use ruma::{MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedRoomId, OwnedUserId};
use serde::{Deserialize, Serialize};
use ruma::{
MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedRoomId, OwnedUserId,
events::secret::request::SecretName,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use vodozemac::{Curve25519PublicKey, base64_encode};
use zeroize::{Zeroize, ZeroizeOnDrop};
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};

use super::{DehydrationError, GossipRequest};
use crate::{
Expand Down Expand Up @@ -80,7 +84,7 @@ pub struct Changes {
/// Stores when a `m.room_key.withheld` is received
pub withheld_session_info: BTreeMap<OwnedRoomId, BTreeMap<String, RoomKeyWithheldEntry>>,
pub room_settings: HashMap<OwnedRoomId, RoomSettings>,
pub secrets: Vec<GossippedSecret>,
pub secrets: Vec<SecretsInboxItem>,
pub next_batch_token: Option<String>,

/// Historical room key history bundles that we have received and should
Expand All @@ -96,6 +100,47 @@ pub struct Changes {
pub rooms_pending_key_bundle: HashMap<OwnedRoomId, Option<RoomPendingKeyBundleDetails>>,
}

/// A secret that was received via an `m.secret.send`.
#[derive(Clone, Serialize, Deserialize)]
pub struct SecretsInboxItem {
/// The name of the secret.
pub secret_name: SecretName,
/// The contents of the secret.
#[serde(
serialize_with = "zeroizing_string_serializer",
deserialize_with = "zeroizing_string_deserializer"
)]
pub secret: Zeroizing<String>,
}

fn zeroizing_string_serializer<S>(x: &Zeroizing<String>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_some(x.deref())
}

fn zeroizing_string_deserializer<'de, D>(deserializer: D) -> Result<Zeroizing<String>, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
Ok(value.into())
}

#[cfg(not(tarpaulin_include))]
impl std::fmt::Debug for SecretsInboxItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("SecretsInboxItem").field(&self.secret_name).finish()
}
}

impl From<GossippedSecret> for SecretsInboxItem {
fn from(secret: GossippedSecret) -> Self {
Self { secret_name: secret.secret_name, secret: secret.event.content.secret.clone().into() }
}
}

/// Information about an [MSC4268] room key bundle.
///
/// [MSC4268]: https://github.com/matrix-org/matrix-spec-proposals/pull/4268
Expand Down
Loading