Created
September 11, 2024 08:06
-
-
Save liamcottle/e85953bccd6a4f8b436ac4284b29af49 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <MsgPack.h> | |
size_t maxEncryptedPackageMaxContentLength() { | |
// LXMF overhead is 111 bytes per message: | |
// 16 bytes for destination hash | |
// 16 bytes for source hash | |
// 64 bytes for Ed25519 signature | |
// 8 bytes for timestamp | |
// 7 bytes for msgpack structure | |
// LXMF_OVERHEAD = 2*DESTINATION_LENGTH + SIGNATURE_LENGTH + 8 + 7 | |
size_t DESTINATION_LENGTH = 16; | |
size_t LXMF_OVERHEAD = 111; | |
return RNS::Type::Packet::ENCRYPTED_MDU - LXMF_OVERHEAD + DESTINATION_LENGTH; | |
} | |
void sendMessage(RNS::Identity sourceIdentity, RNS::Identity destinationIdentity, const char *content) { | |
// create destinations (using OUT for source, to avoid registering it, as we just want the hash) | |
RNS::Destination source = RNS::Destination(sourceIdentity, RNS::Type::Destination::OUT, RNS::Type::Destination::SINGLE, "lxmf", "delivery"); | |
RNS::Destination destination = RNS::Destination(destinationIdentity, RNS::Type::Destination::OUT, RNS::Type::Destination::SINGLE, "lxmf", "delivery"); | |
// create lxmf payload data | |
const char *title = ""; | |
float timestamp = millis(); // FIXME: this should be a unix timestamp of when message is sent, but we have no clock... | |
// msgpack the payload | |
// self.payload = [self.timestamp, self.title, self.content, self.fields] | |
// NOTE: the payload needs to be unique, otherwise it will have the same hash and be ignored by recipients, so we use millis for timestamp... | |
MsgPack::Packer packer; | |
packer.packArraySize(4); // we are msgpacking an array with 4 entries | |
packer.packFloat(timestamp); // timestamp | |
packer.packBinary((const uint8_t*)title, strlen(title)); // title (must be sent as bytes, not string) | |
packer.packBinary((const uint8_t*)content, strlen(content)); // content (must be sent as bytes, not string) | |
packer.packMapSize(0); // fields | |
RNS::Bytes packed_payload = RNS::Bytes(packer.data(), packer.size()); | |
// hashed part | |
RNS::Bytes hashed_part; | |
hashed_part.append(destination.hash()); // self.__destination.hash | |
hashed_part.append(source.hash()); // self.__source.hash | |
hashed_part.append(packed_payload); // msgpack.packb(self.payload) | |
RNS::Bytes hash = RNS::Identity::full_hash(hashed_part); | |
RNS::Bytes message_id = hash; | |
// signed part | |
RNS::Bytes signed_part; | |
signed_part.append(hashed_part); // signed_part += hashed_part | |
signed_part.append(hash); // self.hash | |
RNS::Bytes signature = source.sign(signed_part); // self.__source.sign(signed_part) | |
// packed | |
RNS::Bytes packed; | |
// packed.append(lxmf_destination.hash()); // self.__destination.hash (opportunistic lxmf messages dont send destination in packed data?) | |
packed.append(source.hash()); // self.__source.hash | |
packed.append(signature); // self.signature | |
packed.append(packed_payload); // msgpack.packb(self.payload) | |
size_t content_size = packed.size(); | |
// ensure content size is not larger than allowed | |
if(content_size > maxEncryptedPackageMaxContentLength()){ | |
ERROR("[LXMF] content exceeds single-packet size."); | |
return; | |
} | |
// send packet | |
RNS::Packet packet = RNS::Packet(destination, packed); | |
if(packet.send()){ | |
INFO("[LXMF] message sent!"); | |
} else { | |
ERROR("[LXMF] failed to send!"); | |
} | |
} | |
void onMeshNodePacket(const RNS::Bytes& data, const RNS::Packet& packet) { | |
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); | |
INFO("onMeshNodePacket: data: " + data.toHex()); | |
INFO("onMeshNodePacket: text: \"" + data.toString() + "\""); | |
//TRACE("onMeshNodePacket: " + packet.debugString()); | |
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); | |
std::string str = data.toString(); | |
std::string from = str.substr(0, 32); | |
std::string message = str.substr(32); | |
INFO("from: \"" + from + "\", message: " + message); | |
// find identity of "from" | |
RNS::Bytes fromHash; | |
fromHash.assignHex(from.c_str()); | |
RNS::Identity destinationIdentity = RNS::Identity::recall(fromHash); | |
if(destinationIdentity == RNS::Type::NONE){ | |
INFO("could not find identity for hash: \"" + from + "\""); | |
return; | |
} | |
// echo received messages back to sender | |
sendMessage(RNS::Transport::identity(), destinationIdentity, message.c_str()); | |
} | |
void onLxmfDeliveryPacket(const RNS::Bytes& data, const RNS::Packet& packet) { | |
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); | |
INFO("onLxmfDeliveryPacket: data: " + data.toHex()); | |
INFO("onLxmfDeliveryPacket: text: \"" + data.toString() + "\""); | |
//TRACE("onLxmfDeliveryPacket: " + packet.debugString()); | |
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); | |
// parse sections from lxmf data | |
RNS::Bytes source = data.mid(0, 16); | |
RNS::Bytes signature = data.mid(16, 16 + 64); | |
RNS::Bytes packed_payload = data.mid(16 + 64); | |
INFO("LXMF: source: " + source.toHex()); | |
INFO("LXMF: signature: " + signature.toHex()); | |
INFO("LXMF: packed_payload: " + packed_payload.toHex()); | |
// FIXME: validate signatures | |
// un-msgpack the payload | |
MsgPack::Unpacker unpacker; | |
unpacker.feed(packed_payload.data(), packed_payload.size()); // pass packed data to unpacker | |
size_t arraySize = unpacker.unpackArraySize(); // we expect to be un-msgpacking an array with 4 entries | |
float timestamp = unpacker.unpackFloat(); // timestamp | |
MsgPack::bin_t<uint8_t> titleBytes = unpacker.unpackBinary(); | |
MsgPack::bin_t<uint8_t> contentBytes = unpacker.unpackBinary(); | |
// size_t fieldsSize = unpacker.unpackMapSize(); | |
// convert bytes to strings | |
char* title = reinterpret_cast<char*>(titleBytes.data()); | |
char* content = reinterpret_cast<char*>(contentBytes.data()); | |
// log | |
INFO("LXMF: timestamp: " + std::to_string(timestamp)); | |
INFO(title); | |
INFO(content); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment