work progress: trust manager. DOESN'T START!

This commit is contained in:
Blue 2022-12-19 18:43:24 +03:00
parent 0b61b6e928
commit db3bc358a7
Signed by: blue
GPG Key ID: 9B203B252A63EE38
20 changed files with 634 additions and 55 deletions

View File

@ -142,6 +142,7 @@ if (NOT SYSTEM_QXMPP)
add_subdirectory(external/qxmpp) add_subdirectory(external/qxmpp)
target_link_libraries(squawk PRIVATE qxmpp) target_link_libraries(squawk PRIVATE qxmpp)
target_link_libraries(squawk PRIVATE QXmppOmemo)
else () else ()
target_link_libraries(squawk PRIVATE QXmpp::QXmpp) target_link_libraries(squawk PRIVATE QXmpp::QXmpp)
endif () endif ()

View File

@ -31,6 +31,17 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
config(), config(),
presence(), presence(),
state(Shared::ConnectionState::disconnected), 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()), cm(new QXmppCarbonManager()),
am(new QXmppMamManager()), am(new QXmppMamManager()),
mm(new QXmppMucManager()), mm(new QXmppMucManager()),
@ -40,9 +51,6 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
um(new QXmppUploadRequestManager()), um(new QXmppUploadRequestManager()),
dm(client.findExtension<QXmppDiscoveryManager>()), dm(client.findExtension<QXmppDiscoveryManager>()),
rcpm(new QXmppMessageReceiptManager()), rcpm(new QXmppMessageReceiptManager()),
#ifdef WITH_OMEMO
om(new QXmppOmemoManager()),
#endif
reconnectScheduled(false), reconnectScheduled(false),
reconnectTimer(new QTimer), reconnectTimer(new QTimer),
network(p_net), network(p_net),
@ -50,11 +58,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
lastError(Error::none), lastError(Error::none),
pepSupport(Shared::Support::unknown), pepSupport(Shared::Support::unknown),
active(p_active), active(p_active),
notReadyPassword(false), notReadyPassword(false)
mh(new MessageHandler(this)),
rh(new RosterHandler(this)),
vh(new VCardHandler(this)),
dh(new DiscoveryHandler(this))
{ {
config.setUser(p_login); config.setUser(p_login);
config.setDomain(p_server); config.setDomain(p_server);
@ -62,6 +66,10 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
config.setAutoAcceptSubscriptions(true); config.setAutoAcceptSubscriptions(true);
//config.setAutoReconnectionEnabled(false); //config.setAutoReconnectionEnabled(false);
rh->initialize();
vh->initialize();
dh->initialize();
QObject::connect(&client, &QXmppClient::stateChanged, this, &Account::onClientStateChange); QObject::connect(&client, &QXmppClient::stateChanged, this, &Account::onClientStateChange);
QObject::connect(&client, &QXmppClient::presenceReceived, this, &Account::onPresenceReceived); QObject::connect(&client, &QXmppClient::presenceReceived, this, &Account::onPresenceReceived);
QObject::connect(&client, &QXmppClient::messageReceived, mh, &MessageHandler::onMessageReceived); QObject::connect(&client, &QXmppClient::messageReceived, mh, &MessageHandler::onMessageReceived);
@ -92,6 +100,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived); QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived);
#ifdef WITH_OMEMO #ifdef WITH_OMEMO
client.addExtension(tm);
client.addExtension(om); client.addExtension(om);
qDebug("Added OMEMO manager"); qDebug("Added OMEMO manager");
#endif #endif

View File

