aboutsummaryrefslogtreecommitdiff
path: root/src/data
diff options
context:
space:
mode:
authorLibravatar buttercat1791 <mjjurkoic@gmail.com>2024-05-14 09:43:25 -0500
committerLibravatar buttercat1791 <mjjurkoic@gmail.com>2024-05-14 09:43:25 -0500
commit5ed5b4a3baec273a9552bbb466d727267eeb8f06 (patch)
treedb6a234d55ec5c32b712212c99219d50c18badb5 /src/data
parent4e558f0c63b0f57196d00c8d1c69139633bfce92 (diff)
Add noscrypt and reorganize namespaces
Diffstat (limited to 'src/data')
-rw-r--r--src/data/event.cpp127
-rw-r--r--src/data/filters.cpp70
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