aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlexey Andreyev <aa13q@ya.ru>2019-06-22 19:57:18 +0300
committerAlexey Andreyev <aa13q@ya.ru>2019-07-04 11:21:06 +0300
commit69ba71cca36b4a90328d169c845195f39c041a3a (patch)
treedfcb78bc916b03e13a54c4f8cd707e3324cb2894 /lib
parent46a7350086e42ea3960fe54ef5c68b2207527899 (diff)
downloadlibquotient-69ba71cca36b4a90328d169c845195f39c041a3a.tar.gz
libquotient-69ba71cca36b4a90328d169c845195f39c041a3a.zip
Add EncryptionManager class. Add AccountSettings::encryptionAccountPickle logic.
Diffstat (limited to 'lib')
-rw-r--r--lib/connection.cpp10
-rw-r--r--lib/encryptionmanager.cpp117
-rw-r--r--lib/encryptionmanager.h31
-rw-r--r--lib/settings.cpp22
-rw-r--r--lib/settings.h5
5 files changed, 184 insertions, 1 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp
index a7eae30f..d7c3d78f 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -23,6 +23,7 @@
#include "events/eventloader.h"
#include "room.h"
#include "settings.h"
+#include "encryptionmanager.h"
#include "csapi/login.h"
#include "csapi/capabilities.h"
#include "csapi/logout.h"
@@ -101,6 +102,8 @@ class Connection::Private
GetCapabilitiesJob* capabilitiesJob = nullptr;
GetCapabilitiesJob::Capabilities capabilities;
+ QScopedPointer<EncryptionManager> encryptionManager;
+
SyncJob* syncJob = nullptr;
bool cacheState = true;
@@ -235,6 +238,13 @@ void Connection::doConnectToServer(const QString& user, const QString& password,
[this, loginJob] {
d->connectWithToken(loginJob->userId(), loginJob->accessToken(),
loginJob->deviceId());
+
+ AccountSettings accountSettings(loginJob->userId());
+ d->encryptionManager.reset(new EncryptionManager(accountSettings.encryptionAccountPickle()));
+
+ d->encryptionManager->uploadIdentityKeys(this);
+ d->encryptionManager->uploadOneTimeKeys(this);
+
});
connect(loginJob, &BaseJob::failure, this,
[this, loginJob] {
diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp
new file mode 100644
index 00000000..b40305ea
--- /dev/null
+++ b/lib/encryptionmanager.cpp
@@ -0,0 +1,117 @@
+#include "encryptionmanager.h"
+
+#include <functional>
+#include <memory>
+#include <QtCore/QStringBuilder>
+#include <QtCore/QHash>
+#include <account.h> // QtOlm
+
+#include "csapi/keys.h"
+#include "connection.h"
+
+using namespace QMatrixClient;
+using namespace QtOlm;
+using std::move;
+
+static const auto ed25519Name = QStringLiteral("ed25519");
+static const auto Curve25519Name = QStringLiteral("curve25519");
+static const auto SignedCurve25519Name = QStringLiteral("signed_curve25519");
+static const auto OlmCurve25519AesSha256AlgoName = QStringLiteral("m.olm.curve25519-aes-sha256");
+static const auto MegolmV1AesShaAlgoName = QStringLiteral("m.megolm.v1.aes-sha");
+
+class EncryptionManager::Private
+{
+ public:
+ explicit Private(const QByteArray& encryptionAccountPickle, float signedKeysProportion, float oneTimeKeyThreshold)
+ : olmAccount(new Account(encryptionAccountPickle)), // TODO: passphrase even with qtkeychain?
+ signedKeysProportion(move(signedKeysProportion)),
+ oneTimeKeyThreshold(move(oneTimeKeyThreshold)),
+ targetKeysNumber(olmAccount->maxOneTimeKeys()) // 2 // see note below
+ {
+ Q_ASSERT((0 <= signedKeysProportion) && (signedKeysProportion <= 1));
+ Q_ASSERT((0 <= oneTimeKeyThreshold) && (oneTimeKeyThreshold <= 1));
+ /*
+ * Note about targetKeysNumber:
+ *
+ * From: https://github.com/Zil0/matrix-python-sdk/
+ * File: matrix_client/crypto/olm_device.py
+ *
+ * Try to maintain half the number of one-time keys libolm can hold uploaded
+ * on the HS. This is because some keys will be claimed by peers but not
+ * used instantly, and we want them to stay in libolm, until the limit is reached
+ * and it starts discarding keys, starting by the oldest.
+ */
+ }
+ ~Private()
+ {
+ delete olmAccount;
+ }
+
+ UploadKeysJob* uploadIdentityKeysJob = nullptr;
+ UploadKeysJob* uploadOneTimeKeysJob = nullptr;
+
+ Account* olmAccount;
+ const QByteArray encryptionAccountPickle;
+
+ float signedKeysProportion;
+ float oneTimeKeyThreshold;
+ int targetKeysNumber;
+
+ void updateKeysToUpload();
+ bool oneTimeKeyShouldUpload();
+
+ QHash<QString, int> oneTimeKeyCounts;
+ void setOneTimeKeyCounts(const QHash<QString, int> oneTimeKeyCountsNewValue)
+ {
+ oneTimeKeyCounts = oneTimeKeyCountsNewValue;
+ updateKeysToUpload();
+ }
+ QHash<QString, int> oneTimeKeysToUploadCounts;
+ QHash<QString, int> targetOneTimeKeyCounts
+ {
+ {SignedCurve25519Name, qRound(signedKeysProportion * targetKeysNumber)},
+ {Curve25519Name, qRound((1-signedKeysProportion) * targetKeysNumber)}
+ };
+};
+
+EncryptionManager::EncryptionManager(const QByteArray &encryptionAccountPickle, float signedKeysProportion, float oneTimeKeyThreshold,
+ QObject* parent)
+ : QObject(parent),
+ d(std::make_unique<Private>(std::move(encryptionAccountPickle), std::move(signedKeysProportion), std::move(oneTimeKeyThreshold)))
+{
+
+}
+
+EncryptionManager::~EncryptionManager() = default;
+
+void EncryptionManager::uploadIdentityKeys(Connection* connection)
+{
+ // TODO
+}
+
+void EncryptionManager::uploadOneTimeKeys(Connection* connection, bool forceUpdate)
+{
+ // TODO
+}
+
+void EncryptionManager::Private::updateKeysToUpload()
+{
+ for (auto it = targetOneTimeKeyCounts.cbegin(); it != targetOneTimeKeyCounts.cend(); ++it)
+ {
+ int numKeys = oneTimeKeyCounts.value(it.key(), 0);
+ int numToCreate = qMax(it.value() - numKeys, 0);
+ oneTimeKeysToUploadCounts.insert(it.key(), numToCreate);
+ }
+}
+
+bool EncryptionManager::Private::oneTimeKeyShouldUpload()
+{
+ if (oneTimeKeyCounts.empty())
+ return true;
+ for (auto it = targetOneTimeKeyCounts.cbegin(); it != targetOneTimeKeyCounts.cend(); ++it)
+ {
+ if (oneTimeKeyCounts.value(it.key(), 0) < it.value() * oneTimeKeyThreshold)
+ return true;
+ }
+ return false;
+}
diff --git a/lib/encryptionmanager.h b/lib/encryptionmanager.h
new file mode 100644
index 00000000..0bd05432
--- /dev/null
+++ b/lib/encryptionmanager.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <QtCore/QObject>
+
+namespace QMatrixClient
+{
+ class Connection;
+
+ class EncryptionManager: public QObject
+ {
+ Q_OBJECT
+
+ public:
+ // TODO: store constats separately?
+ // TODO: 0.5 oneTimeKeyThreshold instead of 0.1?
+ explicit EncryptionManager(const QByteArray& encryptionAccountPickle, float signedKeysProportion = 1, float oneTimeKeyThreshold = float(0.1),
+ QObject* parent = nullptr);
+ ~EncryptionManager();
+
+ void uploadIdentityKeys(Connection* connection);
+ void uploadOneTimeKeys(Connection* connection, bool forceUpdate = false);
+
+ private:
+ class Private;
+ std::unique_ptr<Private> d;
+
+ };
+
+} // namespace QMatrixClient
diff --git a/lib/settings.cpp b/lib/settings.cpp
index 124d7042..5f10299c 100644
--- a/lib/settings.cpp
+++ b/lib/settings.cpp
@@ -90,6 +90,7 @@ QMC_DEFINE_SETTING(AccountSettings, bool, keepLoggedIn, "keep_logged_in", false,
static const auto HomeserverKey = QStringLiteral("homeserver");
static const auto AccessTokenKey = QStringLiteral("access_token");
+static const auto EncryptionAccountPickleKey = QStringLiteral("encryption_account_pickle");
QUrl AccountSettings::homeserver() const
{
@@ -114,7 +115,7 @@ QString AccountSettings::accessToken() const
void AccountSettings::setAccessToken(const QString& accessToken)
{
qCWarning(MAIN) << "Saving access_token to QSettings is insecure."
- " Developers, please save access_token separately.";
+ " Developers, do it manually or contribute to share QtKeychain logic to libQuotient.";
setValue(AccessTokenKey, accessToken);
}
@@ -124,3 +125,22 @@ void AccountSettings::clearAccessToken()
legacySettings.remove(QStringLiteral("device_id")); // Force the server to re-issue it
remove(AccessTokenKey);
}
+
+QByteArray AccountSettings::encryptionAccountPickle()
+{
+ QString passphrase = ""; // FIXME: add QtKeychain
+ return value("encryption_account_pickle", "").toByteArray();
+}
+
+void AccountSettings::setEncryptionAccountPickle(const QByteArray& encryptionAccountPickle)
+{
+ qCWarning(MAIN) << "Saving encryption_account_pickle to QSettings is insecure."
+ " Developers, do it manually or contribute to share QtKeychain logic to libQuotient.";
+ QString passphrase = ""; // FIXME: add QtKeychain
+ setValue("encryption_account_pickle", encryptionAccountPickle);
+}
+
+void AccountSettings::clearEncryptionAccountPickle()
+{
+ remove(EncryptionAccountPickleKey); // TODO: Force to re-issue it?
+}
diff --git a/lib/settings.h b/lib/settings.h
index 759bda35..61e5232a 100644
--- a/lib/settings.h
+++ b/lib/settings.h
@@ -131,6 +131,7 @@ void classname::setter(type newValue) \
QMC_DECLARE_SETTING(bool, keepLoggedIn, setKeepLoggedIn)
/** \deprecated \sa setAccessToken */
Q_PROPERTY(QString accessToken READ accessToken WRITE setAccessToken)
+ Q_PROPERTY(QByteArray encryptionAccountPickle READ encryptionAccountPickle WRITE setEncryptionAccountPickle)
public:
template <typename... ArgTs>
explicit AccountSettings(const QString& accountId, ArgTs... qsettingsArgs)
@@ -148,5 +149,9 @@ void classname::setter(type newValue) \
* see QMatrixClient/Quaternion#181 */
void setAccessToken(const QString& accessToken);
Q_INVOKABLE void clearAccessToken();
+
+ QByteArray encryptionAccountPickle();
+ void setEncryptionAccountPickle(const QByteArray& encryptionAccountPickle);
+ Q_INVOKABLE void clearEncryptionAccountPickle();
};
} // namespace QMatrixClient