From 9f71b2a79fba7c5d5ce09ebfdd482c8c470203d9 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 28 Jan 2021 21:59:20 +0100 Subject: Remove duplicated file --- lib/room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 6e6d7f11..0c9af2b9 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -12,7 +12,7 @@ #include "avatar.h" #include "connection.h" #include "converters.h" -#include "e2ee.h" +#include "crypto/e2ee.h" #include "syncdata.h" #include "user.h" #include "eventstats.h" -- cgit v1.2.3 From d72f220e3e3a3b243fdafd93d1405f8207dc516a Mon Sep 17 00:00:00 2001 From: Alexey Andreyev Date: Thu, 28 Jan 2021 23:51:56 +0300 Subject: E2EE: initial port to internal olm wrapper Remove qtolm git module. Update CMakeLists.txt. Rename olm to crypto subdir to prevent disambiguation. Rename internal files accordingly. Comment out not ported E2EE API usage. --- lib/room.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 0c9af2b9..d86b2813 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -65,13 +65,12 @@ #include #ifdef Quotient_E2EE_ENABLED -#include // QtOlm -#include // QtOlm -#include // QtOlm +# include "crypto/qolmaccount.h" +# include "crypto/qolmerrors.h" +# include "crypto/qolminboundsession.h" #endif // Quotient_E2EE_ENABLED using namespace Quotient; -using namespace QtOlm; using namespace std::placeholders; using std::move; #if !(defined __GLIBCXX__ && __GLIBCXX__ <= 20150123) @@ -370,23 +369,25 @@ public: // A map from senderKey to a map of sessionId to InboundGroupSession // Not using QMultiHash, because we want to quickly return // a number of relations for a given event without enumerating them. - QHash, InboundGroupSession*> groupSessions; // TODO: + QHash, QOlmInboundGroupSession*> groupSessions; // TODO: // cache bool addInboundGroupSession(QString senderKey, QString sessionId, QString sessionKey) { + // new e2ee TODO: + /* if (groupSessions.contains({ senderKey, sessionId })) { qCDebug(E2EE) << "Inbound Megolm session" << sessionId << "with senderKey" << senderKey << "already exists"; return false; } - InboundGroupSession* megolmSession; + QOlmInboundGroupSession* megolmSession; try { - megolmSession = new InboundGroupSession(sessionKey.toLatin1(), + megolmSession = new QOlmInboundGroupSession(sessionKey.toLatin1(), InboundGroupSession::Init, q); - } catch (OlmError* e) { + } catch (QOlmError* e) { qCDebug(E2EE) << "Unable to create new InboundGroupSession" << e->what(); return false; @@ -398,6 +399,7 @@ public: return false; } groupSessions.insert({ senderKey, sessionId }, megolmSession); + */ return true; } @@ -408,6 +410,8 @@ public: QDateTime timestamp) { std::pair decrypted; + // new e2ee TODO: + /* QPair senderSessionPairKey = qMakePair(senderKey, sessionId); if (!groupSessions.contains(senderSessionPairKey)) { @@ -416,7 +420,7 @@ public: "this message"; return QString(); } - InboundGroupSession* senderSession = + QOlmInboundGroupSession* senderSession = groupSessions.value(senderSessionPairKey); if (!senderSession) { qCDebug(E2EE) << "Unable to decrypt event" << eventId @@ -425,7 +429,7 @@ public: } try { decrypted = senderSession->decrypt(cipher); - } catch (OlmError* e) { + } catch (QOlmError* e) { qCDebug(E2EE) << "Unable to decrypt event" << eventId << "with matching megolm session:" << e->what(); return QString(); @@ -443,6 +447,7 @@ public: return QString(); } } + */ return decrypted.first; } -- cgit v1.2.3 From e9527012622497b0c418df9442180df58401d394 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 15 Feb 2021 18:03:33 +0100 Subject: Apply suggestions from code review Co-authored-by: Nicolas Fella <6377822+nicolasfella@users.noreply.github.com> --- lib/room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index d86b2813..a8a7fe0c 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -65,7 +65,7 @@ #include #ifdef Quotient_E2EE_ENABLED -# include "crypto/qolmaccount.h" +#include "crypto/qolmaccount.h" # include "crypto/qolmerrors.h" # include "crypto/qolminboundsession.h" #endif // Quotient_E2EE_ENABLED -- cgit v1.2.3 From 97f2d162618e7fb2473c184c77875ac9d5e8d1d5 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 15 Feb 2021 18:10:34 +0100 Subject: Apply a few more comments --- lib/room.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index a8a7fe0c..1a7a9911 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -66,8 +66,8 @@ #ifdef Quotient_E2EE_ENABLED #include "crypto/qolmaccount.h" -# include "crypto/qolmerrors.h" -# include "crypto/qolminboundsession.h" +#include "crypto/qolmerrors.h" +#include "crypto/qolminboundsession.h" #endif // Quotient_E2EE_ENABLED using namespace Quotient; -- cgit v1.2.3 From c408b460bea2010c6745e03c549e136d6b1d9ec6 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Wed, 19 May 2021 00:35:53 +0200 Subject: Start tracking user's devices when a a room starts being encrypted --- lib/room.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 1a7a9911..b6022f1b 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -475,6 +475,9 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) emit baseStateLoaded(); return this == r; // loadedRoomState fires only once per room }); + connectSingleShot(this, &Room::encryption, this, [=](){ + connection->newEncryptedRoom(this); + }); qCDebug(STATE) << "New" << terse << initialJoinState << "Room:" << id; } -- cgit v1.2.3 From f451813f21a76e8c011bbd27f4ded1d31044a572 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Wed, 19 May 2021 22:25:50 +0200 Subject: Update tracked users list when new user joins encrypted room --- lib/room.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index b6022f1b..2707842c 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -476,7 +476,12 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) return this == r; // loadedRoomState fires only once per room }); connectSingleShot(this, &Room::encryption, this, [=](){ - connection->newEncryptedRoom(this); + connection->encryptionUpdate(this); + }); + connect(this, &Room::userAdded, this, [=](){ + if(usesEncryption()) { + connection->encryptionUpdate(this); + } }); qCDebug(STATE) << "New" << terse << initialJoinState << "Room:" << id; } -- cgit v1.2.3 From 0ec4df82265c2f796035c0c103b9f6693f62e24a Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 10 Jun 2021 23:57:15 +0200 Subject: Fix setting encrypted flag in rooms --- lib/room.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 2707842c..3a894b9b 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1913,7 +1913,6 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent) return; } it->setDeparted(); - qCDebug(EVENTS) << "Event txn" << txnId << "has departed"; emit q->pendingEventChanged(int(it - unsyncedEvents.begin())); }); Room::connect(call, &BaseJob::failure, q, -- cgit v1.2.3 From a30d457161fcaadfe944e4411d4b0e487e856178 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 31 Aug 2021 00:48:23 +0200 Subject: Fix build without E2EE --- lib/room.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 3a894b9b..57914db4 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -475,6 +475,7 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) emit baseStateLoaded(); return this == r; // loadedRoomState fires only once per room }); +#ifdef Quotient_E2EE_ENABLED connectSingleShot(this, &Room::encryption, this, [=](){ connection->encryptionUpdate(this); }); @@ -483,6 +484,7 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) connection->encryptionUpdate(this); } }); +#endif qCDebug(STATE) << "New" << terse << initialJoinState << "Room:" << id; } -- cgit v1.2.3 From 703b3f89ef54d9d40c9117788d0920b6b745bd62 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 12 Jun 2021 23:04:17 +0200 Subject: Implement (meg)olm key caching, megolm decrypting, EncryptedEvent decryption, handling of encrypted redactions and replies --- lib/room.cpp | 195 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 141 insertions(+), 54 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 57914db4..5fedd861 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -369,37 +369,95 @@ public: // A map from senderKey to a map of sessionId to InboundGroupSession // Not using QMultiHash, because we want to quickly return // a number of relations for a given event without enumerating them. - QHash, QOlmInboundGroupSession*> groupSessions; // TODO: - // cache + std::map, std::unique_ptr> groupSessions; + + void loadMegOlmSessions() { + QFile file { connection->stateCacheDir().filePath("megolmsessions.json") }; + if(!file.exists() || !file.open(QIODevice::ReadOnly)) { + qCDebug(E2EE) << "No megolm sessions cache exists."; + return; + } + auto data = file.readAll(); + const auto json = data.startsWith('{') + ? QJsonDocument::fromJson(data).object() +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + : QCborValue::fromCbor(data).toJsonValue().toObject() +#else + : QJsonDocument::fromBinaryData(data).object() +#endif + ; + if (json.isEmpty()) { + qCWarning(MAIN) << "Megolm sessions cache is empty"; + return; + } + for(const auto &s : json["sessions"].toArray()) { + auto pickle = s.toObject()["pickle"].toString().toLatin1(); + auto senderKey = s.toObject()["sender_key"].toString(); + auto sessionId = s.toObject()["session_id"].toString(); + auto sessionResult = QOlmInboundGroupSession::unpickle(pickle, Unencrypted{}); + if(std::holds_alternative(sessionResult)) { + qCWarning(E2EE) << "Failed to unpickle olm session"; + continue; + } + groupSessions[qMakePair(senderKey, sessionId)] = std::move(std::get>(sessionResult)); + } + } + void saveMegOlmSessions() { + QFile outFile { connection->stateCacheDir().filePath("megolmsessions.json") }; + if (!outFile.open(QFile::WriteOnly)) { + qCWarning(E2EE) << "Error opening" << outFile.fileName() << ":" + << outFile.errorString(); + qCWarning(E2EE) << "Failed to write megolm sessions"; + return; + } + + QJsonObject rootObj { + { QStringLiteral("cache_version"), + QJsonObject { + { QStringLiteral("major"), 1 }, + { QStringLiteral("minor"), 0 } } } + }; + { + QJsonArray sessionsJson; + for (const auto &session : groupSessions) { + auto pickleResult = session.second->pickle(Unencrypted{}); + sessionsJson += QJsonObject { + {QStringLiteral("sender_key"), session.first.first}, + {QStringLiteral("session_id"), session.first.second}, + {QStringLiteral("pickle"), QString(pickleResult)} + }; + } + rootObj.insert(QStringLiteral("sessions"), sessionsJson); + } + +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + const auto data = QJsonDocument(rootObj).toJson(QJsonDocument::Compact); +#else + QJsonDocument json { rootObj }; + const auto data = json.toJson(QJsonDocument::Compact); +#endif + + outFile.write(data.data(), data.size()); + qCDebug(E2EE) << "Megolm sessions saved to" << outFile.fileName(); + } bool addInboundGroupSession(QString senderKey, QString sessionId, QString sessionKey) { - // new e2ee TODO: - /* - if (groupSessions.contains({ senderKey, sessionId })) { - qCDebug(E2EE) << "Inbound Megolm session" << sessionId + if (groupSessions.find(qMakePair(senderKey, sessionId)) != groupSessions.end()) { + qCWarning(E2EE) << "Inbound Megolm session" << sessionId << "with senderKey" << senderKey << "already exists"; return false; } - QOlmInboundGroupSession* megolmSession; - try { - megolmSession = new QOlmInboundGroupSession(sessionKey.toLatin1(), - InboundGroupSession::Init, - q); - } catch (QOlmError* e) { - qCDebug(E2EE) << "Unable to create new InboundGroupSession" - << e->what(); + std::unique_ptr megolmSession = QOlmInboundGroupSession::create(sessionKey.toLatin1()); + if (megolmSession->sessionId() != sessionId) { + qCWarning(E2EE) << "Session ID mismatch in m.room_key event sent " + "from sender with key" << senderKey; return false; } - if (megolmSession->id() != sessionId) { - qCDebug(E2EE) << "Session ID mismatch in m.room_key event sent " - "from sender with key" - << senderKey; - return false; - } - groupSessions.insert({ senderKey, sessionId }, megolmSession); - */ + qCWarning(E2EE) << "Adding inbound session"; + groupSessions[qMakePair(senderKey, sessionId)] = std::move(megolmSession); + saveMegOlmSessions(); return true; } @@ -409,46 +467,33 @@ public: const QString& eventId, QDateTime timestamp) { - std::pair decrypted; - // new e2ee TODO: - /* QPair senderSessionPairKey = qMakePair(senderKey, sessionId); - if (!groupSessions.contains(senderSessionPairKey)) { - qCDebug(E2EE) << "Unable to decrypt event" << eventId + if (groupSessions.find(senderSessionPairKey) == groupSessions.end()) { + qCWarning(E2EE) << "Unable to decrypt event" << eventId << "The sender's device has not sent us the keys for " "this message"; return QString(); } - QOlmInboundGroupSession* senderSession = - groupSessions.value(senderSessionPairKey); - if (!senderSession) { - qCDebug(E2EE) << "Unable to decrypt event" << eventId - << "senderSessionPairKey:" << senderSessionPairKey; + auto& senderSession = groupSessions[senderSessionPairKey]; + auto decryptResult = senderSession->decrypt(cipher); + if(std::holds_alternative(decryptResult)) { + qCWarning(E2EE) << "Unable to decrypt event" << eventId + << "with matching megolm session:" << std::get(decryptResult); return QString(); } - try { - decrypted = senderSession->decrypt(cipher); - } catch (QOlmError* e) { - qCDebug(E2EE) << "Unable to decrypt event" << eventId - << "with matching megolm session:" << e->what(); - return QString(); - } - QPair properties = groupSessionIndexRecord.value( - qMakePair(senderSession->id(), decrypted.second)); + std::pair decrypted = std::get>(decryptResult); + QPair properties = groupSessionIndexRecord.value(qMakePair(senderSession->sessionId(), decrypted.second)); if (properties.first.isEmpty()) { - groupSessionIndexRecord.insert(qMakePair(senderSession->id(), - decrypted.second), - qMakePair(eventId, timestamp)); + groupSessionIndexRecord.insert(qMakePair(senderSession->sessionId(), decrypted.second), qMakePair(eventId, timestamp)); } else { - if ((properties.first != eventId) - || (properties.second != timestamp)) { - qCDebug(E2EE) << "Detected a replay attack on event" << eventId; + if ((properties.first != eventId) || (properties.second != timestamp)) { + qCWarning(E2EE) << "Detected a replay attack on event" << eventId; return QString(); } } - */ - + //TODO is this necessary? + saveMegOlmSessions(); return decrypted.first; } #endif // Quotient_E2EE_ENABLED @@ -475,6 +520,7 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) emit baseStateLoaded(); return this == r; // loadedRoomState fires only once per room }); + qCDebug(STATE) << "New" << initialJoinState << "Room:" << id; #ifdef Quotient_E2EE_ENABLED connectSingleShot(this, &Room::encryption, this, [=](){ connection->encryptionUpdate(this); @@ -484,6 +530,7 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) connection->encryptionUpdate(this); } }); + d->loadMegOlmSessions(); #endif qCDebug(STATE) << "New" << terse << initialJoinState << "Room:" << id; } @@ -1504,13 +1551,29 @@ RoomEventPtr Room::decryptMessage(const EncryptedEvent& encryptedEvent) encryptedEvent.sessionId(), encryptedEvent.id(), encryptedEvent.originTimestamp()); if (decrypted.isEmpty()) { + qCWarning(E2EE) << "Encrypted message is empty"; return {}; } - return makeEvent( - QJsonDocument::fromJson(decrypted.toUtf8()).object()); + QJsonObject eventObject = QJsonDocument::fromJson(decrypted.toUtf8()).object(); + eventObject["event_id"] = encryptedEvent.id(); + eventObject["sender"] = encryptedEvent.senderId(); + eventObject["origin_server_ts"] = encryptedEvent.originTimestamp().toMSecsSinceEpoch(); + if(encryptedEvent.contentJson().contains("m.relates_to")) { + auto relates = encryptedEvent.contentJson()["m.relates_to"].toObject(); + auto content = eventObject["content"].toObject(); + content["m.relates_to"] = relates; + eventObject["content"] = content; + } + if(encryptedEvent.unsignedJson().contains("redacts")) { + auto redacts = encryptedEvent.unsignedJson()["redacts"].toString(); + auto unsign = eventObject["unsigned"].toObject(); + unsign["redacts"] = redacts; + eventObject["unsigned"] = unsign; + } + return makeEvent(eventObject); } qCDebug(E2EE) << "Algorithm of the encrypted event with id" - << encryptedEvent.id() << "is not for the current device"; + << encryptedEvent.id() << "is not decryptable by the current device"; return {}; #endif // Quotient_E2EE_ENABLED } @@ -1529,8 +1592,8 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, } if (d->addInboundGroupSession(senderKey, roomKeyEvent.sessionId(), roomKeyEvent.sessionKey())) { - qCDebug(E2EE) << "added new inboundGroupSession:" - << d->groupSessions.count(); + qCWarning(E2EE) << "added new inboundGroupSession:" + << d->groupSessions.size(); } #endif // Quotient_E2EE_ENABLED } @@ -2590,6 +2653,18 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) QElapsedTimer et; et.start(); + + //TODO should this be done before dropDuplicateEvents? + for(long unsigned int i = 0; i < events.size(); i++) { + if(auto* encrypted = eventCast(events[i])) { + qDebug() << "Encrypted Event"; + auto decrypted = q->decryptMessage(*encrypted); + if(decrypted) { + events[i] = std::move(decrypted); + } + } + } + { // Pre-process redactions and edits so that events that get // redacted/replaced in the same batch landed in the timeline already @@ -2742,6 +2817,18 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) return; Changes changes {}; + + //TODO should this be done before dropDuplicateEvents? + for(long unsigned int i = 0; i < events.size(); i++) { + if(auto* encrypted = eventCast(events[i])) { + qDebug() << "Encrypted Event"; + auto decrypted = q->decryptMessage(*encrypted); + if(decrypted) { + events[i] = std::move(decrypted); + } + } + } + // In case of lazy-loading new members may be loaded with historical // messages. Also, the cache doesn't store events with empty content; // so when such events show up in the timeline they should be properly -- cgit v1.2.3 From 244938d2c99674ba09f3c1f92b2a4f8507ac5e58 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 17 Aug 2021 20:51:29 +0200 Subject: Various fixes --- lib/room.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 5fedd861..a1354fc5 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -372,7 +372,7 @@ public: std::map, std::unique_ptr> groupSessions; void loadMegOlmSessions() { - QFile file { connection->stateCacheDir().filePath("megolmsessions.json") }; + QFile file { connection->stateCacheDir().filePath(QStringLiteral("megolm/%1.json").arg(id)) }; if(!file.exists() || !file.open(QIODevice::ReadOnly)) { qCDebug(E2EE) << "No megolm sessions cache exists."; return; @@ -387,7 +387,7 @@ public: #endif ; if (json.isEmpty()) { - qCWarning(MAIN) << "Megolm sessions cache is empty"; + qCWarning(E2EE) << "Megolm sessions cache is empty"; return; } for(const auto &s : json["sessions"].toArray()) { @@ -403,7 +403,8 @@ public: } } void saveMegOlmSessions() { - QFile outFile { connection->stateCacheDir().filePath("megolmsessions.json") }; + connection->stateCacheDir().mkdir("megolm"); + QFile outFile { connection->stateCacheDir().filePath(QStringLiteral("megolm/%1.json").arg(id))}; if (!outFile.open(QFile::WriteOnly)) { qCWarning(E2EE) << "Error opening" << outFile.fileName() << ":" << outFile.errorString(); @@ -521,6 +522,7 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) return this == r; // loadedRoomState fires only once per room }); qCDebug(STATE) << "New" << initialJoinState << "Room:" << id; + #ifdef Quotient_E2EE_ENABLED connectSingleShot(this, &Room::encryption, this, [=](){ connection->encryptionUpdate(this); -- cgit v1.2.3 From 0583534d83f902235b46ef6761d6698ddb6e6aba Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Wed, 18 Aug 2021 02:00:15 +0200 Subject: Store pickling key in qtkeychain and pickle encrypted --- lib/room.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index a1354fc5..b60a23f2 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -394,7 +394,7 @@ public: auto pickle = s.toObject()["pickle"].toString().toLatin1(); auto senderKey = s.toObject()["sender_key"].toString(); auto sessionId = s.toObject()["session_id"].toString(); - auto sessionResult = QOlmInboundGroupSession::unpickle(pickle, Unencrypted{}); + auto sessionResult = QOlmInboundGroupSession::unpickle(pickle, connection->picklingMode()); if(std::holds_alternative(sessionResult)) { qCWarning(E2EE) << "Failed to unpickle olm session"; continue; @@ -421,7 +421,7 @@ public: { QJsonArray sessionsJson; for (const auto &session : groupSessions) { - auto pickleResult = session.second->pickle(Unencrypted{}); + auto pickleResult = session.second->pickle(connection->picklingMode()); sessionsJson += QJsonObject { {QStringLiteral("sender_key"), session.first.first}, {QStringLiteral("session_id"), session.first.second}, @@ -2659,7 +2659,6 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) //TODO should this be done before dropDuplicateEvents? for(long unsigned int i = 0; i < events.size(); i++) { if(auto* encrypted = eventCast(events[i])) { - qDebug() << "Encrypted Event"; auto decrypted = q->decryptMessage(*encrypted); if(decrypted) { events[i] = std::move(decrypted); -- cgit v1.2.3 From 77a13cfdace5cb27adb52b3a644a155aee522b12 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 28 Aug 2021 01:03:49 +0200 Subject: Implement download and decryption of encrypted files --- lib/room.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index b60a23f2..a4dfcb8f 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2426,6 +2426,65 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename) d->failedTransfer(eventId); } +#ifdef Quotient_E2EE_ENABLED +void Room::downloadFile(const QString& eventId, const QString& key, const QString& iv, const QString& sha256, const QUrl& localFilename) +{ + if (auto ongoingTransfer = d->fileTransfers.constFind(eventId); + ongoingTransfer != d->fileTransfers.cend() + && ongoingTransfer->status == FileTransferInfo::Started) { + qCWarning(MAIN) << "Transfer for" << eventId + << "is ongoing; download won't start"; + return; + } + + Q_ASSERT_X(localFilename.isEmpty() || localFilename.isLocalFile(), + __FUNCTION__, "localFilename should point at a local file"); + const auto* event = d->getEventWithFile(eventId); + if (!event) { + qCCritical(MAIN) + << eventId << "is not in the local timeline or has no file content"; + Q_ASSERT(false); + return; + } + if (!event->contentJson().contains(QStringLiteral("file"))) { + qCWarning(MAIN) << "Event" << eventId + << "has an empty or malformed mxc URL; won't download"; + return; + } + const auto fileUrl = QUrl(event->contentJson()["file"]["url"].toString()); + auto filePath = localFilename.toLocalFile(); + if (filePath.isEmpty()) { // Setup default file path + filePath = + fileUrl.path().mid(1) % '_' % d->fileNameToDownload(event); + + if (filePath.size() > 200) // If too long, elide in the middle + filePath.replace(128, filePath.size() - 192, "---"); + + filePath = QDir::tempPath() % '/' % filePath; + qDebug(MAIN) << "File path:" << filePath; + } + auto job = connection()->downloadFile(fileUrl, key, iv, sha256, filePath); + if (isJobPending(job)) { + // If there was a previous transfer (completed or failed), overwrite it. + d->fileTransfers[eventId] = { job, job->targetFileName() }; + connect(job, &BaseJob::downloadProgress, this, + [this, eventId](qint64 received, qint64 total) { + d->fileTransfers[eventId].update(received, total); + emit fileTransferProgress(eventId, received, total); + }); + connect(job, &BaseJob::success, this, [this, eventId, fileUrl, job] { + d->fileTransfers[eventId].status = FileTransferInfo::Completed; + emit fileTransferCompleted( + eventId, fileUrl, QUrl::fromLocalFile(job->targetFileName())); + }); + connect(job, &BaseJob::failure, this, + std::bind(&Private::failedTransfer, d, eventId, + job->errorString())); + } else + d->failedTransfer(eventId); +} +#endif + void Room::cancelFileTransfer(const QString& id) { const auto it = d->fileTransfers.find(id); -- cgit v1.2.3 From b35a736da2b09fe5cc0091f9fbd370d057503a54 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Mon, 30 Aug 2021 00:53:29 +0200 Subject: Handle encrypted file download through existing API --- lib/room.cpp | 67 ++++++++---------------------------------------------------- 1 file changed, 9 insertions(+), 58 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index a4dfcb8f..d7ebe021 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2405,65 +2405,17 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename) filePath = QDir::tempPath() % '/' % filePath; qDebug(MAIN) << "File path:" << filePath; } - auto job = connection()->downloadFile(fileUrl, filePath); - if (isJobPending(job)) { - // If there was a previous transfer (completed or failed), overwrite it. - d->fileTransfers[eventId] = { job, job->targetFileName() }; - connect(job, &BaseJob::downloadProgress, this, - [this, eventId](qint64 received, qint64 total) { - d->fileTransfers[eventId].update(received, total); - emit fileTransferProgress(eventId, received, total); - }); - connect(job, &BaseJob::success, this, [this, eventId, fileUrl, job] { - d->fileTransfers[eventId].status = FileTransferInfo::Completed; - emit fileTransferCompleted( - eventId, fileUrl, QUrl::fromLocalFile(job->targetFileName())); - }); - connect(job, &BaseJob::failure, this, - std::bind(&Private::failedTransfer, d, eventId, - job->errorString())); - } else - d->failedTransfer(eventId); -} - + DownloadFileJob *job = nullptr; +#ifdef Quotient_E2EE_ENABLED + if(fileInfo->file.has_value()) { + auto file = *fileInfo->file; + job = connection()->downloadFile(fileUrl, file.key.k, file.iv, file.hashes["sha256"], filePath); + } else { +#endif + job = connection()->downloadFile(fileUrl, filePath); #ifdef Quotient_E2EE_ENABLED -void Room::downloadFile(const QString& eventId, const QString& key, const QString& iv, const QString& sha256, const QUrl& localFilename) -{ - if (auto ongoingTransfer = d->fileTransfers.constFind(eventId); - ongoingTransfer != d->fileTransfers.cend() - && ongoingTransfer->status == FileTransferInfo::Started) { - qCWarning(MAIN) << "Transfer for" << eventId - << "is ongoing; download won't start"; - return; - } - - Q_ASSERT_X(localFilename.isEmpty() || localFilename.isLocalFile(), - __FUNCTION__, "localFilename should point at a local file"); - const auto* event = d->getEventWithFile(eventId); - if (!event) { - qCCritical(MAIN) - << eventId << "is not in the local timeline or has no file content"; - Q_ASSERT(false); - return; - } - if (!event->contentJson().contains(QStringLiteral("file"))) { - qCWarning(MAIN) << "Event" << eventId - << "has an empty or malformed mxc URL; won't download"; - return; - } - const auto fileUrl = QUrl(event->contentJson()["file"]["url"].toString()); - auto filePath = localFilename.toLocalFile(); - if (filePath.isEmpty()) { // Setup default file path - filePath = - fileUrl.path().mid(1) % '_' % d->fileNameToDownload(event); - - if (filePath.size() > 200) // If too long, elide in the middle - filePath.replace(128, filePath.size() - 192, "---"); - - filePath = QDir::tempPath() % '/' % filePath; - qDebug(MAIN) << "File path:" << filePath; } - auto job = connection()->downloadFile(fileUrl, key, iv, sha256, filePath); +#endif if (isJobPending(job)) { // If there was a previous transfer (completed or failed), overwrite it. d->fileTransfers[eventId] = { job, job->targetFileName() }; @@ -2483,7 +2435,6 @@ void Room::downloadFile(const QString& eventId, const QString& key, const QStrin } else d->failedTransfer(eventId); } -#endif void Room::cancelFileTransfer(const QString& id) { -- cgit v1.2.3 From 8636c7028b45ee8de3125bcf4df40ad60ed949a0 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 31 Aug 2021 00:09:59 +0200 Subject: Add mxc protocol to the networkaccessmanager --- lib/room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index d7ebe021..688ba5d4 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2409,7 +2409,7 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename) #ifdef Quotient_E2EE_ENABLED if(fileInfo->file.has_value()) { auto file = *fileInfo->file; - job = connection()->downloadFile(fileUrl, file.key.k, file.iv, file.hashes["sha256"], filePath); + job = connection()->downloadFile(fileUrl, file, filePath); } else { #endif job = connection()->downloadFile(fileUrl, filePath); -- cgit v1.2.3 From 82cffec29937e4449a75040485d5188f429b7b1e Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Wed, 10 Nov 2021 16:29:11 +0100 Subject: Try decrypting existing messages when a new key is added --- lib/room.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 688ba5d4..6c5a9d33 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1596,6 +1596,14 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, roomKeyEvent.sessionKey())) { qCWarning(E2EE) << "added new inboundGroupSession:" << d->groupSessions.size(); + for (unsigned long int i = 0; i < d->timeline.size(); i++) { + if (auto encryptedEvent = d->timeline[i].viewAs()) { + auto decrypted = decryptMessage(*encryptedEvent); + if(decrypted) { + d->timeline[i].replaceEvent(std::move(decrypted)); + } + } + } } #endif // Quotient_E2EE_ENABLED } -- cgit v1.2.3 From 34db4fd1294e41765a5db58ee1a0c59712af62c6 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Mon, 15 Nov 2021 21:26:47 +0100 Subject: Various improvements and fixes --- lib/room.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 6c5a9d33..94f0c9eb 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1600,7 +1600,9 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, if (auto encryptedEvent = d->timeline[i].viewAs()) { auto decrypted = decryptMessage(*encryptedEvent); if(decrypted) { - d->timeline[i].replaceEvent(std::move(decrypted)); + qWarning() << "decrypted" << decrypted->fullJson(); + auto oldEvent = d->timeline[i].replaceEvent(std::move(decrypted)); + emit replacedEvent(d->timeline[i].event(), rawPtr(oldEvent)); } } } -- cgit v1.2.3 From 06facdb1179e2e6789d7263541294fb427f649e5 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Mon, 15 Nov 2021 21:57:59 +0100 Subject: Move non-cache data to a non-cache location --- lib/room.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 94f0c9eb..963b9f88 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -372,7 +372,7 @@ public: std::map, std::unique_ptr> groupSessions; void loadMegOlmSessions() { - QFile file { connection->stateCacheDir().filePath(QStringLiteral("megolm/%1.json").arg(id)) }; + QFile file { connection->e2eeDataDir() + QStringLiteral("/%1.json").arg(id) }; if(!file.exists() || !file.open(QIODevice::ReadOnly)) { qCDebug(E2EE) << "No megolm sessions cache exists."; return; @@ -403,8 +403,7 @@ public: } } void saveMegOlmSessions() { - connection->stateCacheDir().mkdir("megolm"); - QFile outFile { connection->stateCacheDir().filePath(QStringLiteral("megolm/%1.json").arg(id))}; + QFile outFile { connection->e2eeDataDir() + QStringLiteral("/%1.json").arg(id)}; if (!outFile.open(QFile::WriteOnly)) { qCWarning(E2EE) << "Error opening" << outFile.fileName() << ":" << outFile.errorString(); -- cgit v1.2.3 From 15e75b20d5bb9339a8b769b717db00fb5c16b050 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 16 Nov 2021 23:23:26 +0100 Subject: Add function to decrypt notifications --- lib/room.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 963b9f88..d755f8eb 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1599,7 +1599,6 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, if (auto encryptedEvent = d->timeline[i].viewAs()) { auto decrypted = decryptMessage(*encryptedEvent); if(decrypted) { - qWarning() << "decrypted" << decrypted->fullJson(); auto oldEvent = d->timeline[i].replaceEvent(std::move(decrypted)); emit replacedEvent(d->timeline[i].event(), rawPtr(oldEvent)); } -- cgit v1.2.3 From 877591582f07b5c5c104370e80c858b951c0757f Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 20 Nov 2021 16:58:40 +0100 Subject: Use UnorderedMap instead of std::map --- lib/room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index d755f8eb..65ce82ac 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -369,7 +369,7 @@ public: // A map from senderKey to a map of sessionId to InboundGroupSession // Not using QMultiHash, because we want to quickly return // a number of relations for a given event without enumerating them. - std::map, std::unique_ptr> groupSessions; + UnorderedMap, std::unique_ptr> groupSessions; void loadMegOlmSessions() { QFile file { connection->e2eeDataDir() + QStringLiteral("/%1.json").arg(id) }; -- cgit v1.2.3 From e99802772ebab9802e2f35d83ce1de9f83691d90 Mon Sep 17 00:00:00 2001 From: Tobias Fella <9750016+TobiasFella@users.noreply.github.com> Date: Sat, 27 Nov 2021 00:11:36 +0100 Subject: Apply suggestions from code review Co-authored-by: Alexey Rusakov --- lib/room.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 65ce82ac..fca1912f 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -456,7 +456,7 @@ public: return false; } qCWarning(E2EE) << "Adding inbound session"; - groupSessions[qMakePair(senderKey, sessionId)] = std::move(megolmSession); + groupSessions[{senderKey, sessionId}] = std::move(megolmSession); saveMegOlmSessions(); return true; } @@ -469,13 +469,14 @@ public: { QPair senderSessionPairKey = qMakePair(senderKey, sessionId); - if (groupSessions.find(senderSessionPairKey) == groupSessions.end()) { + auto groupSessionIt = groupSessions.find(senderSessionPairKey); + if (groupSessionIt == groupSessions.end()) { qCWarning(E2EE) << "Unable to decrypt event" << eventId << "The sender's device has not sent us the keys for " "this message"; return QString(); } - auto& senderSession = groupSessions[senderSessionPairKey]; + auto& senderSession = *groupSessionIt; auto decryptResult = senderSession->decrypt(cipher); if(std::holds_alternative(decryptResult)) { qCWarning(E2EE) << "Unable to decrypt event" << eventId @@ -520,8 +521,6 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) emit baseStateLoaded(); return this == r; // loadedRoomState fires only once per room }); - qCDebug(STATE) << "New" << initialJoinState << "Room:" << id; - #ifdef Quotient_E2EE_ENABLED connectSingleShot(this, &Room::encryption, this, [=](){ connection->encryptionUpdate(this); @@ -1555,7 +1554,7 @@ RoomEventPtr Room::decryptMessage(const EncryptedEvent& encryptedEvent) qCWarning(E2EE) << "Encrypted message is empty"; return {}; } - QJsonObject eventObject = QJsonDocument::fromJson(decrypted.toUtf8()).object(); + auto eventObject = QJsonDocument::fromJson(decrypted.toUtf8()).object(); eventObject["event_id"] = encryptedEvent.id(); eventObject["sender"] = encryptedEvent.senderId(); eventObject["origin_server_ts"] = encryptedEvent.originTimestamp().toMSecsSinceEpoch(); -- cgit v1.2.3 From 8020505eb582479cf62d0157fe866f63a888f1a9 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 27 Nov 2021 00:52:24 +0100 Subject: Apply more suggestions --- lib/room.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index fca1912f..e143747b 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -430,12 +430,7 @@ public: rootObj.insert(QStringLiteral("sessions"), sessionsJson); } -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) const auto data = QJsonDocument(rootObj).toJson(QJsonDocument::Compact); -#else - QJsonDocument json { rootObj }; - const auto data = json.toJson(QJsonDocument::Compact); -#endif outFile.write(data.data(), data.size()); qCDebug(E2EE) << "Megolm sessions saved to" << outFile.fileName(); @@ -476,26 +471,26 @@ public: "this message"; return QString(); } - auto& senderSession = *groupSessionIt; + auto& senderSession = groupSessionIt->second; auto decryptResult = senderSession->decrypt(cipher); if(std::holds_alternative(decryptResult)) { qCWarning(E2EE) << "Unable to decrypt event" << eventId << "with matching megolm session:" << std::get(decryptResult); return QString(); } - std::pair decrypted = std::get>(decryptResult); - QPair properties = groupSessionIndexRecord.value(qMakePair(senderSession->sessionId(), decrypted.second)); - if (properties.first.isEmpty()) { - groupSessionIndexRecord.insert(qMakePair(senderSession->sessionId(), decrypted.second), qMakePair(eventId, timestamp)); + const auto& [content, index] = std::get>(decryptResult); + const auto& [recordEventId, ts] = groupSessionIndexRecord.value({senderSession->sessionId(), index}); + if (eventId.isEmpty()) { + groupSessionIndexRecord.insert({senderSession->sessionId(), index}, {recordEventId, timestamp}); } else { - if ((properties.first != eventId) || (properties.second != timestamp)) { + if ((eventId != recordEventId) || (ts != timestamp)) { qCWarning(E2EE) << "Detected a replay attack on event" << eventId; return QString(); } } //TODO is this necessary? saveMegOlmSessions(); - return decrypted.first; + return content; } #endif // Quotient_E2EE_ENABLED @@ -2673,7 +2668,6 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) QElapsedTimer et; et.start(); - //TODO should this be done before dropDuplicateEvents? for(long unsigned int i = 0; i < events.size(); i++) { if(auto* encrypted = eventCast(events[i])) { auto decrypted = q->decryptMessage(*encrypted); @@ -2836,7 +2830,6 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) Changes changes {}; - //TODO should this be done before dropDuplicateEvents? for(long unsigned int i = 0; i < events.size(); i++) { if(auto* encrypted = eventCast(events[i])) { qDebug() << "Encrypted Event"; -- cgit v1.2.3 From 3128df9daa196b2cf3cdb8e029e22d79c397ff66 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 27 Nov 2021 01:34:44 +0100 Subject: Apply even more suggestions --- lib/room.cpp | 53 +++++++++++++++++------------------------------------ 1 file changed, 17 insertions(+), 36 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index e143747b..07ffd0cd 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -366,9 +366,7 @@ public: // A map from to QHash, QPair> groupSessionIndexRecord; // TODO: cache - // A map from senderKey to a map of sessionId to InboundGroupSession - // Not using QMultiHash, because we want to quickly return - // a number of relations for a given event without enumerating them. + // A map from (senderKey, sessionId) to InboundGroupSession UnorderedMap, std::unique_ptr> groupSessions; void loadMegOlmSessions() { @@ -399,7 +397,7 @@ public: qCWarning(E2EE) << "Failed to unpickle olm session"; continue; } - groupSessions[qMakePair(senderKey, sessionId)] = std::move(std::get>(sessionResult)); + groupSessions[{senderKey, sessionId}] = std::move(std::get>(sessionResult)); } } void saveMegOlmSessions() { @@ -438,7 +436,7 @@ public: bool addInboundGroupSession(QString senderKey, QString sessionId, QString sessionKey) { - if (groupSessions.find(qMakePair(senderKey, sessionId)) != groupSessions.end()) { + if (groupSessions.find({senderKey, sessionId}) != groupSessions.end()) { qCWarning(E2EE) << "Inbound Megolm session" << sessionId << "with senderKey" << senderKey << "already exists"; return false; @@ -462,8 +460,7 @@ public: const QString& eventId, QDateTime timestamp) { - QPair senderSessionPairKey = - qMakePair(senderKey, sessionId); + const auto senderSessionPairKey = qMakePair(senderKey, sessionId); auto groupSessionIt = groupSessions.find(senderSessionPairKey); if (groupSessionIt == groupSessions.end()) { qCWarning(E2EE) << "Unable to decrypt event" << eventId @@ -1540,36 +1537,20 @@ RoomEventPtr Room::decryptMessage(const EncryptedEvent& encryptedEvent) qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off."; return {}; #else // Quotient_E2EE_ENABLED - if (encryptedEvent.algorithm() == MegolmV1AesSha2AlgoKey) { - QString decrypted = d->groupSessionDecryptMessage( - encryptedEvent.ciphertext(), encryptedEvent.senderKey(), - encryptedEvent.sessionId(), encryptedEvent.id(), - encryptedEvent.originTimestamp()); - if (decrypted.isEmpty()) { - qCWarning(E2EE) << "Encrypted message is empty"; - return {}; - } - auto eventObject = QJsonDocument::fromJson(decrypted.toUtf8()).object(); - eventObject["event_id"] = encryptedEvent.id(); - eventObject["sender"] = encryptedEvent.senderId(); - eventObject["origin_server_ts"] = encryptedEvent.originTimestamp().toMSecsSinceEpoch(); - if(encryptedEvent.contentJson().contains("m.relates_to")) { - auto relates = encryptedEvent.contentJson()["m.relates_to"].toObject(); - auto content = eventObject["content"].toObject(); - content["m.relates_to"] = relates; - eventObject["content"] = content; - } - if(encryptedEvent.unsignedJson().contains("redacts")) { - auto redacts = encryptedEvent.unsignedJson()["redacts"].toString(); - auto unsign = eventObject["unsigned"].toObject(); - unsign["redacts"] = redacts; - eventObject["unsigned"] = unsign; - } - return makeEvent(eventObject); + if (encryptedEvent.algorithm() != MegolmV1AesSha2AlgoKey) { + qWarning(E2EE) << "Algorithm of the encrypted event with id" + << encryptedEvent.id() << "is not decryptable by the current device"; + return {}; } - qCDebug(E2EE) << "Algorithm of the encrypted event with id" - << encryptedEvent.id() << "is not decryptable by the current device"; - return {}; + QString decrypted = d->groupSessionDecryptMessage( + encryptedEvent.ciphertext(), encryptedEvent.senderKey(), + encryptedEvent.sessionId(), encryptedEvent.id(), + encryptedEvent.originTimestamp()); + if (decrypted.isEmpty()) { + qCWarning(E2EE) << "Encrypted message is empty"; + return {}; + } + return encryptedEvent.createDecrypted(decrypted); #endif // Quotient_E2EE_ENABLED } -- cgit v1.2.3 From dcc4556a761f96ae6c71115bf6297feca32581bf Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 27 Nov 2021 01:58:02 +0100 Subject: More improvements --- lib/room.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 07ffd0cd..e4fe2fb8 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -514,10 +514,10 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) return this == r; // loadedRoomState fires only once per room }); #ifdef Quotient_E2EE_ENABLED - connectSingleShot(this, &Room::encryption, this, [=](){ + connectSingleShot(this, &Room::encryption, this, [this, connection](){ connection->encryptionUpdate(this); }); - connect(this, &Room::userAdded, this, [=](){ + connect(this, &Room::userAdded, this, [this, connection](){ if(usesEncryption()) { connection->encryptionUpdate(this); } -- cgit v1.2.3 From 47bd4dfb2bc720d2b5919b93985f87d918af572a Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 7 Dec 2021 00:25:05 +0100 Subject: Port E2EE to database instead of JSON files --- lib/room.cpp | 82 +++++++----------------------------------------------------- 1 file changed, 9 insertions(+), 73 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index e4fe2fb8..8181f16a 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -70,6 +70,8 @@ #include "crypto/qolminboundsession.h" #endif // Quotient_E2EE_ENABLED +#include "database.h" + using namespace Quotient; using namespace std::placeholders; using std::move; @@ -363,75 +365,11 @@ public: bool isLocalUser(const User* u) const { return u == q->localUser(); } #ifdef Quotient_E2EE_ENABLED - // A map from to - QHash, QPair> - groupSessionIndexRecord; // TODO: cache // A map from (senderKey, sessionId) to InboundGroupSession - UnorderedMap, std::unique_ptr> groupSessions; + UnorderedMap, QOlmInboundGroupSessionPtr> groupSessions; void loadMegOlmSessions() { - QFile file { connection->e2eeDataDir() + QStringLiteral("/%1.json").arg(id) }; - if(!file.exists() || !file.open(QIODevice::ReadOnly)) { - qCDebug(E2EE) << "No megolm sessions cache exists."; - return; - } - auto data = file.readAll(); - const auto json = data.startsWith('{') - ? QJsonDocument::fromJson(data).object() -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - : QCborValue::fromCbor(data).toJsonValue().toObject() -#else - : QJsonDocument::fromBinaryData(data).object() -#endif - ; - if (json.isEmpty()) { - qCWarning(E2EE) << "Megolm sessions cache is empty"; - return; - } - for(const auto &s : json["sessions"].toArray()) { - auto pickle = s.toObject()["pickle"].toString().toLatin1(); - auto senderKey = s.toObject()["sender_key"].toString(); - auto sessionId = s.toObject()["session_id"].toString(); - auto sessionResult = QOlmInboundGroupSession::unpickle(pickle, connection->picklingMode()); - if(std::holds_alternative(sessionResult)) { - qCWarning(E2EE) << "Failed to unpickle olm session"; - continue; - } - groupSessions[{senderKey, sessionId}] = std::move(std::get>(sessionResult)); - } - } - void saveMegOlmSessions() { - QFile outFile { connection->e2eeDataDir() + QStringLiteral("/%1.json").arg(id)}; - if (!outFile.open(QFile::WriteOnly)) { - qCWarning(E2EE) << "Error opening" << outFile.fileName() << ":" - << outFile.errorString(); - qCWarning(E2EE) << "Failed to write megolm sessions"; - return; - } - - QJsonObject rootObj { - { QStringLiteral("cache_version"), - QJsonObject { - { QStringLiteral("major"), 1 }, - { QStringLiteral("minor"), 0 } } } - }; - { - QJsonArray sessionsJson; - for (const auto &session : groupSessions) { - auto pickleResult = session.second->pickle(connection->picklingMode()); - sessionsJson += QJsonObject { - {QStringLiteral("sender_key"), session.first.first}, - {QStringLiteral("session_id"), session.first.second}, - {QStringLiteral("pickle"), QString(pickleResult)} - }; - } - rootObj.insert(QStringLiteral("sessions"), sessionsJson); - } - - const auto data = QJsonDocument(rootObj).toJson(QJsonDocument::Compact); - - outFile.write(data.data(), data.size()); - qCDebug(E2EE) << "Megolm sessions saved to" << outFile.fileName(); + groupSessions = Database::instance().loadMegolmSessions(q->localUser()->id(), q->id(), q->connection()->picklingMode()); } bool addInboundGroupSession(QString senderKey, QString sessionId, QString sessionKey) @@ -449,8 +387,8 @@ public: return false; } qCWarning(E2EE) << "Adding inbound session"; + Database::instance().saveMegolmSession(q->localUser()->id(), q->id(), senderKey, sessionId, megolmSession->pickle(q->connection()->picklingMode())); groupSessions[{senderKey, sessionId}] = std::move(megolmSession); - saveMegOlmSessions(); return true; } @@ -476,17 +414,15 @@ public: return QString(); } const auto& [content, index] = std::get>(decryptResult); - const auto& [recordEventId, ts] = groupSessionIndexRecord.value({senderSession->sessionId(), index}); - if (eventId.isEmpty()) { - groupSessionIndexRecord.insert({senderSession->sessionId(), index}, {recordEventId, timestamp}); + const auto& [recordEventId, ts] = Database::instance().groupSessionIndexRecord(q->localUser()->id(), q->id(), senderSession->sessionId(), index); + if (recordEventId.isEmpty()) { + Database::instance().addGroupSessionIndexRecord(q->localUser()->id(), q->id(), senderSession->sessionId(), index, eventId, timestamp.toMSecsSinceEpoch()); } else { - if ((eventId != recordEventId) || (ts != timestamp)) { + if ((eventId != recordEventId) || (ts != timestamp.toMSecsSinceEpoch())) { qCWarning(E2EE) << "Detected a replay attack on event" << eventId; return QString(); } } - //TODO is this necessary? - saveMegOlmSessions(); return content; } #endif // Quotient_E2EE_ENABLED -- cgit v1.2.3 From 2c6fa33ca52842e9dfba0dd3893a9d5526e10e60 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 7 Dec 2021 19:08:29 +0100 Subject: Rename "crypto" -> "e2ee" --- lib/room.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 8181f16a..755f677a 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -12,7 +12,6 @@ #include "avatar.h" #include "connection.h" #include "converters.h" -#include "crypto/e2ee.h" #include "syncdata.h" #include "user.h" #include "eventstats.h" @@ -65,9 +64,10 @@ #include #ifdef Quotient_E2EE_ENABLED -#include "crypto/qolmaccount.h" -#include "crypto/qolmerrors.h" -#include "crypto/qolminboundsession.h" +#include "e2ee/e2ee.h" +#include "e2ee/qolmaccount.h" +#include "e2ee/qolmerrors.h" +#include "e2ee/qolminboundsession.h" #endif // Quotient_E2EE_ENABLED #include "database.h" -- cgit v1.2.3 From 5cf182fd4fed95e1a16936f400e8ff6fcf991d7c Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 7 Dec 2021 19:18:35 +0100 Subject: Fixes --- lib/room.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 755f677a..15cbac28 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -401,9 +401,9 @@ public: const auto senderSessionPairKey = qMakePair(senderKey, sessionId); auto groupSessionIt = groupSessions.find(senderSessionPairKey); if (groupSessionIt == groupSessions.end()) { - qCWarning(E2EE) << "Unable to decrypt event" << eventId - << "The sender's device has not sent us the keys for " - "this message"; + // qCWarning(E2EE) << "Unable to decrypt event" << eventId + // << "The sender's device has not sent us the keys for " + // "this message"; return QString(); } auto& senderSession = groupSessionIt->second; @@ -1483,7 +1483,7 @@ RoomEventPtr Room::decryptMessage(const EncryptedEvent& encryptedEvent) encryptedEvent.sessionId(), encryptedEvent.id(), encryptedEvent.originTimestamp()); if (decrypted.isEmpty()) { - qCWarning(E2EE) << "Encrypted message is empty"; + // qCWarning(E2EE) << "Encrypted message is empty"; return {}; } return encryptedEvent.createDecrypted(decrypted); @@ -2749,7 +2749,6 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) for(long unsigned int i = 0; i < events.size(); i++) { if(auto* encrypted = eventCast(events[i])) { - qDebug() << "Encrypted Event"; auto decrypted = q->decryptMessage(*encrypted); if(decrypted) { events[i] = std::move(decrypted); -- cgit v1.2.3 From 9fb07da8451f024085061e2985e9be384e7beb5c Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 7 Dec 2021 23:12:04 +0100 Subject: Maintain list of undecrypted events to speed up decryption of old messages --- lib/room.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 15cbac28..8e348089 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -138,6 +138,8 @@ public: QString prevBatch; QPointer eventsHistoryJob; QPointer allMembersJob; + // Map from megolm sessionId to set of eventIds + UnorderedMap> undecryptedEvents; struct FileTransferPrivateInfo { FileTransferPrivateInfo() = default; @@ -1506,12 +1508,17 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, roomKeyEvent.sessionKey())) { qCWarning(E2EE) << "added new inboundGroupSession:" << d->groupSessions.size(); - for (unsigned long int i = 0; i < d->timeline.size(); i++) { - if (auto encryptedEvent = d->timeline[i].viewAs()) { + for (const auto& eventId : d->undecryptedEvents[roomKeyEvent.sessionId()]) { + if (!d->eventsIndex.contains(eventId)) { + continue; + } + auto event = d->timeline.rend() - (d->eventsIndex.value(eventId) - minTimelineIndex() + 1); + if (auto encryptedEvent = event->viewAs()) { auto decrypted = decryptMessage(*encryptedEvent); if(decrypted) { - auto oldEvent = d->timeline[i].replaceEvent(std::move(decrypted)); - emit replacedEvent(d->timeline[i].event(), rawPtr(oldEvent)); + auto oldEvent = event->replaceEvent(std::move(decrypted)); + emit replacedEvent(event->event(), rawPtr(oldEvent)); + d->undecryptedEvents[roomKeyEvent.sessionId()] -= eventId; } } } @@ -2590,6 +2597,8 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) auto decrypted = q->decryptMessage(*encrypted); if(decrypted) { events[i] = std::move(decrypted); + } else { + undecryptedEvents[encrypted->sessionId()] += encrypted->id(); } } } @@ -2752,6 +2761,8 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) auto decrypted = q->decryptMessage(*encrypted); if(decrypted) { events[i] = std::move(decrypted); + } else { + undecryptedEvents[encrypted->sessionId()] += encrypted->id(); } } } -- cgit v1.2.3 From a0ce17dfe793c924205b449c026f2f776b032ff3 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Wed, 8 Dec 2021 23:07:14 +0100 Subject: Store encryptedevent in decrypted roomevents --- lib/room.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 8e348089..b3a092f3 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1517,6 +1517,7 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, auto decrypted = decryptMessage(*encryptedEvent); if(decrypted) { auto oldEvent = event->replaceEvent(std::move(decrypted)); + decrypted->setOriginalEvent(std::move(oldEvent)); emit replacedEvent(event->event(), rawPtr(oldEvent)); d->undecryptedEvents[roomKeyEvent.sessionId()] -= eventId; } @@ -2596,7 +2597,8 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) if(auto* encrypted = eventCast(events[i])) { auto decrypted = q->decryptMessage(*encrypted); if(decrypted) { - events[i] = std::move(decrypted); + auto oldEvent = std::exchange(events[i], std::move(decrypted)); + events[i]->setOriginalEvent(std::move(oldEvent)); } else { undecryptedEvents[encrypted->sessionId()] += encrypted->id(); } @@ -2760,7 +2762,8 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) if(auto* encrypted = eventCast(events[i])) { auto decrypted = q->decryptMessage(*encrypted); if(decrypted) { - events[i] = std::move(decrypted); + auto oldEvent = std::exchange(events[i], std::move(decrypted)); + events[i]->setOriginalEvent(std::move(oldEvent)); } else { undecryptedEvents[encrypted->sessionId()] += encrypted->id(); } -- cgit v1.2.3 From 58798ce15f0f235d64f9c34b3f8c013678ebf25f Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Thu, 9 Dec 2021 23:26:24 +0100 Subject: Ifdef all the things --- lib/room.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index b3a092f3..7d608520 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -68,9 +68,9 @@ #include "e2ee/qolmaccount.h" #include "e2ee/qolmerrors.h" #include "e2ee/qolminboundsession.h" +#include "database.h" #endif // Quotient_E2EE_ENABLED -#include "database.h" using namespace Quotient; using namespace std::placeholders; @@ -2593,6 +2593,7 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) QElapsedTimer et; et.start(); +#ifdef Quotient_E2EE_ENABLED for(long unsigned int i = 0; i < events.size(); i++) { if(auto* encrypted = eventCast(events[i])) { auto decrypted = q->decryptMessage(*encrypted); @@ -2604,6 +2605,7 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) } } } +#endif { // Pre-process redactions and edits so that events that get @@ -2758,6 +2760,7 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) Changes changes {}; +#ifdef Quotient_E2EE_ENABLED for(long unsigned int i = 0; i < events.size(); i++) { if(auto* encrypted = eventCast(events[i])) { auto decrypted = q->decryptMessage(*encrypted); @@ -2769,6 +2772,7 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) } } } +#endif // In case of lazy-loading new members may be loaded with historical // messages. Also, the cache doesn't store events with empty content; -- cgit v1.2.3 From b4cc38fc7c2c63d8122106a2451aec2c60176a4b Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Fri, 10 Dec 2021 16:10:10 +0100 Subject: Use individual databases for each connection --- lib/room.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 7d608520..458f870d 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -371,7 +371,7 @@ public: UnorderedMap, QOlmInboundGroupSessionPtr> groupSessions; void loadMegOlmSessions() { - groupSessions = Database::instance().loadMegolmSessions(q->localUser()->id(), q->id(), q->connection()->picklingMode()); + groupSessions = q->connection()->database()->loadMegolmSessions(q->id(), q->connection()->picklingMode()); } bool addInboundGroupSession(QString senderKey, QString sessionId, QString sessionKey) @@ -389,7 +389,7 @@ public: return false; } qCWarning(E2EE) << "Adding inbound session"; - Database::instance().saveMegolmSession(q->localUser()->id(), q->id(), senderKey, sessionId, megolmSession->pickle(q->connection()->picklingMode())); + q->connection()->database()->saveMegolmSession(q->id(), senderKey, sessionId, megolmSession->pickle(q->connection()->picklingMode())); groupSessions[{senderKey, sessionId}] = std::move(megolmSession); return true; } @@ -416,9 +416,9 @@ public: return QString(); } const auto& [content, index] = std::get>(decryptResult); - const auto& [recordEventId, ts] = Database::instance().groupSessionIndexRecord(q->localUser()->id(), q->id(), senderSession->sessionId(), index); + const auto& [recordEventId, ts] = q->connection()->database()->groupSessionIndexRecord(q->id(), senderSession->sessionId(), index); if (recordEventId.isEmpty()) { - Database::instance().addGroupSessionIndexRecord(q->localUser()->id(), q->id(), senderSession->sessionId(), index, eventId, timestamp.toMSecsSinceEpoch()); + q->connection()->database()->addGroupSessionIndexRecord(q->id(), senderSession->sessionId(), index, eventId, timestamp.toMSecsSinceEpoch()); } else { if ((eventId != recordEventId) || (ts != timestamp.toMSecsSinceEpoch())) { qCWarning(E2EE) << "Detected a replay attack on event" << eventId; -- cgit v1.2.3 From 4a17403f9adad9b4390f7e0010c0f7e23a718f7b Mon Sep 17 00:00:00 2001 From: Tobias Fella <9750016+TobiasFella@users.noreply.github.com> Date: Fri, 10 Dec 2021 16:25:18 +0100 Subject: Apply suggestions from code review Co-authored-by: Alexey Rusakov --- lib/room.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 458f870d..0a4fcc68 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1509,16 +1509,18 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, qCWarning(E2EE) << "added new inboundGroupSession:" << d->groupSessions.size(); for (const auto& eventId : d->undecryptedEvents[roomKeyEvent.sessionId()]) { - if (!d->eventsIndex.contains(eventId)) { + const auto pIdx = d->eventsIndex.constFind(eventId); + if (pIdx == d->eventsIndex.cend()) continue; - } - auto event = d->timeline.rend() - (d->eventsIndex.value(eventId) - minTimelineIndex() + 1); - if (auto encryptedEvent = event->viewAs()) { + auto& ti = d->timeline[Timeline::size_type(*pIdx - minTimelineIndex())]; + if (auto encryptedEvent = ti.viewAs()) { auto decrypted = decryptMessage(*encryptedEvent); if(decrypted) { - auto oldEvent = event->replaceEvent(std::move(decrypted)); - decrypted->setOriginalEvent(std::move(oldEvent)); - emit replacedEvent(event->event(), rawPtr(oldEvent)); + // The reference will survive the pointer being moved + auto& decryptedEvent = *decrypted; + auto oldEvent = ti.replaceEvent(std::move(decrypted)); + decryptedEvent.setOriginalEvent(std::move(oldEvent)); + emit replacedEvent(ti.event(), decrypted->originalEvent()); d->undecryptedEvents[roomKeyEvent.sessionId()] -= eventId; } } -- cgit v1.2.3 From 6b29d759a47012eef74948e72c0d0395eb6bf282 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Fri, 10 Dec 2021 17:01:05 +0100 Subject: Remove data from database when leaving room --- lib/room.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 0a4fcc68..a46892f3 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -461,6 +461,10 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) } }); d->loadMegOlmSessions(); + + connect(this, &Room::beforeDestruction, this, [=](){ + connection->database()->clearRoomData(id); + }); #endif qCDebug(STATE) << "New" << terse << initialJoinState << "Room:" << id; } -- cgit v1.2.3 From 148bb1256fb15c73c605c5301da2b9602f859660 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Fri, 11 Feb 2022 23:07:35 +0100 Subject: Implement more suggestions --- lib/room.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index a46892f3..492845d7 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -370,9 +370,6 @@ public: // A map from (senderKey, sessionId) to InboundGroupSession UnorderedMap, QOlmInboundGroupSessionPtr> groupSessions; - void loadMegOlmSessions() { - groupSessions = q->connection()->database()->loadMegolmSessions(q->id(), q->connection()->picklingMode()); - } bool addInboundGroupSession(QString senderKey, QString sessionId, QString sessionKey) { @@ -382,14 +379,14 @@ public: return false; } - std::unique_ptr megolmSession = QOlmInboundGroupSession::create(sessionKey.toLatin1()); + auto megolmSession = QOlmInboundGroupSession::create(sessionKey.toLatin1()); if (megolmSession->sessionId() != sessionId) { qCWarning(E2EE) << "Session ID mismatch in m.room_key event sent " "from sender with key" << senderKey; return false; } qCWarning(E2EE) << "Adding inbound session"; - q->connection()->database()->saveMegolmSession(q->id(), senderKey, sessionId, megolmSession->pickle(q->connection()->picklingMode())); + connection->saveMegolmSession(q, senderKey, megolmSession.get()); groupSessions[{senderKey, sessionId}] = std::move(megolmSession); return true; } @@ -460,7 +457,7 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) connection->encryptionUpdate(this); } }); - d->loadMegOlmSessions(); + d->groupSessions = connection->loadRoomMegolmSessions(this); connect(this, &Room::beforeDestruction, this, [=](){ connection->database()->clearRoomData(id); -- cgit v1.2.3 From b0aef4af9cbf00755c7b70c71d77f0bf7ce0d200 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 12 Feb 2022 12:12:24 +0100 Subject: Replace QPair with std::pair --- lib/room.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/room.cpp') diff --git a/lib/room.cpp b/lib/room.cpp index 492845d7..0fc7d23e 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -368,7 +368,7 @@ public: #ifdef Quotient_E2EE_ENABLED // A map from (senderKey, sessionId) to InboundGroupSession - UnorderedMap, QOlmInboundGroupSessionPtr> groupSessions; + UnorderedMap, QOlmInboundGroupSessionPtr> groupSessions; bool addInboundGroupSession(QString senderKey, QString sessionId, QString sessionKey) @@ -397,7 +397,7 @@ public: const QString& eventId, QDateTime timestamp) { - const auto senderSessionPairKey = qMakePair(senderKey, sessionId); + const auto senderSessionPairKey = make_pair(senderKey, sessionId); auto groupSessionIt = groupSessions.find(senderSessionPairKey); if (groupSessionIt == groupSessions.end()) { // qCWarning(E2EE) << "Unable to decrypt event" << eventId -- cgit v1.2.3