aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelvin Keskin <melvo@olomono.de>2021-08-28 14:39:02 +0200
committerLinus Jahn <lnj@kaidan.im>2021-09-16 18:43:00 +0200
commitbb8780ecdbfe7eddb8280e696871e71b744d0bff (patch)
tree585989b6e6a58c3f2af42c0681d87e93e2c592e7
parentb147ea5f4004cbd9aa2e7ae3936734a869bf3a44 (diff)
Add QXmppAtmManager
-rw-r--r--doc/xep.doc1
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/base/QXmppConstants.cpp2
-rw-r--r--src/base/QXmppConstants_p.h2
-rw-r--r--src/base/QXmppMessage.cpp39
-rw-r--r--src/base/QXmppMessage.h3
-rw-r--r--src/client/QXmppAtmManager.cpp505
-rw-r--r--src/client/QXmppAtmManager.h68
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/qxmppatmmanager/tst_qxmppatmmanager.cpp2054
-rw-r--r--tests/qxmppmessage/tst_qxmppmessage.cpp8
11 files changed, 2685 insertions, 0 deletions
diff --git a/doc/xep.doc b/doc/xep.doc
index 8e2ae949..453f9334 100644
--- a/doc/xep.doc
+++ b/doc/xep.doc
@@ -55,6 +55,7 @@ Complete:
- \xep{0382, Spoiler messages} (v0.2)
- \xep{0428, Fallback Indication} (v0.1)
- \xep{0434, Trust Messages} (v0.5)
+- \xep{0450, Automatic Trust Management (ATM)} (v0.3)
Ongoing:
- \xep{0009, Jabber-RPC} (API is not finalized yet)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5b12c3ee..86849223 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -85,6 +85,7 @@ set(INSTALL_HEADER_FILES
# Client
client/QXmppArchiveManager.h
+ client/QXmppAtmManager.h
client/QXmppAttentionManager.h
client/QXmppBookmarkManager.h
client/QXmppCarbonManager.h
@@ -189,6 +190,7 @@ set(SOURCE_FILES
# Client
client/QXmppArchiveManager.cpp
+ client/QXmppAtmManager.cpp
client/QXmppAttentionManager.cpp
client/QXmppBookmarkManager.cpp
client/QXmppCarbonManager.cpp
diff --git a/src/base/QXmppConstants.cpp b/src/base/QXmppConstants.cpp
index db896683..c6ae77de 100644
--- a/src/base/QXmppConstants.cpp
+++ b/src/base/QXmppConstants.cpp
@@ -186,3 +186,5 @@ const char* ns_mix_misc = "urn:xmpp:mix:misc:0";
const char* ns_fallback_indication = "urn:xmpp:fallback:0";
// XEP-0434: Trust Messages (TM)
const char* ns_tm = "urn:xmpp:tm:0";
+// XEP-0450: Automatic Trust Management (ATM)
+const char* ns_atm = "urn:xmpp:atm:1";
diff --git a/src/base/QXmppConstants_p.h b/src/base/QXmppConstants_p.h
index 1d55ad03..2b9e70d6 100644
--- a/src/base/QXmppConstants_p.h
+++ b/src/base/QXmppConstants_p.h
@@ -198,5 +198,7 @@ extern const char* ns_mix_misc;
extern const char* ns_fallback_indication;
// XEP-0434: Trust Messages (TM)
extern const char* ns_tm;
+// XEP-0450: Automatic Trust Management (ATM)
+extern const char* ns_atm;
#endif // QXMPPCONSTANTS_H
diff --git a/src/base/QXmppMessage.cpp b/src/base/QXmppMessage.cpp
index f975ae3c..e97731ae 100644
--- a/src/base/QXmppMessage.cpp
+++ b/src/base/QXmppMessage.cpp
@@ -108,6 +108,7 @@ public:
QString thread;
QString parentThread;
QXmppMessage::Type type;
+ QString senderKey;
// XEP-0066: Out of Band Data
QString outOfBandUrl;
@@ -325,6 +326,44 @@ void QXmppMessage::setParentThread(const QString &parent)
}
///
+/// Returns the ID of this message's sender's public long-term key.
+///
+/// The key ID is not part of a transmitted message and thus not de- /
+/// serialized.
+/// Instead, the key ID is set by an encryption protocol such as
+/// \xep{0384, OMEMO Encryption} when it decrypts this message.
+/// It can be used by trust management protocols such as
+/// \xep{0450, Automatic Trust Management (ATM)}.
+///
+/// \return the ID of the sender's key
+///
+/// \since QXmpp 1.5
+///
+QString QXmppMessage::senderKey() const
+{
+ return d->senderKey;
+}
+
+///
+/// Sets the ID of this message's sender's public long-term key.
+///
+/// The key ID is not part of a transmitted message and thus not de- /
+/// serialized.
+/// Instead, the key ID is set by an encryption protocol such as
+/// \xep{0384, OMEMO Encryption} when it decrypts this message.
+/// It can be used by trust management protocols such as
+/// \xep{0450, Automatic Trust Management (ATM)}.
+///
+/// \param keyId ID of the sender's key
+///
+/// \since QXmpp 1.5
+///
+void QXmppMessage::setSenderKey(const QString &keyId)
+{
+ d->senderKey = keyId;
+}
+
+///
/// Returns a possibly attached URL from \xep{0066}: Out of Band Data
///
/// \since QXmpp 1.0
diff --git a/src/base/QXmppMessage.h b/src/base/QXmppMessage.h
index 6688d3b6..b2cb972d 100644
--- a/src/base/QXmppMessage.h
+++ b/src/base/QXmppMessage.h
@@ -136,6 +136,9 @@ public:
QXmppMessage::Type type() const;
void setType(QXmppMessage::Type);
+ QString senderKey() const;
+ void setSenderKey(const QString &keyId);
+
// XEP-0066: Out of Band Data
QString outOfBandUrl() const;
void setOutOfBandUrl(const QString &);
diff --git a/src/client/QXmppAtmManager.cpp b/src/client/QXmppAtmManager.cpp
new file mode 100644
index 00000000..df3b1350
--- /dev/null
+++ b/src/client/QXmppAtmManager.cpp
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2008-2021 The QXmpp developers
+ *
+ * Author:
+ * Melvin Keskin <melvo@olomono.de>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include "QXmppAtmManager.h"
+
+#include "QXmppCarbonManager.h"
+#include "QXmppClient.h"
+#include "QXmppConstants_p.h"
+#include "QXmppFutureUtils_p.h"
+#include "QXmppTrustMessageElement.h"
+#include "QXmppUtils.h"
+
+#include <QCoreApplication>
+#include <QDomElement>
+#include <QList>
+
+using namespace QXmpp::Private;
+
+///
+/// \class QXmppAtmManager
+///
+/// \brief The QXmppAtmManager class represents a manager for
+/// \xep{0450, Automatic Trust Management (ATM)}.
+///
+/// For interacting with the storage, a corresponding implementation of the
+/// 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:
+///
+///\code
+/// QXmppTrustStorage *trustStorage = new QXmppTrustMemoryStorage;
+/// \endcode
+///
+/// Afterwards, this manager must be added with the storage:
+/// \code
+/// QXmppAtmManager *manager = new QXmppAtmManager(trustStorage);
+/// client->addExtension(manager);
+/// \endcode
+///
+/// It is strongly recommended to enable \xep{0280, Message Carbons} with
+/// \code
+/// QXmppCarbonManager *carbonManager = new QXmppCarbonManager;
+/// carbonManager->setCarbonsEnabled(true);
+/// client->addExtension(carbonManager);
+/// \endcode
+/// and \xep{0313, Message Archive Management} with
+/// \code
+/// QXmppMamManager *mamManager = new QXmppMamManager;
+/// client->addExtension(mamManager);
+/// \endcode
+/// for delivering trust messages to all online and offline endpoints.
+///
+/// In addition, archiving via MAM must be enabled on the server.
+///
+/// \warning THIS API IS NOT FINALIZED YET!
+///
+/// \ingroup Managers
+///
+/// \since QXmpp 1.5
+///
+
+///
+/// Constructs an ATM manager.
+///
+/// \param trustStorage trust storage implementation
+///
+QXmppAtmManager::QXmppAtmManager(QXmppTrustStorage *trustStorage)
+{
+ m_trustStorage = trustStorage;
+}
+
+///
+/// Authenticates or distrusts keys manually (e.g., by the Trust Message URI of
+/// a scanned QR code or after entering key IDs by hand) and sends corresponding
+/// trust messages.
+///
+/// \param encryption encryption protocol namespace
+/// \param keyOwnerJid JID of the key owner
+/// \param keyIdsForAuthentication IDs of the keys being authenticated
+/// \param keyIdsForDistrusting IDs of the keys being distrusted
+///
+QFuture<void> QXmppAtmManager::makeTrustDecisions(const QString &encryption, const QString &keyOwnerJid, const QList<QString> &keyIdsForAuthentication, const QList<QString> &keyIdsForDistrusting)
+{
+ auto interface = std::make_shared<QFutureInterface<void>>(QFutureInterfaceBase::Started);
+
+ auto future = m_trustStorage->keys(encryption, QXmppTrustStorage::Authenticated | QXmppTrustStorage::ManuallyDistrusted);
+ await(future, this, [=](const QHash<QXmppTrustStorage::TrustLevel, QMultiHash<QString, QString>> &&keys) {
+ const auto authenticatedKeys = keys.value(QXmppTrustStorage::Authenticated);
+ const auto manuallyDistrustedKeys = keys.value(QXmppTrustStorage::ManuallyDistrusted);
+ const auto ownJid = client()->configuration().jidBare();
+ const auto ownAuthenticatedKeys = authenticatedKeys.values(ownJid);
+
+ // Create a key owner for the keys being authenticated or
+ // distrusted.
+ QXmppTrustMessageKeyOwner keyOwner;
+ keyOwner.setJid(keyOwnerJid);
+
+ QList<QString> modifiedAuthenticatedKeys;
+ QList<QString> modifiedManuallyDistrustedKeys;
+
+ for (const auto &keyId : keyIdsForAuthentication) {
+ if (!authenticatedKeys.contains(keyOwnerJid, keyId)) {
+ modifiedAuthenticatedKeys.append(keyId);
+ }
+ }
+
+ for (const auto &keyId : keyIdsForDistrusting) {
+ if (!manuallyDistrustedKeys.contains(keyOwnerJid, keyId)) {
+ modifiedManuallyDistrustedKeys.append(keyId);
+ }
+ }
+
+ if (modifiedAuthenticatedKeys.isEmpty() && modifiedManuallyDistrustedKeys.isEmpty()) {
+ // Skip further processing if there are no changes.
+ interface->reportFinished();
+ } else {
+ keyOwner.setTrustedKeys(modifiedAuthenticatedKeys);
+ keyOwner.setDistrustedKeys(modifiedManuallyDistrustedKeys);
+
+ QMultiHash<QString, QString> keysBeingAuthenticated;
+ QMultiHash<QString, QString> keysBeingDistrusted;
+
+ for (const auto &key : std::as_const(modifiedAuthenticatedKeys)) {
+ keysBeingAuthenticated.insert(keyOwnerJid, key);
+ }
+
+ for (const auto &key : std::as_const(modifiedManuallyDistrustedKeys)) {
+ keysBeingDistrusted.insert(keyOwnerJid, key);
+ }
+
+ // Create a key owner for authenticated and distrusted keys of own
+ // endpoints.
+ QXmppTrustMessageKeyOwner ownKeyOwner;
+ ownKeyOwner.setJid(ownJid);
+
+ if (!ownAuthenticatedKeys.isEmpty()) {
+ ownKeyOwner.setTrustedKeys(ownAuthenticatedKeys);
+ }
+
+ const auto ownManuallyDistrustedKeys = manuallyDistrustedKeys.values(ownJid);
+ if (!ownManuallyDistrustedKeys.isEmpty()) {
+ ownKeyOwner.setDistrustedKeys(ownManuallyDistrustedKeys);
+ }
+
+ const auto areOwnKeysProcessed = keyOwnerJid == ownJid;
+ if (areOwnKeysProcessed) {
+ auto authenticatedKeysTemp = authenticatedKeys;
+ authenticatedKeysTemp.remove(ownJid);
+ const auto contactsAuthenticatedKeys = authenticatedKeysTemp;
+
+ const auto contactsWithAuthenticatedKeys = contactsAuthenticatedKeys.uniqueKeys();
+
+ // Send trust messages for the keys of the own endpoints being
+ // authenticated or distrusted to endpoints of contacts with
+ // authenticated keys.
+ // Own endpoints with authenticated keys can receive the trust
+ // messages via Message Carbons.
+ for (const auto &contactJid : contactsWithAuthenticatedKeys) {
+ sendTrustMessage(encryption, { keyOwner }, contactJid);
+ }
+
+ // Send a trust message for the keys of the own endpoints being
+ // authenticated or distrusted to other own endpoints with
+ // authenticated keys.
+ // It is skipped if a trust message is already delivered via
+ // Message Carbons or there are no other own endpoints with
+ // authenticated keys.
+ const auto *carbonManager = client()->findExtension<QXmppCarbonManager>();
+ const auto isMessageCarbonsDisabled = !carbonManager || !carbonManager->carbonsEnabled();
+ if (isMessageCarbonsDisabled || (contactsAuthenticatedKeys.isEmpty() && !ownAuthenticatedKeys.isEmpty())) {
+ sendTrustMessage(encryption, { keyOwner }, ownJid);
+ }
+
+ auto future = makeTrustDecisions(encryption, keysBeingAuthenticated, keysBeingDistrusted);
+ await(future, this, [=]() {
+ // Send a trust message for all authenticated or distrusted
+ // keys to the own endpoints whose keys have been
+ // authenticated.
+ // It is skipped if no keys of own endpoints have been
+ // authenticated.
+ if (!keyOwner.trustedKeys().isEmpty()) {
+ auto manuallyDistrustedKeysTemp = manuallyDistrustedKeys;
+ manuallyDistrustedKeysTemp.remove(ownJid);
+ const auto contactsManuallyDistrustedKeys = manuallyDistrustedKeysTemp;
+
+ auto contactJids = contactsManuallyDistrustedKeys.uniqueKeys() << contactsWithAuthenticatedKeys;
+
+ // Remove duplicates from contactJids.
+ std::sort(contactJids.begin(), contactJids.end());
+ contactJids.erase(std::unique(contactJids.begin(), contactJids.end()), contactJids.end());
+
+ QList<QXmppTrustMessageKeyOwner> contactsKeyOwners;
+
+ for (const auto &contactJid : std::as_const(contactJids)) {
+ QXmppTrustMessageKeyOwner contactKeyOwner;
+ contactKeyOwner.setJid(contactJid);
+ contactKeyOwner.setTrustedKeys(contactsAuthenticatedKeys.values(contactJid));
+
+ if (const auto contactManuallyDistrustedKeys = contactsManuallyDistrustedKeys.values(contactJid); !contactsManuallyDistrustedKeys.isEmpty()) {
+ contactKeyOwner.setDistrustedKeys(contactManuallyDistrustedKeys);
+ }
+
+ contactsKeyOwners.append(contactKeyOwner);
+ }
+
+ auto allKeyOwners = contactsKeyOwners;
+
+ if (!(ownKeyOwner.trustedKeys().isEmpty() && ownKeyOwner.distrustedKeys().isEmpty())) {
+ allKeyOwners.append(ownKeyOwner);
+ }
+
+ if (!allKeyOwners.isEmpty()) {
+ sendTrustMessage(encryption, allKeyOwners, ownJid);
+ }
+ }
+
+ interface->reportFinished();
+ });
+ } else {
+ // Send a trust message for the keys of the contact's endpoints
+ // being authenticated or distrusted to own endpoints
+ // with authenticated keys.
+ if (!ownAuthenticatedKeys.isEmpty()) {
+ sendTrustMessage(encryption, { keyOwner }, ownJid);
+ }
+
+ auto future = makeTrustDecisions(encryption, keysBeingAuthenticated, keysBeingDistrusted);
+ await(future, this, [=]() {
+ // Send a trust message for own authenticated or distrusted
+ // keys to the contact's endpoints whose keys have been
+ // authenticated.
+ // It is skipped if no keys of contacts have been
+ // authenticated or there are no keys for the trust message.
+ if (!keyOwner.trustedKeys().isEmpty() && !(ownKeyOwner.trustedKeys().isEmpty() && ownKeyOwner.distrustedKeys().isEmpty())) {
+ sendTrustMessage(encryption, { ownKeyOwner }, keyOwnerJid);
+ }
+
+ interface->reportFinished();
+ });
+ }
+ }
+ });
+
+ return interface->future();
+}
+
+/// \cond
+bool QXmppAtmManager::handleStanza(const QDomElement &)
+{
+ return false;
+}
+
+void QXmppAtmManager::setClient(QXmppClient *client)
+{
+ QXmppClientExtension::setClient(client);
+ connect(client, &QXmppClient::messageReceived, this, &QXmppAtmManager::handleMessageReceived);
+}
+
+void QXmppAtmManager::handleMessageReceived(const QXmppMessage &message)
+{
+ handleMessage(message);
+}
+/// \endcond
+
+///
+/// Authenticates or distrusts keys.
+///
+/// \param encryption encryption protocol namespace
+/// \param keyIdsForAuthentication key owners' bare JIDs mapped to the IDs of
+/// their keys being authenticated
+/// \param keyIdsForDistrusting key owners' bare JIDs mapped to the IDs of their
+/// keys being distrusted
+///
+QFuture<void> QXmppAtmManager::makeTrustDecisions(const QString &encryption, const QMultiHash<QString, QString> &keyIdsForAuthentication, const QMultiHash<QString, QString> &keyIdsForDistrusting)
+{
+ auto interface = std::make_shared<QFutureInterface<void>>(QFutureInterfaceBase::Started);
+
+ auto future = authenticate(encryption, keyIdsForAuthentication);
+ await(future, this, [=]() {
+ auto future = distrust(encryption, keyIdsForDistrusting);
+ await(future, this, [=]() {
+ interface->reportFinished();
+ });
+ });
+
+ return interface->future();
+}
+
+///
+/// Handles incoming messages and uses included trust message elements for
+/// making automatic trust decisions.
+///
+/// \param message message that can contain a trust message element
+///
+QFuture<void> QXmppAtmManager::handleMessage(const QXmppMessage &message)
+{
+ auto interface = std::make_shared<QFutureInterface<void>>(QFutureInterfaceBase::Started);
+
+ if (const auto trustMessageElement = message.trustMessageElement(); trustMessageElement && trustMessageElement->usage() == ns_atm && message.from() != client()->configuration().jid()) {
+ const auto senderJid = QXmppUtils::jidToBareJid(message.from());
+ const auto senderKey = message.senderKey();
+ const auto encryption = trustMessageElement->encryption();
+
+ auto future = m_trustStorage->trustLevel(encryption, senderKey);
+ await(future, this, [=](const auto &&senderKeyTrustLevel) {
+ const auto isSenderKeyAuthenticated = senderKeyTrustLevel == QXmppTrustStorage::Authenticated;
+
+ // key owner JIDs mapped to key IDs
+ QMultiHash<QString, QString> keysBeingAuthenticated;
+ QMultiHash<QString, QString> keysBeingDistrusted;
+
+ QList<QXmppTrustMessageKeyOwner> keyOwnersForPostponedTrustDecisions;
+
+ const auto ownJid = client()->configuration().jidBare();
+ const auto isOwnTrustMessage = senderJid == ownJid;
+ const auto keyOwners = trustMessageElement->keyOwners();
+
+ for (const auto &keyOwner : keyOwners) {
+ const auto keyOwnerJid = keyOwner.jid();
+
+ // A trust message from an own endpoint is allowed to
+ // authenticate or distrust the keys of own endpoints and
+ // endpoints of contacts.
+ // Whereas a trust message from an endpoint of a contact is
+ // only allowed to authenticate or distrust the keys of that
+ // contact's own endpoints.
+ const auto isSenderQualifiedForTrustDecisions = isOwnTrustMessage || senderJid == keyOwnerJid;
+ if (isSenderQualifiedForTrustDecisions) {
+ // Make trust decisions if the key of the sender is
+ // authenticated.
+ // Othwerwise, store the keys of the trust message for
+ // making the trust decisions as soon as the key of the
+ // sender is authenticated.
+ if (isSenderKeyAuthenticated) {
+ const auto trustedKeys = keyOwner.trustedKeys();
+ for (const auto &key : trustedKeys) {
+ keysBeingAuthenticated.insert(keyOwnerJid, key);
+ }
+
+ const auto distrustedKeys = keyOwner.distrustedKeys();
+ for (const auto &key : distrustedKeys) {
+ keysBeingDistrusted.insert(keyOwnerJid, key);
+ }
+ } else {
+ keyOwnersForPostponedTrustDecisions.append(keyOwner);
+ }
+ }
+ }
+
+ auto future = m_trustStorage->addKeysForPostponedTrustDecisions(encryption, senderKey, keyOwnersForPostponedTrustDecisions);
+ await(future, this, [=]() {
+ auto future = makeTrustDecisions(encryption, keysBeingAuthenticated, keysBeingDistrusted);
+ await(future, this, [=]() {
+ interface->reportFinished();
+ });
+ });
+ });
+ } else {
+ // Skip further processing in the following cases:
+ // 1. The message does not contain a trust message element.
+ // 2. The trust message is sent by this endpoint and reflected via
+ // Message Carbons.
+ interface->reportFinished();
+ }
+
+ return interface->future();
+}
+
+///
+/// Authenticates keys automatically by the content of a trust message.
+///
+/// \param encryption encryption protocol namespace
+/// \param keyIds key owners' bare JIDs mapped to the IDs of their keys
+///
+QFuture<void> QXmppAtmManager::authenticate(const QString &encryption, const QMultiHash<QString, QString> &keyIds)
+{
+ auto interface = std::make_shared<QFutureInterface<void>>(QFutureInterfaceBase::Started);
+
+ if (keyIds.isEmpty()) {
+ interface->reportFinished();
+ } else {
+ auto future = m_trustStorage->setTrustLevel(encryption, keyIds, QXmppTrustStorage::Authenticated);
+ await(future, this, [=]() {
+ auto future = distrustAutomaticallyTrustedKeys(encryption, keyIds.uniqueKeys());
+ await(future, this, [=]() {
+ auto future = makePostponedTrustDecisions(encryption, keyIds.values());
+ await(future, this, [=]() {
+ interface->reportFinished();
+ });
+ });
+ });
+ }
+
+ return interface->future();
+}
+
+///
+/// Distrusts keys automatically by the content of a trust message.
+///
+/// \param encryption encryption protocol namespace
+/// \param keyIds key owners' bare JIDs mapped to the IDs of their keys
+///
+QFuture<void> QXmppAtmManager::distrust(const QString &encryption, const QMultiHash<QString, QString> &keyIds)
+{
+ auto interface = std::make_shared<QFutureInterface<void>>(QFutureInterfaceBase::Started);
+
+ if (keyIds.isEmpty()) {
+ interface->reportFinished();
+ } else {
+ auto future = m_trustStorage->setTrustLevel(encryption, keyIds, QXmppTrustStorage::ManuallyDistrusted);
+ await(future, this, [=]() {
+ auto future = m_trustStorage->removeKeysForPostponedTrustDecisions(encryption, keyIds.values());
+ await(future, this, [=]() {
+ interface->reportFinished();
+ });
+ });
+ }
+
+ return interface->future();
+}
+
+///
+/// Distrusts all formerly automatically trusted keys (as specifed by the
+/// security policy TOAKAFA).
+///
+/// \param encryption encryption protocol namespace
+/// \param keyOwnerJids bare JIDs of the key owners
+///
+QFuture<void> QXmppAtmManager::distrustAutomaticallyTrustedKeys(const QString &encryption, const QList<QString> &keyOwnerJids)
+{
+ return m_trustStorage->setTrustLevel(encryption, keyOwnerJids, QXmppTrustStorage::AutomaticallyTrusted, QXmppTrustStorage::AutomaticallyDistrusted);
+}
+
+///
+/// Authenticates or distrusts keys for whom earlier trust messages were
+/// received but not used for authenticating or distrusting at that time.
+///
+/// As soon as the senders' keys have been authenticated, all postponed trust
+/// decisions can be performed by this method.
+///
+/// \param encryption encryption protocol namespace
+/// \param senderKeyIds IDs of the keys that were used by the senders
+///
+QFuture<void> QXmppAtmManager::makePostponedTrustDecisions(const QString &encryption, const QList<QString> &senderKeyIds)
+{
+ auto interface = std::make_shared<QFutureInterface<void>>(QFutureInterfaceBase::Started);
+
+ auto future = m_trustStorage->keysForPostponedTrustDecisions(encryption, senderKeyIds);
+ await(future, this, [=](const QHash<bool, QMultiHash<QString, QString>> &&keysForPostponedTrustDecisions) {
+ // JIDs of key owners mapped to the IDs of their keys
+ const auto keysBeingAuthenticated = keysForPostponedTrustDecisions.value(true);
+ const auto keysBeingDistrusted = keysForPostponedTrustDecisions.value(false);
+
+ auto future = m_trustStorage->removeKeysForPostponedTrustDecisions(encryption, keysBeingAuthenticated.values(), keysBeingDistrusted.values());
+ await(future, this, [=]() {
+ auto future = makeTrustDecisions(encryption, keysBeingAuthenticated, keysBeingDistrusted);
+ await(future, this, [=]() {
+ interface->reportFinished();
+ });
+ });
+ });
+
+ return interface->future();
+}
+
+///
+/// Sends a trust message.
+///
+/// \param encryption namespace of the encryption
+/// \param keyOwners key owners containing the data for authentication or distrusting
+/// \param recipientJid JID of the recipient
+///
+QFuture<QXmpp::SendResult> QXmppAtmManager::sendTrustMessage(const QString &encryption, const QList<QXmppTrustMessageKeyOwner> &keyOwners, const QString &recipientJid)
+{
+ QXmppTrustMessageElement trustMessageElement;
+ trustMessageElement.setUsage(ns_atm);
+ trustMessageElement.setEncryption(encryption);
+ trustMessageElement.setKeyOwners(keyOwners);
+
+ QXmppMessage message;
+ message.setTo(recipientJid);
+ message.setTrustMessageElement(trustMessageElement);
+ return client()->send(message);
+}
diff --git a/src/client/QXmppAtmManager.h b/src/client/QXmppAtmManager.h
new file mode 100644
index 00000000..2df2dfce
--- /dev/null
+++ b/src/client/QXmppAtmManager.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008-2021 The QXmpp developers
+ *
+ * Author:
+ * Melvin Keskin <melvo@olomono.de>
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef QXMPPATMMANAGER_H
+#define QXMPPATMMANAGER_H
+
+#include "QXmppClientExtension.h"
+#include "QXmppMessage.h"
+#include "QXmppSendResult.h"
+#include "QXmppTrustMessageKeyOwner.h"
+#include "QXmppTrustStorage.h"
+
+class QXMPP_EXPORT QXmppAtmManager : public QXmppClientExtension
+{
+ Q_OBJECT
+
+public:
+ QXmppAtmManager(QXmppTrustStorage *trustStorage);
+ QFuture<void> makeTrustDecisions(const QString &encryption, const QString &keyOwnerJid, const QList<QString> &keyIdsForAuthentication, const QList<QString> &keyIdsForDistrusting = {});
+
+ /// \cond
+ bool handleStanza(const QDomElement &stanza) override;
+
+protected:
+ void setClient(QXmppClient *client) override;
+
+private slots:
+ void handleMessageReceived(const QXmppMessage &message);
+ /// \endcond
+
+private:
+ QFuture<void> makeTrustDecisions(const QString &encryption, const QMultiHash<QString, QString> &keyIdsForAuthentication, const QMultiHash<QString, QString> &keyIdsForDistrusting);
+ QFuture<void> handleMessage(const QXmppMessage &message);
+
+ QFuture<void> authenticate(const QString &encryption, const QMultiHash<QString, QString> &keyIds);
+ QFuture<void> distrust(const QString &encryption, const QMultiHash<QString, QString> &keyIds);
+
+ QFuture<void> distrustAutomaticallyTrustedKeys(const QString &encryption, const QList<QString> &keyOwnerJids);
+ QFuture<void> makePostponedTrustDecisions(const QString &encryption, const QList<QString> &senderKeyIds);
+
+ QFuture<QXmpp::SendResult> sendTrustMessage(const QString &encryption, const QList<QXmppTrustMessageKeyOwner> &keyOwners, const QString &recipientJid);
+
+ QXmppTrustStorage *m_trustStorage;
+
+ friend class tst_QXmppAtmManager;
+};
+
+#endif // QXMPPATMMANAGER_H
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index db969872..b01b691d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -15,6 +15,7 @@ include_directories(${PROJECT_BINARY_DIR}/src/base)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_simple_test(qxmpparchiveiq)
+add_simple_test(qxmppatmmanager)
add_simple_test(qxmppattentionmanager)
add_simple_test(qxmppbindiq)
add_simple_test(qxmppbitsofbinarycontentid)
diff --git a/tests/qxmppatmmanager/tst_qxmppatmmanager.cpp b/tests/qxmppatmmanager/tst_qxmppatmmanager.cpp
new file mode 100644
index 00000000..ab6071b3
--- /dev/null
+++ b/tests/qxmppatmmanager/tst_qxmppatmmanager.cpp
@@ -0,0 +1,2054 @@
+/*
+ * Copyright (C) 2008-2021 The QXmpp developers
+ *
+ * Authors:
+ * Melvin Keskin
+ *
+ * Source:
+ * https://github.com/qxmpp-project/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include "QXmppAtmManager.h"
+#include "QXmppCarbonManager.h"
+#include "QXmppClient.h"
+#include "QXmppConstants.cpp"
+#include "QXmppConstants_p.h"
+#include "QXmppTrustMemoryStorage.h"
+#include "QXmppTrustMessageElement.h"
+#include "QXmppUtils.h"
+
+#include "util.h"
+#include <QObject>
+#include <QSet>
+
+Q_DECLARE_METATYPE(QList<QXmppTrustMessageKeyOwner>)
+
+// time period (in ms) to wait for a trust message that should not be sent.
+constexpr int UNEXPECTED_TRUST_MESSAGE_WAITING_TIMEOUT = 1000;
+
+class tst_QXmppAtmManager : public QObject
+{
+ Q_OBJECT
+
+signals:
+ void unexpectedTrustMessageSent();
+
+private slots:
+ void initTestCase();
+ void testSendTrustMessage();
+ void testMakePostponedTrustDecisions();
+ void testDistrustAutomaticallyTrustedKeys();
+ void testDistrust();
+ void testAuthenticate();
+ void testMakeTrustDecisions();
+ void testHandleMessage_data();
+ void testHandleMessage();
+ void testMakeTrustDecisionsNoKeys();
+ void testMakeTrustDecisionsOwnKeys();
+ void testMakeTrustDecisionsOwnKeysNoOwnEndpoints();
+ void testMakeTrustDecisionsOwnKeysNoOwnEndpointsWithAuthenticatedKeys();
+ void testMakeTrustDecisionsOwnKeysNoContactsWithAuthenticatedKeys();
+ void testMakeTrustDecisionsSoleOwnKeyDistrusted();
+ void testMakeTrustDecisionsContactKeys();
+ void testMakeTrustDecisionsContactKeysNoOwnEndpoints();
+ void testMakeTrustDecisionsContactKeysNoOwnEndpointsWithAuthenticatedKeys();
+ void testMakeTrustDecisionsSoleContactKeyDistrusted();
+
+private:
+ void testMakeTrustDecisionsOwnKeysDone();
+ void testMakeTrustDecisionsContactKeysDone();
+ void clearTrustStorage();
+
+ QXmppClient m_client;
+ QXmppLogger m_logger;
+ QXmppAtmManager *m_manager;
+ QXmppTrustMemoryStorage *m_trustStorage;
+ QXmppCarbonManager *m_carbonManager;
+};
+
+void tst_QXmppAtmManager::initTestCase()
+{
+ m_trustStorage = new QXmppTrustMemoryStorage;
+ m_manager = new QXmppAtmManager(m_trustStorage);
+ m_client.addExtension(m_manager);
+ m_client.configuration().setJid("alice@example.org/phone");
+
+ m_carbonManager = new QXmppCarbonManager;
+ m_carbonManager->setCarbonsEnabled(true);
+ m_client.addExtension(m_carbonManager);
+
+ m_logger.setLoggingType(QXmppLogger::SignalLogging);
+ m_client.setLogger(&m_logger);
+}
+
+void tst_QXmppAtmManager::testSendTrustMessage()
+{
+ QXmppTrustMessageKeyOwner keyOwnerAlice;
+ keyOwnerAlice.setJid(QStringLiteral("alice@example.org"));
+ keyOwnerAlice.setTrustedKeys({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") });
+ keyOwnerAlice.setDistrustedKeys({ QStringLiteral("788a40d0eae5a40409d4687a36d3106bbe361971aec0245598571e7b629edc6b"),
+ QStringLiteral("b6c21e111bd4f9ed06ee0485cb302bf1238e90b89986a04061e48d49ddbe95cb") });
+
+ QXmppTrustMessageKeyOwner keyOwnerBob;
+ keyOwnerBob.setJid(QStringLiteral("bob@example.com"));
+ keyOwnerBob.setTrustedKeys({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") });
+ keyOwnerBob.setDistrustedKeys({ QStringLiteral("788a40d0eae5a40409d4687a36d3106bbe361971aec0245598571e7b629edc6b"),
+ QStringLiteral("b6c21e111bd4f9ed06ee0485cb302bf1238e90b89986a04061e48d49ddbe95cb") });
+
+ bool isMessageSent = false;
+ const QObject context;
+
+ // trust message to own endpoints
+ connect(&m_logger, &QXmppLogger::message, &context, [=, &isMessageSent, &keyOwnerAlice, &keyOwnerBob](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ isMessageSent = true;
+
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ const std::optional<QXmppTrustMessageElement> trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto sentKeyOwners = trustMessageElement->keyOwners();
+
+ QCOMPARE(sentKeyOwners.size(), 2);
+
+ for (auto &sentKeyOwner : sentKeyOwners) {
+ if (sentKeyOwner.jid() == keyOwnerAlice.jid()) {
+ QCOMPARE(sentKeyOwner.trustedKeys(), keyOwnerAlice.trustedKeys());
+ QCOMPARE(sentKeyOwner.distrustedKeys(), keyOwnerAlice.distrustedKeys());
+ } else if (sentKeyOwner.jid() == keyOwnerBob.jid()) {
+ QCOMPARE(sentKeyOwner.trustedKeys(), keyOwnerBob.trustedKeys());
+ QCOMPARE(sentKeyOwner.distrustedKeys(), keyOwnerBob.distrustedKeys());
+ } else {
+ QFAIL("Unexpected key owner sent!");
+ }
+ }
+ }
+ });
+
+ m_manager->sendTrustMessage(ns_omemo, { keyOwnerAlice, keyOwnerBob }, QStringLiteral("alice@example.org"));
+
+ QVERIFY(isMessageSent);
+}
+
+void tst_QXmppAtmManager::testMakePostponedTrustDecisions()
+{
+ clearTrustStorage();
+
+ QXmppTrustMessageKeyOwner keyOwnerAlice;
+ keyOwnerAlice.setJid(QStringLiteral("alice@example.org"));
+ keyOwnerAlice.setTrustedKeys({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") });
+ keyOwnerAlice.setDistrustedKeys({ QStringLiteral("788a40d0eae5a40409d4687a36d3106bbe361971aec0245598571e7b629edc6b"),
+ QStringLiteral("b6c21e111bd4f9ed06ee0485cb302bf1238e90b89986a04061e48d49ddbe95cb") });
+
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("c33b0b7420ed386508a0b90701037715db7ce862e3134ef5e85d269dc8bfa556"),
+ { keyOwnerAlice });
+
+ QXmppTrustMessageKeyOwner keyOwnerBob;
+ keyOwnerBob.setJid(QStringLiteral("bob@example.com"));
+ keyOwnerBob.setTrustedKeys({ QStringLiteral("cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac"),
+ QStringLiteral("ddba9d09f8506a5b0ea772dcac556e702401e29451582ca805357c28cfe83a16") });
+ keyOwnerBob.setDistrustedKeys({ QStringLiteral("6da21f2f14214ebb58e49999bec2da53531e9c0535c3065c23507b33259ad08b"),
+ QStringLiteral("537f949e44e9d7682eb0a6f35b037496a0cb10f6f609d3313f86d8f39abda710") });
+
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("705dcb8b775d109cedf6bc3fd5e026312df5fc6fc6e194e97fef706c4b39d470"),
+ { keyOwnerBob });
+
+ QXmppTrustMessageKeyOwner keyOwnerCarol;
+ keyOwnerCarol.setJid(QStringLiteral("carol@example.net"));
+ keyOwnerCarol.setTrustedKeys({ QStringLiteral("3b145a90018ab57cae07db1d1f78090dad57cec575f0100c7157ff9b5bc3dd78") });
+ keyOwnerCarol.setDistrustedKeys({ QStringLiteral("4ca6481a110c73e8320a0ac91320a77fb3adba804584eba939685dc0585f6419") });
+
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("6609344b11856de4a00f0fd96a7cdafe3ccdaebeadd4b5348d85f677b45178a6"),
+ { keyOwnerCarol });
+
+ auto futureVoid = m_manager->makePostponedTrustDecisions(ns_omemo,
+ { QStringLiteral("c33b0b7420ed386508a0b90701037715db7ce862e3134ef5e85d269dc8bfa556"),
+ QStringLiteral("705dcb8b775d109cedf6bc3fd5e026312df5fc6fc6e194e97fef706c4b39d470") });
+ while (!futureVoid.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ auto futurePotsponed = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo,
+ { QStringLiteral("c33b0b7420ed386508a0b90701037715db7ce862e3134ef5e85d269dc8bfa556"),
+ QStringLiteral("705dcb8b775d109cedf6bc3fd5e026312df5fc6fc6e194e97fef706c4b39d470") });
+ QVERIFY(futurePotsponed.isFinished());
+ auto resultPostponed = futurePotsponed.result();
+ QVERIFY(resultPostponed.isEmpty());
+
+ QMultiHash<QString, QString> trustedKeys = { { QStringLiteral("carol@example.net"),
+ QStringLiteral("3b145a90018ab57cae07db1d1f78090dad57cec575f0100c7157ff9b5bc3dd78") } };
+ QMultiHash<QString, QString> distrustedKeys = { { QStringLiteral("carol@example.net"),
+ QStringLiteral("4ca6481a110c73e8320a0ac91320a77fb3adba804584eba939685dc0585f6419") } };
+
+ futurePotsponed = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo,
+ { QStringLiteral("6609344b11856de4a00f0fd96a7cdafe3ccdaebeadd4b5348d85f677b45178a6") });
+ QVERIFY(futurePotsponed.isFinished());
+ resultPostponed = futurePotsponed.result();
+ QCOMPARE(
+ resultPostponed,
+ QHash({ std::pair(
+ true,
+ trustedKeys),
+ std::pair(
+ false,
+ distrustedKeys) }));
+
+ QMultiHash<QString, QString> authenticatedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("ddba9d09f8506a5b0ea772dcac556e702401e29451582ca805357c28cfe83a16") } };
+
+ auto future = m_trustStorage->keys(ns_omemo,
+ QXmppTrustStorage::Authenticated);
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ authenticatedKeys) }));
+
+ QMultiHash<QString, QString> manuallyDistrustedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("788a40d0eae5a40409d4687a36d3106bbe361971aec0245598571e7b629edc6b") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("b6c21e111bd4f9ed06ee0485cb302bf1238e90b89986a04061e48d49ddbe95cb") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("6da21f2f14214ebb58e49999bec2da53531e9c0535c3065c23507b33259ad08b") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("537f949e44e9d7682eb0a6f35b037496a0cb10f6f609d3313f86d8f39abda710") } };
+
+ future = m_trustStorage->keys(ns_omemo,
+ QXmppTrustStorage::ManuallyDistrusted);
+ QVERIFY(future.isFinished());
+ result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ manuallyDistrustedKeys) }));
+}
+
+void tst_QXmppAtmManager::testDistrustAutomaticallyTrustedKeys()
+{
+ clearTrustStorage();
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") },
+ QXmppTrustStorage::AutomaticallyTrusted);
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") },
+ QXmppTrustStorage::Authenticated);
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("75955da0120d2b69fc06459e4f3560d2554e6a1e27ffd200fc8bd0a7352ea35c") },
+ QXmppTrustStorage::AutomaticallyTrusted);
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("59efabd40fe48b10da77c7b7f37a139a13c3cbc83e179fe2adc309984113f0c0") },
+ QXmppTrustStorage::ManuallyTrusted);
+
+ m_manager->distrustAutomaticallyTrustedKeys(ns_omemo,
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("bob@example.com") });
+
+ QMultiHash<QString, QString> automaticallyDistrustedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("75955da0120d2b69fc06459e4f3560d2554e6a1e27ffd200fc8bd0a7352ea35c") } };
+
+ auto future = m_trustStorage->keys(ns_omemo,
+ QXmppTrustStorage::AutomaticallyDistrusted);
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::AutomaticallyDistrusted,
+ automaticallyDistrustedKeys) }));
+}
+
+void tst_QXmppAtmManager::testDistrust()
+{
+ clearTrustStorage();
+
+ QMultiHash<QString, QString> authenticatedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") } };
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ authenticatedKeys.values(),
+ QXmppTrustStorage::Authenticated);
+
+ QMultiHash<QString, QString> automaticallyTrustedKeys = { { QStringLiteral("bob@example.com"),
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66") } };
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ automaticallyTrustedKeys.values(),
+ QXmppTrustStorage::AutomaticallyTrusted);
+
+ QMultiHash<QString, QString> manuallyDistrustedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("e858c90ca7305319dc1a46bc46fad3192868f8b5435ffec4d3ea62e6e7aa3814") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("41f5d8cf0ee59a20f7428b68ea5da4c7e1ee335b66290616db0091faeefcabc0") } };
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ manuallyDistrustedKeys.values(),
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ QXmppTrustMessageKeyOwner keyOwnerAlice;
+ keyOwnerAlice.setJid(QStringLiteral("alice@example.org"));
+ keyOwnerAlice.setTrustedKeys({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") });
+ keyOwnerAlice.setDistrustedKeys({ QStringLiteral("788a40d0eae5a40409d4687a36d3106bbe361971aec0245598571e7b629edc6b"),
+ QStringLiteral("b6c21e111bd4f9ed06ee0485cb302bf1238e90b89986a04061e48d49ddbe95cb") });
+
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ { keyOwnerAlice });
+
+ QXmppTrustMessageKeyOwner keyOwnerBob;
+ keyOwnerBob.setJid(QStringLiteral("bob@example.com"));
+ keyOwnerBob.setTrustedKeys({ QStringLiteral("cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac") });
+ keyOwnerBob.setDistrustedKeys({ QStringLiteral("537f949e44e9d7682eb0a6f35b037496a0cb10f6f609d3313f86d8f39abda710") });
+
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66"),
+ { keyOwnerAlice, keyOwnerBob });
+
+ // The entries for the sender key
+ // b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363
+ // and the keys of keyOwnerBob remain in the storage.
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363"),
+ { keyOwnerBob });
+
+ auto futureVoid = m_manager->distrust(ns_omemo, {});
+ QVERIFY(futureVoid.isFinished());
+
+ auto future = m_trustStorage->keys(ns_omemo);
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ authenticatedKeys),
+ std::pair(
+ QXmppTrustStorage::AutomaticallyTrusted,
+ automaticallyTrustedKeys),
+ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ manuallyDistrustedKeys) }));
+
+ futureVoid = m_manager->distrust(ns_omemo,
+ { std::pair(
+ QStringLiteral("alice@example.org"),
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42")),
+ std::pair(
+ QStringLiteral("bob@example.com"),
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66")) });
+ while (!futureVoid.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ authenticatedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") } };
+
+ manuallyDistrustedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("e858c90ca7305319dc1a46bc46fad3192868f8b5435ffec4d3ea62e6e7aa3814") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("41f5d8cf0ee59a20f7428b68ea5da4c7e1ee335b66290616db0091faeefcabc0") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66") } };
+
+ future = m_trustStorage->keys(ns_omemo);
+ QVERIFY(future.isFinished());
+ result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ authenticatedKeys),
+ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ manuallyDistrustedKeys) }));
+
+ auto futurePostponed = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo,
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66") });
+ QVERIFY(futurePostponed.isFinished());
+ auto resultPostponed = futurePostponed.result();
+ QVERIFY(resultPostponed.isEmpty());
+
+ QMultiHash<QString, QString> trustedKeys = { { QStringLiteral("bob@example.com"),
+ QStringLiteral("cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac") } };
+ QMultiHash<QString, QString> distrustedKeys = { { QStringLiteral("bob@example.com"),
+ QStringLiteral("537f949e44e9d7682eb0a6f35b037496a0cb10f6f609d3313f86d8f39abda710") } };
+
+ futurePostponed = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo,
+ { QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") });
+ QVERIFY(futurePostponed.isFinished());
+ resultPostponed = futurePostponed.result();
+ QCOMPARE(
+ resultPostponed,
+ QHash({ std::pair(
+ true,
+ trustedKeys),
+ std::pair(
+ false,
+ distrustedKeys) }));
+}
+
+void tst_QXmppAtmManager::testAuthenticate()
+{
+ clearTrustStorage();
+
+ QMultiHash<QString, QString> authenticatedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("ad020bd9a95bb924758b4e84640a75b99f37f3351e120188ab6c21c2edecf998") },
+ { QStringLiteral("carol@example.net"),
+ QStringLiteral("f82419945cb175e4c681b3dbcbb62fbd94f760855c222fb513c3799d273a4130") } };
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ authenticatedKeys.values(QStringLiteral("alice@example.org")),
+ QXmppTrustStorage::Authenticated);
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ authenticatedKeys.values(QStringLiteral("carol@example.net")),
+ QXmppTrustStorage::Authenticated);
+
+ QMultiHash<QString, QString> automaticallyTrustedKeys = { { QStringLiteral("bob@example.com"),
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("fddaafd3e44dc8520f74c42227b99210958a544c45794044bd35f13ada883038") } };
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ automaticallyTrustedKeys.values(),
+ QXmppTrustStorage::AutomaticallyTrusted);
+
+ QMultiHash<QString, QString> manuallyDistrustedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("e858c90ca7305319dc1a46bc46fad3192868f8b5435ffec4d3ea62e6e7aa3814") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("41f5d8cf0ee59a20f7428b68ea5da4c7e1ee335b66290616db0091faeefcabc0") } };
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ manuallyDistrustedKeys.values(),
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ QMultiHash<QString, QString> automaticallyDistrustedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") } };
+
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ automaticallyDistrustedKeys.values(),
+ QXmppTrustStorage::AutomaticallyDistrusted);
+
+ QXmppTrustMessageKeyOwner keyOwnerAlice;
+ keyOwnerAlice.setJid(QStringLiteral("alice@example.org"));
+ keyOwnerAlice.setTrustedKeys({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") });
+ keyOwnerAlice.setDistrustedKeys({ QStringLiteral("788a40d0eae5a40409d4687a36d3106bbe361971aec0245598571e7b629edc6b"),
+ QStringLiteral("b6c21e111bd4f9ed06ee0485cb302bf1238e90b89986a04061e48d49ddbe95cb") });
+
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ { keyOwnerAlice });
+
+ QXmppTrustMessageKeyOwner keyOwnerBob;
+ keyOwnerBob.setJid(QStringLiteral("bob@example.com"));
+ keyOwnerBob.setTrustedKeys({ QStringLiteral("cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac") });
+ keyOwnerBob.setDistrustedKeys({ QStringLiteral("537f949e44e9d7682eb0a6f35b037496a0cb10f6f609d3313f86d8f39abda710") });
+
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66"),
+ { keyOwnerAlice, keyOwnerBob });
+
+ QXmppTrustMessageKeyOwner keyOwnerCarol;
+ keyOwnerCarol.setJid(QStringLiteral("carol@example.net"));
+ keyOwnerCarol.setTrustedKeys({ QStringLiteral("8a4c33ca6a41b155f3dc0c6aa1f64a5923ecc0d2481a22c60f522d7c60509871") });
+ keyOwnerCarol.setDistrustedKeys({ QStringLiteral("f82419945cb175e4c681b3dbcbb62fbd94f760855c222fb513c3799d273a4130") });
+
+ // The keys of keyOwnerCarol are used for trust decisions once Bob's key
+ // cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac is
+ // authenticated by the authentication of key
+ // 9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66.
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac"),
+ { keyOwnerCarol });
+
+ // The entries for the sender key
+ // 2e9cf33953840a8e0ddcfe01ec2c5897b0c18421c16ed38135ae051ce2bea43e
+ // and the keys of keyOwnerCarol are removed from the storage
+ // because they are already used for trust decisions once Bob's key
+ // cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac is
+ // authenticated.
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("2e9cf33953840a8e0ddcfe01ec2c5897b0c18421c16ed38135ae051ce2bea43e"),
+ { keyOwnerCarol });
+
+ keyOwnerCarol.setTrustedKeys({ QStringLiteral("b3f7d174dd62bab51b6541c6767202ee5ee7965cefe80acbbb0b0ad46720239f") });
+ keyOwnerCarol.setDistrustedKeys({ QStringLiteral("f43e44a243657217e059191f77b2fe729be4713082ab07f9b0ac1cc741df1dbb") });
+
+ // The entries for the sender key
+ // 2975673c8a9b6a4efeed767ee7c7643e87bac3770dfc6ca32a3f08749b5c6edf
+ // and the keys of keyOwnerCarol remain in the storage.
+ m_trustStorage->addKeysForPostponedTrustDecisions(ns_omemo,
+ QStringLiteral("2975673c8a9b6a4efeed767ee7c7643e87bac3770dfc6ca32a3f08749b5c6edf"),
+ { keyOwnerCarol });
+
+ auto futureVoid = m_manager->authenticate(ns_omemo, {});
+ QVERIFY(futureVoid.isFinished());
+
+ auto future = m_trustStorage->keys(ns_omemo);
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ authenticatedKeys),
+ std::pair(
+ QXmppTrustStorage::AutomaticallyTrusted,
+ automaticallyTrustedKeys),
+ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ manuallyDistrustedKeys),
+ std::pair(
+ QXmppTrustStorage::AutomaticallyDistrusted,
+ automaticallyDistrustedKeys) }));
+
+ futureVoid = m_manager->authenticate(ns_omemo,
+ { std::pair(
+ QStringLiteral("alice@example.org"),
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42")),
+ std::pair(
+ QStringLiteral("bob@example.com"),
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66")) });
+ while (!futureVoid.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ authenticatedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("ad020bd9a95bb924758b4e84640a75b99f37f3351e120188ab6c21c2edecf998") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac") },
+ { QStringLiteral("carol@example.net"),
+ QStringLiteral("8a4c33ca6a41b155f3dc0c6aa1f64a5923ecc0d2481a22c60f522d7c60509871") } };
+
+ manuallyDistrustedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("e858c90ca7305319dc1a46bc46fad3192868f8b5435ffec4d3ea62e6e7aa3814") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("41f5d8cf0ee59a20f7428b68ea5da4c7e1ee335b66290616db0091faeefcabc0") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("788a40d0eae5a40409d4687a36d3106bbe361971aec0245598571e7b629edc6b") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("b6c21e111bd4f9ed06ee0485cb302bf1238e90b89986a04061e48d49ddbe95cb") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("537f949e44e9d7682eb0a6f35b037496a0cb10f6f609d3313f86d8f39abda710") },
+ { QStringLiteral("carol@example.net"),
+ QStringLiteral("f82419945cb175e4c681b3dbcbb62fbd94f760855c222fb513c3799d273a4130") } };
+
+ automaticallyDistrustedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("fddaafd3e44dc8520f74c42227b99210958a544c45794044bd35f13ada883038") } };
+
+ future = m_trustStorage->keys(ns_omemo);
+ QVERIFY(future.isFinished());
+ result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ authenticatedKeys),
+ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ manuallyDistrustedKeys),
+ std::pair(
+ QXmppTrustStorage::AutomaticallyDistrusted,
+ automaticallyDistrustedKeys) }));
+
+ auto futurePostponed = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo,
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("9b04f41f0afb686d69fb1d2aeb41f45034849ebf1cafb871bf10c48451ab2e66"),
+ QStringLiteral("cfa3155773071826642a06a99e0f214070a1e7b8999a5710a209939accb7fcac"),
+ QStringLiteral("2e9cf33953840a8e0ddcfe01ec2c5897b0c18421c16ed38135ae051ce2bea43e") });
+ QVERIFY(futurePostponed.isFinished());
+ auto resultPostponed = futurePostponed.result();
+ QVERIFY(resultPostponed.isEmpty());
+
+ QMultiHash<QString, QString> trustedKeys = { { QStringLiteral("carol@example.net"),
+ QStringLiteral("b3f7d174dd62bab51b6541c6767202ee5ee7965cefe80acbbb0b0ad46720239f") } };
+ QMultiHash<QString, QString> distrustedKeys = { { QStringLiteral("carol@example.net"),
+ QStringLiteral("f43e44a243657217e059191f77b2fe729be4713082ab07f9b0ac1cc741df1dbb") } };
+
+ futurePostponed = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo,
+ { QStringLiteral("2975673c8a9b6a4efeed767ee7c7643e87bac3770dfc6ca32a3f08749b5c6edf") });
+ QVERIFY(futurePostponed.isFinished());
+ resultPostponed = futurePostponed.result();
+ QCOMPARE(
+ resultPostponed,
+ QHash({ std::pair(
+ true,
+ trustedKeys),
+ std::pair(
+ false,
+ distrustedKeys) }));
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisions()
+{
+ clearTrustStorage();
+
+ QMultiHash<QString, QString> keysBeingAuthenticated = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("6f85db0fb55a88c3721df6f672aecf2c64da5b788033be625d0a4b91caf7af43") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("3c9cfae387d86abb1810ed44099869aa6aed6e8001e25a8d8128e14229348d23") } };
+ QMultiHash<QString, QString> keysBeingDistrusted = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("3f0e0a676b8b74456e19359a7926f066c4acb41ccddbea6b2b4183783f07c8a0") },
+ { QStringLiteral("bob@example.com"),
+ QStringLiteral("3f0e0a676b8b74456e19359a7926f066c4acb41ccddbea6b2b4183783f07c8a0") } };
+
+ auto futureVoid = m_manager->makeTrustDecisions(ns_omemo,
+ keysBeingAuthenticated,
+ keysBeingDistrusted);
+ while (!futureVoid.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ auto future = m_trustStorage->keys(ns_omemo);
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ keysBeingAuthenticated),
+ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ keysBeingDistrusted) }));
+}
+
+void tst_QXmppAtmManager::testHandleMessage_data()
+{
+ QTest::addColumn<QXmppMessage>("message");
+ QTest::addColumn<bool>("areTrustDecisionsValid");
+ QTest::addColumn<bool>("isSenderKeyAuthenticated");
+
+ QXmppTrustMessageKeyOwner keyOwnerAlice;
+ keyOwnerAlice.setJid(QStringLiteral("alice@example.org"));
+ keyOwnerAlice.setTrustedKeys({ { QStringLiteral("60788b80ba44dddbe8cb831acb1c9c47e04004563dc3a0ffaca663527bb68d26") },
+ { QStringLiteral("39ca796a1fc03c8e8f87cdcdddf14966a39b5fb472c20fbe0f8128c089a016bc") } });
+ keyOwnerAlice.setDistrustedKeys({ { QStringLiteral("d0f3be3a1a53424b8cdc577f0ae85d595b9167362851f433394be970222f2994") },
+ { QStringLiteral("7e470f60872da85f9bceebe477a75532ff33d04a45a00eec12e50d7bf96f131e") } });
+
+ QXmppTrustMessageKeyOwner keyOwnerBob;
+ keyOwnerBob.setJid(QStringLiteral("bob@example.com"));
+ keyOwnerBob.setTrustedKeys({ { QStringLiteral("9ca4facea151343aba1a9590215fc2c1b03ae5fa8df41a38a95c4c7c58f0975c") },
+ { QStringLiteral("138cf9433f5c583b78f63f095f18d21c6950f57c7a6044815fbba47deb762e16") } });
+ keyOwnerBob.setDistrustedKeys({ { QStringLiteral("6f712cbe8341814a62403f4a4479a8b0ffeb47b4fedc103ce0c430e0de9e6665") },
+ { QStringLiteral("82e465668d105715f74dbcdd8723b0cdd968ac6d199e7768fcff4db16b4c924e") } });
+
+ QList<QXmppTrustMessageKeyOwner> keyOwners;
+ keyOwners << keyOwnerAlice << keyOwnerBob;
+
+ QXmppTrustMessageElement trustMessageElement;
+ trustMessageElement.setUsage(ns_atm);
+ trustMessageElement.setEncryption(ns_omemo);
+ trustMessageElement.setKeyOwners(keyOwners);
+
+ QXmppMessage message;
+ message.setFrom(m_client.configuration().jid());
+ message.setSenderKey(QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"));
+ message.setTrustMessageElement(trustMessageElement);
+
+ QTest::newRow("carbonForOwnMessage")
+ << message
+ << false
+ << true;
+
+ message.setFrom(QStringLiteral("alice@example.org/desktop"));
+ message.setTrustMessageElement({});
+
+ QTest::newRow("noTrustMessageElement")
+ << message
+ << false
+ << true;
+
+ trustMessageElement.setUsage(QStringLiteral("invalid-usage"));
+ message.setTrustMessageElement(trustMessageElement);
+
+ QTest::newRow("trustMessageElementNotForAtm")
+ << message
+ << false
+ << true;
+
+ trustMessageElement.setUsage(ns_atm);
+ trustMessageElement.setKeyOwners({});
+ message.setTrustMessageElement(trustMessageElement);
+
+ QTest::newRow("trustMessageElementWithoutKeyOwners")
+ << message
+ << false
+ << true;
+
+ trustMessageElement.setKeyOwners(keyOwners);
+ trustMessageElement.setEncryption(ns_ox);
+ message.setTrustMessageElement(trustMessageElement);
+
+ QTest::newRow("wrongEncryption")
+ << message
+ << false
+ << true;
+
+ trustMessageElement.setEncryption(ns_omemo);
+ message.setTrustMessageElement(trustMessageElement);
+ message.setFrom(QStringLiteral("carol@example.com/tablet"));
+
+ QTest::newRow("senderNotQualifiedForTrustDecisions")
+ << message
+ << false
+ << true;
+
+ message.setFrom(QStringLiteral("alice@example.org/desktop"));
+
+ QTest::newRow("senderKeyFromOwnEndpointNotAuthenticated")
+ << message
+ << true
+ << false;
+
+ QTest::newRow("trustMessageFromOwnEndpoint")
+ << message
+ << true
+ << true;
+
+ message.setFrom(QStringLiteral("bob@example.com/notebook"));
+ message.setSenderKey(QStringLiteral("a9f349b04319f23aeed1d4bbe83b58693c598e2550e65a495818b26948fd5065"));
+
+ QTest::newRow("senderKeyFromContactNotAuthenticated")
+ << message
+ << true
+ << false;
+
+ QTest::newRow("trustMessageFromContactEndpoint")
+ << message
+ << true
+ << true;
+}
+
+void tst_QXmppAtmManager::testHandleMessage()
+{
+ clearTrustStorage();
+
+ QFETCH(QXmppMessage, message);
+ QFETCH(bool, areTrustDecisionsValid);
+ QFETCH(bool, isSenderKeyAuthenticated);
+
+ const auto senderJid = QXmppUtils::jidToBareJid(message.from());
+ const auto senderKey = message.senderKey();
+
+ // Add the sender key in preparation for the test.
+ if (areTrustDecisionsValid) {
+ if (isSenderKeyAuthenticated) {
+ m_trustStorage->addKeys(ns_omemo,
+ senderJid,
+ { senderKey },
+ QXmppTrustStorage::Authenticated);
+ } else {
+ m_trustStorage->addKeys(ns_omemo,
+ senderJid,
+ { senderKey });
+ }
+ }
+
+ auto future = m_manager->handleMessage(message);
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ // Remove the sender key as soon as the method being tested is executed.
+ if (areTrustDecisionsValid) {
+ m_trustStorage->removeKeys(ns_omemo, { senderKey });
+ }
+
+ if (areTrustDecisionsValid) {
+ const auto isOwnMessage = senderJid == m_client.configuration().jidBare();
+ const auto keyOwners = message.trustMessageElement()->keyOwners();
+
+ if (isSenderKeyAuthenticated) {
+ QMultiHash<QString, QString> authenticatedKeys;
+ QMultiHash<QString, QString> manuallyDistrustedKeys;
+
+ if (isOwnMessage) {
+ for (const auto &keyOwner : keyOwners) {
+ for (const auto &trustedKey : keyOwner.trustedKeys()) {
+ authenticatedKeys.insert(keyOwner.jid(), trustedKey);
+ }
+
+ for (const auto &distrustedKey : keyOwner.distrustedKeys()) {
+ manuallyDistrustedKeys.insert(keyOwner.jid(), distrustedKey);
+ }
+ }
+
+ auto future = m_trustStorage->keys(ns_omemo);
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ authenticatedKeys),
+ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ manuallyDistrustedKeys) }));
+
+ } else {
+ for (const auto &keyOwner : keyOwners) {
+ if (keyOwner.jid() == senderJid) {
+ for (const auto &trustedKey : keyOwner.trustedKeys()) {
+ authenticatedKeys.insert(keyOwner.jid(), trustedKey);
+ }
+
+ for (const auto &distrustedKey : keyOwner.distrustedKeys()) {
+ manuallyDistrustedKeys.insert(keyOwner.jid(), distrustedKey);
+ }
+ }
+ }
+
+ auto future = m_trustStorage->keys(ns_omemo);
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ authenticatedKeys),
+ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ manuallyDistrustedKeys) }));
+ }
+ } else {
+ if (isOwnMessage) {
+ QMultiHash<QString, QString> trustedKeys;
+ QMultiHash<QString, QString> distrustedKeys;
+
+ for (const auto &keyOwner : keyOwners) {
+ for (const auto &trustedKey : keyOwner.trustedKeys()) {
+ trustedKeys.insert(keyOwner.jid(), trustedKey);
+ }
+
+ for (const auto &distrustedKey : keyOwner.distrustedKeys()) {
+ distrustedKeys.insert(keyOwner.jid(), distrustedKey);
+ }
+ }
+
+ auto future = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo,
+ { senderKey });
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ true,
+ trustedKeys),
+ std::pair(
+ false,
+ distrustedKeys) }));
+ } else {
+ QMultiHash<QString, QString> trustedKeys;
+ QMultiHash<QString, QString> distrustedKeys;
+
+ for (const auto &keyOwner : keyOwners) {
+ if (keyOwner.jid() == senderJid) {
+ for (const auto &trustedKey : keyOwner.trustedKeys()) {
+ trustedKeys.insert(keyOwner.jid(), trustedKey);
+ }
+
+ for (const auto &distrustedKey : keyOwner.distrustedKeys()) {
+ distrustedKeys.insert(keyOwner.jid(), distrustedKey);
+ }
+ }
+ }
+
+ auto futureHash = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo,
+ { senderKey });
+ QVERIFY(futureHash.isFinished());
+ auto result = futureHash.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ true,
+ trustedKeys),
+ std::pair(
+ false,
+ distrustedKeys) }));
+ }
+ }
+ } else {
+ auto futureHash = m_trustStorage->keys(ns_omemo);
+ QVERIFY(futureHash.isFinished());
+ auto resultHash = futureHash.result();
+ QVERIFY(resultHash.isEmpty());
+
+ auto futureHash2 = m_trustStorage->keysForPostponedTrustDecisions(ns_omemo);
+ QVERIFY(futureHash2.isFinished());
+ auto resultHash2 = futureHash2.result();
+ QVERIFY(resultHash2.isEmpty());
+ }
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsNoKeys()
+{
+ clearTrustStorage();
+
+ QSignalSpy unexpectedTrustMessageSentSpy(this, &tst_QXmppAtmManager::unexpectedTrustMessageSent);
+
+ // key of own endpoints
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoints
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82") },
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ const QObject context;
+
+ // unexpected trust message
+ connect(&m_logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &) {
+ if (type == QXmppLogger::SentMessage) {
+ emit unexpectedTrustMessageSent();
+ }
+ });
+
+ auto futureVoid = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("alice@example.org"),
+ {},
+ {});
+ while (!futureVoid.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QVERIFY2(!unexpectedTrustMessageSentSpy.wait(UNEXPECTED_TRUST_MESSAGE_WAITING_TIMEOUT), "Unexpected trust message sent!");
+
+ QMultiHash<QString, QString> authenticatedKeys = { { QStringLiteral("alice@example.org"),
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") },
+ { QStringLiteral("alice@example.org"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") } };
+
+ QMultiHash<QString, QString> manuallyDistrustedKeys = { { QStringLiteral("bob@example.com"),
+ QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82") } };
+
+ auto future = m_trustStorage->keys(ns_omemo);
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(
+ result,
+ QHash({ std::pair(
+ QXmppTrustStorage::Authenticated,
+ authenticatedKeys),
+ std::pair(
+ QXmppTrustStorage::ManuallyDistrusted,
+ manuallyDistrustedKeys) }));
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsOwnKeys()
+{
+ clearTrustStorage();
+
+ // keys of own endpoints
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") },
+ QXmppTrustStorage::Authenticated);
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") },
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ // keys of contact's endpoints
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") },
+ QXmppTrustStorage::Authenticated);
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82") },
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ { QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") },
+ QXmppTrustStorage::Authenticated);
+
+ int sentMessagesCount = 0;
+ const QObject context;
+
+ // trust message for own keys to Bob
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("bob@example.com")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") }));
+ }
+ }
+ });
+
+ // trust message for own keys to Carol
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("carol@example.net")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") }));
+ }
+ }
+ });
+
+ // trust message for all keys to own endpoints
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("alice@example.org")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 3);
+
+ for (const auto &keyOwner : keyOwners) {
+ const auto keyOwnerJid = keyOwner.jid();
+
+ if (keyOwnerJid == QStringLiteral("alice@example.org")) {
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") }));
+ } else if (keyOwnerJid == QStringLiteral("bob@example.com")) {
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82") }));
+ } else if (keyOwnerJid == QStringLiteral("carol@example.net")) {
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") }));
+ QVERIFY(keyOwner.distrustedKeys().isEmpty());
+ } else {
+ QFAIL("Unexpected key owner sent!");
+ }
+ }
+ }
+ }
+ });
+
+ auto future = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") },
+ { QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4"),
+ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") });
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QCOMPARE(sentMessagesCount, 3);
+
+ testMakeTrustDecisionsOwnKeysDone();
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsOwnKeysNoOwnEndpoints()
+{
+ clearTrustStorage();
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ { QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") },
+ QXmppTrustStorage::Authenticated);
+
+ int sentMessagesCount = 0;
+ const QObject context;
+
+ // trust message for own keys to Bob
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("bob@example.com")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") }));
+ }
+ }
+ });
+
+ // trust message for own keys to Carol
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("carol@example.net")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") }));
+ }
+ }
+ });
+
+ // trust message for contacts' keys to own endpoints
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("alice@example.org")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 2);
+
+ for (const auto &keyOwner : keyOwners) {
+ const auto keyOwnerJid = keyOwner.jid();
+
+ if (keyOwnerJid == QStringLiteral("bob@example.com")) {
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") }));
+ QVERIFY(keyOwner.distrustedKeys().isEmpty());
+ } else if (keyOwnerJid == QStringLiteral("carol@example.net")) {
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") }));
+ QVERIFY(keyOwner.distrustedKeys().isEmpty());
+ } else {
+ QFAIL("Unexpected key owner sent!");
+ }
+ }
+ }
+ }
+ });
+
+ auto future = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") },
+ { QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") });
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QCOMPARE(sentMessagesCount, 3);
+
+ testMakeTrustDecisionsOwnKeysDone();
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsOwnKeysNoOwnEndpointsWithAuthenticatedKeys()
+{
+ clearTrustStorage();
+
+ // key of own endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") },
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ { QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") },
+ QXmppTrustStorage::Authenticated);
+
+ int sentMessagesCount = 0;
+ const QObject context;
+
+ // trust message for own keys to Bob
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("bob@example.com")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") }));
+ }
+ }
+ });
+
+ // trust message for own keys to Carol
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("carol@example.net")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") }));
+ }
+ }
+ });
+
+ // trust message for all keys to own endpoints
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("alice@example.org")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 3);
+
+ for (const auto &keyOwner : keyOwners) {
+ const auto keyOwnerJid = keyOwner.jid();
+
+ if (keyOwnerJid == QStringLiteral("alice@example.org")) {
+ QVERIFY(keyOwner.trustedKeys().isEmpty());
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") }));
+ } else if (keyOwnerJid == QStringLiteral("bob@example.com")) {
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") }));
+ QVERIFY(keyOwner.distrustedKeys().isEmpty());
+ } else if (keyOwnerJid == QStringLiteral("carol@example.net")) {
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") }));
+ QVERIFY(keyOwner.distrustedKeys().isEmpty());
+ } else {
+ QFAIL("Unexpected key owner sent!");
+ }
+ }
+ }
+ }
+ });
+
+ auto future = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") },
+ { QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") });
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QCOMPARE(sentMessagesCount, 3);
+
+ testMakeTrustDecisionsOwnKeysDone();
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsOwnKeysNoContactsWithAuthenticatedKeys()
+{
+ clearTrustStorage();
+
+ // keys of own endpoints
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") },
+ QXmppTrustStorage::Authenticated);
+
+ // keys of contact's endpoints
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82") },
+ QXmppTrustStorage::AutomaticallyDistrusted);
+
+ int sentMessagesCount = 0;
+ const QObject context;
+
+ // trust message for own keys to own endpoints with authenticated keys
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("alice@example.org")) {
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+
+ if (keyOwner.trustedKeys() == QList({ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"), QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") }) &&
+ keyOwner.distrustedKeys() == QList({ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") })) {
+ sentMessagesCount++;
+ }
+ }
+ }
+ });
+
+ // trust message for own keys to own endpoints
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("alice@example.org")) {
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+
+ const auto trustedKeys = keyOwner.trustedKeys();
+ if (trustedKeys == QList({ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"), QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") })) {
+ sentMessagesCount++;
+
+ QVERIFY(keyOwner.distrustedKeys().isEmpty());
+ }
+ }
+ }
+ });
+
+ auto future = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"),
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd") },
+ { QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393") });
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QCOMPARE(sentMessagesCount, 2);
+
+ testMakeTrustDecisionsOwnKeysDone();
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsSoleOwnKeyDistrusted()
+{
+ clearTrustStorage();
+
+ QSignalSpy unexpectedTrustMessageSentSpy(this, &tst_QXmppAtmManager::unexpectedTrustMessageSent);
+
+ // key of own endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ { QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") },
+ QXmppTrustStorage::Authenticated);
+
+ int sentMessagesCount = 0;
+ const QObject context;
+
+ // trust message for own key to Bob
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("bob@example.com")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QVERIFY(keyOwner.trustedKeys().isEmpty());
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") }));
+ }
+ }
+ });
+
+ // trust message for own key to Carol
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("carol@example.net")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QVERIFY(keyOwner.trustedKeys().isEmpty());
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") }));
+ }
+ }
+ });
+
+ // unexpected trust message for contacts' keys to own endpoint
+ connect(&m_logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("alice@example.org")) {
+ emit unexpectedTrustMessageSent();
+ }
+ }
+ });
+
+ auto future = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("alice@example.org"),
+ {},
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") });
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QCOMPARE(sentMessagesCount, 2);
+ QVERIFY2(!unexpectedTrustMessageSentSpy.wait(UNEXPECTED_TRUST_MESSAGE_WAITING_TIMEOUT), "Unexpected trust message sent!");
+
+ auto futureTrustLevel = m_trustStorage->trustLevel(ns_omemo,
+ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"));
+ QVERIFY(futureTrustLevel.isFinished());
+ auto result = futureTrustLevel.result();
+ QCOMPARE(result, QXmppTrustStorage::ManuallyDistrusted);
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsContactKeys()
+{
+ clearTrustStorage();
+
+ QSignalSpy unexpectedTrustMessageSentSpy(this, &tst_QXmppAtmManager::unexpectedTrustMessageSent);
+
+ // keys of own endpoints
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") },
+ QXmppTrustStorage::Authenticated);
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") },
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ // keys of contact's endpoints
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58"),
+ QStringLiteral("4fe76994007cb4649d6d805b4623a6fe3ad2fbc08fbb3187ac7f1999b8f2bcfa") },
+ QXmppTrustStorage::Authenticated);
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82") },
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ { QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") },
+ QXmppTrustStorage::Authenticated);
+
+ int sentMessagesCount = 0;
+ const QObject context;
+
+ // trust message for Bob's keys to own endpoints
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("alice@example.org")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("bob@example.com"));
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("9b30de293401566d5c4e6cc5f438c218a6b5e290c00d93952d3f4a87b08aec03"),
+ QStringLiteral("187ce6ae2fb5539dde1518256d08685e053cbcea675d9d35d9583dd0788bbd6c") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("4fe76994007cb4649d6d805b4623a6fe3ad2fbc08fbb3187ac7f1999b8f2bcfa") }));
+ }
+ }
+ });
+
+ // trust message for own keys to Bob
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("bob@example.com")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QCOMPARE(keyOwner.trustedKeys(),
+ QList({ QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42"),
+ QStringLiteral("b5fb24aee735c5c7c2f952b3baabcb65425565c7195ff3e0e63f3cba4a6e6363") }));
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") }));
+ }
+ }
+ });
+
+ // unexpected trust message to Carol
+ connect(&m_logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("carol@example.net")) {
+ emit unexpectedTrustMessageSent();
+ }
+ }
+ });
+
+ auto future = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58"),
+ QStringLiteral("9b30de293401566d5c4e6cc5f438c218a6b5e290c00d93952d3f4a87b08aec03"),
+ QStringLiteral("187ce6ae2fb5539dde1518256d08685e053cbcea675d9d35d9583dd0788bbd6c") },
+ { QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82"),
+ QStringLiteral("4fe76994007cb4649d6d805b4623a6fe3ad2fbc08fbb3187ac7f1999b8f2bcfa") });
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QCOMPARE(sentMessagesCount, 2);
+ QVERIFY2(!unexpectedTrustMessageSentSpy.wait(UNEXPECTED_TRUST_MESSAGE_WAITING_TIMEOUT), "Unexpected trust message sent!");
+
+ testMakeTrustDecisionsContactKeysDone();
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsContactKeysNoOwnEndpoints()
+{
+ clearTrustStorage();
+
+ QSignalSpy unexpectedTrustMessageSentSpy(this, &tst_QXmppAtmManager::unexpectedTrustMessageSent);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ { QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") },
+ QXmppTrustStorage::Authenticated);
+
+ const QObject context;
+
+ // unexpected trust message
+ connect(&m_logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ emit unexpectedTrustMessageSent();
+ }
+ });
+
+ m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58"),
+ QStringLiteral("9b30de293401566d5c4e6cc5f438c218a6b5e290c00d93952d3f4a87b08aec03") },
+ { QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82") });
+
+ QVERIFY2(!unexpectedTrustMessageSentSpy.wait(UNEXPECTED_TRUST_MESSAGE_WAITING_TIMEOUT), "Unexpected trust message sent!");
+
+ testMakeTrustDecisionsContactKeysDone();
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsContactKeysNoOwnEndpointsWithAuthenticatedKeys()
+{
+ clearTrustStorage();
+
+ QSignalSpy unexpectedTrustMessageSentSpy(this, &tst_QXmppAtmManager::unexpectedTrustMessageSent);
+
+ // key of own endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") },
+ QXmppTrustStorage::ManuallyDistrusted);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ { QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") },
+ QXmppTrustStorage::Authenticated);
+
+ int sentMessagesCount = 0;
+ const QObject context;
+
+ // trust message for own key to Bob
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("bob@example.com")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("alice@example.org"));
+ QVERIFY(keyOwner.trustedKeys().isEmpty());
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("19a1f2b0d85c7c34b31b6aba3804e1446529b8507d13b882451ff598ad532fe4") }));
+ }
+ }
+ });
+
+ // unexpected trust message
+ connect(&m_logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() != QStringLiteral("bob@example.com")) {
+ emit unexpectedTrustMessageSent();
+ }
+ }
+ });
+
+ auto future = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58"),
+ QStringLiteral("9b30de293401566d5c4e6cc5f438c218a6b5e290c00d93952d3f4a87b08aec03") },
+ { QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82") });
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QCOMPARE(sentMessagesCount, 1);
+ QVERIFY2(!unexpectedTrustMessageSentSpy.wait(UNEXPECTED_TRUST_MESSAGE_WAITING_TIMEOUT), "Unexpected trust message sent!");
+
+ testMakeTrustDecisionsContactKeysDone();
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsSoleContactKeyDistrusted()
+{
+ clearTrustStorage();
+
+ QSignalSpy unexpectedTrustMessageSentSpy(this, &tst_QXmppAtmManager::unexpectedTrustMessageSent);
+
+ // key of own endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("alice@example.org"),
+ { QStringLiteral("470c88ff79bd978c208eef4976e1716f930426f04d4437cf7e8d44c219750c42") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("bob@example.com"),
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") },
+ QXmppTrustStorage::Authenticated);
+
+ // key of contact's endpoint
+ m_trustStorage->addKeys(
+ ns_omemo,
+ QStringLiteral("carol@example.net"),
+ { QStringLiteral("b55cb7ca00675b8aba5764d87bca788bdd38cc3fb1e2b34c45e8313e73c8edfc") },
+ QXmppTrustStorage::Authenticated);
+
+ int sentMessagesCount = 0;
+ const QObject context;
+
+ // trust message for Bob's key to own endpoints
+ connect(&m_logger, &QXmppLogger::message, &context, [&](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() == QStringLiteral("alice@example.org")) {
+ sentMessagesCount++;
+
+ const auto trustMessageElement = message.trustMessageElement();
+
+ QVERIFY(trustMessageElement);
+ QCOMPARE(trustMessageElement->usage(), QString(ns_atm));
+ QCOMPARE(trustMessageElement->encryption(), QString(ns_omemo));
+
+ const auto keyOwners = trustMessageElement->keyOwners();
+ QCOMPARE(keyOwners.size(), 1);
+
+ const auto keyOwner = keyOwners.at(0);
+ QCOMPARE(keyOwner.jid(), QStringLiteral("bob@example.com"));
+ QVERIFY(keyOwner.trustedKeys().isEmpty());
+ QCOMPARE(keyOwner.distrustedKeys(),
+ QList({ QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") }));
+ }
+ }
+ });
+
+ // unexpected trust message
+ connect(&m_logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) {
+ if (type == QXmppLogger::SentMessage) {
+ QXmppMessage message;
+ parsePacket(message, text.toUtf8());
+
+ if (message.to() != QStringLiteral("alice@example.org")) {
+ emit unexpectedTrustMessageSent();
+ }
+ }
+ });
+
+ auto future = m_manager->makeTrustDecisions(ns_omemo,
+ QStringLiteral("bob@example.com"),
+ {},
+ { QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58") });
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ QCOMPARE(sentMessagesCount, 1);
+ QVERIFY2(!unexpectedTrustMessageSentSpy.wait(UNEXPECTED_TRUST_MESSAGE_WAITING_TIMEOUT), "Unexpected trust message sent!");
+
+ const auto futureTrustLevel = m_trustStorage->trustLevel(ns_omemo,
+ QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58"));
+ QVERIFY(futureTrustLevel.isFinished());
+ const auto result = futureTrustLevel.result();
+ QCOMPARE(result, QXmppTrustStorage::ManuallyDistrusted);
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsOwnKeysDone()
+{
+ auto future = m_trustStorage->trustLevel(ns_omemo,
+ QStringLiteral("d11715b069372e7a4416caaaced4f30200838155e57dad37a5a4aa24538e58e5"));
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(result, QXmppTrustStorage::Authenticated);
+
+ future = m_trustStorage->trustLevel(ns_omemo,
+ QStringLiteral("b589ffc1c20ec414a85b85b551f3ebff381b2e2a412b62ac15f0bb1756f3badd"));
+ QVERIFY(future.isFinished());
+ result = future.result();
+ QCOMPARE(result, QXmppTrustStorage::Authenticated);
+
+ future = m_trustStorage->trustLevel(ns_omemo,
+ QStringLiteral("e2206cc893d501f35633f3a0c80f5f6ac3af909f0ad7fd30b98a70546c384393"));
+ QVERIFY(future.isFinished());
+ result = future.result();
+ QCOMPARE(result, QXmppTrustStorage::ManuallyDistrusted);
+}
+
+void tst_QXmppAtmManager::testMakeTrustDecisionsContactKeysDone()
+{
+ auto future = m_trustStorage->trustLevel(ns_omemo,
+ QStringLiteral("fb5549bcc2c21af903aae67a99067e492fa04db438dfa04953014ea16d0c6b58"));
+ QVERIFY(future.isFinished());
+ auto result = future.result();
+ QCOMPARE(result, QXmppTrustStorage::Authenticated);
+
+ future = m_trustStorage->trustLevel(ns_omemo,
+ QStringLiteral("9b30de293401566d5c4e6cc5f438c218a6b5e290c00d93952d3f4a87b08aec03"));
+ QVERIFY(future.isFinished());
+ result = future.result();
+ QCOMPARE(result, QXmppTrustStorage::Authenticated);
+
+ future = m_trustStorage->trustLevel(ns_omemo,
+ QStringLiteral("f200530b57eca5890ee1a912e9028df97140f4d99ff4d10883b863b65a538c82"));
+ QVERIFY(future.isFinished());
+ result = future.result();
+ QCOMPARE(result, QXmppTrustStorage::ManuallyDistrusted);
+}
+
+void tst_QXmppAtmManager::clearTrustStorage()
+{
+ m_trustStorage->removeKeys();
+ m_trustStorage->removeKeysForPostponedTrustDecisions();
+}
+
+QTEST_MAIN(tst_QXmppAtmManager)
+#include "tst_qxmppatmmanager.moc"
diff --git a/tests/qxmppmessage/tst_qxmppmessage.cpp b/tests/qxmppmessage/tst_qxmppmessage.cpp
index fe3340d8..9ae98e7a 100644
--- a/tests/qxmppmessage/tst_qxmppmessage.cpp
+++ b/tests/qxmppmessage/tst_qxmppmessage.cpp
@@ -73,6 +73,7 @@ private slots:
void testMixInvitation();
void testTrustMessageElement();
void testOmemoElement();
+ void testSenderkey();
};
void tst_QXmppMessage::testBasic_data()
@@ -1215,5 +1216,12 @@ void tst_QXmppMessage::testOmemoElement()
serializePacket(message2, xmlOut2);
}
+void tst_QXmppMessage::testSenderkey()
+{
+ QXmppMessage message;
+ message.setSenderKey(QStringLiteral("6850019d7ed0feb6d3823072498ceb4f616c6025586f8f666dc6b9c81ef7e0a4"));
+ QCOMPARE(message.senderKey(), QStringLiteral("6850019d7ed0feb6d3823072498ceb4f616c6025586f8f666dc6b9c81ef7e0a4"));
+}
+
QTEST_MAIN(tst_QXmppMessage)
#include "tst_qxmppmessage.moc"