summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-02-18 02:59:33 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2023-02-18 03:08:23 +0100
commit20740c9976e5f16326dea03b6b2cda933caa1d2e (patch)
tree58f57e04ccfff8e47554b12eea7c0ece867f2e29 /src
parentFix edits in other clients jumping out of threads (diff)
downloadnheko-20740c9976e5f16326dea03b6b2cda933caa1d2e.tar.xz
Automatically fetch keys for undecrypted messages after verification
Also fix rerendering edited messages after keys are received.

fixes #1375
fixes #770
fixes #888
Diffstat (limited to 'src')
-rw-r--r--src/ChatPage.cpp14
-rw-r--r--src/ChatPage.h1
-rw-r--r--src/encryption/Olm.cpp34
-rw-r--r--src/timeline/EventStore.cpp26
-rw-r--r--src/timeline/EventStore.h4
-rw-r--r--src/timeline/RoomlistModel.cpp12
-rw-r--r--src/timeline/RoomlistModel.h2
-rw-r--r--src/timeline/TimelineModel.h2
8 files changed, 80 insertions, 15 deletions
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp

index 1d0edb2a..2f6d7410 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp
@@ -547,6 +547,12 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token) &Cache::newReadReceipts, view_manager_, &TimelineViewManager::updateReadReceipts); + + connect(cache::client(), &Cache::secretChanged, this, [this](const std::string &secret) { + if (secret == mtx::secret_storage::secrets::megolm_backup_v1) { + getBackupVersion(); + } + }); } catch (const lmdb::error &e) { nhlog::db()->critical("failure during boot: {}", e.what()); emit dropToLoginPageCb(tr("Failed to open database, logging out!")); @@ -1224,7 +1230,7 @@ ChatPage::getBackupVersion() } // switch to UI thread for secrets stuff - QTimer::singleShot(0, this, [res] { + QTimer::singleShot(0, this, [this, res] { auto auth_data = nlohmann::json::parse(res.auth_data); if (res.algorithm == "m.megolm_backup.v1.curve25519-aes-sha2") { @@ -1247,11 +1253,17 @@ ChatPage::getBackupVersion() return; } + auto oldBackupVersion = cache::client()->backupVersion(); + nhlog::crypto()->info("Using online key backup."); OnlineBackupVersion data{}; data.algorithm = res.algorithm; data.version = res.version; cache::client()->saveBackupVersion(data); + + if (!oldBackupVersion || oldBackupVersion->version != data.version) { + view_manager_->rooms()->refetchOnlineKeyBackupKeys(); + } } else { nhlog::crypto()->info("Unsupported key backup algorithm: {}", res.algorithm); cache::client()->deleteBackupVersion(); diff --git a/src/ChatPage.h b/src/ChatPage.h
index ffe70496..1922b1c3 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h
@@ -180,6 +180,7 @@ signals: QString reason = "", bool failedJoin = false, bool promptForConfirmation = true); + void newOnlineKeyBackupAvailable(); private slots: void logout(); diff --git a/src/encryption/Olm.cpp b/src/encryption/Olm.cpp
index 41dde1b9..157b9169 100644 --- a/src/encryption/Olm.cpp +++ b/src/encryption/Olm.cpp
@@ -896,12 +896,15 @@ download_full_keybackup() { if (!UserSettings::instance()->useOnlineKeyBackup()) { // Online key backup disabled + nhlog::crypto()->debug("Not downloading full online key backup, because it is disabled."); return; } auto backupVersion = cache::client()->backupVersion(); if (!backupVersion) { // no trusted OKB + nhlog::crypto()->debug( + "Not downloading full online key backup, because we don't have a version for it."); return; } @@ -910,10 +913,14 @@ download_full_keybackup() auto decryptedSecret = cache::secret(mtx::secret_storage::secrets::megolm_backup_v1); if (!decryptedSecret) { // no backup key available + nhlog::crypto()->debug( + "Not downloading full online key backup, because we don't have a key for it."); return; } auto sessionDecryptionKey = to_binary_buf(base642bin(*decryptedSecret)); + nhlog::crypto()->debug("Downloading full online key backup."); + http::client()->room_keys( backupVersion->version, [sessionDecryptionKey](const mtx::responses::backup::KeysBackup &bk, @@ -925,11 +932,12 @@ download_full_keybackup() err->matrix_error.error); return; } + nhlog::crypto()->debug("Storing full online key backup."); mtx::crypto::ExportedSessionKeys allKeys; - try { - for (const auto &[room, roomKey] : bk.rooms) { - for (const auto &[session_id, encSession] : roomKey.sessions) { + for (const auto &[room, roomKey] : bk.rooms) { + for (const auto &[session_id, encSession] : roomKey.sessions) { + try { auto session = decrypt_session(encSession.session_data, sessionDecryptionKey); if (session.algorithm != mtx::crypto::MEGOLM_ALGO) @@ -946,16 +954,22 @@ download_full_keybackup() sess.sender_key = std::move(session.sender_key); sess.session_key = std::move(session.session_key); allKeys.sessions.push_back(std::move(sess)); + } catch (const olm_exception &e) { + nhlog::crypto()->critical("failed to decrypt inbound megolm session: {}", + e.what()); } } + } - // call on UI thread - QTimer::singleShot(0, ChatPage::instance(), [keys = std::move(allKeys)] { + // call on UI thread + QTimer::singleShot(0, ChatPage::instance(), [keys = std::move(allKeys)] { + try { cache::importSessionKeys(keys); - }); - } catch (const lmdb::error &e) { - nhlog::crypto()->critical("failed to save inbound megolm session: {}", e.what()); - } + nhlog::crypto()->debug("Storing full online key backup completed."); + } catch (const lmdb::error &e) { + nhlog::crypto()->critical("failed to save inbound megolm session: {}", e.what()); + } + }); }); } void @@ -1083,8 +1097,6 @@ send_key_request_for(mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> e, nhlog::net()->info( "m.room_key_request sent to {}:{} and your own devices", e.sender, e.content.device_id); }); - - // http::client()->room_keys } void diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 2cd16be8..5f118895 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp
@@ -17,6 +17,7 @@ #include "EventAccessors.h" #include "Logging.h" #include "MatrixClient.h" +#include "TimelineModel.h" #include "UserSettingsPage.h" #include "Utils.h" @@ -353,6 +354,16 @@ EventStore::receivedSessionKey(const std::string &session_id) events_.remove({room_id_, toInternalIdx(*idx)}); emit dataChanged(*idx, *idx); } + + if (auto edit = e.content.relations.replaces()) { + auto edit_idx = idToIndex(edit.value()); + if (edit_idx) { + decryptedEvents_.remove({room_id_, e.event_id}); + events_by_id_.remove({room_id_, e.event_id}); + events_.remove({room_id_, toInternalIdx(*edit_idx)}); + emit dataChanged(*edit_idx, *edit_idx); + } + } } } @@ -538,7 +549,7 @@ EventStore::edits(const std::string &event_id) // spec does not allow changing relatings in an edit. So if we are not using the multi // relation format specific to Nheko, just use the original relations + the edit... if (edit_rel.synthesized) { - auto merged_relations = original_relations; + auto merged_relations = original_relations; merged_relations.synthesized = true; merged_relations.relations.push_back( {mtx::common::RelationType::Replace, event_id}); @@ -754,6 +765,15 @@ EventStore::decryptEvent(const IdIndex &idx, } void +EventStore::refetchOnlineKeyBackupKeys(TimelineModel *room) +{ + for (const auto &[session_id, request] : room->events.pending_key_requests) { + (void)request; + olm::lookup_keybackup(room->events.room_id_, session_id); + } +} + +void EventStore::requestSession(const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &ev, bool manual) { @@ -767,8 +787,8 @@ EventStore::requestSession(const mtx::events::EncryptedEvent<mtx::events::msg::E auto &r = pending_key_requests.at(ev.content.session_id); r.events.push_back(copy); - // automatically request once every 10 min, manually every 1 min - qint64 delay = manual ? 60 : (60 * 10); + // automatically request once every 2 min, manually every 30 s + qint64 delay = manual ? 30 : (60 * 2); if (r.requested_at + delay < QDateTime::currentSecsSinceEpoch()) { r.requested_at = QDateTime::currentSecsSinceEpoch(); olm::lookup_keybackup(room_id_, ev.content.session_id); diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h
index bfca7dbe..45dc0169 100644 --- a/src/timeline/EventStore.h +++ b/src/timeline/EventStore.h
@@ -20,6 +20,8 @@ #include "Reaction.h" #include "encryption/Olm.h" +class TimelineModel; + class EventStore final : public QObject { Q_OBJECT @@ -27,6 +29,8 @@ class EventStore final : public QObject public: EventStore(std::string room_id, QObject *parent); + static void refetchOnlineKeyBackupKeys(TimelineModel *room); + // taken from QtPrivate::QHashCombine static uint hashCombine(uint hash, uint seed) { diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index 5bd12a36..c4826453 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp
@@ -812,6 +812,18 @@ RoomlistModel::setCurrentRoom(const QString &roomid) } } +void +RoomlistModel::refetchOnlineKeyBackupKeys() +{ + for (auto i = models.begin(); i != models.end(); ++i) { + auto ptr = i.value(); + + if (!ptr.isNull()) { + EventStore::refetchOnlineKeyBackupKeys(ptr.data()); + } + } +} + namespace { enum NotificationImportance : short { diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index 4b312ddc..8f7694b7 100644 --- a/src/timeline/RoomlistModel.h +++ b/src/timeline/RoomlistModel.h
@@ -95,6 +95,8 @@ public: } RoomPreview getRoomPreviewById(QString roomid) const; + void refetchOnlineKeyBackupKeys(); + public slots: void initializeRooms(); void sync(const mtx::responses::Sync &sync_); diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 334a4d6f..f753f24d 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h
@@ -528,6 +528,8 @@ private: std::unique_ptr<RoomSummary, DeleteLaterDeleter> parentSummary = nullptr; bool parentChecked = false; + + friend void EventStore::refetchOnlineKeyBackupKeys(TimelineModel *room); }; template<class T>