diff options
author | Tobias Fella <fella@posteo.de> | 2021-06-12 23:04:17 +0200 |
---|---|---|
committer | Tobias Fella <fella@posteo.de> | 2021-12-01 21:56:59 +0100 |
commit | 703b3f89ef54d9d40c9117788d0920b6b745bd62 (patch) | |
tree | 800e2e706930a0c2512e4517e16246a2d30d79f9 /lib/encryptionmanager.cpp | |
parent | eaf23c0f6bb97fdf16631296ab7016447a99c4f2 (diff) | |
download | libquotient-703b3f89ef54d9d40c9117788d0920b6b745bd62.tar.gz libquotient-703b3f89ef54d9d40c9117788d0920b6b745bd62.zip |
Implement (meg)olm key caching, megolm decrypting, EncryptedEvent
decryption, handling of encrypted redactions and replies
Diffstat (limited to 'lib/encryptionmanager.cpp')
-rw-r--r-- | lib/encryptionmanager.cpp | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp index 48e6701c..d36d5a7a 100644 --- a/lib/encryptionmanager.cpp +++ b/lib/encryptionmanager.cpp @@ -31,7 +31,6 @@ using std::move; class EncryptionManager::Private { public: explicit Private() - : q(nullptr) { } ~Private() = default; @@ -51,6 +50,73 @@ public: } } } + void loadSessions() { + QFile file { static_cast<Connection *>(q->parent())->stateCacheDir().filePath("olmsessions.json") }; + if(!file.exists() || !file.open(QIODevice::ReadOnly)) { + qCDebug(E2EE) << "No 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) << "Sessions cache is empty"; + return; + } + for(const auto &senderKey : json["sessions"].toObject().keys()) { + auto pickle = json["sessions"].toObject()[senderKey].toString(); + auto sessionResult = QOlmSession::unpickle(pickle.toLatin1(), Unencrypted{}); + if(std::holds_alternative<QOlmError>(sessionResult)) { + qCWarning(E2EE) << "Failed to unpickle olm session"; + continue; + } + sessions[senderKey] = std::move(std::get<std::unique_ptr<QOlmSession>>(sessionResult)); + } + } + void saveSessions() { + QFile outFile { static_cast<Connection *>(q->parent())->stateCacheDir().filePath("olmsessions.json") }; + if (!outFile.open(QFile::WriteOnly)) { + qCWarning(E2EE) << "Error opening" << outFile.fileName() << ":" + << outFile.errorString(); + qCWarning(E2EE) << "Failed to write olm sessions"; + return; + } + + QJsonObject rootObj { + { QStringLiteral("cache_version"), + QJsonObject { + { QStringLiteral("major"), 1 }, + { QStringLiteral("minor"), 0 } } } + }; + { + QJsonObject sessionsJson; + for (const auto &session : sessions) { + auto pickleResult = session.second->pickle(Unencrypted{}); + if(std::holds_alternative<QOlmError>(pickleResult)) { + qCWarning(E2EE) << "Failed to pickle session"; + continue; + } + sessionsJson[session.first] = QString(std::get<QByteArray>(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) << "Sessions saved to" << outFile.fileName(); + } QString sessionDecryptPrekey(const QOlmMessage& message, const QString &senderKey, std::unique_ptr<QOlmAccount>& olmAccount) { Q_ASSERT(message.type() == QOlmMessage::PreKey); @@ -60,6 +126,7 @@ public: qCDebug(E2EE) << "Found inbound session"; const auto result = session.second->decrypt(message); if(std::holds_alternative<QString>(result)) { + saveSessions(); return std::get<QString>(result); } else { qCDebug(E2EE) << "Failed to decrypt prekey message"; @@ -79,6 +146,7 @@ public: const auto result = newSession->decrypt(message); sessions[senderKey] = std::move(newSession); if(std::holds_alternative<QString>(result)) { + saveSessions(); return std::get<QString>(result); } else { qCDebug(E2EE) << "Failed to decrypt prekey message with new session"; @@ -91,6 +159,7 @@ public: for(auto& session : sessions) { const auto result = session.second->decrypt(message); if(std::holds_alternative<QString>(result)) { + saveSessions(); return std::get<QString>(result); } } @@ -104,6 +173,7 @@ EncryptionManager::EncryptionManager(QObject* parent) , d(std::make_unique<Private>()) { d->q = this; + d->loadSessions(); } EncryptionManager::~EncryptionManager() = default; |