From 27a1144217f16a4821fb698a880b6d2c4c40b4b2 Mon Sep 17 00:00:00 2001 From: Elia Zammuto Date: Tue, 11 May 2021 23:38:45 +0200 Subject: [PATCH] Moved Common HTTPS Initialization Logic in a common file --- CMakeLists.txt | 2 + sunshine/confighttp.cpp | 2 +- sunshine/httpcommon.cpp | 148 ++++++++++++++++++++++++++++++++++++++++ sunshine/httpcommon.h | 7 ++ sunshine/main.cpp | 4 +- sunshine/nvhttp.cpp | 117 +++---------------------------- 6 files changed, 168 insertions(+), 112 deletions(-) create mode 100644 sunshine/httpcommon.cpp create mode 100644 sunshine/httpcommon.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a85d880d..1dc30920 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,8 @@ set(SUNSHINE_TARGET_FILES sunshine/crypto.h sunshine/nvhttp.cpp sunshine/nvhttp.h + sunshine/httpcommon.cpp + sunshine/httpcommon.h sunshine/confighttp.cpp sunshine/confighttp.h sunshine/rtsp.cpp diff --git a/sunshine/confighttp.cpp b/sunshine/confighttp.cpp index 8241c9fe..c71fc0f7 100644 --- a/sunshine/confighttp.cpp +++ b/sunshine/confighttp.cpp @@ -264,7 +264,7 @@ void start(std::shared_ptr shutdown_event) return; } - BOOST_LOG(fatal) << "Couldn't start Configuration HTTP server to ports ["sv << PORT_HTTPS << ", "sv << PORT_HTTP << "]: "sv << err.what(); + BOOST_LOG(fatal) << "Couldn't start Configuration HTTP server to ports ["sv << PORT_HTTP << ", "sv << PORT_HTTP << "]: "sv << err.what(); shutdown_event->raise(true); return; } diff --git a/sunshine/httpcommon.cpp b/sunshine/httpcommon.cpp new file mode 100644 index 00000000..6c05dba9 --- /dev/null +++ b/sunshine/httpcommon.cpp @@ -0,0 +1,148 @@ +#include "process.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include "config.h" +#include "utility.h" +#include "rtsp.h" +#include "crypto.h" +#include "nvhttp.h" +#include "platform/common.h" +#include "network.h" +#include "uuid.h" +#include "main.h" +#include "httpcommon.h" + +namespace http +{ + using namespace std::literals; + namespace fs = std::filesystem; + + int create_creds(const std::string &pkey, const std::string &cert); + std::string read_file(const char *path); + int write_file(const char *path, const std::string_view &contents); + std::string unique_id; + + void init(std::shared_ptr shutdown_event) + { + bool clean_slate = config::sunshine.flags[config::flag::FRESH_STATE]; + if (clean_slate) + { + unique_id = util::uuid_t::generate().string(); + auto dir = std::filesystem::temp_directory_path() / "Sushine"sv; + config::nvhttp.cert = (dir / ("cert-"s + unique_id)).string(); + config::nvhttp.pkey = (dir / ("pkey-"s + unique_id)).string(); + } + + if (!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) + { + if (create_creds(config::nvhttp.pkey, config::nvhttp.cert)) + { + shutdown_event->raise(true); + return; + } + } + } + + int create_creds(const std::string &pkey, const std::string &cert) + { + fs::path pkey_path = pkey; + fs::path cert_path = cert; + + auto creds = crypto::gen_creds("Sunshine Gamestream Host"sv, 2048); + + auto pkey_dir = pkey_path; + auto cert_dir = cert_path; + pkey_dir.remove_filename(); + cert_dir.remove_filename(); + + 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(); + 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(); + return -1; + } + + if (write_file(pkey.c_str(), creds.pkey)) + { + BOOST_LOG(fatal) << "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 << ']'; + return -1; + } + + fs::permissions(pkey_path, + fs::perms::owner_read | fs::perms::owner_write, + 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(); + return -1; + } + + fs::permissions(cert_path, + fs::perms::owner_read | fs::perms::group_read | fs::perms::others_read | fs::perms::owner_write, + 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(); + return -1; + } + + return 0; + } + int write_file(const char *path, const std::string_view &contents) + { + std::ofstream out(path); + + if (!out.is_open()) + { + return -1; + } + + out << contents; + + return 0; + } + + std::string read_file(const char *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 diff --git a/sunshine/httpcommon.h b/sunshine/httpcommon.h new file mode 100644 index 00000000..5320025a --- /dev/null +++ b/sunshine/httpcommon.h @@ -0,0 +1,7 @@ +namespace http{ + void init(std::shared_ptr shutdown_event); + int create_creds(const std::string &pkey, const std::string &cert); + std::string read_file(const char *path); + int write_file(const char *path, const std::string_view &contents); + extern std::string unique_id; +} \ No newline at end of file diff --git a/sunshine/main.cpp b/sunshine/main.cpp index 15248deb..defaa348 100644 --- a/sunshine/main.cpp +++ b/sunshine/main.cpp @@ -17,6 +17,7 @@ #include "video.h" #include "input.h" #include "nvhttp.h" +#include "httpcommon.h" #include "confighttp.h" #include "rtsp.h" #include "config.h" @@ -137,13 +138,12 @@ int main(int argc, char *argv[]) { if(video::init()) { return 2; } - + http::init(shutdown_event); task_pool.start(1); std::thread httpThread { nvhttp::start, shutdown_event }; std::thread configThread { confighttp::start, shutdown_event }; stream::rtpThread(shutdown_event); - httpThread.join(); task_pool.stop(); task_pool.join(); diff --git a/sunshine/nvhttp.cpp b/sunshine/nvhttp.cpp index 98f5a79d..8799dc1f 100644 --- a/sunshine/nvhttp.cpp +++ b/sunshine/nvhttp.cpp @@ -25,6 +25,7 @@ #include "network.h" #include "uuid.h" #include "main.h" +#include "httpcommon.h" namespace nvhttp { @@ -38,9 +39,6 @@ constexpr auto GFE_VERSION = "3.12.0.1"; namespace fs = std::filesystem; namespace pt = boost::property_tree; -std::string read_file(const char *path); -int write_file(const char *path, const std::string_view &contents); - using https_server_t = SimpleWeb::Server; using http_server_t = SimpleWeb::Server; @@ -78,7 +76,6 @@ struct pair_session_t { // uniqueID, session std::unordered_map map_id_sess; std::unordered_map map_id_client; -std::string unique_id; net::net_e origin_pin_allowed; using args_t = SimpleWeb::CaseInsensitiveMultimap; @@ -95,7 +92,7 @@ enum class op_e { void save_state() { pt::ptree root; - root.put("root.uniqueid", unique_id); + root.put("root.uniqueid", http::unique_id); auto &nodes = root.add_child("root.devices", pt::ptree {}); for(auto &[_,client] : map_id_client) { pt::ptree node; @@ -120,7 +117,7 @@ void load_state() { auto file_state = fs::current_path() / config::nvhttp.file_state; if(!fs::exists(file_state)) { - unique_id = util::uuid_t::generate().string(); + http::unique_id = util::uuid_t::generate().string(); return; } @@ -133,7 +130,7 @@ void load_state() { return; } - unique_id = root.get("root.uniqueid"); + http::unique_id = root.get("root.uniqueid"); auto device_nodes = root.get_child("root.devices"); for(auto &[_,device_node] : device_nodes) { @@ -474,7 +471,7 @@ void serverinfo(std::shared_ptr::Response> res tree.put("root.appversion", VERSION); tree.put("root.GfeVersion", GFE_VERSION); - tree.put("root.uniqueid", unique_id); + tree.put("root.uniqueid", http::unique_id); tree.put("root.mac", platf::get_mac_address(request->local_endpoint_address())); tree.put("root.MaxLumaPixelsHEVC", config::video.hevc_mode > 1 ? "1869449984" : "0"); tree.put("root.LocalIP", request->local_endpoint_address()); @@ -677,88 +674,17 @@ void appasset(resp_https_t response, req_https_t request) { response->write(SimpleWeb::StatusCode::success_ok, in); } -int create_creds(const std::string &pkey, const std::string &cert) { - fs::path pkey_path = pkey; - fs::path cert_path = cert; - - auto creds = crypto::gen_creds("Sunshine Gamestream Host"sv, 2048); - - auto pkey_dir = pkey_path; - auto cert_dir = cert_path; - pkey_dir.remove_filename(); - cert_dir.remove_filename(); - - 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(); - 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(); - return -1; - } - - if (write_file(pkey.c_str(), creds.pkey)) { - BOOST_LOG(fatal) << "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 << ']'; - return -1; - } - - fs::permissions(pkey_path, - fs::perms::owner_read | fs::perms::owner_write, - 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(); - return -1; - } - - fs::permissions(cert_path, - fs::perms::owner_read | fs::perms::group_read | fs::perms::others_read | fs::perms::owner_write, - 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(); - return -1; - } - - return 0; -} - void start(std::shared_ptr shutdown_event) { + bool clean_slate = config::sunshine.flags[config::flag::FRESH_STATE]; - if(clean_slate) { - unique_id = util::uuid_t::generate().string(); - - auto dir = std::filesystem::temp_directory_path() / "Sushine"sv; - - config::nvhttp.cert = (dir / ("cert-"s + unique_id)).string(); - config::nvhttp.pkey = (dir / ("pkey-"s + unique_id)).string(); - } - - - if(!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) { - if(create_creds(config::nvhttp.pkey, config::nvhttp.cert)) { - shutdown_event->raise(true); - return; - } - } - origin_pin_allowed = net::from_enum_string(config::nvhttp.origin_pin_allowed); if(!clean_slate) { load_state(); } - conf_intern.pkey = read_file(config::nvhttp.pkey.c_str()); - conf_intern.servercert = read_file(config::nvhttp.cert.c_str()); + conf_intern.pkey = http::read_file(config::nvhttp.pkey.c_str()); + conf_intern.servercert = http::read_file(config::nvhttp.cert.c_str()); auto ctx = std::make_shared(boost::asio::ssl::context::tls); ctx->use_certificate_chain_file(config::nvhttp.cert); @@ -872,31 +798,4 @@ void start(std::shared_ptr shutdown_event) { ssl.join(); tcp.join(); } - -int write_file(const char *path, const std::string_view &contents) { - std::ofstream out(path); - - if(!out.is_open()) { - return -1; - } - - out << contents; - - return 0; -} - -std::string read_file(const char *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; -} }