[fractal] room: Retry to decrypt room messages
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal] room: Retry to decrypt room messages
- Date: Wed, 18 May 2022 09:37:11 +0000 (UTC)
commit 002be9075ee78665ad98095f9b3fa092cd4e591d
Author: Julian Sparber <julian sparber net>
Date: Fri May 13 12:24:08 2022 +0200
room: Retry to decrypt room messages
.../content/room_history/message_row/mod.rs | 2 +-
src/session/mod.rs | 33 ++++++++-
src/session/room/event.rs | 46 +++++++++++-
src/session/room/mod.rs | 85 +++++++++++++++++++++-
4 files changed, 161 insertions(+), 5 deletions(-)
---
diff --git a/src/session/content/room_history/message_row/mod.rs
b/src/session/content/room_history/message_row/mod.rs
index 74f72bb35..864a97e7c 100644
--- a/src/session/content/room_history/message_row/mod.rs
+++ b/src/session/content/room_history/message_row/mod.rs
@@ -412,7 +412,7 @@ fn build_content(parent: &adw::Bin, event: &Event, compact: bool) {
parent.set_child(Some(&child));
child
};
- child.text(gettext("Fractal couldn’t decrypt this message."));
+ child.text(gettext("Fractal couldn’t decrypt this message, but will retry once the keys are
available."));
}
Some(AnyMessageLikeEventContent::RoomRedaction(_)) => {
let child = if let Some(Ok(child)) = parent.child().map(|w| w.downcast::<MessageText>())
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 8de119523..0f748fe69 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -26,6 +26,7 @@ use log::{debug, error, warn};
use matrix_sdk::{
config::{RequestConfig, SyncSettings},
deserialized_responses::SyncResponse,
+ room::Room as MatrixRoom,
ruma::{
api::{
client::{
@@ -36,7 +37,10 @@ use matrix_sdk::{
error::{FromHttpResponseError, ServerError},
},
assign,
- events::{direct::DirectEventContent, GlobalAccountDataEvent},
+ events::{
+ direct::DirectEventContent, room::encryption::SyncRoomEncryptionEvent,
+ GlobalAccountDataEvent,
+ },
RoomId,
},
store::{make_store_config, OpenStoreError},
@@ -476,6 +480,7 @@ impl Session {
self.room_list().load();
self.setup_direct_room_handler();
+ self.setup_room_encrypted_changes();
self.sync();
@@ -881,6 +886,32 @@ impl Session {
})
);
}
+
+ fn setup_room_encrypted_changes(&self) {
+ let session_weak = glib::SendWeakRef::from(self.downgrade());
+ let client = self.client();
+ spawn_tokio!(async move {
+ client
+ .register_event_handler(
+ move |_: SyncRoomEncryptionEvent, matrix_room: MatrixRoom| {
+ let session_weak = session_weak.clone();
+ async move {
+ let ctx = glib::MainContext::default();
+ ctx.spawn(async move {
+ if let Some(session) = session_weak.upgrade() {
+ if let Some(room) =
+ session.room_list().get(matrix_room.room_id())
+ {
+ room.set_is_encrypted(true);
+ }
+ }
+ });
+ }
+ },
+ )
+ .await;
+ });
+ }
}
impl Default for Session {
diff --git a/src/session/room/event.rs b/src/session/room/event.rs
index 8f46970b5..79919570f 100644
--- a/src/session/room/event.rs
+++ b/src/session/room/event.rs
@@ -11,11 +11,13 @@ use matrix_sdk::{
ruma::{
events::{
room::{
+ encrypted::RoomEncryptedEventContent,
message::{MessageType, Relation},
redaction::SyncRoomRedactionEvent,
},
AnyMessageLikeEventContent, AnySyncMessageLikeEvent, AnySyncRoomEvent,
- AnySyncStateEvent, MessageLikeUnsigned, SyncMessageLikeEvent, SyncStateEvent,
+ AnySyncStateEvent, MessageLikeUnsigned, OriginalSyncMessageLikeEvent,
+ SyncMessageLikeEvent, SyncStateEvent,
},
MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId,
},
@@ -27,7 +29,7 @@ use super::{
Member, ReactionList, Room,
};
use crate::{
- spawn_tokio,
+ spawn, spawn_tokio,
utils::{filename_for_mime, media_type_uid},
};
@@ -54,6 +56,7 @@ mod imp {
pub replacing_events: RefCell<Vec<super::Event>>,
pub reactions: ReactionList,
pub source_changed_handler: RefCell<Option<SignalHandlerId>>,
+ pub keys_handle: RefCell<Option<SignalHandlerId>>,
pub room: OnceCell<WeakRef<Room>>,
}
@@ -221,6 +224,16 @@ impl Event {
let priv_ = self.imp();
if let Ok(deserialized) = event.event.deserialize() {
+ if let AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted(
+ SyncMessageLikeEvent::Original(ref encrypted),
+ )) = deserialized
+ {
+ let encrypted = encrypted.to_owned();
+ spawn!(clone!(@weak self as obj => async move {
+ obj.try_to_decrypt(encrypted).await;
+ }));
+ }
+
priv_.event.replace(Some(deserialized));
} else {
warn!("Failed to deserialize event: {:?}", event);
@@ -230,6 +243,35 @@ impl Event {
self.notify("event");
self.notify("activatable");
+ self.notify("source");
+ }
+
+ async fn try_to_decrypt(&self, event: OriginalSyncMessageLikeEvent<RoomEncryptedEventContent>) {
+ let priv_ = self.imp();
+ let room = self.room().matrix_room();
+ let handle = spawn_tokio!(async move { room.decrypt_event(&event).await });
+
+ match handle.await.unwrap() {
+ Ok(decrypted) => {
+ if let Some(keys_handle) = priv_.keys_handle.take() {
+ self.room().disconnect(keys_handle);
+ }
+ self.set_matrix_pure_event(decrypted.into());
+ }
+ Err(error) => {
+ warn!("Failed to decrypt event: {}", error);
+ if priv_.keys_handle.borrow().is_none() {
+ let handle = self.room().connect_new_encryption_keys(
+ clone!(@weak self as obj => move |_| {
+ // Try to decrypt the event again
+ obj.set_matrix_pure_event(obj.matrix_pure_event());
+ }),
+ );
+
+ priv_.keys_handle.replace(Some(handle));
+ }
+ }
+ }
}
pub fn matrix_sender(&self) -> OwnedUserId {
diff --git a/src/session/room/mod.rs b/src/session/room/mod.rs
index 9db979fe7..b61758957 100644
--- a/src/session/room/mod.rs
+++ b/src/session/room/mod.rs
@@ -31,11 +31,12 @@ use matrix_sdk::{
redaction::{OriginalSyncRoomRedactionEvent, RoomRedactionEventContent},
topic::RoomTopicEventContent,
},
+ room_key::ToDeviceRoomKeyEventContent,
tag::{TagInfo, TagName},
AnyRoomAccountDataEvent, AnyStrippedStateEvent, AnySyncMessageLikeEvent,
AnySyncRoomEvent, AnySyncStateEvent, EventContent, MessageLikeEventType,
MessageLikeUnsigned, OriginalSyncMessageLikeEvent, StateEventType,
- SyncMessageLikeEvent, SyncStateEvent,
+ SyncMessageLikeEvent, SyncStateEvent, ToDeviceEvent,
},
receipt::ReceiptType,
serde::Raw,
@@ -110,6 +111,8 @@ mod imp {
pub successor: OnceCell<OwnedRoomId>,
/// The most recent verification request event.
pub verification: RefCell<Option<IdentityVerification>>,
+ /// Whether this room is encrypted
+ pub is_encrypted: Cell<bool>,
}
#[glib::object_subclass]
@@ -241,6 +244,13 @@ mod imp {
IdentityVerification::static_type(),
glib::ParamFlags::READWRITE,
),
+ glib::ParamSpecBoolean::new(
+ "encrypted",
+ "Encrypted",
+ "Whether this room is encrypted",
+ false,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
]
});
@@ -276,6 +286,7 @@ mod imp {
obj.store_topic(topic);
}
"verification" => obj.set_verification(value.get().unwrap()),
+ "encrypted" => obj.set_is_encrypted(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -310,6 +321,7 @@ mod imp {
|id| id.as_ref().to_value(),
),
"verification" => obj.verification().to_value(),
+ "encrypted" => obj.is_encrypted().to_value(),
_ => unimplemented!(),
}
}
@@ -319,6 +331,7 @@ mod imp {
vec![
Signal::builder("order-changed", &[], <()>::static_type().into()).build(),
Signal::builder("room-forgotten", &[], <()>::static_type().into()).build(),
+ Signal::builder("new-encryption-keys", &[], <()>::static_type().into()).build(),
]
});
SIGNALS.as_ref()
@@ -338,6 +351,7 @@ mod imp {
.unwrap();
obj.load_power_levels();
+ obj.setup_is_encrypted();
obj.bind_property("display-name", obj.avatar(), "display-name")
.flags(glib::BindingFlags::SYNC_CREATE)
@@ -1637,6 +1651,75 @@ impl Room {
self.set_latest_unread(latest_unread);
}
+
+ pub fn is_encrypted(&self) -> bool {
+ self.imp().is_encrypted.get()
+ }
+
+ pub fn set_is_encrypted(&self, is_encrypted: bool) {
+ let was_encrypted = self.is_encrypted();
+ if was_encrypted == is_encrypted {
+ return;
+ }
+
+ if was_encrypted && !is_encrypted {
+ error!("Encryption for a room can't be disabled");
+ return;
+ }
+
+ if self.matrix_room().is_encrypted() != is_encrypted {
+ // TODO: enable encryption if it isn't enabled yet
+ }
+
+ self.setup_is_encrypted();
+ }
+
+ fn setup_is_encrypted(&self) {
+ if !self.matrix_room().is_encrypted() {
+ return;
+ }
+ self.setup_new_encryption_keys_handler();
+ self.imp().is_encrypted.set(true);
+ self.notify("encrypted");
+ }
+
+ fn setup_new_encryption_keys_handler(&self) {
+ spawn!(
+ glib::PRIORITY_DEFAULT_IDLE,
+ clone!(@weak self as obj => async move {
+ let obj_weak = glib::SendWeakRef::from(obj.downgrade());
+ obj.session().client().register_event_handler(
+ move |event: ToDeviceEvent<ToDeviceRoomKeyEventContent>| {
+ let obj_weak = obj_weak.clone();
+ async move {
+ let ctx = glib::MainContext::default();
+ ctx.spawn(async move {
+ if let Some(room) = obj_weak.upgrade() {
+ if room.room_id() == event.content.room_id {
+ room.emit_by_name::<()>("new-encryption-keys", &[]);
+ }
+ }
+ });
+ }
+ },
+ )
+ .await;
+ })
+ );
+ }
+
+ pub fn connect_new_encryption_keys<F: Fn(&Self) + 'static>(
+ &self,
+ f: F,
+ ) -> glib::SignalHandlerId {
+ self.connect_local("new-encryption-keys", true, move |values| {
+ let obj = values[0].get::<Self>().unwrap();
+
+ f(&obj);
+
+ None
+ })
+ }
}
/// Whether the given event can count as an unread message.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]