20 static std::pair<std::string, std::string> validate_address(
21 const ParsedAddress& addr,
const std::string& default_port =
"0")
23 auto found = addr.find_last_of(
":");
24 auto hostname = addr.substr(0, found);
27 found == std::string::npos ? default_port : addr.substr(found + 1);
32 std::from_chars(port.data(), port.data() + port.size(), port_n);
33 if (ec == std::errc::invalid_argument)
35 throw std::logic_error(fmt::format(
"Port '{}' is not a number", port));
37 else if (ec == std::errc::result_out_of_range)
39 throw std::logic_error(
40 fmt::format(
"Port '{}' is not in range 0-65535", port));
42 else if (ec != std::errc())
44 throw std::logic_error(fmt::format(
"Error parsing port '{}'", port));
47 return std::make_pair(hostname, port);
50 static bool parse_address(
51 const std::string& addr,
53 const std::string& option_name,
54 const std::string& default_port =
"0")
58 validate_address(addr, default_port);
60 catch (
const std::exception& e)
62 throw CLI::ValidationError(option_name, e.what());
70 static CLI::Option* add_address_option(
73 const std::string& option_name,
74 const std::string& option_desc,
75 const std::string& default_port =
"0")
77 CLI::callback_t fun = [&parsed, option_name, default_port](
78 CLI::results_t results) {
79 if (results.size() != 1)
81 throw CLI::ValidationError(option_name,
"Address could not be parsed");
84 auto addr = results[0];
85 return parse_address(addr, parsed, option_name, default_port);
88 auto* option = app.add_option(option_name, fun, option_desc,
true);
89 option->type_name(
"HOST:PORT");
94 static const std::string IP_ADDRESS_PREFIX(
"iPAddress:");
95 static const std::string DNS_NAME_PREFIX(
"dNSName:");
97 static CLI::Option* add_subject_alternative_name_option(
99 std::vector<ccf::crypto::SubjectAltName>& parsed,
100 const std::string& option_name,
101 const std::string& option_desc)
103 CLI::callback_t fun = [&parsed, option_name](CLI::results_t results) {
104 for (
auto& result : results)
106 if (result.starts_with(IP_ADDRESS_PREFIX))
108 parsed.push_back({result.substr(IP_ADDRESS_PREFIX.size()),
true});
110 else if (result.starts_with(DNS_NAME_PREFIX))
112 parsed.push_back({result.substr(DNS_NAME_PREFIX.size()),
false});
116 throw CLI::ValidationError(
119 "SAN could not be parsed: {}, must be (iPAddress|dNSName):VALUE",
127 auto* option = app.add_option(option_name, fun, option_desc,
true);
128 option->type_name(
"(iPAddress|dNSName):VALUE")->type_size(-1);