// 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; } }