@ -42,9 +42,6 @@
#include <QXmppUploadRequestManager.h> #include <QXmppUploadRequestManager.h>
#include <QXmppVCardManager.h> #include <QXmppVCardManager.h>
#include <QXmppMessageReceiptManager.h> #include <QXmppMessageReceiptManager.h>
#ifdef WITH_OMEMO
#include <QXmppOmemoManager.h>
#endif
#include <shared/shared.h> #include <shared/shared.h>
#include <shared/identity.h> #include <shared/identity.h>
@ -57,6 +54,13 @@
#include "handlers/vcardhandler.h" #include "handlers/vcardhandler.h"
#include "handlers/discoveryhandler.h" #include "handlers/discoveryhandler.h"
#ifdef WITH_OMEMO
#include <QXmppOmemoManager.h>
#include <QXmppTrustManager.h>
#include "handlers/trusthandler.h"
#include "handlers/omemohandler.h"
#endif
namespace Core namespace Core
{ {
@ -170,6 +174,18 @@ private:
QXmppConfiguration config; QXmppConfiguration config;
QXmppPresence presence; QXmppPresence presence;
Shared::ConnectionState state; 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; QXmppCarbonManager* cm;
QXmppMamManager* am; QXmppMamManager* am;
QXmppMucManager* mm; QXmppMucManager* mm;
@ -179,9 +195,6 @@ private:
QXmppUploadRequestManager* um; QXmppUploadRequestManager* um;
QXmppDiscoveryManager* dm; QXmppDiscoveryManager* dm;
QXmppMessageReceiptManager* rcpm; QXmppMessageReceiptManager* rcpm;
#ifdef WITH_OMEMO
QXmppOmemoManager* om;
#endif
bool reconnectScheduled; bool reconnectScheduled;
QTimer* reconnectTimer; QTimer* reconnectTimer;
@ -192,11 +205,6 @@ private:
bool active; bool active;
bool notReadyPassword; bool notReadyPassword;
MessageHandler* mh;
RosterHandler* rh;
VCardHandler* vh;
DiscoveryHandler* dh;
private slots: private slots:
void onClientStateChange(QXmppClient::State state); void onClientStateChange(QXmppClient::State state);
void onClientError(QXmppClient::Error err); void onClientError(QXmppClient::Error err);

View File

@ -19,27 +19,28 @@
#include <QDebug> #include <QDebug>
Core::ClientCache::ClientCache(): Core::ClientCache::ClientCache():
db("clients"),
cache(db.addCache<QString, Shared::ClientInfo>("info")),
requested(), requested(),
cache("clients"),
specific() specific()
{ {
cache.open(); db.open();
} }
Core::ClientCache::~ClientCache() { Core::ClientCache::~ClientCache() {
cache.close(); db.close();
} }
void Core::ClientCache::open() { void Core::ClientCache::open() {
cache.open();} db.open();}
void Core::ClientCache::close() { void Core::ClientCache::close() {
cache.close();} db.close();}
bool Core::ClientCache::checkClient(const QString& node, const QString& ver, const QString& hash) { bool Core::ClientCache::checkClient(const QString& node, const QString& ver, const QString& hash) {
QString id = node + "/" + ver; 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; Shared::ClientInfo& info = requested.insert(std::make_pair(id, Shared::ClientInfo())).first->second;
info.node = node; info.node = node;
info.verification = ver; info.verification = ver;
@ -65,7 +66,7 @@ bool Core::ClientCache::registerClientInfo (
bool valid = info.valid(); bool valid = info.valid();
if (valid) { if (valid) {
cache.addRecord(id, info); cache->addRecord(id, info);
} else { } else {
info.specificPresence = sourceFullJid; info.specificPresence = sourceFullJid;
specific.insert(std::make_pair(sourceFullJid, info)); specific.insert(std::make_pair(sourceFullJid, info));

View File

@ -23,7 +23,8 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <core/storage/cache.h> #include <cache.h>
#include <shared/clientinfo.h> #include <shared/clientinfo.h>
#include <shared/identity.h> #include <shared/identity.h>
@ -46,8 +47,9 @@ public slots:
bool registerClientInfo(const QString& sourceFullJid, const QString& id, const std::set<Shared::Identity>& identities, const std::set<QString>& features); bool registerClientInfo(const QString& sourceFullJid, const QString& id, const std::set<Shared::Identity>& identities, const std::set<QString>& features);
private: private:
DataBase db;
DataBase::Cache<QString, Shared::ClientInfo>* cache;
std::map<QString, Shared::ClientInfo> requested; std::map<QString, Shared::ClientInfo> requested;
Cache<QString, Shared::ClientInfo> cache;
std::map<QString, Shared::ClientInfo> specific; std::map<QString, Shared::ClientInfo> specific;
}; };

View File

@ -9,4 +9,6 @@ target_sources(squawk PRIVATE
discoveryhandler.h discoveryhandler.h
omemohandler.cpp omemohandler.cpp
omemohandler.h omemohandler.h
trusthandler.cpp
trusthandler.h
) )

View File

@ -21,7 +21,11 @@
Core::DiscoveryHandler::DiscoveryHandler(Core::Account* account): Core::DiscoveryHandler::DiscoveryHandler(Core::Account* account):
QObject(), 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::itemsReceived, this, &DiscoveryHandler::onItemsReceived);
QObject::connect(acc->dm, &QXmppDiscoveryManager::infoReceived, this, &DiscoveryHandler::onInfoReceived); 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"); acc->dm->setClientCapabilitiesNode("https://git.macaw.me/blue/squawk");
} }
Core::DiscoveryHandler::~DiscoveryHandler()
{
}
void Core::DiscoveryHandler::onItemsReceived(const QXmppDiscoveryIq& items) void Core::DiscoveryHandler::onItemsReceived(const QXmppDiscoveryIq& items)
{ {
QString server = acc->getServer(); QString server = acc->getServer();

View File

@ -32,6 +32,8 @@ public:
DiscoveryHandler(Account* account); DiscoveryHandler(Account* account);
~DiscoveryHandler(); ~DiscoveryHandler();
void initialize();
private slots: private slots:
void onItemsReceived (const QXmppDiscoveryIq& items); void onItemsReceived (const QXmppDiscoveryIq& items);
void onInfoReceived (const QXmppDiscoveryIq& info); void onInfoReceived (const QXmppDiscoveryIq& info);

View File

@ -22,7 +22,7 @@ Core::OmemoHandler::OmemoHandler(Account* account) :
QXmppOmemoStorage(), QXmppOmemoStorage(),
acc(account), acc(account),
ownDevice(std::nullopt), ownDevice(std::nullopt),
db("omemo"), db(acc->getName() + "/omemo"),
meta(db.addCache<QString, QVariant>("meta")), meta(db.addCache<QString, QVariant>("meta")),
devices(db.addCache<QString, QHash<uint32_t, Device>>("devices")), devices(db.addCache<QString, QHash<uint32_t, Device>>("devices")),
preKeyPairs(db.addCache<uint32_t, QByteArray>("preKeyPairs")), preKeyPairs(db.addCache<uint32_t, QByteArray>("preKeyPairs")),
@ -155,7 +155,60 @@ QFuture<void> Core::OmemoHandler::resetAll() {
return emptyVoidFuture(); 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;
}

View File

@ -21,6 +21,8 @@
#include <cache.h> #include <cache.h>
Q_DECLARE_METATYPE(QXmppOmemoStorage::OwnDevice); Q_DECLARE_METATYPE(QXmppOmemoStorage::OwnDevice);
Q_DECLARE_METATYPE(QXmppOmemoStorage::Device);
Q_DECLARE_METATYPE(QXmppOmemoStorage::SignedPreKeyPair);
namespace Core { namespace Core {
class Account; class Account;
@ -63,9 +65,12 @@ private:
} }
QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::Device& device); 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, const QXmppOmemoStorage::SignedPreKeyPair& device);
QDataStream& operator >> (QDataStream &out, QXmppOmemoStorage::SignedPreKeyPair device); QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::SignedPreKeyPair& device);
#endif // CORE_OMEMOHANDLER_H #endif // CORE_OMEMOHANDLER_H

