summaryrefslogtreecommitdiff
path: root/src/identity.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/identity.cpp')
-rw-r--r--src/identity.cpp101
1 files changed, 89 insertions, 12 deletions
diff --git a/src/identity.cpp b/src/identity.cpp
index ae20b3b..8b6ee2a 100644
--- a/src/identity.cpp
+++ b/src/identity.cpp
@@ -9,7 +9,7 @@
using namespace erebos;
using std::async;
-using std::get_if;
+using std::holds_alternative;
using std::nullopt;
using std::runtime_error;
using std::set;
@@ -89,6 +89,7 @@ vector<Stored<Signed<IdentityData>>> Identity::data() const
for (const auto & d : p->data)
base.push_back(d.base());
+ filterAncestors(base);
return base;
}
@@ -149,8 +150,26 @@ optional<Ref> Identity::ref() const
return nullopt;
}
+optional<Ref> Identity::extRef() const
+{
+ if (p->data.size() == 1)
+ return p->data[0].ref();
+ return nullopt;
+}
+
vector<Ref> Identity::refs() const
{
+ auto base = data();
+ vector<Ref> res;
+ res.reserve(base.size());
+
+ for (const auto & d : base)
+ res.push_back(d.ref());
+ return res;
+}
+
+vector<Ref> Identity::extRefs() const
+{
vector<Ref> res;
res.reserve(p->data.size());
for (const auto & idata : p->data)
@@ -178,9 +197,22 @@ Identity::Builder Identity::create(const Storage & st)
Identity::Builder Identity::modify() const
{
+ vector<Stored<Signed<IdentityData>>> prevBase;
+ vector<StoredIdentityPart> prevExt;
+
+ prevBase.reserve(p->data.size());
+ for (const auto & d : p->data) {
+ prevBase.push_back(d.base());
+ if (holds_alternative<Stored<Signed<IdentityExtension>>>(d.part))
+ prevExt.push_back(d);
+ }
+
+ filterAncestors(prevBase);
+
return Builder (new Builder::Priv {
.storage = p->data[0].ref().storage(),
- .prev = data(),
+ .prevBase = move(prevBase),
+ .prevExt = move(prevExt),
.keyIdentity = p->data[0].base()->data->keyIdentity,
.keyMessage = p->data[0].base()->data->keyMessage,
});
@@ -247,11 +279,18 @@ Identity::Builder::Builder(Priv * p): p(p) {}
Identity Identity::Builder::commit() const
{
- auto idata = p->storage.store(IdentityData {
- .prev = p->prev,
- .name = p->name,
- .owner = p->owner && p->owner->p->data.size() == 1 ?
- optional(p->owner->p->data[0].base()) : nullopt,
+ optional<Stored<Signed<IdentityData>>> ownerBaseData;
+ optional<StoredIdentityPart> ownerExtData;
+ if (p->owner && p->owner->p->data.size() == 1) {
+ ownerExtData = p->owner->p->data[0];
+ ownerBaseData = ownerExtData->base();
+ if (holds_alternative<Stored<Signed<IdentityData>>>(ownerExtData->part))
+ ownerExtData.reset();
+ }
+
+ auto base = p->storage.store(IdentityData {
+ .prev = p->prevBase,
+ .owner = ownerBaseData,
.keyIdentity = p->keyIdentity,
.keyMessage = p->keyMessage,
});
@@ -260,15 +299,38 @@ Identity Identity::Builder::commit() const
if (!key)
throw runtime_error("failed to load secret key");
- auto sdata = key->sign(idata);
- if (idata->owner) {
- if (auto okey = SecretKey::load((*idata->owner)->data->keyIdentity))
- sdata = okey->signAdd(sdata);
+ auto sbase = key->sign(base);
+ if (base->owner) {
+ if (auto okey = SecretKey::load((*base->owner)->data->keyIdentity))
+ sbase = okey->signAdd(sbase);
else
throw runtime_error("failed to load secret key");
}
- auto p = Identity::Priv::validate({ StoredIdentityPart(sdata) });
+ optional<StoredIdentityPart> spart;
+
+ if (not p->prevExt.empty() || p->name || ownerExtData) {
+ auto ext = p->storage.store(IdentityExtension {
+ .base = sbase,
+ .prev = p->prevExt,
+ .name = p->name,
+ .owner = ownerExtData,
+ });
+
+ auto sext = key->sign(ext);
+ if (ext->owner) {
+ if (auto okey = SecretKey::load(p->owner->keyIdentity()))
+ sext = okey->signAdd(sext);
+ else
+ throw runtime_error("failed to load secret key");
+ }
+
+ spart.emplace(sext);
+ } else {
+ spart.emplace(sbase);
+ }
+
+ auto p = Identity::Priv::validate({ *spart });
if (!p)
throw runtime_error("failed to validate committed identity");
@@ -350,6 +412,21 @@ IdentityExtension IdentityExtension::load(const Ref & ref)
};
}
+Ref IdentityExtension::store(const Storage & st) const
+{
+ vector<Record::Item> items;
+
+ items.emplace_back("SBASE", base);
+ for (const auto & p : prev)
+ items.emplace_back("SPREV", p.ref());
+ if (name)
+ items.emplace_back("name", *name);
+ if (owner)
+ items.emplace_back("owner", owner->ref());
+
+ return st.storeObject(Record(std::move(items)));
+}
+
StoredIdentityPart StoredIdentityPart::load(const Ref & ref)
{
if (auto srec = ref->asRecord()) {