From 1afd1b7c9435218968a6aa203a708f679e7c6975 Mon Sep 17 00:00:00 2001 From: loki Date: Wed, 9 Jun 2021 21:55:13 +0200 Subject: [PATCH] generate user credentials based on command line iuput --- sunshine/config.cpp | 44 +++++++++++++------------------ sunshine/config.h | 6 +++++ sunshine/confighttp.cpp | 2 +- sunshine/httpcommon.cpp | 14 ++++++---- sunshine/httpcommon.h | 7 ++++- sunshine/main.cpp | 57 ++++++++++++++++++++++++++++++++++++++++- sunshine/main.h | 2 ++ 7 files changed, 98 insertions(+), 34 deletions(-) diff --git a/sunshine/config.cpp b/sunshine/config.cpp index 00a43dd2..da29f8ed 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -210,12 +210,14 @@ input_t input { }; sunshine_t sunshine { - 2, // min_log_level - 0, // flags - {}, //User file - {}, //Username - {}, //Password - {} //Password Salt + 2, // min_log_level + 0, // flags + {}, // User file + {}, // Username + {}, // Password + {}, // Password Salt + SUNSHINE_ASSETS_DIR "/sunshine.conf", // config file + {} // cmd args }; bool endline(char ch) { @@ -500,19 +502,6 @@ void list_int_f(std::unordered_map &vars, const std::s } } -void print_help(const char *name) { - std::cout - << "Usage: "sv << name << " [options] [/path/to/configuration_file]"sv << std::endl - << " Any configurable option can be overwritten with: \"name=value\""sv << std::endl - << std::endl - << " --help | print help"sv << std::endl - << std::endl - << " flags"sv << std::endl - << " -0 | Read PIN from stdin"sv << std::endl - << " -1 | Do not load previously saved state and do retain any state after shutdown"sv << std::endl - << " | Effectively starting as if for the first time without overwriting any pairings with your devices"sv; -} - int apply_flags(const char *line) { int ret = 0; while(*line != '\0') { @@ -651,11 +640,9 @@ void apply_config(std::unordered_map &&vars) { } int parse(int argc, char *argv[]) { - const char *config_file = SUNSHINE_ASSETS_DIR "/sunshine.conf"; - std::unordered_map cmd_vars; - for(auto x = argc - 1; x > 0; --x) { + for(auto x = 1; x < argc; ++x) { auto line = argv[x]; if(line == "--help"sv) { @@ -663,6 +650,13 @@ int parse(int argc, char *argv[]) { return 1; } else if(*line == '-') { + if(*(line + 1) == '-') { + sunshine.cmd.name = line + 2; + sunshine.cmd.argc = argc - x - 1; + sunshine.cmd.argv = argv + x + 1; + + break; + } if(apply_flags(line + 1)) { print_help(*argv); return -1; @@ -673,7 +667,7 @@ int parse(int argc, char *argv[]) { auto pos = std::find(line, line_end, '='); if(pos == line_end) { - config_file = line; + sunshine.config_file = line; } else { TUPLE_EL(var, 1, parse_option(line, line_end)); @@ -687,9 +681,7 @@ int parse(int argc, char *argv[]) { } } - sunshine.config_file = config_file; - - auto vars = parse_config(read_file(config_file)); + auto vars = parse_config(read_file(sunshine.config_file.c_str())); for(auto &[name, value] : cmd_vars) { vars.insert_or_assign(std::move(name), std::move(value)); diff --git a/sunshine/config.h b/sunshine/config.h index 45640b8d..1ff02801 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -96,6 +96,12 @@ struct sunshine_t { std::string salt; std::string config_file; + + struct cmd_t { + std::string name; + int argc; + char **argv; + } cmd; }; extern video_t video; diff --git a/sunshine/confighttp.cpp b/sunshine/confighttp.cpp index 7234cb3f..7dec86e3 100644 --- a/sunshine/confighttp.cpp +++ b/sunshine/confighttp.cpp @@ -405,7 +405,7 @@ void savePassword(resp_https_t response, req_https_t request) { outputTree.put("error", "Password Mismatch"); } - http::save_user_creds(config::sunshine.credentials_file, newUsername, newPassword, crypto::rand_alphabet(16)); + http::save_user_creds(config::sunshine.credentials_file, newUsername, newPassword); http::reload_user_creds(config::sunshine.credentials_file); outputTree.put("status", true); } diff --git a/sunshine/httpcommon.cpp b/sunshine/httpcommon.cpp index 05beb899..a5f3f144 100644 --- a/sunshine/httpcommon.cpp +++ b/sunshine/httpcommon.cpp @@ -53,7 +53,7 @@ void init(std::shared_ptr shutdown_event) { } } if(!user_creds_exist(config::sunshine.credentials_file)) { - if(save_user_creds(config::sunshine.credentials_file, "sunshine"s, crypto::rand_alphabet(16), crypto::rand_alphabet(16))) { + if(save_user_creds(config::sunshine.credentials_file, "sunshine"s, crypto::rand_alphabet(16), true)) { shutdown_event->raise(true); return; } @@ -64,7 +64,7 @@ void init(std::shared_ptr shutdown_event) { } } -int save_user_creds(const std::string &file, const std::string &username, const std::string &password, const std::string &salt) { +int save_user_creds(const std::string &file, const std::string &username, const std::string &password, bool run_our_mouth) { pt::ptree outputTree; if(fs::exists(file)) { @@ -77,7 +77,8 @@ int save_user_creds(const std::string &file, const std::string &username, const } } - outputTree.put("username", "sunshine"); + auto salt = crypto::rand_alphabet(16); + outputTree.put("username", username); outputTree.put("salt", salt); outputTree.put("password", util::hex(crypto::hash(password + salt)).to_string()); try { @@ -89,8 +90,11 @@ int save_user_creds(const std::string &file, const std::string &username, const } BOOST_LOG(info) << "New credentials have been created"sv; - BOOST_LOG(info) << "Username: "sv << username; - BOOST_LOG(info) << "Password: "sv << password; + + if(run_our_mouth) { + BOOST_LOG(info) << "Username: "sv << username; + BOOST_LOG(info) << "Password: "sv << password; + } return 0; } diff --git a/sunshine/httpcommon.h b/sunshine/httpcommon.h index ba2d587f..2153bce1 100644 --- a/sunshine/httpcommon.h +++ b/sunshine/httpcommon.h @@ -5,7 +5,12 @@ namespace http { void init(std::shared_ptr shutdown_event); int create_creds(const std::string &pkey, const std::string &cert); -int save_user_creds(const std::string &file, const std::string &username, const std::string &password, const std::string &salt); +int save_user_creds( + const std::string &file, + const std::string &username, + const std::string &password, + bool run_our_mouth = false); + int reload_user_creds(const std::string &file); extern std::string unique_id; extern net::net_e origin_pin_allowed; diff --git a/sunshine/main.cpp b/sunshine/main.cpp index a2e45504..caf820fc 100644 --- a/sunshine/main.cpp +++ b/sunshine/main.cpp @@ -6,9 +6,9 @@ #include #include +#include #include #include -#include #include #include @@ -52,6 +52,27 @@ struct NoDelete { BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) +void print_help(const char *name) { + std::cout + << "Usage: "sv << name << " [options] [/path/to/configuration_file] [--cmd]"sv << std::endl + << " Any configurable option can be overwritten with: \"name=value\""sv << std::endl + << std::endl + << " --help | print help"sv << std::endl + << " --creds username password | set user credentials for the Web manager" << std::endl + << std::endl + << " flags"sv << std::endl + << " -0 | Read PIN from stdin"sv << std::endl + << " -1 | Do not load previously saved state and do retain any state after shutdown"sv << std::endl + << " | Effectively starting as if for the first time without overwriting any pairings with your devices"sv << std::endl; +} + +namespace help { +int entry(const char *name, int argc, char *argv[]) { + print_help(name); + return 0; +} +} // namespace help + void log_flush() { sink->flush(); } @@ -68,6 +89,24 @@ void on_signal(int sig, FN &&fn) { std::signal(sig, on_signal_forwarder); } +namespace gen_creds { +int entry(const char *name, int argc, char *argv[]) { + if(argc < 2 || argv[0] == "help"sv || argv[1] == "help"sv) { + print_help(name); + return 0; + } + + http::save_user_creds(config::sunshine.credentials_file, argv[0], argv[1]); + + return 0; +} +} // namespace gen_creds + +std::map> cmd_to_func { + { "creds"sv, gen_creds::entry }, + { "help"sv, help::entry } +}; + int main(int argc, char *argv[]) { if(config::parse(argc, argv)) { return 0; @@ -123,6 +162,22 @@ int main(int argc, char *argv[]) { bl::core::get()->add_sink(sink); auto fg = util::fail_guard(log_flush); + if(!config::sunshine.cmd.name.empty()) { + auto fn = cmd_to_func.find(config::sunshine.cmd.name); + if(fn == std::end(cmd_to_func)) { + BOOST_LOG(fatal) << "Unknown command: "sv << config::sunshine.cmd.name; + + BOOST_LOG(info) << "Possible commands:"sv; + for(auto &[key, _] : cmd_to_func) { + BOOST_LOG(info) << '\t' << key; + } + + return 7; + } + + return fn->second(argv[0], config::sunshine.cmd.argc, config::sunshine.cmd.argv); + } + // Create signal handler after logging has been initialized auto shutdown_event = std::make_shared>(); on_signal(SIGINT, [shutdown_event]() { diff --git a/sunshine/main.h b/sunshine/main.h index ce34cd4b..8b767ad1 100644 --- a/sunshine/main.h +++ b/sunshine/main.h @@ -20,6 +20,8 @@ extern boost::log::sources::severity_logger fatal; void log_flush(); +void print_help(const char *name); + std::string read_file(const char *path); int write_file(const char *path, const std::string_view &contents); #endif //SUNSHINE_MAIN_H