From 17d3fcf0d0c18f2be6e13c12b5c1f9961d23e162 Mon Sep 17 00:00:00 2001 From: loki Date: Wed, 9 Jun 2021 19:12:00 +0200 Subject: [PATCH] fix adding and editing apps json --- assets/sunshine.conf | 6 +- assets/web/apps.html | 14 +-- sunshine/config.cpp | 33 +++---- sunshine/config.h | 6 +- sunshine/confighttp.cpp | 200 +++++++++++++++++++++++----------------- sunshine/httpcommon.cpp | 77 +++++++++++----- sunshine/httpcommon.h | 1 + sunshine/nvhttp.cpp | 31 ++++++- sunshine/nvhttp.h | 10 +- 9 files changed, 234 insertions(+), 144 deletions(-) diff --git a/assets/sunshine.conf b/assets/sunshine.conf index 7a67c87b..9042beb4 100644 --- a/assets/sunshine.conf +++ b/assets/sunshine.conf @@ -37,6 +37,10 @@ # The file where current state of Sunshine is stored # file_state = sunshine_state.json +# The file where user credentials for the UI are stored +# By default, credentials are stored in `file_state` +# credentials_file = sunshine_state.json + # The display modes advertised by Sunshine # # Some versions of Moonlight, such as Moonlight-nx (Switch), @@ -228,7 +232,7 @@ #################################### VAAPI ################################### ####### adapter ########## -# Unlike with `amfvce` and `nvenc`, it doesn't matter if video encoding is done +# Unlike with `amdvce` and `nvenc`, it doesn't matter if video encoding is done # on a different GPU. # Run the following commands: # 1. ls /dev/dri/renderD* diff --git a/assets/web/apps.html b/assets/web/apps.html index d1784608..6a5056d8 100644 --- a/assets/web/apps.html +++ b/assets/web/apps.html @@ -15,7 +15,8 @@ {{app.name}} - + + @@ -41,7 +42,7 @@
A list of commands to be run before/after the application.
If any of the prep-commands fail, starting the application is aborted
- +
@@ -73,7 +74,8 @@
- +
The main application, if it is not specified, a processs is started that sleeps indefinitely
@@ -84,7 +86,7 @@ -
+
@@ -113,7 +115,8 @@ output: '', cmd: [], index: -1, - "prep-cmd": [] + "prep-cmd": [], + "detached": [] }; this.editForm.index = -1; this.showEditForm = true; @@ -156,5 +159,4 @@ .monospace { font-family: monospace; } - \ No newline at end of file diff --git a/sunshine/config.cpp b/sunshine/config.cpp index f2cf391e..00a43dd2 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -7,6 +7,7 @@ #include #include "config.h" +#include "main.h" #include "utility.h" #define CA_DIR "credentials" @@ -209,12 +210,12 @@ input_t input { }; sunshine_t sunshine { - 2, // min_log_level - 0, // flags - "user_credentials.json"s, //User file - ""s, //Username - ""s, //Password - ""s //Password Salt + 2, // min_log_level + 0, // flags + {}, //User file + {}, //Username + {}, //Password + {} //Password Salt }; bool endline(char ch) { @@ -297,7 +298,7 @@ parse_option(std::string_view::const_iterator begin, std::string_view::const_ite std::make_pair(to_string(begin, end_name), to_string(begin_val, endl))); } -std::unordered_map parse_config(std::string_view file_content) { +std::unordered_map parse_config(const std::string_view &file_content) { std::unordered_map vars; auto pos = std::begin(file_content); @@ -567,6 +568,11 @@ void apply_config(std::unordered_map &&vars) { list_string_f(vars, "resolutions"s, nvhttp.resolutions); list_int_f(vars, "fps"s, nvhttp.fps); + string_f(vars, "credentials_file", config::sunshine.credentials_file); + if(config::sunshine.credentials_file.empty()) { + config::sunshine.credentials_file = config::nvhttp.file_state; + } + string_f(vars, "audio_sink", audio.sink); string_f(vars, "virtual_sink", audio.virtual_sink); @@ -681,18 +687,9 @@ int parse(int argc, char *argv[]) { } } - std::ifstream in { config_file }; + sunshine.config_file = config_file; - if(!in.is_open()) { - std::cout << "Error: Couldn't open "sv << config_file << std::endl; - - return -1; - } - - auto vars = parse_config(std::string { - // Quick and dirty - std::istreambuf_iterator(in), - std::istreambuf_iterator() }); + auto vars = parse_config(read_file(config_file)); 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 99f50408..45640b8d 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -82,7 +82,7 @@ namespace flag { enum flag_e : std::size_t { PIN_STDIN = 0, // Read PIN from stdin instead of http FRESH_STATE, // Do not load or save state - CONST_PIN = 4, // Use "universal" pin + CONST_PIN, // Use "universal" pin FLAG_SIZE }; } @@ -94,6 +94,8 @@ struct sunshine_t { std::string username; std::string password; std::string salt; + + std::string config_file; }; extern video_t video; @@ -104,6 +106,6 @@ extern input_t input; extern sunshine_t sunshine; int parse(int argc, char *argv[]); -std::unordered_map parse_config(std::string_view file_content); +std::unordered_map parse_config(const std::string_view &file_content); } // namespace config #endif diff --git a/sunshine/confighttp.cpp b/sunshine/confighttp.cpp index d5db6fd9..7234cb3f 100644 --- a/sunshine/confighttp.cpp +++ b/sunshine/confighttp.cpp @@ -30,8 +30,6 @@ #include "utility.h" #include "uuid.h" -std::string read_file(std::string path); - namespace confighttp { using namespace std::literals; constexpr auto PORT_HTTPS = 47990; @@ -50,6 +48,23 @@ enum class op_e { REMOVE }; +void print_req(const req_https_t &request) { + BOOST_LOG(debug) << "METHOD :: "sv << request->method; + BOOST_LOG(debug) << "DESTINATION :: "sv << request->path; + + for(auto &[name, val] : request->header) { + BOOST_LOG(debug) << name << " -- " << val; + } + + BOOST_LOG(debug) << " [--] "sv; + + for(auto &[name, val] : request->parse_query_string()) { + BOOST_LOG(debug) << name << " -- " << val; + } + + BOOST_LOG(debug) << " [--] "sv; +} + void send_unauthorized(resp_https_t response, req_https_t request) { auto address = request->remote_endpoint_address(); BOOST_LOG(info) << '[' << address << "] -- denied"sv; @@ -62,27 +77,40 @@ void send_unauthorized(resp_https_t response, req_https_t request) { bool authenticate(resp_https_t response, req_https_t request) { auto address = request->remote_endpoint_address(); auto ip_type = net::from_address(address); + if(ip_type > http::origin_pin_allowed) { BOOST_LOG(info) << '[' << address << "] -- denied"sv; response->write(SimpleWeb::StatusCode::client_error_forbidden); return false; } + + auto fg = util::fail_guard([&]() { + send_unauthorized(response, request); + }); + auto auth = request->header.find("authorization"); if(auth == request->header.end()) { - send_unauthorized(response, request); return false; } - std::string rawAuth = auth->second; - std::string authData = rawAuth.substr("Basic "sv.length()); - authData = SimpleWeb::Crypto::Base64::decode(authData); - int index = authData.find(':'); - std::string username = authData.substr(0, index); - std::string password = authData.substr(index + 1); - std::string hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string(); - if(username == config::sunshine.username && hash == config::sunshine.password) return true; - send_unauthorized(response, request); - return false; + auto &rawAuth = auth->second; + auto authData = SimpleWeb::Crypto::Base64::decode(rawAuth.substr("Basic "sv.length())); + + int index = authData.find(':'); + if(index >= authData.size() - 1) { + return false; + } + + auto username = authData.substr(0, index); + auto password = authData.substr(index + 1); + auto hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string(); + + if(username != config::sunshine.username || hash != config::sunshine.password) { + return false; + } + + fg.disable(); + return true; } void not_found(resp_https_t response, req_https_t request) { @@ -101,6 +129,8 @@ void not_found(resp_https_t response, req_https_t request) { void getIndexPage(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::string header = read_file(WEB_DIR "header.html"); std::string content = read_file(WEB_DIR "index.html"); response->write(header + content); @@ -109,6 +139,8 @@ void getIndexPage(resp_https_t response, req_https_t request) { void getPinPage(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::string header = read_file(WEB_DIR "header.html"); std::string content = read_file(WEB_DIR "pin.html"); response->write(header + content); @@ -117,6 +149,8 @@ void getPinPage(resp_https_t response, req_https_t request) { void getAppsPage(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::string header = read_file(WEB_DIR "header.html"); std::string content = read_file(WEB_DIR "apps.html"); response->write(header + content); @@ -125,6 +159,8 @@ void getAppsPage(resp_https_t response, req_https_t request) { void getClientsPage(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::string header = read_file(WEB_DIR "header.html"); std::string content = read_file(WEB_DIR "clients.html"); response->write(header + content); @@ -133,6 +169,8 @@ void getClientsPage(resp_https_t response, req_https_t request) { void getConfigPage(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::string header = read_file(WEB_DIR "header.html"); std::string content = read_file(WEB_DIR "config.html"); response->write(header + content); @@ -141,6 +179,8 @@ void getConfigPage(resp_https_t response, req_https_t request) { void getPasswordPage(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::string header = read_file(WEB_DIR "header.html"); std::string content = read_file(WEB_DIR "password.html"); response->write(header + content); @@ -149,15 +189,20 @@ void getPasswordPage(resp_https_t response, req_https_t request) { void getApps(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; - std::string content = read_file(SUNSHINE_ASSETS_DIR "/" APPS_JSON); + print_req(request); + + std::string content = read_file(config::stream.file_apps.c_str()); response->write(content); } void saveApp(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::stringstream ss; ss << request->content.rdbuf(); + pt::ptree outputTree; auto g = util::fail_guard([&]() { std::ostringstream data; @@ -165,20 +210,28 @@ void saveApp(resp_https_t response, req_https_t request) { pt::write_json(data, outputTree); response->write(data.str()); }); + pt::ptree inputTree, fileTree; + + BOOST_LOG(fatal) << config::stream.file_apps; try { //TODO: Input Validation pt::read_json(ss, inputTree); - pt::read_json(SUNSHINE_ASSETS_DIR "/" APPS_JSON, fileTree); + pt::read_json(config::stream.file_apps, fileTree); + + if(inputTree.get_child("prep-cmd").empty()) { + inputTree.erase("prep-cmd"); + } + + if(inputTree.get_child("detached").empty()) { + inputTree.erase("detached"); + } + auto &apps_node = fileTree.get_child("apps"s); int index = inputTree.get("index"); - if(inputTree.get_child("prep-cmd").empty()) - inputTree.erase("prep-cmd"); - - if(inputTree.get_child("detached").empty()) - inputTree.erase("detached"); inputTree.erase("index"); + if(index == -1) { apps_node.push_back(std::make_pair("", inputTree)); } @@ -198,21 +251,25 @@ void saveApp(resp_https_t response, req_https_t request) { fileTree.erase("apps"); fileTree.push_back(std::make_pair("apps", newApps)); } - pt::write_json(SUNSHINE_ASSETS_DIR "/" APPS_JSON, fileTree); - outputTree.put("status", "true"); - proc::refresh(SUNSHINE_ASSETS_DIR "/" APPS_JSON); + pt::write_json(config::stream.file_apps, fileTree); } catch(std::exception &e) { - BOOST_LOG(warning) << e.what(); + BOOST_LOG(warning) << "SaveApp: "sv << e.what(); + outputTree.put("status", "false"); outputTree.put("error", "Invalid Input JSON"); return; } + + outputTree.put("status", "true"); + proc::refresh(config::stream.file_apps); } void deleteApp(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + pt::ptree outputTree; auto g = util::fail_guard([&]() { std::ostringstream data; @@ -225,8 +282,8 @@ void deleteApp(resp_https_t response, req_https_t request) { pt::read_json(config::stream.file_apps, fileTree); auto &apps_node = fileTree.get_child("apps"s); int index = stoi(request->path_match[1]); - BOOST_LOG(info) << index; - if(index <= 0) { + + if(index < 0) { outputTree.put("status", "false"); outputTree.put("error", "Invalid Index"); return; @@ -236,29 +293,31 @@ void deleteApp(resp_https_t response, req_https_t request) { pt::ptree newApps; int i = 0; for(const auto &kv : apps_node) { - if(i != index) { + if(i++ != index) { newApps.push_back(std::make_pair("", kv.second)); } - i++; } fileTree.erase("apps"); fileTree.push_back(std::make_pair("apps", newApps)); } - pt::write_json(SUNSHINE_ASSETS_DIR "/" APPS_JSON, fileTree); - outputTree.put("status", "true"); - proc::refresh(SUNSHINE_ASSETS_DIR "/" APPS_JSON); + pt::write_json(config::stream.file_apps, fileTree); } catch(std::exception &e) { - BOOST_LOG(warning) << e.what(); + BOOST_LOG(warning) << "DeleteApp: "sv << e.what(); outputTree.put("status", "false"); outputTree.put("error", "Invalid File JSON"); return; } + + outputTree.put("status", "true"); + proc::refresh(config::stream.file_apps); } void getConfig(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + pt::ptree outputTree; auto g = util::fail_guard([&]() { std::ostringstream data; @@ -266,36 +325,22 @@ void getConfig(resp_https_t response, req_https_t request) { pt::write_json(data, outputTree); response->write(data.str()); }); - try { - outputTree.put("status", "true"); - outputTree.put("platform", SUNSHINE_PLATFORM); - const char *config_file = SUNSHINE_ASSETS_DIR "/sunshine.conf"; - std::ifstream in { config_file }; - if(!in.is_open()) { - std::cout << "Error: Couldn't open "sv << config_file << std::endl; - } + outputTree.put("status", "true"); + outputTree.put("platform", SUNSHINE_PLATFORM); - auto vars = config::parse_config(std::string { - // Quick and dirty - std::istreambuf_iterator(in), - std::istreambuf_iterator() }); + auto vars = config::parse_config(read_file(config::sunshine.config_file.c_str())); - for(auto &[name, value] : vars) { - outputTree.put(std::move(name), std::move(value)); - } - } - catch(std::exception &e) { - BOOST_LOG(warning) << e.what(); - outputTree.put("status", "false"); - outputTree.put("error", "Invalid File JSON"); - return; + for(auto &[name, value] : vars) { + outputTree.put(std::move(name), std::move(value)); } } void saveConfig(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::stringstream ss; std::stringstream configStream; ss << request->content.rdbuf(); @@ -316,10 +361,10 @@ void saveConfig(resp_https_t response, req_https_t request) { configStream << kv.first << " = " << value << std::endl; } - write_file(SUNSHINE_ASSETS_DIR "/sunshine.conf", configStream.str()); + write_file(config::sunshine.config_file.c_str(), configStream.str()); } catch(std::exception &e) { - BOOST_LOG(warning) << e.what(); + BOOST_LOG(warning) << "SaveConfig: "sv << e.what(); outputTree.put("status", "false"); outputTree.put("error", e.what()); return; @@ -329,11 +374,13 @@ void saveConfig(resp_https_t response, req_https_t request) { void savePassword(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::stringstream ss; std::stringstream configStream; ss << request->content.rdbuf(); - pt::ptree inputTree, outputTree, fileTree; + pt::ptree inputTree, outputTree; auto g = util::fail_guard([&]() { std::ostringstream data; @@ -344,23 +391,21 @@ void savePassword(resp_https_t response, req_https_t request) { try { //TODO: Input Validation pt::read_json(ss, inputTree); - std::string username = inputTree.get("currentUsername"); - std::string newUsername = inputTree.get("newUsername"); - std::string password = inputTree.get("currentPassword"); - std::string newPassword = inputTree.get("newPassword"); - std::string confirmPassword = inputTree.get("confirmNewPassword"); + auto username = inputTree.get("currentUsername"); + auto newUsername = inputTree.get("newUsername"); + auto password = inputTree.get("currentPassword"); + auto newPassword = inputTree.get("newPassword"); + auto confirmPassword = inputTree.get("confirmNewPassword"); if(newUsername.length() == 0) newUsername = username; - std::string hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string(); + auto hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string(); if(username == config::sunshine.username && hash == config::sunshine.password) { if(newPassword != confirmPassword) { outputTree.put("status", false); outputTree.put("error", "Password Mismatch"); } - fileTree.put("username", newUsername); - fileTree.put("password", util::hex(crypto::hash(newPassword + config::sunshine.salt)).to_string()); - fileTree.put("salt", config::sunshine.salt); - pt::write_json(config::sunshine.credentials_file, fileTree); + + http::save_user_creds(config::sunshine.credentials_file, newUsername, newPassword, crypto::rand_alphabet(16)); http::reload_user_creds(config::sunshine.credentials_file); outputTree.put("status", true); } @@ -370,7 +415,7 @@ void savePassword(resp_https_t response, req_https_t request) { } } catch(std::exception &e) { - BOOST_LOG(warning) << e.what(); + BOOST_LOG(warning) << "SavePassword: "sv << e.what(); outputTree.put("status", false); outputTree.put("error", e.what()); return; @@ -380,6 +425,8 @@ void savePassword(resp_https_t response, req_https_t request) { void savePin(resp_https_t response, req_https_t request) { if(!authenticate(response, request)) return; + print_req(request); + std::stringstream ss; ss << request->content.rdbuf(); @@ -398,7 +445,7 @@ void savePin(resp_https_t response, req_https_t request) { outputTree.put("status", nvhttp::pin(pin)); } catch(std::exception &e) { - BOOST_LOG(warning) << e.what(); + BOOST_LOG(warning) << "SavePin: "sv << e.what(); outputTree.put("status", false); outputTree.put("error", e.what()); return; @@ -462,19 +509,4 @@ void start(std::shared_ptr shutdown_event) { tcp.join(); } -} // namespace confighttp - -std::string read_file(std::string path) { - std::ifstream in(path); - - std::string input; - std::string base64_cert; - - //FIXME: Being unable to read file could result in infinite loop - while(!in.eof()) { - std::getline(in, input); - base64_cert += input + '\n'; - } - - return base64_cert; -} \ No newline at end of file +} // namespace confighttp \ No newline at end of file diff --git a/sunshine/httpcommon.cpp b/sunshine/httpcommon.cpp index a68b7eb3..05beb899 100644 --- a/sunshine/httpcommon.cpp +++ b/sunshine/httpcommon.cpp @@ -30,9 +30,9 @@ using namespace std::literals; namespace fs = std::filesystem; namespace pt = boost::property_tree; -int create_creds(const std::string &pkey, const std::string &cert); -int generate_user_creds(const std::string &file); int reload_user_creds(const std::string &file); +bool user_creds_exist(const std::string &file); + std::string unique_id; net::net_e origin_pin_allowed; @@ -52,8 +52,8 @@ void init(std::shared_ptr shutdown_event) { return; } } - if(!fs::exists(config::sunshine.credentials_file)) { - if(generate_user_creds(config::sunshine.credentials_file)) { + 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))) { shutdown_event->raise(true); return; } @@ -64,27 +64,56 @@ void init(std::shared_ptr shutdown_event) { } } -int generate_user_creds(const std::string &file) { +int save_user_creds(const std::string &file, const std::string &username, const std::string &password, const std::string &salt) { pt::ptree outputTree; + + if(fs::exists(file)) { + try { + pt::read_json(file, outputTree); + } + catch(std::exception &e) { + BOOST_LOG(error) << "Couldn't read user credentials: "sv << e.what(); + return -1; + } + } + + outputTree.put("username", "sunshine"); + outputTree.put("salt", salt); + outputTree.put("password", util::hex(crypto::hash(password + salt)).to_string()); try { - std::string username = "sunshine"; - std::string plainPassword = crypto::rand_alphabet(16); - std::string salt = crypto::rand_alphabet(16); - outputTree.put("username", "sunshine"); - outputTree.put("salt", salt); - outputTree.put("password", util::hex(crypto::hash(plainPassword + salt)).to_string()); - BOOST_LOG(info) << "New credentials have been created"; - BOOST_LOG(info) << "Username: " << username; - BOOST_LOG(info) << "Password: " << plainPassword; pt::write_json(file, outputTree); } catch(std::exception &e) { - BOOST_LOG(fatal) << e.what(); - return 1; + BOOST_LOG(error) << "generating user credentials: "sv << e.what(); + return -1; } + + BOOST_LOG(info) << "New credentials have been created"sv; + BOOST_LOG(info) << "Username: "sv << username; + BOOST_LOG(info) << "Password: "sv << password; + return 0; } +bool user_creds_exist(const std::string &file) { + if(!fs::exists(file)) { + return false; + } + + pt::ptree inputTree; + try { + pt::read_json(file, inputTree); + return inputTree.find("username") != inputTree.not_found() && + inputTree.find("password") != inputTree.not_found() && + inputTree.find("salt") != inputTree.not_found(); + } + catch(std::exception &e) { + BOOST_LOG(error) << "validating user credentials: "sv << e.what(); + } + + return false; +} + int reload_user_creds(const std::string &file) { pt::ptree inputTree; try { @@ -94,8 +123,8 @@ int reload_user_creds(const std::string &file) { config::sunshine.salt = inputTree.get("salt"); } catch(std::exception &e) { - BOOST_LOG(fatal) << e.what(); - return 1; + BOOST_LOG(error) << "loading user credentials: "sv << e.what(); + return -1; } return 0; } @@ -114,23 +143,23 @@ int create_creds(const std::string &pkey, const std::string &cert) { std::error_code err_code {}; fs::create_directories(pkey_dir, err_code); if(err_code) { - BOOST_LOG(fatal) << "Couldn't create directory ["sv << pkey_dir << "] :"sv << err_code.message(); + BOOST_LOG(error) << "Couldn't create directory ["sv << pkey_dir << "] :"sv << err_code.message(); return -1; } fs::create_directories(cert_dir, err_code); if(err_code) { - BOOST_LOG(fatal) << "Couldn't create directory ["sv << cert_dir << "] :"sv << err_code.message(); + BOOST_LOG(error) << "Couldn't create directory ["sv << cert_dir << "] :"sv << err_code.message(); return -1; } if(write_file(pkey.c_str(), creds.pkey)) { - BOOST_LOG(fatal) << "Couldn't open ["sv << config::nvhttp.pkey << ']'; + BOOST_LOG(error) << "Couldn't open ["sv << config::nvhttp.pkey << ']'; return -1; } if(write_file(cert.c_str(), creds.x509)) { - BOOST_LOG(fatal) << "Couldn't open ["sv << config::nvhttp.cert << ']'; + BOOST_LOG(error) << "Couldn't open ["sv << config::nvhttp.cert << ']'; return -1; } @@ -139,7 +168,7 @@ int create_creds(const std::string &pkey, const std::string &cert) { fs::perm_options::replace, err_code); if(err_code) { - BOOST_LOG(fatal) << "Couldn't change permissions of ["sv << config::nvhttp.pkey << "] :"sv << err_code.message(); + BOOST_LOG(error) << "Couldn't change permissions of ["sv << config::nvhttp.pkey << "] :"sv << err_code.message(); return -1; } @@ -148,7 +177,7 @@ int create_creds(const std::string &pkey, const std::string &cert) { fs::perm_options::replace, err_code); if(err_code) { - BOOST_LOG(fatal) << "Couldn't change permissions of ["sv << config::nvhttp.cert << "] :"sv << err_code.message(); + BOOST_LOG(error) << "Couldn't change permissions of ["sv << config::nvhttp.cert << "] :"sv << err_code.message(); return -1; } diff --git a/sunshine/httpcommon.h b/sunshine/httpcommon.h index 49923290..ba2d587f 100644 --- a/sunshine/httpcommon.h +++ b/sunshine/httpcommon.h @@ -5,6 +5,7 @@ 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 reload_user_creds(const std::string &file); extern std::string unique_id; extern net::net_e origin_pin_allowed; diff --git a/sunshine/nvhttp.cpp b/sunshine/nvhttp.cpp index 07e25422..b425ea4e 100644 --- a/sunshine/nvhttp.cpp +++ b/sunshine/nvhttp.cpp @@ -93,6 +93,18 @@ enum class op_e { void save_state() { pt::ptree root; + if(fs::exists(config::nvhttp.file_state)) { + try { + pt::read_json(config::nvhttp.file_state, root); + } + catch(std::exception &e) { + BOOST_LOG(error) << e.what(); + return; + } + } + + root.erase("root"s); + root.put("root.uniqueid", http::unique_id); auto &nodes = root.add_child("root.devices", pt::ptree {}); for(auto &[_, client] : map_id_client) { @@ -111,7 +123,13 @@ void save_state() { nodes.push_back(std::make_pair(""s, node)); } - pt::write_json(config::nvhttp.file_state, root); + try { + pt::write_json(config::nvhttp.file_state, root); + } + catch(std::exception &e) { + BOOST_LOG(error) << e.what(); + return; + } } void load_state() { @@ -131,7 +149,16 @@ void load_state() { return; } - http::unique_id = root.get("root.uniqueid"); + auto unique_id_p = root.find("root.uniqueid"s); + if(unique_id_p == root.not_found()) { + // This file doesn't contain moonlight credentials + http::unique_id = util::uuid_t::generate().string(); + return; + } + else { + http::unique_id = root.get("root.uniqueid"); + } + auto device_nodes = root.get_child("root.devices"); for(auto &[_, device_node] : device_nodes) { diff --git a/sunshine/nvhttp.h b/sunshine/nvhttp.h index f6853b60..7ee9f2c7 100644 --- a/sunshine/nvhttp.h +++ b/sunshine/nvhttp.h @@ -5,15 +5,11 @@ #ifndef SUNSHINE_NVHTTP_H #define SUNSHINE_NVHTTP_H -#include -#include +#include "thread_safe.h" #include #include -#include "thread_safe.h" - -#define CA_DIR SUNSHINE_ASSETS_DIR "/demoCA" -#define PRIVATE_KEY_FILE CA_DIR "/cakey.pem" -#define CERTIFICATE_FILE CA_DIR "/cacert.pem" +#include +#include namespace nvhttp { void start(std::shared_ptr shutdown_event);
Do Undo