Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into reshare_after_unwedging
Browse files Browse the repository at this point in the history
  • Loading branch information
uhoreg committed Jun 27, 2024
2 parents 9239cde + 1c92633 commit 6c5f3dc
Show file tree
Hide file tree
Showing 35 changed files with 1,089 additions and 191 deletions.
42 changes: 36 additions & 6 deletions bindings/matrix-sdk-crypto-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ mod responses;
mod users;
mod verification;

use std::{collections::HashMap, sync::Arc, time::Duration};
use std::{
collections::{BTreeMap, HashMap},
sync::Arc,
time::Duration,
};

use anyhow::Context as _;
pub use backup_recovery_key::{
Expand All @@ -33,7 +37,9 @@ use matrix_sdk_common::deserialized_responses::ShieldState as RustShieldState;
use matrix_sdk_crypto::{
olm::{IdentityKeys, InboundGroupSession, Session},
store::{Changes, CryptoStore, PendingChanges, RoomSettings as RustRoomSettings},
types::{EventEncryptionAlgorithm as RustEventEncryptionAlgorithm, SigningKey},
types::{
DeviceKey, DeviceKeys, EventEncryptionAlgorithm as RustEventEncryptionAlgorithm, SigningKey,
},
CollectStrategy, EncryptionSettings as RustEncryptionSettings,
};
use matrix_sdk_sqlite::SqliteCryptoStore;
Expand All @@ -43,8 +49,8 @@ pub use responses::{
};
use ruma::{
events::room::history_visibility::HistoryVisibility as RustHistoryVisibility,
DeviceKeyAlgorithm, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedUserId, RoomId,
SecondsSinceUnixEpoch, UserId,
DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedUserId,
RoomId, SecondsSinceUnixEpoch, UserId,
};
use serde::{Deserialize, Serialize};
use tokio::runtime::Runtime;
Expand Down Expand Up @@ -332,6 +338,10 @@ async fn save_changes(
processed_steps += 1;
listener(processed_steps, total_steps);

// The Sessions were created with incorrect device keys, so clear the cache
// so that they'll get recreated with correct ones.
store.clear_caches().await;

Ok(())
}

Expand Down Expand Up @@ -419,6 +429,27 @@ fn collect_sessions(
) -> anyhow::Result<(Vec<Session>, Vec<InboundGroupSession>)> {
let mut sessions = Vec::new();

// Create a DeviceKeys struct with enough information to get a working
// Session, but we will won't actually use the Sessions (and we'll clear
// the session cache after migration) so we don't need to worry about
// signatures.
let device_keys = DeviceKeys::new(
user_id.clone(),
device_id.clone(),
Default::default(),
BTreeMap::from([
(
DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &device_id),
DeviceKey::Ed25519(identity_keys.ed25519),
),
(
DeviceKeyId::from_parts(DeviceKeyAlgorithm::Curve25519, &device_id),
DeviceKey::Curve25519(identity_keys.curve25519),
),
]),
Default::default(),
);

for session_pickle in session_pickles {
let pickle =
vodozemac::olm::Session::from_libolm_pickle(&session_pickle.pickle, pickle_key)?
Expand All @@ -439,8 +470,7 @@ fn collect_sessions(
last_use_time,
};

let session =
Session::from_pickle(user_id.clone(), device_id.clone(), identity_keys.clone(), pickle);
let session = Session::from_pickle(device_keys.clone(), pickle)?;

sessions.push(session);
processed_steps += 1;
Expand Down
17 changes: 15 additions & 2 deletions bindings/matrix-sdk-ffi/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::fmt::Display;

use matrix_sdk::{
encryption::CryptoStoreError, event_cache::EventCacheError, oidc::OidcError, HttpError,
IdParseError, NotificationSettingsError as SdkNotificationSettingsError, StoreError,
encryption::CryptoStoreError, event_cache::EventCacheError, oidc::OidcError,
send_queue::RoomSendQueueError, HttpError, IdParseError,
NotificationSettingsError as SdkNotificationSettingsError, StoreError,
};
use matrix_sdk_ui::{encryption_sync_service, notification_client, sync_service, timeline};
use uniffi::UnexpectedUniFFICallbackError;
Expand Down Expand Up @@ -91,6 +92,12 @@ impl From<timeline::Error> for ClientError {
}
}

impl From<timeline::UnsupportedEditItem> for ClientError {
fn from(e: timeline::UnsupportedEditItem) -> Self {
Self::new(e)
}
}

impl From<notification_client::Error> for ClientError {
fn from(e: notification_client::Error) -> Self {
Self::new(e)
Expand Down Expand Up @@ -121,6 +128,12 @@ impl From<EventCacheError> for ClientError {
}
}

impl From<RoomSendQueueError> for ClientError {
fn from(e: RoomSendQueueError) -> Self {
Self::new(e)
}
}

#[derive(Debug, thiserror::Error, uniffi::Error)]
#[uniffi(flat_error)]
pub enum RoomError {
Expand Down
44 changes: 30 additions & 14 deletions bindings/matrix-sdk-ffi/src/timeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,9 @@ impl Timeline {
pub async fn send(
self: Arc<Self>,
msg: Arc<RoomMessageEventContentWithoutRelation>,
) -> Result<Arc<AbortSendHandle>, ClientError> {
) -> Result<Arc<SendHandle>, ClientError> {
match self.inner.send((*msg).to_owned().with_relation(None).into()).await {
Ok(handle) => Ok(Arc::new(AbortSendHandle { inner: Mutex::new(Some(handle)) })),
Ok(handle) => Ok(Arc::new(SendHandle { inner: Mutex::new(Some(handle)) })),
Err(err) => {
error!("error when sending a message: {err}");
Err(anyhow::anyhow!(err).into())
Expand Down Expand Up @@ -470,22 +470,38 @@ impl Timeline {
Ok(())
}

/// Edits an event from the timeline.
///
/// Only works for events that exist as timeline items.
///
/// If it was a local event, this will *try* to edit it, if it was not
/// being sent already. If the event was a remote event, then it will be
/// redacted by sending an edit request to the server.
///
/// Returns whether the edit did happen. It can only return false for
/// local events that are being processed.
pub async fn edit(
&self,
item: Arc<EventTimelineItem>,
new_content: Arc<RoomMessageEventContentWithoutRelation>,
) -> Result<bool, ClientError> {
let edit_info = item.0.edit_info().map_err(ClientError::from)?;

self.inner.edit((*new_content).clone(), edit_info).await.map_err(ClientError::from)
}

/// Edit an event given its event id. Useful when we're not sure a remote
/// timeline event has been fetched by the timeline.
pub async fn edit_by_event_id(
&self,
event_id: String,
new_content: Arc<RoomMessageEventContentWithoutRelation>,
) -> Result<(), ClientError> {
let event_id = EventId::parse(event_id)?;
let edit_info = self
.inner
.edit_info_from_event_id(&event_id)
.await
.map_err(|err| anyhow::anyhow!(err))?;
let edit_info =
self.inner.edit_info_from_event_id(&event_id).await.map_err(ClientError::from)?;

self.inner
.edit((*new_content).clone(), edit_info)
.await
.map_err(|err| anyhow::anyhow!(err))?;
self.inner.edit((*new_content).clone(), edit_info).await.map_err(ClientError::from)?;
Ok(())
}

Expand Down Expand Up @@ -647,12 +663,12 @@ impl Timeline {
}

#[derive(uniffi::Object)]
pub struct AbortSendHandle {
inner: Mutex<Option<matrix_sdk::send_queue::AbortSendHandle>>,
pub struct SendHandle {
inner: Mutex<Option<matrix_sdk::send_queue::SendHandle>>,
}

#[uniffi::export(async_runtime = "tokio")]
impl AbortSendHandle {
impl SendHandle {
/// Try to abort the sending of the current event.
///
/// If this returns `true`, then the sending could be aborted, because the
Expand Down
27 changes: 10 additions & 17 deletions crates/matrix-sdk-base/src/read_receipts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,18 +762,16 @@ mod tests {
#[test]
fn test_count_unread_and_mentions() {
fn make_event(user_id: &UserId, push_actions: Vec<Action>) -> SyncTimelineEvent {
SyncTimelineEvent {
event: sync_timeline_event!({
SyncTimelineEvent::new_with_push_actions(
sync_timeline_event!({
"sender": user_id,
"type": "m.room.message",
"event_id": "$ida",
"origin_server_ts": 12344446,
"content": { "body":"A", "msgtype": "m.text" },
}),
encryption_info: None,
push_actions,
unsigned_encryption_info: None,
}
)
}

let user_id = user_id!("@alice:example.org");
Expand Down Expand Up @@ -848,18 +846,13 @@ mod tests {
// When provided with one event, that's not the receipt event, we don't count
// it.
fn make_event(event_id: &EventId) -> SyncTimelineEvent {
SyncTimelineEvent {
event: sync_timeline_event!({
"sender": "@bob:example.org",
"type": "m.room.message",
"event_id": event_id,
"origin_server_ts": 12344446,
"content": { "body":"A", "msgtype": "m.text" },
}),
encryption_info: None,
push_actions: Vec::new(),
unsigned_encryption_info: None,
}
SyncTimelineEvent::new(sync_timeline_event!({
"sender": "@bob:example.org",
"type": "m.room.message",
"event_id": event_id,
"origin_server_ts": 12344446,
"content": { "body":"A", "msgtype": "m.text" },
}))
}

let mut receipts = RoomReadReceipts {
Expand Down
39 changes: 35 additions & 4 deletions crates/matrix-sdk-base/src/store/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ impl StateStoreIntegrationTests for DynStateStore {
// Saving one thing should work.
let txn0 = TransactionId::new();
let event0 =
SerializableEventContent::new(RoomMessageEventContent::text_plain("msg0").into())
SerializableEventContent::new(&RoomMessageEventContent::text_plain("msg0").into())
.unwrap();
self.save_send_queue_event(room_id, txn0.clone(), event0).await.unwrap();

Expand All @@ -1334,7 +1334,7 @@ impl StateStoreIntegrationTests for DynStateStore {
for i in 1..=3 {
let txn = TransactionId::new();
let event = SerializableEventContent::new(
RoomMessageEventContent::text_plain(format!("msg{i}")).into(),
&RoomMessageEventContent::text_plain(format!("msg{i}")).into(),
)
.unwrap();

Expand Down Expand Up @@ -1374,6 +1374,37 @@ impl StateStoreIntegrationTests for DynStateStore {
}
}

// Updating an event will work, and reset its wedged state to false.
let event0 = SerializableEventContent::new(
&RoomMessageEventContent::text_plain("wow that's a cool test").into(),
)
.unwrap();
self.update_send_queue_event(room_id, txn2, event0).await.unwrap();

// And it is reflected.
let pending = self.load_send_queue_events(room_id).await.unwrap();

assert_eq!(pending.len(), 4);
{
assert_eq!(pending[2].transaction_id, *txn2);

let deserialized = pending[2].event.deserialize().unwrap();
assert_let!(AnyMessageLikeEventContent::RoomMessage(content) = deserialized);
assert_eq!(content.body(), "wow that's a cool test");

assert!(!pending[2].is_wedged);

for i in 0..4 {
if i != 2 {
let deserialized = pending[i].event.deserialize().unwrap();
assert_let!(AnyMessageLikeEventContent::RoomMessage(content) = deserialized);
assert_eq!(content.body(), format!("msg{i}"));

assert!(!pending[i].is_wedged);
}
}
}

// Removing an event works.
self.remove_send_queue_event(room_id, &txn0).await.unwrap();

Expand All @@ -1394,7 +1425,7 @@ impl StateStoreIntegrationTests for DynStateStore {
{
let txn = TransactionId::new();
let event =
SerializableEventContent::new(RoomMessageEventContent::text_plain("room2").into())
SerializableEventContent::new(&RoomMessageEventContent::text_plain("room2").into())
.unwrap();
self.save_send_queue_event(room_id2, txn.clone(), event).await.unwrap();
}
Expand All @@ -1404,7 +1435,7 @@ impl StateStoreIntegrationTests for DynStateStore {
let room_id3 = room_id!("!test_send_queue_three:localhost");
let txn = TransactionId::new();
let event =
SerializableEventContent::new(RoomMessageEventContent::text_plain("room3").into())
SerializableEventContent::new(&RoomMessageEventContent::text_plain("room3").into())
.unwrap();
self.save_send_queue_event(room_id3, txn.clone(), event).await.unwrap();

Expand Down
21 changes: 21 additions & 0 deletions crates/matrix-sdk-base/src/store/memory_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,27 @@ impl StateStore for MemoryStore {
Ok(())
}

async fn update_send_queue_event(
&self,
room_id: &RoomId,
transaction_id: &TransactionId,
content: SerializableEventContent,
) -> Result<(), Self::Error> {
if let Some(entry) = self
.send_queue_events
.write()
.unwrap()
.entry(room_id.to_owned())
.or_default()
.iter_mut()
.find(|item| item.transaction_id == transaction_id)
{
entry.event = content;
entry.is_wedged = false;
}
Ok(())
}

async fn remove_send_queue_event(
&self,
room_id: &RoomId,
Expand Down
29 changes: 27 additions & 2 deletions crates/matrix-sdk-base/src/store/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,22 @@ pub trait StateStore: AsyncTraitDeps {
content: SerializableEventContent,
) -> Result<(), Self::Error>;

/// Updates a send queue event with the given content, and resets its wedged
/// status to false.
///
/// # Arguments
///
/// * `room_id` - The `RoomId` of the send queue's room.
/// * `transaction_id` - The unique key identifying the event to be sent
/// (and its transaction).
/// * `content` - Serializable event content to replace the original one.
async fn update_send_queue_event(
&self,
room_id: &RoomId,
transaction_id: &TransactionId,
content: SerializableEventContent,
) -> Result<(), Self::Error>;

/// Remove an event previously inserted with [`Self::save_send_queue_event`]
/// from the database, based on its transaction id.
async fn remove_send_queue_event(
Expand Down Expand Up @@ -666,6 +682,15 @@ impl<T: StateStore> StateStore for EraseStateStoreError<T> {
self.0.save_send_queue_event(room_id, transaction_id, content).await.map_err(Into::into)
}

async fn update_send_queue_event(
&self,
room_id: &RoomId,
transaction_id: &TransactionId,
content: SerializableEventContent,
) -> Result<(), Self::Error> {
self.0.update_send_queue_event(room_id, transaction_id, content).await.map_err(Into::into)
}

async fn remove_send_queue_event(
&self,
room_id: &RoomId,
Expand Down Expand Up @@ -1042,8 +1067,8 @@ impl SerializableEventContent {

/// Create a [`SerializableEventContent`] from an
/// [`AnyMessageLikeEventContent`].
pub fn new(event: AnyMessageLikeEventContent) -> Result<Self, serde_json::Error> {
Ok(Self::from_raw(Raw::new(&event)?, event.event_type().to_string()))
pub fn new(event: &AnyMessageLikeEventContent) -> Result<Self, serde_json::Error> {
Ok(Self::from_raw(Raw::new(event)?, event.event_type().to_string()))
}

/// Convert a [`SerializableEventContent`] back into a
Expand Down
Loading

0 comments on commit 6c5f3dc

Please sign in to comment.