split up driver and library
This commit is contained in:
parent
5218ea0892
commit
281937e2c5
@ -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)
|
||||
|
12
driver/CMakeLists.txt
Normal file
12
driver/CMakeLists.txt
Normal file
@ -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)
|
@ -36,7 +36,16 @@ static auto start(boost::asio::io_context &io, const Settings &settings) -> void
|
||||
|
||||
const auto connection = std::make_shared<Connection>(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;
|
31
myirc/CMakeLists.txt
Normal file
31
myirc/CMakeLists.txt
Normal file
@ -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)
|
@ -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 <class... Ts>
|
||||
struct overloaded : Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
};
|
||||
template <class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
}
|
||||
|
||||
auto Client::on_authenticate(const std::string_view body) -> void
|
||||
{
|
||||
if (not sasl_mechanism_)
|
||||
@ -233,18 +243,25 @@ 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));
|
||||
|
||||
connection_.send_authenticate_encoded(*reply);
|
||||
|
||||
// Clean up completed SASL transactions
|
||||
if (sasl_mechanism_->is_complete())
|
||||
{
|
||||
sasl_mechanism_.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Client::start_sasl(std::unique_ptr<SaslMechanism> mechanism) -> void
|
||||
{
|
@ -467,7 +467,7 @@ auto build_ssl_context(
|
||||
}
|
||||
|
||||
auto Connection::connect(
|
||||
ConnectSettings settings
|
||||
Settings settings
|
||||
) -> boost::asio::awaitable<void>
|
||||
{
|
||||
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)),
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct Bot : std::enable_shared_from_this<Bot>
|
||||
{
|
||||
struct Command
|
||||
{
|
||||
std::string_view source;
|
||||
@ -16,8 +18,6 @@ struct Command
|
||||
std::string_view arguments;
|
||||
};
|
||||
|
||||
struct Bot : std::enable_shared_from_this<Bot>
|
||||
{
|
||||
std::shared_ptr<Client> self_;
|
||||
char command_prefix_;
|
||||
|
@ -10,5 +10,7 @@ struct CCallback_<R (F::*) (Ts...) const>
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Wrapper for passing closures through C-style callbacks.
|
||||
/// @tparam F Type of the closure
|
||||
template <typename F>
|
||||
using CCallback = CCallback_<decltype(&F::operator())>;
|
@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
/// @brief Implements the CHALLENGE command protocol to identify as an operator.
|
||||
class Challenge : std::enable_shared_from_this<Challenge>
|
||||
{
|
||||
EVP_PKEY_Ref key_;
|
||||
@ -20,5 +21,11 @@ class Challenge : std::enable_shared_from_this<Challenge>
|
||||
|
||||
public:
|
||||
Challenge(EVP_PKEY_Ref, Connection &);
|
||||
static auto start(Connection &, std::string_view user, EVP_PKEY_Ref) -> std::shared_ptr<Challenge>;
|
||||
|
||||
/// @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<Challenge>;
|
||||
};
|
@ -13,7 +13,10 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct ConnectSettings
|
||||
class Connection : public std::enable_shared_from_this<Connection>
|
||||
{
|
||||
public:
|
||||
struct Settings
|
||||
{
|
||||
bool tls;
|
||||
std::string host;
|
||||
@ -30,8 +33,6 @@ struct ConnectSettings
|
||||
std::string socks_pass;
|
||||
};
|
||||
|
||||
class Connection : public std::enable_shared_from_this<Connection>
|
||||
{
|
||||
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<void>;
|
||||
auto connect(Settings settings) -> boost::asio::awaitable<void>;
|
||||
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;
|
@ -33,8 +33,10 @@ struct Ref : std::unique_ptr<T, FnDeleter<T>> {
|
||||
*this = ref;
|
||||
}
|
||||
Ref &operator=(const Ref &ref) {
|
||||
if (ref) {
|
||||
RefTraits<T>::UpRef(ref.get());
|
||||
this->reset(ref.get());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "connection.hpp"
|
||||
#include "client.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "ref.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -11,7 +11,21 @@
|
||||
|
||||
class Registration : public std::enable_shared_from_this<Registration>
|
||||
{
|
||||
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> client_;
|
||||
|
||||
boost::signals2::scoped_connection slot_;
|
||||
@ -27,12 +41,12 @@ class Registration : public std::enable_shared_from_this<Registration>
|
||||
|
||||
public:
|
||||
Registration(
|
||||
const Settings &,
|
||||
Settings,
|
||||
std::shared_ptr<Client>
|
||||
);
|
||||
|
||||
static auto start(
|
||||
const Settings &,
|
||||
Settings,
|
||||
std::shared_ptr<Client>
|
||||
) -> std::shared_ptr<Registration>;
|
||||
};
|
@ -6,14 +6,20 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
class SaslMechanism
|
||||
{
|
||||
public:
|
||||
struct NoReply {};
|
||||
struct Failure {};
|
||||
|
||||
using StepResult = std::variant<std::string, NoReply, Failure>;
|
||||
|
||||
virtual ~SaslMechanism() {}
|
||||
|
||||
virtual auto mechanism_name() const -> std::string = 0;
|
||||
virtual auto step(std::string_view msg) -> std::optional<std::string> = 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<std::string> 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<std::string> override;
|
||||
auto step(std::string_view msg) -> StepResult override;
|
||||
|
||||
auto is_complete() const -> bool override
|
||||
{
|
@ -9,10 +9,10 @@
|
||||
#include <unordered_map>
|
||||
|
||||
Registration::Registration(
|
||||
const Settings &settings,
|
||||
Settings settings,
|
||||
std::shared_ptr<Client> client
|
||||
)
|
||||
: settings_{settings}
|
||||
: settings_{std::move(settings)}
|
||||
, client_{std::move(client)}
|
||||
{
|
||||
}
|
||||
@ -95,7 +95,7 @@ auto Registration::on_cap_list(const std::unordered_map<std::string, std::string
|
||||
}
|
||||
|
||||
auto Registration::start(
|
||||
const Settings &settings,
|
||||
Settings settings,
|
||||
std::shared_ptr<Client> client
|
||||
) -> std::shared_ptr<Registration>
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
#include "sasl_mechanism.hpp"
|
||||
|
||||
auto SaslPlain::step(std::string_view msg) -> std::optional<std::string> {
|
||||
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<std::string> {
|
||||
|
||||
complete_ = true;
|
||||
|
||||
return {std::move(reply)};
|
||||
return std::move(reply);
|
||||
}
|
||||
}
|
||||
|
||||
auto SaslExternal::step(std::string_view msg) -> std::optional<std::string> {
|
||||
auto SaslExternal::step(std::string_view msg) -> StepResult {
|
||||
if (complete_) {
|
||||
return std::nullopt;
|
||||
return Failure{};
|
||||
} else {
|
||||
return {std::move(authzid_)};
|
||||
return std::move(authzid_);
|
||||
}
|
||||
}
|
@ -90,7 +90,7 @@ 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 \\((.*)\\)\\.$"},
|
Loading…
x
Reference in New Issue
Block a user