diff --git a/src/encryption/Olm.cpp b/src/encryption/Olm.cpp
index 5de18fa3..e6426658 100644
--- a/src/encryption/Olm.cpp
+++ b/src/encryption/Olm.cpp
@@ -471,6 +471,30 @@ handle_pre_key_olm_message(const std::string &sender,
}
mtx::events::msg::Encrypted
+encrypt_group_message_with_session(mtx::crypto::OutboundGroupSessionPtr &session,
+ const std::string &device_id,
+ nlohmann::json body)
+{
+ using namespace mtx::events;
+
+ // relations shouldn't be encrypted...
+ mtx::common::Relations relations = mtx::common::parse_relations(body["content"]);
+
+ auto payload = olm::client()->encrypt_group_message(session.get(), body.dump());
+
+ // Prepare the m.room.encrypted event.
+ msg::Encrypted data;
+ data.ciphertext = std::string((char *)payload.data(), payload.size());
+ data.sender_key = olm::client()->identity_keys().curve25519;
+ data.session_id = mtx::crypto::session_id(session.get());
+ data.device_id = device_id;
+ data.algorithm = MEGOLM_ALGO;
+ data.relations = relations;
+
+ return data;
+}
+
+mtx::events::msg::Encrypted
encrypt_group_message(const std::string &room_id, const std::string &device_id, nlohmann::json body)
{
using namespace mtx::events;
@@ -631,19 +655,7 @@ encrypt_group_message(const std::string &room_id, const std::string &device_id,
if (!sendSessionTo.empty())
olm::send_encrypted_to_device_messages(sendSessionTo, megolm_payload);
- // relations shouldn't be encrypted...
- mtx::common::Relations relations = mtx::common::parse_relations(body["content"]);
-
- auto payload = olm::client()->encrypt_group_message(session.get(), body.dump());
-
- // Prepare the m.room.encrypted event.
- msg::Encrypted data;
- data.ciphertext = std::string((char *)payload.data(), payload.size());
- data.sender_key = olm::client()->identity_keys().curve25519;
- data.session_id = mtx::crypto::session_id(session.get());
- data.device_id = device_id;
- data.algorithm = MEGOLM_ALGO;
- data.relations = relations;
+ auto data = encrypt_group_message_with_session(session, device_id, body);
group_session_data.message_index = olm_outbound_group_session_message_index(session.get());
nhlog::crypto()->debug("next message_index {}", group_session_data.message_index);
diff --git a/src/encryption/Olm.h b/src/encryption/Olm.h
index a6822b68..9d99bcf4 100644
--- a/src/encryption/Olm.h
+++ b/src/encryption/Olm.h
@@ -80,6 +80,11 @@ handle_pre_key_olm_message(const std::string &sender,
const mtx::events::msg::OlmCipherContent &content);
mtx::events::msg::Encrypted
+encrypt_group_message_with_session(mtx::crypto::OutboundGroupSessionPtr &session,
+ const std::string &device_id,
+ nlohmann::json body);
+
+mtx::events::msg::Encrypted
encrypt_group_message(const std::string &room_id,
const std::string &device_id,
nlohmann::json body);
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index f7d15b61..4151356f 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -184,11 +184,21 @@ EventStore::EventStore(std::string room_id, QObject *)
// Replace the event_id in pending edits/replies/redactions with the actual
// event_id of this event. This allows one to edit and reply to events that are
// currently pending.
-
- // FIXME (introduced by balsoft): this doesn't work for encrypted events, but
- // allegedly it's hard to fix so I'll leave my first contribution at that
for (const auto &pending_event_id : cache::client()->pendingEvents(room_id_)) {
if (auto pending_event = cache::client()->getEvent(room_id_, pending_event_id)) {
+ bool was_encrypted = false;
+ mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> original_encrypted;
+ if (auto encrypted =
+ std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
+ &pending_event->data)) {
+ auto d_event = decryptEvent({room_id_, encrypted->event_id}, *encrypted);
+ if (d_event->event) {
+ was_encrypted = true;
+ original_encrypted = *encrypted;
+ pending_event->data = *d_event->event;
+ }
+ }
+
auto relations = mtx::accessors::relations(pending_event->data);
// Replace the blockquote in fallback reply
@@ -202,13 +212,49 @@ EventStore::EventStore(std::string room_id, QObject *)
}
}
+ bool replaced_txn = false;
for (mtx::common::Relation &rel : relations.relations) {
- if (rel.event_id == txn_id)
+ if (rel.event_id == txn_id) {
rel.event_id = event_id;
+ replaced_txn = true;
+ }
}
+ if (!replaced_txn)
+ continue;
+
mtx::accessors::set_relations(pending_event->data, std::move(relations));
+ // reencrypt. This is a bit of a hack and might make people able to read the
+ // message, that were in the room at the time of sending the last pending message.
+ // That window is pretty small though, so it should be good enough. We also just
+ // fail, if there was no session. But there SHOULD always be one. Let's wait until
+ // I am proven wrong :3
+ if (was_encrypted) {
+ auto session = cache::getOutboundMegolmSession(room_id_);
+ if (!session.session)
+ continue;
+
+ std::visit(
+ [&pending_event, &original_encrypted, &session, this](auto &msg) {
+ json doc = {{"type", mtx::events::to_string(msg.type)},
+ {"content", json(msg.content)},
+ {"room_id", room_id_}};
+
+ auto data = olm::encrypt_group_message_with_session(
+ session.session, http::client()->device_id(), doc);
+
+ session.data.message_index =
+ olm_outbound_group_session_message_index(session.session.get());
+ cache::updateOutboundMegolmSession(
+ room_id_, session.data, session.session);
+
+ original_encrypted.content = data;
+ pending_event->data = original_encrypted;
+ },
+ pending_event->data);
+ }
+
cache::client()->replaceEvent(room_id_, pending_event_id, *pending_event);
auto idx = idToIndex(pending_event_id);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 7892c2e4..a8b6cf6f 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -423,19 +423,22 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
// When a message is sent, check if the current edit/reply relates to that message,
// and update the event_id so that it points to the sent message and not the pending one.
- connect(&events,
- &EventStore::messageSent,
- this,
- [this](const std::string &txn_id, const std::string &event_id) {
- if (edit_.toStdString() == txn_id) {
- edit_ = QString::fromStdString(event_id);
- emit editChanged(edit_);
- }
- if (reply_.toStdString() == txn_id) {
- reply_ = QString::fromStdString(event_id);
- emit replyChanged(reply_);
- }
- });
+ connect(
+ &events,
+ &EventStore::messageSent,
+ this,
+ [this](const std::string &txn_id, const std::string &event_id) {
+ if (edit_.toStdString() == txn_id) {
+ edit_ = QString::fromStdString(event_id);
+ emit editChanged(edit_);
+ }
+ nhlog::net()->debug("reply {}\ntxn {}\nev {}", reply_.toStdString(), txn_id, event_id);
+ if (reply_.toStdString() == txn_id) {
+ reply_ = QString::fromStdString(event_id);
+ emit replyChanged(reply_);
+ }
+ },
+ Qt::QueuedConnection);
connect(
manager_, &TimelineViewManager::initialSyncChanged, &events, &EventStore::enableKeyRequests);
|