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)] { - cache::importSessionKeys(keys); - }); - } catch (const lmdb::error &e) { - nhlog::crypto()->critical("failed to save inbound megolm session: {}", e.what()); } + + // call on UI thread + QTimer::singleShot(0, ChatPage::instance(), [keys = std::move(allKeys)] { + try { + cache::importSessionKeys(keys); + 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 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}); @@ -753,6 +764,15 @@ EventStore::decryptEvent(const IdIndex &idx, return asCacheEntry(std::move(decryptionResult)); } +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 &ev, bool manual) @@ -767,8 +787,8 @@ EventStore::requestSession(const mtx::events::EncryptedEvent parentSummary = nullptr; bool parentChecked = false; + + friend void EventStore::refetchOnlineKeyBackupKeys(TimelineModel *room); }; template