diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f5bd96..b40e876 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,7 @@ if (NOT SYSTEM_QXMPP) add_subdirectory(external/qxmpp) target_link_libraries(squawk PRIVATE qxmpp) + target_link_libraries(squawk PRIVATE QXmppOmemo) else () target_link_libraries(squawk PRIVATE QXmpp::QXmpp) endif () diff --git a/core/account.cpp b/core/account.cpp index 87c341b..4b25737 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -31,6 +31,17 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& config(), presence(), state(Shared::ConnectionState::disconnected), + + mh(new MessageHandler(this)), + rh(new RosterHandler(this)), + vh(new VCardHandler(this)), + dh(new DiscoveryHandler(this)), +#ifdef WITH_OMEMO + th(new TrustHandler(this)), + oh(new OmemoHandler(this)), + tm(new QXmppTrustManager(th)), + om(new QXmppOmemoManager(oh)), +#endif cm(new QXmppCarbonManager()), am(new QXmppMamManager()), mm(new QXmppMucManager()), @@ -40,9 +51,6 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& um(new QXmppUploadRequestManager()), dm(client.findExtension()), rcpm(new QXmppMessageReceiptManager()), -#ifdef WITH_OMEMO - om(new QXmppOmemoManager()), -#endif reconnectScheduled(false), reconnectTimer(new QTimer), network(p_net), @@ -50,17 +58,17 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& lastError(Error::none), pepSupport(Shared::Support::unknown), active(p_active), - notReadyPassword(false), - mh(new MessageHandler(this)), - rh(new RosterHandler(this)), - vh(new VCardHandler(this)), - dh(new DiscoveryHandler(this)) + notReadyPassword(false) { config.setUser(p_login); config.setDomain(p_server); config.setPassword(p_password); config.setAutoAcceptSubscriptions(true); //config.setAutoReconnectionEnabled(false); + + rh->initialize(); + vh->initialize(); + dh->initialize(); QObject::connect(&client, &QXmppClient::stateChanged, this, &Account::onClientStateChange); QObject::connect(&client, &QXmppClient::presenceReceived, this, &Account::onPresenceReceived); @@ -92,6 +100,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived); #ifdef WITH_OMEMO + client.addExtension(tm); client.addExtension(om); qDebug("Added OMEMO manager"); #endif diff --git a/core/account.h b/core/account.h index 1c5d14a..7e5e3b0 100644 --- a/core/account.h +++ b/core/account.h @@ -42,9 +42,6 @@ #include #include #include -#ifdef WITH_OMEMO -#include -#endif #include #include @@ -57,6 +54,13 @@ #include "handlers/vcardhandler.h" #include "handlers/discoveryhandler.h" +#ifdef WITH_OMEMO +#include +#include +#include "handlers/trusthandler.h" +#include "handlers/omemohandler.h" +#endif + namespace Core { @@ -170,6 +174,18 @@ private: QXmppConfiguration config; QXmppPresence presence; Shared::ConnectionState state; + + MessageHandler* mh; + RosterHandler* rh; + VCardHandler* vh; + DiscoveryHandler* dh; +#ifdef WITH_OMEMO + TrustHandler* th; + OmemoHandler* oh; + + QXmppTrustManager* tm; + QXmppOmemoManager* om; +#endif QXmppCarbonManager* cm; QXmppMamManager* am; QXmppMucManager* mm; @@ -179,9 +195,6 @@ private: QXmppUploadRequestManager* um; QXmppDiscoveryManager* dm; QXmppMessageReceiptManager* rcpm; -#ifdef WITH_OMEMO - QXmppOmemoManager* om; -#endif bool reconnectScheduled; QTimer* reconnectTimer; @@ -192,11 +205,6 @@ private: bool active; bool notReadyPassword; - MessageHandler* mh; - RosterHandler* rh; - VCardHandler* vh; - DiscoveryHandler* dh; - private slots: void onClientStateChange(QXmppClient::State state); void onClientError(QXmppClient::Error err); diff --git a/core/components/clientcache.cpp b/core/components/clientcache.cpp index a054428..a312b24 100644 --- a/core/components/clientcache.cpp +++ b/core/components/clientcache.cpp @@ -19,27 +19,28 @@ #include Core::ClientCache::ClientCache(): + db("clients"), + cache(db.addCache("info")), requested(), - cache("clients"), specific() { - cache.open(); + db.open(); } Core::ClientCache::~ClientCache() { - cache.close(); + db.close(); } void Core::ClientCache::open() { - cache.open();} + db.open();} void Core::ClientCache::close() { - cache.close();} + db.close();} bool Core::ClientCache::checkClient(const QString& node, const QString& ver, const QString& hash) { QString id = node + "/" + ver; - if (requested.count(id) == 0 && !cache.checkRecord(id)) { + if (requested.count(id) == 0 && !cache->checkRecord(id)) { Shared::ClientInfo& info = requested.insert(std::make_pair(id, Shared::ClientInfo())).first->second; info.node = node; info.verification = ver; @@ -65,7 +66,7 @@ bool Core::ClientCache::registerClientInfo ( bool valid = info.valid(); if (valid) { - cache.addRecord(id, info); + cache->addRecord(id, info); } else { info.specificPresence = sourceFullJid; specific.insert(std::make_pair(sourceFullJid, info)); diff --git a/core/components/clientcache.h b/core/components/clientcache.h index 15bcb7d..640def3 100644 --- a/core/components/clientcache.h +++ b/core/components/clientcache.h @@ -23,7 +23,8 @@ #include #include -#include +#include + #include #include @@ -46,8 +47,9 @@ public slots: bool registerClientInfo(const QString& sourceFullJid, const QString& id, const std::set& identities, const std::set& features); private: + DataBase db; + DataBase::Cache* cache; std::map requested; - Cache cache; std::map specific; }; diff --git a/core/handlers/CMakeLists.txt b/core/handlers/CMakeLists.txt index 1516aa7..746a36f 100644 --- a/core/handlers/CMakeLists.txt +++ b/core/handlers/CMakeLists.txt @@ -9,4 +9,6 @@ target_sources(squawk PRIVATE discoveryhandler.h omemohandler.cpp omemohandler.h + trusthandler.cpp + trusthandler.h ) diff --git a/core/handlers/discoveryhandler.cpp b/core/handlers/discoveryhandler.cpp index e17c072..2464f07 100644 --- a/core/handlers/discoveryhandler.cpp +++ b/core/handlers/discoveryhandler.cpp @@ -21,7 +21,11 @@ Core::DiscoveryHandler::DiscoveryHandler(Core::Account* account): QObject(), - acc(account) + acc(account) {} + +Core::DiscoveryHandler::~DiscoveryHandler() {} + +void Core::DiscoveryHandler::initialize() { QObject::connect(acc->dm, &QXmppDiscoveryManager::itemsReceived, this, &DiscoveryHandler::onItemsReceived); QObject::connect(acc->dm, &QXmppDiscoveryManager::infoReceived, this, &DiscoveryHandler::onInfoReceived); @@ -32,11 +36,6 @@ Core::DiscoveryHandler::DiscoveryHandler(Core::Account* account): acc->dm->setClientCapabilitiesNode("https://git.macaw.me/blue/squawk"); } -Core::DiscoveryHandler::~DiscoveryHandler() -{ -} - - void Core::DiscoveryHandler::onItemsReceived(const QXmppDiscoveryIq& items) { QString server = acc->getServer(); diff --git a/core/handlers/discoveryhandler.h b/core/handlers/discoveryhandler.h index 3129219..e4ef265 100644 --- a/core/handlers/discoveryhandler.h +++ b/core/handlers/discoveryhandler.h @@ -32,6 +32,8 @@ public: DiscoveryHandler(Account* account); ~DiscoveryHandler(); + void initialize(); + private slots: void onItemsReceived (const QXmppDiscoveryIq& items); void onInfoReceived (const QXmppDiscoveryIq& info); diff --git a/core/handlers/omemohandler.cpp b/core/handlers/omemohandler.cpp index c1dc7ef..25ac752 100644 --- a/core/handlers/omemohandler.cpp +++ b/core/handlers/omemohandler.cpp @@ -22,7 +22,7 @@ Core::OmemoHandler::OmemoHandler(Account* account) : QXmppOmemoStorage(), acc(account), ownDevice(std::nullopt), - db("omemo"), + db(acc->getName() + "/omemo"), meta(db.addCache("meta")), devices(db.addCache>("devices")), preKeyPairs(db.addCache("preKeyPairs")), @@ -155,7 +155,60 @@ QFuture Core::OmemoHandler::resetAll() { return emptyVoidFuture(); } +QDataStream & operator >> (QDataStream& in, QXmppOmemoStorage::Device& device) { + in >> device.label; + in >> device.keyId; + in >> device.session; + in >> device.unrespondedSentStanzasCount; + in >> device.unrespondedReceivedStanzasCount; + in >> device.removalFromDeviceListDate; + return in; +} +QDataStream & operator << (QDataStream& out, const QXmppOmemoStorage::Device& device) { + out << device.label; + out << device.keyId; + out << device.session; + out << device.unrespondedSentStanzasCount; + out << device.unrespondedReceivedStanzasCount; + out << device.removalFromDeviceListDate; + return out; +} +QDataStream & operator >> (QDataStream& in, QXmppOmemoStorage::OwnDevice& device) { + in >> device.id; + in >> device.label; + in >> device.privateIdentityKey; + in >> device.publicIdentityKey; + in >> device.latestSignedPreKeyId; + in >> device.latestPreKeyId; + + return in; +} + +QDataStream & operator << (QDataStream& out, const QXmppOmemoStorage::OwnDevice& device) { + out << device.id; + out << device.label; + out << device.privateIdentityKey; + out << device.publicIdentityKey; + out << device.latestSignedPreKeyId; + out << device.latestPreKeyId; + + return out; +} + +QDataStream & operator >> (QDataStream& in, QXmppOmemoStorage::SignedPreKeyPair& pair) { + in >> pair.creationDate; + in >> pair.data; + + return in; +} + +QDataStream & operator << (QDataStream& out, const QXmppOmemoStorage::SignedPreKeyPair& pair) { + out << pair.creationDate; + out << pair.data; + + return out; +} diff --git a/core/handlers/omemohandler.h b/core/handlers/omemohandler.h index 8f3ac9c..537dfec 100644 --- a/core/handlers/omemohandler.h +++ b/core/handlers/omemohandler.h @@ -21,6 +21,8 @@ #include Q_DECLARE_METATYPE(QXmppOmemoStorage::OwnDevice); +Q_DECLARE_METATYPE(QXmppOmemoStorage::Device); +Q_DECLARE_METATYPE(QXmppOmemoStorage::SignedPreKeyPair); namespace Core { class Account; @@ -63,9 +65,12 @@ private: } QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::Device& device); -QDataStream& operator >> (QDataStream &out, QXmppOmemoStorage::Device device); +QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::Device& device); + +QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::OwnDevice& device); +QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::OwnDevice& device); QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::SignedPreKeyPair& device); -QDataStream& operator >> (QDataStream &out, QXmppOmemoStorage::SignedPreKeyPair device); +QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::SignedPreKeyPair& device); #endif // CORE_OMEMOHANDLER_H diff --git a/core/handlers/rosterhandler.cpp b/core/handlers/rosterhandler.cpp index 1a61440..8c65c63 100644 --- a/core/handlers/rosterhandler.cpp +++ b/core/handlers/rosterhandler.cpp @@ -26,14 +26,15 @@ Core::RosterHandler::RosterHandler(Core::Account* account): conferences(), groups(), queuedContacts(), - outOfRosterContacts() -{ + outOfRosterContacts() {} + +void Core::RosterHandler::initialize() { connect(acc->rm, &QXmppRosterManager::rosterReceived, this, &RosterHandler::onRosterReceived); connect(acc->rm, &QXmppRosterManager::itemAdded, this, &RosterHandler::onRosterItemAdded); connect(acc->rm, &QXmppRosterManager::itemRemoved, this, &RosterHandler::onRosterItemRemoved); connect(acc->rm, &QXmppRosterManager::itemChanged, this, &RosterHandler::onRosterItemChanged); - - + + connect(acc->mm, &QXmppMucManager::roomAdded, this, &RosterHandler::onMucRoomAdded); connect(acc->bm, &QXmppBookmarkManager::bookmarksReceived, this, &RosterHandler::bookmarksReceived); diff --git a/core/handlers/rosterhandler.h b/core/handlers/rosterhandler.h index 6a56b15..11525be 100644 --- a/core/handlers/rosterhandler.h +++ b/core/handlers/rosterhandler.h @@ -65,6 +65,8 @@ public: void storeConferences(); void clearConferences(); + + void initialize(); private slots: void onRosterReceived(); diff --git a/core/handlers/trusthandler.cpp b/core/handlers/trusthandler.cpp new file mode 100644 index 0000000..2c0be29 --- /dev/null +++ b/core/handlers/trusthandler.cpp @@ -0,0 +1,390 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "trusthandler.h" +#include "core/account.h" + +using namespace Core; + +Core::TrustHandler::TrustHandler(Account* account): + acc(account), + db(acc->getName() + "/trust"), + protocols(db.createDirectory() + "/protocols"), + securityPolicies(db.addCache("securityPolicies")), + ownKeys(db.addCache("ownKeys")), + keysByProtocol() +{ + if (!protocols.open(QIODevice::ReadWrite | QIODevice::Text)) { //never supposed to happen since I have just created a directory; + throw DataBase::Directory(protocols.fileName().toStdString()); + } + + QTextStream in(&protocols); + while(!in.atEnd()) { + QString protocol = in.readLine(); + + if (protocol.size() > 1) { //I'm afraid of reading some nonsence like separately standing \n or EF or BOM, so... let it be at least 2 chars long + KeyCache* cache = db.addCache(protocol.toStdString()); + keysByProtocol.insert(std::make_pair(protocol, cache)); + } + } + + protocols.close(); + db.open(); +} + +Core::TrustHandler::~TrustHandler() { + protocols.close(); + db.close(); +} + +Core::TrustHandler::KeyCache * Core::TrustHandler::getCache(const QString& encryption) { + std::map::iterator itr = keysByProtocol.find(encryption); + if (itr == keysByProtocol.end()) { + return createNewCache(encryption); + } else { + return itr->second; + } +} + +Core::TrustHandler::KeyCache * Core::TrustHandler::createNewCache(const QString& encryption) { + db.close(); + KeyCache* cache = db.addCache(encryption.toStdString()); + keysByProtocol.insert(std::make_pair(encryption, cache)); + + if(!protocols.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { + throw DataBase::Directory(protocols.fileName().toStdString()); + } + QTextStream out(&protocols); + out << encryption + "\n"; + protocols.close(); + + db.open(); + return cache; +} + + +QFuture Core::TrustHandler::emptyVoidFuture() { + QFutureInterface result(QFutureInterfaceBase::Started); + result.reportFinished(); + return result.future(); +} + + +QFuture Core::TrustHandler::resetAll(const QString& encryption) { + securityPolicies->removeRecord(encryption); + ownKeys->removeRecord(encryption); + getCache(encryption)->drop(); + + return emptyVoidFuture(); +} + +QFuture Core::TrustHandler::trustLevel( + const QString& encryption, + const QString& keyOwnerJid, + const QByteArray& keyId) +{ + Keys map = getCache(encryption)->getRecord(keyOwnerJid); + Shared::TrustLevel level = map.at(keyId); + + QFutureInterface result(QFutureInterfaceBase::Started); + result.reportResult(convert(level)); + result.reportFinished(); + return result.future(); +} + +QFuture>> Core::TrustHandler::setTrustLevel( + const QString& encryption, + const QList& keyOwnerJids, + QXmpp::TrustLevel oldTrustLevel, + QXmpp::TrustLevel newTrustLevel) +{ + QHash> modifiedKeys; + Shared::TrustLevel oldLevel = convert(oldTrustLevel); + Shared::TrustLevel newLevel = convert(newTrustLevel); + KeyCache* cache = getCache(encryption); + for (const QString& keyOwnerJid : keyOwnerJids) { + Keys map = cache->getRecord(keyOwnerJid); + uint count = 0; + for (std::pair& pair : map) { + Shared::TrustLevel& current = pair.second; + if (current == oldLevel) { + current = newLevel; + modifiedKeys[encryption].insert(keyOwnerJid, pair.first); + ++count; + } + } + if (count > 0) { + cache->changeRecord(keyOwnerJid, map); + } + } + + QFutureInterface>> result(QFutureInterfaceBase::Started); + result.reportResult(modifiedKeys); + result.reportFinished(); + return result.future(); +} + +QFuture>> Core::TrustHandler::setTrustLevel( + const QString& encryption, + const QMultiHash& keyIds, + QXmpp::TrustLevel trustLevel) +{ + QHash> modifiedKeys; + Shared::TrustLevel level = convert(trustLevel); + KeyCache* cache = getCache(encryption); + + for (MultySB::const_iterator itr = keyIds.begin(), end = keyIds.end(); itr != end; ++itr) { + const QString& keyOwnerJid = itr.key(); + const QByteArray& keyId = itr.value(); + Keys map = cache->getRecord(keyOwnerJid); + std::pair result = map.insert(std::make_pair(keyId, level)); + if (result.second) { + modifiedKeys[encryption].insert(keyOwnerJid, keyId); + cache->changeRecord(keyOwnerJid, map); + } else if (result.first->second != level) { + result.first->second = level; + modifiedKeys[encryption].insert(keyOwnerJid, keyId); + cache->changeRecord(keyOwnerJid, map); + } + } + + QFutureInterface>> result(QFutureInterfaceBase::Started); + result.reportResult(modifiedKeys); + result.reportFinished(); + return result.future(); +} + +QFuture TrustHandler::hasKey(const QString& encryption, + const QString& keyOwnerJid, + QXmpp::TrustLevels trustLevels) +{ + KeyCache* cache = getCache(encryption); + bool found = false; + try { + Keys map = cache->getRecord(keyOwnerJid); + for (const std::pair& pair : map) { + if (trustLevels.testFlag(convert(pair.second))) { + found = true; + break; + } + } + } catch (const DataBase::NotFound& e) {} + + QFutureInterface result(QFutureInterfaceBase::Started); + result.reportResult(found); + result.reportFinished(); + return result.future(); +} + +QFuture>> TrustHandler::keys( + const QString& encryption, + const QList& keyOwnerJids, + QXmpp::TrustLevels trustLevels) +{ + HSHBTL res; + + KeyCache* cache = getCache(encryption); + for (const QString& keyOwnerJid : keyOwnerJids) { + try { + Keys map = cache->getRecord(keyOwnerJid); + QHash& pRes = res[keyOwnerJid]; + for (const std::pair& pair : map) { + QXmpp::TrustLevel level = convert(pair.second); + if (!trustLevels || trustLevels.testFlag(level)) { + pRes.insert(pair.first, level); + } + } + } catch (const DataBase::NotFound& e) {} + } + + QFutureInterface result(QFutureInterfaceBase::Started); + result.reportResult(res); + result.reportFinished(); + return result.future(); +} + +QFuture>> TrustHandler::keys( + const QString& encryption, + QXmpp::TrustLevels trustLevels) +{ + QHash res; + KeyCache* cache = getCache(encryption); + std::map storage = cache->readAll(); + for (const std::pair& value : storage) { + for (const std::pair& pair : value.second) { + QXmpp::TrustLevel level = convert(pair.second); + if (!trustLevels || trustLevels.testFlag(level)) { + res[level].insert(value.first, pair.first); + } + } + } + + QFutureInterface> result(QFutureInterfaceBase::Started); + result.reportResult(res); + result.reportFinished(); + return result.future(); +} + +QFuture TrustHandler::removeKeys(const QString& encryption) { + getCache(encryption)->drop(); + return emptyVoidFuture(); +} + +QFuture TrustHandler::removeKeys(const QString& encryption, const QString& keyOwnerJid) { + getCache(encryption)->removeRecord(keyOwnerJid); + return emptyVoidFuture(); +} + +QFuture TrustHandler::removeKeys(const QString& encryption, const QList& keyIds) { + std::set set; + for (const QByteArray& keyId : keyIds) { + set.insert(keyId); + } + + KeyCache* cache = getCache(encryption); + std::map data = cache->readAll(); + bool changed = false; + for (std::map::iterator cItr = data.begin(), cEnd = data.end(); cItr != cEnd; /*no increment*/) { + Keys& byOwner = cItr->second; + for (Keys::const_iterator itr = byOwner.begin(), end = byOwner.end(); itr != end; /*no increment*/) { + const QByteArray& keyId = itr->first; + if (set.erase(keyId)) { + byOwner.erase(itr++); + changed = true; + } else { + ++itr; + } + } + if (byOwner.size() > 0) { + data.erase(cItr++); + } else { + ++cItr; + } + } + if (changed) { + cache->replaceAll(data); + } + + return emptyVoidFuture(); +} + +QFuture TrustHandler::addKeys( + const QString& encryption, + const QString& keyOwnerJid, + const QList& keyIds, + QXmpp::TrustLevel trustLevel) +{ + KeyCache* cache = getCache(encryption); + Shared::TrustLevel level = convert(trustLevel); + Keys data; + bool had = false; + try { + data = cache->getRecord(keyOwnerJid); + had = true; + } catch (const DataBase::NotFound& e) {} + for (const QByteArray& keyId : keyIds) { + std::pair result = data.insert(std::make_pair(keyId, level)); + if (!result.second) { + result.first->second = level; + } + } + + if (had) { + cache->changeRecord(keyOwnerJid, data); + } else { + cache->addRecord(keyOwnerJid, data); + } + + return emptyVoidFuture(); +} + +QFuture TrustHandler::ownKey(const QString& encryption) { + QByteArray res; + try { + res = ownKeys->getRecord(encryption); + } catch (const DataBase::NotFound& e) {} + + QFutureInterface result(QFutureInterfaceBase::Started); + result.reportResult(res); + result.reportFinished(); + return result.future(); +} + +QFuture TrustHandler::resetOwnKey(const QString& encryption) { + try { + ownKeys->removeRecord(encryption); + } catch (const DataBase::NotFound& e) {} + + return emptyVoidFuture(); +} + +QFuture TrustHandler::setOwnKey(const QString& encryption, const QByteArray& keyId) { + ownKeys->forceRecord(encryption, keyId); + return emptyVoidFuture(); +} + +QFuture TrustHandler::securityPolicy(const QString& encryption) { + QXmpp::TrustSecurityPolicy res; + try { + res = static_cast(securityPolicies->getRecord(encryption)); + } catch (const DataBase::NotFound& e) {} + + QFutureInterface result(QFutureInterfaceBase::Started); + result.reportResult(res); + result.reportFinished(); + return result.future(); +} + +QFuture TrustHandler::resetSecurityPolicy(const QString& encryption) { + try { + securityPolicies->removeRecord(encryption); + } catch (const DataBase::NotFound& e) {} + return emptyVoidFuture(); +} + +QFuture TrustHandler::setSecurityPolicy( + const QString& encryption, + QXmpp::TrustSecurityPolicy securityPolicy) +{ + uint8_t pol = securityPolicy; + securityPolicies->forceRecord(encryption, pol); + + return emptyVoidFuture(); +} + +Shared::TrustLevel Core::TrustHandler::convert(Core::TrustHandler::TL level) +{ + switch (level) { + case QXmpp::TrustLevel::Undecided: return Shared::TrustLevel::Undecided; + case QXmpp::TrustLevel::AutomaticallyDistrusted: return Shared::TrustLevel::AutomaticallyDistrusted; + case QXmpp::TrustLevel::ManuallyDistrusted: return Shared::TrustLevel::ManuallyDistrusted; + case QXmpp::TrustLevel::AutomaticallyTrusted: return Shared::TrustLevel::AutomaticallyTrusted; + case QXmpp::TrustLevel::ManuallyTrusted: return Shared::TrustLevel::ManuallyTrusted; + case QXmpp::TrustLevel::Authenticated: return Shared::TrustLevel::Authenticated; + } +} + +Core::TrustHandler::TL Core::TrustHandler::convert(Shared::TrustLevel level) +{ + switch (level) { + case Shared::TrustLevel::Undecided: return QXmpp::TrustLevel::Undecided; + case Shared::TrustLevel::AutomaticallyDistrusted: return QXmpp::TrustLevel::AutomaticallyDistrusted; + case Shared::TrustLevel::ManuallyDistrusted: return QXmpp::TrustLevel::ManuallyDistrusted; + case Shared::TrustLevel::AutomaticallyTrusted: return QXmpp::TrustLevel::AutomaticallyTrusted; + case Shared::TrustLevel::ManuallyTrusted: return QXmpp::TrustLevel::ManuallyTrusted; + case Shared::TrustLevel::Authenticated: return QXmpp::TrustLevel::Authenticated; + } +} diff --git a/core/handlers/trusthandler.h b/core/handlers/trusthandler.h new file mode 100644 index 0000000..b1fe0b4 --- /dev/null +++ b/core/handlers/trusthandler.h @@ -0,0 +1,81 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef CORE_TRUSTHANDLER_H +#define CORE_TRUSTHANDLER_H + +#include + +#include +#include + +namespace Core { +class Account; + +class TrustHandler : public QXmppTrustStorage { +public: + TrustHandler(Account* account); + ~TrustHandler(); + + typedef QMultiHash MultySB; + typedef QHash HashSM; + typedef const QList& CLSR; + typedef const QList& CLBAR; + typedef const QString& CSR; + typedef QXmpp::TrustLevel TL; + typedef QHash> HSHBTL; + + typedef std::map Keys; + typedef DataBase::Cache KeyCache; + + virtual QFuture resetAll(CSR encryption); + virtual QFuture trustLevel(CSR encryption, CSR keyOwnerJid, const QByteArray& keyId); + virtual QFuture setTrustLevel(CSR encryption, CLSR keyOwnerJids, TL oldTrustLevel, TL newTrustLevel); + virtual QFuture setTrustLevel(CSR encryption, const MultySB& keyIds, TL trustLevel); + virtual QFuture hasKey(CSR encryption, CSR keyOwnerJid, QXmpp::TrustLevels trustLevels); + virtual QFuture keys(CSR encryption, CLSR keyOwnerJids, QXmpp::TrustLevels trustLevels); + virtual QFuture> keys(CSR encryption, QXmpp::TrustLevels trustLevels); + virtual QFuture removeKeys(CSR encryption); + virtual QFuture removeKeys(CSR encryption, CSR keyOwnerJid); + virtual QFuture removeKeys(CSR encryption, CLBAR keyIds); + virtual QFuture addKeys(CSR encryption, CSR keyOwnerJid, CLBAR keyIds, TL trustLevel); + virtual QFuture ownKey(CSR encryption); + virtual QFuture resetOwnKey(CSR encryption); + virtual QFuture setOwnKey(CSR encryption, const QByteArray& keyId); + virtual QFuture securityPolicy(CSR encryption); + virtual QFuture resetSecurityPolicy(CSR encryption); + virtual QFuture setSecurityPolicy(CSR encryption, QXmpp::TrustSecurityPolicy securityPolicy); + + static TL convert(Shared::TrustLevel level); + static Shared::TrustLevel convert(TL level); + +private: + static QFuture emptyVoidFuture(); + KeyCache* createNewCache(const QString& encryption); + KeyCache* getCache(const QString& encryption); + +private: + Account* acc; + DataBase db; + QFile protocols; + DataBase::Cache* securityPolicies; + DataBase::Cache* ownKeys; + std::map keysByProtocol; +}; + +} + +#endif // CORE_TRUSTHANDLER_H diff --git a/core/handlers/vcardhandler.cpp b/core/handlers/vcardhandler.cpp index 24cb6ee..bde0e64 100644 --- a/core/handlers/vcardhandler.cpp +++ b/core/handlers/vcardhandler.cpp @@ -25,10 +25,6 @@ Core::VCardHandler::VCardHandler(Account* account): avatarHash(), avatarType() { - connect(acc->vm, &QXmppVCardManager::vCardReceived, this, &VCardHandler::onVCardReceived); - //for some reason it doesn't work, launching from common handler - //connect(acc->vm, &QXmppVCardManager::clientVCardReceived, this, &VCardHandler::onOwnVCardReceived); - QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); path += "/" + acc->name; QDir dir(path); @@ -67,6 +63,15 @@ Core::VCardHandler::VCardHandler(Account* account): avatarType = type; } } +} + +Core::VCardHandler::~VCardHandler() {} + +void Core::VCardHandler::initialize() { + connect(acc->vm, &QXmppVCardManager::vCardReceived, this, &VCardHandler::onVCardReceived); + //for some reason it doesn't work, launching from common handler + //connect(acc->vm, &QXmppVCardManager::clientVCardReceived, this, &VCardHandler::onOwnVCardReceived); + if (avatarType.size() != 0) { acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto); acc->presence.setPhotoHash(avatarHash.toUtf8()); @@ -75,10 +80,6 @@ Core::VCardHandler::VCardHandler(Account* account): } } -Core::VCardHandler::~VCardHandler() -{ - -} void Core::VCardHandler::onVCardReceived(const QXmppVCardIq& card) { diff --git a/core/handlers/vcardhandler.h b/core/handlers/vcardhandler.h index ee61d0a..f774cd5 100644 --- a/core/handlers/vcardhandler.h +++ b/core/handlers/vcardhandler.h @@ -48,6 +48,8 @@ public: void uploadVCard(const Shared::VCard& card); QString getAvatarPath() const; + void initialize(); + private slots: void onVCardReceived(const QXmppVCardIq& card); void onOwnVCardReceived(const QXmppVCardIq& card); diff --git a/core/storage/CMakeLists.txt b/core/storage/CMakeLists.txt index 2da3c67..238b59a 100644 --- a/core/storage/CMakeLists.txt +++ b/core/storage/CMakeLists.txt @@ -1,10 +1,10 @@ target_sources(squawk PRIVATE archive.cpp archive.h - storage.hpp - storage.h +# storage.hpp +# storage.h urlstorage.cpp urlstorage.h - cache.hpp - cache.h +# cache.hpp +# cache.h ) diff --git a/external/qxmpp b/external/qxmpp index f6e7591..befab2f 160000 --- a/external/qxmpp +++ b/external/qxmpp @@ -1 +1 @@ -Subproject commit f6e7591e21b4c55319918ac296b2341b2e9f1988 +Subproject commit befab2fe2e71330170bba48f173258be724c65b9 diff --git a/external/storage b/external/storage index 08daad4..a79dae8 160000 --- a/external/storage +++ b/external/storage @@ -1 +1 @@ -Subproject commit 08daad48ad36d9f12dc6485a085190e31e4cf49e +Subproject commit a79dae8fd07b36446041f6f85e2ad42cf5ae5264 diff --git a/shared/enums.h b/shared/enums.h index 273a22d..a32b57e 100644 --- a/shared/enums.h +++ b/shared/enums.h @@ -124,5 +124,25 @@ enum class Support { }; Q_ENUM_NS(Support) +enum class TrustLevel { + /// The key's trust is not decided. + Undecided, + /// The key is automatically distrusted (e.g., by the security policy TOAKAFA). + /// \see SecurityPolicy + AutomaticallyDistrusted, + /// The key is manually distrusted (e.g., by clicking a button or \xep{0450, Automatic Trust + /// Management (ATM)}). + ManuallyDistrusted, + /// The key is automatically trusted (e.g., by the client for all keys of a bare JID until one + /// of it is authenticated). + AutomaticallyTrusted, + /// The key is manually trusted (e.g., by clicking a button). + ManuallyTrusted, + /// The key is authenticated (e.g., by QR code scanning or \xep{0450, Automatic Trust + /// Management (ATM)}). + Authenticated +}; +Q_ENUM_NS(TrustLevel) + } #endif // SHARED_ENUMS_H