Skip to content

Commit

Permalink
Probably fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
KitsuneRal committed Aug 23, 2024
1 parent 9b70aa1 commit 61fe407
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 44 deletions.
21 changes: 9 additions & 12 deletions Quotient/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,18 +323,15 @@ void Connection::Private::completeSetup(const QString& mxId, bool mock)

if (useEncryption) {
using _impl::ConnectionEncryptionData;
ConnectionEncryptionData::setup(q, mock).then(
[this](std::unique_ptr<ConnectionEncryptionData>&& encData) {
if (encData) {
encryptionData = std::move(encData);
} else {
useEncryption = false;
emit q->encryptionChanged(false);
}
emit q->ready();
emit q->stateChanged();
emit q->connected();
});
ConnectionEncryptionData::setup(q, mock, encryptionData).then([this](bool successful) {
if (!successful || !encryptionData) {
useEncryption = false;
emit q->encryptionChanged(false);
}
emit q->ready();
emit q->stateChanged();
emit q->connected();
});
} else {
qCInfo(E2EE) << "End-to-end encryption (E2EE) support is off for" << q->objectName();
emit q->ready();
Expand Down
62 changes: 32 additions & 30 deletions Quotient/connectionencryptiondata_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,38 @@
using namespace Quotient;
using namespace Quotient::_impl;

QFuture<PicklingKey> setupPicklingKey(const QString& id, bool mock)
// The following two functions fill up encryptionData instead of returning it in a future because
// Qt 6.4 doesn't handle QFutures with move-only data quite well (see Qt 6.5 change list)

QFuture<void> setupPicklingKey(Connection* connection, bool mock,
std::unique_ptr<ConnectionEncryptionData>& encryptionData)
{
if (mock) {
qInfo(E2EE) << "Using a mock pickling key";
return QtFuture::makeReadyFuture(PicklingKey::generate());
encryptionData =
std::make_unique<ConnectionEncryptionData>(connection, PicklingKey::generate());
return QtFuture::makeReadyFuture<void>();
}

QPromise<PicklingKey> promise;
QPromise<void> promise;
auto futureResult = promise.future();
promise.start();

using namespace QKeychain;
const auto keychainId = id + "-Pickle"_ls;
const auto keychainId = connection->userId() + "-Pickle"_ls;
auto readJob = new ReadPasswordJob(qAppName());
readJob->setAutoDelete(true);
qCInfo(MAIN) << "Keychain request: app" << qAppName() << "id" << keychainId;
readJob->setKey(keychainId);
QObject::connect(readJob, &Job::finished, readJob,
[readJob, keychainId, promise = std::move(promise)]() mutable {
[readJob, keychainId, &encryptionData, connection, promise = std::move(promise)]() mutable {
switch (readJob->error()) {
case Error::NoError: {
auto&& data = readJob->binaryData();
if (data.size() == PicklingKey::extent) {
qDebug(E2EE) << "Successfully loaded pickling key from keychain";
promise.addResult(PicklingKey::fromByteArray(std::move(data)));
encryptionData = std::make_unique<ConnectionEncryptionData>(
connection, PicklingKey::fromByteArray(std::move(data)));
} else {
qCritical(E2EE)
<< "The pickling key loaded from" << keychainId << "has length"
Expand All @@ -60,7 +67,8 @@ QFuture<PicklingKey> setupPicklingKey(const QString& id, bool mock)
writeJob->setKey(keychainId);
writeJob->setBinaryData(picklingKey.viewAsByteArray());
qDebug(E2EE) << "Saving a new pickling key to the keychain";
promise.addResult(std::move(picklingKey)); // but don't finish yet
encryptionData = std::make_unique<ConnectionEncryptionData>(
connection, std::move(picklingKey)); // but don't finish the future yet
QObject::connect(writeJob, &Job::finished, writeJob,
[promise = std::move(promise), writeJob]() mutable {
if (writeJob->error() != Error::NoError) {
Expand All @@ -84,47 +92,41 @@ QFuture<PicklingKey> setupPicklingKey(const QString& id, bool mock)
return futureResult;
}

QFuture<std::unique_ptr<ConnectionEncryptionData>> ConnectionEncryptionData::setup(
Connection* connection, bool mock)
QFuture<bool> ConnectionEncryptionData::setup(Connection* connection, bool mock,
std::unique_ptr<ConnectionEncryptionData>& result)
{
return setupPicklingKey(connection->userId(), mock)
.then([connection, mock](QFuture<PicklingKey> ft) {
auto encryptionData =
std::make_unique<ConnectionEncryptionData>(connection, ft.takeResult());
return setupPicklingKey(connection, mock, result)
.then([connection, mock, &result] {
if (mock) {
encryptionData->database.clear();
encryptionData->olmAccount.setupNewAccount();
return encryptionData;
result->database.clear();
result->olmAccount.setupNewAccount();
return true;
}
if (const auto outcome =
encryptionData->database.setupOlmAccount(encryptionData->olmAccount)) {
if (const auto outcome = result->database.setupOlmAccount(result->olmAccount)) {
if (outcome == OLM_SUCCESS) {
qCDebug(E2EE) << "The existing Olm account successfully unpickled";
return encryptionData;
return true;
}

qCritical(E2EE) << "Could not unpickle Olm account for" << connection->objectName();
ft.cancel();
return std::unique_ptr<ConnectionEncryptionData>{};
return false;
}
qCDebug(E2EE) << "A new Olm account has been created, uploading device keys";
connection->callApi<UploadKeysJob>(encryptionData->olmAccount.deviceKeys())
connection->callApi<UploadKeysJob>(result->olmAccount.deviceKeys())
.then(connection,
// eData is meant to have the same lifetime as connection so it's safe
// to pass an unguarded pointer to encryption data here
[connection, eData = encryptionData.get()] {
eData->trackedUsers += connection->userId();
eData->outdatedUsers += connection->userId();
eData->encryptionUpdateRequired = true;
[connection, &result] {
result->trackedUsers += connection->userId();
result->outdatedUsers += connection->userId();
result->encryptionUpdateRequired = true;
},
[](auto* job) {
qCWarning(E2EE) << "Failed to upload device keys:" << job->errorString();
});
return encryptionData;
return true;
})
.onCanceled([connection] {
qCritical(E2EE) << "Could not setup E2EE for" << connection->objectName();
return std::unique_ptr<ConnectionEncryptionData>{};
return false;
});
}

Expand Down
4 changes: 2 additions & 2 deletions Quotient/connectionencryptiondata_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ struct DevicesList;
namespace _impl {
class ConnectionEncryptionData {
public:
static QFuture<std::unique_ptr<ConnectionEncryptionData>> setup(Connection* connection,
bool mock = false);
static QFuture<bool> setup(Connection* connection, bool mock,
std::unique_ptr<ConnectionEncryptionData>& result);

Connection* q;
QOlmAccount olmAccount;
Expand Down

0 comments on commit 61fe407

Please sign in to comment.