summary refs log tree commit diff
path: root/src/timeline/EventStore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/timeline/EventStore.cpp')
-rw-r--r--src/timeline/EventStore.cpp170
1 files changed, 158 insertions, 12 deletions
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp

index 749d4092..d3c5c3fa 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp
@@ -5,6 +5,7 @@ #include "Cache.h" #include "Cache_p.h" +#include "ChatPage.h" #include "EventAccessors.h" #include "Logging.h" #include "MatrixClient.h" @@ -53,9 +54,8 @@ EventStore::EventStore(std::string room_id, QObject *) &EventStore::oldMessagesRetrieved, this, [this](const mtx::responses::Messages &res) { - // uint64_t newFirst = cache::client()->saveOldMessages(room_id_, res); - if (newFirst == first && !res.chunk.empty()) + if (newFirst == first) fetchMore(); else { emit beginInsertRows(toExternalIdx(newFirst), @@ -97,8 +97,8 @@ EventStore::EventStore(std::string room_id, QObject *) room_id_, txn_id, e.content, - [this, txn_id](const mtx::responses::EventId &event_id, - mtx::http::RequestErr err) { + [this, txn_id, e](const mtx::responses::EventId &event_id, + mtx::http::RequestErr err) { if (err) { const int status_code = static_cast<int>(err->status_code); @@ -110,7 +110,21 @@ EventStore::EventStore(std::string room_id, QObject *) emit messageFailed(txn_id); return; } + emit messageSent(txn_id, event_id.event_id.to_string()); + if constexpr (std::is_same_v< + decltype(e.content), + mtx::events::msg::Encrypted>) { + auto event = + decryptEvent({room_id_, e.event_id}, e); + if (auto dec = + std::get_if<mtx::events::RoomEvent< + mtx::events::msg:: + KeyVerificationRequest>>(event)) { + emit updateFlowEventId( + event_id.event_id.to_string()); + } + } }); }, event->data); @@ -265,9 +279,78 @@ EventStore::handleSync(const mtx::responses::Timeline &events) emit dataChanged(toExternalIdx(*idx), toExternalIdx(*idx)); } } + + // decrypting and checking some encrypted messages + if (auto encrypted = + std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>( + &event)) { + mtx::events::collections::TimelineEvents *d_event = + decryptEvent({room_id_, encrypted->event_id}, *encrypted); + if (std::visit( + [](auto e) { return (e.sender != utils::localUser().toStdString()); }, + *d_event)) { + handle_room_verification(*d_event); + } + // else { + // // only the key.verification.ready sent by localuser's other + // device + // // is of significance as it is used for detecting accepted request + // if (std::get_if<mtx::events::RoomEvent< + // mtx::events::msg::KeyVerificationReady>>(d_event)) { + // auto msg = std::get_if<mtx::events::RoomEvent< + // mtx::events::msg::KeyVerificationReady>>(d_event); + // ChatPage::instance()->receivedDeviceVerificationReady( + // msg->content); + // } + //} + } } } +namespace { +template<class... Ts> +struct overloaded : Ts... +{ + using Ts::operator()...; +}; +template<class... Ts> +overloaded(Ts...) -> overloaded<Ts...>; +} + +void +EventStore::handle_room_verification(mtx::events::collections::TimelineEvents event) +{ + std::visit( + overloaded{ + [this](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &msg) { + emit startDMVerification(msg); + }, + [](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationCancel> &msg) { + ChatPage::instance()->receivedDeviceVerificationCancel(msg.content); + }, + [](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationAccept> &msg) { + ChatPage::instance()->receivedDeviceVerificationAccept(msg.content); + }, + [](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationKey> &msg) { + ChatPage::instance()->receivedDeviceVerificationKey(msg.content); + }, + [](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationMac> &msg) { + ChatPage::instance()->receivedDeviceVerificationMac(msg.content); + }, + [](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationReady> &msg) { + ChatPage::instance()->receivedDeviceVerificationReady(msg.content); + }, + [](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationDone> &msg) { + ChatPage::instance()->receivedDeviceVerificationDone(msg.content); + }, + [](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationStart> &msg) { + ChatPage::instance()->receivedDeviceVerificationStart(msg.content, msg.sender); + }, + [](const auto &) {}, + }, + event); +} + QVariantList EventStore::reactions(const std::string &event_id) { @@ -289,13 +372,14 @@ EventStore::reactions(const std::string &event_id) continue; if (auto reaction = std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>( - related_event)) { - auto &agg = aggregation[reaction->content.relates_to.key]; + related_event); + reaction && reaction->content.relates_to.key) { + auto &agg = aggregation[reaction->content.relates_to.key.value()]; if (agg.count == 0) { Reaction temp{}; temp.key_ = - QString::fromStdString(reaction->content.relates_to.key); + QString::fromStdString(reaction->content.relates_to.key.value()); reactions.push_back(temp); } @@ -407,11 +491,12 @@ EventStore::decryptEvent(const IdIndex &idx, auto decryptionResult = olm::decryptEvent(index, e); + mtx::events::RoomEvent<mtx::events::msg::Notice> dummy; + dummy.origin_server_ts = e.origin_server_ts; + dummy.event_id = e.event_id; + dummy.sender = e.sender; + if (decryptionResult.error) { - mtx::events::RoomEvent<mtx::events::msg::Notice> dummy; - dummy.origin_server_ts = e.origin_server_ts; - dummy.event_id = e.event_id; - dummy.sender = e.sender; switch (*decryptionResult.error) { case olm::DecryptionErrorCode::MissingSession: dummy.content.body = @@ -484,6 +569,66 @@ EventStore::decryptEvent(const IdIndex &idx, return asCacheEntry(std::move(dummy)); } + std::string msg_str; + try { + auto session = cache::client()->getInboundMegolmSession(index); + auto res = olm::client()->decrypt_group_message(session, e.content.ciphertext); + msg_str = std::string((char *)res.data.data(), res.data.size()); + } catch (const lmdb::error &e) { + nhlog::db()->critical("failed to retrieve megolm session with index ({}, {}, {})", + index.room_id, + index.session_id, + index.sender_key, + e.what()); + dummy.content.body = + tr("-- Decryption Error (failed to retrieve megolm keys from db) --", + "Placeholder, when the message can't be decrypted, because the DB " + "access " + "failed.") + .toStdString(); + return asCacheEntry(std::move(dummy)); + } catch (const mtx::crypto::olm_exception &e) { + nhlog::crypto()->critical("failed to decrypt message with index ({}, {}, {}): {}", + index.room_id, + index.session_id, + index.sender_key, + e.what()); + dummy.content.body = + tr("-- Decryption Error (%1) --", + "Placeholder, when the message can't be decrypted. In this case, the " + "Olm " + "decrytion returned an error, which is passed as %1.") + .arg(e.what()) + .toStdString(); + return asCacheEntry(std::move(dummy)); + } + + // Add missing fields for the event. + json body = json::parse(msg_str); + body["event_id"] = e.event_id; + body["sender"] = e.sender; + body["origin_server_ts"] = e.origin_server_ts; + body["unsigned"] = e.unsigned_data; + + // relations are unencrypted in content... + if (json old_ev = e; old_ev["content"].count("m.relates_to") != 0) + body["content"]["m.relates_to"] = old_ev["content"]["m.relates_to"]; + + json event_array = json::array(); + event_array.push_back(body); + + std::vector<mtx::events::collections::TimelineEvents> temp_events; + mtx::responses::utils::parse_timeline_events(event_array, temp_events); + + if (temp_events.size() == 1) { + auto encInfo = mtx::accessors::file(temp_events[0]); + + if (encInfo) + emit newEncryptedImage(encInfo.value()); + + return asCacheEntry(std::move(temp_events[0])); + } + auto encInfo = mtx::accessors::file(decryptionResult.event.value()); if (encInfo) emit newEncryptedImage(encInfo.value()); @@ -515,7 +660,8 @@ EventStore::get(std::string_view id, std::string_view related_to, bool decrypt) mtx::http::RequestErr err) { if (err) { nhlog::net()->error( - "Failed to retrieve event with id {}, which was " + "Failed to retrieve event with id {}, which " + "was " "requested to show the replyTo for event {}", relatedTo, id);