View File

@ -26,8 +26,9 @@ Core::RosterHandler::RosterHandler(Core::Account* account):
conferences(), conferences(),
groups(), groups(),
queuedContacts(), queuedContacts(),
outOfRosterContacts() outOfRosterContacts() {}
{
void Core::RosterHandler::initialize() {
connect(acc->rm, &QXmppRosterManager::rosterReceived, this, &RosterHandler::onRosterReceived); connect(acc->rm, &QXmppRosterManager::rosterReceived, this, &RosterHandler::onRosterReceived);
connect(acc->rm, &QXmppRosterManager::itemAdded, this, &RosterHandler::onRosterItemAdded); connect(acc->rm, &QXmppRosterManager::itemAdded, this, &RosterHandler::onRosterItemAdded);
connect(acc->rm, &QXmppRosterManager::itemRemoved, this, &RosterHandler::onRosterItemRemoved); connect(acc->rm, &QXmppRosterManager::itemRemoved, this, &RosterHandler::onRosterItemRemoved);

View File

@ -66,6 +66,8 @@ public:
void storeConferences(); void storeConferences();
void clearConferences(); void clearConferences();
void initialize();
private slots: private slots:
void onRosterReceived(); void onRosterReceived();
void onRosterItemAdded(const QString& bareJid); void onRosterItemAdded(const QString& bareJid);

View File

@ -0,0 +1,390 @@
// Squawk messenger.
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
//
// 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 <http://www.gnu.org/licenses/>.
#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<QString, uint8_t>("securityPolicies")),
ownKeys(db.addCache<QString, QByteArray>("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<QString, Keys>(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<QString, KeyCache*>::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<QString, Keys>(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<void> Core::TrustHandler::emptyVoidFuture() {
QFutureInterface<QXmppOmemoStorage::OmemoData> result(QFutureInterfaceBase::Started);
result.reportFinished();
return result.future();
}
QFuture<void> Core::TrustHandler::resetAll(const QString& encryption) {
securityPolicies->removeRecord(encryption);
ownKeys->removeRecord(encryption);
getCache(encryption)->drop();
return emptyVoidFuture();
}
QFuture<QXmpp::TrustLevel> 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<QXmpp::TrustLevel> result(QFutureInterfaceBase::Started);
result.reportResult(convert(level));
result.reportFinished();
return result.future();
}
QFuture<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::setTrustLevel(
const QString& encryption,
const QList<QString>& keyOwnerJids,
QXmpp::TrustLevel oldTrustLevel,
QXmpp::TrustLevel newTrustLevel)
{
QHash<QString, QMultiHash<QString, QByteArray>> 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<const QByteArray, Shared::TrustLevel>& 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<QHash<QString, QMultiHash<QString, QByteArray>>> result(QFutureInterfaceBase::Started);
result.reportResult(modifiedKeys);
result.reportFinished();
return result.future();
}
QFuture<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::setTrustLevel(
const QString& encryption,
const QMultiHash<QString, QByteArray>& keyIds,
QXmpp::TrustLevel trustLevel)
{
QHash<QString, QMultiHash<QString, QByteArray>> 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<Keys::iterator, bool> 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<QHash<QString, QMultiHash<QString, QByteArray>>> result(QFutureInterfaceBase::Started);
result.reportResult(modifiedKeys);
result.reportFinished();
return result.future();
}
QFuture<bool> 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<const QByteArray, Shared::TrustLevel>& pair : map) {
if (trustLevels.testFlag(convert(pair.second))) {
found = true;
break;
}
}
} catch (const DataBase::NotFound& e) {}
QFutureInterface<bool> result(QFutureInterfaceBase::Started);
result.reportResult(found);
result.reportFinished();
return result.future();
}
QFuture<QHash<QString, QHash<QByteArray, QXmpp::TrustLevel>>> TrustHandler::keys(
const QString& encryption,
const QList<QString>& keyOwnerJids,
QXmpp::TrustLevels trustLevels)
{
HSHBTL res;
KeyCache* cache = getCache(encryption);
for (const QString& keyOwnerJid : keyOwnerJids) {
try {
Keys map = cache->getRecord(keyOwnerJid);
QHash<QByteArray, QXmpp::TrustLevel>& pRes = res[keyOwnerJid];
for (const std::pair<const QByteArray, Shared::TrustLevel>& pair : map) {
QXmpp::TrustLevel level = convert(pair.second);
if (!trustLevels || trustLevels.testFlag(level)) {
pRes.insert(pair.first, level);
}
}
} catch (const DataBase::NotFound& e) {}
}
QFutureInterface<HSHBTL> result(QFutureInterfaceBase::Started);
result.reportResult(res);
result.reportFinished();
return result.future();
}
QFuture<QHash<QXmpp::TrustLevel, QMultiHash<QString, QByteArray>>> TrustHandler::keys(
const QString& encryption,
QXmpp::TrustLevels trustLevels)
{
QHash<TL, MultySB> res;
KeyCache* cache = getCache(encryption);
std::map<QString, Keys> storage = cache->readAll();
for (const std::pair<const QString, Keys>& value : storage) {
for (const std::pair<const QByteArray, Shared::TrustLevel>& pair : value.second) {
QXmpp::TrustLevel level = convert(pair.second);
if (!trustLevels || trustLevels.testFlag(level)) {
res[level].insert(value.first, pair.first);
}
}
}
QFutureInterface<QHash<TL, MultySB>> result(QFutureInterfaceBase::Started);
result.reportResult(res);
result.reportFinished();
return result.future();
}
QFuture<void> TrustHandler::removeKeys(const QString& encryption) {
getCache(encryption)->drop();
return emptyVoidFuture();
}
QFuture<void> TrustHandler::removeKeys(const QString& encryption, const QString& keyOwnerJid) {
getCache(encryption)->removeRecord(keyOwnerJid);
return emptyVoidFuture();
}
QFuture<void> TrustHandler::removeKeys(const QString& encryption, const QList<QByteArray>& keyIds) {
std::set<QByteArray> set;
for (const QByteArray& keyId : keyIds) {
set.insert(keyId);
}
KeyCache* cache = getCache(encryption);
std::map<QString, Keys> data = cache->readAll();
bool changed = false;
for (std::map<QString, Keys>::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<void> TrustHandler::addKeys(
const QString& encryption,
const QString& keyOwnerJid,
const QList<QByteArray>& 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<Keys::iterator, bool> 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<QByteArray> TrustHandler::ownKey(const QString& encryption) {
QByteArray res;
try {
res = ownKeys->getRecord(encryption);
} catch (const DataBase::NotFound& e) {}
QFutureInterface<QByteArray> result(QFutureInterfaceBase::Started);
result.reportResult(res);
result.reportFinished();
return result.future();
}
QFuture<void> TrustHandler::resetOwnKey(const QString& encryption) {
try {
ownKeys->removeRecord(encryption);
} catch (const DataBase::NotFound& e) {}
return emptyVoidFuture();
}
QFuture<void> TrustHandler::setOwnKey(const QString& encryption, const QByteArray& keyId) {
ownKeys->forceRecord(encryption, keyId);
return emptyVoidFuture();
}
QFuture<QXmpp::TrustSecurityPolicy> TrustHandler::securityPolicy(const QString& encryption) {
QXmpp::TrustSecurityPolicy res;
try {
res = static_cast<QXmpp::TrustSecurityPolicy>(securityPolicies->getRecord(encryption));
} catch (const DataBase::NotFound& e) {}
QFutureInterface<QXmpp::TrustSecurityPolicy> result(QFutureInterfaceBase::Started);
result.reportResult(res);
result.reportFinished();
return result.future();
}
QFuture<void> TrustHandler::resetSecurityPolicy(const QString& encryption) {
try {
securityPolicies->removeRecord(encryption);
} catch (const DataBase::NotFound& e) {}
return emptyVoidFuture();
}
QFuture<void> 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;
}
}

View File

@ -0,0 +1,81 @@
// Squawk messenger.
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
//
// 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 <http://www.gnu.org/licenses/>.
#ifndef CORE_TRUSTHANDLER_H
#define CORE_TRUSTHANDLER_H
#include <shared/enums.h>
#include <QXmppTrustStorage.h>
#include <cache.h>
namespace Core {
class Account;
class TrustHandler : public QXmppTrustStorage {
public:
TrustHandler(Account* account);
~TrustHandler();
typedef QMultiHash<QString, QByteArray> MultySB;
typedef QHash<QString, MultySB> HashSM;
typedef const QList<QString>& CLSR;
typedef const QList<QByteArray>& CLBAR;
typedef const QString& CSR;
typedef QXmpp::TrustLevel TL;
typedef QHash<QString, QHash<QByteArray, TL>> HSHBTL;
typedef std::map<QByteArray, Shared::TrustLevel> Keys;
typedef DataBase::Cache<QString, Keys> KeyCache;
virtual QFuture<void> resetAll(CSR encryption);
virtual QFuture<TL> trustLevel(CSR encryption, CSR keyOwnerJid, const QByteArray& keyId);
virtual QFuture<HashSM> setTrustLevel(CSR encryption, CLSR keyOwnerJids, TL oldTrustLevel, TL newTrustLevel);
virtual QFuture<HashSM> setTrustLevel(CSR encryption, const MultySB& keyIds, TL trustLevel);
virtual QFuture<bool> hasKey(CSR encryption, CSR keyOwnerJid, QXmpp::TrustLevels trustLevels);
virtual QFuture<HSHBTL> keys(CSR encryption, CLSR keyOwnerJids, QXmpp::TrustLevels trustLevels);
virtual QFuture<QHash<TL, MultySB>> keys(CSR encryption, QXmpp::TrustLevels trustLevels);
virtual QFuture<void> removeKeys(CSR encryption);
virtual QFuture<void> removeKeys(CSR encryption, CSR keyOwnerJid);
virtual QFuture<void> removeKeys(CSR encryption, CLBAR keyIds);
virtual QFuture<void> addKeys(CSR encryption, CSR keyOwnerJid, CLBAR keyIds, TL trustLevel);
virtual QFuture<QByteArray> ownKey(CSR encryption);
virtual QFuture<void> resetOwnKey(CSR encryption);
virtual QFuture<void> setOwnKey(CSR encryption, const QByteArray& keyId);
virtual QFuture<QXmpp::TrustSecurityPolicy> securityPolicy(CSR encryption);
virtual QFuture<void> resetSecurityPolicy(CSR encryption);
virtual QFuture<void> setSecurityPolicy(CSR encryption, QXmpp::TrustSecurityPolicy securityPolicy);
static TL convert(Shared::TrustLevel level);
static Shared::TrustLevel convert(TL level);
private:
static QFuture<void> emptyVoidFuture();
KeyCache* createNewCache(const QString& encryption);
KeyCache* getCache(const QString& encryption);
private:
Account* acc;
DataBase db;
QFile protocols;
DataBase::Cache<QString, uint8_t>* securityPolicies;
DataBase::Cache<QString, QByteArray>* ownKeys;
std::map<QString, KeyCache*> keysByProtocol;
};
}
#endif // CORE_TRUSTHANDLER_H

View File

@ -25,10 +25,6 @@ Core::VCardHandler::VCardHandler(Account* account):
avatarHash(), avatarHash(),
avatarType() 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)); QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
path += "/" + acc->name; path += "/" + acc->name;
QDir dir(path); QDir dir(path);
@ -67,6 +63,15 @@ Core::VCardHandler::VCardHandler(Account* account):
avatarType = type; 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) { if (avatarType.size() != 0) {
acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto); acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto);
acc->presence.setPhotoHash(avatarHash.toUtf8()); acc->presence.setPhotoHash(avatarHash.toUtf8());
@ -75,10 +80,6 @@ Core::VCardHandler::VCardHandler(Account* account):
} }
} }
Core::VCardHandler::~VCardHandler()
{
}
void Core::VCardHandler::onVCardReceived(const QXmppVCardIq& card) void Core::VCardHandler::onVCardReceived(const QXmppVCardIq& card)
{ {

View File

@ -48,6 +48,8 @@ public:
void uploadVCard(const Shared::VCard& card); void uploadVCard(const Shared::VCard& card);
QString getAvatarPath() const; QString getAvatarPath() const;
void initialize();
private slots: private slots:
void onVCardReceived(const QXmppVCardIq& card); void onVCardReceived(const QXmppVCardIq& card);
void onOwnVCardReceived(const QXmppVCardIq& card); void onOwnVCardReceived(const QXmppVCardIq& card);

View File

@ -1,10 +1,10 @@
target_sources(squawk PRIVATE target_sources(squawk PRIVATE
archive.cpp archive.cpp
archive.h archive.h
storage.hpp # storage.hpp
storage.h # storage.h
urlstorage.cpp urlstorage.cpp
urlstorage.h urlstorage.h
cache.hpp # cache.hpp
cache.h # cache.h
) )

2
external/qxmpp vendored

@ -1 +1 @@
Subproject commit f6e7591e21b4c55319918ac296b2341b2e9f1988 Subproject commit befab2fe2e71330170bba48f173258be724c65b9

2
external/storage vendored

@ -1 +1 @@
Subproject commit 08daad48ad36d9f12dc6485a085190e31e4cf49e Subproject commit a79dae8fd07b36446041f6f85e2ad42cf5ae5264

View File

@ -124,5 +124,25 @@ enum class Support {
}; };
Q_ENUM_NS(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 #endif // SHARED_ENUMS_H