summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/erebos/message.h6
-rw-r--r--include/erebos/storage.h16
-rw-r--r--src/channel.cpp102
-rw-r--r--src/channel.h6
-rw-r--r--src/identity.cpp45
-rw-r--r--src/identity.h2
-rw-r--r--src/message.cpp39
-rw-r--r--src/message.h8
-rw-r--r--src/network.cpp14
-rw-r--r--src/pubkey.cpp57
-rw-r--r--src/pubkey.h37
-rw-r--r--src/storage.cpp34
12 files changed, 184 insertions, 182 deletions
diff --git a/include/erebos/message.h b/include/erebos/message.h
index 0b5e257..c94e8c3 100644
--- a/include/erebos/message.h
+++ b/include/erebos/message.h
@@ -14,9 +14,9 @@ class Identity;
class DirectMessage
{
public:
- const Identity & from() const;
- const struct ZonedTime & time() const;
- const std::string & text() const;
+ const std::optional<Identity> & from() const;
+ const std::optional<struct ZonedTime> & time() const;
+ std::string text() const;
private:
friend class DirectMessageThread;
diff --git a/include/erebos/storage.h b/include/erebos/storage.h
index d5ae45a..d46c056 100644
--- a/include/erebos/storage.h
+++ b/include/erebos/storage.h
@@ -72,6 +72,7 @@ public:
PartialStorage derivePartialStorage() const;
std::optional<Ref> ref(const Digest &) const;
+ Ref zref() const;
std::optional<Object> loadObject(const Digest &) const;
Ref storeObject(const Object &) const;
@@ -103,6 +104,7 @@ public:
explicit Digest(std::array<uint8_t, size> value): value(value) {}
explicit Digest(const std::string &);
explicit operator std::string() const;
+ bool isZero() const;
const std::array<uint8_t, size> & arr() const { return value; }
@@ -151,6 +153,7 @@ public:
Ref & operator=(Ref &&) = default;
static std::optional<Ref> create(Storage, const Digest &);
+ static Ref zcreate(Storage);
constexpr operator bool() const { return true; }
const Object operator*() const;
@@ -265,7 +268,8 @@ class ObjectT
public:
typedef std::variant<
RecordT<S>,
- Blob> Variants;
+ Blob,
+ std::monostate> Variants;
ObjectT(const ObjectT<S> &) = default;
ObjectT(Variants content): content(content) {}
@@ -282,7 +286,7 @@ public:
std::vector<uint8_t>::const_iterator);
static std::vector<ObjectT<S>> decodeMany(const S &, const std::vector<uint8_t> &);
std::vector<uint8_t> encode() const;
- static std::optional<ObjectT<S>> load(const typename S::Ref &);
+ static ObjectT<S> load(const typename S::Ref &);
std::optional<RecordT<S>> asRecord() const;
std::optional<Blob> asBlob() const;
@@ -317,7 +321,7 @@ public:
Stored & operator=(const Stored &) = default;
Stored & operator=(Stored &&) = default;
- static std::optional<Stored<T>> load(const Ref &);
+ static Stored<T> load(const Ref &);
Ref store(const Storage &) const;
bool operator==(const Stored<T> & other) const
@@ -354,11 +358,9 @@ Stored<T> Storage::store(const T & val) const
}
template<typename T>
-std::optional<Stored<T>> Stored<T>::load(const Ref & ref)
+Stored<T> Stored<T>::load(const Ref & ref)
{
- if (auto val = T::load(ref))
- return Stored(ref, std::make_shared<T>(val.value()));
- return std::nullopt;
+ return Stored(ref, std::make_shared<T>(T::load(ref)));
}
template<typename T>
diff --git a/src/channel.cpp b/src/channel.cpp
index 50c5f97..b13a71e 100644
--- a/src/channel.cpp
+++ b/src/channel.cpp
@@ -22,28 +22,25 @@ Ref ChannelRequestData::store(const Storage & st) const
return st.storeObject(Record(std::move(items)));
}
-optional<ChannelRequestData> ChannelRequestData::load(const Ref & ref)
+ChannelRequestData ChannelRequestData::load(const Ref & ref)
{
- auto rec = ref->asRecord();
- if (!rec)
- return nullopt;
-
- remove_const<decltype(peers)>::type peers;
- for (const auto & i : rec->items("peer"))
- if (auto p = i.as<Signed<IdentityData>>())
- peers.push_back(*p);
-
- auto enc = rec->item("enc").asText();
- if (!enc || enc != "aes-128-gcm")
- return nullopt;
-
- auto key = rec->item("key").as<PublicKexKey>();
- if (!key)
- return nullopt;
+ if (auto rec = ref->asRecord()) {
+ remove_const<decltype(peers)>::type peers;
+ for (const auto & i : rec->items("peer"))
+ if (auto p = i.as<Signed<IdentityData>>())
+ peers.push_back(*p);
+
+ if (rec->item("enc").asText() == "aes-128-gcm")
+ if (auto key = rec->item("key").as<PublicKexKey>())
+ return ChannelRequestData {
+ .peers = std::move(peers),
+ .key = *key,
+ };
+ }
return ChannelRequestData {
- .peers = std::move(peers),
- .key = *key,
+ .peers = {},
+ .key = Stored<PublicKexKey>::load(ref.storage().zref()),
};
}
@@ -58,27 +55,18 @@ Ref ChannelAcceptData::store(const Storage & st) const
return st.storeObject(Record(std::move(items)));
}
-optional<ChannelAcceptData> ChannelAcceptData::load(const Ref & ref)
+ChannelAcceptData ChannelAcceptData::load(const Ref & ref)
{
- auto rec = ref->asRecord();
- if (!rec)
- return nullopt;
-
- auto request = rec->item("req").as<ChannelRequest>();
- if (!request)
- return nullopt;
-
- auto enc = rec->item("enc").asText();
- if (!enc || enc != "aes-128-gcm")
- return nullopt;
-
- auto key = rec->item("key").as<PublicKexKey>();
- if (!key)
- return nullopt;
+ if (auto rec = ref->asRecord())
+ if (rec->item("enc").asText() == "aes-128-gcm")
+ return ChannelAcceptData {
+ .request = *rec->item("req").as<ChannelRequest>(),
+ .key = *rec->item("key").as<PublicKexKey>(),
+ };
return ChannelAcceptData {
- .request = *request,
- .key = *key,
+ .request = Stored<ChannelRequest>::load(ref.storage().zref()),
+ .key = Stored<PublicKexKey>::load(ref.storage().zref()),
};
}
@@ -114,26 +102,20 @@ Ref Channel::store(const Storage & st) const
return st.storeObject(Record(std::move(items)));
}
-optional<Channel> Channel::load(const Ref & ref)
+Channel Channel::load(const Ref & ref)
{
- auto rec = ref->asRecord();
- if (!rec)
- return nullopt;
-
- remove_const<decltype(peers)>::type peers;
- for (const auto & i : rec->items("peer"))
- if (auto p = i.as<Signed<IdentityData>>())
- peers.push_back(*p);
-
- auto enc = rec->item("enc").asText();
- if (!enc || enc != "aes-128-gcm")
- return nullopt;
-
- auto key = rec->item("key").asBinary();
- if (!key)
- return nullopt;
-
- return Channel(peers, std::move(*key));
+ if (auto rec = ref->asRecord()) {
+ remove_const<decltype(peers)>::type peers;
+ for (const auto & i : rec->items("peer"))
+ if (auto p = i.as<Signed<IdentityData>>())
+ peers.push_back(*p);
+
+ if (rec->item("enc").asText() == "aes-128-gcm")
+ if (auto key = rec->item("key").asBinary())
+ return Channel(peers, std::move(*key));
+ }
+
+ return Channel({}, {});
}
Stored<ChannelRequest> Channel::generateRequest(const Storage & st,
@@ -146,12 +128,12 @@ Stored<ChannelRequest> Channel::generateRequest(const Storage & st,
return signKey->sign(st.store(ChannelRequestData {
.peers = self.ref()->digest() < peer.ref()->digest() ?
vector<Stored<Signed<IdentityData>>> {
- *Stored<Signed<IdentityData>>::load(*self.ref()),
- *Stored<Signed<IdentityData>>::load(*peer.ref()),
+ Stored<Signed<IdentityData>>::load(*self.ref()),
+ Stored<Signed<IdentityData>>::load(*peer.ref()),
} :
vector<Stored<Signed<IdentityData>>> {
- *Stored<Signed<IdentityData>>::load(*peer.ref()),
- *Stored<Signed<IdentityData>>::load(*self.ref()),
+ Stored<Signed<IdentityData>>::load(*peer.ref()),
+ Stored<Signed<IdentityData>>::load(*self.ref()),
},
.key = SecretKexKey::generate(st).pub(),
}));
diff --git a/src/channel.h b/src/channel.h
index 100003c..1c7df30 100644
--- a/src/channel.h
+++ b/src/channel.h
@@ -9,7 +9,7 @@ namespace erebos {
struct ChannelRequestData
{
Ref store(const Storage & st) const;
- static optional<ChannelRequestData> load(const Ref &);
+ static ChannelRequestData load(const Ref &);
const vector<Stored<Signed<IdentityData>>> peers;
const Stored<PublicKexKey> key;
@@ -20,7 +20,7 @@ typedef Signed<ChannelRequestData> ChannelRequest;
struct ChannelAcceptData
{
Ref store(const Storage & st) const;
- static optional<ChannelAcceptData> load(const Ref &);
+ static ChannelAcceptData load(const Ref &);
Stored<class Channel> channel() const;
@@ -40,7 +40,7 @@ public:
{}
Ref store(const Storage & st) const;
- static optional<Channel> load(const Ref &);
+ static Channel load(const Ref &);
static Stored<ChannelRequest> generateRequest(const Storage &,
const Identity & self, const Identity & peer);
diff --git a/src/identity.cpp b/src/identity.cpp
index 3cba97c..2396b9f 100644
--- a/src/identity.cpp
+++ b/src/identity.cpp
@@ -24,12 +24,8 @@ optional<Identity> Identity::load(const vector<Ref> & refs)
vector<Stored<Signed<IdentityData>>> data;
data.reserve(refs.size());
- for (const auto & ref : refs) {
- auto d = Stored<Signed<IdentityData>>::load(ref);
- if (!d)
- return nullopt;
- data.push_back(*d);
- }
+ for (const auto & ref : refs)
+ data.push_back(Stored<Signed<IdentityData>>::load(ref));
if (auto ptr = Priv::validate(data))
return Identity(ptr);
@@ -124,27 +120,30 @@ void Identity::Builder::owner(const Identity & val)
p->owner.emplace(val);
}
-optional<IdentityData> IdentityData::load(const Ref & ref)
+IdentityData IdentityData::load(const Ref & ref)
{
- auto rec = ref->asRecord();
- if (!rec)
- return nullopt;
-
- vector<Stored<Signed<IdentityData>>> prev;
- for (auto p : rec->items("SPREV"))
- if (const auto & x = p.as<Signed<IdentityData>>())
- prev.push_back(x.value());
+ if (auto rec = ref->asRecord()) {
+ vector<Stored<Signed<IdentityData>>> prev;
+ for (auto p : rec->items("SPREV"))
+ if (const auto & x = p.as<Signed<IdentityData>>())
+ prev.push_back(x.value());
- auto keyIdentity = rec->item("key-id").as<PublicKey>();
- if (!keyIdentity)
- return nullopt;
+ if (auto keyIdentity = rec->item("key-id").as<PublicKey>())
+ return IdentityData {
+ .prev = std::move(prev),
+ .name = rec->item("name").asText(),
+ .owner = rec->item("owner").as<Signed<IdentityData>>(),
+ .keyIdentity = keyIdentity.value(),
+ .keyMessage = rec->item("key-msg").as<PublicKey>(),
+ };
+ }
return IdentityData {
- .prev = std::move(prev),
- .name = rec->item("name").asText(),
- .owner = rec->item("owner").as<Signed<IdentityData>>(),
- .keyIdentity = keyIdentity.value(),
- .keyMessage = rec->item("key-msg").as<PublicKey>(),
+ .prev = {},
+ .name = nullopt,
+ .owner = nullopt,
+ .keyIdentity = Stored<PublicKey>::load(ref.storage().zref()),
+ .keyMessage = nullopt,
};
}
diff --git a/src/identity.h b/src/identity.h
index 92ac34f..1dfc193 100644
--- a/src/identity.h
+++ b/src/identity.h
@@ -13,7 +13,7 @@ namespace erebos {
class IdentityData
{
public:
- static optional<IdentityData> load(const Ref &);
+ static IdentityData load(const Ref &);
Ref store(const Storage & st) const;
const vector<Stored<Signed<IdentityData>>> prev;
diff --git a/src/message.cpp b/src/message.cpp
index b7d4bda..354703e 100644
--- a/src/message.cpp
+++ b/src/message.cpp
@@ -48,11 +48,11 @@ DirectMessage::DirectMessage(Priv * p):
p(p)
{}
-optional<DirectMessageData> DirectMessageData::load(const Ref & ref)
+DirectMessageData DirectMessageData::load(const Ref & ref)
{
auto rec = ref->asRecord();
if (!rec)
- return nullopt;
+ return DirectMessageData();
vector<Stored<DirectMessageData>> prev;
for (auto p : rec->items("PREV"))
@@ -60,16 +60,10 @@ optional<DirectMessageData> DirectMessageData::load(const Ref & ref)
prev.push_back(*x);
auto fref = rec->item("from").asRef();
- if (!fref)
- return nullopt;
-
- auto from = Identity::load(*fref);
- if (!from)
- return nullopt;
return DirectMessageData {
.prev = std::move(prev),
- .from = *from,
+ .from = fref ? Identity::load(*fref) : nullopt,
.time = *rec->item("time").asDate(),
.text = rec->item("text").asText().value(),
};
@@ -81,27 +75,32 @@ Ref DirectMessageData::store(const Storage & st) const
for (const auto prev : prev)
items.emplace_back("PREV", prev.ref());
- items.emplace_back("from", from.ref().value());
- items.emplace_back("time", time);
- items.emplace_back("text", text);
+ if (from)
+ items.emplace_back("from", from->ref().value());
+ if (time)
+ items.emplace_back("time", *time);
+ if (text)
+ items.emplace_back("text", *text);
return st.storeObject(Record(std::move(items)));
}
-const Identity & DirectMessage::from() const
+const optional<Identity> & DirectMessage::from() const
{
return p->data->from;
}
-const ZonedTime & DirectMessage::time() const
+const optional<ZonedTime> & DirectMessage::time() const
{
return p->data->time;
}
-const string & DirectMessage::text() const
+string DirectMessage::text() const
{
- return p->data->text;
+ if (p->data->text)
+ return p->data->text.value();
+ return "";
}
@@ -138,7 +137,7 @@ DirectMessageThread::Iterator & DirectMessageThread::Iterator::operator++()
auto ncur = p->next[0];
for (const auto & m : p->next)
- if (m->time.time >= ncur->time.time)
+ if (!ncur->time || (m->time && m->time->time >= ncur->time->time))
ncur = m;
p->current.emplace(DirectMessage(new DirectMessage::Priv {
@@ -216,10 +215,6 @@ UUID DirectMessageService::uuid() const
void DirectMessageService::handle(Context & ctx) const
{
- auto dm = Stored<DirectMessageData>::load(ctx.ref());
- if (!dm)
- return;
-
auto pid = ctx.peer().identity();
if (!pid)
return;
@@ -228,7 +223,7 @@ void DirectMessageService::handle(Context & ctx) const
unique_lock lock(threadLock);
vector<Stored<DirectMessageData>> head(DirectMessageThread::Priv::getThreadLocked(powner).p->head);
- head.push_back(*dm);
+ head.push_back(Stored<DirectMessageData>::load(ctx.ref()));
filterAncestors(head);
auto dmt = DirectMessageThread::Priv::updateThreadLocked(powner, std::move(head));
diff --git a/src/message.h b/src/message.h
index 7e0f597..c4a3549 100644
--- a/src/message.h
+++ b/src/message.h
@@ -19,13 +19,13 @@ namespace erebos {
struct DirectMessageData
{
- static optional<DirectMessageData> load(const Ref &);
+ static DirectMessageData load(const Ref &);
Ref store(const Storage &) const;
vector<Stored<DirectMessageData>> prev;
- Identity from;
- ZonedTime time;
- string text;
+ optional<Identity> from;
+ optional<ZonedTime> time;
+ optional<string> text;
};
struct DirectMessage::Priv
diff --git a/src/network.cpp b/src/network.cpp
index b31d949..91f1923 100644
--- a/src/network.cpp
+++ b/src/network.cpp
@@ -298,7 +298,7 @@ Server::Peer & Server::Priv::getPeer(const sockaddr_in & paddr)
void Server::Priv::handlePacket(Server::Peer & peer, const TransportHeader & header, ReplyBuilder & reply)
{
unordered_set<Digest> plaintextRefs;
- for (const auto & obj : collectStoredObjects(*Stored<Object>::load(*self.ref())))
+ for (const auto & obj : collectStoredObjects(Stored<Object>::load(*self.ref())))
plaintextRefs.insert(obj.ref().digest());
optional<UUID> serviceType;
@@ -397,9 +397,11 @@ void Server::Priv::handlePacket(Server::Peer & peer, const TransportHeader & hea
auto cres = peer.tempStorage.copy(pref);
if (auto r = std::get_if<Ref>(&cres)) {
- if (auto acc = ChannelAccept::load(*r)) {
+ auto acc = ChannelAccept::load(*r);
+ if (holds_alternative<Identity>(peer.identity) &&
+ acc.isSignedBy(std::get<Identity>(peer.identity).keyMessage())) {
reply.header({ TransportHeader::Type::Acknowledged, pref });
- peer.channel.emplace<Stored<Channel>>(acc->data->channel());
+ peer.channel.emplace<Stored<Channel>>(acc.data->channel());
}
}
}
@@ -485,8 +487,10 @@ void Server::Peer::updateChannel(ReplyBuilder & reply)
if (holds_alternative<shared_ptr<WaitingRef>>(channel)) {
if (auto ref = std::get<shared_ptr<WaitingRef>>(channel)->check(reply)) {
- if (auto req = Stored<ChannelRequest>::load(*ref)) {
- if (auto acc = Channel::acceptRequest(server.self, std::get<Identity>(identity), *req)) {
+ auto req = Stored<ChannelRequest>::load(*ref);
+ if (holds_alternative<Identity>(identity) &&
+ req->isSignedBy(std::get<Identity>(identity).keyMessage())) {
+ if (auto acc = Channel::acceptRequest(server.self, std::get<Identity>(identity), req)) {
channel.emplace<Stored<ChannelAccept>>(*acc);
reply.header({ TransportHeader::Type::ChannelAccept, acc->ref() });
reply.body(acc->ref());
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 0e83136..6d85d33 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -8,11 +8,11 @@ using std::string;
using namespace erebos;
-optional<PublicKey> PublicKey::load(const Ref & ref)
+PublicKey PublicKey::load(const Ref & ref)
{
auto rec = ref->asRecord();
if (!rec)
- return nullopt;
+ return PublicKey(nullptr);
if (auto ktype = rec->item("type").asText())
if (ktype.value() != "ed25519")
@@ -22,7 +22,7 @@ optional<PublicKey> PublicKey::load(const Ref & ref)
return PublicKey(EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, nullptr,
pubkey.value().data(), pubkey.value().size()));
- return nullopt;
+ return PublicKey(nullptr);
}
Ref PublicKey::store(const Storage & st) const
@@ -31,12 +31,14 @@ Ref PublicKey::store(const Storage & st) const
items.emplace_back("type", "ed25519");
- vector<uint8_t> keyData;
- size_t keyLen;
- EVP_PKEY_get_raw_public_key(key.get(), nullptr, &keyLen);
- keyData.resize(keyLen);
- EVP_PKEY_get_raw_public_key(key.get(), keyData.data(), &keyLen);
- items.emplace_back("pubkey", keyData);
+ if (key) {
+ vector<uint8_t> keyData;
+ size_t keyLen;
+ EVP_PKEY_get_raw_public_key(key.get(), nullptr, &keyLen);
+ keyData.resize(keyLen);
+ EVP_PKEY_get_raw_public_key(key.get(), keyData.data(), &keyLen);
+ items.emplace_back("pubkey", keyData);
+ }
return st.storeObject(Record(std::move(items)));
}
@@ -110,19 +112,14 @@ vector<uint8_t> SecretKey::sign(const Digest & dgst) const
return sigData;
}
-optional<Signature> Signature::load(const Ref & ref)
+Signature Signature::load(const Ref & ref)
{
- auto rec = ref->asRecord();
- if (!rec)
- return nullopt;
+ if (auto rec = ref->asRecord())
+ if (auto key = rec->item("key").as<PublicKey>())
+ if (auto sig = rec->item("sig").asBinary())
+ return Signature(*key, *sig);
- auto key = rec->item("key").as<PublicKey>();
- auto sig = rec->item("sig").asBinary();
-
- if (!key || !sig)
- return nullopt;
-
- return Signature(*key, *sig);
+ return Signature(Stored<PublicKey>::load(ref.storage().zref()), {});
}
Ref Signature::store(const Storage & st) const
@@ -151,11 +148,11 @@ bool Signature::verify(const Ref & ref) const
}
-optional<PublicKexKey> PublicKexKey::load(const Ref & ref)
+PublicKexKey PublicKexKey::load(const Ref & ref)
{
auto rec = ref->asRecord();
if (!rec)
- return nullopt;
+ return PublicKexKey(nullptr);
if (auto ktype = rec->item("type").asText())
if (ktype.value() != "x25519")
@@ -165,7 +162,7 @@ optional<PublicKexKey> PublicKexKey::load(const Ref & ref)
return PublicKexKey(EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, nullptr,
pubkey.value().data(), pubkey.value().size()));
- return nullopt;
+ return PublicKexKey(nullptr);
}
Ref PublicKexKey::store(const Storage & st) const
@@ -174,12 +171,14 @@ Ref PublicKexKey::store(const Storage & st) const
items.emplace_back("type", "x25519");
- vector<uint8_t> keyData;
- size_t keyLen;
- EVP_PKEY_get_raw_public_key(key.get(), nullptr, &keyLen);
- keyData.resize(keyLen);
- EVP_PKEY_get_raw_public_key(key.get(), keyData.data(), &keyLen);
- items.emplace_back("pubkey", keyData);
+ if (key) {
+ vector<uint8_t> keyData;
+ size_t keyLen;
+ EVP_PKEY_get_raw_public_key(key.get(), nullptr, &keyLen);
+ keyData.resize(keyLen);
+ EVP_PKEY_get_raw_public_key(key.get(), keyData.data(), &keyLen);
+ items.emplace_back("pubkey", keyData);
+ }
return st.storeObject(Record(std::move(items)));
}
diff --git a/src/pubkey.h b/src/pubkey.h
index c922dc7..7b80752 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -18,7 +18,7 @@ class PublicKey
key(key, EVP_PKEY_free) {}
friend class SecretKey;
public:
- static optional<PublicKey> load(const Ref &);
+ static PublicKey load(const Ref &);
Ref store(const Storage &) const;
const shared_ptr<EVP_PKEY> key;
@@ -49,7 +49,7 @@ private:
class Signature
{
public:
- static optional<Signature> load(const Ref &);
+ static Signature load(const Ref &);
Ref store(const Storage &) const;
bool verify(const Ref &) const;
@@ -67,7 +67,7 @@ template<typename T>
class Signed
{
public:
- static optional<Signed<T>> load(const Ref &);
+ static Signed<T> load(const Ref &);
Ref store(const Storage &) const;
bool isSignedBy(const Stored<PublicKey> &) const;
@@ -90,23 +90,20 @@ Stored<Signed<T>> SecretKey::sign(const Stored<T> & val) const
}
template<typename T>
-optional<Signed<T>> Signed<T>::load(const Ref & ref)
+Signed<T> Signed<T>::load(const Ref & ref)
{
- auto rec = ref->asRecord();
- if (!rec)
- return nullopt;
-
- auto data = rec->item("SDATA").as<T>();
- if (!data)
- return nullopt;
-
- vector<Stored<Signature>> sigs;
- for (auto item : rec->items("sig"))
- if (auto sig = item.as<Signature>())
- if (sig.value()->verify(data.value().ref()))
- sigs.push_back(sig.value());
-
- return Signed(*data, sigs);
+ if (auto rec = ref->asRecord())
+ if (auto data = rec->item("SDATA").as<T>()) {
+ vector<Stored<Signature>> sigs;
+ for (auto item : rec->items("sig"))
+ if (auto sig = item.as<Signature>())
+ if (sig.value()->verify(data.value().ref()))
+ sigs.push_back(sig.value());
+
+ return Signed(*data, sigs);
+ }
+
+ return Signed(Stored<T>::load(ref.storage().zref()), {});
}
template<typename T>
@@ -137,7 +134,7 @@ class PublicKexKey
key(key, EVP_PKEY_free) {}
friend class SecretKexKey;
public:
- static optional<PublicKexKey> load(const Ref &);
+ static PublicKexKey load(const Ref &);
Ref store(const Storage &) const;
const shared_ptr<EVP_PKEY> key;
diff --git a/src/storage.cpp b/src/storage.cpp
index 81a70e1..6a0669c 100644
--- a/src/storage.cpp
+++ b/src/storage.cpp
@@ -315,6 +315,11 @@ optional<Ref> Storage::ref(const Digest & digest) const
return Ref::create(*this, digest);
}
+Ref Storage::zref() const
+{
+ return Ref::zcreate(*this);
+}
+
Digest PartialStorage::Priv::storeBytes(const vector<uint8_t> & content) const
{
array<uint8_t, Digest::size> arr;
@@ -346,6 +351,8 @@ optional<vector<uint8_t>> PartialStorage::Priv::loadBytes(const Digest & digest)
optional<PartialObject> PartialStorage::loadObject(const Digest & digest) const
{
+ if (digest.isZero())
+ return PartialObject(monostate());
if (auto content = p->loadBytes(digest))
return PartialObject::decode(*this, *content);
return nullopt;
@@ -362,6 +369,8 @@ PartialRef PartialStorage::storeObject(const Blob & val) const
optional<Object> Storage::loadObject(const Digest & digest) const
{
+ if (digest.isZero())
+ return Object(monostate());
if (auto content = p->loadBytes(digest))
return Object::decode(*this, *content);
return nullopt;
@@ -466,6 +475,13 @@ Digest::operator string() const
return res;
}
+bool Digest::isZero() const
+{
+ for (uint8_t x : value)
+ if (x) return false;
+ return true;
+}
+
PartialRef PartialRef::create(PartialStorage st, const Digest & digest)
{
@@ -517,6 +533,16 @@ optional<Ref> Ref::create(Storage st, const Digest & digest)
return Ref(shared_ptr<Priv>(p));
}
+Ref Ref::zcreate(Storage st)
+{
+ auto p = new Priv {
+ .storage = make_unique<PartialStorage>(st),
+ .digest = Digest(array<uint8_t, Digest::size> {}),
+ };
+
+ return Ref(shared_ptr<Priv>(p));
+}
+
const Object Ref::operator*() const
{
if (auto res = static_cast<Storage*>(p->storage.get())->loadObject(p->digest))
@@ -854,11 +880,9 @@ vector<uint8_t> ObjectT<S>::encode() const
}
template<class S>
-optional<ObjectT<S>> ObjectT<S>::load(const typename S::Ref & ref)
+ObjectT<S> ObjectT<S>::load(const typename S::Ref & ref)
{
- if (ref)
- return *ref;
- return nullopt;
+ return *ref;
}
template<class S>
@@ -899,7 +923,7 @@ vector<Stored<Object>> erebos::collectStoredObjects(const Stored<Object> & from)
if (auto rec = cur->asRecord())
for (const auto & item : rec->items())
if (auto ref = item.asRef())
- queue.push_back(*Stored<Object>::load(*ref));
+ queue.push_back(Stored<Object>::load(*ref));
}
return res;