aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-05-31 18:58:27 +0200
committerAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-05-31 18:58:27 +0200
commit21ae4eca4c06e500ec04a52ad42772bf8e8e9b6f (patch)
tree271fe41d8d9d0a5eecfd07d16973c30b4b1c9e8c
parent42811660094c88a4a1bfa8bd8ace5f4b148c246a (diff)
downloadlibquotient-21ae4eca4c06e500ec04a52ad42772bf8e8e9b6f.tar.gz
libquotient-21ae4eca4c06e500ec04a52ad42772bf8e8e9b6f.zip
Tweak QOlmAccount and data structures around
This is mainly to plug the definition of a string-to-variant map for one-time keys (see https://spec.matrix.org/v1.2/client-server-api/#key-algorithms) into the CS API generated code (see the "shortcut OneTimeKeys" commit for gtad.yaml); but along with it came considerable streamlining of code in qolmaccount.cpp. Using std::variant to store that map also warranted converters.h to gain support for that type (even wider than toJson() that is already in dev - a non-trivial merge from dev is in order).
-rw-r--r--autotests/testolmaccount.cpp18
-rw-r--r--lib/converters.h20
-rw-r--r--lib/e2ee/e2ee.h10
-rw-r--r--lib/e2ee/qolmaccount.cpp108
-rw-r--r--lib/e2ee/qolmaccount.h9
5 files changed, 73 insertions, 92 deletions
diff --git a/autotests/testolmaccount.cpp b/autotests/testolmaccount.cpp
index e31ff6d3..c85718dd 100644
--- a/autotests/testolmaccount.cpp
+++ b/autotests/testolmaccount.cpp
@@ -198,7 +198,7 @@ void TestOlmAccount::uploadIdentityKey()
QVERIFY(idKeys.curve25519.size() > 10);
- OneTimeKeys unused;
+ UnsignedOneTimeKeys unused;
auto request = olmAccount->createUploadKeyRequest(unused);
connect(request, &BaseJob::result, this, [request, conn] {
QCOMPARE(request->oneTimeKeyCounts().size(), 0);
@@ -221,7 +221,7 @@ void TestOlmAccount::uploadOneTimeKeys()
auto oneTimeKeys = olmAccount->oneTimeKeys();
- QHash<QString, QVariant> oneTimeKeysHash;
+ OneTimeKeys oneTimeKeysHash;
const auto curve = oneTimeKeys.curve25519();
for (const auto &[keyId, key] : asKeyValueRange(curve)) {
oneTimeKeysHash["curve25519:"+keyId] = key;
@@ -247,12 +247,10 @@ void TestOlmAccount::uploadSignedOneTimeKeys()
QCOMPARE(nKeys, 5);
auto oneTimeKeys = olmAccount->oneTimeKeys();
- QHash<QString, QVariant> oneTimeKeysHash;
+ OneTimeKeys oneTimeKeysHash;
const auto signedKey = olmAccount->signOneTimeKeys(oneTimeKeys);
for (const auto &[keyId, key] : asKeyValueRange(signedKey)) {
- QVariant var;
- var.setValue(key);
- oneTimeKeysHash[keyId] = var;
+ oneTimeKeysHash[keyId] = key;
}
auto request = new UploadKeysJob(none, oneTimeKeysHash);
connect(request, &BaseJob::result, this, [request, nKeys, conn] {
@@ -410,11 +408,9 @@ void TestOlmAccount::claimKeys()
// The key is the one bob sent.
const auto& oneTimeKey =
job->oneTimeKeys().value(userId).value(deviceId);
- QVERIFY(oneTimeKey.canConvert<QVariantMap>());
-
- const auto varMap = oneTimeKey.toMap();
- QVERIFY(std::any_of(varMap.constKeyValueBegin(),
- varMap.constKeyValueEnd(), [](const auto& kv) {
+ QVERIFY(std::any_of(oneTimeKey.constKeyValueBegin(),
+ oneTimeKey.constKeyValueEnd(),
+ [](const auto& kv) {
return kv.first.startsWith(
SignedCurve25519Key);
}));
diff --git a/lib/converters.h b/lib/converters.h
index 5e3becb8..64a5cfb6 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -224,6 +224,26 @@ struct QUOTIENT_API JsonConverter<QVariant> {
static QVariant load(const QJsonValue& jv);
};
+template <typename... Ts>
+inline QJsonValue toJson(const std::variant<Ts...>& v)
+{
+ // std::visit requires all overloads to return the same type - and
+ // QJsonValue is a perfect candidate for that same type (assuming that
+ // variants never occur on the top level in Matrix API)
+ return std::visit(
+ [](const auto& value) { return QJsonValue { toJson(value) }; }, v);
+}
+
+template <typename T>
+struct QUOTIENT_API JsonConverter<std::variant<QString, T>> {
+ static std::variant<QString, T> load(const QJsonValue& jv)
+ {
+ if (jv.isString())
+ return fromJson<QString>(jv);
+ return fromJson<T>(jv);
+ }
+};
+
template <typename T>
struct JsonConverter<Omittable<T>> {
static QJsonValue dump(const Omittable<T>& from)
diff --git a/lib/e2ee/e2ee.h b/lib/e2ee/e2ee.h
index 8e433d60..f97eb27a 100644
--- a/lib/e2ee/e2ee.h
+++ b/lib/e2ee/e2ee.h
@@ -70,15 +70,12 @@ struct IdentityKeys
};
//! Struct representing the one-time keys.
-struct QUOTIENT_API OneTimeKeys
+struct QUOTIENT_API UnsignedOneTimeKeys
{
QHash<QString, QHash<QString, QString>> keys;
//! Get the HashMap containing the curve25519 one-time keys.
- QHash<QString, QString> curve25519() const;
-
- //! Get a reference to the hashmap corresponding to given key type.
-// std::optional<QHash<QString, QString>> get(QString keyType) const;
+ QHash<QString, QString> curve25519() const { return keys[Curve25519Key]; }
};
//! Struct representing the signed one-time keys.
@@ -93,7 +90,6 @@ public:
QHash<QString, QHash<QString, QString>> signatures;
};
-
template <>
struct JsonObjectConverter<SignedOneTimeKey> {
static void fillFrom(const QJsonObject& jo, SignedOneTimeKey& result)
@@ -109,6 +105,8 @@ struct JsonObjectConverter<SignedOneTimeKey> {
}
};
+using OneTimeKeys = QHash<QString, std::variant<QString, SignedOneTimeKey>>;
+
template <typename T>
class asKeyValueRange
{
diff --git a/lib/e2ee/qolmaccount.cpp b/lib/e2ee/qolmaccount.cpp
index 72dddafb..4cfc6151 100644
--- a/lib/e2ee/qolmaccount.cpp
+++ b/lib/e2ee/qolmaccount.cpp
@@ -17,19 +17,6 @@
using namespace Quotient;
-QHash<QString, QString> OneTimeKeys::curve25519() const
-{
- return keys[Curve25519Key];
-}
-
-//std::optional<QHash<QString, QString>> OneTimeKeys::get(QString keyType) const
-//{
-// if (!keys.contains(keyType)) {
-// return std::nullopt;
-// }
-// return keys[keyType];
-//}
-
// Convert olm error to enum
QOlmError lastError(OlmAccount *account) {
return fromString(olm_account_last_error(account));
@@ -122,20 +109,15 @@ QByteArray QOlmAccount::sign(const QJsonObject &message) const
QByteArray QOlmAccount::signIdentityKeys() const
{
const auto keys = identityKeys();
- QJsonObject body
- {
- {"algorithms", QJsonArray{"m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"}},
- {"user_id", m_userId},
- {"device_id", m_deviceId},
- {"keys",
- QJsonObject{
- {QStringLiteral("curve25519:") + m_deviceId, QString::fromUtf8(keys.curve25519)},
- {QStringLiteral("ed25519:") + m_deviceId, QString::fromUtf8(keys.ed25519)}
- }
- }
- };
- return sign(QJsonDocument(body).toJson(QJsonDocument::Compact));
-
+ return sign(QJsonObject {
+ { "algorithms", QJsonArray { "m.olm.v1.curve25519-aes-sha2",
+ "m.megolm.v1.aes-sha2" } },
+ { "user_id", m_userId },
+ { "device_id", m_deviceId },
+ { "keys", QJsonObject { { QStringLiteral("curve25519:") + m_deviceId,
+ QString::fromUtf8(keys.curve25519) },
+ { QStringLiteral("ed25519:") + m_deviceId,
+ QString::fromUtf8(keys.ed25519) } } } });
}
size_t QOlmAccount::maxNumberOfOneTimeKeys() const
@@ -145,9 +127,13 @@ size_t QOlmAccount::maxNumberOfOneTimeKeys() const
size_t QOlmAccount::generateOneTimeKeys(size_t numberOfKeys)
{
- const size_t randomLength = olm_account_generate_one_time_keys_random_length(m_account, numberOfKeys);
+ const size_t randomLength =
+ olm_account_generate_one_time_keys_random_length(m_account,
+ numberOfKeys);
QByteArray randomBuffer = getRandom(randomLength);
- const auto error = olm_account_generate_one_time_keys(m_account, numberOfKeys, randomBuffer.data(), randomLength);
+ const auto error =
+ olm_account_generate_one_time_keys(m_account, numberOfKeys,
+ randomBuffer.data(), randomLength);
if (error == olm_error()) {
throw lastError(m_account);
@@ -156,7 +142,7 @@ size_t QOlmAccount::generateOneTimeKeys(size_t numberOfKeys)
return error;
}
-OneTimeKeys QOlmAccount::oneTimeKeys() const
+UnsignedOneTimeKeys QOlmAccount::oneTimeKeys() const
{
const size_t oneTimeKeyLength = olm_account_one_time_keys_length(m_account);
QByteArray oneTimeKeysBuffer(oneTimeKeyLength, '0');
@@ -166,34 +152,25 @@ OneTimeKeys QOlmAccount::oneTimeKeys() const
throw lastError(m_account);
}
const auto json = QJsonDocument::fromJson(oneTimeKeysBuffer).object();
- OneTimeKeys oneTimeKeys;
+ UnsignedOneTimeKeys oneTimeKeys;
fromJson(json, oneTimeKeys.keys);
return oneTimeKeys;
}
-QHash<QString, SignedOneTimeKey> QOlmAccount::signOneTimeKeys(const OneTimeKeys &keys) const
+OneTimeKeys QOlmAccount::signOneTimeKeys(const UnsignedOneTimeKeys &keys) const
{
- QHash<QString, SignedOneTimeKey> signedOneTimeKeys;
- for (const auto &keyid : keys.curve25519().keys()) {
- const auto oneTimeKey = keys.curve25519()[keyid];
- QByteArray sign = signOneTimeKey(oneTimeKey);
- signedOneTimeKeys["signed_curve25519:" + keyid] = signedOneTimeKey(oneTimeKey.toUtf8(), sign);
- }
+ OneTimeKeys signedOneTimeKeys;
+ const auto& curveKeys = keys.curve25519();
+ for (const auto& [keyId, key] : asKeyValueRange(curveKeys))
+ signedOneTimeKeys["signed_curve25519:" % keyId] =
+ signedOneTimeKey(key.toUtf8(), sign(QJsonObject{{"key", key}}));
return signedOneTimeKeys;
}
-SignedOneTimeKey QOlmAccount::signedOneTimeKey(const QByteArray &key, const QString &signature) const
+SignedOneTimeKey QOlmAccount::signedOneTimeKey(const QByteArray& key,
+ const QString& signature) const
{
- SignedOneTimeKey sign{};
- sign.key = key;
- sign.signatures = {{m_userId, {{"ed25519:" + m_deviceId, signature}}}};
- return sign;
-}
-
-QByteArray QOlmAccount::signOneTimeKey(const QString &key) const
-{
- QJsonDocument j(QJsonObject{{"key", key}});
- return sign(j.toJson(QJsonDocument::Compact));
+ return { key, { { m_userId, { { "ed25519:" + m_deviceId, signature } } } } };
}
std::optional<QOlmError> QOlmAccount::removeOneTimeKeys(
@@ -227,39 +204,32 @@ DeviceKeys QOlmAccount::deviceKeys() const
return deviceKeys;
}
-UploadKeysJob *QOlmAccount::createUploadKeyRequest(const OneTimeKeys &oneTimeKeys)
+UploadKeysJob* QOlmAccount::createUploadKeyRequest(
+ const UnsignedOneTimeKeys& oneTimeKeys) const
{
- auto keys = deviceKeys();
-
- if (oneTimeKeys.curve25519().isEmpty()) {
- return new UploadKeysJob(keys);
- }
-
- // Sign & append the one time keys.
- auto temp = signOneTimeKeys(oneTimeKeys);
- QHash<QString, QVariant> oneTimeKeysSigned;
- for (const auto &[keyId, key] : asKeyValueRange(temp)) {
- oneTimeKeysSigned[keyId] = QVariant::fromValue(toJson(key));
- }
-
- return new UploadKeysJob(keys, oneTimeKeysSigned);
+ return new UploadKeysJob(deviceKeys(), signOneTimeKeys(oneTimeKeys));
}
-QOlmExpected<QOlmSessionPtr> QOlmAccount::createInboundSession(const QOlmMessage &preKeyMessage)
+QOlmExpected<QOlmSessionPtr> QOlmAccount::createInboundSession(
+ const QOlmMessage& preKeyMessage)
{
Q_ASSERT(preKeyMessage.type() == QOlmMessage::PreKey);
return QOlmSession::createInboundSession(this, preKeyMessage);
}
-QOlmExpected<QOlmSessionPtr> QOlmAccount::createInboundSessionFrom(const QByteArray &theirIdentityKey, const QOlmMessage &preKeyMessage)
+QOlmExpected<QOlmSessionPtr> QOlmAccount::createInboundSessionFrom(
+ const QByteArray& theirIdentityKey, const QOlmMessage& preKeyMessage)
{
Q_ASSERT(preKeyMessage.type() == QOlmMessage::PreKey);
- return QOlmSession::createInboundSessionFrom(this, theirIdentityKey, preKeyMessage);
+ return QOlmSession::createInboundSessionFrom(this, theirIdentityKey,
+ preKeyMessage);
}
-QOlmExpected<QOlmSessionPtr> QOlmAccount::createOutboundSession(const QByteArray &theirIdentityKey, const QByteArray &theirOneTimeKey)
+QOlmExpected<QOlmSessionPtr> QOlmAccount::createOutboundSession(
+ const QByteArray& theirIdentityKey, const QByteArray& theirOneTimeKey)
{
- return QOlmSession::createOutboundSession(this, theirIdentityKey, theirOneTimeKey);
+ return QOlmSession::createOutboundSession(this, theirIdentityKey,
+ theirOneTimeKey);
}
void QOlmAccount::markKeysAsPublished()
diff --git a/lib/e2ee/qolmaccount.h b/lib/e2ee/qolmaccount.h
index ee2aa69d..23fe58dd 100644
--- a/lib/e2ee/qolmaccount.h
+++ b/lib/e2ee/qolmaccount.h
@@ -59,17 +59,14 @@ public:
size_t generateOneTimeKeys(size_t numberOfKeys);
//! Gets the OlmAccount's one time keys formatted as JSON.
- OneTimeKeys oneTimeKeys() const;
+ UnsignedOneTimeKeys oneTimeKeys() const;
//! Sign all one time keys.
- QHash<QString, SignedOneTimeKey> signOneTimeKeys(const OneTimeKeys &keys) const;
-
- //! Sign one time key.
- QByteArray signOneTimeKey(const QString &key) const;
+ OneTimeKeys signOneTimeKeys(const UnsignedOneTimeKeys &keys) const;
SignedOneTimeKey signedOneTimeKey(const QByteArray &key, const QString &signature) const;
- UploadKeysJob *createUploadKeyRequest(const OneTimeKeys &oneTimeKeys);
+ UploadKeysJob* createUploadKeyRequest(const UnsignedOneTimeKeys& oneTimeKeys) const;
DeviceKeys deviceKeys() const;