From 5bbe04c9ca091a0626f34afe5e3ba2141e2963de Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Mon, 28 Aug 2023 00:20:54 +0200 Subject: WIP OMEMO TrustDb/JidDb --- trust_db.cpp | 376 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 272 insertions(+), 104 deletions(-) (limited to 'trust_db.cpp') diff --git a/trust_db.cpp b/trust_db.cpp index 138c028..0d8073b 100644 --- a/trust_db.cpp +++ b/trust_db.cpp @@ -1,8 +1,9 @@ #include "trust_db.h" +#include +#include #include #include #include -#include #include #include #include @@ -13,16 +14,44 @@ TrustDb::TrustDb(const QString &jid, const JidDb &db) : { } +static const struct +{ + QXmpp::TrustLevel level; + const char *str; +} trustlevels[] = +{ + {QXmpp::TrustLevel::Undecided, "Undecided"}, + {QXmpp::TrustLevel::AutomaticallyDistrusted, "AutomaticallyDistrusted"}, + {QXmpp::TrustLevel::ManuallyDistrusted, "ManuallyDistrusted"}, + {QXmpp::TrustLevel::AutomaticallyTrusted, "AutomaticallyTrusted"}, + {QXmpp::TrustLevel::ManuallyTrusted, "ManuallyTrusted"}, + {QXmpp::TrustLevel::Authenticated, "Authenticated"} +}; + +static const struct +{ + QXmpp::TrustSecurityPolicy policy; + const char *str; +} tsp_levels[] = +{ + {QXmpp::NoSecurityPolicy, "NoSecurityPolicy"}, + {QXmpp::Toakafa, "Toakafa"} +}; + static QString toString(const QXmpp::TrustSecurityPolicy securityPolicy) { - switch (securityPolicy) - { - case QXmpp::NoSecurityPolicy: - return "NoSecurityPolicy"; + for (const auto &t : tsp_levels) + if (t.policy == securityPolicy) + return t.str; - case QXmpp::Toakafa: - return "Toakafa"; - } + return "unknown"; +} + +static QString toString(const QXmpp::TrustLevel &trustLevel) +{ + for (const auto &t : trustlevels) + if (t.level == trustLevel) + return t.str; return "unknown"; } @@ -30,16 +59,24 @@ static QString toString(const QXmpp::TrustSecurityPolicy securityPolicy) static int toSecurityPolicy(const QString &s, QXmpp::TrustSecurityPolicy &securityPolicy) { - if (s == "NoSecurityPolicy") - { - securityPolicy = QXmpp::NoSecurityPolicy; - return 0; - } - else if (s == "Toakafa") - { - securityPolicy = QXmpp::Toakafa; - return 0; - } + for (const auto &t : tsp_levels) + if (t.str == s) + { + securityPolicy = t.policy; + return 0; + } + + return -1; +} + +static int toTrustLevel(const QString &tstr, QXmpp::TrustLevel &trustLevel) +{ + for (const auto &t : trustlevels) + if (t.str == tstr) + { + trustLevel = t.level; + return 0; + } return -1; } @@ -52,35 +89,18 @@ QString TrustDb::service() const QXmppTask TrustDb::setSecurityPolicy(const QString &encryption, const QXmpp::TrustSecurityPolicy securityPolicy) { - QKeychain::WritePasswordJob job(service()); - QEventLoop loop; - - job.setKey("securityPolicy/" + encryption); - job.setTextData(toString(securityPolicy)); - job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); - job.start(); - loop.exec(); - - if (job.error()) - std::cerr << "Failed to store security policy: " - << qPrintable(job.errorString()) << std::endl; + if (db.store(encryption, toString(securityPolicy))) + std::cerr << "TrustDb::setSecurityPolicy: store failed" + << std::endl; return QXmpp::Private::makeReadyTask(); } QXmppTask TrustDb::resetSecurityPolicy(const QString &encryption) { - QKeychain::DeletePasswordJob job(service()); - QEventLoop loop; - - job.setKey("securityPolicy/" + encryption); - job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); - job.start(); - loop.exec(); - - if (job.error()) - std::cerr << "Failed to reset security policy: " - << qPrintable(job.errorString()) << std::endl; + if (db.store(encryption, QString())) + std::cerr << "TrustDb::resetSecurityPolicy: store failed" + << std::endl; return QXmpp::Private::makeReadyTask(); } @@ -88,23 +108,11 @@ QXmppTask TrustDb::resetSecurityPolicy(const QString &encryption) QXmppTask TrustDb::securityPolicy( const QString &encryption) { - QKeychain::ReadPasswordJob job(service()); - QEventLoop loop; - - job.setKey("securityPolicy/" + encryption); - job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); - job.start(); - loop.exec(); + const auto s = db.securityPolicy(encryption); + QXmpp::TrustSecurityPolicy policy; - if (job.error()) - std::cerr << "Failed to read security policy: " - << qPrintable(job.errorString()) << std::endl; - - QXmpp::TrustSecurityPolicy policy = QXmpp::Toakafa; - const QString data = job.textData(); - - if (toSecurityPolicy(data, policy)) - std::cerr << "Invalid security policy " << qPrintable(data) + if (toSecurityPolicy(s, policy)) + std::cerr << "TrustDb::securityPolicy: toSecurityPolicy failed" << std::endl; return QXmpp::Private::makeReadyTask(QXmpp::TrustSecurityPolicy(policy)); @@ -113,81 +121,80 @@ QXmppTask TrustDb::securityPolicy( QXmppTask TrustDb::setOwnKey(const QString &encryption, const QByteArray &keyId) { - QKeychain::WritePasswordJob job(service()); - QEventLoop loop; - - job.setKey("key/" + encryption); - job.setBinaryData(keyId); - job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); - job.start(); - loop.exec(); - - if (job.error()) - std::cerr << "Failed to store own key: " - << qPrintable(job.errorString()) << std::endl; + if (db.store(encryption, keyId)) + std::cerr << "TrustDb::setOwnKey: db.store failed" << std::endl; return QXmpp::Private::makeReadyTask(); } QXmppTask TrustDb::resetOwnKey(const QString &encryption) { - QKeychain::DeletePasswordJob job(service()); - QEventLoop loop; - - job.setKey("key/" + encryption); - job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); - job.start(); - loop.exec(); - - if (job.error()) - std::cerr << "Failed to reset own key: " - << qPrintable(job.errorString()) << std::endl; - return QXmpp::Private::makeReadyTask(); } QXmppTask TrustDb::ownKey(const QString &encryption) { - QKeychain::ReadPasswordJob job(service()); - QEventLoop loop; - - job.setKey("key/" + encryption); - job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit); - job.start(); - loop.exec(); - - QByteArray ret; - - if (job.error()) - std::cerr << "Failed to read own key: " - << qPrintable(job.errorString()) << std::endl; - else - ret = job.binaryData(); - - return QXmpp::Private::makeReadyTask(QByteArray(ret)); + return QXmpp::Private::makeReadyTask(db.ownKeyId(encryption)); } QXmppTask TrustDb::addKeys(const QString &encryption, const QString &keyOwnerJid, const QList &keyIds, const QXmpp::TrustLevel trustLevel) { + const struct JidDb::Keys keys(keyOwnerJid, toString(trustLevel), keyIds); + + if (db.store(encryption, keys)) + std::cerr << "TrustDb::addKeys: store failed" << std::endl; + return QXmpp::Private::makeReadyTask(); } QXmppTask TrustDb::removeKeys(const QString &encryption, const QList &keyIds) { + auto keys = db.keys(encryption); + + for (const auto &id : keyIds) + for (auto &k : keys) + { + const auto i = k.keys.indexOf(id); + + if (i != -1) + { + k.keys.removeAt(i); + break; + } + } + + for (const auto &k : keys) + if (db.store(encryption, k)) + std::cerr << "TrustDb::removeKeys: store failed" << std::endl; + return QXmpp::Private::makeReadyTask(); } QXmppTask TrustDb::removeKeys(const QString &encryption, const QString &keyOwnerJid) { + auto keys = db.keys(encryption); + + for (int i = 0; i < keys.count(); i++) + if (keys[i].owner == keyOwnerJid) + { + keys.removeAt(i); + break; + } + + for (const auto &k : keys) + if (db.store(encryption, k)) + std::cerr << "TrustDb::removeKeys: store failed" << std::endl; + return QXmpp::Private::makeReadyTask(); } QXmppTask TrustDb::removeKeys(const QString &encryption) { + db.removeKeys(encryption); return QXmpp::Private::makeReadyTask(); } @@ -195,8 +202,32 @@ QXmppTask>> TrustDb::keys(const QString &encryption, const QXmpp::TrustLevels trustLevels) { + QHash> ret; + const auto keys = db.keys(encryption); + + for (const auto &k : keys) + { + QXmpp::TrustLevel level; + + if (toTrustLevel(k.trust_level, level)) + { + std::cerr << "TrustDb::keys: invalid trust level: " + << qPrintable(k.trust_level) << std::endl; + continue; + } + else if (!trustLevels.testFlag(level)) + continue; + + QMultiHash mh; + + for (const auto &key : k.keys) + mh.insert(k.owner, key); + + ret.insert(level, mh); + } + return QXmpp::Private::makeReadyTask(QHash>()); + QMultiHash>(ret)); } QXmppTask &keyOwnerJids, const QXmpp::TrustLevels trustLevels) { + QHash> ret; + const auto keys = db.keys(encryption); + + for (const auto &jid : keyOwnerJids) + for (const auto &k : keys) + { + if (k.owner != jid) + continue; + + QXmpp::TrustLevel level; + + if (toTrustLevel(k.trust_level, level)) + { + std::cerr << "TrustDb::keys: invalid trust level: " + << qPrintable(k.trust_level) << std::endl; + continue; + } + else if (!trustLevels.testFlag(level)) + continue; + + QHash h; + + for (const auto &key : k.keys) + h.insert(key, level); + + ret.insert(jid, h); + break; + } + return QXmpp::Private::makeReadyTask(QHash>()); + QHash>(ret)); } QXmppTask TrustDb::hasKey(const QString &encryption, const QString &keyOwnerJid, QXmpp::TrustLevels trustLevels) { - return QXmpp::Private::makeReadyTask(bool()); + bool ret = false; + const auto keys = db.keys(encryption); + + for (const auto &k : keys) + { + if (k.owner != keyOwnerJid) + continue; + + QXmpp::TrustLevel level; + + if (toTrustLevel(k.trust_level, level)) + { + std::cerr << "TrustDb::keys: invalid trust level: " + << qPrintable(k.trust_level) << std::endl; + break; + } + else if (!trustLevels.testFlag(level)) + break; + + ret = true; + break; + } + + return QXmpp::Private::makeReadyTask(bool(ret)); } QXmppTask &keyIds, const QXmpp::TrustLevel trustLevel) { + QHash> ret; + auto keys = db.keys(encryption); + const auto str = toString(trustLevel); + + for (const auto &owner : keyIds.keys()) + for (auto &k : keys) + { + if (k.owner != owner) + continue; + + k.trust_level = str; + QMultiHash mh; + + for (const auto &id : k.keys) + mh.insert(owner, id); + + ret.insert(owner, mh); + break; + } + + for (const auto &key : keys) + if (db.store(encryption, key)) + std::cerr << "TrustDb::setTrustLevel: store failed" + << std::endl; + return QXmpp::Private::makeReadyTask(QHash>()); + QMultiHash>(ret)); } QXmppTask> ret; + auto keys = db.keys(encryption); + const auto str = toString(newTrustLevel); + + for (const auto &owner : keyOwnerJids) + for (auto &k : keys) + { + QXmpp::TrustLevel trust_level; + + if (k.owner != owner + || toTrustLevel(k.trust_level, trust_level) + || trust_level != oldTrustLevel) + continue; + + k.trust_level = str; + QMultiHash mh; + + for (const auto &id : k.keys) + mh.insert(owner, id); + + ret.insert(owner, mh); + break; + } + + for (const auto &key : keys) + if (db.store(encryption, key)) + std::cerr << "TrustDb::setTrustLevel: store failed" << std::endl; + return QXmpp::Private::makeReadyTask(QHash>()); + QMultiHash>(ret)); } QXmppTask TrustDb::trustLevel(const QString &encryption, const QString &keyOwnerJid, const QByteArray &keyId) { - return QXmpp::Private::makeReadyTask(QXmpp::TrustLevel()); + const auto keys = db.keys(encryption); + + for (const auto &k : keys) + { + if (k.owner != keyOwnerJid) + continue; + + for (const auto &id : k.keys) + if (id == keyId) + { + QXmpp::TrustLevel ret(QXmpp::TrustLevel::Undecided); + + if (toTrustLevel(k.trust_level, ret)) + std::cerr << "toTrustLevel failed" << std::endl; + + return QXmpp::Private::makeReadyTask( QXmpp::TrustLevel(ret)); + } + } + + return QXmpp::Private::makeReadyTask(QXmpp::TrustLevel( + QXmpp::TrustLevel::Undecided)); } QXmppTask TrustDb::resetAll(const QString &encryption) { + db.removeKeys(encryption); + return QXmpp::Private::makeReadyTask(); } + +namespace QXmpp +{ + +uint qHash(const TrustLevel &key, uint seed) +{ + return qHash(key, seed); +} + +} -- cgit v1.2.3