From d084c069be38b6f3ad74912ca629403d9fdaec58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= Date: Wed, 11 Dec 2019 22:14:12 +0100 Subject: Identity loading and validation --- src/identity.cpp | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 src/identity.cpp (limited to 'src/identity.cpp') diff --git a/src/identity.cpp b/src/identity.cpp new file mode 100644 index 0000000..0160a69 --- /dev/null +++ b/src/identity.cpp @@ -0,0 +1,146 @@ +#include "identity.h" + +#include +#include + +using namespace erebos; + +using std::async; +using std::nullopt; +using std::set; + +optional Identity::load(const Ref & ref) +{ + return Identity::load(vector { ref }); +} + +optional Identity::load(const vector & refs) +{ + vector>> data; + data.reserve(refs.size()); + + for (const auto & ref : refs) { + auto d = Stored>::load(ref); + if (!d) + return nullopt; + data.push_back(*d); + } + + if (auto ptr = Priv::validate(data)) + return Identity(ptr); + return nullopt; +} + +optional Identity::name() const +{ + return p->name.get(); +} + +optional Identity::owner() const +{ + return p->owner; +} + +optional IdentityData::load(const Ref & ref) +{ + auto rec = ref->asRecord(); + if (!rec) + return nullopt; + + vector>> prev; + for (auto p : rec->items("SPREV")) + if (const auto & x = p.as>()) + prev.push_back(x.value()); + + auto keyIdentity = rec->item("key-id").as(); + if (!keyIdentity) + return nullopt; + + return IdentityData { + .prev = std::move(prev), + .name = rec->item("name").asText(), + .owner = rec->item("owner").as>(), + .keyIdentity = keyIdentity.value(), + .keyMessage = rec->item("key-msg").as(), + }; +} + +bool Identity::Priv::verifySignatures(const Stored> & sdata) +{ + if (!sdata->isSignedBy(sdata->data->keyIdentity)) + return false; + + for (const auto & p : sdata->data->prev) + if (!sdata->isSignedBy(p->data->keyIdentity)) + return false; + + if (sdata->data->owner && + !sdata->isSignedBy(sdata->data->owner.value()->data->keyIdentity)) + return false; + + for (const auto & p : sdata->data->prev) + if (!verifySignatures(p)) + return false; + + return true; +} + +shared_ptr Identity::Priv::validate(const vector>> & sdata) +{ + for (const auto & d : sdata) + if (!verifySignatures(d)) + return nullptr; + + auto p = new Priv { + .data = sdata, + }; + shared_ptr ret(p); + + auto ownerProp = p->lookupProperty([] + (const IdentityData & d) { return d.owner.has_value(); }); + if (ownerProp) { + auto owner = validate({ *ownerProp.value()->owner }); + if (!owner) + return nullptr; + p->owner.emplace(Identity(owner)); + } + + p->name = async(std::launch::deferred, [p] () -> optional { + if (auto d = p->lookupProperty([] (const IdentityData & d) { return d.name.has_value(); })) + return d.value()->name; + return nullopt; + }); + + return ret; +} + +optional> Identity::Priv::lookupProperty( + function sel) const +{ + set>> current, prop_heads; + + for (const auto & d : data) + current.insert(d); + + while (!current.empty()) { + Stored> sdata = + current.extract(current.begin()).value(); + + if (sel(*sdata->data)) + prop_heads.insert(sdata); + else + for (const auto & p : sdata->data->prev) + current.insert(p); + } + + for (auto x = prop_heads.begin(); x != prop_heads.end(); x++) + for (auto y = std::next(x); y != prop_heads.end();) + if (y->precedes(*x)) + y = prop_heads.erase(y); + else + y++; + + if (prop_heads.begin() != prop_heads.end()) + return (*prop_heads.begin())->data; + return nullopt; +} -- cgit v1.2.3