summary refs log tree commit diff
path: root/src/encryption/Olm.cpp
diff options
context:
space:
mode:
authorZhymabek Roman <61125068+ZhymabekRoman@users.noreply.github.com>2023-01-02 21:59:29 +0600
committerGitHub <noreply@github.com>2023-01-02 21:59:29 +0600
commit59410a99ac9b5a90356adc2192b8c6107456c78f (patch)
treef42e081641cee3d62057208f3af1de3afddd02e6 /src/encryption/Olm.cpp
parentAppImage: reduce package size (diff)
parentA whole new year full of excitement and possibilities! (diff)
downloadnheko-59410a99ac9b5a90356adc2192b8c6107456c78f.tar.xz
Merge branch 'master' into master
Diffstat (limited to 'src/encryption/Olm.cpp')
-rw-r--r--src/encryption/Olm.cpp171
1 files changed, 95 insertions, 76 deletions
diff --git a/src/encryption/Olm.cpp b/src/encryption/Olm.cpp

index 03d0e983..ea30da4c 100644 --- a/src/encryption/Olm.cpp +++ b/src/encryption/Olm.cpp
@@ -1,11 +1,13 @@ // SPDX-FileCopyrightText: 2021 Nheko Contributors // SPDX-FileCopyrightText: 2022 Nheko Contributors +// SPDX-FileCopyrightText: 2023 Nheko Contributors // // SPDX-License-Identifier: GPL-3.0-or-later #include "Olm.h" #include <QObject> +#include <QRandomGenerator> #include <QTimer> #include <nlohmann/json.hpp> @@ -98,13 +100,19 @@ handle_secret_request(const mtx::events::DeviceEvent<mtx::events::msg::SecretReq return; secretSend.content.secret = secret.value(); - send_encrypted_to_device_messages( - {{local_user.to_string(), {{e->content.requesting_device_id}}}}, secretSend); + // Randomly delay reply to workaround olm session generation races + QTimer::singleShot(QRandomGenerator::global()->bounded(0, 3000), + ChatPage::instance(), + [local_user, e = *e, secretSend] { + send_encrypted_to_device_messages( + {{local_user.to_string(), {{e.content.requesting_device_id}}}}, + secretSend); - nhlog::net()->info("Sent secret '{}' to ({},{})", - e->content.name, - local_user.to_string(), - e->content.requesting_device_id); + nhlog::net()->info("Sent secret '{}' to ({},{})", + e.content.name, + local_user.to_string(), + e.content.requesting_device_id); + }); } void @@ -1144,7 +1152,7 @@ handle_key_request_message(const mtx::events::DeviceEvent<mtx::events::msg::KeyR } bool shouldSeeKeys = false; - uint64_t minimumIndex = -1; + uint32_t minimumIndex = -1; if (sessionData->currently.keys.count(req.sender)) { if (sessionData->currently.keys.at(req.sender) .deviceids.count(req.content.requesting_device_id)) { @@ -1299,78 +1307,83 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s auto our_curve = olm::client()->identity_keys().curve25519; - for (const auto &[user, devices] : targets) { - auto deviceKeys = cache::client()->userKeys(user); + { + auto currentTime = QDateTime::currentSecsSinceEpoch(); + std::vector<std::pair<std::string, mtx::crypto::OlmSessionPtr>> sessionsToPersist; - // no keys for user, query them - if (!deviceKeys) { - keysToQuery[user] = devices; - continue; - } + for (const auto &[user, devices] : targets) { + auto deviceKeys = cache::client()->userKeys(user); - auto deviceTargets = devices; - if (devices.empty()) { - deviceTargets.clear(); - deviceTargets.reserve(deviceKeys->device_keys.size()); - for (const auto &[device, keys] : deviceKeys->device_keys) { - (void)keys; - deviceTargets.push_back(device); + // no keys for user, query them + if (!deviceKeys) { + keysToQuery[user] = devices; + continue; } - } - for (const auto &device : deviceTargets) { - if (!deviceKeys->device_keys.count(device)) { - keysToQuery[user] = {}; - break; + auto deviceTargets = devices; + if (devices.empty()) { + deviceTargets.clear(); + deviceTargets.reserve(deviceKeys->device_keys.size()); + for (const auto &[device, keys] : deviceKeys->device_keys) { + (void)keys; + deviceTargets.push_back(device); + } } - auto d = deviceKeys->device_keys.at(device); + for (const auto &device : deviceTargets) { + if (!deviceKeys->device_keys.count(device)) { + keysToQuery[user] = {}; + break; + } - if (!d.keys.count("curve25519:" + device) || !d.keys.count("ed25519:" + device)) { - nhlog::crypto()->warn("Skipping device {} since it has no keys!", device); - continue; - } + const auto &d = deviceKeys->device_keys.at(device); - auto device_curve = d.keys.at("curve25519:" + device); - if (device_curve == our_curve) { - nhlog::crypto()->warn("Skipping our own device, since sending " - "ourselves olm messages makes no sense."); - continue; - } + if (!d.keys.count("curve25519:" + device) || !d.keys.count("ed25519:" + device)) { + nhlog::crypto()->warn("Skipping device {} since it has no keys!", device); + continue; + } - auto session = cache::getLatestOlmSession(device_curve); - if (!session || force_new_session) { - auto currentTime = QDateTime::currentSecsSinceEpoch(); - if (rateLimit.value(QPair(user, device)) + 60 * 60 * 10 < currentTime) { - claims.one_time_keys[user][device] = mtx::crypto::SIGNED_CURVE25519; - pks[user][device].ed25519 = d.keys.at("ed25519:" + device); - pks[user][device].curve25519 = d.keys.at("curve25519:" + device); + auto device_curve = d.keys.at("curve25519:" + device); + if (device_curve == our_curve) { + nhlog::crypto()->warn("Skipping our own device, since sending " + "ourselves olm messages makes no sense."); + continue; + } - rateLimit.insert(QPair(user, device), currentTime); - } else { - nhlog::crypto()->warn("Not creating new session with {}:{} " - "because of rate limit", - user, - device); + auto session = cache::getLatestOlmSession(device_curve); + if (!session || force_new_session) { + if (rateLimit.value(QPair(user, device)) + 60 * 60 * 10 < currentTime) { + claims.one_time_keys[user][device] = mtx::crypto::SIGNED_CURVE25519; + pks[user][device].ed25519 = d.keys.at("ed25519:" + device); + pks[user][device].curve25519 = d.keys.at("curve25519:" + device); + + rateLimit.insert(QPair(user, device), currentTime); + } else { + nhlog::crypto()->warn("Not creating new session with {}:{} " + "because of rate limit", + user, + device); + } + continue; } - continue; - } - messages[mtx::identifiers::parse<mtx::identifiers::User>(user)][device] = - olm::client() - ->create_olm_encrypted_content(session->get(), - ev_json, - UserId(user), - d.keys.at("ed25519:" + device), - device_curve) - .get<mtx::events::msg::OlmEncrypted>(); + messages[mtx::identifiers::parse<mtx::identifiers::User>(user)][device] = + olm::client() + ->create_olm_encrypted_content(session->get(), + ev_json, + UserId(user), + d.keys.at("ed25519:" + device), + device_curve) + .get<mtx::events::msg::OlmEncrypted>(); + sessionsToPersist.emplace_back(d.keys.at("curve25519:" + device), + std::move(*session)); + } + } + if (!sessionsToPersist.empty()) { try { - nhlog::crypto()->debug("Updated olm session: {}", - mtx::crypto::session_id(session->get())); - cache::saveOlmSession(d.keys.at("curve25519:" + device), - std::move(*session), - QDateTime::currentMSecsSinceEpoch()); + nhlog::crypto()->debug("Updated olm sessions: {}", sessionsToPersist.size()); + cache::client()->saveOlmSessions(std::move(sessionsToPersist), currentTime); } catch (const lmdb::error &e) { nhlog::db()->critical("failed to save outbound olm session: {}", e.what()); } catch (const mtx::crypto::olm_exception &e) { @@ -1395,6 +1408,9 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s mtx::http::RequestErr) { std::map<mtx::identifiers::User, std::map<std::string, mtx::events::msg::OlmEncrypted>> messages; + auto currentTime = QDateTime::currentSecsSinceEpoch(); + std::vector<std::pair<std::string, mtx::crypto::OlmSessionPtr>> sessionsToPersist; + for (const auto &[user_id, retrieved_devices] : res.one_time_keys) { nhlog::net()->debug("claimed keys for {}", user_id); if (retrieved_devices.size() == 0) { @@ -1440,21 +1456,24 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s session.get(), ev_json, UserId(user_id), sign_key, id_key) .get<mtx::events::msg::OlmEncrypted>(); - try { - nhlog::crypto()->debug("Updated olm session: {}", - mtx::crypto::session_id(session.get())); - cache::saveOlmSession( - id_key, std::move(session), QDateTime::currentMSecsSinceEpoch()); - } catch (const lmdb::error &e) { - nhlog::db()->critical("failed to save outbound olm session: {}", e.what()); - } catch (const mtx::crypto::olm_exception &e) { - nhlog::crypto()->critical("failed to pickle outbound olm session: {}", - e.what()); - } + sessionsToPersist.emplace_back(id_key, std::move(session)); } nhlog::net()->info("send_to_device: {}", user_id); } + if (!sessionsToPersist.empty()) { + try { + nhlog::crypto()->debug("Updated (new) olm sessions: {}", + sessionsToPersist.size()); + cache::client()->saveOlmSessions(std::move(sessionsToPersist), currentTime); + } catch (const lmdb::error &e) { + nhlog::db()->critical("failed to save outbound olm session: {}", e.what()); + } catch (const mtx::crypto::olm_exception &e) { + nhlog::crypto()->critical("failed to pickle outbound olm session: {}", + e.what()); + } + } + if (!messages.empty()) http::client()->send_to_device<mtx::events::msg::OlmEncrypted>( http::client()->generate_txn_id(), messages, [](mtx::http::RequestErr err) {