diff options
Diffstat (limited to 'lib/connection.cpp')
-rw-r--r-- | lib/connection.cpp | 70 |
1 files changed, 66 insertions, 4 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index d99ab64d..28377dd9 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -33,6 +33,7 @@ #include "jobs/downloadfilejob.h" #include "jobs/mediathumbnailjob.h" #include "jobs/syncjob.h" +#include <variant> #ifdef Quotient_E2EE_ENABLED # include "e2ee/qolmaccount.h" @@ -223,13 +224,23 @@ public: std::pair<QString, QString> sessionDecryptPrekey(const QOlmMessage& message, const QString &senderKey, std::unique_ptr<QOlmAccount>& olmAccount) { Q_ASSERT(message.type() == QOlmMessage::PreKey); - for(auto& session : olmSessions[senderKey]) { + for (size_t i = 0; i < olmSessions[senderKey].size(); i++) { + auto& session = olmSessions[senderKey][i]; const auto matches = session->matchesInboundSessionFrom(senderKey, message); if(std::holds_alternative<bool>(matches) && std::get<bool>(matches)) { qCDebug(E2EE) << "Found inbound session"; const auto result = session->decrypt(message); if(std::holds_alternative<QString>(result)) { q->database()->setOlmSessionLastReceived(QString(session->sessionId()), QDateTime::currentDateTime()); + auto pickle = session->pickle(q->picklingMode()); + if (std::holds_alternative<QByteArray>(pickle)) { + q->database()->updateOlmSession(senderKey, session->sessionId(), std::get<QByteArray>(pickle)); + } else { + qCWarning(E2EE) << "Failed to pickle olm session."; + } + auto s = std::move(session); + olmSessions[senderKey].erase(olmSessions[senderKey].begin() + i); + olmSessions[senderKey].insert(olmSessions[senderKey].begin(), std::move(s)); return { std::get<QString>(result), session->sessionId() }; } else { qCDebug(E2EE) << "Failed to decrypt prekey message"; @@ -251,7 +262,7 @@ public: const auto result = newSession->decrypt(message); QString sessionId = newSession->sessionId(); saveSession(newSession, senderKey); - olmSessions[senderKey].push_back(std::move(newSession)); + olmSessions[senderKey].insert(olmSessions[senderKey].begin(), std::move(newSession)); if(std::holds_alternative<QString>(result)) { return { std::get<QString>(result), sessionId }; } else { @@ -262,10 +273,20 @@ public: std::pair<QString, QString> sessionDecryptGeneral(const QOlmMessage& message, const QString &senderKey) { Q_ASSERT(message.type() == QOlmMessage::General); - for(auto& session : olmSessions[senderKey]) { + for (size_t i = 0; i < olmSessions[senderKey].size(); i++) { + auto& session = olmSessions[senderKey][i]; const auto result = session->decrypt(message); if(std::holds_alternative<QString>(result)) { q->database()->setOlmSessionLastReceived(QString(session->sessionId()), QDateTime::currentDateTime()); + auto pickle = session->pickle(q->picklingMode()); + if (std::holds_alternative<QByteArray>(pickle)) { + q->database()->updateOlmSession(senderKey, session->sessionId(), std::get<QByteArray>(pickle)); + } else { + qCWarning(E2EE) << "Failed to pickle olm session."; + } + auto s = std::move(session); + olmSessions[senderKey].erase(olmSessions[senderKey].begin() + i); + olmSessions[senderKey].insert(olmSessions[senderKey].begin(), std::move(s)); return { std::get<QString>(result), session->sessionId() }; } } @@ -1338,7 +1359,7 @@ Connection::sendToDevices(const QString& eventType, [&jsonUser](const auto& deviceToEvents) { jsonUser.insert( deviceToEvents.first, - deviceToEvents.second.contentJson()); + deviceToEvents.second->contentJson()); }); }); return callApi<SendToDeviceJob>(BackgroundRequest, eventType, @@ -2225,6 +2246,47 @@ QString Connection::edKeyForUserDevice(const QString& user, const QString& devic return d->deviceKeys[user][device].keys["ed25519:" % device]; } +bool Connection::hasOlmSession(User* user, const QString& deviceId) const +{ + const auto& curveKey = curveKeyForUserDevice(user->id(), deviceId); + return d->olmSessions.contains(curveKey) && d->olmSessions[curveKey].size() > 0; +} + +QPair<QOlmMessage::Type, QByteArray> Connection::olmEncryptMessage(User* user, const QString& device, const QByteArray& message) +{ + const auto& curveKey = curveKeyForUserDevice(user->id(), device); + QOlmMessage::Type type = d->olmSessions[curveKey][0]->encryptMessageType(); + auto result = d->olmSessions[curveKey][0]->encrypt(message); + auto pickle = d->olmSessions[curveKey][0]->pickle(picklingMode()); + if (std::holds_alternative<QByteArray>(pickle)) { + database()->updateOlmSession(curveKey, d->olmSessions[curveKey][0]->sessionId(), std::get<QByteArray>(pickle)); + } else { + qCWarning(E2EE) << "Failed to pickle olm session."; + } + return qMakePair(type, result.toCiphertext()); +} + +void Connection::createOlmSession(const QString& theirIdentityKey, const QString& theirOneTimeKey) +{ + auto session = QOlmSession::createOutboundSession(olmAccount(), theirIdentityKey, theirOneTimeKey); + if (std::holds_alternative<QOlmError>(session)) { + qCWarning(E2EE) << "Failed to create olm session for " << theirIdentityKey << std::get<QOlmError>(session); + return; + } + d->saveSession(std::get<std::unique_ptr<QOlmSession>>(session), theirIdentityKey); + d->olmSessions[theirIdentityKey].push_back(std::move(std::get<std::unique_ptr<QOlmSession>>(session))); +} + +QOlmOutboundGroupSessionPtr Connection::loadCurrentOutboundMegolmSession(Room* room) +{ + return d->database->loadCurrentOutboundMegolmSession(room->id(), d->picklingMode); +} + +void Connection::saveCurrentOutboundMegolmSession(Room *room, const QOlmOutboundGroupSessionPtr& data) +{ + d->database->saveCurrentOutboundMegolmSession(room->id(), d->picklingMode, data); +} + bool Connection::isKnownCurveKey(const QString& user, const QString& curveKey) { auto query = database()->prepareQuery(QStringLiteral("SELECT * FROM tracked_devices WHERE matrixId=:matrixId AND curveKey=:curveKey")); |