From 7c455754dbdc8e53a6956975ea8b35af668d9f53 Mon Sep 17 00:00:00 2001 From: TomZ Date: Fri, 11 Apr 2025 18:14:47 +0200 Subject: [PATCH] Add trust inherited from authchain --- documentation/trust | 26 +++++++++++++++--- src/DownloadJob.cpp | 4 +-- src/Processor.cpp | 65 ++++++++++++++++++++++++++++++++++++++------- src/Processor.h | 6 ++--- 4 files changed, 82 insertions(+), 19 deletions(-) diff --git a/documentation/trust b/documentation/trust index 608fd57..4e8be77 100644 --- a/documentation/trust +++ b/documentation/trust @@ -53,14 +53,32 @@ The file is very simple name/value pairs in standard unix line-endings. Fields are read from top to bottom, you can mention the same field various times such that the item is processed in order. -* trust=ultimate - The trust level is given. none, marginal, good, high, ultimate +* trust=good + The trust level is given. absent, marginal, good, high * domain=bitcoincash.org Provides the source of the metadata in dns form. -* category=deadbeef0124 +* category=deadbeef0124 A 64 character, hex-encoded token category. Which will then inherit the most recently set trust. -* authbase=deadbeef0124 +* authbase=deadbeef0124 A 64 character, hex-encoded authbase (txid). Which will then inherit the most recently set trust. Allowing for all metadata files indicated by it to likewise inherit this trust. + + +Trust levels + ++---+---+ +|Level|Description| ++---+---+ +| absent | Trust has been violated, this is likely a scam or spam. | +| marginal | [Default] No trust could be established | +| good | Minimal checking has been done, likely an honest party | +| high | The party is trusted by the registry owner | +| ultimate | We know that the content comes from the party they say they are.| + +Notice that the ultimate trust is really only used to describe confidence +level of the metadata file being published by who they say they are. Or +really if you are publishing your own metadata on your own registry this +way. + diff --git a/src/DownloadJob.cpp b/src/DownloadJob.cpp index e651396..099ba98 100644 --- a/src/DownloadJob.cpp +++ b/src/DownloadJob.cpp @@ -49,7 +49,7 @@ void DownloadJob::start() else { auto data = reply->readAll(); if (checkHash(data)) { - out.write(reply->readAll()); + out.write(data); out.flush(); } else { logWarning() << "Download failed hash-check" << m_sourceUrl.toString(); @@ -116,12 +116,12 @@ bool DownloadJob::checkHash(const QByteArray &contents) const { if (m_targetHash.isEmpty()) return true; + static_assert(CSHA256::OUTPUT_SIZE == 32); assert(m_targetHash.size() == 32); CSHA256 hasher; hasher.write(contents.constData(), contents.size()); char hash[CSHA256::OUTPUT_SIZE]; - static_assert(CSHA256::OUTPUT_SIZE == 32); hasher.finalize(hash); return memcmp(hash, m_targetHash.begin(), 32) == 0; } diff --git a/src/Processor.cpp b/src/Processor.cpp index f5a17ea..1fc33cd 100644 --- a/src/Processor.cpp +++ b/src/Processor.cpp @@ -31,7 +31,7 @@ static bool walk(QJsonObject &item, const QStringList &steps) { static Processor::Trust trustFromString(const QString &string) { auto lc = string.toLower(); - if (lc == "none") + if (lc == "absent") return Processor::NoTrust; if (lc == "marginal") return Processor::MarginalTrust; @@ -42,13 +42,13 @@ static Processor::Trust trustFromString(const QString &string) { if (lc == "ultimate") return Processor::UltimateTrust; logWarning() << "Unrecognized trust passed:" << string; - return Processor::NoTrust; + return Processor::MarginalTrust; } static QString trustToString(Processor::Trust trust) { switch (trust) { case Processor::NoTrust: - return "none"; + return "absent"; case Processor::MarginalTrust: return "marginal"; case Processor::GoodTrust: @@ -113,6 +113,24 @@ void Processor::run2() } } } + for (auto iter = m_transactions.begin(); iter != m_transactions.end(); ++iter) { + // create placeholder bcmr data objects in order to inherit trust from + // the authchain group. + Transaction *d = iter->second; + auto gId = d->authbase(); + auto gIter = m_groups.find(gId); + if (gIter != m_groups.end()) { + MetaGroup *g = gIter->second; + if (g->trust != MarginalTrust) { + // the transaction, and any bcmrs it might contain would inherit + // the trust from that group. Lets create a placeholder to mark that. + QFileInfo target(m_inDir + "bcmrs/downloaded/" + + QString::fromStdString(d->txid.ToString()) + ".json"); + auto *meta = fetchOrCreate(target.absoluteFilePath()); + meta->trust = g->trust; + } + } + } QDirIterator iter(m_inDir + "bcmrs", QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs, QDirIterator::Subdirectories); while (iter.hasNext()) { @@ -365,7 +383,9 @@ void Processor::parseBCMR(const QString &path) id->category = cat; MetaGroup *mg = fetchOrCreate(cat, Category); id->tokens.push_back(mg); - mg->trust = std::max(mg->trust, me->trust); + // identities inherit trust from the bcmr + if (me->trust != MarginalTrust) + mg->trust = me->trust; mg->owners.insert(me); // walk all nfts and extract image and icon resource urls auto types = token; @@ -394,6 +414,10 @@ void Processor::parseBCMR(const QString &path) // we conclude it was an authbase auto *group = fetchOrCreate(id->identity, AuthBase); group->owners.insert(me); + + logFatal() << "xxxx" << in.fileName(); + + group->trust = me->trust; } } @@ -407,11 +431,11 @@ void Processor::parseTrustFile(const QString &path) logCritical() << "Failed to read" << path; return; } - Trust trust = NoTrust; + Trust trust = MarginalTrust; for (const QString &line : QString::fromUtf8(in.readAll()).split('\n')) { if (line.startsWith("domain=")) { QFileInfo cache(m_inDir + "bcmrs/downloaded/" + me.fileName()); - if (trust != NoTrust) + if (trust != MarginalTrust) fetchOrCreate(cache.absoluteFilePath())->trust = trust; if (cache.exists()) { @@ -440,7 +464,7 @@ void Processor::parseTrustFile(const QString &path) continue; } - if (trust != NoTrust) + if (trust != MarginalTrust) fetchOrCreate(cat, Category)->trust = trust; } else if (line.startsWith("authbase=")) { @@ -450,7 +474,7 @@ void Processor::parseTrustFile(const QString &path) continue; } - if (trust != NoTrust) + if (trust != MarginalTrust) fetchOrCreate(ab, AuthBase)->trust = trust; } } @@ -459,7 +483,13 @@ void Processor::parseTrustFile(const QString &path) void Processor::parseBCHTx(QFile &file) { if (file.size() < 65) { - logWarning() << "Skipping file, it's too small"<< file.fileName(); + // downloading a bcmr from a transaction may fail to match the hash + // and then we create an empty file to avoid downloading it again + // in the future. So don't complain about those. + // (scenario is not weird, maybe bcmr owners don't host new files + // when they update the on-chain reference to them, so old ones fail) + if (file.size() > 0) + logWarning() << "Skipping file, it's too small"<< file.fileName(); return; } m_pool.reserve(file.size()); @@ -486,8 +516,10 @@ void Processor::parseBCHTx(QFile &file) && output.outputScript[6] == 0x20) { // space auto hash = output.outputScript.mid(7, 32); + // filename is the original transaction id, so we can figure out + // who owns it. QFileInfo target(m_inDir + "bcmrs/downloaded/" - + QString::fromStdString(hash.toHex()) + ".json"); + + QString::fromStdString(tx.createHash().ToString()) + ".json"); if (target.exists()) continue; @@ -579,3 +611,16 @@ void Processor::addJob(DownloadJob *job) }); m_downloadJobs.append(job); } + + +QString Processor::Transaction::authbase() const +{ + auto *root = this; + while (true) { + if (root->previous) + root = root->previous; + else + break; + } + return QString::fromStdString(root->txid.ToString()); +} diff --git a/src/Processor.h b/src/Processor.h index 02343e8..ca6040e 100644 --- a/src/Processor.h +++ b/src/Processor.h @@ -59,7 +59,7 @@ private: QSet resources; }; struct MetaBCMR { - Trust trust = NoTrust; + Trust trust = MarginalTrust; QString hash; QString origFilename; std::vector identities; @@ -71,7 +71,7 @@ private: struct MetaGroup { GroupType type; QString id; - Trust trust = NoTrust; + Trust trust = MarginalTrust; std::set owners; }; @@ -81,7 +81,7 @@ private: GroupMap m_groups; struct Transaction { - uint256 authbase() const; + QString authbase() const; Tx transaction; uint256 txid; Transaction *previous = nullptr;