forked from Flowee/registry
Introduce the concept of trust.
This commit is contained in:
+15
-3
@@ -35,10 +35,15 @@ The opposite is true too, a known company can have identified itself as the
|
||||
owner and that we can advertise the trust to be higher.
|
||||
|
||||
|
||||
In hour generated metadata this is reflected by the (token) category itself
|
||||
In our generated metadata this is reflected by the (token) category itself
|
||||
having a trust, and each metadata file linked having it's own specific
|
||||
trust.
|
||||
|
||||
As a suggestion of policy, if a publisher of metadata has inconsistent data,
|
||||
for instance they failed to have 18+ tags in their metadata file while this
|
||||
would be appropriate, then what we suggest is to simply not include this
|
||||
teams data in the registry until such a time that this omission has been fixed.
|
||||
|
||||
# Config format
|
||||
|
||||
In the trust subdir of the input directory you can place many text files
|
||||
@@ -49,6 +54,13 @@ 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, ultimate
|
||||
The trust level is given. none, marginal, good, high, ultimate
|
||||
* domain=bitcoincash.org
|
||||
Provides the source of the
|
||||
Provides the source of the metadata in dns form.
|
||||
* category=deadbeef0124
|
||||
A 64 character, hex-encoded token category. Which will then inherit
|
||||
the most recently set trust.
|
||||
* 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.
|
||||
|
||||
+5
-5
@@ -24,8 +24,8 @@ void DownloadJob::start()
|
||||
connect (reply, &QNetworkReply::finished, this, [=]() {
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
// TODO mark file as not available somehow.
|
||||
logCritical() << "Download failed" << m_sourceUrl.toString();
|
||||
logCritical() << reply->errorString();
|
||||
logWarning() << "Download failed" << m_sourceUrl.toString();
|
||||
logInfo() << reply->errorString();
|
||||
}
|
||||
else {
|
||||
QFileInfo info(m_targetFilePath);
|
||||
@@ -44,12 +44,12 @@ void DownloadJob::start()
|
||||
});
|
||||
|
||||
connect (reply, &QNetworkReply::errorOccurred, this, [=](QNetworkReply::NetworkError error) {
|
||||
logFatal() << "error occurred" << error;
|
||||
logInfo() << "Download error occurred" << error << "on" << m_sourceUrl.toString();
|
||||
});
|
||||
connect (reply, &QNetworkReply::sslErrors, this, [=](const QList<QSslError> &error) {
|
||||
logFatal() << "ssl errors";
|
||||
logWarning() << "ssl errors on" << m_sourceUrl.toString();
|
||||
for (const auto &e : error) {
|
||||
logFatal() << e.error() << e.errorString();
|
||||
logWarning() << e.error() << e.errorString();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+93
-19
@@ -29,6 +29,40 @@ static bool walk(QJsonObject &item, const QStringList &steps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static Processor::Trust trustFromString(const QString &string) {
|
||||
auto lc = string.toLower();
|
||||
if (lc == "none")
|
||||
return Processor::NoTrust;
|
||||
if (lc == "marginal")
|
||||
return Processor::MarginalTrust;
|
||||
if (lc == "good")
|
||||
return Processor::GoodTrust;
|
||||
if (lc == "high")
|
||||
return Processor::HighTrust;
|
||||
if (lc == "ultimate")
|
||||
return Processor::UltimateTrust;
|
||||
logWarning() << "Unrecognized trust passed:" << string;
|
||||
return Processor::NoTrust;
|
||||
}
|
||||
|
||||
static QString trustToString(Processor::Trust trust) {
|
||||
switch (trust) {
|
||||
case Processor::NoTrust:
|
||||
return "none";
|
||||
case Processor::MarginalTrust:
|
||||
return "marginal";
|
||||
case Processor::GoodTrust:
|
||||
return "good";
|
||||
case Processor::HighTrust:
|
||||
return "high";
|
||||
case Processor::UltimateTrust:
|
||||
return "ultimate";
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Processor::Processor(const QString &inDir, const QString &outDir)
|
||||
: m_inDir(inDir),
|
||||
@@ -68,7 +102,8 @@ void Processor::run2()
|
||||
|
||||
for (auto *source : m_sources) {
|
||||
assert(source);
|
||||
assert(source->identities.size() > 0);
|
||||
if (source->identities.empty()) // created by a trust file, but seems no data.
|
||||
continue;
|
||||
QString outPath = m_outDir + source->hash + ".json";
|
||||
if (!QFile::exists(outPath)) {
|
||||
logCritical() << "Placing BCMR " << source->identities.at(0)->name << "as" << source->hash;
|
||||
@@ -124,10 +159,12 @@ void Processor::run2()
|
||||
MetaIdentity *id = owner->idForGroupId(mg->id);
|
||||
o.insert("name", id->name);
|
||||
o.insert("timestamp", id->timestampStr);
|
||||
o.insert("trust", trustToString(owner->trust));
|
||||
sources.append(o);
|
||||
}
|
||||
QJsonObject root;
|
||||
root.insert("sources", sources);
|
||||
root.insert("trust", trustToString(mg->trust));
|
||||
QJsonDocument doc;
|
||||
doc.setObject(root);
|
||||
auto memData = doc.toJson(QJsonDocument::Compact);
|
||||
@@ -183,7 +220,9 @@ void Processor::runDownloadQueue()
|
||||
logInfo() << "Starting download" << one->sourceUrl().toString();
|
||||
logInfo() << "for" << one->targetFilePath();
|
||||
// we should iterate all BCMRs that may have the same path already on the filesystem.
|
||||
if (id) {
|
||||
for (auto &group : m_groups) {
|
||||
assert(id);
|
||||
if ((group.second->type == AuthBase && id->identity == group.second->id)
|
||||
|| (group.second->type != AuthBase && id->category == group.second->id)) {
|
||||
for (auto *owner : group.second->owners) {
|
||||
@@ -205,6 +244,7 @@ void Processor::runDownloadQueue()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
one->start();
|
||||
}
|
||||
@@ -268,16 +308,13 @@ void Processor::parseBCMR(const QString &path)
|
||||
if (revision.isEmpty())
|
||||
continue;
|
||||
if (me == nullptr) {
|
||||
me = new MetaBCMR();
|
||||
me->origFilename = path;
|
||||
me = fetchOrCreate(path);
|
||||
// calc hash
|
||||
CSHA256 hasher;
|
||||
hasher.write(data.constData(), data.size());
|
||||
char buf[CSHA256::OUTPUT_SIZE];
|
||||
hasher.finalize(buf);
|
||||
me->hash = QByteArray(buf, sizeof(buf)).toHex();
|
||||
|
||||
m_sources.push_back(me);
|
||||
}
|
||||
MetaIdentity *id = new MetaIdentity();
|
||||
id->name = revision["name"].toString();
|
||||
@@ -305,6 +342,7 @@ 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);
|
||||
mg->owners.insert(me);
|
||||
// walk all nfts and extract image and icon resource urls
|
||||
auto types = token;
|
||||
@@ -331,31 +369,35 @@ void Processor::parseBCMR(const QString &path)
|
||||
if (iter == m_groups.end()) {
|
||||
// the identity was not duplicated as a category, then.
|
||||
// we conclude it was an authbase
|
||||
fetchOrCreate(id->identity, AuthBase)->owners.insert(me);
|
||||
auto *group = fetchOrCreate(id->identity, AuthBase);
|
||||
group->owners.insert(me);
|
||||
group->trust = me->trust;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Processor::parseTrustFile(const QString &path)
|
||||
{
|
||||
// TODO move the cache to a in/bcmrs/downloaded/trust_[filename].domain file
|
||||
QFileInfo me(path);
|
||||
QFileInfo cache(me.absolutePath() + "/../bcmrs/downloaded/" + me.fileName());
|
||||
if (cache.exists()) {
|
||||
QDateTime marker = QDateTime::currentDateTimeUtc().addDays(-7);
|
||||
if (cache.lastModified() > marker) {
|
||||
logInfo() << "Skipping check of" << path;
|
||||
return;
|
||||
}
|
||||
}
|
||||
QFile in(path);
|
||||
if (!in.open(QIODevice::ReadOnly)) {
|
||||
logCritical() << "Failed to read" << path;
|
||||
return;
|
||||
}
|
||||
Trust trust = NoTrust;
|
||||
for (const QString &line : QString::fromUtf8(in.readAll()).split('\n')) {
|
||||
if (line.startsWith("domain=")) {
|
||||
// .well-known/bitcoin-cash-metadata-registry.json
|
||||
QFileInfo cache(me.absolutePath() + "/../bcmrs/downloaded/" + me.fileName());
|
||||
if (trust != NoTrust)
|
||||
fetchOrCreate(cache.absoluteFilePath())->trust = trust;
|
||||
|
||||
if (cache.exists()) {
|
||||
QDateTime marker = QDateTime::currentDateTimeUtc().addDays(-7);
|
||||
if (cache.lastModified() > marker) {
|
||||
logInfo() << "Skipping check of" << path;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
QUrl location;
|
||||
location.setHost(line.mid(7).trimmed());
|
||||
location.setPath("/.well-known/bitcoin-cash-metadata-registry.json");
|
||||
@@ -369,11 +411,30 @@ void Processor::parseTrustFile(const QString &path)
|
||||
});
|
||||
m_downloadJobs.append(job);
|
||||
}
|
||||
// if (line.startsWith("trust=")) {
|
||||
// //TODO
|
||||
// }
|
||||
else if (line.startsWith("trust=")) {
|
||||
trust = trustFromString(line.mid(6).trimmed());
|
||||
}
|
||||
else if (line.startsWith("category=")) {
|
||||
auto cat = line.mid(9).trimmed();
|
||||
if (cat.length() != 64) {
|
||||
logWarning() << "category line in" << path << "has wrong format.";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trust != NoTrust)
|
||||
fetchOrCreate(cat, Category)->trust = trust;
|
||||
}
|
||||
else if (line.startsWith("authbase=")) {
|
||||
auto ab = line.mid(9).trimmed();
|
||||
if (ab.length() != 64) {
|
||||
logWarning() << "authbase line in" << path << "has wrong format.";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trust != NoTrust)
|
||||
fetchOrCreate(ab, AuthBase)->trust = trust;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Processor::parseBCHTx(QFile &file)
|
||||
@@ -382,6 +443,19 @@ void Processor::parseBCHTx(QFile &file)
|
||||
logFatal() << "parse tx is a TODO";
|
||||
}
|
||||
|
||||
Processor::MetaBCMR *Processor::fetchOrCreate(const QString &bcmrFileName)
|
||||
{
|
||||
for (auto *s : m_sources) {
|
||||
if (s->origFilename == bcmrFileName) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
MetaBCMR *meta = new MetaBCMR();
|
||||
meta->origFilename = bcmrFileName;
|
||||
m_sources.push_back(meta);
|
||||
return meta;
|
||||
}
|
||||
|
||||
bool Processor::offline() const
|
||||
{
|
||||
return m_offline;
|
||||
|
||||
@@ -21,6 +21,14 @@ public:
|
||||
bool offline() const;
|
||||
void setOffline(bool newOffline);
|
||||
|
||||
enum Trust {
|
||||
NoTrust,
|
||||
MarginalTrust,
|
||||
GoodTrust,
|
||||
HighTrust,
|
||||
UltimateTrust
|
||||
};
|
||||
|
||||
private slots:
|
||||
void runDownloadQueue();
|
||||
void run2();
|
||||
@@ -47,16 +55,19 @@ private:
|
||||
QSet<QString> resources;
|
||||
};
|
||||
struct MetaBCMR {
|
||||
Trust trust = NoTrust;
|
||||
QString hash;
|
||||
QString origFilename;
|
||||
std::vector<MetaIdentity*> identities;
|
||||
|
||||
MetaIdentity* idForGroupId(const QString &groupId) const;
|
||||
};
|
||||
MetaBCMR *fetchOrCreate(const QString &bcmrFileName);
|
||||
|
||||
struct MetaGroup {
|
||||
GroupType type;
|
||||
QString id;
|
||||
Trust trust = NoTrust;
|
||||
std::set<MetaBCMR*> owners;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user