Mercurial > irccd
changeset 644:aae6d5a2b28d
Irccd: change how configuration is loaded
line wrap: on
line diff
--- a/irccd-test/main.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/irccd-test/main.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -73,7 +73,7 @@ auto s = daemon->servers().get(name); if (!s) { - s = std::make_shared<debug_server>(io, std::move(name)); + s = std::make_shared<debug_server>(io, std::move(name), "localhost"); daemon->servers().add(s); }
--- a/irccdctl/main.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/irccdctl/main.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -122,7 +122,6 @@ { std::unique_ptr<connection> conn; std::string host; - std::uint16_t port; ini::section::const_iterator it; if ((it = sc.find("host")) == sc.end()) @@ -133,16 +132,19 @@ if ((it = sc.find("port")) == sc.end()) throw std::invalid_argument("missing port parameter"); - port = string_util::to_uint<std::uint16_t>(it->value()); + const auto port = string_util::to_uint<std::uint16_t>(it->value()); + + if (!port) + throw std::invalid_argument("invalid port parameter"); if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) #if defined(HAVE_SSL) - conn = std::make_unique<tls_connection>(service, ctx, host, port); + conn = std::make_unique<tls_connection>(service, ctx, host, *port); #else throw std::runtime_error("SSL disabled"); #endif else - conn = std::make_unique<ip_connection>(service, host, port); + conn = std::make_unique<ip_connection>(service, host, *port); return conn; } @@ -305,9 +307,12 @@ if ((it = options.find("-p")) == options.end() && (it = options.find("--port")) == options.end()) throw std::invalid_argument("missing port argument (-p or --port)"); - auto port = string_util::to_uint<std::uint16_t>(it->second); + const auto port = string_util::to_uint<std::uint16_t>(it->second); - return std::make_unique<ip_connection>(service, host, port); + if (!port) + throw std::invalid_argument("invalid port argument"); + + return std::make_unique<ip_connection>(service, host, *port); } /*
--- a/irccdctl/rule_add_cli.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/irccdctl/rule_add_cli.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -21,6 +21,8 @@ #include "rule_add_cli.hpp" +using irccd::string_util::to_uint; + namespace irccd { namespace ctl { @@ -72,10 +74,15 @@ } // Index. - if (result.count("-i") > 0) - json["index"] = string_util::to_uint<unsigned>(result.find("-i")->second); - if (result.count("--index") > 0) - json["index"] = string_util::to_uint<unsigned>(result.find("--index")->second); + boost::optional<unsigned> index; + + if (result.count("-i") > 0 && !(index = to_uint(result.find("-i")->second))) + throw std::invalid_argument("invalid index argument"); + if (result.count("--index") > 0 && !(index = to_uint(result.find("--index")->second))) + throw std::invalid_argument("invalid index argument"); + + if (index) + json["index"] = *index; // And action. if (copy[0] != "accept" && copy[0] != "drop")
--- a/irccdctl/rule_edit_cli.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/irccdctl/rule_edit_cli.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -94,7 +94,10 @@ } // Index. - json["index"] = string_util::to_uint<unsigned>(copy[0]); + const auto index = string_util::to_uint(copy[0]); + + if (!index) + throw std::invalid_argument("invalid index argument"); request(ctl, json); }
--- a/irccdctl/rule_move_cli.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/irccdctl/rule_move_cli.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -34,13 +34,18 @@ if (args.size() < 2) throw std::invalid_argument("rule-move requires 2 arguments"); - int from = string_util::to_int<int>(args[0]); - int to = string_util::to_int<int>(args[1]); + const auto from = string_util::to_int<int>(args[0]); + const auto to = string_util::to_int<int>(args[1]); + + if (!from) + throw std::invalid_argument("invalid source argument"); + if (!to) + throw std::invalid_argument("invalid destination argument"); request(ctl, { { "command", "rule-move" }, - { "from", from }, - { "to", to } + { "from", *from }, + { "to", *to } }); }
--- a/irccdctl/server_connect_cli.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/irccdctl/server_connect_cli.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -69,8 +69,14 @@ { "host", copy[1] } }); - if (copy.size() == 3) - object["port"] = string_util::to_int(copy[2]); + if (copy.size() == 3) { + const auto port = string_util::to_int(copy[2]); + + if (!port) + throw std::invalid_argument("invalid port given"); + + object["port"] = *port; + } if (result.count("-S") > 0 || result.count("--ssl-verify") > 0) object["sslVerify"] = true;
--- a/libcommon/CMakeLists.txt Wed Mar 21 19:45:55 2018 +0100 +++ b/libcommon/CMakeLists.txt Fri Mar 23 14:00:03 2018 +0100 @@ -37,7 +37,6 @@ SOURCES ${libcommon_SOURCE_DIR}/irccd/config.cpp ${libcommon_SOURCE_DIR}/irccd/ini.cpp - ${libcommon_SOURCE_DIR}/irccd/json_util.cpp ${libcommon_SOURCE_DIR}/irccd/options.cpp ${libcommon_SOURCE_DIR}/irccd/string_util.cpp ${libcommon_SOURCE_DIR}/irccd/system.cpp
--- a/libcommon/irccd/json_util.cpp Wed Mar 21 19:45:55 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -/* - * json_util.cpp -- utilities for JSON - * - * Copyright (c) 2018 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "json_util.hpp" -#include "string_util.hpp" - -namespace irccd { - -namespace json_util { - -boost::optional<nlohmann::json> get(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept -{ - // Unfortunately, there is no find using pointer yet. - try { - return json.at(key); - } catch (...) { - return boost::none; - } -} - -boost::optional<bool> get_bool(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept -{ - const auto v = get(json, key); - - if (!v || !v->is_boolean()) - return boost::none; - - return v->get<bool>(); -} - -boost::optional<std::uint64_t> get_int(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept -{ - const auto v = get(json, key); - - if (!v || !v->is_number_integer()) - return boost::none; - - return v->get<std::uint64_t>(); -} - -boost::optional<std::uint64_t> get_uint(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept -{ - const auto v = get(json, key); - - if (!v || !v->is_number_unsigned()) - return boost::none; - - return v->get<std::uint64_t>(); -} - -boost::optional<std::string> get_string(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept -{ - const auto v = get(json, key); - - if (!v || !v->is_string()) - return boost::none; - - return v->get<std::string>(); -} - -boost::optional<bool> optional_bool(const nlohmann::json& json, - const nlohmann::json::json_pointer& key, - bool def) noexcept -{ - const auto v = get(json, key); - - if (!v) - return def; - if (!v->is_boolean()) - return boost::none; - - return v->get<bool>(); -} - -boost::optional<std::int64_t> optional_int(const nlohmann::json& json, - const nlohmann::json::json_pointer& key, - std::int64_t def) noexcept -{ - const auto v = get(json, key); - - if (!v) - return def; - if (!v->is_number_integer()) - return boost::none; - - return v->get<std::int64_t>(); -} - -boost::optional<std::uint64_t> optional_uint(const nlohmann::json& json, - const nlohmann::json::json_pointer& key, - std::uint64_t def) noexcept -{ - const auto v = get(json, key); - - if (!v) - return def; - if (!v->is_number_unsigned()) - return boost::none; - - return v->get<std::uint64_t>(); -} - -boost::optional<std::string> optional_string(const nlohmann::json& json, - const nlohmann::json::json_pointer& key, - const std::string& def) noexcept -{ - const auto v = get(json, key); - - if (!v) - return def; - if (!v->is_string()) - return boost::none; - - return v->get<std::string>(); -} - -std::string pretty(const nlohmann::json& value) -{ - switch (value.type()) { - case nlohmann::json::value_t::boolean: - return value.get<bool>() ? "true" : "false"; - case nlohmann::json::value_t::string: - return value.get<std::string>(); - default: - return value.dump(); - } -} - -bool contains(const nlohmann::json& array, const nlohmann::json& value) noexcept -{ - for (const auto &v : array) - if (v == value) - return true; - - return false; -} - -} // !json_util - -} // !irccd
--- a/libcommon/irccd/json_util.hpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libcommon/irccd/json_util.hpp Fri Mar 23 14:00:03 2018 +0100 @@ -24,8 +24,6 @@ * \brief Utilities for JSON. */ -#include <irccd/sysconfig.hpp> - #include <cstdint> #include <string> @@ -47,53 +45,106 @@ * \param key the pointer to the object * \return the value or boost::none if not found */ -IRCCD_EXPORT -boost::optional<nlohmann::json> get(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept; +inline boost::optional<nlohmann::json> get(const nlohmann::json& json, + const nlohmann::json::json_pointer& key) noexcept +{ + // Unfortunately, there is no find using pointer yet. + try { + return json.at(key); + } catch (...) { + return boost::none; + } +} + +/** + * Convenient overload with simple key. + * + * \param json the JSON object/array + * \param key the pointer to the object + * \return the value or boost::none if not found + */ +inline boost::optional<nlohmann::json> get(const nlohmann::json& json, + const std::string& key) noexcept +{ + const auto it = json.find(key); + + if (it == json.end()) + return boost::none; + + return *it; +} /** * Get a bool or null if not found or invalid. * * \param json the JSON object/array - * \param key the pointer to the object + * \param key the pointer or property key * \return the value or boost::none if not found or invalid */ -IRCCD_EXPORT -boost::optional<bool> get_bool(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept; +template <typename Key> +inline boost::optional<bool> get_bool(const nlohmann::json& json, const Key& key) noexcept +{ + const auto v = get(json, key); + + if (!v || !v->is_boolean()) + return boost::none; + + return v->template get<bool>(); +} /** * Get a 64 bit signed integer or null if not found or invalid. * * \param json the JSON object/array - * \param key the pointer to the object + * \param key the pointer or property key * \return the value or boost::none if not found or invalid */ -IRCCD_EXPORT -boost::optional<std::uint64_t> get_int(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept; +template <typename Key> +inline boost::optional<std::int64_t> get_int(const nlohmann::json& json, const Key& key) noexcept +{ + const auto v = get(json, key); + + if (!v || !v->is_number_integer()) + return boost::none; + + return v->template get<std::int64_t>(); +} /** * Get a 64 bit unsigned integer or null if not found or invalid. * * \param json the JSON object/array - * \param key the pointer to the object + * \param key the pointer or property key * \return the value or boost::none if not found or invalid */ -IRCCD_EXPORT -boost::optional<std::uint64_t> get_uint(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept; +template <typename Key> +inline boost::optional<std::uint64_t> get_uint(const nlohmann::json& json, const Key& key) noexcept +{ + const auto v = get(json, key); + + if (!v || !v->is_number_unsigned()) + return boost::none; + + return v->template get<std::uint64_t>(); +} /** * Get a string or null if not found or invalid. * * \param json the JSON object/array - * \param key the pointer to the object + * \param key the pointer or property key * \return the value or boost::none if not found or invalid */ -IRCCD_EXPORT -boost::optional<std::string> get_string(const nlohmann::json& json, - const nlohmann::json::json_pointer& key) noexcept; +template <typename Key> +inline boost::optional<std::string> get_string(const nlohmann::json& json, const Key& key) noexcept +{ + const auto v = get(json, key); + + if (!v || !v->is_string()) + return boost::none; + + return v->template get<std::string>(); +} /** * Get an optional bool. @@ -102,14 +153,22 @@ * a bool, return boost::none, otherwise return the value. * * \param json the JSON object/array - * \param key the pointer to the object + * \param key the pointer or property key * \param def the default value * \return the value, boost::none or def */ -IRCCD_EXPORT -boost::optional<bool> optional_bool(const nlohmann::json& json, - const nlohmann::json::json_pointer& key, - bool def = false) noexcept; +template <typename Key> +inline boost::optional<bool> optional_bool(const nlohmann::json& json, const Key& key, bool def = false) noexcept +{ + const auto v = get(json, key); + + if (!v) + return def; + if (!v->is_boolean()) + return boost::none; + + return v->template get<bool>(); +} /** * Get an optional integer. @@ -118,14 +177,24 @@ * an integer, return boost::none, otherwise return the value. * * \param json the JSON object/array - * \param key the pointer to the object + * \param key the pointer or property key * \param def the default value * \return the value, boost::none or def */ -IRCCD_EXPORT -boost::optional<std::int64_t> optional_int(const nlohmann::json& json, - const nlohmann::json::json_pointer& key, - std::int64_t def = 0) noexcept; +template <typename Key> +inline boost::optional<std::int64_t> optional_int(const nlohmann::json& json, + const Key& key, + std::int64_t def = 0) noexcept +{ + const auto v = get(json, key); + + if (!v) + return def; + if (!v->is_number_integer()) + return boost::none; + + return v->template get<std::int64_t>(); +} /** * Get an optional unsigned integer. @@ -134,14 +203,24 @@ * an unsigned integer, return boost::none, otherwise return the value. * * \param json the JSON object/array - * \param key the pointer to the object + * \param key the pointer or property key * \param def the default value * \return the value, boost::none or def */ -IRCCD_EXPORT -boost::optional<std::uint64_t> optional_uint(const nlohmann::json& json, - const nlohmann::json::json_pointer& key, - std::uint64_t def = 0) noexcept; +template <typename Key> +inline boost::optional<std::uint64_t> optional_uint(const nlohmann::json& json, + const Key& key, + std::uint64_t def = 0) noexcept +{ + const auto v = get(json, key); + + if (!v) + return def; + if (!v->is_number_unsigned()) + return boost::none; + + return v->template get<std::uint64_t>(); +} /** * Get an optional string. @@ -150,36 +229,73 @@ * a string, return boost::none, otherwise return the value. * * \param json the JSON object/array - * \param key the pointer to the object + * \param key the pointer or property key * \param def the default value * \return the value, boost::none or def */ -IRCCD_EXPORT -boost::optional<std::string> optional_string(const nlohmann::json& json, - const nlohmann::json::json_pointer& key, - const std::string& def = "") noexcept; +template <typename Key> +inline boost::optional<std::string> optional_string(const nlohmann::json& json, + const Key& key, + const std::string& def = "") noexcept +{ + const auto v = get(json, key); + + if (!v) + return def; + if (!v->is_string()) + return boost::none; + + return v->template get<std::string>(); +} /** * Print the value as human readable. * + * \note This only works on flat objects. * \param value the value + * \param indent the optional indent for objects/arrays * \return the string */ -IRCCD_EXPORT -std::string pretty(const nlohmann::json& value); +inline std::string pretty(const nlohmann::json& value, int indent = 4) +{ + switch (value.type()) { + case nlohmann::json::value_t::null: + return "null"; + case nlohmann::json::value_t::string: + return value.get<std::string>(); + case nlohmann::json::value_t::boolean: + return value.get<bool>() ? "true" : "false"; + case nlohmann::json::value_t::number_integer: + return std::to_string(value.get<std::int64_t>()); + case nlohmann::json::value_t::number_unsigned: + return std::to_string(value.get<std::uint64_t>()); + case nlohmann::json::value_t::number_float: + return std::to_string(value.get<double>()); + default: + return value.dump(indent); + } +} /** - * Check if the array contains the given value. + * Check if a JSON array contains a specific value in any order. * - * \param array the array - * \param value the JSON value to check - * \return true if present + * \param array the JSON array + * \param value the JSON value + * \return true if value is present */ -IRCCD_EXPORT -bool contains(const nlohmann::json& array, const nlohmann::json& value) noexcept; +inline bool contains(const nlohmann::json& array, const nlohmann::json& value) noexcept +{ + for (const auto& v : array) + if (v == value) + return true; + + return false; +} + + } // !json_util } // !irccd -#endif // !JSON_UTIL_HPP +#endif // !IRCCD_JSON_UTIL_HPP
--- a/libcommon/irccd/string_util.hpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libcommon/irccd/string_util.hpp Fri Mar 23 14:00:03 2018 +0100 @@ -38,6 +38,7 @@ #include <unordered_map> #include <boost/format.hpp> +#include <boost/optional.hpp> namespace irccd { @@ -383,99 +384,52 @@ } /** - * \cond HIDDEN_SYMBOLS - */ - -namespace detail { - -inline std::invalid_argument make_invalid_argument(const std::string& str) -{ - std::ostringstream oss; - - oss << "invalid number '" << str << "'"; - - return std::invalid_argument(oss.str()); -} - -template <typename T> -inline std::out_of_range make_out_of_range(const std::string& str, T min, T max) -{ - std::ostringstream oss; - - oss << "number '" << str << "' is out of range "; - oss << min << ".." << max; - - return std::out_of_range(oss.str()); -} - -} // !detail - -/** - * \endcond - */ - -/** * Convert the given string into a signed integer. * * \param str the string to convert * \param min the minimum value allowed * \param max the maximum value allowed - * \throw std::invalid_argument if the number was not parsed - * \throw std::out_or_range if the argument is out of the specified range + * \return the value or boost::none if not convertible */ template <typename T = int> -T to_int(const std::string& str, T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max()) +boost::optional<T> to_int(const std::string& str, + T min = std::numeric_limits<T>::min(), + T max = std::numeric_limits<T>::max()) noexcept { static_assert(std::is_signed<T>::value, "must be signed"); char* end; auto v = std::strtoll(str.c_str(), &end, 10); - if (*end != '\0') - throw detail::make_invalid_argument(str); - if (v < min || v > max) - throw detail::make_out_of_range(str, min, max); + if (*end != '\0' || v < min || v > max) + return boost::none; return static_cast<T>(v); } /** - * Convert the given string into an unsigned integer. - * - * In contrast to the [std::strtoull][strtoull] function, this functions - * verifies if the string starts with minus sign and throws an exception if any. + * Convert the given string into a unsigned integer. * - * Note, for this you need to have a trimmed string which contains no leading - * whitespaces. - * - * \pre string must be trimmed + * \note invalid numbers are valid as well * \param str the string to convert * \param min the minimum value allowed * \param max the maximum value allowed - * \throw std::invalid_argument if the number was not parsed - * \throw std::out_or_range if the argument is out of the specified range - * - * [strtoull]: http://en.cppreference.com/w/cpp/string/byte/strtoul + * \return the value or boost::none if not convertible */ template <typename T = unsigned> -T to_uint(const std::string& str, T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max()) +boost::optional<T> to_uint(const std::string& str, + T min = std::numeric_limits<T>::min(), + T max = std::numeric_limits<T>::max()) noexcept { static_assert(std::is_unsigned<T>::value, "must be unsigned"); - assert(str.empty() || !std::isspace(str[0])); - - if (str.size() > 0U && str[0] == '-') - throw detail::make_out_of_range(str, min, max); - char* end; auto v = std::strtoull(str.c_str(), &end, 10); - if (*end != '\0') - throw detail::make_invalid_argument(str); - if (v < min || v > max) - throw detail::make_out_of_range(str, min, max); + if (*end != '\0' || v < min || v > max) + return boost::none; - return v; + return static_cast<T>(v); } } // !string_util
--- a/libirccd-test/irccd/test/plugin_test.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd-test/irccd/test/plugin_test.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -41,7 +41,7 @@ namespace irccd { plugin_test::plugin_test(std::string name, std::string path) - : server_(std::make_shared<journal_server>(service_, "test")) + : server_(std::make_shared<journal_server>(service_, "test", "local")) { server_->set_nickname("irccd"); plugin_ = std::make_unique<js_plugin>(std::move(name), std::move(path));
--- a/libirccd/irccd/daemon/command/plugin_config_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/plugin_config_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -81,7 +81,7 @@ void plugin_config_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = json_util::get_string(args, "/plugin"_json_pointer); + const auto id = json_util::get_string(args, "plugin"); if (!id || !string_util::is_identifier(*id)) throw plugin_error(plugin_error::invalid_identifier);
--- a/libirccd/irccd/daemon/command/plugin_info_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/plugin_info_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -35,7 +35,7 @@ void plugin_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = json_util::get_string(args, "/plugin"_json_pointer); + const auto id = json_util::get_string(args, "plugin"); if (!id || !string_util::is_identifier(*id)) throw plugin_error(plugin_error::invalid_identifier);
--- a/libirccd/irccd/daemon/command/plugin_load_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/plugin_load_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -35,7 +35,7 @@ void plugin_load_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = json_util::get_string(args, "/plugin"_json_pointer); + const auto id = json_util::get_string(args, "plugin"); if (!id || !string_util::is_identifier(*id)) throw plugin_error(plugin_error::invalid_identifier);
--- a/libirccd/irccd/daemon/command/plugin_reload_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/plugin_reload_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -35,7 +35,7 @@ void plugin_reload_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = json_util::get_string(args, "/plugin"_json_pointer); + const auto id = json_util::get_string(args, "plugin"); if (!id || !string_util::is_identifier(*id)) throw plugin_error(plugin_error::invalid_identifier);
--- a/libirccd/irccd/daemon/command/plugin_unload_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/plugin_unload_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -35,7 +35,7 @@ void plugin_unload_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = json_util::get_string(args, "/plugin"_json_pointer); + const auto id = json_util::get_string(args, "plugin"); if (!id || !string_util::is_identifier(*id)) throw plugin_error(plugin_error::invalid_identifier);
--- a/libirccd/irccd/daemon/command/rule_add_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/rule_add_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -35,7 +35,7 @@ void rule_add_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - auto index = json_util::get_uint(args, "/index"_json_pointer); + auto index = json_util::get_uint(args, "index"); if (!index) index = irccd.rules().length();
--- a/libirccd/irccd/daemon/command/rule_edit_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/rule_edit_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -49,7 +49,7 @@ }; // Create a copy to avoid incomplete edition in case of errors. - const auto index = json_util::get_uint(args, "/index"_json_pointer); + const auto index = json_util::get_uint(args, "index"); if (!index) throw rule_error(rule_error::invalid_index);
--- a/libirccd/irccd/daemon/command/rule_info_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/rule_info_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -35,7 +35,7 @@ void rule_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto index = json_util::get_uint(args, "/index"_json_pointer); + const auto index = json_util::get_uint(args, "index"); if (!index) throw rule_error(rule_error::invalid_index);
--- a/libirccd/irccd/daemon/command/rule_move_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/rule_move_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -35,8 +35,8 @@ void rule_move_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto from = json_util::get_uint(args, "/from"_json_pointer); - const auto to = json_util::get_uint(args, "/to"_json_pointer); + const auto from = json_util::get_uint(args, "from"); + const auto to = json_util::get_uint(args, "to"); if (!from || !to) throw rule_error(rule_error::invalid_index);
--- a/libirccd/irccd/daemon/command/rule_remove_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/rule_remove_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -34,7 +34,7 @@ void rule_remove_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto index = json_util::get_uint(args, "/index"_json_pointer); + const auto index = json_util::get_uint(args, "index"); if (!index || *index >= irccd.rules().length()) throw rule_error(rule_error::invalid_index);
--- a/libirccd/irccd/daemon/command/server_connect_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_connect_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -36,7 +36,7 @@ auto server = server_util::from_json(irccd.service(), args); if (irccd.servers().has(server->name())) - throw server_error(server->name(), server_error::already_exists); + throw server_error(server_error::already_exists); irccd.servers().add(std::move(server)); client.success("server-connect");
--- a/libirccd/irccd/daemon/command/server_disconnect_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_disconnect_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -41,7 +41,7 @@ irccd.servers().clear(); else { if (!it->is_string() || !string_util::is_identifier(it->get<std::string>())) - throw server_error("", server_error::invalid_identifier); + throw server_error(server_error::invalid_identifier); const auto name = it->get<std::string>();
--- a/libirccd/irccd/daemon/command/server_info_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_info_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -16,6 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> + #include <irccd/daemon/irccd.hpp> #include <irccd/daemon/server_util.hpp> #include <irccd/daemon/transport_client.hpp> @@ -33,9 +36,14 @@ void server_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); + const auto id = json_util::get_string(args, "server"); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); + + const auto server = irccd.servers().require(*id); + + // Construct the JSON response. auto response = nlohmann::json::object(); // General stuff.
--- a/libirccd/irccd/daemon/command/server_invite_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_invite_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,9 +17,9 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/transport_client.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,17 +35,18 @@ void server_invite_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto target = json_util::get_string(args, "/target"_json_pointer); - const auto channel = json_util::get_string(args, "/channel"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto target = json_util::get_string(args, "target"); + const auto channel = json_util::get_string(args, "channel"); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!target || target->empty()) - throw server_error(server->name(), server_error::invalid_nickname); + throw server_error(server_error::invalid_nickname); if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); + throw server_error(server_error::invalid_channel); - server->invite(*target, *channel); + irccd.servers().require(*id)->invite(*target, *channel); client.success("server-invite"); }
--- a/libirccd/irccd/daemon/command/server_join_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_join_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,10 +17,10 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> #include <irccd/daemon/transport_client.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,15 +35,16 @@ void server_join_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto channel = json_util::get_string(args, "/channel"_json_pointer); - const auto password = json_util::get_string(args, "/password"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto channel = json_util::get_string(args, "channel"); + const auto password = json_util::get_string(args, "password"); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); + throw server_error(server_error::invalid_channel); - server->join(*channel, password ? *password : ""); + irccd.servers().require(*id)->join(*channel, password ? *password : ""); client.success("server-join"); }
--- a/libirccd/irccd/daemon/command/server_kick_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_kick_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,10 +17,10 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> #include <irccd/daemon/transport_client.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,18 +35,19 @@ void server_kick_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto target = json_util::get_string(args, "/target"_json_pointer); - const auto channel = json_util::get_string(args, "/channel"_json_pointer); - const auto reason = json_util::get_string(args, "/reason"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto target = json_util::get_string(args, "target"); + const auto channel = json_util::get_string(args, "channel"); + const auto reason = json_util::get_string(args, "reason"); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!target || target->empty()) - throw server_error(server->name(), server_error::invalid_nickname); + throw server_error(server_error::invalid_nickname); if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); + throw server_error(server_error::invalid_channel); - server->kick(*target, *channel, reason ? *reason : ""); + irccd.servers().require(*id)->kick(*target, *channel, reason ? *reason : ""); client.success("server-kick"); }
--- a/libirccd/irccd/daemon/command/server_me_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_me_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,10 +17,10 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> #include <irccd/daemon/transport_client.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,15 +35,18 @@ void server_me_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto channel = json_util::get_string(args, "/target"_json_pointer); - const auto message = json_util::get_string(args, "/message"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto channel = json_util::get_string(args, "target"); + const auto message = json_util::optional_string(args, "message", ""); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); + throw server_error(server_error::invalid_channel); + if (!message) + throw server_error(server_error::invalid_message); - server->me(*channel, message ? *message : ""); + irccd.servers().require(*id)->me(*channel, *message); client.success("server-me"); }
--- a/libirccd/irccd/daemon/command/server_message_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_message_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,9 +17,9 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/transport_client.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,15 +35,18 @@ void server_message_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto channel = json_util::get_string(args, "/target"_json_pointer); - const auto message = json_util::get_string(args, "/message"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto channel = json_util::get_string(args, "target"); + const auto message = json_util::optional_string(args, "message", ""); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); + throw server_error(server_error::invalid_channel); + if (!message) + throw server_error(server_error::invalid_message); - server->message(*channel, message ? *message : ""); + irccd.servers().require(*id)->message(*channel, *message); client.success("server-message"); }
--- a/libirccd/irccd/daemon/command/server_mode_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_mode_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,9 +17,9 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/transport_client.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,28 +35,23 @@ void server_mode_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto channel = json_util::get_string(args, "/channel"_json_pointer); - const auto mode = json_util::get_string(args, "/mode"_json_pointer); - - if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); - if (!mode || mode->empty()) - throw server_error(server->name(), server_error::invalid_mode); + const auto id = json_util::get_string(args, "server"); + const auto channel = json_util::get_string(args, "channel"); + const auto mode = json_util::get_string(args, "mode"); + const auto limit = json_util::optional_string(args, "limit", ""); + const auto user = json_util::optional_string(args, "user", ""); + const auto mask = json_util::optional_string(args, "mask", ""); - auto limit = json_util::get_string(args, "/limit"_json_pointer); - auto user = json_util::get_string(args, "/user"_json_pointer); - auto mask = json_util::get_string(args, "/mask"_json_pointer); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); + if (!channel || channel->empty()) + throw server_error(server_error::invalid_channel); + if (!mode || mode->empty()) + throw server_error(server_error::invalid_mode); + if (!limit || !user || !mask) + throw server_error(server_error::invalid_mode); - if (!limit) - limit = ""; - if (!user) - user = ""; - if (!mask) - mask = ""; - - server->mode(*channel, *mode, *limit, *user, *mask); + irccd.servers().require(*id)->mode(*channel, *mode, *limit, *user, *mask); client.success("server-mode"); }
--- a/libirccd/irccd/daemon/command/server_nick_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_nick_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,9 +17,9 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/transport_client.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,14 +35,15 @@ void server_nick_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto nick = json_util::get_string(args, "/nickname"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto nick = json_util::get_string(args, "nickname"); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!nick || nick->empty()) - throw server_error(server->name(), server_error::invalid_nickname); + throw server_error(server_error::invalid_nickname); - server->set_nickname(*nick); + irccd.servers().require(*id)->set_nickname(*nick); client.success("server-nick"); }
--- a/libirccd/irccd/daemon/command/server_notice_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_notice_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,9 +17,9 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/transport_client.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,15 +35,18 @@ void server_notice_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto channel = json_util::get_string(args, "/target"_json_pointer); - const auto message = json_util::get_string(args, "/message"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto channel = json_util::get_string(args, "target"); + const auto message = json_util::optional_string(args, "message", ""); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); + throw server_error(server_error::invalid_channel); + if (!message) + throw server_error(server_error::invalid_message); - server->notice(*channel, message ? *message : ""); + irccd.servers().require(*id)->notice(*channel, *message); client.success("server-notice"); }
--- a/libirccd/irccd/daemon/command/server_part_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_part_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,9 +17,9 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/transport_client.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,15 +35,18 @@ void server_part_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto channel = json_util::get_string(args, "/channel"_json_pointer); - const auto reason = json_util::get_string(args, "/reason"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto channel = json_util::get_string(args, "channel"); + const auto reason = json_util::optional_string(args, "reason", ""); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); + throw server_error(server_error::invalid_channel); + if (!reason) + throw server_error(server_error::invalid_message); - server->part(*channel, reason ? *reason : ""); + irccd.servers().require(*id)->part(*channel, *reason); client.success("server-part"); }
--- a/libirccd/irccd/daemon/command/server_reconnect_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_reconnect_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -42,7 +42,7 @@ server->reconnect(); } else { if (!it->is_string() || !string_util::is_identifier(it->get<std::string>())) - throw server_error("", server_error::invalid_identifier); + throw server_error(server_error::invalid_identifier); irccd.servers().require(it->get<std::string>())->reconnect(); }
--- a/libirccd/irccd/daemon/command/server_topic_command.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/command/server_topic_command.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -17,9 +17,9 @@ */ #include <irccd/json_util.hpp> +#include <irccd/string_util.hpp> #include <irccd/daemon/irccd.hpp> -#include <irccd/daemon/server_util.hpp> #include <irccd/daemon/transport_client.hpp> #include <irccd/daemon/service/server_service.hpp> @@ -35,15 +35,18 @@ void server_topic_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - const auto id = server_util::get_identifier(args); - const auto server = irccd.servers().require(id); - const auto channel = json_util::get_string(args, "/channel"_json_pointer); - const auto topic = json_util::get_string(args, "/topic"_json_pointer); + const auto id = json_util::get_string(args, "server"); + const auto channel = json_util::get_string(args, "channel"); + const auto topic = json_util::optional_string(args, "topic", ""); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); if (!channel || channel->empty()) - throw server_error(server->name(), server_error::invalid_channel); + throw server_error(server_error::invalid_channel); + if (!topic) + throw server_error(server_error::invalid_message); - server->topic(*channel, topic ? *topic : ""); + irccd.servers().require(*id)->topic(*channel, *topic); client.success("server-topic"); }
--- a/libirccd/irccd/daemon/server.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/server.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -121,11 +121,14 @@ return {value, ""}; } -server::server(boost::asio::io_service& service, std::string name) +server::server(boost::asio::io_service& service, std::string name, std::string host) : name_(std::move(name)) + , host_(std::move(host)) , service_(service) , timer_(service) { + assert(!host_.empty()); + // Initialize nickname and username. auto user = sys::username(); @@ -668,9 +671,8 @@ send(string_util::sprintf("WHOIS %s %s", target, target)); } -server_error::server_error(std::string name, error code) noexcept +server_error::server_error(error code) noexcept : system_error(make_error_code(code)) - , name_(std::move(name)) { } @@ -720,6 +722,8 @@ return "invalid CTCP VERSION"; case server_error::invalid_command_char: return "invalid character command"; + case server_error::invalid_message: + return "invalid message"; case server_error::ssl_disabled: return "ssl is not enabled"; default:
--- a/libirccd/irccd/daemon/server.hpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/server.hpp Fri Mar 23 14:00:03 2018 +0100 @@ -474,10 +474,14 @@ /** * Construct a server. * + * \pre !host.empty() * \param service the service * \param name the identifier + * \param host the hostname */ - server(boost::asio::io_service& service, std::string name); + server(boost::asio::io_service& service, + std::string name, + std::string host = "localhost"); /** * Destructor. Close the connection if needed. @@ -962,31 +966,20 @@ //!< Invalid command character. invalid_command_char, + //!< Message (PRIVMSG) was invalid + invalid_message, + //!< SSL was requested but is disabled. ssl_disabled, }; -private: - std::string name_; - public: /** * Constructor. * - * \param name the server name * \param code the error code */ - server_error(std::string name, error code) noexcept; - - /** - * Get the server that triggered the error. - * - * \return the name - */ - inline const std::string& name() const noexcept - { - return name_; - } + server_error(error code) noexcept; }; /**
--- a/libirccd/irccd/daemon/server_util.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/server_util.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -25,185 +25,203 @@ #include "server_util.hpp" -using nlohmann::json; - -using std::uint16_t; -using std::string; -using std::forward; - namespace irccd { namespace server_util { namespace { -template <typename... Args> -std::string require_conf_host(const ini::section& sc, Args&&... args) +// TODO: ini_util +std::string optional_string(const ini::section& sc, + const std::string& name, + const std::string& def) { - auto value = sc.get("host"); + const auto it = sc.find(name); + + if (it == sc.end()) + return def; + + return it->value(); +} - if (value.empty()) - throw server_error(forward<Args>(args)...); +// TODO: ini_util +template <typename Int> +boost::optional<Int> optional_uint(const ini::section& sc, + const std::string& name, + Int def) +{ + const auto it = sc.find(name); - return value.value(); + if (it == sc.end()) + return def; + + return string_util::to_uint<Int>(it->value()); } -template <typename... Args> -std::string require_conf_id(const ini::section& sc, Args&&... args) +void from_config_load_identity(server& sv, const ini::section& sc) { - auto id = sc.get("name"); + const auto username = optional_string(sc, "username", sv.username()); + const auto realname = optional_string(sc, "realname", sv.realname()); + const auto nickname = optional_string(sc, "nickname", sv.nickname()); + const auto ctcp_version = optional_string(sc, "ctcp-version", sv.ctcp_version()); - if (!string_util::is_identifier(id.value())) - throw server_error(forward<Args>(args)...); + if (username.empty()) + throw server_error(server_error::invalid_username); + if (realname.empty()) + throw server_error(server_error::invalid_realname); + if (nickname.empty()) + throw server_error(server_error::invalid_nickname); + if (ctcp_version.empty()) + throw server_error(server_error::invalid_ctcp_version); - return id.value(); + sv.set_username(username); + sv.set_realname(realname); + sv.set_nickname(nickname); + sv.set_ctcp_version(ctcp_version); } -template <typename Int, typename... Args> -Int optional_conf_int(const string& value, Args&&... args) +void from_config_load_channels(server& sv, const ini::section& sc) { - try { - return string_util::to_int<Int>(value); - } catch (...) { - throw server_error(std::forward<Args>(args)...); - } -} + for (const auto& s : sc.get("channels")) { + channel channel; -template <typename Int, typename... Args> -Int optional_conf_uint(const string& value, Args&&... args) -{ - try { - return string_util::to_uint<Int>(value); - } catch (...) { - throw server_error(std::forward<Args>(args)...); + if (auto pos = s.find(":") != std::string::npos) { + channel.name = s.substr(0, pos); + channel.password = s.substr(pos + 1); + } else + channel.name = s; + + sv.join(channel.name, channel.password); } } -template <typename Int, typename... Args> -Int optional_json_uint(const json& json, const json::json_pointer& key, Int def, Args&&... args) +void from_config_load_flags(server& sv, const ini::section& sc) { - const auto v = json_util::optional_uint(json, key, def); + const auto ipv6 = sc.get("ipv6"); + const auto ssl = sc.get("ssl"); + const auto ssl_verify = sc.get("ssl-verify"); + const auto auto_rejoin = sc.get("auto-rejoin"); + const auto join_invite = sc.get("join-invite"); - if (!v || *v > std::numeric_limits<Int>::max()) - throw server_error(forward<Args>(args)...); - - return *v; + if (string_util::is_boolean(ipv6.value())) + sv.set_flags(sv.flags() | server::ipv6); + if (string_util::is_boolean(ssl.value())) + sv.set_flags(sv.flags() | server::ssl); + if (string_util::is_boolean(ssl_verify.value())) + sv.set_flags(sv.flags() | server::ssl_verify); + if (string_util::is_boolean(auto_rejoin.value())) + sv.set_flags(sv.flags() | server::auto_rejoin); + if (string_util::is_boolean(join_invite.value())) + sv.set_flags(sv.flags() | server::join_invite); } -bool optional_json_bool(const json& json, const json::json_pointer& key, bool def = false) +void from_config_load_numeric_parameters(server& sv, const ini::section& sc) { - const auto v = json_util::optional_bool(json, key, def); + const auto port = optional_uint<std::uint16_t>(sc, "port", sv.port()); + const auto ping_timeout = optional_uint<uint16_t>(sc, "ping-timeout", sv.ping_timeout()); + const auto reco_tries = optional_uint<uint8_t>(sc, "reconnect-tries", sv.reconnect_tries()); + const auto reco_timeout = optional_uint<uint16_t>(sc, "reconnect-delay", sv.reconnect_delay()); - if (!v) - return def; + if (!port) + throw server_error(server_error::invalid_port); + if (!ping_timeout) + throw server_error(server_error::invalid_ping_timeout); + if (!reco_tries) + throw server_error(server_error::invalid_reconnect_tries); + if (!reco_timeout) + throw server_error(server_error::invalid_reconnect_timeout); - return *v; + sv.set_port(*port); + sv.set_ping_timeout(*ping_timeout); + sv.set_reconnect_tries(*reco_tries); + sv.set_reconnect_delay(*reco_timeout); } -template <typename... Args> -std::string optional_json_string(const json& json, - const json::json_pointer& key, - const string& def, - Args&&... args) +void from_config_load_options(server& sv, const ini::section& sc) { - const auto v = json_util::optional_string(json, key, def); + const auto password = optional_string(sc, "password", ""); + const auto command_char = optional_string(sc, "command-char", sv.command_char()); - if (!v) - throw server_error(forward<Args>(args)...); - - return *v; + sv.set_password(password); + sv.set_command_char(command_char); } -template <typename... Args> -std::string require_json_id(const nlohmann::json& json, Args&&... args) +void from_json_load_options(server& sv, const nlohmann::json& object) { - const auto id = json_util::get_string(json, "/name"_json_pointer); - - if (!id || !string_util::is_identifier(*id)) - throw server_error(forward<Args>(args)...); + const auto port = json_util::optional_uint(object, "port", sv.port()); + const auto nickname = json_util::optional_string(object, "nickname", sv.nickname()); + const auto realname = json_util::optional_string(object, "realname", sv.realname()); + const auto username = json_util::optional_string(object, "username", sv.username()); + const auto ctcp_version = json_util::optional_string(object, "ctcpVersion", sv.ctcp_version()); + const auto command = json_util::optional_string(object, "commandChar", sv.command_char()); + const auto password = json_util::optional_string(object, "password", sv.password()); - return *id; -} + if (!port || *port > std::numeric_limits<std::uint16_t>::max()) + throw server_error(server_error::invalid_port); + if (!nickname) + throw server_error(server_error::invalid_nickname); + if (!realname) + throw server_error(server_error::invalid_realname); + if (!username) + throw server_error(server_error::invalid_username); + if (!ctcp_version) + throw server_error(server_error::invalid_ctcp_version); + if (!command) + throw server_error(server_error::invalid_command_char); + if (!password) + throw server_error(server_error::invalid_password); -template <typename... Args> -std::string require_json_host(const nlohmann::json& object, Args&&... args) -{ - const auto value = json_util::get_string(object, "/host"_json_pointer); - - if (!value || value->empty()) - throw server_error(forward<Args>(args)...); - - return *value; + sv.set_port(*port); + sv.set_nickname(*nickname); + sv.set_realname(*realname); + sv.set_username(*username); + sv.set_ctcp_version(*ctcp_version); + sv.set_command_char(*command); + sv.set_password(*password); } -void load_identity(server& server, const config& cfg, const std::string& identity) +void from_json_load_flags(server& sv, nlohmann::json object) { - auto sc = std::find_if(cfg.doc().begin(), cfg.doc().end(), [&] (const auto& sc) { - if (sc.key() != "identity") - return false; - - auto name = sc.find("name"); - - return name != sc.end() && name->value() == identity; - }); + const auto ipv6 = object["ipv6"]; + const auto ssl = object["ssl"]; + const auto ssl_verify = object["sslVerify"]; + const auto auto_rejoin = object["autoRejoin"]; + const auto join_invite = object["joinInvite"]; - if (sc == cfg.doc().end()) - return; - - ini::section::const_iterator it; + if (ipv6.is_boolean() && ipv6.get<bool>()) + sv.set_flags(sv.flags() | server::ipv6); + if (ssl.is_boolean() && ssl.get<bool>()) + sv.set_flags(sv.flags() | server::ssl); + if (ssl_verify.is_boolean() && ssl_verify.get<bool>()) + sv.set_flags(sv.flags() | server::ssl_verify); + if (auto_rejoin.is_boolean() && auto_rejoin.get<bool>()) + sv.set_flags(sv.flags() | server::auto_rejoin); + if (join_invite.is_boolean() && join_invite.get<bool>()) + sv.set_flags(sv.flags() | server::join_invite); - if ((it = sc->find("username")) != sc->end()) - server.set_username(it->value()); - if ((it = sc->find("realname")) != sc->end()) - server.set_realname(it->value()); - if ((it = sc->find("nickname")) != sc->end()) - server.set_nickname(it->value()); - if ((it = sc->find("ctcp-version")) != sc->end()) - server.set_ctcp_version(it->value()); +#if !defined(HAVE_SSL) + if (sv.flags() & server::ssl) + throw server_error(server_error::ssl_disabled); +#endif } } // !namespace std::shared_ptr<server> from_json(boost::asio::io_service& service, const nlohmann::json& object) { - const auto id = require_json_id(object, "", server_error::invalid_identifier); - const auto sv = std::make_shared<server>(service, id); - - // Mandatory fields. - sv->set_host(require_json_host(object, sv->name(), server_error::invalid_hostname)); + // Mandatory parameters. + const auto id = json_util::get_string(object, "name"); + const auto host = json_util::get_string(object, "host"); - // Optional fields. - sv->set_port(optional_json_uint<uint16_t>(object, "/port"_json_pointer, sv->port(), - sv->name(), server_error::invalid_port)); - sv->set_password(optional_json_string(object, "/password"_json_pointer, sv->password(), - sv->name(), server_error::invalid_password)); - sv->set_nickname(optional_json_string(object, "/nickname"_json_pointer, sv->nickname(), - sv->name(), server_error::invalid_nickname)); - sv->set_realname(optional_json_string(object, "/realname"_json_pointer, sv->realname(), - sv->name(), server_error::invalid_realname)); - sv->set_username(optional_json_string(object, "/username"_json_pointer, sv->username(), - sv->name(), server_error::invalid_username)); - sv->set_ctcp_version(optional_json_string(object, "/ctcpVersion"_json_pointer, sv->ctcp_version(), - sv->name(), server_error::invalid_ctcp_version)); - sv->set_command_char(optional_json_string(object, "/commandChar"_json_pointer, sv->command_char(), - sv->name(), server_error::invalid_command_char)); + if (!id || !string_util::is_identifier(*id)) + throw server_error(server_error::invalid_identifier); + if (!host || host->empty()) + throw server_error(server_error::invalid_hostname); - // Boolean does not throw options though. - if (optional_json_bool(object, "/ipv6"_json_pointer)) - sv->set_flags(sv->flags() | server::ipv6); - if (optional_json_bool(object, "/sslVerify"_json_pointer)) - sv->set_flags(sv->flags() | server::ssl_verify); - if (optional_json_bool(object, "/autoRejoin"_json_pointer)) - sv->set_flags(sv->flags() | server::auto_rejoin); - if (optional_json_bool(object, "/joinInvite"_json_pointer)) - sv->set_flags(sv->flags() | server::join_invite); + const auto sv = std::make_shared<server>(service, *id, *host); - if (optional_json_bool(object, "/ssl"_json_pointer)) -#if defined(HAVE_SSL) - sv->set_flags(sv->flags() | server::ssl); -#else - throw server_error(sv->name(), server_error::ssl_disabled); -#endif + from_json_load_options(*sv, object); + from_json_load_flags(*sv, object); return sv; } @@ -212,94 +230,37 @@ const config& cfg, const ini::section& sc) { - assert(sc.key() == "server"); - - const auto id = require_conf_id(sc, "", server_error::invalid_identifier); - const auto sv = std::make_shared<server>(service, id); + // Mandatory parameters. + const auto id = sc.get("name"); + const auto host = sc.get("hostname"); - // Mandatory fields. - sv->set_host(require_conf_host(sc, sv->name(), server_error::invalid_hostname)); + if (!string_util::is_identifier(id.value())) + throw server_error(server_error::invalid_identifier); + if (host.value().empty()) + throw server_error(server_error::invalid_hostname); - // Optional fields. - ini::section::const_iterator it; + const auto sv = std::make_shared<server>(service, id.value(), host.value()); - if ((it = sc.find("password")) != sc.end()) - sv->set_password(it->value()); + from_config_load_channels(*sv, sc); + from_config_load_flags(*sv, sc); + from_config_load_numeric_parameters(*sv, sc); + from_config_load_options(*sv, sc); - // Optional flags - if ((it = sc.find("ipv6")) != sc.end() && string_util::is_boolean(it->value())) - sv->set_flags(sv->flags() | server::ipv6); + // Identity is in a separate section + const auto identity = sc.get("identity"); - if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) { -#if defined(HAVE_SSL) - sv->set_flags(sv->flags() | server::ssl); -#else - throw server_error(sv->name(), server_error::ssl_disabled); -#endif + if (identity.value().size() > 0) { + const auto it = std::find_if(cfg.doc().begin(), cfg.doc().end(), [&] (const auto& i) { + return i.get("name").value() == identity.value(); + }); + + if (it != cfg.doc().end()) + from_config_load_identity(*sv, sc); } - if ((it = sc.find("ssl-verify")) != sc.end() && string_util::is_boolean(it->value())) - sv->set_flags(sv->flags() | server::ssl_verify); - - // Optional identity - if ((it = sc.find("identity")) != sc.end()) - load_identity(*sv, cfg, it->value()); - - // Options - if ((it = sc.find("auto-rejoin")) != sc.end() && string_util::is_boolean(it->value())) - sv->set_flags(sv->flags() | server::auto_rejoin); - if ((it = sc.find("join-invite")) != sc.end() && string_util::is_boolean(it->value())) - sv->set_flags(sv->flags() | server::join_invite); - - // Channels - if ((it = sc.find("channels")) != sc.end()) { - for (const auto& s : *it) { - channel channel; - - if (auto pos = s.find(":") != std::string::npos) { - channel.name = s.substr(0, pos); - channel.password = s.substr(pos + 1); - } else - channel.name = s; - - sv->join(channel.name, channel.password); - } - } - if ((it = sc.find("command-char")) != sc.end()) - sv->set_command_char(it->value()); - - // Reconnect and ping timeout - if ((it = sc.find("port")) != sc.end()) - sv->set_port(optional_conf_uint<std::uint16_t>(it->value(), - sv->name(), server_error::invalid_port)); - - if ((it = sc.find("reconnect-tries")) != sc.end()) - sv->set_reconnect_tries(optional_conf_int<std::int8_t>(it->value(), - sv->name(), server_error::invalid_reconnect_tries)); - - if ((it = sc.find("reconnect-timeout")) != sc.end()) - sv->set_reconnect_delay(optional_conf_uint<std::uint16_t>(it->value(), - sv->name(), server_error::invalid_reconnect_timeout)); - - if ((it = sc.find("ping-timeout")) != sc.end()) - sv->set_ping_timeout(optional_conf_uint<std::uint16_t>(it->value(), - sv->name(), server_error::invalid_ping_timeout)); - return sv; } -std::string get_identifier(const nlohmann::json& json) -{ - const auto v = json_util::get_string(json, "/server"_json_pointer); - - if (!v) - throw server_error("", server_error::invalid_identifier); - if (!string_util::is_identifier(*v)) - throw server_error(*v, server_error::invalid_identifier); - - return *v; -} - } // !server_util } // !irccd
--- a/libirccd/irccd/daemon/server_util.hpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/server_util.hpp Fri Mar 23 14:00:03 2018 +0100 @@ -71,16 +71,6 @@ const config& cfg, const ini::section& sc); -/** - * Get a server identifier from the JSON object. - * - * This searches for the `server` property. - * - * \param json the JSON object - * \throw server_error on errors - */ -std::string get_identifier(const nlohmann::json& json); - } // !server_util } // !irccd
--- a/libirccd/irccd/daemon/service/server_service.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/service/server_service.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -472,12 +472,12 @@ std::shared_ptr<server> server_service::require(const std::string& name) const { if (!string_util::is_identifier(name)) - throw server_error(name, server_error::invalid_identifier); + throw server_error(server_error::invalid_identifier); const auto s = get(name); if (!s) - throw server_error(name, server_error::not_found); + throw server_error(server_error::not_found); return s; }
--- a/libirccd/irccd/daemon/transport_util.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/libirccd/irccd/daemon/transport_util.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -55,6 +55,9 @@ auto port = string_util::to_uint<std::uint16_t>(it->value()); + if (!port) + throw std::invalid_argument("invalid port number"); + // Address. std::string address = "*"; @@ -108,8 +111,8 @@ } auto endpoint = (address == "*") - ? boost::asio::ip::tcp::endpoint(protocol, port) - : boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port); + ? boost::asio::ip::tcp::endpoint(protocol, *port) + : boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), *port); boost::asio::ip::tcp::acceptor acceptor(service, endpoint, true);
--- a/tests/src/libirccd/util/main.cpp Wed Mar 21 19:45:55 2018 +0100 +++ b/tests/src/libirccd/util/main.cpp Fri Mar 23 14:00:03 2018 +0100 @@ -416,63 +416,6 @@ BOOST_AUTO_TEST_SUITE_END() /* - * string_util::to_int function - * ------------------------------------------------------------------ - */ - -BOOST_AUTO_TEST_SUITE(to_int) - -BOOST_AUTO_TEST_CASE(signed_to_int) -{ - BOOST_TEST(string_util::to_int("10") == 10); - BOOST_TEST(string_util::to_int<std::int8_t>("-10") == -10); - BOOST_TEST(string_util::to_int<std::int8_t>("10") == 10); - BOOST_TEST(string_util::to_int<std::int16_t>("-1000") == -1000); - BOOST_TEST(string_util::to_int<std::int16_t>("1000") == 1000); - BOOST_TEST(string_util::to_int<std::int32_t>("-1000") == -1000); - BOOST_TEST(string_util::to_int<std::int32_t>("1000") == 1000); -} - -BOOST_AUTO_TEST_CASE(signed_to_int64) -{ - BOOST_TEST(string_util::to_int<std::int64_t>("-9223372036854775807") == -9223372036854775807LL); - BOOST_TEST(string_util::to_int<std::int64_t>("9223372036854775807") == 9223372036854775807LL); -} - -BOOST_AUTO_TEST_CASE(unsigned_to_uint) -{ - BOOST_TEST(string_util::to_uint("10") == 10U); - BOOST_TEST(string_util::to_uint<std::uint8_t>("10") == 10U); - BOOST_TEST(string_util::to_uint<std::uint16_t>("1000") == 1000U); - BOOST_TEST(string_util::to_uint<std::uint32_t>("1000") == 1000U); -} - -BOOST_AUTO_TEST_CASE(unsigned_to_uint64) -{ - BOOST_TEST(string_util::to_uint<std::uint64_t>("18446744073709551615") == 18446744073709551615ULL); -} - -BOOST_AUTO_TEST_SUITE_END() - -BOOST_AUTO_TEST_SUITE(errors) - -BOOST_AUTO_TEST_CASE(invalid_argument) -{ - BOOST_REQUIRE_THROW(string_util::to_int("plopation"), std::invalid_argument); - BOOST_REQUIRE_THROW(string_util::to_uint("plopation"), std::invalid_argument); -} - -BOOST_AUTO_TEST_CASE(out_of_range) -{ - BOOST_REQUIRE_THROW(string_util::to_int<std::int8_t>("1000"), std::out_of_range); - BOOST_REQUIRE_THROW(string_util::to_int<std::int8_t>("-1000"), std::out_of_range); - BOOST_REQUIRE_THROW(string_util::to_uint<std::uint8_t>("1000"), std::out_of_range); - BOOST_REQUIRE_THROW(string_util::to_uint<std::uint8_t>("-1000"), std::out_of_range); -} - -BOOST_AUTO_TEST_SUITE_END() - -/* * fs_util::find function (name) * ------------------------------------------------------------------ */