mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-10-31 01:50:47 +03:00
Allow properly editing pending encrypted messages
This commit is contained in:
parent
9f5b647fb3
commit
8e20139079
4 changed files with 96 additions and 30 deletions
|
@ -470,6 +470,30 @@ handle_pre_key_olm_message(const std::string &sender,
|
||||||
return plaintext;
|
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
|
mtx::events::msg::Encrypted
|
||||||
encrypt_group_message(const std::string &room_id, const std::string &device_id, nlohmann::json body)
|
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())
|
if (!sendSessionTo.empty())
|
||||||
olm::send_encrypted_to_device_messages(sendSessionTo, megolm_payload);
|
olm::send_encrypted_to_device_messages(sendSessionTo, megolm_payload);
|
||||||
|
|
||||||
// relations shouldn't be encrypted...
|
auto data = encrypt_group_message_with_session(session, device_id, body);
|
||||||
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;
|
|
||||||
|
|
||||||
group_session_data.message_index = olm_outbound_group_session_message_index(session.get());
|
group_session_data.message_index = olm_outbound_group_session_message_index(session.get());
|
||||||
nhlog::crypto()->debug("next message_index {}", group_session_data.message_index);
|
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 std::string &sender_key,
|
||||||
const mtx::events::msg::OlmCipherContent &content);
|
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
|
mtx::events::msg::Encrypted
|
||||||
encrypt_group_message(const std::string &room_id,
|
encrypt_group_message(const std::string &room_id,
|
||||||
const std::string &device_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
|
// 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
|
// event_id of this event. This allows one to edit and reply to events that are
|
||||||
// currently pending.
|
// 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_)) {
|
for (const auto &pending_event_id : cache::client()->pendingEvents(room_id_)) {
|
||||||
if (auto pending_event = cache::client()->getEvent(room_id_, pending_event_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);
|
auto relations = mtx::accessors::relations(pending_event->data);
|
||||||
|
|
||||||
// Replace the blockquote in fallback reply
|
// 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) {
|
for (mtx::common::Relation &rel : relations.relations) {
|
||||||
if (rel.event_id == txn_id)
|
if (rel.event_id == txn_id) {
|
||||||
rel.event_id = event_id;
|
rel.event_id = event_id;
|
||||||
|
replaced_txn = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!replaced_txn)
|
||||||
|
continue;
|
||||||
|
|
||||||
mtx::accessors::set_relations(pending_event->data, std::move(relations));
|
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);
|
cache::client()->replaceEvent(room_id_, pending_event_id, *pending_event);
|
||||||
|
|
||||||
auto idx = idToIndex(pending_event_id);
|
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,
|
// 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.
|
// and update the event_id so that it points to the sent message and not the pending one.
|
||||||
connect(&events,
|
connect(
|
||||||
&EventStore::messageSent,
|
&events,
|
||||||
this,
|
&EventStore::messageSent,
|
||||||
[this](const std::string &txn_id, const std::string &event_id) {
|
this,
|
||||||
if (edit_.toStdString() == txn_id) {
|
[this](const std::string &txn_id, const std::string &event_id) {
|
||||||
edit_ = QString::fromStdString(event_id);
|
if (edit_.toStdString() == txn_id) {
|
||||||
emit editChanged(edit_);
|
edit_ = QString::fromStdString(event_id);
|
||||||
}
|
emit editChanged(edit_);
|
||||||
if (reply_.toStdString() == txn_id) {
|
}
|
||||||
reply_ = QString::fromStdString(event_id);
|
nhlog::net()->debug("reply {}\ntxn {}\nev {}", reply_.toStdString(), txn_id, event_id);
|
||||||
emit replyChanged(reply_);
|
if (reply_.toStdString() == txn_id) {
|
||||||
}
|
reply_ = QString::fromStdString(event_id);
|
||||||
});
|
emit replyChanged(reply_);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
manager_, &TimelineViewManager::initialSyncChanged, &events, &EventStore::enableKeyRequests);
|
manager_, &TimelineViewManager::initialSyncChanged, &events, &EventStore::enableKeyRequests);
|
||||||
|
|
Loading…
Reference in a new issue