2023-05-07 18:12:39 -04:00
|
|
|
/**
|
|
|
|
* @file src/httpcommon.cpp
|
|
|
|
* @brief todo
|
|
|
|
*/
|
2021-06-08 22:23:39 +02:00
|
|
|
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
|
|
|
2021-05-11 23:38:45 +02:00
|
|
|
#include "process.h"
|
|
|
|
|
|
|
|
#include <filesystem>
|
2024-04-26 12:49:15 -07:00
|
|
|
#include <utility>
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2021-06-08 21:58:32 +02:00
|
|
|
#include <boost/property_tree/json_parser.hpp>
|
2021-05-11 23:38:45 +02:00
|
|
|
#include <boost/property_tree/ptree.hpp>
|
|
|
|
#include <boost/property_tree/xml_parser.hpp>
|
|
|
|
|
|
|
|
#include <boost/asio/ssl/context.hpp>
|
|
|
|
|
|
|
|
#include <Simple-Web-Server/server_http.hpp>
|
|
|
|
#include <Simple-Web-Server/server_https.hpp>
|
|
|
|
#include <boost/asio/ssl/context_base.hpp>
|
2022-11-19 01:07:22 +09:00
|
|
|
#include <curl/curl.h>
|
2021-05-11 23:38:45 +02:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "crypto.h"
|
2024-02-10 07:37:27 -05:00
|
|
|
#include "file_handler.h"
|
2021-06-08 21:58:32 +02:00
|
|
|
#include "httpcommon.h"
|
2024-02-07 09:59:24 -05:00
|
|
|
#include "logging.h"
|
2021-06-08 21:58:32 +02:00
|
|
|
#include "network.h"
|
2021-05-11 23:38:45 +02:00
|
|
|
#include "nvhttp.h"
|
|
|
|
#include "platform/common.h"
|
2021-06-08 21:58:32 +02:00
|
|
|
#include "rtsp.h"
|
|
|
|
#include "utility.h"
|
2021-05-11 23:38:45 +02:00
|
|
|
#include "uuid.h"
|
|
|
|
|
2021-05-29 22:29:10 +02:00
|
|
|
namespace http {
|
2023-03-27 21:45:29 -04:00
|
|
|
using namespace std::literals;
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
namespace pt = boost::property_tree;
|
|
|
|
|
|
|
|
int
|
|
|
|
reload_user_creds(const std::string &file);
|
|
|
|
bool
|
|
|
|
user_creds_exist(const std::string &file);
|
|
|
|
|
|
|
|
std::string unique_id;
|
|
|
|
net::net_e origin_web_ui_allowed;
|
|
|
|
|
|
|
|
int
|
|
|
|
init() {
|
|
|
|
bool clean_slate = config::sunshine.flags[config::flag::FRESH_STATE];
|
|
|
|
origin_web_ui_allowed = net::from_enum_string(config::nvhttp.origin_web_ui_allowed);
|
|
|
|
|
|
|
|
if (clean_slate) {
|
|
|
|
unique_id = uuid_util::uuid_t::generate().string();
|
|
|
|
auto dir = std::filesystem::temp_directory_path() / "Sunshine"sv;
|
|
|
|
config::nvhttp.cert = (dir / ("cert-"s + unique_id)).string();
|
|
|
|
config::nvhttp.pkey = (dir / ("pkey-"s + unique_id)).string();
|
|
|
|
}
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
if (!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) {
|
|
|
|
if (create_creds(config::nvhttp.pkey, config::nvhttp.cert)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2021-05-28 22:49:27 +02:00
|
|
|
}
|
2023-03-27 21:45:29 -04:00
|
|
|
if (user_creds_exist(config::sunshine.credentials_file)) {
|
|
|
|
if (reload_user_creds(config::sunshine.credentials_file)) return -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BOOST_LOG(info) << "Open the Web UI to set your new username and password and getting started";
|
|
|
|
}
|
|
|
|
return 0;
|
2021-05-29 22:29:10 +02:00
|
|
|
}
|
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
int
|
|
|
|
save_user_creds(const std::string &file, const std::string &username, const std::string &password, bool run_our_mouth) {
|
|
|
|
pt::ptree outputTree;
|
2021-06-09 19:12:00 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
2021-06-09 19:12:00 +02:00
|
|
|
try {
|
2023-03-27 21:45:29 -04:00
|
|
|
pt::write_json(file, outputTree);
|
2021-06-09 19:12:00 +02:00
|
|
|
}
|
2023-03-27 21:45:29 -04:00
|
|
|
catch (std::exception &e) {
|
2023-04-29 00:22:01 -05:00
|
|
|
BOOST_LOG(error) << "error writing to the credentials file, perhaps try this again as an administrator? Details: "sv << e.what();
|
2021-06-09 19:12:00 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
BOOST_LOG(info) << "New credentials have been created"sv;
|
|
|
|
return 0;
|
2021-05-29 22:29:10 +02:00
|
|
|
}
|
2021-06-09 19:12:00 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
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();
|
|
|
|
}
|
2021-05-29 22:29:10 +02:00
|
|
|
|
2021-06-09 19:12:00 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
int
|
|
|
|
reload_user_creds(const std::string &file) {
|
|
|
|
pt::ptree inputTree;
|
|
|
|
try {
|
|
|
|
pt::read_json(file, inputTree);
|
|
|
|
config::sunshine.username = inputTree.get<std::string>("username");
|
|
|
|
config::sunshine.password = inputTree.get<std::string>("password");
|
|
|
|
config::sunshine.salt = inputTree.get<std::string>("salt");
|
|
|
|
}
|
|
|
|
catch (std::exception &e) {
|
|
|
|
BOOST_LOG(error) << "loading user credentials: "sv << e.what();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2021-06-09 19:12:00 +02:00
|
|
|
}
|
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
int
|
|
|
|
create_creds(const std::string &pkey, const std::string &cert) {
|
|
|
|
fs::path pkey_path = pkey;
|
|
|
|
fs::path cert_path = cert;
|
2021-06-09 19:12:00 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
auto creds = crypto::gen_creds("Sunshine Gamestream Host"sv, 2048);
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
auto pkey_dir = pkey_path;
|
|
|
|
auto cert_dir = cert_path;
|
|
|
|
pkey_dir.remove_filename();
|
|
|
|
cert_dir.remove_filename();
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
std::error_code err_code {};
|
|
|
|
fs::create_directories(pkey_dir, err_code);
|
|
|
|
if (err_code) {
|
|
|
|
BOOST_LOG(error) << "Couldn't create directory ["sv << pkey_dir << "] :"sv << err_code.message();
|
|
|
|
return -1;
|
|
|
|
}
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
fs::create_directories(cert_dir, err_code);
|
|
|
|
if (err_code) {
|
|
|
|
BOOST_LOG(error) << "Couldn't create directory ["sv << cert_dir << "] :"sv << err_code.message();
|
|
|
|
return -1;
|
|
|
|
}
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2024-02-10 07:37:27 -05:00
|
|
|
if (file_handler::write_file(pkey.c_str(), creds.pkey)) {
|
2023-03-27 21:45:29 -04:00
|
|
|
BOOST_LOG(error) << "Couldn't open ["sv << config::nvhttp.pkey << ']';
|
|
|
|
return -1;
|
|
|
|
}
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2024-02-10 07:37:27 -05:00
|
|
|
if (file_handler::write_file(cert.c_str(), creds.x509)) {
|
2023-03-27 21:45:29 -04:00
|
|
|
BOOST_LOG(error) << "Couldn't open ["sv << config::nvhttp.cert << ']';
|
|
|
|
return -1;
|
|
|
|
}
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
fs::permissions(pkey_path,
|
|
|
|
fs::perms::owner_read | fs::perms::owner_write,
|
|
|
|
fs::perm_options::replace, err_code);
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
if (err_code) {
|
|
|
|
BOOST_LOG(error) << "Couldn't change permissions of ["sv << config::nvhttp.pkey << "] :"sv << err_code.message();
|
|
|
|
return -1;
|
|
|
|
}
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
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);
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
if (err_code) {
|
|
|
|
BOOST_LOG(error) << "Couldn't change permissions of ["sv << config::nvhttp.cert << "] :"sv << err_code.message();
|
|
|
|
return -1;
|
|
|
|
}
|
2021-05-11 23:38:45 +02:00
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
return 0;
|
2021-05-29 22:29:10 +02:00
|
|
|
}
|
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
bool
|
|
|
|
download_file(const std::string &url, const std::string &file) {
|
|
|
|
CURL *curl = curl_easy_init();
|
|
|
|
if (!curl) {
|
|
|
|
BOOST_LOG(error) << "Couldn't create CURL instance";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
FILE *fp = fopen(file.c_str(), "wb");
|
|
|
|
if (!fp) {
|
|
|
|
BOOST_LOG(error) << "Couldn't open ["sv << file << ']';
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
|
|
|
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
2022-11-19 01:07:22 +09:00
|
|
|
#ifdef _WIN32
|
2023-03-27 21:45:29 -04:00
|
|
|
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
|
2022-11-19 01:07:22 +09:00
|
|
|
#endif
|
2023-03-27 21:45:29 -04:00
|
|
|
CURLcode result = curl_easy_perform(curl);
|
|
|
|
if (result != CURLE_OK) {
|
|
|
|
BOOST_LOG(error) << "Couldn't download ["sv << url << ", code:" << result << ']';
|
|
|
|
}
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
fclose(fp);
|
|
|
|
return result == CURLE_OK;
|
2022-11-19 01:07:22 +09:00
|
|
|
}
|
2023-03-27 21:45:29 -04:00
|
|
|
|
|
|
|
std::string
|
|
|
|
url_escape(const std::string &url) {
|
|
|
|
CURL *curl = curl_easy_init();
|
|
|
|
char *string = curl_easy_escape(curl, url.c_str(), url.length());
|
|
|
|
std::string result(string);
|
|
|
|
curl_free(string);
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
url_get_host(const std::string &url) {
|
|
|
|
CURLU *curlu = curl_url();
|
|
|
|
curl_url_set(curlu, CURLUPART_URL, url.c_str(), url.length());
|
|
|
|
char *host;
|
|
|
|
if (curl_url_get(curlu, CURLUPART_HOST, &host, 0) != CURLUE_OK) {
|
|
|
|
curl_url_cleanup(curlu);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string result(host);
|
|
|
|
curl_free(host);
|
2022-11-19 01:07:22 +09:00
|
|
|
curl_url_cleanup(curlu);
|
2023-03-27 21:45:29 -04:00
|
|
|
return result;
|
2022-11-19 01:07:22 +09:00
|
|
|
}
|
|
|
|
|
2023-03-27 21:45:29 -04:00
|
|
|
} // namespace http
|