From 5f0eb57e8354516649480592ec4af206c7aeaa6f Mon Sep 17 00:00:00 2001 From: Eric Mertens Date: Wed, 29 Nov 2023 11:07:24 -0800 Subject: [PATCH] add and remove priv commands --- priv_thread.cpp | 162 ++++++++++++++++++++++++++++++++++++++---------- priv_thread.hpp | 7 ++- 2 files changed, 133 insertions(+), 36 deletions(-) diff --git a/priv_thread.cpp b/priv_thread.cpp index c6ab671..d656512 100644 --- a/priv_thread.cpp +++ b/priv_thread.cpp @@ -6,7 +6,10 @@ #include +#include #include +#include +#include PrivThread::PrivThread(Connection& connection, std::string config_path) : connection_{connection} @@ -18,11 +21,11 @@ auto PrivThread::check_command(CommandEvent& event, std::string priv) -> bool { return (not event.account.empty() && - (check(account_privs, priv, "") || - check(account_privs, priv, std::string{event.account}))) || + (check(account_privs_, priv, wildcard) || + check(account_privs_, priv, std::string{event.account}))) || (not event.oper.empty() && - (check(oper_privs, priv, "") || - check(oper_privs, priv, std::string{event.oper}))); + (check(oper_privs_, priv, wildcard) || + check(oper_privs_, priv, std::string{event.oper}))); } auto PrivThread::check( @@ -35,40 +38,131 @@ auto PrivThread::check( return cursor != privs.end() && cursor->second.contains(priv); } +auto PrivThread::list_privs(std::string_view nick) -> void +{ + for (auto const& [oper, privset] : oper_privs_) + { + std::string message = "Oper "; + message += oper; + message += ":"; + + for (auto const& priv : privset) + { + message += " "; + message += priv; + } + + send_notice(connection_, nick, message); + } + + for (auto const& [account, privset] : account_privs_) + { + std::string message = "Account "; + message += account; + message += ":"; + + for (auto const& priv : privset) + { + message += " "; + message += priv; + } + + send_notice(connection_, nick, message); + } +} + auto PrivThread::on_command(CommandEvent& event) -> void { - if (event.command == "list_privs" && check_command(event, PrivThread::owner_priv)) + if ("list_privs" == event.command) { - for (auto const& [oper, privset] : oper_privs) + if (check_command(event, PrivThread::owner_priv)) { - std::string message = "Oper "; - message += oper; - message += ":"; - - for (auto const& priv : privset) - { - message += " "; - message += priv; - } - - send_notice(connection_, event.nick, message); - } - - for (auto const& [account, privset] : account_privs) - { - std::string message = "Account "; - message += account; - message += ":"; - - for (auto const& priv : privset) - { - message += " "; - message += priv; - } - - send_notice(connection_, event.nick, message); + list_privs(event.nick); } } + else if ("add_priv" == event.command) + { + if (check_command(event, PrivThread::owner_priv)) + { + auto in = std::istringstream{std::string{event.arg}}; + std::string kind, name, priv; + if (in >> kind >> name >> priv) + { + if ("oper" == kind) + { + oper_privs_[name].insert(priv); + save_config(); + send_notice(connection_, event.nick, "ack"); + return; + } + else if ("account" == kind) + { + account_privs_[name].insert(priv); + save_config(); + send_notice(connection_, event.nick, "ack"); + return; + } + } + send_notice(connection_, event.nick, "nak"); + } + } + else if ("remove_priv" == event.command) + { + if (check_command(event, PrivThread::owner_priv)) + { + auto in = std::istringstream{std::string{event.arg}}; + std::string kind, name, priv; + if (in >> kind >> name >> priv) + { + if ("oper" == kind) + { + oper_privs_[name].erase(priv); + if (oper_privs_[name].empty()) oper_privs_.erase(name); + save_config(); + send_notice(connection_, event.nick, "ack"); + return; + } + else if ("account" == kind) + { + account_privs_[name].erase(priv); + if (account_privs_[name].empty()) account_privs_.erase(name); + save_config(); + send_notice(connection_, event.nick, "ack"); + return; + } + } + send_notice(connection_, event.nick, "nak"); + } + } +} + +auto PrivThread::save_config() -> void +{ + auto serialize_table = [](auto map) { + auto tab = toml::table{}; + for (auto const& [oper, privs] : map) + { + auto privset = toml::array{}; + for (auto const& priv : privs) + { + privset.push_back(priv); + } + tab.insert(oper, privset); + } + return tab; + }; + + auto config = toml::table{}; + if (not oper_privs_.empty()) { + config.insert("oper", serialize_table(oper_privs_)); + } + if (not account_privs_.empty()) { + config.insert("account", serialize_table(account_privs_)); + } + + std::string tmp = config_path_ + ".tmp"; + std::ofstream{tmp} << config; + std::filesystem::rename(tmp, config_path_); } auto PrivThread::load_config() -> void @@ -81,7 +175,7 @@ auto PrivThread::load_config() -> void { for (auto const [oper, privs] : *config["oper"].as_table()) { - auto& privset = oper_privs[std::string{oper.str()}]; + auto& privset = oper_privs_[std::string{oper.str()}]; for (auto const& priv : *privs.as_array()) { privset.insert(priv.as_string()->get()); @@ -93,7 +187,7 @@ auto PrivThread::load_config() -> void { for (auto const [account, privs] : *config["account"].as_table()) { - auto& privset = account_privs[std::string{account.str()}]; + auto& privset = account_privs_[std::string{account.str()}]; for (auto const& priv : *privs.as_array()) { privset.insert(priv.as_string()->get()); diff --git a/priv_thread.hpp b/priv_thread.hpp index b1dd245..7fde165 100644 --- a/priv_thread.hpp +++ b/priv_thread.hpp @@ -13,8 +13,8 @@ class PrivThread : std::enable_shared_from_this Connection& connection_; std::string config_path_; - std::unordered_map> oper_privs; - std::unordered_map> account_privs; + std::unordered_map> oper_privs_; + std::unordered_map> account_privs_; auto on_command(CommandEvent&) -> void; @@ -24,12 +24,15 @@ class PrivThread : std::enable_shared_from_this std::string const& name) -> bool; auto load_config() -> void; + auto save_config() -> void; + auto list_privs(std::string_view nick) -> void; public: PrivThread(Connection&, std::string config_path); auto check_command(CommandEvent& event, std::string priv) -> bool; static constexpr char const* owner_priv = "owner"; + static constexpr char const* wildcard = "*"; static auto start(Connection&, std::string config_path) -> std::shared_ptr; };