diff options
author | buttercat1791 <mjjurkoic@gmail.com> | 2024-05-14 09:43:25 -0500 |
---|---|---|
committer | buttercat1791 <mjjurkoic@gmail.com> | 2024-05-14 09:43:25 -0500 |
commit | 5ed5b4a3baec273a9552bbb466d727267eeb8f06 (patch) | |
tree | db6a234d55ec5c32b712212c99219d50c18badb5 /src/data | |
parent | 4e558f0c63b0f57196d00c8d1c69139633bfce92 (diff) |
Add noscrypt and reorganize namespaces
Diffstat (limited to 'src/data')
-rw-r--r-- | src/data/event.cpp | 127 | ||||
-rw-r--r-- | src/data/filters.cpp | 70 |
2 files changed, 197 insertions, 0 deletions
diff --git a/src/data/event.cpp b/src/data/event.cpp new file mode 100644 index 0000000..620ee3f --- /dev/null +++ b/src/data/event.cpp @@ -0,0 +1,127 @@ +#include "data/data.hpp" + +using namespace nlohmann; +using namespace std; + +namespace nostr +{ +namespace data +{ +string Event::serialize() +{ + try + { + this->validate(); + } + catch (const invalid_argument& e) + { + throw e; + } + + json j = { + {"pubkey", this->pubkey}, + {"created_at", this->createdAt}, + {"kind", this->kind}, + {"tags", this->tags}, + {"content", this->content}, + {"sig", this->sig}}; + + j["id"] = this->generateId(j.dump()); + + return j.dump(); +}; + +Event Event::fromString(string jstr) +{ + json j = json::parse(jstr); + Event event; + + try + { + event = Event::fromJson(j); + } + catch (const invalid_argument& e) + { + throw e; + } + + return event; +}; + +Event Event::fromJson(json j) +{ + Event event; + + try { + event.id = j.at("id"); + event.pubkey = j.at("pubkey"); + event.createdAt = j.at("created_at"); + event.kind = j.at("kind"); + event.tags = j.at("tags"); + event.content = j.at("content"); + event.sig = j.at("sig"); + } catch (const json::out_of_range& e) { + ostringstream oss; + oss << "Event::fromJson: Tried to access an out-of-range element: " << e.what(); + throw invalid_argument(oss.str()); + } + + return event; +}; + +void Event::validate() +{ + bool hasPubkey = this->pubkey.length() > 0; + if (!hasPubkey) + { + throw std::invalid_argument("Event::validate: The pubkey of the event author is required."); + } + + bool hasCreatedAt = this->createdAt > 0; + if (!hasCreatedAt) + { + this->createdAt = time(nullptr); + } + + bool hasKind = this->kind >= 0 && this->kind < 40000; + if (!hasKind) + { + throw std::invalid_argument("Event::validate: A valid event kind is required."); + } + + bool hasSignature = this->sig.length() > 0; + if (!hasSignature) + { + throw std::invalid_argument("Event::validate: The event must be signed."); + } +}; + +string Event::generateId(string serializedData) const +{ + unsigned char hash[SHA256_DIGEST_LENGTH]; + EVP_Digest(serializedData.c_str(), serializedData.length(), hash, NULL, EVP_sha256(), NULL); + + stringstream ss; + for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) + { + ss << hex << setw(2) << setfill('0') << (int)hash[i]; + } + + return ss.str(); +}; + +bool Event::operator==(const Event& other) const +{ + if (this->id.empty()) + { + throw invalid_argument("Event::operator==: Cannot check equality, the left-side argument is undefined."); + } + if (other.id.empty()) + { + throw invalid_argument("Event::operator==: Cannot check equality, the right-side argument is undefined."); + } + + return this->id == other.id; +}; +} // namespace data +} // namespace nostr diff --git a/src/data/filters.cpp b/src/data/filters.cpp new file mode 100644 index 0000000..7e1c744 --- /dev/null +++ b/src/data/filters.cpp @@ -0,0 +1,70 @@ +#include "data/data.hpp" + +using namespace nlohmann; +using namespace std; + +namespace nostr +{ +namespace data +{ +string Filters::serialize(string& subscriptionId) +{ + try + { + this->validate(); + } + catch (const invalid_argument& e) + { + throw e; + } + + json j = { + {"ids", this->ids}, + {"authors", this->authors}, + {"kinds", this->kinds}, + {"since", this->since}, + {"until", this->until}, + {"limit", this->limit}}; + + for (auto& tag : this->tags) + { + stringstream ss; + ss << "#" << tag.first; + string tagname = ss.str(); + + j[tagname] = tag.second; + } + + json jarr = json::array({ "REQ", subscriptionId, j }); + + return jarr.dump(); +}; + +void Filters::validate() +{ + bool hasLimit = this->limit > 0; + if (!hasLimit) + { + throw invalid_argument("Filters::validate: The limit must be greater than 0."); + } + + bool hasUntil = this->until > 0; + if (!hasUntil) + { + this->until = time(nullptr); + } + + bool hasIds = this->ids.size() > 0; + bool hasAuthors = this->authors.size() > 0; + bool hasKinds = this->kinds.size() > 0; + bool hasTags = this->tags.size() > 0; + + bool hasFilter = hasIds || hasAuthors || hasKinds || hasTags; + + if (!hasFilter) + { + throw invalid_argument("Filters::validate: At least one filter must be set."); + } +}; +} // namespace data +} // namespace nostr |