This commit is contained in:
Richard van der Hoff
2025-04-29 11:28:22 +01:00
parent f042084bd2
commit e8cf202c7f
4 changed files with 153 additions and 4 deletions

View File

@@ -95,6 +95,7 @@ use crate::{
AnyIncomingResponse, KeysQueryRequest, OutgoingRequest, ToDeviceRequest,
UploadSigningKeysRequest,
},
room_history::RoomKeyBundle,
EventEncryptionAlgorithm, ProcessedToDeviceEvent, Signatures,
},
utilities::timestamp_to_iso8601,
@@ -968,6 +969,43 @@ impl OlmMachine {
Ok(())
}
/// Import the contents of a downloaded and decrypted [MSC4268] key bundle.
///
/// # Arguments
///
/// * `bundle` - The decrypted and deserialized bundle itself.
/// * `room_id` - The room that we expect this bundle to correspond to.
/// * `sender_user` - The user that sent us the to-device message pointing
/// to this data.
/// * `sender_data` - Information on the sending device at the time we
/// received that message.
///
/// [MSC4268]: https://github.com/matrix-org/matrix-spec-proposals/pull/4268
#[instrument(skip(bundle))]
pub async fn receive_room_key_bundle(
&self,
bundle: &RoomKeyBundle,
room_id: &RoomId,
sender_user: &UserId,
sender_data: &SenderData,
) -> OlmResult<()> {
for key in bundle.room_keys.iter() {
if key.room_id != room_id {
warn!("Ignoring key for incorrect room {} in bundle", key.room_id);
continue;
}
let _session = match InboundGroupSession::try_from(key) {
Ok(session) => session,
Err(e) => {
warn!("Ignoring key in bundle with import error: {}", e);
continue;
}
};
}
Ok(())
}
fn add_withheld_info(&self, changes: &mut Changes, event: &RoomKeyWithheldEvent) {
debug!(?event.content, "Processing `m.room_key.withheld` event");

View File

@@ -55,10 +55,10 @@ use crate::{
room::encrypted::{EncryptedEvent, RoomEventEncryptionScheme},
room_key,
},
room_history::HistoricRoomKey,
serialize_curve_key, EventEncryptionAlgorithm, SigningKeys,
},
};
// TODO: add creation times to the inbound group sessions so we can export
// sessions that were created between some time period, this should only be set
// for non-imported sessions.
@@ -672,6 +672,42 @@ fn default_algorithm() -> EventEncryptionAlgorithm {
EventEncryptionAlgorithm::MegolmV1AesSha2
}
impl TryFrom<&HistoricRoomKey> for InboundGroupSession {
type Error = SessionCreationError;
fn try_from(key: &HistoricRoomKey) -> Result<Self, Self::Error> {
let HistoricRoomKey {
algorithm,
room_id,
sender_key,
session_id,
session_key,
sender_claimed_keys,
} = key;
let config = OutboundGroupSession::session_config(algorithm)?;
let session = InnerSession::import(session_key, config);
let first_known_index = session.first_known_index();
Ok(InboundGroupSession {
inner: Mutex::new(session).into(),
session_id: session_id.to_owned().into(),
creator_info: SessionCreatorInfo {
curve25519_key: *sender_key,
signing_keys: sender_claimed_keys.to_owned().into(),
},
sender_data: SenderData::default(),
history_visibility: None.into(),
first_known_index,
room_id: room_id.to_owned(),
imported: true,
algorithm: algorithm.to_owned().into(),
backed_up: AtomicBool::from(false).into(),
shared_history: true,
})
}
}
impl TryFrom<&ExportedRoomKey> for InboundGroupSession {
type Error = SessionCreationError;

View File

@@ -267,12 +267,24 @@ impl Room {
false
});
#[cfg(all(feature = "experimental-share-history-on-invite", feature = "e2e-encryption"))]
let inviter = if prev_room_state == RoomState::Invited {
self.invite_details().await?.inviter
} else {
None
};
self.client.join_room_by_id(self.room_id()).await?;
if mark_as_direct {
self.set_is_direct(true).await?;
}
#[cfg(all(feature = "experimental-share-history-on-invite", feature = "e2e-encryption"))]
if let Some(inviter) = inviter {
shared_room_history::accept_key_bundle(&self, inviter.user_id()).await?;
}
Ok(())
}

View File

@@ -12,12 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::iter;
use std::{iter, ops::Deref};
use ruma::OwnedUserId;
use matrix_sdk_base::media::{MediaFormat, MediaRequestParameters};
use ruma::{api::client::authenticated_media, events::room::MediaSource, OwnedUserId, UserId};
use tracing::{info, instrument, warn};
use crate::{crypto::types::events::room_key_bundle::RoomKeyBundleContent, Error, Result, Room};
use crate::{
crypto::types::{events::room_key_bundle::RoomKeyBundleContent, room_history::RoomKeyBundle},
Error, Result, Room,
};
/// Share any shareable E2EE history in the given room with the given recipient,
/// as per [MSC4268].
@@ -85,3 +89,62 @@ pub async fn share_room_history(room: &Room, user_id: OwnedUserId) -> Result<()>
}
Ok(())
}
/// Having accepted an invite for the given room from the given user, download a
/// key bundle and import the room keys, as per [MSC4268].
///
/// [MSC4268]: https://github.com/matrix-org/matrix-spec-proposals/pull/4268
#[instrument(skip(room), fields(room_id = ?room.room_id()))]
pub async fn accept_key_bundle(room: &Room, user_id: &UserId) -> Result<()> {
// TODO: retry this if it gets interrupted or it fails.
// TODO: do this in the background.
let client = &room.client;
let olm_machine = client.olm_machine().await;
let Some(olm_machine) = olm_machine.deref() else {
warn!("Not fetching room key bundle as the Olm machine is not available");
return Ok(());
};
let Some(bundle) =
olm_machine.store().get_received_room_key_bundle_data(room.room_id(), user_id).await?
else {
// No bundle received (yet).
// TODO: deal with the bundle arriving later (https://github.com/matrix-org/matrix-rust-sdk/issues/4926)
return Ok(());
};
// TODO
// olm_machine.store().clear_received_room_key_bundle_data(room.room_id(),
// user_id).await?;
let bundle_content = client
.media()
.get_media_content(
&MediaRequestParameters {
source: MediaSource::Encrypted(Box::new(bundle.bundle_data.file)),
format: MediaFormat::File,
},
false,
)
.await?;
let bundle_content: RoomKeyBundle = match serde_json::from_slice(&bundle_content) {
Ok(bundle_content) => bundle_content,
Err(err) => {
warn!("Failed to deserialize room key bundle: {}", err);
return Ok(());
}
};
olm_machine
.receive_room_key_bundle(
&bundle_content,
room.room_id(),
&bundle.sender_user,
&bundle.sender_data,
)
.await?;
Ok(())
}