From 281937e2c5cb6cb760424f67385bef96c4bfe0a1 Mon Sep 17 00:00:00 2001 From: Eric Mertens Date: Thu, 30 Jan 2025 09:28:28 -0800 Subject: [PATCH] split up driver and library --- CMakeLists.txt | 35 +---------------- driver/CMakeLists.txt | 12 ++++++ main.cpp => driver/main.cpp | 16 ++++++-- settings.cpp => driver/settings.cpp | 0 settings.hpp => driver/settings.hpp | 0 myirc/CMakeLists.txt | 31 +++++++++++++++ bot.cpp => myirc/bot.cpp | 0 challenge.cpp => myirc/challenge.cpp | 0 client.cpp => myirc/client.cpp | 35 ++++++++++++----- connection.cpp => myirc/connection.cpp | 4 +- bot.hpp => myirc/include/bot.hpp | 20 +++++----- .../include/c_callback.hpp | 2 + challenge.hpp => myirc/include/challenge.hpp | 9 ++++- client.hpp => myirc/include/client.hpp | 0 .../include/connection.hpp | 39 ++++++++++--------- .../include/irc_command.hpp | 0 .../include/irc_coroutine.hpp | 0 ircmsg.hpp => myirc/include/ircmsg.hpp | 0 .../include/linebuffer.hpp | 0 .../include/openssl_utils.hpp | 0 ref.hpp => myirc/include/ref.hpp | 6 ++- .../include/registration.hpp | 22 +++++++++-- .../include/sasl_mechanism.hpp | 12 ++++-- snote.hpp => myirc/include/snote.hpp | 0 stream.hpp => myirc/include/stream.hpp | 0 .../irc_commands.gperf | 0 ircmsg.cpp => myirc/ircmsg.cpp | 0 openssl_utils.cpp => myirc/openssl_utils.cpp | 0 registration.cpp => myirc/registration.cpp | 6 +-- .../sasl_mechanism.cpp | 12 +++--- snote.cpp => myirc/snote.cpp | 20 +++++----- 31 files changed, 176 insertions(+), 105 deletions(-) create mode 100644 driver/CMakeLists.txt rename main.cpp => driver/main.cpp (83%) rename settings.cpp => driver/settings.cpp (100%) rename settings.hpp => driver/settings.hpp (100%) create mode 100644 myirc/CMakeLists.txt rename bot.cpp => myirc/bot.cpp (100%) rename challenge.cpp => myirc/challenge.cpp (100%) rename client.cpp => myirc/client.cpp (93%) rename connection.cpp => myirc/connection.cpp (99%) rename bot.hpp => myirc/include/bot.hpp (72%) rename c_callback.hpp => myirc/include/c_callback.hpp (76%) rename challenge.hpp => myirc/include/challenge.hpp (60%) rename client.hpp => myirc/include/client.hpp (100%) rename connection.hpp => myirc/include/connection.hpp (89%) rename irc_command.hpp => myirc/include/irc_command.hpp (100%) rename irc_coroutine.hpp => myirc/include/irc_coroutine.hpp (100%) rename ircmsg.hpp => myirc/include/ircmsg.hpp (100%) rename linebuffer.hpp => myirc/include/linebuffer.hpp (100%) rename openssl_utils.hpp => myirc/include/openssl_utils.hpp (100%) rename ref.hpp => myirc/include/ref.hpp (90%) rename registration.hpp => myirc/include/registration.hpp (64%) rename sasl_mechanism.hpp => myirc/include/sasl_mechanism.hpp (79%) rename snote.hpp => myirc/include/snote.hpp (100%) rename stream.hpp => myirc/include/stream.hpp (100%) rename irc_commands.gperf => myirc/irc_commands.gperf (100%) rename ircmsg.cpp => myirc/ircmsg.cpp (100%) rename openssl_utils.cpp => myirc/openssl_utils.cpp (100%) rename registration.cpp => myirc/registration.cpp (97%) rename sasl_mechanism.cpp => myirc/sasl_mechanism.cpp (51%) rename snote.cpp => myirc/snote.cpp (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e94450..bca731c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,38 +26,7 @@ FetchContent_Declare( FetchContent_MakeAvailable(tomlplusplus) FetchContent_MakeAvailable(Boost) -add_custom_command( - OUTPUT irc_commands.inc - COMMAND - gperf - -C -Z IrcCommandHash -K text -L C++ -t - --output-file irc_commands.inc - ${CMAKE_CURRENT_SOURCE_DIR}/irc_commands.gperf - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/irc_commands.gperf - VERBATIM) - add_subdirectory(mybase64) add_subdirectory(mysocks5) - -add_executable(xbot - main.cpp - irc_commands.inc - bot.cpp - challenge.cpp - client.cpp - connection.cpp - ircmsg.cpp - openssl_utils.cpp - registration.cpp - sasl_mechanism.cpp - settings.cpp - snote.cpp -) - -target_include_directories(xbot PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(xbot PRIVATE - OpenSSL::SSL - Boost::signals2 Boost::log Boost::asio - tomlplusplus_tomlplusplus - PkgConfig::LIBHS - mysocks5 mybase64) +add_subdirectory(myirc) +add_subdirectory(driver) diff --git a/driver/CMakeLists.txt b/driver/CMakeLists.txt new file mode 100644 index 0000000..2c7d985 --- /dev/null +++ b/driver/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable(xbot + main.cpp + settings.cpp +) + +target_link_libraries(xbot PRIVATE + myirc + OpenSSL::SSL + Boost::signals2 Boost::log Boost::asio + tomlplusplus_tomlplusplus + PkgConfig::LIBHS + mysocks5 mybase64) diff --git a/main.cpp b/driver/main.cpp similarity index 83% rename from main.cpp rename to driver/main.cpp index 875a14d..ecaa686 100644 --- a/main.cpp +++ b/driver/main.cpp @@ -36,7 +36,16 @@ static auto start(boost::asio::io_context &io, const Settings &settings) -> void const auto connection = std::make_shared(io); const auto client = Client::start(*connection); - Registration::start(settings, client); + Registration::start({ + .nickname = settings.nickname, + .realname = settings.realname, + .username = settings.username, + .password = settings.password, + .sasl_mechanism = settings.sasl_mechanism, + .sasl_authcid = settings.sasl_authcid, + .sasl_authzid = settings.sasl_authzid, + .sasl_password = settings.sasl_password, + }, client); const auto bot = Bot::start(client); @@ -59,7 +68,7 @@ static auto start(boost::asio::io_context &io, const Settings &settings) -> void } ); - bot->sig_command.connect([connection](const Command &cmd) { + bot->sig_command.connect([connection](auto &cmd) { std::cout << "COMMAND " << cmd.command << " from " << cmd.account << std::endl; if (cmd.oper == "glguy" && cmd.command == "ping") { connection->send_notice("glguy", cmd.arguments); @@ -91,7 +100,8 @@ static auto get_settings(const char *filename) -> Settings auto main(int argc, char *argv[]) -> int { - boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::warning); + //boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::warning); + if (argc != 2) { BOOST_LOG_TRIVIAL(error) << "Bad arguments"; return 1; diff --git a/settings.cpp b/driver/settings.cpp similarity index 100% rename from settings.cpp rename to driver/settings.cpp diff --git a/settings.hpp b/driver/settings.hpp similarity index 100% rename from settings.hpp rename to driver/settings.hpp diff --git a/myirc/CMakeLists.txt b/myirc/CMakeLists.txt new file mode 100644 index 0000000..1a31bbe --- /dev/null +++ b/myirc/CMakeLists.txt @@ -0,0 +1,31 @@ +add_custom_command( + OUTPUT irc_commands.inc + COMMAND + gperf + -C -Z IrcCommandHash -K text -L C++ -t + --output-file irc_commands.inc + ${CMAKE_CURRENT_SOURCE_DIR}/irc_commands.gperf + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/irc_commands.gperf + VERBATIM) + +add_library(myirc STATIC + irc_commands.inc + bot.cpp + challenge.cpp + client.cpp + connection.cpp + ircmsg.cpp + openssl_utils.cpp + registration.cpp + sasl_mechanism.cpp + snote.cpp +) + +target_include_directories(myirc PUBLIC include) +target_include_directories(myirc PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(myirc PRIVATE + OpenSSL::SSL + Boost::signals2 Boost::log Boost::asio + tomlplusplus_tomlplusplus + PkgConfig::LIBHS + mysocks5 mybase64) diff --git a/bot.cpp b/myirc/bot.cpp similarity index 100% rename from bot.cpp rename to myirc/bot.cpp diff --git a/challenge.cpp b/myirc/challenge.cpp similarity index 100% rename from challenge.cpp rename to myirc/challenge.cpp diff --git a/client.cpp b/myirc/client.cpp similarity index 93% rename from client.cpp rename to myirc/client.cpp index 8dac02d..1b08e79 100644 --- a/client.cpp +++ b/myirc/client.cpp @@ -224,6 +224,16 @@ auto Client::is_channel(std::string_view name) const -> bool return not name.empty() && channel_prefix_.find(name[0]) != channel_prefix_.npos; } +namespace { + template + struct overloaded : Ts... + { + using Ts::operator()...; + }; + template + overloaded(Ts...) -> overloaded; +} + auto Client::on_authenticate(const std::string_view body) -> void { if (not sasl_mechanism_) @@ -233,16 +243,23 @@ auto Client::on_authenticate(const std::string_view body) -> void return; } - if (auto reply = sasl_mechanism_->step(body)) + std::visit( + overloaded{ + [this](const std::string &reply) { + connection_.send_authenticate_encoded(reply); + }, + [this](SaslMechanism::NoReply) { + connection_.send_authenticate("*"sv); + }, + [this](SaslMechanism::Failure) { + connection_.send_authenticate_abort(); + }, + }, + sasl_mechanism_->step(body)); + + if (sasl_mechanism_->is_complete()) { - - connection_.send_authenticate_encoded(*reply); - - // Clean up completed SASL transactions - if (sasl_mechanism_->is_complete()) - { - sasl_mechanism_.reset(); - } + sasl_mechanism_.reset(); } } diff --git a/connection.cpp b/myirc/connection.cpp similarity index 99% rename from connection.cpp rename to myirc/connection.cpp index db65165..096f4f6 100644 --- a/connection.cpp +++ b/myirc/connection.cpp @@ -467,7 +467,7 @@ auto build_ssl_context( } auto Connection::connect( - ConnectSettings settings + Settings settings ) -> boost::asio::awaitable { using namespace std::placeholders; @@ -539,7 +539,7 @@ auto Connection::connect( stream_.close(); } -auto Connection::start(ConnectSettings settings) -> void +auto Connection::start(Settings settings) -> void { boost::asio::co_spawn( stream_.get_executor(), connect(std::move(settings)), diff --git a/bot.hpp b/myirc/include/bot.hpp similarity index 72% rename from bot.hpp rename to myirc/include/bot.hpp index dedab87..90e70b7 100644 --- a/bot.hpp +++ b/myirc/include/bot.hpp @@ -6,18 +6,18 @@ #include -struct Command -{ - std::string_view source; - std::string_view target; - std::string_view oper; - std::string_view account; - std::string_view command; - std::string_view arguments; -}; - struct Bot : std::enable_shared_from_this { + struct Command + { + std::string_view source; + std::string_view target; + std::string_view oper; + std::string_view account; + std::string_view command; + std::string_view arguments; + }; + std::shared_ptr self_; char command_prefix_; diff --git a/c_callback.hpp b/myirc/include/c_callback.hpp similarity index 76% rename from c_callback.hpp rename to myirc/include/c_callback.hpp index fbf4dcd..652cf6d 100644 --- a/c_callback.hpp +++ b/myirc/include/c_callback.hpp @@ -10,5 +10,7 @@ struct CCallback_ } }; +/// @brief Wrapper for passing closures through C-style callbacks. +/// @tparam F Type of the closure template using CCallback = CCallback_; diff --git a/challenge.hpp b/myirc/include/challenge.hpp similarity index 60% rename from challenge.hpp rename to myirc/include/challenge.hpp index 8c22457..19c7458 100644 --- a/challenge.hpp +++ b/myirc/include/challenge.hpp @@ -8,6 +8,7 @@ #include #include +/// @brief Implements the CHALLENGE command protocol to identify as an operator. class Challenge : std::enable_shared_from_this { EVP_PKEY_Ref key_; @@ -20,5 +21,11 @@ class Challenge : std::enable_shared_from_this public: Challenge(EVP_PKEY_Ref, Connection &); - static auto start(Connection &, std::string_view user, EVP_PKEY_Ref) -> std::shared_ptr; + + /// @brief Starts the CHALLENGE protocol. + /// @param connection Registered connection. + /// @param user Operator username + /// @param key Operator private RSA key + /// @return Handle to the challenge object. + static auto start(Connection &, std::string_view user, EVP_PKEY_Ref key) -> std::shared_ptr; }; diff --git a/client.hpp b/myirc/include/client.hpp similarity index 100% rename from client.hpp rename to myirc/include/client.hpp diff --git a/connection.hpp b/myirc/include/connection.hpp similarity index 89% rename from connection.hpp rename to myirc/include/connection.hpp index d833c25..3dde320 100644 --- a/connection.hpp +++ b/myirc/include/connection.hpp @@ -13,25 +13,26 @@ #include #include -struct ConnectSettings -{ - bool tls; - std::string host; - std::uint16_t port; - - X509_Ref client_cert; - EVP_PKEY_Ref client_key; - std::string verify; - std::string sni; - - std::string socks_host; - std::uint16_t socks_port; - std::string socks_user; - std::string socks_pass; -}; - class Connection : public std::enable_shared_from_this { +public: + struct Settings + { + bool tls; + std::string host; + std::uint16_t port; + + X509_Ref client_cert; + EVP_PKEY_Ref client_key; + std::string verify; + std::string sni; + + std::string socks_host; + std::uint16_t socks_port; + std::string socks_user; + std::string socks_pass; + }; + private: Stream stream_; boost::asio::steady_timer watchdog_timer_; @@ -52,7 +53,7 @@ private: auto watchdog() -> void; auto watchdog_activity() -> void; - auto connect(ConnectSettings settings) -> boost::asio::awaitable; + auto connect(Settings settings) -> boost::asio::awaitable; auto on_authenticate(std::string_view) -> void; /// Build and send well-formed IRC message from individual parameters @@ -78,7 +79,7 @@ public: return stream_.get_executor(); } - auto start(ConnectSettings) -> void; + auto start(Settings) -> void; auto close() -> void; auto send_ping(std::string_view) -> void; diff --git a/irc_command.hpp b/myirc/include/irc_command.hpp similarity index 100% rename from irc_command.hpp rename to myirc/include/irc_command.hpp diff --git a/irc_coroutine.hpp b/myirc/include/irc_coroutine.hpp similarity index 100% rename from irc_coroutine.hpp rename to myirc/include/irc_coroutine.hpp diff --git a/ircmsg.hpp b/myirc/include/ircmsg.hpp similarity index 100% rename from ircmsg.hpp rename to myirc/include/ircmsg.hpp diff --git a/linebuffer.hpp b/myirc/include/linebuffer.hpp similarity index 100% rename from linebuffer.hpp rename to myirc/include/linebuffer.hpp diff --git a/openssl_utils.hpp b/myirc/include/openssl_utils.hpp similarity index 100% rename from openssl_utils.hpp rename to myirc/include/openssl_utils.hpp diff --git a/ref.hpp b/myirc/include/ref.hpp similarity index 90% rename from ref.hpp rename to myirc/include/ref.hpp index 3c117ce..917fd79 100644 --- a/ref.hpp +++ b/myirc/include/ref.hpp @@ -33,8 +33,10 @@ struct Ref : std::unique_ptr> { *this = ref; } Ref &operator=(const Ref &ref) { - RefTraits::UpRef(ref.get()); - this->reset(ref.get()); + if (ref) { + RefTraits::UpRef(ref.get()); + this->reset(ref.get()); + } return *this; } }; diff --git a/registration.hpp b/myirc/include/registration.hpp similarity index 64% rename from registration.hpp rename to myirc/include/registration.hpp index b87d6be..8f8af1f 100644 --- a/registration.hpp +++ b/myirc/include/registration.hpp @@ -2,7 +2,7 @@ #include "connection.hpp" #include "client.hpp" -#include "settings.hpp" +#include "ref.hpp" #include #include @@ -11,7 +11,21 @@ class Registration : public std::enable_shared_from_this { - const Settings &settings_; +public: + struct Settings { + std::string nickname; + std::string username; + std::string realname; + std::string password; + std::string sasl_mechanism; + std::string sasl_authcid; + std::string sasl_authzid; + std::string sasl_password; + EVP_PKEY_Ref sasl_key; + }; + +private: + Settings settings_; std::shared_ptr client_; boost::signals2::scoped_connection slot_; @@ -27,12 +41,12 @@ class Registration : public std::enable_shared_from_this public: Registration( - const Settings &, + Settings, std::shared_ptr ); static auto start( - const Settings &, + Settings, std::shared_ptr ) -> std::shared_ptr; }; diff --git a/sasl_mechanism.hpp b/myirc/include/sasl_mechanism.hpp similarity index 79% rename from sasl_mechanism.hpp rename to myirc/include/sasl_mechanism.hpp index 7e97841..ca693a3 100644 --- a/sasl_mechanism.hpp +++ b/myirc/include/sasl_mechanism.hpp @@ -6,14 +6,20 @@ #include #include #include +#include class SaslMechanism { public: + struct NoReply {}; + struct Failure {}; + + using StepResult = std::variant; + virtual ~SaslMechanism() {} virtual auto mechanism_name() const -> std::string = 0; - virtual auto step(std::string_view msg) -> std::optional = 0; + virtual auto step(std::string_view msg) -> StepResult = 0; virtual auto is_complete() const -> bool = 0; }; @@ -37,7 +43,7 @@ public: return "PLAIN"; } - auto step(std::string_view msg) -> std::optional override; + auto step(std::string_view msg) -> StepResult override; auto is_complete() const -> bool override { @@ -61,7 +67,7 @@ public: return "EXTERNAL"; } - auto step(std::string_view msg) -> std::optional override; + auto step(std::string_view msg) -> StepResult override; auto is_complete() const -> bool override { diff --git a/snote.hpp b/myirc/include/snote.hpp similarity index 100% rename from snote.hpp rename to myirc/include/snote.hpp diff --git a/stream.hpp b/myirc/include/stream.hpp similarity index 100% rename from stream.hpp rename to myirc/include/stream.hpp diff --git a/irc_commands.gperf b/myirc/irc_commands.gperf similarity index 100% rename from irc_commands.gperf rename to myirc/irc_commands.gperf diff --git a/ircmsg.cpp b/myirc/ircmsg.cpp similarity index 100% rename from ircmsg.cpp rename to myirc/ircmsg.cpp diff --git a/openssl_utils.cpp b/myirc/openssl_utils.cpp similarity index 100% rename from openssl_utils.cpp rename to myirc/openssl_utils.cpp diff --git a/registration.cpp b/myirc/registration.cpp similarity index 97% rename from registration.cpp rename to myirc/registration.cpp index 68695da..d116201 100644 --- a/registration.cpp +++ b/myirc/registration.cpp @@ -9,10 +9,10 @@ #include Registration::Registration( - const Settings &settings, + Settings settings, std::shared_ptr client ) - : settings_{settings} + : settings_{std::move(settings)} , client_{std::move(client)} { } @@ -95,7 +95,7 @@ auto Registration::on_cap_list(const std::unordered_map client ) -> std::shared_ptr { diff --git a/sasl_mechanism.cpp b/myirc/sasl_mechanism.cpp similarity index 51% rename from sasl_mechanism.cpp rename to myirc/sasl_mechanism.cpp index d7ff9e4..65b6429 100644 --- a/sasl_mechanism.cpp +++ b/myirc/sasl_mechanism.cpp @@ -1,8 +1,8 @@ #include "sasl_mechanism.hpp" -auto SaslPlain::step(std::string_view msg) -> std::optional { +auto SaslPlain::step(std::string_view msg) -> StepResult { if (complete_) { - return std::nullopt; + return Failure{}; } else { std::string reply; @@ -14,14 +14,14 @@ auto SaslPlain::step(std::string_view msg) -> std::optional { complete_ = true; - return {std::move(reply)}; + return std::move(reply); } } -auto SaslExternal::step(std::string_view msg) -> std::optional { +auto SaslExternal::step(std::string_view msg) -> StepResult { if (complete_) { - return std::nullopt; + return Failure{}; } else { - return {std::move(authzid_)}; + return std::move(authzid_); } } diff --git a/snote.cpp b/myirc/snote.cpp similarity index 99% rename from snote.cpp rename to myirc/snote.cpp index bed7a60..5d70178 100644 --- a/snote.cpp +++ b/myirc/snote.cpp @@ -73,7 +73,7 @@ const SnotePattern static patterns[] = { {SnoteTag::KilledRemoteOper, R"(^Received KILL message for ([^ ]+)!([^ ]+)@([^ ]+)\. From ([^ ]+) Path: ([^ ]+)!([^ ]+)!([^ ]+)!([^ ]+) (.*)$)"}, - + {SnoteTag::Killed, R"(^Received KILL message for ([^ ]+)!([^ ]+)@([^ ]+)\. From ([^ ]+) (.*)$)"}, @@ -90,11 +90,11 @@ const SnotePattern static patterns[] = { R"(^([^ ]+) \(([^ ]+)!([^ ]+)@([^ ]+)\) is now an operator$)"}, {SnoteTag::OperspyWhois, - R"(^OPERSPY ([^ ]+)!([^ ]+)@([^ ]+)\{([^ ]+)\} WHOIS ([^ ]+)!([^ ]+)@([^ ]+) ([^ ]+)$)"}, + R"(^OPERSPY ([^ ]+)!([^ ]+)@([^ ]+)\{([^ ]+)\} WHOIS ([^ ]+)!([^ ]+)@([^ ]+) ([^ ]+) $)"}, // trailing space intentional {SnoteTag::Freeze, "^\x02([^ ]+)\x02 froze the account \x02([^ ]+)\x02 \\((.*)\\)\\.$"}, - + {SnoteTag::DroppedChannel, "^\x02([^ ]+)\x02 dropped the channel \x02([^ ]+)\x02$"}, @@ -112,28 +112,28 @@ const SnotePattern static patterns[] = { {SnoteTag::TemporaryDline, R"(^([^ ]+) added temporary ([^ ]+) min\. D-Line for \[([^ ]+)\] \[(.*)\]$)"}, - + {SnoteTag::FailedChallengeMissingSecure, R"(^Failed CHALLENGE attempt - missing secure connection by ([^ ]+) \(([^ ]+)@([^ ]+)\)$)"}, - + {SnoteTag::FailedChallenge, R"(^Failed CHALLENGE attempt by ([^ ]+) \(([^ ]+)@([^ ]+)\)$)"}, - + {SnoteTag::FailedChallengeHostMismatch, R"(^Failed CHALLENGE attempt - host mismatch by ([^ ]+) \(([^ ]+)@([^ ]+)\)$)"}, - + {SnoteTag::FailedChallengeNoBlock, R"(^Failed CHALLENGE attempt - user@host mismatch or no operator block for ([^ ]+) by ([^ ]+) \(([^ ]+)@([^ ]+)\)$)"}, - + {SnoteTag::FailedChallengeTls, R"(^Failed CHALLENGE attempt - missing SSL/TLS by ([^ ]+) \(([^ ]+)@([^ ]+)\)$)"}, - + {SnoteTag::FailedChallengeFingerprintMismatch, R"(^Failed CHALLENGE attempt - client certificate fingerprint mismatch by ([^ ]+) \(([^ ]+)@([^ ]+)\)$)"}, {SnoteTag::SighupReloadingConf, R"(^Got signal SIGHUP, reloading ircd conf\. file$)"}, - + {SnoteTag::JoinedJuped, R"(^User ([^ ]+) \(([^ ]+)@([^ ]+)\) is attempting to join locally juped channel ([^ ]+) \((.*)\)$)"},