diff options
| author | Melvin Keskin <melvo@olomono.de> | 2022-05-09 21:45:49 +0200 |
|---|---|---|
| committer | Linus Jahn <lnj@kaidan.im> | 2022-08-13 15:55:03 +0200 |
| commit | ceb62dd9d0d86bc8327ace116930962cf7fad1e9 (patch) | |
| tree | 35bdcccf3e1bebddadcdab6205383975ca66e4c4 /tests | |
| parent | ec0669845b9072ea6cdc0fefb66f1d07511386a4 (diff) | |
| download | qxmpp-ceb62dd9d0d86bc8327ace116930962cf7fad1e9.tar.gz | |
Implement XEP-0384: OMEMO Encryption v0.8
This implements XEP-0384 in version v0.8 with a manager and storage
classes to be user-implemented for persistant storage.
The license of the code is LGPL-2.1-or-later as usual. However since
libomemo-c (libsignal-protocol-c) is GPL-3.0, the built binary is always
licensed under GPL-3.0. Having our code LGPL licensed will make it
avoids relicensing in the future in case we port it to an LGPL
compatible omemo library.
Closes #133.
Co-authored-by: Linus Jahn <lnj@kaidan.im>
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | tests/qxmppomemodata/tst_qxmppomemodata.cpp | 2 | ||||
| -rw-r--r-- | tests/qxmppomemomanager/tst_qxmppomemomanager.cpp | 513 | ||||
| -rw-r--r-- | tests/qxmppomemomemorystorage/tst_qxmppomemomemorystorage.cpp | 310 |
4 files changed, 834 insertions, 2 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4155f42c..cf6def66 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -76,8 +76,17 @@ if(WITH_GSTREAMER) add_simple_test(qxmppcallmanager) endif() +if(WITH_OMEMO) + if(BUILD_INTERNAL_TESTS) + add_simple_test(qxmppomemodata) + endif() + add_simple_test(qxmppomemomemorystorage) + + add_simple_test(qxmppomemomanager) + target_link_libraries(tst_qxmppomemomanager PkgConfig::OmemoC qca-qt${QT_VERSION_MAJOR}) +endif() + if(BUILD_INTERNAL_TESTS) - add_simple_test(qxmppomemodata) add_simple_test(qxmppsasl) add_simple_test(qxmppstreaminitiationiq) endif() diff --git a/tests/qxmppomemodata/tst_qxmppomemodata.cpp b/tests/qxmppomemodata/tst_qxmppomemodata.cpp index 778e9cea..2048cfcf 100644 --- a/tests/qxmppomemodata/tst_qxmppomemodata.cpp +++ b/tests/qxmppomemodata/tst_qxmppomemodata.cpp @@ -660,7 +660,7 @@ void tst_QXmppOmemoData::testOmemoIq() QXmppOmemoIq omemoIq2; omemoIq2.setOmemoElement(omemoElement); - QCOMPARE(omemoIq1.omemoElement().payload(), QByteArray::fromBase64(omemoPayload)); + QCOMPARE(omemoIq2.omemoElement().payload(), QByteArray::fromBase64(omemoPayload)); serializePacket(omemoIq2, xmlOmemoIq); } diff --git a/tests/qxmppomemomanager/tst_qxmppomemomanager.cpp b/tests/qxmppomemomanager/tst_qxmppomemomanager.cpp new file mode 100644 index 00000000..f0cf2447 --- /dev/null +++ b/tests/qxmppomemomanager/tst_qxmppomemomanager.cpp @@ -0,0 +1,513 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "QXmppAtmManager.h" +#include "QXmppAtmTrustMemoryStorage.h" +#include "QXmppBitsOfBinaryContentId.h" +#include "QXmppBitsOfBinaryIq.h" +#include "QXmppCarbonManager.h" +#include "QXmppClient.h" +#include "QXmppDiscoveryManager.h" +#include "QXmppE2eeMetadata.h" +#include "QXmppMessage.h" +#include "QXmppOmemoElement_p.h" +#include "QXmppOmemoEnvelope_p.h" +#include "QXmppOmemoManager.h" +#include "QXmppOmemoManager_p.h" +#include "QXmppOmemoMemoryStorage.h" +#include "QXmppPubSubIq.h" +#include "QXmppPubSubItem.h" +#include "QXmppPubSubManager.h" + +#include "IntegrationTesting.h" +#include "util.h" +#include <QObject> + +using namespace QXmpp; +using namespace QXmpp::Private; + +struct OmemoUser +{ + QXmppClient client; + QXmppLogger logger; + QXmppOmemoManager *manager; + QXmppCarbonManager *carbonManager; + QXmppDiscoveryManager *discoveryManager; + QXmppPubSubManager *pubSubManager; + std::unique_ptr<QXmppOmemoMemoryStorage> omemoStorage; + std::unique_ptr<QXmppAtmTrustStorage> trustStorage; + QXmppAtmManager *trustManager; +}; + +class OmemoIqHandler : public QXmppClientExtension +{ +public: + OmemoIqHandler(const QXmppBitsOfBinaryIq &requestIq, const QXmppBitsOfBinaryIq &responseIq) + { + m_requestIq = requestIq; + m_responseIq = responseIq; + } + + bool handleStanza(const QDomElement &stanza, const std::optional<QXmppE2eeMetadata> &e2eeMetadata) override + { + if (stanza.tagName() == "iq" && QXmppBitsOfBinaryIq::isBitsOfBinaryIq(stanza)) { + QXmppBitsOfBinaryIq iq; + iq.parse(stanza); + + if (iq.cid().toContentId() != m_requestIq.cid().toContentId()) { + return false; + } + + m_responseIq.setId(iq.id()); + client()->reply(std::move(m_responseIq), e2eeMetadata); + return true; + } + + return false; + }; + +private: + QXmppBitsOfBinaryIq m_requestIq; + QXmppBitsOfBinaryIq m_responseIq; +}; + +class tst_QXmppOmemoManager : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void testSecurityPolicies(); + void testTrustLevels(); + void initOmemoUser(OmemoUser &omemoUser); + void testInit(); + void testSetUp(); + void testLoad(); + void testSendMessage(); + void testSendIq(); + void finish(OmemoUser &omemoUser); + +private: + OmemoUser m_alice1; + OmemoUser m_alice2; +}; + +void tst_QXmppOmemoManager::initTestCase() +{ + initOmemoUser(m_alice1); + initOmemoUser(m_alice2); +} + +void tst_QXmppOmemoManager::testSecurityPolicies() +{ + auto futureSecurityPolicy = m_alice1.manager->securityPolicy(); + QVERIFY(futureSecurityPolicy.isFinished()); + auto resultSecurityPolicy = futureSecurityPolicy.result(); + QCOMPARE(resultSecurityPolicy, NoSecurityPolicy); + + m_alice1.manager->setSecurityPolicy(Toakafa); + + futureSecurityPolicy = m_alice1.manager->securityPolicy(); + QVERIFY(futureSecurityPolicy.isFinished()); + resultSecurityPolicy = futureSecurityPolicy.result(); + QCOMPARE(resultSecurityPolicy, Toakafa); +} + +void tst_QXmppOmemoManager::testTrustLevels() +{ + auto futureTrustLevel = m_alice1.manager->trustLevel(QStringLiteral("alice@example.org"), + QByteArray::fromBase64(QByteArrayLiteral("AZ/cF4OrUOILKO1gQBf62pQevOhBJ2NyHnXLwM4FDZU="))); + QVERIFY(futureTrustLevel.isFinished()); + auto resultTrustLevel = futureTrustLevel.result(); + QCOMPARE(resultTrustLevel, TrustLevel::Undecided); + + m_alice1.manager->setTrustLevel( + { { QStringLiteral("alice@example.org"), + QByteArray::fromBase64(QByteArrayLiteral("AZ/cF4OrUOILKO1gQBf62pQevOhBJ2NyHnXLwM4FDZU=")) }, + { QStringLiteral("bob@example.com"), + QByteArray::fromBase64(QByteArrayLiteral("9E51lG3vVmUn8CM7/AIcmIlLP2HPl6Ao0/VSf4VT/oA=")) } }, + TrustLevel::Authenticated); + + futureTrustLevel = m_alice1.manager->trustLevel(QStringLiteral("alice@example.org"), + QByteArray::fromBase64(QByteArrayLiteral("AZ/cF4OrUOILKO1gQBf62pQevOhBJ2NyHnXLwM4FDZU="))); + QVERIFY(futureTrustLevel.isFinished()); + resultTrustLevel = futureTrustLevel.result(); + QCOMPARE(resultTrustLevel, TrustLevel::Authenticated); +} + +void tst_QXmppOmemoManager::initOmemoUser(OmemoUser &omemoUser) +{ + omemoUser.discoveryManager = new QXmppDiscoveryManager; + omemoUser.client.addExtension(omemoUser.discoveryManager); + + omemoUser.pubSubManager = new QXmppPubSubManager; + omemoUser.client.addExtension(omemoUser.pubSubManager); + + omemoUser.trustStorage = std::make_unique<QXmppAtmTrustMemoryStorage>(); + omemoUser.trustManager = new QXmppAtmManager(omemoUser.trustStorage.get()); + omemoUser.client.addExtension(omemoUser.trustManager); + + omemoUser.omemoStorage = std::make_unique<QXmppOmemoMemoryStorage>(); + omemoUser.manager = new QXmppOmemoManager(omemoUser.omemoStorage.get()); + omemoUser.client.addExtension(omemoUser.manager); + + omemoUser.carbonManager = new QXmppCarbonManager; + omemoUser.client.addExtension(omemoUser.carbonManager); + + connect(omemoUser.carbonManager, &QXmppCarbonManager::messageSent, omemoUser.manager, &QXmppOmemoManager::handleMessage); + connect(omemoUser.carbonManager, &QXmppCarbonManager::messageReceived, omemoUser.manager, &QXmppOmemoManager::handleMessage); + + omemoUser.logger.setLoggingType(QXmppLogger::SignalLogging); + omemoUser.client.setLogger(&omemoUser.logger); +} + +void tst_QXmppOmemoManager::testInit() +{ + auto omemoStorage = std::make_unique<QXmppOmemoMemoryStorage>(); + auto manager = std::make_unique<QXmppOmemoManager>(omemoStorage.get()); + QVERIFY(manager->d->initGlobalContext()); + QVERIFY(manager->d->initLocking()); + QVERIFY(manager->d->initCryptoProvider()); + // TODO: Test initStores() +} + +void tst_QXmppOmemoManager::testSetUp() +{ + SKIP_IF_INTEGRATION_TESTS_DISABLED(); + + auto isManagerSetUp = false; + const QObject context; + + connect(&m_alice1.client, &QXmppClient::connected, &context, [=, &isManagerSetUp]() { + auto future = m_alice1.manager->setUp(); + await(future, this, [=, &isManagerSetUp](bool isSetUp) { + if (isSetUp) { + isManagerSetUp = true; + } + }); + }); + + connect(&m_alice1.logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) { + if (type == QXmppLogger::SentMessage) { + qDebug() << "SENT: " << text; + } else { + qDebug() << "RECEIVED: " << text; + } + }); + + m_alice1.client.connectToServer(IntegrationTests::clientConfiguration()); + + QTRY_VERIFY(isManagerSetUp); + finish(m_alice1); +} + +void tst_QXmppOmemoManager::testLoad() +{ + auto future = m_alice1.manager->load(); + while (!future.isFinished()) { + QCoreApplication::processEvents(); + } + auto result = future.result(); + QVERIFY(!result); + + const QXmppOmemoStorage::OwnDevice ownDevice = { 1, + QStringLiteral("notebook"), + QByteArray::fromBase64(QByteArrayLiteral("OU5HM3loYnFjZVVaYmpSbHdab0FPTDhJVHRzUFVUcFMK")), + QByteArray::fromBase64(QByteArrayLiteral("TkhodEZ6cnFDeGtENWRuT1ZZdUsyaGIwQkRPdHFRSE8K")), + 2, + 3 }; + m_alice1.omemoStorage->setOwnDevice(ownDevice); + m_alice1.omemoStorage->addSignedPreKeyPair(2, + { QDateTime::currentDateTimeUtc(), + QByteArray::fromBase64(QByteArrayLiteral("VEZBOTZFRjNQSVRzVE1OcnIzYmV2ZFFuM0R3WmduUWwK")) }); + m_alice1.omemoStorage->addPreKeyPairs({ { 3, + QByteArray::fromBase64(QByteArrayLiteral("RmVmQ0RTTzB0Z2R2T0ZjckQ4N29PN01VTGFFMVZjUmIK")) } }); + + future = m_alice1.manager->load(); + while (!future.isFinished()) { + QCoreApplication::processEvents(); + } + result = future.result(); + QVERIFY(result); + + const auto storedOwnDevice = m_alice1.manager->ownDevice(); + // QCOMPARE(storedOwnDevice.keyId(), m_alice1.manager->d->createKeyId(ownDevice.publicIdentityKey)); + QCOMPARE(storedOwnDevice.label(), ownDevice.label); + + m_alice1.omemoStorage->resetAll(); +} + +void tst_QXmppOmemoManager::testSendMessage() +{ + SKIP_IF_INTEGRATION_TESTS_DISABLED() + + QSignalSpy disconnectedAlice1Spy(&m_alice1.client, &QXmppClient::disconnected); + + auto isFirstMessageSentByAlice1 = false; + auto isFirstMessageDecryptedByAlice2 = false; + auto isEmptyOmemoMessageReceivedByAlice1 = false; + auto isSecondMessageSentByAlice1 = false; + auto isSecondMessageDecryptedByAlice2 = false; + + const auto config1 = IntegrationTests::clientConfiguration(); + auto config2 = config1; + config2.setResource(config2.resource() % QStringLiteral("2")); + + const QObject context; + QString recipient = "bob@" % config1.domain(); + + QXmppMessage message1; + message1.setTo(recipient); + message1.setBody("Hello Bob!"); + + QXmppMessage message2; + message2.setTo(recipient); + message2.setBody("Hello Bob again!"); + + connect(&m_alice1.client, &QXmppClient::connected, &context, [=]() { + auto future = m_alice1.manager->setUp(); + await(future, this, [=](bool isSetUp) { + if (isSetUp) { + m_alice1.carbonManager->setCarbonsEnabled(true); + + auto future = m_alice1.manager->setSecurityPolicy(Toakafa); + await(future, this, [=]() { + auto future = m_alice2.manager->setSecurityPolicy(Toakafa); + await(future, this, [=]() { + m_alice2.client.connectToServer(config2); + }); + }); + } + }); + }); + + connect(&m_alice2.client, &QXmppClient::connected, &context, [=]() { + auto future = m_alice2.manager->setUp(); + await(future, this, [=](bool isSetUp) { + if (isSetUp) { + m_alice2.carbonManager->setCarbonsEnabled(true); + } + }); + }); + + connect(&m_alice2.logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) { + if (type == QXmppLogger::SentMessage) { + qDebug() << "Alice 2 - SENT: " << text; + } else { + qDebug() << "Alice 2 - RECEIVED: " << text; + } + }); + + connect(&m_alice2.client, &QXmppClient::messageReceived, &context, [=, &isFirstMessageDecryptedByAlice2, &isSecondMessageDecryptedByAlice2](const QXmppMessage &receivedMessage) { + // Process only encrypted stanzas. + if (receivedMessage.e2eeMetadata()) { + qDebug() << "Decrypted message:" << receivedMessage.body(); + if (receivedMessage.body() == message1.body()) { + isFirstMessageDecryptedByAlice2 = true; + } else if (receivedMessage.body() == message2.body()) { + isSecondMessageDecryptedByAlice2 = true; + } + } + }); + + connect(&m_alice1.logger, &QXmppLogger::message, &context, [=, &isEmptyOmemoMessageReceivedByAlice1, &isSecondMessageSentByAlice1](QXmppLogger::MessageType type, const QString &text) mutable { + if (type == QXmppLogger::SentMessage) { + qDebug() << "Alice - SENT: " << text; + } else if (type == QXmppLogger::ReceivedMessage) { + qDebug() << "Alice - RECEIVED: " << text; + + // Check if Alice 1 received an empty OMEMO message from Alice 2. + // If that is the case, send a second message to Alice 2. + // The empty OMEMO message is not emitted via QXmppClient::messageReceived(). + // Thus, it must be parsed manually here. + const auto content = text.toUtf8(); + if (content.startsWith(QByteArrayLiteral("<message "))) { + QXmppMessage message; + parsePacket(message, text.toUtf8()); + + if (const auto optionalOmemoElement = message.omemoElement(); optionalOmemoElement && optionalOmemoElement.value().payload().isEmpty()) { + isEmptyOmemoMessageReceivedByAlice1 = true; + + auto future = m_alice1.client.send(std::move(message2), QXmppSendStanzaParams()); + await(future, this, [=, &isSecondMessageSentByAlice1](QXmpp::SendResult result) { + if (std::get_if<QXmpp::SendSuccess>(&result)) { + isSecondMessageSentByAlice1 = true; + } + }); + } + } + } + }); + + // Wait for receiving the device of Alice 2 in order to send a message to Bob and a message + // carbon to Alice 2. + connect(m_alice1.manager, &QXmppOmemoManager::deviceAdded, &context, [=, &isFirstMessageSentByAlice1](const QString &jid, uint32_t) mutable { + if (jid == m_alice2.client.configuration().jidBare()) { + if (!isFirstMessageSentByAlice1) { + auto future = m_alice1.client.send(std::move(message1), QXmppSendStanzaParams()); + await(future, this, [=, &isFirstMessageSentByAlice1](QXmpp::SendResult result) { + if (std::get_if<QXmpp::SendSuccess>(&result)) { + isFirstMessageSentByAlice1 = true; + } + }); + } + } + }); + + m_alice1.client.connectToServer(config1); + + QTRY_VERIFY_WITH_TIMEOUT(isFirstMessageSentByAlice1, 10000); + QTRY_VERIFY_WITH_TIMEOUT(isFirstMessageDecryptedByAlice2, 10000); + QTRY_VERIFY_WITH_TIMEOUT(isEmptyOmemoMessageReceivedByAlice1, 10000); + QTRY_VERIFY_WITH_TIMEOUT(isSecondMessageSentByAlice1, 10000); + QTRY_VERIFY_WITH_TIMEOUT(isSecondMessageDecryptedByAlice2, 10000); + + m_alice1.client.disconnectFromServer(); + QVERIFY2(disconnectedAlice1Spy.wait(), "Could not disconnect from server!"); + finish(m_alice2); +} + +void tst_QXmppOmemoManager::testSendIq() +{ + SKIP_IF_INTEGRATION_TESTS_DISABLED() + + QSignalSpy disconnectedAlice1Spy(&m_alice1.client, &QXmppClient::disconnected); + + auto isFirstRequestSent = false; + auto isErrorResponseReceived = false; + auto isSecondRequestSent = false; + auto isResultResponseReceived = false; + + const auto config1 = IntegrationTests::clientConfiguration(); + auto config2 = config1; + config2.setResource(config2.resource() % QStringLiteral("2")); + + const QObject context; + + QXmppBitsOfBinaryIq requestIq; + requestIq.setTo(config2.jid()); + requestIq.setCid(QXmppBitsOfBinaryContentId::fromContentId(QStringLiteral("sha1+8f35fef110ffc5df08d579a50083ff9308fb6242@bob.xmpp.org"))); + + QXmppBitsOfBinaryIq responseIq; + responseIq.setType(QXmppIq::Result); + responseIq.setTo(config1.jid()); + responseIq.setData(QByteArray::fromBase64(QByteArrayLiteral( + "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAclBMVEUAAADYZArfaA9GIAoBAAGN" + "QA3MXgniaAiEOgZMIATDXRXZZhHUZBHIXhDrbQ6sUQ7OYA2TRAubRwqMQQq7VQlKHgMAAAK5WRfJ" + "YBOORBFoMBCwUQ/ycA6FPgvbZQpeKglNJQmrTQeOPgQyFwR6MwACAABRPE/oAAAAW0lEQVQI1xXI" + "Rw6EMBTAUP8kJKENnaF37n9FQPLCekAgzklhgCwfrlNHEXhrvCsxaU/SwLGAFuIWZFpBERtKm9Xf" + "JqH+vVWh4POqgHrsAtht095b+geYRSl57QHSPgP3+CwvAAAAAABJRU5ErkJggg=="))); + + OmemoIqHandler iqHandler(requestIq, responseIq); + + connect(&m_alice1.client, &QXmppClient::connected, &context, [=]() { + auto future = m_alice1.manager->setUp(); + await(future, this, [=](bool isSetUp) { + if (isSetUp) { + auto future = m_alice1.manager->setSecurityPolicy(Toakafa); + await(future, this, [=]() { + auto future = m_alice2.manager->setSecurityPolicy(Toakafa); + await(future, this, [=]() { + m_alice2.client.connectToServer(config2); + }); + }); + } + }); + }); + + connect(&m_alice2.client, &QXmppClient::connected, &context, [=]() { + m_alice2.manager->setUp(); + }); + + connect(&m_alice1.logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) { + if (type == QXmppLogger::SentMessage) { + qDebug() << "Alice - SENT: " << text; + } else if (type == QXmppLogger::ReceivedMessage) { + qDebug() << "Alice - RECEIVED: " << text; + } + }); + + connect(&m_alice2.logger, &QXmppLogger::message, &context, [=](QXmppLogger::MessageType type, const QString &text) { + if (type == QXmppLogger::SentMessage) { + qDebug() << "Alice 2 - SENT: " << text; + } else { + qDebug() << "Alice 2 - RECEIVED: " << text; + } + }); + + // Wait for receiving the device of Alice 2 in order to send a request to it. + connect(m_alice1.manager, &QXmppOmemoManager::deviceAdded, &context, [=, &isFirstRequestSent, &isErrorResponseReceived, &isSecondRequestSent, &isResultResponseReceived, &iqHandler](const QString &jid, uint32_t) { + if (jid != m_alice2.client.configuration().jidBare()) { + return; + } + if (!isFirstRequestSent && !isSecondRequestSent) { + auto requestIqCopy = requestIq; + auto future = m_alice1.client.sendSensitiveIq(std::move(requestIqCopy)); + await(future, this, [=, &isFirstRequestSent, &isErrorResponseReceived, &isSecondRequestSent, &isResultResponseReceived, &iqHandler](QXmppClient::IqResult result) { + if (const auto response = std::get_if<QDomElement>(&result)) { + isFirstRequestSent = true; + + QXmppIq iq; + iq.parse(*response); + + QCOMPARE(iq.type(), QXmppIq::Error); + const auto error = iq.error(); + QCOMPARE(error.type(), QXmppStanza::Error::Cancel); + QCOMPARE(error.condition(), QXmppStanza::Error::FeatureNotImplemented); + isErrorResponseReceived = true; + + m_alice2.client.addExtension(&iqHandler); + + auto requestIqCopy = requestIq; + auto future = m_alice1.client.sendSensitiveIq(std::move(requestIqCopy)); + await(future, this, [=, &isSecondRequestSent, &isResultResponseReceived](QXmppClient::IqResult result) { + if (const auto response = std::get_if<QDomElement>(&result)) { + isSecondRequestSent = true; + + if (QXmppBitsOfBinaryIq::isBitsOfBinaryIq(*response)) { + QXmppBitsOfBinaryIq iq; + iq.parse(*response); + QCOMPARE(iq.data(), responseIq.data()); + isResultResponseReceived = true; + } + } + }); + } + }); + } + }); + + m_alice1.client.connectToServer(config1); + + QTRY_VERIFY_WITH_TIMEOUT(isFirstRequestSent, 20'000); + QTRY_VERIFY(isErrorResponseReceived); + QTRY_VERIFY(isSecondRequestSent); + QTRY_VERIFY(isResultResponseReceived); + + m_alice1.client.disconnectFromServer(); + QVERIFY2(disconnectedAlice1Spy.wait(), "Could not disconnect from server!"); + finish(m_alice2); +} + +void tst_QXmppOmemoManager::finish(OmemoUser &omemoUser) +{ + QSignalSpy disconnectedSpy(&omemoUser.client, &QXmppClient::disconnected); + + bool isManagerReset = false; + + auto future = omemoUser.manager->resetAll(); + await(future, this, [=, &isManagerReset, &omemoUser](bool isReset) { + if (isReset) { + isManagerReset = true; + } + + omemoUser.client.disconnectFromServer(); + }); + + QVERIFY2(disconnectedSpy.wait(), "Could not disconnect from server!"); + QTRY_VERIFY(isManagerReset); +} + +QTEST_MAIN(tst_QXmppOmemoManager) +#include "tst_qxmppomemomanager.moc" diff --git a/tests/qxmppomemomemorystorage/tst_qxmppomemomemorystorage.cpp b/tests/qxmppomemomemorystorage/tst_qxmppomemomemorystorage.cpp new file mode 100644 index 00000000..cb751ae5 --- /dev/null +++ b/tests/qxmppomemomemorystorage/tst_qxmppomemomemorystorage.cpp @@ -0,0 +1,310 @@ +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "QXmppOmemoMemoryStorage.h" + +#include <QtTest> + +class tst_QXmppOmemoMemoryStorage : public QObject +{ + Q_OBJECT + +private slots: + void testOwnDevice(); + void testSignedPreKeyPairs(); + void testPreKeyPairs(); + void testDevices(); + void testResetAll(); + +private: + QXmppOmemoMemoryStorage m_omemoStorage; +}; + +void tst_QXmppOmemoMemoryStorage::testOwnDevice() +{ + auto future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + auto optionalResult = future.result().ownDevice; + QVERIFY(!optionalResult); + + QXmppOmemoStorage::OwnDevice ownDevice; + + m_omemoStorage.setOwnDevice(ownDevice); + + // Check the default values. + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + optionalResult = future.result().ownDevice; + QVERIFY(optionalResult); + auto result = optionalResult.value(); + QCOMPARE(result.id, 0); + QVERIFY(result.label.isEmpty()); + QVERIFY(result.privateIdentityKey.isEmpty()); + QVERIFY(result.publicIdentityKey.isEmpty()); + QCOMPARE(result.latestSignedPreKeyId, 1); + QCOMPARE(result.latestPreKeyId, 1); + + ownDevice.id = 1; + ownDevice.label = QStringLiteral("Notebook"); + ownDevice.privateIdentityKey = QByteArray::fromBase64(QByteArrayLiteral("ZDVNZFdJeFFUa3N6ZWdSUG9scUdoQXFpWERGbHRsZTIK")); + ownDevice.publicIdentityKey = QByteArray::fromBase64(QByteArrayLiteral("dUsxSTJyM2tKVHE1TzNXbk1Xd0tpMGY0TnFleDRYUGkK")); + ownDevice.latestSignedPreKeyId = 2; + ownDevice.latestPreKeyId = 100; + + m_omemoStorage.setOwnDevice(ownDevice); + + // Check the set values. + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + optionalResult = future.result().ownDevice; + QVERIFY(optionalResult); + result = optionalResult.value(); + QCOMPARE(result.id, 1); + QCOMPARE(result.label, QStringLiteral("Notebook")); + QCOMPARE(result.privateIdentityKey, QByteArray::fromBase64(QByteArrayLiteral("ZDVNZFdJeFFUa3N6ZWdSUG9scUdoQXFpWERGbHRsZTIK"))); + QCOMPARE(result.publicIdentityKey, QByteArray::fromBase64(QByteArrayLiteral("dUsxSTJyM2tKVHE1TzNXbk1Xd0tpMGY0TnFleDRYUGkK"))); + QCOMPARE(result.latestSignedPreKeyId, 2); + QCOMPARE(result.latestPreKeyId, 100); +} + +void tst_QXmppOmemoMemoryStorage::testSignedPreKeyPairs() +{ + auto future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + auto result = future.result().signedPreKeyPairs; + QVERIFY(result.isEmpty()); + + QXmppOmemoStorage::SignedPreKeyPair signedPreKeyPair1; + signedPreKeyPair1.creationDate = QDateTime(QDate(2022, 01, 01), QTime()); + signedPreKeyPair1.data = QByteArrayLiteral("FaZmWjwqppAoMff72qTzUIktGUbi4pAmds1Cuh6OElmi"); + + QXmppOmemoStorage::SignedPreKeyPair signedPreKeyPair2; + signedPreKeyPair2.creationDate = QDateTime(QDate(2022, 01, 02), QTime()); + signedPreKeyPair2.data = QByteArrayLiteral("jsrj4UYQqaHJrlysNu0uoHgmAU8ffknPpwKJhdqLYgIU"); + + QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair> signedPreKeyPairs = { { 1, signedPreKeyPair1 }, + { 2, signedPreKeyPair2 } }; + + m_omemoStorage.addSignedPreKeyPair(1, signedPreKeyPair1); + m_omemoStorage.addSignedPreKeyPair(2, signedPreKeyPair2); + + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + result = future.result().signedPreKeyPairs; + const auto signedPreKeyPairResult1 = result.value(1); + QCOMPARE(signedPreKeyPairResult1.creationDate, QDateTime(QDate(2022, 01, 01), QTime())); + QCOMPARE(signedPreKeyPairResult1.data, QByteArrayLiteral("FaZmWjwqppAoMff72qTzUIktGUbi4pAmds1Cuh6OElmi")); + const auto signedPreKeyPairResult2 = result.value(2); + QCOMPARE(signedPreKeyPairResult2.creationDate, QDateTime(QDate(2022, 01, 02), QTime())); + QCOMPARE(signedPreKeyPairResult2.data, QByteArrayLiteral("jsrj4UYQqaHJrlysNu0uoHgmAU8ffknPpwKJhdqLYgIU")); + + signedPreKeyPairs.remove(1); + m_omemoStorage.removeSignedPreKeyPair(1); + + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + result = future.result().signedPreKeyPairs; + const auto signedPreKeyPairResult = result.value(2); + QCOMPARE(signedPreKeyPairResult.creationDate, QDateTime(QDate(2022, 01, 02), QTime())); + QCOMPARE(signedPreKeyPairResult.data, QByteArrayLiteral("jsrj4UYQqaHJrlysNu0uoHgmAU8ffknPpwKJhdqLYgIU")); +} + +void tst_QXmppOmemoMemoryStorage::testPreKeyPairs() +{ + auto future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + auto result = future.result().preKeyPairs; + QVERIFY(result.isEmpty()); + + const QHash<uint32_t, QByteArray> preKeyPairs1 = { { 1, QByteArrayLiteral("RZLgD0lmL2WpJbskbGKFRMZL4zqSSvU0rElmO7UwGSVt") }, + { 2, QByteArrayLiteral("3PGPNsf9P7pPitp9dt2uvZYT4HkxdHJAbWqLvOPXUeca") } }; + const QHash<uint32_t, QByteArray> preKeyPairs2 = { { 3, QByteArrayLiteral("LpLBVXejfU4d0qcPOJCRNDDg9IMbOujpV3UTYtZU9LTy") } }; + + QHash<uint32_t, QByteArray> preKeyPairs; + preKeyPairs.insert(preKeyPairs1); + preKeyPairs.insert(preKeyPairs2); + + m_omemoStorage.addPreKeyPairs(preKeyPairs1); + m_omemoStorage.addPreKeyPairs(preKeyPairs2); + + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + result = future.result().preKeyPairs; + QCOMPARE(result, preKeyPairs); + + preKeyPairs.remove(1); + m_omemoStorage.removePreKeyPair(1); + + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + result = future.result().preKeyPairs; + QCOMPARE(result, preKeyPairs); +} + +void tst_QXmppOmemoMemoryStorage::testDevices() +{ + auto future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + auto result = future.result().devices; + QVERIFY(result.isEmpty()); + + QXmppOmemoStorage::Device deviceAlice; + deviceAlice.label = QStringLiteral("Desktop"); + deviceAlice.keyId = QByteArray::fromBase64(QByteArrayLiteral("bEFLaDRQRkFlYXdyakE2aURoN0wyMzk2NTJEM2hRMgo=")); + deviceAlice.session = QByteArray::fromBase64(QByteArrayLiteral("Cs8CCAQSIQWIhBRMdJ80tLVT7ius0H1LutRLeXBid68NH90M/kwhGxohBT+2kM/wVQ2UrZZPJBRmGZP0ZoCCWiET7KxA3ieAa888IiBSTWnp4qrTeo7z9kfKRaAFy+fYwPBI2HCSOxfC0anyPigAMmsKIQXZ95Xs7I+tOsg76eLtp266XTuCF8STa+VZkXPPJ00WSRIgmJ73wjhXPZqIt9ofB0NVwbWOKnYzQ90SHJEd/hyBHkUaJAgAEiDxXDT00+zpJd+TKJrD6nWQxQZhB8I7vCRdD/Oxw61MYjpJCiEFmTV1l+cOLEytoTp17VOEunYlCZmDqn/qoUYI/8P9ZQsaJAgBEiB/QP+9Lb0YOhSQmIr/X75Vs1FME1qzmohSzqBVTzbfZFCnf1jsR2AAaiEFPxj3VK+knGrndOjcgMXI4wEfH/0VrbgJqobGWbewYyA=")); + deviceAlice.unrespondedSentStanzasCount = 10; + deviceAlice.unrespondedReceivedStanzasCount = 11; + deviceAlice.removalFromDeviceListDate = QDateTime(QDate(2022, 01, 01), QTime()); + + QXmppOmemoStorage::Device deviceBob1; + deviceBob1.label = QStringLiteral("Phone"); + deviceBob1.keyId = QByteArray::fromBase64(QByteArrayLiteral("WTV6c3B2UFhYbE9OQ1d0N0ZScUhLWXpmYnY2emJoego=")); + deviceBob1.session = QByteArray::fromBase64(QByteArrayLiteral("CvgCCAQSIQXZwE+G9R6ECMxKWPMidwcx3lPboUT2KEoea3B2T3vjUBohBQ7qW+Fb9Gi/SLsuQTv2TRixF0zLx2/mw0V4arjYSmgHIiCwuvEP2eyFU7FsbtSZBWKt+hH/DwBF7C0WrfxDrSu1bSgAMmsKIQXm5tRa73ZcUWn7fQa2YlDv+yLw1copPjdRZCrGcK7cNRIg0OXBvqBTAfyiUlLKW3LDIiSMHkRYYWDyknSJz3s+81oaJAgAEiAQlSKV+70EMYAjjW88dO52dp9e/aDhT8YUDHNFaCFUxTpJCiEF2OE4fb7Quwg0PMeJfT1uXmq/YXVaos9A7bn37TySiWkaJAgAEiDJlr5w0mBHBHZzttfVyvd2y2IzBV7bGdoX+lKHaEGIoUonCAwSIQXN7Y76Vwcsaubw8EHYaIPnBB11WjEEYcEPalwlgEUECRgCUMgnWMgnYABqIQXN7Y76Vwcsaubw8EHYaIPnBB11WjEEYcEPalwlgEUECQ==")); + deviceBob1.unrespondedSentStanzasCount = 20; + deviceBob1.unrespondedReceivedStanzasCount = 21; + deviceBob1.removalFromDeviceListDate = QDateTime(QDate(2022, 01, 02), QTime()); + + QXmppOmemoStorage::Device deviceBob2; + deviceBob2.label = QStringLiteral("Tablet"); + deviceBob2.keyId = QByteArray::fromBase64(QByteArrayLiteral("U0tXcUlSVHVISzZLYUdGcW53czBtdXYxTEt2blVsbQo=")); + deviceBob2.session = QByteArray::fromBase64(QByteArrayLiteral("CvgCCAQSIQU/tpDP8FUNlK2WTyQUZhmT9GaAglohE+ysQN4ngGvPPBohBdnAT4b1HoQIzEpY8yJ3BzHeU9uhRPYoSh5rcHZPe+NQIiBNmwyjLm5xdbf5f9ab9AASopfdiSybMFMdS4SQR5pSTygAMmsKIQW5FhVKpKUzKlhUCfoCmMwoo5jUFn7+NrcOQl6CQYraZRIgkNHGSWgeoLUvYMM8wsgqU4RUv8ymv/Kv4LLJb8q4vlEaJAgAEiA/GmWir7/6tWyOTrGXsehUnnPZhFs6zGvTDNe1LZaIeTpJCiEFa7t/sVQV2uofS36GbijY63d2B4yJKFGDu6K96cU5PFsaJAgAEiA6kX2jqwfZkN0AmNOZGLPg9J8ryrSSpo74DxU85z0q/konCE4SIQWZRzzFf3M1/gzbg9/xUsNcyiUnr5jAjLpSPOj7BOW6BBgCUKd/WKd/YABqIQWZRzzFf3M1/gzbg9/xUsNcyiUnr5jAjLpSPOj7BOW6BA==")); + deviceBob2.unrespondedSentStanzasCount = 30; + deviceBob2.unrespondedReceivedStanzasCount = 31; + deviceBob2.removalFromDeviceListDate = QDateTime(QDate(2022, 01, 03), QTime()); + + m_omemoStorage.addDevice(QStringLiteral("alice@example.org"), 1, deviceAlice); + m_omemoStorage.addDevice(QStringLiteral("bob@example.com"), 1, deviceBob1); + m_omemoStorage.addDevice(QStringLiteral("bob@example.com"), 2, deviceBob2); + + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + result = future.result().devices; + QCOMPARE(result.size(), 2); + + auto resultDevicesAlice = result.value(QStringLiteral("alice@example.org")); + QCOMPARE(resultDevicesAlice.size(), 1); + + auto resultDeviceAlice = resultDevicesAlice.value(1); + QCOMPARE(resultDeviceAlice.label, QStringLiteral("Desktop")); + QCOMPARE(resultDeviceAlice.keyId, QByteArray::fromBase64(QByteArrayLiteral("bEFLaDRQRkFlYXdyakE2aURoN0wyMzk2NTJEM2hRMgo="))); + QCOMPARE(resultDeviceAlice.session, QByteArray::fromBase64(QByteArrayLiteral("Cs8CCAQSIQWIhBRMdJ80tLVT7ius0H1LutRLeXBid68NH90M/kwhGxohBT+2kM/wVQ2UrZZPJBRmGZP0ZoCCWiET7KxA3ieAa888IiBSTWnp4qrTeo7z9kfKRaAFy+fYwPBI2HCSOxfC0anyPigAMmsKIQXZ95Xs7I+tOsg76eLtp266XTuCF8STa+VZkXPPJ00WSRIgmJ73wjhXPZqIt9ofB0NVwbWOKnYzQ90SHJEd/hyBHkUaJAgAEiDxXDT00+zpJd+TKJrD6nWQxQZhB8I7vCRdD/Oxw61MYjpJCiEFmTV1l+cOLEytoTp17VOEunYlCZmDqn/qoUYI/8P9ZQsaJAgBEiB/QP+9Lb0YOhSQmIr/X75Vs1FME1qzmohSzqBVTzbfZFCnf1jsR2AAaiEFPxj3VK+knGrndOjcgMXI4wEfH/0VrbgJqobGWbewYyA="))); + QCOMPARE(resultDeviceAlice.unrespondedSentStanzasCount, 10); + QCOMPARE(resultDeviceAlice.unrespondedReceivedStanzasCount, 11); + QCOMPARE(resultDeviceAlice.removalFromDeviceListDate, QDateTime(QDate(2022, 01, 01), QTime())); + + auto resultDevicesBob = result.value(QStringLiteral("bob@example.com")); + QCOMPARE(resultDevicesBob.size(), 2); + + auto resultDeviceBob1 = resultDevicesBob.value(1); + QCOMPARE(resultDeviceBob1.label, QStringLiteral("Phone")); + QCOMPARE(resultDeviceBob1.keyId, QByteArray::fromBase64(QByteArrayLiteral("WTV6c3B2UFhYbE9OQ1d0N0ZScUhLWXpmYnY2emJoego="))); + QCOMPARE(resultDeviceBob1.session, QByteArray::fromBase64(QByteArrayLiteral("CvgCCAQSIQXZwE+G9R6ECMxKWPMidwcx3lPboUT2KEoea3B2T3vjUBohBQ7qW+Fb9Gi/SLsuQTv2TRixF0zLx2/mw0V4arjYSmgHIiCwuvEP2eyFU7FsbtSZBWKt+hH/DwBF7C0WrfxDrSu1bSgAMmsKIQXm5tRa73ZcUWn7fQa2YlDv+yLw1copPjdRZCrGcK7cNRIg0OXBvqBTAfyiUlLKW3LDIiSMHkRYYWDyknSJz3s+81oaJAgAEiAQlSKV+70EMYAjjW88dO52dp9e/aDhT8YUDHNFaCFUxTpJCiEF2OE4fb7Quwg0PMeJfT1uXmq/YXVaos9A7bn37TySiWkaJAgAEiDJlr5w0mBHBHZzttfVyvd2y2IzBV7bGdoX+lKHaEGIoUonCAwSIQXN7Y76Vwcsaubw8EHYaIPnBB11WjEEYcEPalwlgEUECRgCUMgnWMgnYABqIQXN7Y76Vwcsaubw8EHYaIPnBB11WjEEYcEPalwlgEUECQ=="))); + QCOMPARE(resultDeviceBob1.unrespondedSentStanzasCount, 20); + QCOMPARE(resultDeviceBob1.unrespondedReceivedStanzasCount, 21); + QCOMPARE(resultDeviceBob1.removalFromDeviceListDate, QDateTime(QDate(2022, 01, 02), QTime())); + + auto resultDeviceBob2 = resultDevicesBob.value(2); + QCOMPARE(resultDeviceBob2.label, QStringLiteral("Tablet")); + QCOMPARE(resultDeviceBob2.keyId, QByteArray::fromBase64(QByteArrayLiteral("U0tXcUlSVHVISzZLYUdGcW53czBtdXYxTEt2blVsbQo="))); + QCOMPARE(resultDeviceBob2.session, QByteArray::fromBase64(QByteArrayLiteral("CvgCCAQSIQU/tpDP8FUNlK2WTyQUZhmT9GaAglohE+ysQN4ngGvPPBohBdnAT4b1HoQIzEpY8yJ3BzHeU9uhRPYoSh5rcHZPe+NQIiBNmwyjLm5xdbf5f9ab9AASopfdiSybMFMdS4SQR5pSTygAMmsKIQW5FhVKpKUzKlhUCfoCmMwoo5jUFn7+NrcOQl6CQYraZRIgkNHGSWgeoLUvYMM8wsgqU4RUv8ymv/Kv4LLJb8q4vlEaJAgAEiA/GmWir7/6tWyOTrGXsehUnnPZhFs6zGvTDNe1LZaIeTpJCiEFa7t/sVQV2uofS36GbijY63d2B4yJKFGDu6K96cU5PFsaJAgAEiA6kX2jqwfZkN0AmNOZGLPg9J8ryrSSpo74DxU85z0q/konCE4SIQWZRzzFf3M1/gzbg9/xUsNcyiUnr5jAjLpSPOj7BOW6BBgCUKd/WKd/YABqIQWZRzzFf3M1/gzbg9/xUsNcyiUnr5jAjLpSPOj7BOW6BA=="))); + QCOMPARE(resultDeviceBob2.unrespondedSentStanzasCount, 30); + QCOMPARE(resultDeviceBob2.unrespondedReceivedStanzasCount, 31); + QCOMPARE(resultDeviceBob2.removalFromDeviceListDate, QDateTime(QDate(2022, 01, 03), QTime())); + + m_omemoStorage.removeDevice(QStringLiteral("bob@example.com"), 2); + + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + result = future.result().devices; + QCOMPARE(result.size(), 2); + + resultDevicesAlice = result.value(QStringLiteral("alice@example.org")); + QCOMPARE(resultDevicesAlice.size(), 1); + + resultDeviceAlice = resultDevicesAlice.value(1); + QCOMPARE(resultDeviceAlice.label, QStringLiteral("Desktop")); + QCOMPARE(resultDeviceAlice.keyId, QByteArray::fromBase64(QByteArrayLiteral("bEFLaDRQRkFlYXdyakE2aURoN0wyMzk2NTJEM2hRMgo="))); + QCOMPARE(resultDeviceAlice.session, QByteArray::fromBase64(QByteArrayLiteral("Cs8CCAQSIQWIhBRMdJ80tLVT7ius0H1LutRLeXBid68NH90M/kwhGxohBT+2kM/wVQ2UrZZPJBRmGZP0ZoCCWiET7KxA3ieAa888IiBSTWnp4qrTeo7z9kfKRaAFy+fYwPBI2HCSOxfC0anyPigAMmsKIQXZ95Xs7I+tOsg76eLtp266XTuCF8STa+VZkXPPJ00WSRIgmJ73wjhXPZqIt9ofB0NVwbWOKnYzQ90SHJEd/hyBHkUaJAgAEiDxXDT00+zpJd+TKJrD6nWQxQZhB8I7vCRdD/Oxw61MYjpJCiEFmTV1l+cOLEytoTp17VOEunYlCZmDqn/qoUYI/8P9ZQsaJAgBEiB/QP+9Lb0YOhSQmIr/X75Vs1FME1qzmohSzqBVTzbfZFCnf1jsR2AAaiEFPxj3VK+knGrndOjcgMXI4wEfH/0VrbgJqobGWbewYyA="))); + QCOMPARE(resultDeviceAlice.unrespondedSentStanzasCount, 10); + QCOMPARE(resultDeviceAlice.unrespondedReceivedStanzasCount, 11); + QCOMPARE(resultDeviceAlice.removalFromDeviceListDate, QDateTime(QDate(2022, 01, 01), QTime())); + + resultDevicesBob = result.value(QStringLiteral("bob@example.com")); + QCOMPARE(resultDevicesBob.size(), 1); + + resultDeviceBob1 = resultDevicesBob.value(1); + QCOMPARE(resultDeviceBob1.label, QStringLiteral("Phone")); + QCOMPARE(resultDeviceBob1.keyId, QByteArray::fromBase64(QByteArrayLiteral("WTV6c3B2UFhYbE9OQ1d0N0ZScUhLWXpmYnY2emJoego="))); + QCOMPARE(resultDeviceBob1.session, QByteArray::fromBase64(QByteArrayLiteral("CvgCCAQSIQXZwE+G9R6ECMxKWPMidwcx3lPboUT2KEoea3B2T3vjUBohBQ7qW+Fb9Gi/SLsuQTv2TRixF0zLx2/mw0V4arjYSmgHIiCwuvEP2eyFU7FsbtSZBWKt+hH/DwBF7C0WrfxDrSu1bSgAMmsKIQXm5tRa73ZcUWn7fQa2YlDv+yLw1copPjdRZCrGcK7cNRIg0OXBvqBTAfyiUlLKW3LDIiSMHkRYYWDyknSJz3s+81oaJAgAEiAQlSKV+70EMYAjjW88dO52dp9e/aDhT8YUDHNFaCFUxTpJCiEF2OE4fb7Quwg0PMeJfT1uXmq/YXVaos9A7bn37TySiWkaJAgAEiDJlr5w0mBHBHZzttfVyvd2y2IzBV7bGdoX+lKHaEGIoUonCAwSIQXN7Y76Vwcsaubw8EHYaIPnBB11WjEEYcEPalwlgEUECRgCUMgnWMgnYABqIQXN7Y76Vwcsaubw8EHYaIPnBB11WjEEYcEPalwlgEUECQ=="))); + QCOMPARE(resultDeviceBob1.unrespondedSentStanzasCount, 20); + QCOMPARE(resultDeviceBob1.unrespondedReceivedStanzasCount, 21); + QCOMPARE(resultDeviceBob1.removalFromDeviceListDate, QDateTime(QDate(2022, 01, 02), QTime())); + + m_omemoStorage.removeDevice(QStringLiteral("alice@example.org"), 1); + + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + result = future.result().devices; + QCOMPARE(result.size(), 1); + + resultDevicesBob = result.value(QStringLiteral("bob@example.com")); + QCOMPARE(resultDevicesBob.size(), 1); + + resultDeviceBob1 = resultDevicesBob.value(1); + QCOMPARE(resultDeviceBob1.label, QStringLiteral("Phone")); + QCOMPARE(resultDeviceBob1.keyId, QByteArray::fromBase64(QByteArrayLiteral("WTV6c3B2UFhYbE9OQ1d0N0ZScUhLWXpmYnY2emJoego="))); + QCOMPARE(resultDeviceBob1.session, QByteArray::fromBase64(QByteArrayLiteral("CvgCCAQSIQXZwE+G9R6ECMxKWPMidwcx3lPboUT2KEoea3B2T3vjUBohBQ7qW+Fb9Gi/SLsuQTv2TRixF0zLx2/mw0V4arjYSmgHIiCwuvEP2eyFU7FsbtSZBWKt+hH/DwBF7C0WrfxDrSu1bSgAMmsKIQXm5tRa73ZcUWn7fQa2YlDv+yLw1copPjdRZCrGcK7cNRIg0OXBvqBTAfyiUlLKW3LDIiSMHkRYYWDyknSJz3s+81oaJAgAEiAQlSKV+70EMYAjjW88dO52dp9e/aDhT8YUDHNFaCFUxTpJCiEF2OE4fb7Quwg0PMeJfT1uXmq/YXVaos9A7bn37TySiWkaJAgAEiDJlr5w0mBHBHZzttfVyvd2y2IzBV7bGdoX+lKHaEGIoUonCAwSIQXN7Y76Vwcsaubw8EHYaIPnBB11WjEEYcEPalwlgEUECRgCUMgnWMgnYABqIQXN7Y76Vwcsaubw8EHYaIPnBB11WjEEYcEPalwlgEUECQ=="))); + QCOMPARE(resultDeviceBob1.unrespondedSentStanzasCount, 20); + QCOMPARE(resultDeviceBob1.unrespondedReceivedStanzasCount, 21); + QCOMPARE(resultDeviceBob1.removalFromDeviceListDate, QDateTime(QDate(2022, 01, 02), QTime())); + + m_omemoStorage.addDevice(QStringLiteral("alice@example.org"), 1, deviceAlice); + m_omemoStorage.addDevice(QStringLiteral("bob@example.com"), 2, deviceBob2); + m_omemoStorage.removeDevices(QStringLiteral("bob@example.com")); + + future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + result = future.result().devices; + QCOMPARE(result.size(), 1); + + resultDevicesAlice = result.value(QStringLiteral("alice@example.org")); + QCOMPARE(resultDevicesAlice.size(), 1); + + resultDeviceAlice = resultDevicesAlice.value(1); + QCOMPARE(resultDeviceAlice.label, QStringLiteral("Desktop")); + QCOMPARE(resultDeviceAlice.keyId, QByteArray::fromBase64(QByteArrayLiteral("bEFLaDRQRkFlYXdyakE2aURoN0wyMzk2NTJEM2hRMgo="))); + QCOMPARE(resultDeviceAlice.session, QByteArray::fromBase64(QByteArrayLiteral("Cs8CCAQSIQWIhBRMdJ80tLVT7ius0H1LutRLeXBid68NH90M/kwhGxohBT+2kM/wVQ2UrZZPJBRmGZP0ZoCCWiET7KxA3ieAa888IiBSTWnp4qrTeo7z9kfKRaAFy+fYwPBI2HCSOxfC0anyPigAMmsKIQXZ95Xs7I+tOsg76eLtp266XTuCF8STa+VZkXPPJ00WSRIgmJ73wjhXPZqIt9ofB0NVwbWOKnYzQ90SHJEd/hyBHkUaJAgAEiDxXDT00+zpJd+TKJrD6nWQxQZhB8I7vCRdD/Oxw61MYjpJCiEFmTV1l+cOLEytoTp17VOEunYlCZmDqn/qoUYI/8P9ZQsaJAgBEiB/QP+9Lb0YOhSQmIr/X75Vs1FME1qzmohSzqBVTzbfZFCnf1jsR2AAaiEFPxj3VK+knGrndOjcgMXI4wEfH/0VrbgJqobGWbewYyA="))); + QCOMPARE(resultDeviceAlice.unrespondedSentStanzasCount, 10); + QCOMPARE(resultDeviceAlice.unrespondedReceivedStanzasCount, 11); + QCOMPARE(resultDeviceAlice.removalFromDeviceListDate, QDateTime(QDate(2022, 01, 01), QTime())); +} + +void tst_QXmppOmemoMemoryStorage::testResetAll() +{ + m_omemoStorage.setOwnDevice(QXmppOmemoStorage::OwnDevice()); + + QXmppOmemoStorage::SignedPreKeyPair signedPreKeyPair; + signedPreKeyPair.creationDate = QDateTime(QDate(2022, 01, 01), QTime()); + signedPreKeyPair.data = QByteArrayLiteral("FaZmWjwqppAoMff72qTzUIktGUbi4pAmds1Cuh6OElmi"); + m_omemoStorage.addSignedPreKeyPair(1, signedPreKeyPair); + + m_omemoStorage.addPreKeyPairs({ { 1, QByteArrayLiteral("RZLgD0lmL2WpJbskbGKFRMZL4zqSSvU0rElmO7UwGSVt") }, + { 2, QByteArrayLiteral("3PGPNsf9P7pPitp9dt2uvZYT4HkxdHJAbWqLvOPXUeca") } }); + m_omemoStorage.addDevice(QStringLiteral("alice@example.org"), + 123, + QXmppOmemoStorage::Device()); + + m_omemoStorage.resetAll(); + + auto future = m_omemoStorage.allData(); + QVERIFY(future.isFinished()); + auto result = future.result(); + QVERIFY(!result.ownDevice); + QVERIFY(result.signedPreKeyPairs.isEmpty()); + QVERIFY(result.preKeyPairs.isEmpty()); + QVERIFY(result.devices.isEmpty()); +} + +QTEST_MAIN(tst_QXmppOmemoMemoryStorage) +#include "tst_qxmppomemomemorystorage.moc" |
