diff options
| -rw-r--r-- | src/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/client/QXmppAtmManager.cpp | 23 | ||||
| -rw-r--r-- | src/client/QXmppAtmManager.h | 11 | ||||
| -rw-r--r-- | src/client/QXmppAtmTrustMemoryStorage.cpp | 145 | ||||
| -rw-r--r-- | src/client/QXmppAtmTrustMemoryStorage.h | 33 | ||||
| -rw-r--r-- | src/client/QXmppAtmTrustStorage.cpp | 80 | ||||
| -rw-r--r-- | src/client/QXmppAtmTrustStorage.h | 24 | ||||
| -rw-r--r-- | src/client/QXmppTrustMemoryStorage.cpp | 221 | ||||
| -rw-r--r-- | src/client/QXmppTrustMemoryStorage.h | 21 | ||||
| -rw-r--r-- | src/client/QXmppTrustStorage.cpp | 142 | ||||
| -rw-r--r-- | src/client/QXmppTrustStorage.h | 33 | ||||
| -rw-r--r-- | tests/qxmppatmmanager/tst_qxmppatmmanager.cpp | 16 | ||||
| -rw-r--r-- | tests/qxmpptrustmemorystorage/tst_qxmpptrustmemorystorage.cpp | 550 |
13 files changed, 978 insertions, 325 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1efd3c21..5f1e5eb5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -91,6 +91,8 @@ set(INSTALL_HEADER_FILES # Client client/QXmppArchiveManager.h client/QXmppAtmManager.h + client/QXmppAtmTrustMemoryStorage.h + client/QXmppAtmTrustStorage.h client/QXmppAttentionManager.h client/QXmppBookmarkManager.h client/QXmppCarbonManager.h @@ -196,6 +198,8 @@ set(SOURCE_FILES # Client client/QXmppArchiveManager.cpp client/QXmppAtmManager.cpp + client/QXmppAtmTrustMemoryStorage.cpp + client/QXmppAtmTrustStorage.cpp client/QXmppAttentionManager.cpp client/QXmppBookmarkManager.cpp client/QXmppCarbonManager.cpp diff --git a/src/client/QXmppAtmManager.cpp b/src/client/QXmppAtmManager.cpp index 4155e993..c4fe2cad 100644 --- a/src/client/QXmppAtmManager.cpp +++ b/src/client/QXmppAtmManager.cpp @@ -8,13 +8,11 @@ #include "QXmppClient.h" #include "QXmppConstants_p.h" #include "QXmppFutureUtils_p.h" +#include "QXmppMessage.h" #include "QXmppTrustMessageElement.h" +#include "QXmppTrustMessageKeyOwner.h" #include "QXmppUtils.h" -#include <QCoreApplication> -#include <QDomElement> -#include <QList> - using namespace QXmpp::Private; /// @@ -27,21 +25,10 @@ using namespace QXmpp::Private; /// storage interface must be added. /// That implementation has to be adapted to your storage such as a database. /// In case you only need memory and no peristent storage, you can use the -/// existing implementation: +/// existing implementation and add the storage with it: /// ///\code -/// QXmppTrustStorage *trustStorage = new QXmppTrustMemoryStorage; -/// \endcode -/// -/// You can set a security policy used by ATM via the trust manager. -/// Is is recommended to apply TOAKAFA for good security and usability when -/// using \xep{0384, OMEMO Encryption}: -/// \code -/// trustStorage->setSecurityPolicy("urn:xmpp:omemo:2", QXmppTrustStorage::Toakafa); -/// \endcode -/// -/// Afterwards, this manager must be added with the storage: -/// \code +/// QXmppAtmTrustStorage *trustStorage = new QXmppAtmTrustMemoryStorage; /// QXmppAtmManager *manager = new QXmppAtmManager(trustStorage); /// client->addExtension(manager); /// \endcode @@ -73,7 +60,7 @@ using namespace QXmpp::Private; /// /// \param trustStorage trust storage implementation /// -QXmppAtmManager::QXmppAtmManager(QXmppTrustStorage *trustStorage) +QXmppAtmManager::QXmppAtmManager(QXmppAtmTrustStorage *trustStorage) { m_trustStorage = trustStorage; } diff --git a/src/client/QXmppAtmManager.h b/src/client/QXmppAtmManager.h index 5c2dc1e7..042d1342 100644 --- a/src/client/QXmppAtmManager.h +++ b/src/client/QXmppAtmManager.h @@ -5,18 +5,19 @@ #ifndef QXMPPATMMANAGER_H #define QXMPPATMMANAGER_H +#include "QXmppAtmTrustStorage.h" #include "QXmppClientExtension.h" -#include "QXmppMessage.h" #include "QXmppSendResult.h" -#include "QXmppTrustMessageKeyOwner.h" -#include "QXmppTrustStorage.h" + +class QXmppMessage; +class QXmppTrustMessageKeyOwner; class QXMPP_EXPORT QXmppAtmManager : public QXmppClientExtension { Q_OBJECT public: - QXmppAtmManager(QXmppTrustStorage *trustStorage); + QXmppAtmManager(QXmppAtmTrustStorage *trustStorage); QFuture<void> makeTrustDecisions(const QString &encryption, const QString &keyOwnerJid, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting = {}); /// \cond @@ -41,7 +42,7 @@ private: QFuture<QXmpp::SendResult> sendTrustMessage(const QString &encryption, const QList<QXmppTrustMessageKeyOwner> &keyOwners, const QString &recipientJid); - QXmppTrustStorage *m_trustStorage; + QXmppAtmTrustStorage *m_trustStorage; friend class tst_QXmppAtmManager; }; diff --git a/src/client/QXmppAtmTrustMemoryStorage.cpp b/src/client/QXmppAtmTrustMemoryStorage.cpp new file mode 100644 index 00000000..404c5564 --- /dev/null +++ b/src/client/QXmppAtmTrustMemoryStorage.cpp @@ -0,0 +1,145 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "QXmppAtmTrustMemoryStorage.h" + +#include "QXmppFutureUtils_p.h" +#include "QXmppTrustMessageKeyOwner.h" + +using namespace QXmpp::Private; + +/// +/// \class QXmppAtmTrustMemoryStorage +/// +/// \brief The QXmppAtmTrustMemoryStorage class stores trust data for +/// \xep{0450, Automatic Trust Management (ATM)} in the memory. +/// +/// \warning THIS API IS NOT FINALIZED YET! +/// +/// \since QXmpp 1.5 +/// + +struct UnprocessedKey +{ + QByteArray id; + QString ownerJid; + QByteArray senderKeyId; + bool trust; +}; + +class QXmppAtmTrustMemoryStoragePrivate +{ +public: + // encryption protocols mapped to trust message data received from endpoints + // with unauthenticated keys + QMultiHash<QString, UnprocessedKey> keys; +}; + +/// +/// Constructs an ATM trust memory storage. +/// +QXmppAtmTrustMemoryStorage::QXmppAtmTrustMemoryStorage() + : d(new QXmppAtmTrustMemoryStoragePrivate) +{ +} + +QXmppAtmTrustMemoryStorage::~QXmppAtmTrustMemoryStorage() = default; + +/// \cond +QFuture<void> QXmppAtmTrustMemoryStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners) +{ + const auto addKeys = [&](const QXmppTrustMessageKeyOwner &keyOwner, bool trust, const QList<QByteArray> &keyIds) { + for (const auto &keyId : keyIds) { + auto isKeyFound = false; + + for (auto itr = d->keys.find(encryption); itr != d->keys.end() && itr.key() == encryption; ++itr) { + auto &key = itr.value(); + if (key.id == keyId && key.ownerJid == keyOwner.jid() && key.senderKeyId == senderKeyId) { + // Update the stored trust if it differs from the new one. + if (key.trust != trust) { + key.trust = trust; + } + + isKeyFound = true; + break; + } + } + + // Create a new entry and store it if there is no such entry yet. + if (!isKeyFound) { + UnprocessedKey key; + key.id = keyId; + key.ownerJid = keyOwner.jid(); + key.senderKeyId = senderKeyId; + key.trust = trust; + d->keys.insert(encryption, key); + } + } + }; + + for (const auto &keyOwner : keyOwners) { + addKeys(keyOwner, true, keyOwner.trustedKeys()); + addKeys(keyOwner, false, keyOwner.distrustedKeys()); + } + + return makeReadyFuture(); +} + +QFuture<void> QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting) +{ + for (auto itr = d->keys.find(encryption); + itr != d->keys.end() && itr.key() == encryption;) { + const auto &key = itr.value(); + if ((key.trust && keyIdsForAuthentication.contains(key.id)) || + (!key.trust && keyIdsForDistrusting.contains(key.id))) { + itr = d->keys.erase(itr); + } else { + ++itr; + } + } + + return makeReadyFuture(); +} + +QFuture<void> QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds) +{ + for (auto itr = d->keys.find(encryption); + itr != d->keys.end() && itr.key() == encryption;) { + if (senderKeyIds.contains(itr.value().senderKeyId)) { + itr = d->keys.erase(itr); + } else { + ++itr; + } + } + + return makeReadyFuture(); +} + +QFuture<void> QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption) +{ + d->keys.remove(encryption); + return makeReadyFuture(); +} + +QFuture<QHash<bool, QMultiHash<QString, QByteArray>>> QXmppAtmTrustMemoryStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds) +{ + QHash<bool, QMultiHash<QString, QByteArray>> keys; + + const auto storedKeys = d->keys.values(encryption); + for (const auto &key : storedKeys) { + if (senderKeyIds.contains(key.senderKeyId) || senderKeyIds.isEmpty()) { + keys[key.trust].insert(key.ownerJid, key.id); + } + } + + return makeReadyFuture(std::move(keys)); +} + +QFuture<void> QXmppAtmTrustMemoryStorage::resetAll(const QString &encryption) +{ + QXmppTrustMemoryStorage::resetAll(encryption); + d->keys.remove(encryption); + return makeReadyFuture(); +} +/// \endcond diff --git a/src/client/QXmppAtmTrustMemoryStorage.h b/src/client/QXmppAtmTrustMemoryStorage.h new file mode 100644 index 00000000..432c2058 --- /dev/null +++ b/src/client/QXmppAtmTrustMemoryStorage.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPATMTRUSTMEMORYSTORAGE_H +#define QXMPPATMTRUSTMEMORYSTORAGE_H + +#include "QXmppAtmTrustStorage.h" +#include "QXmppTrustMemoryStorage.h" + +class QXmppAtmTrustMemoryStoragePrivate; + +class QXMPP_EXPORT QXmppAtmTrustMemoryStorage : virtual public QXmppAtmTrustStorage, public QXmppTrustMemoryStorage +{ +public: + QXmppAtmTrustMemoryStorage(); + ~QXmppAtmTrustMemoryStorage(); + + /// \cond + QFuture<void> addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners) override; + QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting) override; + QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds) override; + QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption) override; + QFuture<QHash<bool, QMultiHash<QString, QByteArray>>> keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds = {}) override; + + QFuture<void> resetAll(const QString &encryption) override; + /// \endcond + +private: + std::unique_ptr<QXmppAtmTrustMemoryStoragePrivate> d; +}; + +#endif // QXMPPATMTRUSTMEMORYSTORAGE_H diff --git a/src/client/QXmppAtmTrustStorage.cpp b/src/client/QXmppAtmTrustStorage.cpp new file mode 100644 index 00000000..70ce2822 --- /dev/null +++ b/src/client/QXmppAtmTrustStorage.cpp @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +/// +/// \class QXmppAtmTrustStorage +/// +/// \brief The QXmppAtmTrustStorage class stores trust data for +/// \xep{0450, Automatic Trust Management (ATM)}. +/// +/// \warning THIS API IS NOT FINALIZED YET! +/// +/// \since QXmpp 1.5 +/// + +/// +/// \fn QXmppAtmTrustStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners) +/// +/// Adds keys that cannot be authenticated or distrusted directly because the +/// key of the trust message's sender is not yet authenticated. +/// +/// Those keys are being authenticated or distrusted once the sender's key is +/// authenticated. +/// Each element of keyOwners (i.e., keyOwner) can contain keys for postponed +/// authentication as trustedKeys or for postponed distrusting as +/// distrustedKeys. +/// +/// If keys of keyOwner.trustedKeys() are already stored for postponed +/// distrusting, they are changed to be used for postponed authentication. +/// If keys of keyOwner.distrustedKeys() are already stored for postponed +/// authentication, they are changed to be used for postponed distrusting. +/// If the same keys are in keyOwner.trustedKeys() and +/// keyOwner.distrustedKeys(), they are used for postponed distrusting. +/// +/// \param encryption encryption protocol namespace +/// \param senderKeyId key ID of the trust message's sender +/// \param keyOwners key owners containing key IDs for postponed trust decisions +/// + +/// +/// \fn QXmppAtmTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting) +/// +/// Removes keys for postponed authentication or distrusting. +/// +/// \param encryption encryption protocol namespace +/// \param keyIdsForAuthentication IDs of the keys for postponed authentication +/// \param keyIdsForDistrusting IDs of the keys for postponed distrusting +/// + +/// +/// \fn QXmppAtmTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds) +/// +/// Removes keys for postponed authentication or distrusting by the trust +/// message sender's key ID. +/// +/// \param encryption encryption protocol namespace +/// \param senderKeyIds key IDs of the trust messages' senders +/// + +/// +/// \fn QXmppAtmTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption) +/// +/// Removes all keys for postponed authentication or distrusting for encryption. +/// +/// \param encryption encryption protocol namespace +/// + +/// +/// \fn QXmppAtmTrustStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds = {}) +/// +/// Returns the JIDs of key owners mapped to the IDs of their keys stored for +/// postponed authentication (true) or postponed distrusting (false). +/// +/// If senderKeyIds is empty, all keys for encryption are returned. +/// +/// \param encryption encryption protocol namespace +/// \param senderKeyIds key IDs of the trust messages' senders +/// +/// \return the key owner JIDs mapped to their keys +/// diff --git a/src/client/QXmppAtmTrustStorage.h b/src/client/QXmppAtmTrustStorage.h new file mode 100644 index 00000000..e801c7df --- /dev/null +++ b/src/client/QXmppAtmTrustStorage.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPATMTRUSTSTORAGE_H +#define QXMPPATMTRUSTSTORAGE_H + +#include "QXmppTrustStorage.h" + +class QXmppTrustMessageKeyOwner; + +class QXMPP_EXPORT QXmppAtmTrustStorage : virtual public QXmppTrustStorage +{ +public: + virtual ~QXmppAtmTrustStorage() = default; + + virtual QFuture<void> addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners) = 0; + virtual QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting) = 0; + virtual QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds) = 0; + virtual QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption) = 0; + virtual QFuture<QHash<bool, QMultiHash<QString, QByteArray>>> keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds = {}) = 0; +}; + +#endif // QXMPPATMTRUSTSTORAGE_H diff --git a/src/client/QXmppTrustMemoryStorage.cpp b/src/client/QXmppTrustMemoryStorage.cpp index f5e99b33..5a1b6e61 100644 --- a/src/client/QXmppTrustMemoryStorage.cpp +++ b/src/client/QXmppTrustMemoryStorage.cpp @@ -5,7 +5,6 @@ #include "QXmppTrustMemoryStorage.h" #include "QXmppFutureUtils_p.h" -#include "QXmppTrustMessageKeyOwner.h" using namespace QXmpp::Private; @@ -20,21 +19,13 @@ using namespace QXmpp::Private; /// \since QXmpp 1.5 /// -struct ProcessedKey +struct Key { QByteArray id; QString ownerJid; QXmppTrustStorage::TrustLevel trustLevel; }; -struct UnprocessedKey -{ - QByteArray id; - QString ownerJid; - QByteArray senderKeyId; - bool trust; -}; - class QXmppTrustMemoryStoragePrivate { public: @@ -45,11 +36,7 @@ public: QMap<QString, QByteArray> ownKeys; // encryption protocols mapped to keys with specified trust levels - QMultiHash<QString, ProcessedKey> processedKeys; - - // encryption protocols mapped to trust message data received from endpoints - // with unauthenticated keys - QMultiHash<QString, UnprocessedKey> unprocessedKeys; + QMultiHash<QString, Key> keys; }; /// @@ -63,16 +50,15 @@ QXmppTrustMemoryStorage::QXmppTrustMemoryStorage() QXmppTrustMemoryStorage::~QXmppTrustMemoryStorage() = default; /// \cond -QFuture<void> QXmppTrustMemoryStorage::setSecurityPolicies(const QString &encryption, const QXmppTrustStorage::SecurityPolicy securityPolicy) +QFuture<void> QXmppTrustMemoryStorage::setSecurityPolicy(const QString &encryption, const QXmppTrustStorage::SecurityPolicy securityPolicy) { - if (encryption.isEmpty()) { - d->securityPolicies.clear(); - } else if (securityPolicy == QXmppTrustStorage::NoSecurityPolicy) { - d->securityPolicies.remove(encryption); - } else { - d->securityPolicies.insert(encryption, securityPolicy); - } + d->securityPolicies.insert(encryption, securityPolicy); + return makeReadyFuture(); +} +QFuture<void> QXmppTrustMemoryStorage::resetSecurityPolicy(const QString &encryption) +{ + d->securityPolicies.remove(encryption); return makeReadyFuture(); } @@ -81,13 +67,13 @@ QFuture<QXmppTrustStorage::SecurityPolicy> QXmppTrustMemoryStorage::securityPoli return makeReadyFuture(std::move(d->securityPolicies.value(encryption))); } -QFuture<void> QXmppTrustMemoryStorage::addOwnKey(const QString &encryption, const QByteArray &keyId) +QFuture<void> QXmppTrustMemoryStorage::setOwnKey(const QString &encryption, const QByteArray &keyId) { d->ownKeys.insert(encryption, keyId); return makeReadyFuture(); } -QFuture<void> QXmppTrustMemoryStorage::removeOwnKey(const QString &encryption) +QFuture<void> QXmppTrustMemoryStorage::resetOwnKey(const QString &encryption) { d->ownKeys.remove(encryption); return makeReadyFuture(); @@ -102,11 +88,11 @@ QFuture<QByteArray> QXmppTrustMemoryStorage::ownKey(const QString &encryption) QFuture<void> QXmppTrustMemoryStorage::addKeys(const QString &encryption, const QString &keyOwnerJid, const QList<QByteArray> &keyIds, const QXmppTrustStorage::TrustLevel trustLevel) { for (const auto &keyId : keyIds) { - ProcessedKey key; + Key key; key.id = keyId; key.ownerJid = keyOwnerJid; key.trustLevel = trustLevel; - d->processedKeys.insert(encryption, key); + d->keys.insert(encryption, key); } return makeReadyFuture(); @@ -114,30 +100,44 @@ QFuture<void> QXmppTrustMemoryStorage::addKeys(const QString &encryption, const QFuture<void> QXmppTrustMemoryStorage::removeKeys(const QString &encryption, const QList<QByteArray> &keyIds) { - if (encryption.isEmpty()) { - d->processedKeys.clear(); - } else if (keyIds.isEmpty()) { - d->processedKeys.remove(encryption); - } else { - for (auto itr = d->processedKeys.find(encryption); - itr != d->processedKeys.end() && itr.key() == encryption;) { - if (keyIds.contains(itr.value().id)) { - itr = d->processedKeys.erase(itr); - } else { - itr++; - } + for (auto itr = d->keys.find(encryption); + itr != d->keys.end() && itr.key() == encryption;) { + if (keyIds.contains(itr.value().id)) { + itr = d->keys.erase(itr); + } else { + ++itr; } } return makeReadyFuture(); } +QFuture<void> QXmppTrustMemoryStorage::removeKeys(const QString &encryption, const QString &keyOwnerJid) +{ + for (auto itr = d->keys.find(encryption); + itr != d->keys.end() && itr.key() == encryption;) { + if (itr.value().ownerJid == keyOwnerJid) { + itr = d->keys.erase(itr); + } else { + ++itr; + } + } + + return makeReadyFuture(); +} + +QFuture<void> QXmppTrustMemoryStorage::removeKeys(const QString &encryption) +{ + d->keys.remove(encryption); + return makeReadyFuture(); +} + QFuture<QHash<QXmppTrustStorage::TrustLevel, QMultiHash<QString, QByteArray>>> QXmppTrustMemoryStorage::keys(const QString &encryption, const TrustLevels trustLevels) { QHash<TrustLevel, QMultiHash<QString, QByteArray>> keys; - const auto processedKeys = d->processedKeys.values(encryption); - for (const auto &key : processedKeys) { + const auto storedKeys = d->keys.values(encryption); + for (const auto &key : storedKeys) { const auto trustLevel = key.trustLevel; if (trustLevels.testFlag(trustLevel) || !trustLevels) { keys[trustLevel].insert(key.ownerJid, key.id); @@ -147,6 +147,34 @@ QFuture<QHash<QXmppTrustStorage::TrustLevel, QMultiHash<QString, QByteArray>>> Q return makeReadyFuture(std::move(keys)); } +QFuture<QHash<QString, QHash<QByteArray, QXmppTrustStorage::TrustLevel>>> QXmppTrustMemoryStorage::keys(const QString &encryption, const QList<QString> &keyOwnerJids, TrustLevels trustLevels) +{ + QHash<QString, QHash<QByteArray, QXmppTrustStorage::TrustLevel>> keys; + + const auto storedKeys = d->keys.values(encryption); + for (const auto &key : storedKeys) { + const auto keyOwnerJid = key.ownerJid; + const auto trustLevel = key.trustLevel; + if (keyOwnerJids.contains(keyOwnerJid) && (trustLevels.testFlag(trustLevel) || !trustLevels)) { + keys[keyOwnerJid].insert(key.id, trustLevel); + } + } + + return makeReadyFuture(std::move(keys)); +} + +QFuture<bool> QXmppTrustMemoryStorage::hasKey(const QString &encryption, const QString &keyOwnerJid, TrustLevels trustLevels) +{ + const auto storedKeys = d->keys.values(encryption); + for (const auto &key : storedKeys) { + if (key.ownerJid == keyOwnerJid && trustLevels.testFlag(key.trustLevel)) { + return makeReadyFuture(std::move(true)); + } + } + + return makeReadyFuture(std::move(false)); +} + QFuture<void> QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, const QMultiHash<QString, QByteArray> &keyIds, const TrustLevel trustLevel) { for (auto itr = keyIds.constBegin(); itr != keyIds.constEnd(); ++itr) { @@ -155,13 +183,13 @@ QFuture<void> QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, auto isKeyFound = false; - for (auto itrProcessedKeys = d->processedKeys.find(encryption); - itrProcessedKeys != d->processedKeys.end() && itrProcessedKeys.key() == encryption; - ++itrProcessedKeys) { - auto &key = itrProcessedKeys.value(); + for (auto itrKeys = d->keys.find(encryption); + itrKeys != d->keys.end() && itrKeys.key() == encryption; + ++itrKeys) { + auto &key = itrKeys.value(); if (key.id == keyId && key.ownerJid == keyOwnerJid) { + // Update the stored trust level if it differs from the new one. if (key.trustLevel != trustLevel) { - // Update the stored trust level if it differs from the new one. key.trustLevel = trustLevel; } @@ -170,13 +198,13 @@ QFuture<void> QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, } } + // Create a new entry and store it if there is no such entry yet. if (!isKeyFound) { - // Create a new entry and store it if there is no such entry yet. - ProcessedKey key; + Key key; key.id = keyId; key.ownerJid = keyOwnerJid; key.trustLevel = trustLevel; - d->processedKeys.insert(encryption, key); + d->keys.insert(encryption, key); } } @@ -185,7 +213,7 @@ QFuture<void> QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, QFuture<void> QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, const QList<QString> &keyOwnerJids, const QXmppTrustStorage::TrustLevel oldTrustLevel, const QXmppTrustStorage::TrustLevel newTrustLevel) { - for (auto itr = d->processedKeys.find(encryption); itr != d->processedKeys.end() && itr.key() == encryption; ++itr) { + for (auto itr = d->keys.find(encryption); itr != d->keys.end() && itr.key() == encryption; ++itr) { auto &key = itr.value(); if (keyOwnerJids.contains(key.ownerJid) && key.trustLevel == oldTrustLevel) { key.trustLevel = newTrustLevel; @@ -197,101 +225,22 @@ QFuture<void> QXmppTrustMemoryStorage::setTrustLevel(const QString &encryption, QFuture<QXmppTrustStorage::TrustLevel> QXmppTrustMemoryStorage::trustLevel(const QString &encryption, const QByteArray &keyId) { - const auto processedKeys = d->processedKeys.values(encryption); - for (const auto &key : processedKeys) { + const auto keys = d->keys.values(encryption); + for (const auto &key : keys) { if (key.id == keyId) { return makeReadyFuture(std::move(QXmppTrustStorage::TrustLevel(key.trustLevel))); } } - return makeReadyFuture(std::move(TrustLevel::AutomaticallyDistrusted)); -} - -QFuture<void> QXmppTrustMemoryStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners) -{ - const auto addKeys = [&](const QXmppTrustMessageKeyOwner &keyOwner, bool trust, const QList<QByteArray> &keyIds) { - for (const auto &keyId : keyIds) { - auto isKeyFound = false; - - for (auto itr = d->unprocessedKeys.find(encryption); itr != d->unprocessedKeys.end() && itr.key() == encryption; ++itr) { - auto &key = itr.value(); - if (key.id == keyId && key.ownerJid == keyOwner.jid() && key.senderKeyId == senderKeyId) { - if (key.trust != trust) { - // Update the stored trust if it differs from the new one. - key.trust = trust; - } - - isKeyFound = true; - break; - } - } - - if (!isKeyFound) { - // Create a new entry and store it if there is no such entry yet. - UnprocessedKey key; - key.id = keyId; - key.ownerJid = keyOwner.jid(); - key.senderKeyId = senderKeyId; - key.trust = trust; - d->unprocessedKeys.insert(encryption, key); - } - } - }; - - for (const auto &keyOwner : keyOwners) { - addKeys(keyOwner, true, keyOwner.trustedKeys()); - addKeys(keyOwner, false, keyOwner.distrustedKeys()); - } - - return makeReadyFuture(); -} - -QFuture<void> QXmppTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting) -{ - for (auto itr = d->unprocessedKeys.find(encryption); - itr != d->unprocessedKeys.end() && itr.key() == encryption;) { - const auto &key = itr.value(); - if ((key.trust && keyIdsForAuthentication.contains(key.id)) || - (!key.trust && keyIdsForDistrusting.contains(key.id))) { - itr = d->unprocessedKeys.erase(itr); - } else { - ++itr; - } - } - return makeReadyFuture(); + return makeReadyFuture(std::move(QXmppTrustStorage::Undecided)); } -QFuture<void> QXmppTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds) +QFuture<void> QXmppTrustMemoryStorage::resetAll(const QString &encryption) { - if (encryption.isEmpty()) { - d->unprocessedKeys.clear(); - } else if (senderKeyIds.isEmpty()) { - d->unprocessedKeys.remove(encryption); - } else { - for (auto itr = d->unprocessedKeys.find(encryption); - itr != d->unprocessedKeys.end() && itr.key() == encryption;) { - if (senderKeyIds.contains(itr.value().senderKeyId)) { - itr = d->unprocessedKeys.erase(itr); - } else { - ++itr; - } - } - } + d->securityPolicies.remove(encryption); + d->ownKeys.remove(encryption); + d->keys.remove(encryption); return makeReadyFuture(); } - -QFuture<QHash<bool, QMultiHash<QString, QByteArray>>> QXmppTrustMemoryStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds) -{ - QHash<bool, QMultiHash<QString, QByteArray>> keys; - - const auto unprocessedKeys = d->unprocessedKeys.values(encryption); - for (const auto &key : unprocessedKeys) { - if (senderKeyIds.contains(key.senderKeyId) || senderKeyIds.isEmpty()) { - keys[key.trust].insert(key.ownerJid, key.id); - } - } - - return makeReadyFuture(std::move(keys)); -} /// \endcond diff --git a/src/client/QXmppTrustMemoryStorage.h b/src/client/QXmppTrustMemoryStorage.h index 63b8a14e..08696039 100644 --- a/src/client/QXmppTrustMemoryStorage.h +++ b/src/client/QXmppTrustMemoryStorage.h @@ -5,39 +5,40 @@ #ifndef QXMPPTRUSTMEMORYSTORAGE_H #define QXMPPTRUSTMEMORYSTORAGE_H -#include "QXmppGlobal.h" #include "QXmppTrustStorage.h" #include <memory> class QXmppTrustMemoryStoragePrivate; -class QXMPP_EXPORT QXmppTrustMemoryStorage : public QXmppTrustStorage +class QXMPP_EXPORT QXmppTrustMemoryStorage : virtual public QXmppTrustStorage { public: QXmppTrustMemoryStorage(); ~QXmppTrustMemoryStorage(); /// \cond - QFuture<void> setSecurityPolicies(const QString &encryption = {}, SecurityPolicy securityPolicy = QXmppTrustStorage::NoSecurityPolicy) override; + QFuture<void> setSecurityPolicy(const QString &encryption, SecurityPolicy securityPolicy) override; + QFuture<void> resetSecurityPolicy(const QString &encryption) override; QFuture<SecurityPolicy> securityPolicy(const QString &encryption) override; - QFuture<void> addOwnKey(const QString &encryption, const QByteArray &keyId) override; - QFuture<void> removeOwnKey(const QString &encryption) override; + QFuture<void> setOwnKey(const QString &encryption, const QByteArray &keyId) override; + QFuture<void> resetOwnKey(const QString &encryption) override; QFuture<QByteArray> ownKey(const QString &encryption) override; QFuture<void> addKeys(const QString &encryption, const QString &keyOwnerJid, const QList<QByteArray> &keyIds, TrustLevel trustLevel = TrustLevel::AutomaticallyDistrusted) override; - QFuture<void> removeKeys(const QString &encryption = {}, const QList<QByteArray> &keyIds = {}) override; + QFuture<void> removeKeys(const QString &encryption, const QList<QByteArray> &keyIds) override; + QFuture<void> removeKeys(const QString &encryption, const QString &keyOwnerJid) override; + QFuture<void> removeKeys(const QString &encryption) override; QFuture<QHash<TrustLevel, QMultiHash<QString, QByteArray>>> keys(const QString &encryption, TrustLevels trustLevels = {}) override; + QFuture<QHash<QString, QHash<QByteArray, TrustLevel>>> keys(const QString &encryption, const QList<QString> &keyOwnerJids, TrustLevels trustLevels = {}) override; + QFuture<bool> hasKey(const QString &encryption, const QString &keyOwnerJid, TrustLevels trustLevels) override; QFuture<void> setTrustLevel(const QString &encryption, const QMultiHash<QString, QByteArray> &keyIds, const TrustLevel trustLevel) override; QFuture<void> setTrustLevel(const QString &encryption, const QList<QString> &keyOwnerJids, const TrustLevel oldTrustLevel, const TrustLevel newTrustLevel) override; QFuture<TrustLevel> trustLevel(const QString &encryption, const QByteArray &keyId) override; - QFuture<void> addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners) override; - QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting) override; - QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption = {}, const QList<QByteArray> &senderKeyIds = {}) override; - QFuture<QHash<bool, QMultiHash<QString, QByteArray>>> keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds = {}) override; + QFuture<void> resetAll(const QString &encryption) override; /// \endcond private: diff --git a/src/client/QXmppTrustStorage.cpp b/src/client/QXmppTrustStorage.cpp index dc26d1ed..149eccfe 100644 --- a/src/client/QXmppTrustStorage.cpp +++ b/src/client/QXmppTrustStorage.cpp @@ -8,26 +8,31 @@ /// \brief The QXmppTrustStorage class stores trust data for end-to-end /// encryption. /// +/// The term "key" is used for a public long-term key. +/// /// \warning THIS API IS NOT FINALIZED YET! /// /// \since QXmpp 1.5 /// /// -/// \fn QXmppTrustStorage::setSecurityPolicies(const QString &encryption = {}, SecurityPolicy securityPolicy = SecurityPolicy::NoSecurityPolicy) -/// -/// Sets the security policy for an encryption protocol or resets the set -/// security policies. +/// \fn QXmppTrustStorage::setSecurityPolicy(const QString &encryption, SecurityPolicy securityPolicy) /// -/// If securityPolicy is not passed, the set security policy for encryption is -/// reset. -/// If also encryption is not passed, all set security policies are reset. +/// Sets the security policy for an encryption protocol. /// /// \param encryption encryption protocol namespace /// \param securityPolicy security policy being applied /// /// +/// \fn QXmppTrustStorage::resetSecurityPolicy(const QString &encryption) +/// +/// Resets the security policy for an encryption protocol. +/// +/// \param encryption encryption protocol namespace +/// + +/// /// \fn QXmppTrustStorage::securityPolicy(const QString &encryption) /// /// Returns the security policy for an encryption protocol. @@ -38,18 +43,20 @@ /// /// -/// \fn QXmppTrustStorage::addOwnKey(const QString &encryption, const QByteArray &keyId) +/// \fn QXmppTrustStorage::setOwnKey(const QString &encryption, const QByteArray &keyId) /// -/// Adds an own key (i.e., the key used by this client instance). +/// Sets the own key (i.e., the key used by this client instance) for an +/// encryption protocol. /// /// \param encryption encryption protocol namespace /// \param keyId ID of the key /// /// -/// \fn QXmppTrustStorage::removeOwnKey(const QString &encryption) +/// \fn QXmppTrustStorage::resetOwnKey(const QString &encryption) /// -/// Removes an own key (i.e., the key used by this client instance). +/// Resets the own key (i.e., the key used by this client instance) for an +/// encryption protocol. /// /// \param encryption encryption protocol namespace /// @@ -57,7 +64,8 @@ /// /// \fn QXmppTrustStorage::ownKey(const QString &encryption) /// -/// Returns an own key (i.e., the key used by this client instance). +/// Returns the own key (i.e., the key used by this client instance) for an +/// encryption protocol. /// /// \param encryption encryption protocol namespace /// @@ -80,120 +88,110 @@ /// /// Removes keys. /// -/// If keyIds is not passed, all keys for encryption are removed. -/// If encryption is also not passed, all keys are removed. -/// /// \param encryption encryption protocol namespace /// \param keyIds IDs of the keys /// /// -/// \fn QXmppTrustStorage::keys(const QString &encryption, TrustLevels trustLevels = {}) -/// -/// Returns the JIDs of the key owners mapped to the IDs of their keys with a -/// specific trust level. +/// \fn QXmppTrustStorage::removeKeys(const QString &encryption, const QString &keyOwnerJid) /// -/// If no trust levels are passed, all keys are returned. +/// Removes all keys of a key owner. /// /// \param encryption encryption protocol namespace -/// \param trustLevels trust levels of the keys +/// \param keyOwnerJid key owner's bare JID +/// + /// -/// \return the key owner JIDs mapped to their keys with a specific trust level +/// \fn QXmppTrustStorage::removeKeys(const QString &encryption) +/// +/// Removes all keys for encryption. +/// +/// \param encryption encryption protocol namespace /// /// -/// \fn QXmppTrustStorage::setTrustLevel(const QString &encryption, const QMultiHash<QString, QByteArray> &keyIds, TrustLevel trustLevel) +/// \fn QXmppTrustStorage::keys(const QString &encryption, TrustLevels trustLevels = {}) /// -/// Sets the trust level of keys. +/// Returns the JIDs of all key owners mapped to the IDs of their keys with +/// specific trust levels. /// -/// If a key is not stored, it is added to the storage. +/// If no trust levels are passed, all keys for encryption are returned. /// /// \param encryption encryption protocol namespace -/// \param keyIds key owners' bare JIDs mapped to the IDs of their keys -/// \param trustLevel trust level being set +/// \param trustLevels trust levels of the keys +/// +/// \return the key owner JIDs mapped to their keys with specific trust levels /// /// -/// \fn QXmppTrustStorage::setTrustLevel(const QString &encryption, const QList<QString> &keyOwnerJids, TrustLevel oldTrustLevel, TrustLevel newTrustLevel) +/// \fn QXmppTrustStorage::keys(const QString &encryption, const QList<QString> &keyOwnerJids, TrustLevels trustLevels = {}) /// -/// Sets the trust level of keys specified by their key owner and trust level. +/// Returns the IDs of keys mapped to their trust levels for specific key +/// owners. +/// +/// If no trust levels are passed, all keys for encryption and keyOwnerJids are +/// returned. /// /// \param encryption encryption protocol namespace /// \param keyOwnerJids key owners' bare JIDs -/// \param oldTrustLevel trust level being changed -/// \param newTrustLevel trust level being set +/// \param trustLevels trust levels of the keys /// - +/// \return the key IDs mapped to their trust levels for specific key owners /// -/// \fn QXmppTrustStorage::trustLevel(const QString &encryption, const QByteArray &keyId) + /// -/// Returns the trust level of a key. +/// \fn QXmppTrustStorage::hasKey(const QString &encryption, const QString &keyOwnerJid, TrustLevels trustLevels) /// -/// If the key is not stored, it is seen as automatically distrusted. +/// Returns whether at least one key of a key owner with a specific trust level +/// is stored. /// /// \param encryption encryption protocol namespace -/// \param keyId ID of the key +/// \param keyOwnerJid key owner's bare JID +/// \param trustLevels possible trust levels of the key /// -/// \return the key's trust level +/// \return whether a key of the key owner with a passed trust level is stored /// /// -/// \fn QXmppTrustStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners) -/// -/// Adds keys that cannot be authenticated or distrusted directly because the -/// key of the trust message's sender is not yet authenticated. +/// \fn QXmppTrustStorage::setTrustLevel(const QString &encryption, const QMultiHash<QString, QByteArray> &keyIds, TrustLevel trustLevel) /// -/// Those keys are being authenticated or distrusted once the sender's key is -/// authenticated. -/// Each element of keyOwners (i.e., keyOwner) can contain keys for postponed -/// authentication as trustedKeys or for postponed distrusting as -/// distrustedKeys. +/// Sets the trust level of keys. /// -/// If keys of keyOwner.trustedKeys() are already stored for postponed -/// distrusting, they are changed to be used for postponed authentication. -/// If keys of keyOwner.distrustedKeys() are already stored for postponed -/// authentication, they are changed to be used for postponed distrusting. -/// If the same keys are in keyOwner.trustedKeys() and -/// keyOwner.distrustedKeys(), they are used for postponed distrusting. +/// If a key is not stored, it is added to the storage. /// /// \param encryption encryption protocol namespace -/// \param senderKeyId key ID of the trust message's sender -/// \param keyOwners key owners containing key IDs for postponed trust decisions +/// \param keyIds key owners' bare JIDs mapped to the IDs of their keys +/// \param trustLevel trust level being set /// /// -/// \fn QXmppTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting) +/// \fn QXmppTrustStorage::setTrustLevel(const QString &encryption, const QList<QString> &keyOwnerJids, TrustLevel oldTrustLevel, TrustLevel newTrustLevel) /// -/// Removes keys for postponed authentication or distrusting. +/// Sets the trust level of keys specified by their key owner and trust level. /// /// \param encryption encryption protocol namespace -/// \param keyIdsForAuthentication IDs of the keys for postponed authentication -/// \param keyIdsForDistrusting IDs of the keys for postponed distrusting +/// \param keyOwnerJids key owners' bare JIDs +/// \param oldTrustLevel trust level being changed +/// \param newTrustLevel trust level being set /// /// -/// \fn QXmppTrustStorage::removeKeysForPostponedTrustDecisions(const QString &encryption = {}, const QList<QByteArray> &senderKeyIds = {}) +/// \fn QXmppTrustStorage::trustLevel(const QString &encryption, const QByteArray &keyId) /// -/// Removes keys for postponed authentication or distrusting by the trust -/// message's sender's key ID. +/// Returns the trust level of a key. /// -/// If senderKeyIds is empty, all keys for encryption are removed. -/// If encryption is empty too, all keys are removed. +/// If the key is not stored, the trust in that key is undecided. /// /// \param encryption encryption protocol namespace -/// \param senderKeyIds key IDs of the trust messages' senders +/// \param keyId ID of the key /// - +/// \return the key's trust level /// -/// \fn QXmppTrustStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds = {}) + /// -/// Returns the JIDs of key owners mapped to the IDs of their keys stored for -/// postponed authentication (true) or postponed distrusting (false). +/// \fn QXmppTrustStorage::resetAll(const QString &encryption) /// -/// If senderKeyIds is empty, all keys for encryption are returned. +/// Resets all data for encryption. /// /// \param encryption encryption protocol namespace -/// \param senderKeyIds key IDs of the trust messages' senders -/// -/// \return the key owner JIDs mapped to their keys /// diff --git a/src/client/QXmppTrustStorage.h b/src/client/QXmppTrustStorage.h index 2c7b593e..dffbcfae 100644 --- a/src/client/QXmppTrustStorage.h +++ b/src/client/QXmppTrustStorage.h @@ -9,8 +9,6 @@ #include <QFuture> -class QXmppTrustMessageKeyOwner; - class QXMPP_EXPORT QXmppTrustStorage { public: @@ -20,7 +18,7 @@ public: /// enum SecurityPolicy { NoSecurityPolicy, ///< New keys must be trusted manually. - Toakafa, ///< New keys are trusted automatically until the first authentication but automatically distrusted afterwards. + Toakafa, ///< New keys are trusted automatically until the first authentication but automatically distrusted afterwards. \see \xep{0450, Automatic Trust Management (ATM)} }; /// @@ -28,35 +26,38 @@ public: /// protocols /// enum TrustLevel { - AutomaticallyDistrusted = 1, ///< The key is automatically distrusted (e.g., by ATM's security policy). - ManuallyDistrusted = 2, ///< The key is manually distrusted (e.g., by clicking a button or ATM). - AutomaticallyTrusted = 4, ///< The key is automatically trusted (e.g., by the client for all keys of a bare JID until one of it is authenticated). - ManuallyTrusted = 8, ///< The key is manually trusted (e.g., by clicking a button). - Authenticated = 16, ///< The key is authenticated (e.g., by QR code scanning or ATM). + Undecided = 1, ///< The key's trust is not decided. + AutomaticallyDistrusted = 2, ///< The key is automatically distrusted (e.g., by the security policy TOAKAFA). \see SecurityPolicy + ManuallyDistrusted = 4, ///< The key is manually distrusted (e.g., by clicking a button or \xep{0450, Automatic Trust Management (ATM)}). + AutomaticallyTrusted = 8, ///< The key is automatically trusted (e.g., by the client for all keys of a bare JID until one of it is authenticated). + ManuallyTrusted = 16, ///< The key is manually trusted (e.g., by clicking a button). + Authenticated = 32, ///< The key is authenticated (e.g., by QR code scanning or \xep{0450, Automatic Trust Management (ATM)}). }; Q_DECLARE_FLAGS(TrustLevels, TrustLevel) virtual ~QXmppTrustStorage() = default; - virtual QFuture<void> setSecurityPolicies(const QString &encryption = {}, SecurityPolicy securityPolicy = SecurityPolicy::NoSecurityPolicy) = 0; + virtual QFuture<void> setSecurityPolicy(const QString &encryption, SecurityPolicy securityPolicy) = 0; + virtual QFuture<void> resetSecurityPolicy(const QString &encryption) = 0; virtual QFuture<SecurityPolicy> securityPolicy(const QString &encryption) = 0; - virtual QFuture<void> addOwnKey(const QString &encryption, const QByteArray &keyId) = 0; - virtual QFuture<void> removeOwnKey(const QString &encryption) = 0; + virtual QFuture<void> setOwnKey(const QString &encryption, const QByteArray &keyId) = 0; + virtual QFuture<void> resetOwnKey(const QString &encryption) = 0; virtual QFuture<QByteArray> ownKey(const QString &encryption) = 0; virtual QFuture<void> addKeys(const QString &encryption, const QString &keyOwnerJid, const QList<QByteArray> &keyIds, TrustLevel trustLevel = TrustLevel::AutomaticallyDistrusted) = 0; - virtual QFuture<void> removeKeys(const QString &encryption = {}, const QList<QByteArray> &keyIds = {}) = 0; + virtual QFuture<void> removeKeys(const QString &encryption, const QList<QByteArray> &keyIds) = 0; + virtual QFuture<void> removeKeys(const QString &encryption, const QString &keyOwnerJid) = 0; + virtual QFuture<void> removeKeys(const QString &encryption) = 0; virtual QFuture<QHash<TrustLevel, QMultiHash<QString, QByteArray>>> keys(const QString &encryption, TrustLevels trustLevels = {}) = 0; + virtual QFuture<QHash<QString, QHash<QByteArray, TrustLevel>>> keys(const QString &encryption, const QList<QString> &keyOwnerJids, TrustLevels trustLevels = {}) = 0; + virtual QFuture<bool> hasKey(const QString &encryption, const QString &keyOwnerJid, TrustLevels trustLevels) = 0; virtual QFuture<void> setTrustLevel(const QString &encryption, const QMultiHash<QString, QByteArray> &keyIds, TrustLevel trustLevel) = 0; virtual QFuture<void> setTrustLevel(const QString &encryption, const QList<QString> &keyOwnerJids, TrustLevel oldTrustLevel, TrustLevel newTrustLevel) = 0; virtual QFuture<TrustLevel> trustLevel(const QString &encryption, const QByteArray &keyId) = 0; - virtual QFuture<void> addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners) = 0; - virtual QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting) = 0; - virtual QFuture<void> removeKeysForPostponedTrustDecisions(const QString &encryption = {}, const QList<QByteArray> &senderKeyIds = {}) = 0; - virtual QFuture<QHash<bool, QMultiHash<QString, QByteArray>>> keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds = {}) = 0; + virtual QFuture<void> resetAll(const QString &encryption) = 0; }; Q_DECLARE_METATYPE(QXmppTrustStorage::SecurityPolicy) diff --git a/tests/qxmppatmmanager/tst_qxmppatmmanager.cpp b/tests/qxmppatmmanager/tst_qxmppatmmanager.cpp index c5899e0a..4ff4e079 100644 --- a/tests/qxmppatmmanager/tst_qxmppatmmanager.cpp +++ b/tests/qxmppatmmanager/tst_qxmppatmmanager.cpp @@ -3,12 +3,14 @@ // SPDX-License-Identifier: LGPL-2.1-or-later #include "QXmppAtmManager.h" +#include "QXmppAtmTrustMemoryStorage.h" #include "QXmppCarbonManager.h" #include "QXmppClient.h" #include "QXmppConstants.cpp" #include "QXmppConstants_p.h" -#include "QXmppTrustMemoryStorage.h" +#include "QXmppMessage.h" #include "QXmppTrustMessageElement.h" +#include "QXmppTrustMessageKeyOwner.h" #include "QXmppUtils.h" #include "util.h" @@ -57,13 +59,13 @@ private: QXmppClient m_client; QXmppLogger m_logger; QXmppAtmManager *m_manager; - QXmppTrustMemoryStorage *m_trustStorage; + QXmppAtmTrustMemoryStorage *m_trustStorage; QXmppCarbonManager *m_carbonManager; }; void tst_QXmppAtmManager::initTestCase() { - m_trustStorage = new QXmppTrustMemoryStorage; + m_trustStorage = new QXmppAtmTrustMemoryStorage; m_manager = new QXmppAtmManager(m_trustStorage); m_client.addExtension(m_manager); m_client.configuration().setJid("alice@example.org/phone"); @@ -446,7 +448,7 @@ void tst_QXmppAtmManager::testAuthenticate() clearTrustStorage(); QFETCH(QXmppTrustStorage::SecurityPolicy, securityPolicy); - m_trustStorage->setSecurityPolicies(ns_omemo, securityPolicy); + m_trustStorage->setSecurityPolicy(ns_omemo, securityPolicy); QMultiHash<QString, QByteArray> authenticatedKeys = { { QStringLiteral("alice@example.org"), QByteArray::fromBase64(QByteArrayLiteral("rQIL2albuSR1i06EZAp1uZ838zUeEgGIq2whwu3s+Zg=")) }, @@ -859,7 +861,7 @@ void tst_QXmppAtmManager::testHandleMessage() // Remove the sender key as soon as the method being tested is executed. if (areTrustDecisionsValid) { - m_trustStorage->removeKeys(ns_omemo, { senderKey }); + m_trustStorage->removeKeys(ns_omemo, QList { senderKey }); } if (areTrustDecisionsValid) { @@ -2070,8 +2072,8 @@ void tst_QXmppAtmManager::testMakeTrustDecisionsContactKeysDone() void tst_QXmppAtmManager::clearTrustStorage() { - m_trustStorage->removeKeys(); - m_trustStorage->removeKeysForPostponedTrustDecisions(); + m_trustStorage->removeKeys(ns_omemo); + m_trustStorage->removeKeysForPostponedTrustDecisions(ns_omemo); } QTEST_MAIN(tst_QXmppAtmManager) diff --git a/tests/qxmpptrustmemorystorage/tst_qxmpptrustmemorystorage.cpp b/tests/qxmpptrustmemorystorage/tst_qxmpptrustmemorystorage.cpp index d7827b7f..ff7537dc 100644 --- a/tests/qxmpptrustmemorystorage/tst_qxmpptrustmemorystorage.cpp +++ b/tests/qxmpptrustmemorystorage/tst_qxmpptrustmemorystorage.cpp @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: LGPL-2.1-or-later +#include "QXmppAtmTrustMemoryStorage.h" #include "QXmppConstants.cpp" #include "QXmppConstants_p.h" #include "QXmppTrustMemoryStorage.h" @@ -14,44 +15,42 @@ class tst_QXmppTrustMemoryStorage : public QObject Q_OBJECT private slots: - void testSecurityPolicies(); + // QXmppTrustMemoryStorage + void testSecurityPolicy(); void testOwnKeys(); void testKeys(); void testTrustLevels(); - void testKeysForPostponedTrustDecisions(); + void testResetAll(); + + // QXmppAtmTrustMemoryStorage + void atmTestKeysForPostponedTrustDecisions(); + void atmTestResetAll(); private: QXmppTrustMemoryStorage m_trustStorage; + QXmppAtmTrustMemoryStorage m_atmTrustStorage; }; -void tst_QXmppTrustMemoryStorage::testSecurityPolicies() +void tst_QXmppTrustMemoryStorage::testSecurityPolicy() { auto future = m_trustStorage.securityPolicy(ns_ox); QVERIFY(future.isFinished()); auto result = future.result(); QCOMPARE(result, QXmppTrustStorage::NoSecurityPolicy); - m_trustStorage.setSecurityPolicies(ns_ox, QXmppTrustStorage::Toakafa); - m_trustStorage.setSecurityPolicies(ns_omemo, QXmppTrustStorage::Toakafa); + m_trustStorage.setSecurityPolicy(ns_omemo, QXmppTrustStorage::Toakafa); future = m_trustStorage.securityPolicy(ns_ox); QVERIFY(future.isFinished()); result = future.result(); - QCOMPARE(result, QXmppTrustStorage::Toakafa); + QCOMPARE(result, QXmppTrustStorage::NoSecurityPolicy); future = m_trustStorage.securityPolicy(ns_omemo); QVERIFY(future.isFinished()); result = future.result(); QCOMPARE(result, QXmppTrustStorage::Toakafa); - m_trustStorage.setSecurityPolicies(ns_ox); - - future = m_trustStorage.securityPolicy(ns_ox); - QVERIFY(future.isFinished()); - result = future.result(); - QCOMPARE(result, QXmppTrustStorage::NoSecurityPolicy); - - m_trustStorage.setSecurityPolicies(); + m_trustStorage.resetSecurityPolicy(ns_omemo); future = m_trustStorage.securityPolicy(ns_omemo); QVERIFY(future.isFinished()); @@ -61,13 +60,18 @@ void tst_QXmppTrustMemoryStorage::testSecurityPolicies() void tst_QXmppTrustMemoryStorage::testOwnKeys() { - m_trustStorage.addOwnKey(ns_ox, QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ="))); - m_trustStorage.addOwnKey(ns_omemo, QByteArray::fromBase64(QByteArrayLiteral("IhpPjiKLchgrAG5cpSfTvdzPjZ5v6vTOluHEUehkgCA="))); - - // own OX key auto future = m_trustStorage.ownKey(ns_ox); QVERIFY(future.isFinished()); auto result = future.result(); + QVERIFY(result.isEmpty()); + + m_trustStorage.setOwnKey(ns_ox, QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ="))); + m_trustStorage.setOwnKey(ns_omemo, QByteArray::fromBase64(QByteArrayLiteral("IhpPjiKLchgrAG5cpSfTvdzPjZ5v6vTOluHEUehkgCA="))); + + // own OX key + future = m_trustStorage.ownKey(ns_ox); + QVERIFY(future.isFinished()); + result = future.result(); QCOMPARE(result, QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ="))); // own OMEMO key @@ -76,9 +80,15 @@ void tst_QXmppTrustMemoryStorage::testOwnKeys() result = future.result(); QCOMPARE(result, QByteArray::fromBase64(QByteArrayLiteral("IhpPjiKLchgrAG5cpSfTvdzPjZ5v6vTOluHEUehkgCA="))); - m_trustStorage.removeOwnKey(ns_omemo); + m_trustStorage.resetOwnKey(ns_omemo); + + // own OX key + future = m_trustStorage.ownKey(ns_ox); + QVERIFY(future.isFinished()); + result = future.result(); + QCOMPARE(result, QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ="))); - // no stored own OMEMO key + // no own OMEMO key future = m_trustStorage.ownKey(ns_omemo); QVERIFY(future.isFinished()); result = future.result(); @@ -87,6 +97,33 @@ void tst_QXmppTrustMemoryStorage::testOwnKeys() void tst_QXmppTrustMemoryStorage::testKeys() { + // no OMEMO keys + auto future = m_trustStorage.keys(ns_omemo); + QVERIFY(future.isFinished()); + auto result = future.result(); + QVERIFY(result.isEmpty()); + + // no OMEMO keys (via JIDs) + auto futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org"), QStringLiteral("bob@example.com") }); + QVERIFY(futureForJids.isFinished()); + auto resultForJids = futureForJids.result(); + + // no automatically trusted and authenticated OMEMO keys + future = m_trustStorage.keys(ns_omemo, + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + QVERIFY(future.isFinished()); + result = future.result(); + QVERIFY(result.isEmpty()); + + // no automatically trusted and authenticated OMEMO key from Alice + auto futureBool = m_trustStorage.hasKey(ns_omemo, + QStringLiteral("alice@example.org"), + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + QVERIFY(futureBool.isFinished()); + auto resultBool = futureBool.result(); + QVERIFY(!resultBool); + // Store keys with the default trust level. m_trustStorage.addKeys( ns_omemo, @@ -149,10 +186,27 @@ void tst_QXmppTrustMemoryStorage::testKeys() QMultiHash<QString, QByteArray> authenticatedKeys = { { QStringLiteral("bob@example.com"), QByteArray::fromBase64(QByteArrayLiteral("YjVI04NcbTPvXLaA95RO84HPcSvyOgEZ2r5cTyUs0C8=")) } }; + QHash<QByteArray, QXmppTrustStorage::TrustLevel> keysAlice = { { QByteArray::fromBase64(QByteArrayLiteral("WaAnpWyW1hnFooH3oJo9Ba5XYoksnLPeJRTAjxPbv38=")), + QXmppTrustStorage::AutomaticallyDistrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("/1eK3R2LtjPBT3el8f0q4DvzqUJSfFy5fkKkKPNFNYw=")), + QXmppTrustStorage::AutomaticallyDistrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ=")), + QXmppTrustStorage::ManuallyDistrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("Ciemp4ZNzRJxnRD+k28vAie0kXJrwl4IrbfDy7n6OxE=")), + QXmppTrustStorage::AutomaticallyTrusted } }; + QHash<QByteArray, QXmppTrustStorage::TrustLevel> keysBob = { { QByteArray::fromBase64(QByteArrayLiteral("rvSXBRd+EICMhQvVgcREQJxxP+T4EBmai4mYHBfJQGg=")), + QXmppTrustStorage::AutomaticallyTrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("tCP1CI3pqSTVGzFYFyPYUMfMZ9Ck/msmfD0wH/VtJBM=")), + QXmppTrustStorage::ManuallyTrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("2fhJtrgoMJxfLI3084/YkYh9paqiSiLFDVL2m0qAgX4=")), + QXmppTrustStorage::ManuallyTrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("YjVI04NcbTPvXLaA95RO84HPcSvyOgEZ2r5cTyUs0C8=")), + QXmppTrustStorage::Authenticated } }; + // all OMEMO keys - auto future = m_trustStorage.keys(ns_omemo); + future = m_trustStorage.keys(ns_omemo); QVERIFY(future.isFinished()); - auto result = future.result(); + result = future.result(); QCOMPARE( result, QHash({ std::pair( @@ -172,7 +226,8 @@ void tst_QXmppTrustMemoryStorage::testKeys() authenticatedKeys) })); // automatically trusted and authenticated OMEMO keys - future = m_trustStorage.keys(ns_omemo, QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + future = m_trustStorage.keys(ns_omemo, + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); QVERIFY(future.isFinished()); result = future.result(); QCOMPARE( @@ -184,6 +239,73 @@ void tst_QXmppTrustMemoryStorage::testKeys() QXmppTrustStorage::Authenticated, authenticatedKeys) })); + // all OMEMO keys (via JIDs) + futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org"), QStringLiteral("bob@example.com") }); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("alice@example.org"), + keysAlice), + std::pair( + QStringLiteral("bob@example.com"), + keysBob) })); + + // Alice's OMEMO keys + futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org") }); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("alice@example.org"), + keysAlice) })); + + keysAlice = { { QByteArray::fromBase64(QByteArrayLiteral("Ciemp4ZNzRJxnRD+k28vAie0kXJrwl4IrbfDy7n6OxE=")), + QXmppTrustStorage::AutomaticallyTrusted } }; + keysBob = { { QByteArray::fromBase64(QByteArrayLiteral("rvSXBRd+EICMhQvVgcREQJxxP+T4EBmai4mYHBfJQGg=")), + QXmppTrustStorage::AutomaticallyTrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("YjVI04NcbTPvXLaA95RO84HPcSvyOgEZ2r5cTyUs0C8=")), + QXmppTrustStorage::Authenticated } }; + + // automatically trusted and authenticated OMEMO keys (via JIDs) + futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org"), QStringLiteral("bob@example.com") }, + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("alice@example.org"), + keysAlice), + std::pair( + QStringLiteral("bob@example.com"), + keysBob) })); + + // Alice's automatically trusted and authenticated OMEMO keys + futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org") }, + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("alice@example.org"), + keysAlice) })); + + // at least one automatically trusted or authenticated OMEMO key from Alice + futureBool = m_trustStorage.hasKey(ns_omemo, + QStringLiteral("alice@example.org"), + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + QVERIFY(futureBool.isFinished()); + resultBool = futureBool.result(); + QVERIFY(resultBool); + m_trustStorage.removeKeys(ns_omemo, { QByteArray::fromBase64(QByteArrayLiteral("WaAnpWyW1hnFooH3oJo9Ba5XYoksnLPeJRTAjxPbv38=")), QByteArray::fromBase64(QByteArrayLiteral("Ciemp4ZNzRJxnRD+k28vAie0kXJrwl4IrbfDy7n6OxE=")) }); @@ -193,7 +315,20 @@ void tst_QXmppTrustMemoryStorage::testKeys() automaticallyTrustedKeys = { { QStringLiteral("bob@example.com"), QByteArray::fromBase64(QByteArrayLiteral("rvSXBRd+EICMhQvVgcREQJxxP+T4EBmai4mYHBfJQGg=")) } }; - // all OMEMO keys after removal + keysAlice = { { QByteArray::fromBase64(QByteArrayLiteral("/1eK3R2LtjPBT3el8f0q4DvzqUJSfFy5fkKkKPNFNYw=")), + QXmppTrustStorage::AutomaticallyDistrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ=")), + QXmppTrustStorage::ManuallyDistrusted } }; + keysBob = { { QByteArray::fromBase64(QByteArrayLiteral("rvSXBRd+EICMhQvVgcREQJxxP+T4EBmai4mYHBfJQGg=")), + QXmppTrustStorage::AutomaticallyTrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("tCP1CI3pqSTVGzFYFyPYUMfMZ9Ck/msmfD0wH/VtJBM=")), + QXmppTrustStorage::ManuallyTrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("2fhJtrgoMJxfLI3084/YkYh9paqiSiLFDVL2m0qAgX4=")), + QXmppTrustStorage::ManuallyTrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("YjVI04NcbTPvXLaA95RO84HPcSvyOgEZ2r5cTyUs0C8=")), + QXmppTrustStorage::Authenticated } }; + + // OMEMO keys after removal future = m_trustStorage.keys(ns_omemo); QVERIFY(future.isFinished()); result = future.result(); @@ -215,6 +350,76 @@ void tst_QXmppTrustMemoryStorage::testKeys() QXmppTrustStorage::Authenticated, authenticatedKeys) })); + // OMEMO keys after removal (via JIDs) + futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org"), QStringLiteral("bob@example.com") }); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("alice@example.org"), + keysAlice), + std::pair( + QStringLiteral("bob@example.com"), + keysBob) })); + + // Alice's OMEMO keys after removal + futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org") }); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("alice@example.org"), + keysAlice) })); + + keysAlice = { { QByteArray::fromBase64(QByteArrayLiteral("Ciemp4ZNzRJxnRD+k28vAie0kXJrwl4IrbfDy7n6OxE=")), + QXmppTrustStorage::AutomaticallyTrusted } }; + keysBob = { { QByteArray::fromBase64(QByteArrayLiteral("rvSXBRd+EICMhQvVgcREQJxxP+T4EBmai4mYHBfJQGg=")), + QXmppTrustStorage::AutomaticallyTrusted }, + { QByteArray::fromBase64(QByteArrayLiteral("YjVI04NcbTPvXLaA95RO84HPcSvyOgEZ2r5cTyUs0C8=")), + QXmppTrustStorage::Authenticated } }; + + // automatically trusted and authenticated OMEMO keys after removal (via JIDs) + futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org"), QStringLiteral("bob@example.com") }, + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("bob@example.com"), + keysBob) })); + + // Alice's automatically trusted and authenticated OMEMO keys after removal + futureForJids = m_trustStorage.keys(ns_omemo, + { QStringLiteral("alice@example.org") }, + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QVERIFY(resultForJids.isEmpty()); + + m_trustStorage.removeKeys(ns_omemo, QStringLiteral("alice@example.org")); + + // OMEMO keys after removing Alice's keys + future = m_trustStorage.keys(ns_omemo); + QVERIFY(future.isFinished()); + result = future.result(); + QCOMPARE( + result, + QHash({ std::pair( + QXmppTrustStorage::AutomaticallyTrusted, + automaticallyTrustedKeys), + std::pair( + QXmppTrustStorage::ManuallyTrusted, + manuallyTrustedKeys), + std::pair( + QXmppTrustStorage::Authenticated, + authenticatedKeys) })); + m_trustStorage.removeKeys(ns_omemo); // no stored OMEMO keys @@ -228,6 +433,11 @@ void tst_QXmppTrustMemoryStorage::testKeys() { QStringLiteral("alice@example.org"), QByteArray::fromBase64(QByteArrayLiteral("IhpPjiKLchgrAG5cpSfTvdzPjZ5v6vTOluHEUehkgCA=")) } }; + keysAlice = { { QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ=")), + QXmppTrustStorage::Authenticated }, + { QByteArray::fromBase64(QByteArrayLiteral("IhpPjiKLchgrAG5cpSfTvdzPjZ5v6vTOluHEUehkgCA=")), + QXmppTrustStorage::Authenticated } }; + // remaining OX keys future = m_trustStorage.keys(ns_ox); QVERIFY(future.isFinished()); @@ -238,13 +448,50 @@ void tst_QXmppTrustMemoryStorage::testKeys() QXmppTrustStorage::Authenticated, authenticatedKeys) })); - m_trustStorage.removeKeys(); + // remaining OX keys (via JIDs) + futureForJids = m_trustStorage.keys(ns_ox, + { QStringLiteral("alice@example.org"), QStringLiteral("bob@example.com") }); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("alice@example.org"), + keysAlice) })); + + // Alice's remaining OX keys + futureForJids = m_trustStorage.keys(ns_ox, + { QStringLiteral("alice@example.org") }); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QCOMPARE( + resultForJids, + QHash({ std::pair( + QStringLiteral("alice@example.org"), + keysAlice) })); + + m_trustStorage.removeKeys(ns_ox); // no stored OX keys future = m_trustStorage.keys(ns_ox); QVERIFY(future.isFinished()); result = future.result(); QVERIFY(result.isEmpty()); + + // no stored OX keys (via JIDs) + futureForJids = m_trustStorage.keys(ns_ox, + { QStringLiteral("alice@example.org"), QStringLiteral("bob@example.com") }); + QVERIFY(futureForJids.isFinished()); + resultForJids = futureForJids.result(); + QVERIFY(resultForJids.isEmpty()); + + // no automatically trusted or authenticated OX key from Alice + futureBool = m_trustStorage.hasKey(ns_ox, + QStringLiteral("alice@example.org"), + QXmppTrustStorage::AutomaticallyTrusted | QXmppTrustStorage::Authenticated); + QVERIFY(futureBool.isFinished()); + resultBool = futureBool.result(); + QVERIFY(!resultBool); } void tst_QXmppTrustMemoryStorage::testTrustLevels() @@ -325,7 +572,7 @@ void tst_QXmppTrustMemoryStorage::testTrustLevels() QByteArray::fromBase64(QByteArrayLiteral("WXL4EDfzUGbVPQWjT9pmBeiCpCBzYZv3lUAaj+UbPyE="))); QVERIFY(future.isFinished()); result = future.result(); - QCOMPARE(result, QXmppTrustStorage::AutomaticallyDistrusted); + QCOMPARE(result, QXmppTrustStorage::Undecided); // Set the trust levels of all authenticated keys belonging to Alice and // Bob. @@ -356,13 +603,111 @@ void tst_QXmppTrustMemoryStorage::testTrustLevels() QByteArray::fromBase64(QByteArrayLiteral("wE06Gwf8f4DvDLFDoaCsGs8ibcUjf84WIOA2FAjPI3o="))); QVERIFY(future.isFinished()); result = future.result(); - QCOMPARE(result, QXmppTrustStorage::AutomaticallyDistrusted); + QCOMPARE(result, QXmppTrustStorage::Undecided); - m_trustStorage.removeKeys(); + m_trustStorage.removeKeys(ns_ox); + m_trustStorage.removeKeys(ns_omemo); } -void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() +void tst_QXmppTrustMemoryStorage::testResetAll() { + m_trustStorage.setSecurityPolicy(ns_ox, QXmppTrustStorage::Toakafa); + m_trustStorage.setSecurityPolicy(ns_omemo, QXmppTrustStorage::Toakafa); + + m_trustStorage.setOwnKey(ns_ox, QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ="))); + m_trustStorage.setOwnKey(ns_omemo, QByteArray::fromBase64(QByteArrayLiteral("IhpPjiKLchgrAG5cpSfTvdzPjZ5v6vTOluHEUehkgCA="))); + + m_trustStorage.addKeys( + ns_omemo, + QStringLiteral("alice@example.org"), + { QByteArray::fromBase64(QByteArrayLiteral("WaAnpWyW1hnFooH3oJo9Ba5XYoksnLPeJRTAjxPbv38=")), + QByteArray::fromBase64(QByteArrayLiteral("/1eK3R2LtjPBT3el8f0q4DvzqUJSfFy5fkKkKPNFNYw=")) }); + + m_trustStorage.addKeys( + ns_omemo, + QStringLiteral("alice@example.org"), + { QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ=")) }, + QXmppTrustStorage::ManuallyDistrusted); + + m_trustStorage.addKeys( + ns_omemo, + QStringLiteral("alice@example.org"), + { QByteArray::fromBase64(QByteArrayLiteral("Ciemp4ZNzRJxnRD+k28vAie0kXJrwl4IrbfDy7n6OxE=")) }, + QXmppTrustStorage::AutomaticallyTrusted); + + m_trustStorage.addKeys( + ns_omemo, + QStringLiteral("bob@example.com"), + { QByteArray::fromBase64(QByteArrayLiteral("rvSXBRd+EICMhQvVgcREQJxxP+T4EBmai4mYHBfJQGg=")) }, + QXmppTrustStorage::AutomaticallyTrusted); + + m_trustStorage.addKeys( + ns_omemo, + QStringLiteral("bob@example.com"), + { QByteArray::fromBase64(QByteArrayLiteral("tCP1CI3pqSTVGzFYFyPYUMfMZ9Ck/msmfD0wH/VtJBM=")), + QByteArray::fromBase64(QByteArrayLiteral("2fhJtrgoMJxfLI3084/YkYh9paqiSiLFDVL2m0qAgX4=")) }, + QXmppTrustStorage::ManuallyTrusted); + + m_trustStorage.addKeys( + ns_omemo, + QStringLiteral("bob@example.com"), + { QByteArray::fromBase64(QByteArrayLiteral("YjVI04NcbTPvXLaA95RO84HPcSvyOgEZ2r5cTyUs0C8=")) }, + QXmppTrustStorage::Authenticated); + + m_trustStorage.addKeys( + ns_ox, + QStringLiteral("alice@example.org"), + { QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ=")), + QByteArray::fromBase64(QByteArrayLiteral("IhpPjiKLchgrAG5cpSfTvdzPjZ5v6vTOluHEUehkgCA=")) }, + QXmppTrustStorage::Authenticated); + + m_trustStorage.resetAll(ns_omemo); + + auto future = m_trustStorage.securityPolicy(ns_omemo); + QVERIFY(future.isFinished()); + auto result = future.result(); + QCOMPARE(result, QXmppTrustStorage::NoSecurityPolicy); + + future = m_trustStorage.securityPolicy(ns_ox); + QVERIFY(future.isFinished()); + result = future.result(); + QCOMPARE(result, QXmppTrustStorage::Toakafa); + + auto futureKey = m_trustStorage.ownKey(ns_omemo); + QVERIFY(futureKey.isFinished()); + auto resultKey = futureKey.result(); + QVERIFY(resultKey.isEmpty()); + + futureKey = m_trustStorage.ownKey(ns_ox); + QVERIFY(futureKey.isFinished()); + resultKey = futureKey.result(); + QCOMPARE(resultKey, QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ="))); + + auto futureKeys = m_trustStorage.keys(ns_omemo); + QVERIFY(futureKeys.isFinished()); + auto resultKeys = futureKeys.result(); + QVERIFY(resultKeys.isEmpty()); + + const QMultiHash<QString, QByteArray> authenticatedKeys = { { QStringLiteral("alice@example.org"), + QByteArray::fromBase64(QByteArrayLiteral("aFABnX7Q/rbTgjBySYzrT2FsYCVYb49mbca5yB734KQ=")) }, + { QStringLiteral("alice@example.org"), + QByteArray::fromBase64(QByteArrayLiteral("IhpPjiKLchgrAG5cpSfTvdzPjZ5v6vTOluHEUehkgCA=")) } }; + + futureKeys = m_trustStorage.keys(ns_ox); + QVERIFY(futureKeys.isFinished()); + resultKeys = futureKeys.result(); + QCOMPARE( + resultKeys, + QHash({ std::pair( + QXmppTrustStorage::Authenticated, + authenticatedKeys) })); +} + +void tst_QXmppTrustMemoryStorage::atmTestKeysForPostponedTrustDecisions() +{ + // The key 7y1t0LnmNBeXJka43XejFPLrKtQlSFATrYmy7xHaKYU= + // is set for both postponed authentication and distrusting. + // Thus, it is only stored for postponed distrusting. QXmppTrustMessageKeyOwner keyOwnerAlice; keyOwnerAlice.setJid(QStringLiteral("alice@example.org")); keyOwnerAlice.setTrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("Wl53ZchbtAtCZQCHROiD20W7UnKTQgWQrjTHAVNw1ic=")), @@ -375,21 +720,18 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() keyOwnerBobTrustedKeys.setJid(QStringLiteral("bob@example.com")); keyOwnerBobTrustedKeys.setTrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("GgTqeRLp1M+MEenzFQym2oqer9PfHukS4brJDQl5ARE=")) }); - // The key 7y1t0LnmNBeXJka43XejFPLrKtQlSFATrYmy7xHaKYU= - // is passed for both postponed authentication and distrusting. - // Thus, it is only stored for postponed distrusting. - m_trustStorage.addKeysForPostponedTrustDecisions(ns_omemo, - QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")), - { keyOwnerAlice, keyOwnerBobTrustedKeys }); + m_atmTrustStorage.addKeysForPostponedTrustDecisions(ns_omemo, + QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")), + { keyOwnerAlice, keyOwnerBobTrustedKeys }); QXmppTrustMessageKeyOwner keyOwnerBobDistrustedKeys; keyOwnerBobDistrustedKeys.setJid(QStringLiteral("bob@example.com")); keyOwnerBobDistrustedKeys.setDistrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("sD6ilugEBeKxPsdDEyX43LSGKHKWd5MFEdhT+4RpsxA=")), QByteArray::fromBase64(QByteArrayLiteral("X5tJ1D5rEeaeQE8eqhBKAj4KUZGYe3x+iHifaTBY1kM=")) }); - m_trustStorage.addKeysForPostponedTrustDecisions(ns_omemo, - QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")), - { keyOwnerBobDistrustedKeys }); + m_atmTrustStorage.addKeysForPostponedTrustDecisions(ns_omemo, + QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")), + { keyOwnerBobDistrustedKeys }); QXmppTrustMessageKeyOwner keyOwnerCarol; keyOwnerCarol.setJid(QStringLiteral("carol@example.net")); @@ -398,9 +740,9 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() keyOwnerCarol.setDistrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("N0B2StHKk1/slwg1rzybTFzjdg7FChc+3cXmTU/rS8g=")), QByteArray::fromBase64(QByteArrayLiteral("wsEN32UHCiNjYqTG/J63hY4Nu8tZT42Ni1FxrgyRQ5g=")) }); - m_trustStorage.addKeysForPostponedTrustDecisions(ns_ox, - QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")), - { keyOwnerCarol }); + m_atmTrustStorage.addKeysForPostponedTrustDecisions(ns_ox, + QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")), + { keyOwnerCarol }); QMultiHash<QString, QByteArray> trustedKeys = { { QStringLiteral("alice@example.org"), QByteArray::fromBase64(QByteArrayLiteral("Wl53ZchbtAtCZQCHROiD20W7UnKTQgWQrjTHAVNw1ic=")) }, @@ -413,8 +755,8 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() { QStringLiteral("alice@example.org"), QByteArray::fromBase64(QByteArrayLiteral("7y1t0LnmNBeXJka43XejFPLrKtQlSFATrYmy7xHaKYU=")) } }; - auto future = m_trustStorage.keysForPostponedTrustDecisions(ns_omemo, - { QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")) }); + auto future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_omemo, + { QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")) }); QVERIFY(future.isFinished()); auto result = future.result(); QCOMPARE( @@ -435,9 +777,9 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() { QStringLiteral("bob@example.com"), QByteArray::fromBase64(QByteArrayLiteral("X5tJ1D5rEeaeQE8eqhBKAj4KUZGYe3x+iHifaTBY1kM=")) } }; - future = m_trustStorage.keysForPostponedTrustDecisions(ns_omemo, - { QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")), - QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")) }); + future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_omemo, + { QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")), + QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")) }); QVERIFY(future.isFinished()); result = future.result(); QCOMPARE( @@ -450,7 +792,7 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() distrustedKeys) })); // Retrieve all keys. - future = m_trustStorage.keysForPostponedTrustDecisions(ns_omemo); + future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_omemo); QVERIFY(future.isFinished()); result = future.result(); QCOMPARE( @@ -468,7 +810,7 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() // sD6ilugEBeKxPsdDEyX43LSGKHKWd5MFEdhT+4RpsxA= for the // sending endpoint with the key // IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=. - m_trustStorage.addKeysForPostponedTrustDecisions( + m_atmTrustStorage.addKeysForPostponedTrustDecisions( ns_omemo, QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")), { keyOwnerBobTrustedKeys }); @@ -478,8 +820,8 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() distrustedKeys = { { QStringLiteral("bob@example.com"), QByteArray::fromBase64(QByteArrayLiteral("X5tJ1D5rEeaeQE8eqhBKAj4KUZGYe3x+iHifaTBY1kM=")) } }; - future = m_trustStorage.keysForPostponedTrustDecisions(ns_omemo, - { QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")) }); + future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_omemo, + { QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")) }); QVERIFY(future.isFinished()); result = future.result(); QCOMPARE( @@ -491,10 +833,10 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() false, distrustedKeys) })); - m_trustStorage.removeKeysForPostponedTrustDecisions(ns_omemo, - { QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")) }); + m_atmTrustStorage.removeKeysForPostponedTrustDecisions(ns_omemo, + { QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")) }); - future = m_trustStorage.keysForPostponedTrustDecisions(ns_omemo); + future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_omemo); QVERIFY(future.isFinished()); result = future.result(); QCOMPARE( @@ -506,11 +848,43 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() false, distrustedKeys) })); - // Remove all OMEMO keys including those stored for sender key - // IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=. - m_trustStorage.removeKeysForPostponedTrustDecisions(ns_omemo); + m_atmTrustStorage.addKeysForPostponedTrustDecisions( + ns_omemo, + QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")), + { keyOwnerAlice }); + + // The key QR05jrab7PFkSLhtdzyXrPfCqhkNCYCrlWATaBMTenE= is not removed + // because its ID is passed within the parameter "keyIdsForDistrusting" but + // stored for postponed authentication. + m_atmTrustStorage.removeKeysForPostponedTrustDecisions(ns_omemo, + { QByteArray::fromBase64(QByteArrayLiteral("Wl53ZchbtAtCZQCHROiD20W7UnKTQgWQrjTHAVNw1ic=")), + QByteArray::fromBase64(QByteArrayLiteral("sD6ilugEBeKxPsdDEyX43LSGKHKWd5MFEdhT+4RpsxA=")) }, + { QByteArray::fromBase64(QByteArrayLiteral("mB98hhdVps++skUuy4TGy/Vp6RQXLJO4JGf86FAUjyc=")), + QByteArray::fromBase64(QByteArrayLiteral("QR05jrab7PFkSLhtdzyXrPfCqhkNCYCrlWATaBMTenE=")) }); + + trustedKeys = { { QStringLiteral("alice@example.org"), + QByteArray::fromBase64(QByteArrayLiteral("QR05jrab7PFkSLhtdzyXrPfCqhkNCYCrlWATaBMTenE=")) } }; + distrustedKeys = { { QStringLiteral("alice@example.org"), + QByteArray::fromBase64(QByteArrayLiteral("7y1t0LnmNBeXJka43XejFPLrKtQlSFATrYmy7xHaKYU=")) }, + { QStringLiteral("bob@example.com"), + QByteArray::fromBase64(QByteArrayLiteral("X5tJ1D5rEeaeQE8eqhBKAj4KUZGYe3x+iHifaTBY1kM=")) } }; + + future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_omemo); + QVERIFY(future.isFinished()); + result = future.result(); + QCOMPARE( + result, + QHash({ std::pair( + true, + trustedKeys), + std::pair( + false, + distrustedKeys) })); + + // Remove all OMEMO keys. + m_atmTrustStorage.removeKeysForPostponedTrustDecisions(ns_omemo); - future = m_trustStorage.keysForPostponedTrustDecisions(ns_omemo); + future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_omemo); QVERIFY(future.isFinished()); result = future.result(); QVERIFY(result.isEmpty()); @@ -525,7 +899,7 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() QByteArray::fromBase64(QByteArrayLiteral("wsEN32UHCiNjYqTG/J63hY4Nu8tZT42Ni1FxrgyRQ5g=")) } }; // remaining OX keys - future = m_trustStorage.keysForPostponedTrustDecisions(ns_ox); + future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_ox); QVERIFY(future.isFinished()); result = future.result(); QCOMPARE( @@ -537,15 +911,69 @@ void tst_QXmppTrustMemoryStorage::testKeysForPostponedTrustDecisions() false, distrustedKeys) })); - m_trustStorage.removeKeysForPostponedTrustDecisions(); + m_atmTrustStorage.removeKeysForPostponedTrustDecisions(ns_ox); // no OX keys - future = m_trustStorage.keysForPostponedTrustDecisions(ns_ox); + future = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_ox); QVERIFY(future.isFinished()); result = future.result(); QVERIFY(result.isEmpty()); +} - m_trustStorage.removeKeys(); +void tst_QXmppTrustMemoryStorage::atmTestResetAll() +{ + QXmppTrustMessageKeyOwner keyOwnerAlice; + keyOwnerAlice.setJid(QStringLiteral("alice@example.org")); + keyOwnerAlice.setTrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("Wl53ZchbtAtCZQCHROiD20W7UnKTQgWQrjTHAVNw1ic=")), + QByteArray::fromBase64(QByteArrayLiteral("QR05jrab7PFkSLhtdzyXrPfCqhkNCYCrlWATaBMTenE=")) }); + keyOwnerAlice.setDistrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("mB98hhdVps++skUuy4TGy/Vp6RQXLJO4JGf86FAUjyc=")) }); + + QXmppTrustMessageKeyOwner keyOwnerBobTrustedKeys; + keyOwnerBobTrustedKeys.setJid(QStringLiteral("bob@example.com")); + keyOwnerBobTrustedKeys.setTrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("GgTqeRLp1M+MEenzFQym2oqer9PfHukS4brJDQl5ARE=")) }); + + m_atmTrustStorage.addKeysForPostponedTrustDecisions(ns_omemo, + QByteArray::fromBase64(QByteArrayLiteral("Mp6Y4wOF3aMcl38lb/VNbdPF9ucGFqSx2eyaEsqyHKE=")), + { keyOwnerAlice, keyOwnerBobTrustedKeys }); + + QXmppTrustMessageKeyOwner keyOwnerCarol; + keyOwnerCarol.setJid(QStringLiteral("carol@example.net")); + keyOwnerCarol.setTrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("WcL+cEMpEeK+dpqg3Xd3amctzwP8h2MqwXcEzFf6LpU=")), + QByteArray::fromBase64(QByteArrayLiteral("bH3R31z0N97K1fUwG3+bdBrVPuDfXguQapHudkfa5nE=")) }); + keyOwnerCarol.setDistrustedKeys({ QByteArray::fromBase64(QByteArrayLiteral("N0B2StHKk1/slwg1rzybTFzjdg7FChc+3cXmTU/rS8g=")), + QByteArray::fromBase64(QByteArrayLiteral("wsEN32UHCiNjYqTG/J63hY4Nu8tZT42Ni1FxrgyRQ5g=")) }); + + m_atmTrustStorage.addKeysForPostponedTrustDecisions(ns_ox, + QByteArray::fromBase64(QByteArrayLiteral("IL5iwDQwquH7yjb5RAiIP+nvYiBUsNCXtKB8IpKc9QU=")), + { keyOwnerCarol }); + + m_atmTrustStorage.resetAll(ns_omemo); + + auto futureKeysForPostponedTrustDecisions = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_omemo); + QVERIFY(futureKeysForPostponedTrustDecisions.isFinished()); + auto resultKeysForPostponedTrustDecisions = futureKeysForPostponedTrustDecisions.result(); + QVERIFY(resultKeysForPostponedTrustDecisions.isEmpty()); + + QMultiHash<QString, QByteArray> trustedKeys = { { QStringLiteral("carol@example.net"), + QByteArray::fromBase64(QByteArrayLiteral("WcL+cEMpEeK+dpqg3Xd3amctzwP8h2MqwXcEzFf6LpU=")) }, + { QStringLiteral("carol@example.net"), + QByteArray::fromBase64(QByteArrayLiteral("bH3R31z0N97K1fUwG3+bdBrVPuDfXguQapHudkfa5nE=")) } }; + QMultiHash<QString, QByteArray> distrustedKeys = { { QStringLiteral("carol@example.net"), + QByteArray::fromBase64(QByteArrayLiteral("N0B2StHKk1/slwg1rzybTFzjdg7FChc+3cXmTU/rS8g=")) }, + { QStringLiteral("carol@example.net"), + QByteArray::fromBase64(QByteArrayLiteral("wsEN32UHCiNjYqTG/J63hY4Nu8tZT42Ni1FxrgyRQ5g=")) } }; + + futureKeysForPostponedTrustDecisions = m_atmTrustStorage.keysForPostponedTrustDecisions(ns_ox); + QVERIFY(futureKeysForPostponedTrustDecisions.isFinished()); + resultKeysForPostponedTrustDecisions = futureKeysForPostponedTrustDecisions.result(); + QCOMPARE( + resultKeysForPostponedTrustDecisions, + QHash({ std::pair( + true, + trustedKeys), + std::pair( + false, + distrustedKeys) })); } QTEST_MAIN(tst_QXmppTrustMemoryStorage) |
