aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--lib/connection.cpp48
-rw-r--r--lib/connection.h5
-rw-r--r--lib/encryptionmanager.cpp4
-rw-r--r--lib/events/eventcontent.cpp1
-rw-r--r--lib/room.cpp5
6 files changed, 59 insertions, 8 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8d5f08af..3977a9d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -109,6 +109,8 @@ if (${PROJECT_NAME}_ENABLE_E2EE)
endif()
endif()
+find_package(Qt${QT_MAJOR_VERSION}Keychain REQUIRED)
+
# Set up source files
list(APPEND lib_SRCS
lib/quotient_common.h
@@ -325,7 +327,7 @@ if (${PROJECT_NAME}_ENABLE_E2EE)
find_dependency(OpenSSL)") # For QuotientConfig.cmake.in
endif()
-target_link_libraries(${PROJECT_NAME} ${Qt}::Core ${Qt}::Network ${Qt}::Gui)
+target_link_libraries(${PROJECT_NAME} ${Qt}::Core ${Qt}::Network ${Qt}::Gui ${QTKEYCHAIN_LIBRARIES})
if (Qt STREQUAL Qt5) # See #483
target_link_libraries(${PROJECT_NAME} ${Qt}::Multimedia)
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 7a96bc50..77ab3b72 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -39,6 +39,7 @@
#ifdef Quotient_E2EE_ENABLED
# include "crypto/qolmaccount.h"
+# include "crypto/qolmutils.h"
#endif // Quotient_E2EE_ENABLED
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
@@ -55,6 +56,13 @@
#include <QtCore/QStringBuilder>
#include <QtNetwork/QDnsLookup>
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+# include <qt6keychain/keychain.h>
+#else
+# include <qt5keychain/keychain.h>
+#endif
+
using namespace Quotient;
// This is very much Qt-specific; STL iterators don't have key() and value()
@@ -108,6 +116,7 @@ public:
QHash<QString, QHash<QString, QueryKeysJob::DeviceInformation>> deviceKeys;
QueryKeysJob *currentQueryKeysJob = nullptr;
bool encryptionUpdateRequired = false;
+ PicklingMode picklingMode = Unencrypted {};
#endif
GetCapabilitiesJob* capabilitiesJob = nullptr;
@@ -457,10 +466,40 @@ void Connection::Private::completeSetup(const QString& mxId)
#else // Quotient_E2EE_ENABLED
AccountSettings accountSettings(data->userId());
+ QKeychain::ReadPasswordJob job(qAppName());
+ job.setAutoDelete(false);
+ job.setKey(accountSettings.userId() + QStringLiteral("-Pickle"));
+ QEventLoop loop;
+ QKeychain::ReadPasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
+ job.start();
+ loop.exec();
+
+ if (job.error() == QKeychain::Error::EntryNotFound) {
+ picklingMode = Encrypted { getRandom(128) };
+ QKeychain::WritePasswordJob job(qAppName());
+ job.setAutoDelete(false);
+ job.setKey(accountSettings.userId() + QStringLiteral("-Pickle"));
+ job.setBinaryData(std::get<Encrypted>(picklingMode).key);
+ QEventLoop loop;
+ QKeychain::WritePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
+ job.start();
+ loop.exec();
+
+ if (job.error()) {
+ qCWarning(E2EE) << "Could not save pickling key to keychain: " << job.errorString();
+ }
+ } else if(job.error() != QKeychain::Error::NoError) {
+ //TODO Error, do something
+ qCWarning(E2EE) << "Error loading pickling key from keychain:" << job.error();
+ } else {
+ qCDebug(E2EE) << "Successfully loaded pickling key from keychain";
+ picklingMode = Encrypted { job.binaryData() };
+ }
+
// init olmAccount
olmAccount = std::make_unique<QOlmAccount>(data->userId(), data->deviceId(), q);
connect(olmAccount.get(), &QOlmAccount::needsSave, q, [=](){
- auto pickle = olmAccount->pickle(Unencrypted{});
+ auto pickle = olmAccount->pickle(picklingMode);
AccountSettings(data->userId()).setEncryptionAccountPickle(std::get<QByteArray>(pickle));
//TODO handle errors
});
@@ -476,7 +515,7 @@ void Connection::Private::completeSetup(const QString& mxId)
} else {
// account already existing
auto pickle = accountSettings.encryptionAccountPickle();
- olmAccount->unpickle(pickle, Unencrypted{});
+ olmAccount->unpickle(pickle, picklingMode);
}
#endif // Quotient_E2EE_ENABLED
emit q->stateChanged();
@@ -1982,4 +2021,9 @@ void Connection::Private::loadDevicesList()
}
});
}
+
+PicklingMode Connection::picklingMode() const
+{
+ return d->picklingMode;
+}
#endif
diff --git a/lib/connection.h b/lib/connection.h
index c351f93e..e5cec34b 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -21,6 +21,10 @@
#include <functional>
+#ifdef Quotient_E2EE_ENABLED
+#include "crypto/e2ee.h"
+#endif
+
Q_DECLARE_METATYPE(Quotient::GetLoginFlowsJob::LoginFlow)
namespace Quotient {
@@ -650,6 +654,7 @@ public Q_SLOTS:
#ifdef Quotient_E2EE_ENABLED
void encryptionUpdate(Room *room);
+ PicklingMode picklingMode() const;
#endif
Q_SIGNALS:
/// \brief Initial server resolution has failed
diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp
index e8cc7b3a..5c1750c9 100644
--- a/lib/encryptionmanager.cpp
+++ b/lib/encryptionmanager.cpp
@@ -71,7 +71,7 @@ public:
}
for(const auto &senderKey : json["sessions"].toObject().keys()) {
auto pickle = json["sessions"].toObject()[senderKey].toString();
- auto sessionResult = QOlmSession::unpickle(pickle.toLatin1(), Unencrypted{});
+ auto sessionResult = QOlmSession::unpickle(pickle.toLatin1(), static_cast<Connection *>(q->parent())->picklingMode());
if(std::holds_alternative<QOlmError>(sessionResult)) {
qCWarning(E2EE) << "Failed to unpickle olm session";
continue;
@@ -97,7 +97,7 @@ public:
{
QJsonObject sessionsJson;
for (const auto &session : sessions) {
- auto pickleResult = session.second->pickle(Unencrypted{});
+ auto pickleResult = session.second->pickle(static_cast<Connection *>(q->parent())->picklingMode());
if(std::holds_alternative<QOlmError>(pickleResult)) {
qCWarning(E2EE) << "Failed to pickle session";
continue;
diff --git a/lib/events/eventcontent.cpp b/lib/events/eventcontent.cpp
index 22878d4c..d4cb43ff 100644
--- a/lib/events/eventcontent.cpp
+++ b/lib/events/eventcontent.cpp
@@ -75,6 +75,7 @@ void FileInfo::fillInfoJson(QJsonObject* infoJson) const
infoJson->insert(QStringLiteral("size"), payloadSize);
if (mimeType.isValid())
infoJson->insert(QStringLiteral("mimetype"), mimeType.name());
+ //TODO add encryptedfile
}
ImageInfo::ImageInfo(const QFileInfo& fi, QSize imageSize)
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<QOlmError>(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<EncryptedEvent>(events[i])) {
- qDebug() << "Encrypted Event";
auto decrypted = q->decryptMessage(*encrypted);
if(decrypted) {
events[i] = std::move(decrypted);