diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-05-31 18:58:27 +0200 |
---|---|---|
committer | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-05-31 18:58:27 +0200 |
commit | 21ae4eca4c06e500ec04a52ad42772bf8e8e9b6f (patch) | |
tree | 271fe41d8d9d0a5eecfd07d16973c30b4b1c9e8c | |
parent | 42811660094c88a4a1bfa8bd8ace5f4b148c246a (diff) | |
download | libquotient-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.cpp | 18 | ||||
-rw-r--r-- | lib/converters.h | 20 | ||||
-rw-r--r-- | lib/e2ee/e2ee.h | 10 | ||||
-rw-r--r-- | lib/e2ee/qolmaccount.cpp | 108 | ||||
-rw-r--r-- | lib/e2ee/qolmaccount.h | 9 |
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; |