diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index e6284704..4c02a459 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -16,6 +16,9 @@ namespace Components Loader::Register(new Maps()); Loader::Register(new News()); Loader::Register(new Node()); +#ifndef DISABLE_BITMESSAGE + Loader::Register(new BitMessage()); +#endif Loader::Register(new RCon()); Loader::Register(new Menus()); Loader::Register(new Toast()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 4681166e..5a18b299 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -49,6 +49,7 @@ namespace Components #include "Modules\Network.hpp" #include "Modules\Theatre.hpp" #include "Modules\Node.hpp" +#include "Modules\BitMessage.hpp" #include "Modules\RCon.hpp" #include "Modules\Party.hpp" // Destroys the order, but requires network classes :D #include "Modules\Download.hpp" diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp new file mode 100644 index 00000000..69fe6f21 --- /dev/null +++ b/src/Components/Modules/BitMessage.cpp @@ -0,0 +1,261 @@ +#include "STDInclude.hpp" + +#ifndef DISABLE_BITMESSAGE + +#include + +using namespace Utils; + +namespace Components +{ + BitMessage* BitMessage::Singleton = nullptr; + + BitMessage::BitMessage() + { + if (Singleton != nullptr) + { + throw new std::runtime_error("Only 1 BitMessage instance allowed at the same time."); + } + Singleton = this; + + Logger::Print("Initializing BitMessage...\n"); + this->LoadObjectsAndKeys(); + this->LoadNodes(); + + if (this->BMClient->PrivAddresses.empty()) + { + if (!this->InitAddr()) + { + // Generate a random address ready to use + throw std::runtime_error("Failed to prepare source address for exception handling"); + } + this->SaveObjectsAndKeys(); + } + + this->BMClient->start(); + + Command::Add("bm_sendb", [](Command::Params) { + ustring msg; + msg.appendVarString("testing"); + Singleton->BMClient->sendBroadcast(msg, Singleton->BMClient->PrivAddresses[0]); + }); + Command::Add("bm_check_messages", [](Command::Params) { + while (Singleton->BMClient->new_messages.size() > 0) + { + auto msg = Singleton->BMClient->new_messages.pop(); + Logger::Print("New message:\nFrom: %s\nTo: %s\nMessage:\n%s\n", msg.from.c_str(), msg.to.c_str(), msg.info.c_str()); + } + }); + Command::Add("bm_check_connections", [](Command::Params) { + std::shared_lock mlock(Singleton->BMClient->mutex_nodes); + + for (auto& node : Singleton->BMClient->Nodes) + { + switch (node->state) { + case 0: // Not connected + Logger::Print("%s: Disconnected\n", node->Ip.c_str()); + break; + case 1: // Connecting + Logger::Print("%s: Connecting\n", node->Ip.c_str()); + break; + case 2: // Connected + Logger::Print("%s: Connected\n", node->Ip.c_str()); + break; + case 3: // Reconnecting + Logger::Print("%s: Reconnecting\n", node->Ip.c_str()); + break; + } + } + + mlock.unlock(); + }); + Command::Add("bm_check_privatekey", [](Command::Params) { + std::shared_lock mlock(Singleton->BMClient->mutex_priv); + + if (Singleton->BMClient->PrivAddresses.empty()) { + Logger::Print("No private key\n"); + } + else + for (auto& addr : Singleton->BMClient->PrivAddresses) + { + Logger::Print("%s\n", addr.getAddress().c_str()); + } + + mlock.unlock(); + }); + Command::Add("bm_check_publickey", [](Command::Params) { + std::shared_lock mlock(Singleton->BMClient->mutex_pub); + + if (Singleton->BMClient->PubAddresses.empty()) { + Logger::Print("No public key\n"); + } + else + for (auto& addr : Singleton->BMClient->PubAddresses) + { + Logger::Print("%s\n", addr.getAddress().c_str()); + } + + mlock.unlock(); + }); + Command::Add("bm_save", [](Command::Params) { + Singleton->BMClient->save(BITMESSAGE_OBJECT_STORAGE_FILENAME); + }); + Command::Add("bm_save_nodes", [](Command::Params) { + Singleton->SaveNodes(); + }); + Command::Add("bm_address_public", [](Command::Params params) { + if (params.Length() < 1) return; + + ustring addre; + addre.fromString(params[0]); + PubAddr address; + if (address.loadAddr(addre)) + { + Logger::Print("Asking public key!\n"); + Singleton->BMClient->getPubKey(address); + Logger::Print("Asked! check publickey for news on that address!\n"); + } + else + { + Logger::Print("Address not correct!\n"); + } + }); + Command::Add("bm_address_broadcast", [](Command::Params params) { + if (params.Length() < 1) return; + + ustring addre; + addre.fromString(params[0]); + PubAddr address; + if (address.loadAddr(addre)) + { + Logger::Print("Adding subscription!\n"); + Singleton->BMClient->addSubscription(address); + } + else + { + Logger::Print("Address not correct!\n"); + } + }); + } + + bool BitMessage::InitAddr() + { + Logger::Print("Generating BM address...\n"); + Addr myAddress; + if (!myAddress.generateRandom()) + { + return false; + } + BMClient->addAddr(myAddress); + return true; + } + + void BitMessage::LoadObjectsAndKeys() + { + Logger::Print("Loading BM objects and keys...\n"); + this->BMClient->load(BITMESSAGE_OBJECT_STORAGE_FILENAME); + } + + void BitMessage::SaveObjectsAndKeys() + { + Logger::Print("Saving BM objects and keys...\n"); + this->BMClient->save(BITMESSAGE_OBJECT_STORAGE_FILENAME); + } + + void BitMessage::SaveNodes() + { + Logger::Print("Saving BM nodes...\n"); + Proto::Node::List list; + std::vector nodeList; // keep track of dupes + + std::shared_lock mlock(Singleton->BMClient->mutex_nodes); + + for (auto& node : Singleton->BMClient->Nodes) + { + std::string nodeStr = String::VA("%s:%s", node->Ip.c_str(), node->Port.c_str()); + switch (node->state) { + case 0: // Not connected + break; + case 1: // Connecting + break; + case 2: // Connected + if (std::find(nodeList.begin(), nodeList.end(), nodeStr) == nodeList.end()) + { + // This allows us to keep track of duplicates + nodeList.push_back(nodeStr); + + DWORD ip = 0; + unsigned short port = 0; + sscanf_s(nodeStr.c_str(), "%d.%d.%d.%d:%hu", &ip, &ip + 1, &ip + 2, &ip + 3, &port); + + Network::Address address; + address.SetIP(ip); + address.SetPort(port); + + address.Serialize(list.add_address()); + + Logger::Print("Saved node: %s\n", address.GetCString()); + } + break; + case 3: // Reconnecting + break; + } + } + + mlock.unlock(); + + if (list.address_size() <= 0) + return; + + // Create directory if it doesn't exist yet + auto dirName = const_cast(BITMESSAGE_NODE_STORAGE_FILENAME.c_str()); + PathRemoveFileSpecA(dirName); + CreateDirectoryA(dirName, NULL); + + // Now write the actual file + Utils::IO::WriteFile(BITMESSAGE_NODE_STORAGE_FILENAME, list.SerializeAsString()); + } + + void BitMessage::LoadNodes() + { + Logger::Print("Loading BM nodes...\n"); + // Load nodes stored in file + Proto::Node::List list; + std::string nodes = IO::ReadFile(BITMESSAGE_NODE_STORAGE_FILENAME); + if (!nodes.empty() && list.ParseFromString(nodes)) + { + for (int i = 0; i < list.address_size(); ++i) + { + Network::Address address = list.address(i); + + this->BMClient->connectNode(new NodeConnection( + String::VA("%d.%d.%d.%d", address.GetIP().bytes[0], address.GetIP().bytes[1], address.GetIP().bytes[2], address.GetIP().bytes[3]), // urgh. + String::VA("%d", address.GetPort()), this->BMClient)); + } + } + + // Load default nodes if not connected to yet + for (auto addr : bitmessageKnownNodes) { + auto portStr = std::string(String::VA("%d", addr.second)); + if (!this->HasNode(addr.first, portStr)) + { + this->BMClient->connectNode(new NodeConnection(addr.first, portStr, this->BMClient)); + } + } + } + + bool BitMessage::HasNode(std::string ip, std::string port) + { + for (auto& node : this->BMClient->Nodes) + { + if (node->Ip == ip && node->Port == port) + { + return true; + } + } + + return false; + } +} + +#endif \ No newline at end of file diff --git a/src/Components/Modules/BitMessage.hpp b/src/Components/Modules/BitMessage.hpp new file mode 100644 index 00000000..8eb67952 --- /dev/null +++ b/src/Components/Modules/BitMessage.hpp @@ -0,0 +1,56 @@ +#pragma once + +#ifndef DISABLE_BITMESSAGE + +#define BITMESSAGE_NODE_STORAGE_FILENAME std::string("players/bmnodes.dat") +#define BITMESSAGE_OBJECT_STORAGE_FILENAME std::string("save") + +static const std::map bitmessageKnownNodes = { + // https://github.com/Bitmessage/PyBitmessage/blob/4622d952e47a7dbb3a90aa79f4d20163aa14b041/src/defaultKnownNodes.py#L15-L23 + + // Stream 1 + //{ "2604:2000:1380:9f:82e:148b:2746:d0c7", 8080 }, + { "5.45.99.75", 8444 }, + { "75.167.159.54", 8444 }, + { "95.165.168.168", 8444 }, + { "85.180.139.241", 8444 }, + { "158.222.211.81", 8080 }, + { "178.62.12.187", 8448 }, + { "24.188.198.204", 8111 }, + { "109.147.204.113", 1195 }, + { "178.11.46.221", 8444 }, + + // Stream 2 has none yet + + // Stream 3 has none yet +}; + +namespace Components +{ + class BitMessage : public Component + { + public: + BitMessage(); + +#ifdef DEBUG + const char* GetName() { return "BitMessage"; }; +#endif + + static BitMessage* Singleton; + BitMRC* BMClient = new BitMRC(); + + void SaveNodes(); + bool HasNode(std::string ip, std::string port); + + void SaveObjectsAndKeys(); + + private: + void LoadNodes(); + + void LoadObjectsAndKeys(); + + bool InitAddr(); + }; +} + +#endif \ No newline at end of file