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.
|
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
|
having a trust, and each metadata file linked having it's own specific
|
||||||
trust.
|
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
|
# Config format
|
||||||
|
|
||||||
In the trust subdir of the input directory you can place many text files
|
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.
|
times such that the item is processed in order.
|
||||||
|
|
||||||
* trust=ultimate
|
* trust=ultimate
|
||||||
The trust level is given. none, marginal, good, ultimate
|
The trust level is given. none, marginal, good, high, ultimate
|
||||||
* domain=bitcoincash.org
|
* 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, [=]() {
|
connect (reply, &QNetworkReply::finished, this, [=]() {
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
// TODO mark file as not available somehow.
|
// TODO mark file as not available somehow.
|
||||||
logCritical() << "Download failed" << m_sourceUrl.toString();
|
logWarning() << "Download failed" << m_sourceUrl.toString();
|
||||||
logCritical() << reply->errorString();
|
logInfo() << reply->errorString();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QFileInfo info(m_targetFilePath);
|
QFileInfo info(m_targetFilePath);
|
||||||
@@ -44,12 +44,12 @@ void DownloadJob::start()
|
|||||||
});
|
});
|
||||||
|
|
||||||
connect (reply, &QNetworkReply::errorOccurred, this, [=](QNetworkReply::NetworkError error) {
|
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) {
|
connect (reply, &QNetworkReply::sslErrors, this, [=](const QList<QSslError> &error) {
|
||||||
logFatal() << "ssl errors";
|
logWarning() << "ssl errors on" << m_sourceUrl.toString();
|
||||||
for (const auto &e : error) {
|
for (const auto &e : error) {
|
||||||
logFatal() << e.error() << e.errorString();
|
logWarning() << e.error() << e.errorString();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+111
-37
@@ -29,6 +29,40 @@ static bool walk(QJsonObject &item, const QStringList &steps) {
|
|||||||
return true;
|
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)
|
Processor::Processor(const QString &inDir, const QString &outDir)
|
||||||
: m_inDir(inDir),
|
: m_inDir(inDir),
|
||||||
@@ -68,7 +102,8 @@ void Processor::run2()
|
|||||||
|
|
||||||
for (auto *source : m_sources) {
|
for (auto *source : m_sources) {
|
||||||
assert(source);
|
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";
|
QString outPath = m_outDir + source->hash + ".json";
|
||||||
if (!QFile::exists(outPath)) {
|
if (!QFile::exists(outPath)) {
|
||||||
logCritical() << "Placing BCMR " << source->identities.at(0)->name << "as" << source->hash;
|
logCritical() << "Placing BCMR " << source->identities.at(0)->name << "as" << source->hash;
|
||||||
@@ -124,10 +159,12 @@ void Processor::run2()
|
|||||||
MetaIdentity *id = owner->idForGroupId(mg->id);
|
MetaIdentity *id = owner->idForGroupId(mg->id);
|
||||||
o.insert("name", id->name);
|
o.insert("name", id->name);
|
||||||
o.insert("timestamp", id->timestampStr);
|
o.insert("timestamp", id->timestampStr);
|
||||||
|
o.insert("trust", trustToString(owner->trust));
|
||||||
sources.append(o);
|
sources.append(o);
|
||||||
}
|
}
|
||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
root.insert("sources", sources);
|
root.insert("sources", sources);
|
||||||
|
root.insert("trust", trustToString(mg->trust));
|
||||||
QJsonDocument doc;
|
QJsonDocument doc;
|
||||||
doc.setObject(root);
|
doc.setObject(root);
|
||||||
auto memData = doc.toJson(QJsonDocument::Compact);
|
auto memData = doc.toJson(QJsonDocument::Compact);
|
||||||
@@ -183,24 +220,27 @@ void Processor::runDownloadQueue()
|
|||||||
logInfo() << "Starting download" << one->sourceUrl().toString();
|
logInfo() << "Starting download" << one->sourceUrl().toString();
|
||||||
logInfo() << "for" << one->targetFilePath();
|
logInfo() << "for" << one->targetFilePath();
|
||||||
// we should iterate all BCMRs that may have the same path already on the filesystem.
|
// we should iterate all BCMRs that may have the same path already on the filesystem.
|
||||||
for (auto &group : m_groups) {
|
if (id) {
|
||||||
if ((group.second->type == AuthBase && id->identity == group.second->id)
|
for (auto &group : m_groups) {
|
||||||
|| (group.second->type != AuthBase && id->category == group.second->id)) {
|
assert(id);
|
||||||
for (auto *owner : group.second->owners) {
|
if ((group.second->type == AuthBase && id->identity == group.second->id)
|
||||||
QString target = m_outDir + owner->hash;
|
|| (group.second->type != AuthBase && id->category == group.second->id)) {
|
||||||
if (one->targetFilePath().startsWith(target)) // that's 'me'
|
for (auto *owner : group.second->owners) {
|
||||||
continue;
|
QString target = m_outDir + owner->hash;
|
||||||
target += one->targetFilePath().mid(target.size());
|
if (one->targetFilePath().startsWith(target)) // that's 'me'
|
||||||
if (QFile::exists(target)) {
|
continue;
|
||||||
logInfo() << "Found in cache, skipping download";
|
target += one->targetFilePath().mid(target.size());
|
||||||
|
if (QFile::exists(target)) {
|
||||||
|
logInfo() << "Found in cache, skipping download";
|
||||||
|
|
||||||
QFileInfo info(one->targetFilePath());
|
QFileInfo info(one->targetFilePath());
|
||||||
QDir("/").mkpath(info.absolutePath());
|
QDir("/").mkpath(info.absolutePath());
|
||||||
QFile::copy(target, one->targetFilePath());
|
QFile::copy(target, one->targetFilePath());
|
||||||
m_downloadJobs.removeAll(one);
|
m_downloadJobs.removeAll(one);
|
||||||
one->deleteLater();
|
one->deleteLater();
|
||||||
QTimer::singleShot(1, this, SLOT(runDownloadQueue()));
|
QTimer::singleShot(1, this, SLOT(runDownloadQueue()));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,16 +308,13 @@ void Processor::parseBCMR(const QString &path)
|
|||||||
if (revision.isEmpty())
|
if (revision.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
if (me == nullptr) {
|
if (me == nullptr) {
|
||||||
me = new MetaBCMR();
|
me = fetchOrCreate(path);
|
||||||
me->origFilename = path;
|
|
||||||
// calc hash
|
// calc hash
|
||||||
CSHA256 hasher;
|
CSHA256 hasher;
|
||||||
hasher.write(data.constData(), data.size());
|
hasher.write(data.constData(), data.size());
|
||||||
char buf[CSHA256::OUTPUT_SIZE];
|
char buf[CSHA256::OUTPUT_SIZE];
|
||||||
hasher.finalize(buf);
|
hasher.finalize(buf);
|
||||||
me->hash = QByteArray(buf, sizeof(buf)).toHex();
|
me->hash = QByteArray(buf, sizeof(buf)).toHex();
|
||||||
|
|
||||||
m_sources.push_back(me);
|
|
||||||
}
|
}
|
||||||
MetaIdentity *id = new MetaIdentity();
|
MetaIdentity *id = new MetaIdentity();
|
||||||
id->name = revision["name"].toString();
|
id->name = revision["name"].toString();
|
||||||
@@ -305,6 +342,7 @@ void Processor::parseBCMR(const QString &path)
|
|||||||
id->category = cat;
|
id->category = cat;
|
||||||
MetaGroup *mg = fetchOrCreate(cat, Category);
|
MetaGroup *mg = fetchOrCreate(cat, Category);
|
||||||
id->tokens.push_back(mg);
|
id->tokens.push_back(mg);
|
||||||
|
mg->trust = std::max(mg->trust, me->trust);
|
||||||
mg->owners.insert(me);
|
mg->owners.insert(me);
|
||||||
// walk all nfts and extract image and icon resource urls
|
// walk all nfts and extract image and icon resource urls
|
||||||
auto types = token;
|
auto types = token;
|
||||||
@@ -331,31 +369,35 @@ void Processor::parseBCMR(const QString &path)
|
|||||||
if (iter == m_groups.end()) {
|
if (iter == m_groups.end()) {
|
||||||
// the identity was not duplicated as a category, then.
|
// the identity was not duplicated as a category, then.
|
||||||
// we conclude it was an authbase
|
// 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)
|
void Processor::parseTrustFile(const QString &path)
|
||||||
{
|
{
|
||||||
// TODO move the cache to a in/bcmrs/downloaded/trust_[filename].domain file
|
|
||||||
QFileInfo me(path);
|
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);
|
QFile in(path);
|
||||||
if (!in.open(QIODevice::ReadOnly)) {
|
if (!in.open(QIODevice::ReadOnly)) {
|
||||||
logCritical() << "Failed to read" << path;
|
logCritical() << "Failed to read" << path;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Trust trust = NoTrust;
|
||||||
for (const QString &line : QString::fromUtf8(in.readAll()).split('\n')) {
|
for (const QString &line : QString::fromUtf8(in.readAll()).split('\n')) {
|
||||||
if (line.startsWith("domain=")) {
|
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;
|
QUrl location;
|
||||||
location.setHost(line.mid(7).trimmed());
|
location.setHost(line.mid(7).trimmed());
|
||||||
location.setPath("/.well-known/bitcoin-cash-metadata-registry.json");
|
location.setPath("/.well-known/bitcoin-cash-metadata-registry.json");
|
||||||
@@ -369,11 +411,30 @@ void Processor::parseTrustFile(const QString &path)
|
|||||||
});
|
});
|
||||||
m_downloadJobs.append(job);
|
m_downloadJobs.append(job);
|
||||||
}
|
}
|
||||||
// if (line.startsWith("trust=")) {
|
else if (line.startsWith("trust=")) {
|
||||||
// //TODO
|
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)
|
void Processor::parseBCHTx(QFile &file)
|
||||||
@@ -382,6 +443,19 @@ void Processor::parseBCHTx(QFile &file)
|
|||||||
logFatal() << "parse tx is a TODO";
|
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
|
bool Processor::offline() const
|
||||||
{
|
{
|
||||||
return m_offline;
|
return m_offline;
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ public:
|
|||||||
bool offline() const;
|
bool offline() const;
|
||||||
void setOffline(bool newOffline);
|
void setOffline(bool newOffline);
|
||||||
|
|
||||||
|
enum Trust {
|
||||||
|
NoTrust,
|
||||||
|
MarginalTrust,
|
||||||
|
GoodTrust,
|
||||||
|
HighTrust,
|
||||||
|
UltimateTrust
|
||||||
|
};
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void runDownloadQueue();
|
void runDownloadQueue();
|
||||||
void run2();
|
void run2();
|
||||||
@@ -47,16 +55,19 @@ private:
|
|||||||
QSet<QString> resources;
|
QSet<QString> resources;
|
||||||
};
|
};
|
||||||
struct MetaBCMR {
|
struct MetaBCMR {
|
||||||
|
Trust trust = NoTrust;
|
||||||
QString hash;
|
QString hash;
|
||||||
QString origFilename;
|
QString origFilename;
|
||||||
std::vector<MetaIdentity*> identities;
|
std::vector<MetaIdentity*> identities;
|
||||||
|
|
||||||
MetaIdentity* idForGroupId(const QString &groupId) const;
|
MetaIdentity* idForGroupId(const QString &groupId) const;
|
||||||
};
|
};
|
||||||
|
MetaBCMR *fetchOrCreate(const QString &bcmrFileName);
|
||||||
|
|
||||||
struct MetaGroup {
|
struct MetaGroup {
|
||||||
GroupType type;
|
GroupType type;
|
||||||
QString id;
|
QString id;
|
||||||
|
Trust trust = NoTrust;
|
||||||
std::set<MetaBCMR*> owners;
|
std::set<MetaBCMR*> owners;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user