10#include <internal_use_only/config.hpp>
13#include <nlohmann/json.hpp>
18#include <spdlog/spdlog.h>
61 -> std::optional<core::events::message_received>
63 std::vector<uint8_t> encrypted_bytes;
64 constexpr int hex_base = 16;
65 for (
size_t i = 0; i <
event.content.length(); i += 2) {
66 auto byte_string =
event.content.substr(i, 2);
67 auto byte_value =
static_cast<uint8_t
>(std::stoul(byte_string,
nullptr, hex_base));
68 encrypted_bytes.push_back(byte_value);
74 auto result = bridge_->decrypt_message(event.pubkey, encrypted_bytes);
76 const std::string decrypted_content(result.plaintext.begin(), result.plaintext.end());
78 bridge_->update_last_message_timestamp(event.created_at);
81 auto sender_contact = bridge_->lookup_contact(event.pubkey);
84 .sender_alias = sender_contact.user_alias,
85 .content = decrypted_content,
86 .timestamp =
event.created_at,
87 .should_republish_bundle = result.should_republish_bundle };
98 std::variant<core::events::bundle_announcement_received, core::events::bundle_announcement_removed>>
101 if (not version.has_value()) {
return std::nullopt; }
107 if (event.content.empty()) {
112 .
pubkey =
event.pubkey, .bundle_content =
event.content, .event_id =
event.id
124 std::vector<uint8_t> plaintext_bytes(cmd.message.begin(), cmd.message.end());
125 auto encrypted_bytes = bridge_->encrypt_message(cmd.peer, plaintext_bytes);
127 std::string hex_content;
128 for (
const auto &
byte : encrypted_bytes) { hex_content += fmt::format(
"{:02x}",
byte); }
130 auto signed_event_json = bridge_->create_and_sign_encrypted_message(
131 cmd.peer, hex_content,
static_cast<std::uint32_t
>(std::time(
nullptr)), std::string{ cmake::project_version });
133 auto event_json = nlohmann::json::parse(signed_event_json);
134 const std::string event_id = event_json[
"id"].template get<std::string>();
137 event_data.
id = event_id;
138 event_data.
pubkey = event_json[
"pubkey"].template get<std::string>();
139 event_data.
created_at = event_json[
"created_at"].template get<std::uint64_t>();
140 event_data.kind = event_json[
"kind"].template get<nostr::protocol::kind>();
141 event_data.
content = event_json[
"content"].template get<std::string>();
142 event_data.
sig = event_json[
"sig"].template get<std::string>();
144 for (
const auto &tag : event_json[
"tags"]) {
145 std::vector<std::string> tag_vec;
146 std::ranges::transform(
147 tag, std::back_inserter(tag_vec), [](
const auto &item) {
return item.template get<std::string>(); });
148 event_data.
tags.push_back(tag_vec);
152 auto json_str = protocol_event.serialize();
154 std::vector<std::byte> bytes;
155 bytes.resize(json_str.size());
156 std::ranges::transform(json_str, bytes.begin(), [](
char character) { return std::bit_cast<std::byte>(character); });
158 return { event_id, bytes };
169 const std::string version_str{ radix_relay::cmake::project_version };
170 auto bundle_info = bridge_->generate_prekey_bundle_announcement(version_str);
171 auto event_json = nlohmann::json::parse(bundle_info.announcement_json);
173 const std::string event_id = event_json[
"id"].template get<std::string>();
176 event_data.
id = event_id;
177 event_data.
pubkey = event_json[
"pubkey"].template get<std::string>();
178 event_data.
created_at = event_json[
"created_at"].template get<std::uint64_t>();
179 event_data.kind = event_json[
"kind"].template get<nostr::protocol::kind>();
180 event_data.
content = event_json[
"content"].template get<std::string>();
181 event_data.
sig = event_json[
"sig"].template get<std::string>();
183 for (
const auto &tag : event_json[
"tags"]) {
184 std::vector<std::string> tag_vec;
185 std::ranges::transform(
186 tag, std::back_inserter(tag_vec), [](
const auto &item) {
return item.template get<std::string>(); });
187 event_data.
tags.push_back(tag_vec);
191 auto json_str = protocol_event.serialize();
193 std::vector<std::byte> bytes;
194 bytes.resize(json_str.size());
195 std::ranges::transform(json_str, bytes.begin(), [](
char character) { return std::bit_cast<std::byte>(character); });
198 .bytes = std::move(bytes),
199 .pre_key_id = bundle_info.pre_key_id,
200 .signed_pre_key_id = bundle_info.signed_pre_key_id,
201 .kyber_pre_key_id = bundle_info.kyber_pre_key_id };
211 -> std::pair<std::string, std::vector<std::byte>>
213 const std::string version_str{ radix_relay::cmake::project_version };
214 auto bundle_json = bridge_->generate_empty_bundle_announcement(version_str);
215 auto event_json = nlohmann::json::parse(bundle_json);
217 const std::string event_id = event_json[
"id"].template get<std::string>();
220 event_data.
id = event_id;
221 event_data.
pubkey = event_json[
"pubkey"].template get<std::string>();
222 event_data.
created_at = event_json[
"created_at"].template get<std::uint64_t>();
223 event_data.kind = event_json[
"kind"].template get<nostr::protocol::kind>();
224 event_data.
content = event_json[
"content"].template get<std::string>();
225 event_data.
sig = event_json[
"sig"].template get<std::string>();
227 for (
const auto &tag : event_json[
"tags"]) {
228 std::vector<std::string> tag_vec;
229 std::ranges::transform(
230 tag, std::back_inserter(tag_vec), [](
const auto &item) {
return item.template get<std::string>(); });
231 event_data.
tags.push_back(tag_vec);
235 auto json_str = protocol_event.serialize();
237 std::vector<std::byte> bytes;
238 bytes.resize(json_str.size());
239 std::ranges::transform(json_str, bytes.begin(), [](
char character) { return std::bit_cast<std::byte>(character); });
241 return { event_id, bytes };
258 -> std::optional<core::events::session_established>
260 auto peer_rdx = bridge_->add_contact_and_establish_session_from_base64(cmd.bundle_data,
"");
272 std::vector<std::byte> bytes;
273 bytes.resize(cmd.subscription_json.size());
274 std::ranges::transform(
275 cmd.subscription_json, bytes.begin(), [](
char character) { return std::bit_cast<std::byte>(character); });
277 auto parsed = nlohmann::json::parse(cmd.subscription_json);
278 const std::string subscription_id = parsed[1].get<std::string>();
280 return { subscription_id, bytes };
290 spdlog::debug(
"[nostr_handler] OK received: event_id={}, accepted={}, message={}",
303 spdlog::debug(
"[nostr_handler] EOSE received: subscription_id={}", event.subscription_id);
313 spdlog::warn(
"[nostr_handler] Unknown message kind: {}",
static_cast<std::uint16_t
>(event.kind));
323 spdlog::warn(
"[nostr_handler] Unknown protocol message: {}", event.message);
348 std::shared_ptr<Bridge> bridge_;
Handles processing of incoming and outgoing Nostr messages.
static auto handle(const nostr::events::incoming::identity_announcement &) -> void
Handles an incoming identity announcement (no-op).
auto handle(const core::events::send &cmd) -> std::pair< std::string, std::vector< std::byte > >
Handles a send command by encrypting and serializing a message.
auto handle(const core::events::trust &cmd) -> void
Handles a trust command by assigning an alias to a peer.
static auto handle(const core::events::subscribe &cmd) -> std::pair< std::string, std::vector< std::byte > >
Handles a subscription request.
message_handler(std::shared_ptr< Bridge > bridge)
Constructs a message handler.
auto handle(const nostr::events::incoming::encrypted_message &event) -> std::optional< core::events::message_received >
Handles an incoming encrypted message event.
static auto handle(const nostr::events::incoming::unknown_message &event) -> void
Handles an unknown message type (logs warning).
static auto handle(const nostr::events::incoming::session_request &) -> void
Handles an incoming session request (no-op).
static auto handle(const nostr::events::incoming::unknown_protocol &event) -> void
Handles an unknown protocol message (logs warning).
auto handle(const core::events::unpublish_identity &) -> std::pair< std::string, std::vector< std::byte > >
Handles an unpublish identity command by generating an empty bundle.
static auto handle(const nostr::events::incoming::bundle_announcement &event) -> std::optional< std::variant< core::events::bundle_announcement_received, core::events::bundle_announcement_removed > >
Handles an incoming bundle announcement event.
static auto handle(const nostr::events::incoming::ok &event) -> void
Handles an incoming OK response (logs only).
auto handle(const core::events::publish_identity &) -> publish_bundle_result
Handles a publish identity command by generating and serializing a bundle.
static auto handle(const nostr::events::incoming::node_status &) -> void
Handles an incoming node status update (no-op).
static auto handle(const nostr::events::incoming::eose &event) -> void
Handles an incoming EOSE marker (logs only).
auto handle(const core::events::establish_session &cmd) -> std::optional< core::events::session_established >
Handles session establishment from bundle data.
auto is_version_compatible(const std::string &version_str, const std::string &minimum_version_str) -> bool
Checks if a version meets a minimum version requirement.
constexpr auto bundle_announcement_minimum_version
Minimum protocol version required for bundle announcements.
auto extract_version_from_tags(const std::vector< std::vector< std::string > > &tags) -> std::optional< std::string >
Extracts Radix protocol version from Nostr event tags.
Notification of received bundle announcement.
std::string pubkey
Nostr public key.
Notification of removed bundle announcement.
std::string pubkey
Nostr public key.
Establish session from a received bundle.
Notification of received encrypted message.
std::string sender_rdx
RDX fingerprint of sender.
Publish identity bundle to the network.
Send encrypted message to a specific peer.
Notification of successfully established session.
Subscribe to custom Nostr events.
Establish trust with a peer and assign an alias.
Remove identity bundle from the network.
Received bundle announcement event.
Received encrypted message event (kind 40001)
Received End of Stored Events marker.
Received identity announcement event.
Received node status announcement.
Received OK response from relay.
Received session establishment request.
Received unknown/unrecognized message type.
Received unknown protocol message.
Nostr event data structure.
std::string sig
Schnorr signature (64-byte hex)
std::string id
Event ID (32-byte hex hash)
std::string content
Event content.
std::string pubkey
Public key of event creator (32-byte hex)
std::uint64_t created_at
Unix timestamp.
std::vector< std::vector< std::string > > tags
Event tags (arbitrary string arrays)
static auto from_event_data(const event_data &evt) -> event
Creates an event message from event_data.
Result of publishing a bundle to Nostr.
std::string event_id
Nostr event ID.
std::uint32_t kyber_pre_key_id
Kyber prekey ID used.
std::uint32_t pre_key_id
One-time prekey ID used.
std::uint32_t signed_pre_key_id
Signed prekey ID used.
std::vector< std::byte > bytes
Serialized event bytes.