Skip to content
Snippets Groups Projects
Verified Commit 8e201390 authored by Nicolas Werner's avatar Nicolas Werner
Browse files

Allow properly editing pending encrypted messages

parent 9f5b647f
No related branches found
No related tags found
No related merge requests found
Pipeline #2730 passed
......@@ -470,6 +470,30 @@ handle_pre_key_olm_message(const std::string &sender,
return plaintext;
}
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)
{
......@@ -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);
......
......@@ -79,6 +79,11 @@ handle_pre_key_olm_message(const std::string &sender,
const std::string &sender_key,
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,
......
......@@ -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);
......
......@@ -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);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment