From 56db0dbc7d0878ce1621a4dc998024d470d200a5 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Tue, 17 Aug 2021 03:23:51 +0200 Subject: [PATCH] Allow downloading keys from key backup --- CMakeLists.txt | 2 +- io.github.NhekoReborn.Nheko.yaml | 2 +- resources/qml/EncryptionIndicator.qml | 2 +- src/Cache.cpp | 47 ++++++++++++ src/CacheCryptoStructs.h | 25 +++++++ src/Cache_p.h | 4 + src/ChatPage.cpp | 100 +++++++++++++++++++++++++ src/ChatPage.h | 1 + src/MainWindow.cpp | 37 ++++----- src/Olm.cpp | 104 +++++++++++++++++++++++++- src/Olm.h | 4 +- src/UserSettingsPage.cpp | 24 ++++++ src/UserSettingsPage.h | 7 ++ src/timeline/EventStore.cpp | 7 +- src/timeline/TimelineModel.cpp | 10 +-- 15 files changed, 342 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ef4470c..db77c1f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,7 +381,7 @@ if(USE_BUNDLED_MTXCLIENT) FetchContent_Declare( MatrixClient GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git - GIT_TAG deb51ef1d6df870098069312f0a1999550e1eb85 + GIT_TAG 513196f520733e2f70576168aff7aaf16e0df180 ) set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "") set(BUILD_LIB_TESTS OFF CACHE INTERNAL "") diff --git a/io.github.NhekoReborn.Nheko.yaml b/io.github.NhekoReborn.Nheko.yaml index c9caddc8..9d4b3b2e 100644 --- a/io.github.NhekoReborn.Nheko.yaml +++ b/io.github.NhekoReborn.Nheko.yaml @@ -163,7 +163,7 @@ modules: buildsystem: cmake-ninja name: mtxclient sources: - - commit: deb51ef1d6df870098069312f0a1999550e1eb85 + - commit: 513196f520733e2f70576168aff7aaf16e0df180 type: git url: https://github.com/Nheko-Reborn/mtxclient.git - config-opts: diff --git a/resources/qml/EncryptionIndicator.qml b/resources/qml/EncryptionIndicator.qml index 52d2eeed..6bc16a18 100644 --- a/resources/qml/EncryptionIndicator.qml +++ b/resources/qml/EncryptionIndicator.qml @@ -39,7 +39,7 @@ Image { case Crypto.TOFU: return qsTr("Encrypted by an unverified device, but you have trusted that user so far."); default: - return qsTr("Encrypted by an unverified device"); + return qsTr("Encrypted by an unverified device or the key is from an untrusted source like the key backup."); } } diff --git a/src/Cache.cpp b/src/Cache.cpp index 8b8b2985..6b28ca91 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -42,6 +42,7 @@ static const std::string SECRET("secret"); static const std::string_view NEXT_BATCH_KEY("next_batch"); static const std::string_view OLM_ACCOUNT_KEY("olm_account"); static const std::string_view CACHE_FORMAT_VERSION_KEY("cache_format_version"); +static const std::string_view CURRENT_ONLINE_BACKUP_VERSION("current_online_backup_version"); constexpr size_t MAX_RESTORED_MESSAGES = 30'000; @@ -723,6 +724,36 @@ Cache::restoreOlmAccount() return std::string(pickled.data(), pickled.size()); } +void +Cache::saveBackupVersion(const OnlineBackupVersion &data) +{ + auto txn = lmdb::txn::begin(env_); + syncStateDb_.put(txn, CURRENT_ONLINE_BACKUP_VERSION, nlohmann::json(data).dump()); + txn.commit(); +} + +void +Cache::deleteBackupVersion() +{ + auto txn = lmdb::txn::begin(env_); + syncStateDb_.del(txn, CURRENT_ONLINE_BACKUP_VERSION); + txn.commit(); +} + +std::optional +Cache::backupVersion() +{ + try { + auto txn = ro_txn(env_); + std::string_view v; + syncStateDb_.get(txn, CURRENT_ONLINE_BACKUP_VERSION, v); + + return nlohmann::json::parse(v).get(); + } catch (...) { + return std::nullopt; + } +} + void Cache::storeSecret(const std::string name, const std::string secret) { @@ -4114,6 +4145,20 @@ from_json(const json &j, VerificationCache &info) info.device_blocked = j.at("device_blocked").get>(); } +void +to_json(json &j, const OnlineBackupVersion &info) +{ + j["v"] = info.version; + j["a"] = info.algorithm; +} + +void +from_json(const json &j, OnlineBackupVersion &info) +{ + info.version = j.at("v").get(); + info.algorithm = j.at("a").get(); +} + std::optional Cache::verificationCache(const std::string &user_id, lmdb::txn &txn) { @@ -4461,6 +4506,7 @@ to_json(nlohmann::json &obj, const GroupSessionData &msg) { obj["message_index"] = msg.message_index; obj["ts"] = msg.timestamp; + obj["trust"] = msg.trusted; obj["sender_claimed_ed25519_key"] = msg.sender_claimed_ed25519_key; obj["forwarding_curve25519_key_chain"] = msg.forwarding_curve25519_key_chain; @@ -4475,6 +4521,7 @@ from_json(const nlohmann::json &obj, GroupSessionData &msg) { msg.message_index = obj.at("message_index"); msg.timestamp = obj.value("ts", 0ULL); + msg.trusted = obj.value("trust", true); msg.sender_claimed_ed25519_key = obj.value("sender_claimed_ed25519_key", ""); msg.forwarding_curve25519_key_chain = diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h index 6c402674..80dd1046 100644 --- a/src/CacheCryptoStructs.h +++ b/src/CacheCryptoStructs.h @@ -47,6 +47,11 @@ struct GroupSessionData uint64_t message_index = 0; uint64_t timestamp = 0; + // If we got the session via key sharing or forwarding, we can usually trust it. + // If it came from asymmetric key backup, it is not trusted. + // TODO(Nico): What about forwards? They might come from key backup? + bool trusted = true; + std::string sender_claimed_ed25519_key; std::vector forwarding_curve25519_key_chain; @@ -83,6 +88,13 @@ from_json(const nlohmann::json &obj, DevicePublicKeys &msg); //! Represents a unique megolm session identifier. struct MegolmSessionIndex { + MegolmSessionIndex() = default; + MegolmSessionIndex(std::string room_id_, const mtx::events::msg::Encrypted &e) + : room_id(std::move(room_id_)) + , session_id(e.session_id) + , sender_key(e.sender_key) + {} + //! The room in which this session exists. std::string room_id; //! The session_id of the megolm session. @@ -167,3 +179,16 @@ void to_json(nlohmann::json &j, const VerificationCache &info); void from_json(const nlohmann::json &j, VerificationCache &info); + +struct OnlineBackupVersion +{ + //! the version of the online backup currently enabled + std::string version; + //! the algorithm used by the backup + std::string algorithm; +}; + +void +to_json(nlohmann::json &j, const OnlineBackupVersion &info); +void +from_json(const nlohmann::json &j, OnlineBackupVersion &info); diff --git a/src/Cache_p.h b/src/Cache_p.h index 748404d1..8322a6af 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -287,6 +287,10 @@ public: void saveOlmAccount(const std::string &pickled); std::string restoreOlmAccount(); + void saveBackupVersion(const OnlineBackupVersion &data); + void deleteBackupVersion(); + std::optional backupVersion(); + void storeSecret(const std::string name, const std::string secret); void deleteSecret(const std::string name); std::optional secret(const std::string name); diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 8a0e891b..639f3818 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -385,6 +385,7 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token) } getProfileInfo(); + getBackupVersion(); tryInitialSync(); } @@ -418,6 +419,7 @@ ChatPage::loadStateFromCache() nhlog::crypto()->info("curve25519: {}", olm::client()->identity_keys().curve25519); getProfileInfo(); + getBackupVersion(); emit contentLoaded(); @@ -974,6 +976,104 @@ ChatPage::getProfileInfo() }); } +void +ChatPage::getBackupVersion() +{ + if (!UserSettings::instance()->useOnlineKeyBackup()) { + nhlog::crypto()->info("Online key backup disabled."); + return; + } + + http::client()->backup_version( + [this](const mtx::responses::backup::BackupVersion &res, mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("Failed to retrieve backup version"); + if (err->status_code == 404) + cache::client()->deleteBackupVersion(); + return; + } + + // switch to UI thread for secrets stuff + 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") { + auto key = + cache::secret(mtx::secret_storage::secrets::megolm_backup_v1); + if (!key) { + nhlog::crypto()->info("No key for online key backup."); + cache::client()->deleteBackupVersion(); + return; + } + + using namespace mtx::crypto; + auto pubkey = CURVE25519_public_key_from_private( + to_binary_buf(base642bin(*key))); + + if (auth_data["public_key"].get() != pubkey) { + nhlog::crypto()->info( + "Our backup key {} does not match the one " + "used in the online backup {}", + pubkey, + auth_data["public_key"]); + cache::client()->deleteBackupVersion(); + return; + } + + nhlog::crypto()->info("Using online key backup."); + OnlineBackupVersion data{}; + data.algorithm = res.algorithm; + data.version = res.version; + cache::client()->saveBackupVersion(data); + + // We really don't need to add our signature. + // if (!auth_data["signatures"] + // [http::client()->user_id().to_string()] + // .contains("ed25519:" + + // http::client()->device_id())) { + // // add our signature + // // This is not strictly necessary, but some Element + // // clients rely on it. We assume the master_key + // signature + // // already exists and add our device signature just to + // be + // // safe, even though just the master signature is + // enough, + // // if cross-signing is used. + // auto signatures = auth_data["signatures"]; + // auth_data.erase("signatures"); + // auth_data.erase("unsigned"); + // signatures[http::client()->user_id().to_string()] + // ["ed25519:" + http::client()->device_id()] = + // olm::client()->sign_message(auth_data.dump()); + // auth_data["signatures"] = signatures; + + // auto copy = res; + // copy.auth_data = auth_data.dump(); + // http::client()->update_backup_version( + // res.version, copy, [](mtx::http::RequestErr e) { + // if (e) { + // nhlog::crypto()->error( + // "Failed to update online backup " + // "signatures: {} - {}", + // mtx::errors::to_string( + // e->matrix_error.errcode), + // e->matrix_error.error); + // } else { + // nhlog::crypto()->info( + // "Updated key backup signatures"); + // } + // }); + //} + } else { + nhlog::crypto()->info("Unsupported key backup algorithm: {}", + res.algorithm); + cache::client()->deleteBackupVersion(); + } + }); + }); +} + void ChatPage::initiateLogout() { diff --git a/src/ChatPage.h b/src/ChatPage.h index c90b87f5..dfe94c37 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -182,6 +182,7 @@ private: void trySync(); void ensureOneTimeKeyCount(const std::map &counts); void getProfileInfo(); + void getBackupVersion(); //! Check if the given room is currently open. bool isRoomActive(const QString &room_id); diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 8bc90f29..396e1ab1 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -130,26 +130,29 @@ MainWindow::MainWindow(QWidget *parent) trayIcon_->setVisible(userSettings_->tray()); - if (hasActiveUser()) { - QString token = userSettings_->accessToken(); - QString home_server = userSettings_->homeserver(); - QString user_id = userSettings_->userId(); - QString device_id = userSettings_->deviceId(); + // load cache on event loop + QTimer::singleShot(0, this, [this] { + if (hasActiveUser()) { + QString token = userSettings_->accessToken(); + QString home_server = userSettings_->homeserver(); + QString user_id = userSettings_->userId(); + QString device_id = userSettings_->deviceId(); - http::client()->set_access_token(token.toStdString()); - http::client()->set_server(home_server.toStdString()); - http::client()->set_device_id(device_id.toStdString()); + http::client()->set_access_token(token.toStdString()); + http::client()->set_server(home_server.toStdString()); + http::client()->set_device_id(device_id.toStdString()); - try { - using namespace mtx::identifiers; - http::client()->set_user(parse(user_id.toStdString())); - } catch (const std::invalid_argument &) { - nhlog::ui()->critical("bootstrapped with invalid user_id: {}", - user_id.toStdString()); + try { + using namespace mtx::identifiers; + http::client()->set_user(parse(user_id.toStdString())); + } catch (const std::invalid_argument &) { + nhlog::ui()->critical("bootstrapped with invalid user_id: {}", + user_id.toStdString()); + } + + showChatPage(); } - - showChatPage(); - } + }); if (loadJdenticonPlugin()) { nhlog::ui()->info("loaded jdenticon."); diff --git a/src/Olm.cpp b/src/Olm.cpp index 2c9ac5a3..05eefce4 100644 --- a/src/Olm.cpp +++ b/src/Olm.cpp @@ -833,6 +833,8 @@ import_inbound_megolm_session( data.forwarding_curve25519_key_chain = roomKey.content.forwarding_curve25519_key_chain; data.sender_claimed_ed25519_key = roomKey.content.sender_claimed_ed25519_key; + // may have come from online key backup, so we can't trust it... + data.trusted = false; cache::saveInboundMegolmSession(index, std::move(megolm_session), data); } catch (const lmdb::error &e) { @@ -856,6 +858,97 @@ mark_keys_as_published() cache::saveOlmAccount(olm::client()->save(STORAGE_SECRET_KEY)); } +void +lookup_keybackup(const std::string room, const std::string session_id) +{ + if (!UserSettings::instance()->useOnlineKeyBackup()) { + // Online key backup disabled + return; + } + + auto backupVersion = cache::client()->backupVersion(); + if (!backupVersion) { + // no trusted OKB + return; + } + + using namespace mtx::crypto; + + auto decryptedSecret = cache::secret(mtx::secret_storage::secrets::megolm_backup_v1); + if (!decryptedSecret) { + // no backup key available + return; + } + auto sessionDecryptionKey = to_binary_buf(base642bin(*decryptedSecret)); + + http::client()->room_keys( + backupVersion->version, + room, + session_id, + [room, session_id, sessionDecryptionKey](const mtx::responses::backup::SessionBackup &bk, + mtx::http::RequestErr err) { + if (err) { + if (err->status_code != 404) + nhlog::crypto()->error( + "Failed to dowload key {}:{}: {} - {}", + room, + session_id, + mtx::errors::to_string(err->matrix_error.errcode), + err->matrix_error.error); + return; + } + try { + auto session = decrypt_session(bk.session_data, sessionDecryptionKey); + + if (session.algorithm != mtx::crypto::MEGOLM_ALGO) + // don't know this algorithm + return; + + MegolmSessionIndex index; + index.room_id = room; + index.session_id = session_id; + index.sender_key = session.sender_key; + + GroupSessionData data{}; + data.forwarding_curve25519_key_chain = + session.forwarding_curve25519_key_chain; + data.sender_claimed_ed25519_key = session.sender_claimed_keys["ed25519"]; + // online key backup can't be trusted, because anyone can upload to it. + data.trusted = false; + + auto megolm_session = + olm::client()->import_inbound_group_session(session.session_key); + + if (!cache::inboundMegolmSessionExists(index) || + olm_inbound_group_session_first_known_index(megolm_session.get()) < + olm_inbound_group_session_first_known_index( + cache::getInboundMegolmSession(index).get())) { + cache::saveInboundMegolmSession( + index, std::move(megolm_session), data); + + nhlog::crypto()->info("imported inbound megolm session " + "from key backup ({}, {})", + room, + session_id); + + // call on UI thread + QTimer::singleShot(0, ChatPage::instance(), [index] { + ChatPage::instance()->receivedSessionKey( + index.room_id, index.session_id); + }); + } + } catch (const lmdb::error &e) { + nhlog::crypto()->critical("failed to save inbound megolm session: {}", + e.what()); + return; + } catch (const mtx::crypto::olm_exception &e) { + nhlog::crypto()->critical("failed to import inbound megolm session: {}", + e.what()); + return; + } + }); +} + void send_key_request_for(mtx::events::EncryptedEvent e, const std::string &request_id, @@ -898,6 +991,8 @@ send_key_request_for(mtx::events::EncryptedEvent e, e.sender, e.content.device_id); }); + + // http::client()->room_keys } void @@ -1095,12 +1190,15 @@ decryptEvent(const MegolmSessionIndex &index, } crypto::Trust -calculate_trust(const std::string &user_id, const std::string &curve25519) +calculate_trust(const std::string &user_id, const MegolmSessionIndex &index) { auto status = cache::client()->verificationStatus(user_id); + auto megolmData = cache::client()->getMegolmSessionData(index); crypto::Trust trustlevel = crypto::Trust::Unverified; - if (status.verified_device_keys.count(curve25519)) - trustlevel = status.verified_device_keys.at(curve25519); + + if (megolmData && megolmData->trusted && + status.verified_device_keys.count(index.sender_key)) + trustlevel = status.verified_device_keys.at(index.sender_key); return trustlevel; } diff --git a/src/Olm.h b/src/Olm.h index ab86ca00..eb60ae3a 100644 --- a/src/Olm.h +++ b/src/Olm.h @@ -70,6 +70,8 @@ create_inbound_megolm_session(const mtx::events::DeviceEvent &roomKey); +void +lookup_keybackup(const std::string room, const std::string session_id); nlohmann::json handle_pre_key_olm_message(const std::string &sender, @@ -87,7 +89,7 @@ decryptEvent(const MegolmSessionIndex &index, const mtx::events::EncryptedEvent &event, bool dont_write_db = false); crypto::Trust -calculate_trust(const std::string &user_id, const std::string &curve25519); +calculate_trust(const std::string &user_id, const MegolmSessionIndex &index); void mark_keys_as_published(); diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index f67c5e2d..ab1e442c 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -124,6 +124,7 @@ UserSettings::load(std::optional profile) .toBool(); onlyShareKeysWithVerifiedUsers_ = settings.value(prefix + "user/only_share_keys_with_verified_users", false).toBool(); + useOnlineKeyBackup_ = settings.value(prefix + "user/online_key_backup", true).toBool(); disableCertificateValidation_ = settings.value("disable_certificate_validation", false).toBool(); @@ -425,6 +426,17 @@ UserSettings::setShareKeysWithTrustedUsers(bool shareKeys) save(); } +void +UserSettings::setUseOnlineKeyBackup(bool useBackup) +{ + if (useBackup == useOnlineKeyBackup_) + return; + + useOnlineKeyBackup_ = useBackup; + emit useOnlineKeyBackupChanged(useBackup); + save(); +} + void UserSettings::setRingtone(QString ringtone) { @@ -664,6 +676,7 @@ UserSettings::save() shareKeysWithTrustedUsers_); settings.setValue(prefix + "user/only_share_keys_with_verified_users", onlyShareKeysWithVerifiedUsers_); + settings.setValue(prefix + "user/online_key_backup", useOnlineKeyBackup_); settings.setValue("disable_certificate_validation", disableCertificateValidation_); @@ -725,6 +738,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer settings, QWidge privacyScreen_ = new Toggle{this}; onlyShareKeysWithVerifiedUsers_ = new Toggle(this); shareKeysWithTrustedUsers_ = new Toggle(this); + useOnlineKeyBackup_ = new Toggle(this); groupViewToggle_ = new Toggle{this}; timelineButtonsToggle_ = new Toggle{this}; typingNotifications_ = new Toggle{this}; @@ -756,6 +770,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer settings, QWidge privacyScreen_->setChecked(settings_->privacyScreen()); onlyShareKeysWithVerifiedUsers_->setChecked(settings_->onlyShareKeysWithVerifiedUsers()); shareKeysWithTrustedUsers_->setChecked(settings_->shareKeysWithTrustedUsers()); + useOnlineKeyBackup_->setChecked(settings_->useOnlineKeyBackup()); groupViewToggle_->setChecked(settings_->groupView()); timelineButtonsToggle_->setChecked(settings_->buttonsInTimeline()); typingNotifications_->setChecked(settings_->typingNotifications()); @@ -1033,6 +1048,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer settings, QWidge shareKeysWithTrustedUsers_, tr("Automatically replies to key requests from other users, if they are verified, " "even if that device shouldn't have access to those keys otherwise.")); + boxWrap(tr("Online Key Backup"), + useOnlineKeyBackup_, + tr("Download message encryption keys from and upload to the encrypted online key " + "backup.")); formLayout_->addRow(new HorizontalLine{this}); formLayout_->addRow(sessionKeysLabel, sessionKeysLayout); formLayout_->addRow(crossSigningKeysLabel, crossSigningKeysLayout); @@ -1208,6 +1227,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer settings, QWidge settings_->setShareKeysWithTrustedUsers(enabled); }); + connect(useOnlineKeyBackup_, &Toggle::toggled, this, [this](bool enabled) { + settings_->setUseOnlineKeyBackup(enabled); + }); + connect(avatarCircles_, &Toggle::toggled, this, [this](bool enabled) { settings_->setAvatarCircles(enabled); }); @@ -1298,6 +1321,7 @@ UserSettingsPage::showEvent(QShowEvent *) privacyScreen_->setState(settings_->privacyScreen()); onlyShareKeysWithVerifiedUsers_->setState(settings_->onlyShareKeysWithVerifiedUsers()); shareKeysWithTrustedUsers_->setState(settings_->shareKeysWithTrustedUsers()); + useOnlineKeyBackup_->setState(settings_->useOnlineKeyBackup()); avatarCircles_->setState(settings_->avatarCircles()); typingNotifications_->setState(settings_->typingNotifications()); sortByImportance_->setState(settings_->sortByImportance()); diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h index 84940e47..ab9c9a3b 100644 --- a/src/UserSettingsPage.h +++ b/src/UserSettingsPage.h @@ -93,6 +93,8 @@ class UserSettings : public QObject setOnlyShareKeysWithVerifiedUsers NOTIFY onlyShareKeysWithVerifiedUsersChanged) Q_PROPERTY(bool shareKeysWithTrustedUsers READ shareKeysWithTrustedUsers WRITE setShareKeysWithTrustedUsers NOTIFY shareKeysWithTrustedUsersChanged) + Q_PROPERTY(bool useOnlineKeyBackup READ useOnlineKeyBackup WRITE setUseOnlineKeyBackup + NOTIFY useOnlineKeyBackupChanged) Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged) Q_PROPERTY(QString userId READ userId WRITE setUserId NOTIFY userIdChanged) Q_PROPERTY( @@ -159,6 +161,7 @@ public: void setUseStunServer(bool state); void setOnlyShareKeysWithVerifiedUsers(bool state); void setShareKeysWithTrustedUsers(bool state); + void setUseOnlineKeyBackup(bool state); void setProfile(QString profile); void setUserId(QString userId); void setAccessToken(QString accessToken); @@ -215,6 +218,7 @@ public: bool useStunServer() const { return useStunServer_; } bool shareKeysWithTrustedUsers() const { return shareKeysWithTrustedUsers_; } bool onlyShareKeysWithVerifiedUsers() const { return onlyShareKeysWithVerifiedUsers_; } + bool useOnlineKeyBackup() const { return useOnlineKeyBackup_; } QString profile() const { return profile_; } QString userId() const { return userId_; } QString accessToken() const { return accessToken_; } @@ -261,6 +265,7 @@ signals: void useStunServerChanged(bool state); void onlyShareKeysWithVerifiedUsersChanged(bool state); void shareKeysWithTrustedUsersChanged(bool state); + void useOnlineKeyBackupChanged(bool state); void profileChanged(QString profile); void userIdChanged(QString userId); void accessTokenChanged(QString accessToken); @@ -293,6 +298,7 @@ private: int privacyScreenTimeout_; bool shareKeysWithTrustedUsers_; bool onlyShareKeysWithVerifiedUsers_; + bool useOnlineKeyBackup_; bool mobileMode_; int timelineMaxWidth_; int roomListWidth_; @@ -384,6 +390,7 @@ private: QSpinBox *privacyScreenTimeout_; Toggle *shareKeysWithTrustedUsers_; Toggle *onlyShareKeysWithVerifiedUsers_; + Toggle *useOnlineKeyBackup_; Toggle *mobileMode_; QLabel *deviceFingerprintValue_; QLabel *deviceIdValue_; diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 742f8dbb..8860bc75 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -643,10 +643,7 @@ EventStore::decryptEvent(const IdIndex &idx, if (auto cachedEvent = decryptedEvents_.object(idx)) return cachedEvent; - MegolmSessionIndex index; - index.room_id = room_id_; - index.session_id = e.content.session_id; - index.sender_key = e.content.sender_key; + MegolmSessionIndex index(room_id_, e.content); auto asCacheEntry = [&idx](olm::DecryptionResult &&event) { auto event_ptr = new olm::DecryptionResult(std::move(event)); @@ -726,6 +723,7 @@ EventStore::requestSession(const mtx::events::EncryptedEventgenerate_txn_id(); request.requested_at = QDateTime::currentSecsSinceEpoch(); request.events.push_back(copy); + olm::lookup_keybackup(room_id_, ev.content.session_id); olm::send_key_request_for(copy, request.request_id); pending_key_requests[ev.content.session_id] = request; } diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 79c28edf..88d575fa 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -641,8 +641,9 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r if (auto encrypted = std::get_if>( &*encrypted_event)) { - return olm::calculate_trust(encrypted->sender, - encrypted->content.sender_key); + return olm::calculate_trust( + encrypted->sender, + MegolmSessionIndex(room_id_.toStdString(), encrypted->content)); } } return crypto::Trust::Unverified; @@ -840,10 +841,7 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline) for (auto e : timeline.events) { if (auto encryptedEvent = std::get_if>(&e)) { - MegolmSessionIndex index; - index.room_id = room_id_.toStdString(); - index.session_id = encryptedEvent->content.session_id; - index.sender_key = encryptedEvent->content.sender_key; + MegolmSessionIndex index(room_id_.toStdString(), encryptedEvent->content); auto result = olm::decryptEvent(index, *encryptedEvent); if (result.event)