Sunshine master
Self-hosted game stream host for Moonlight.
confighttp.cpp File Reference

Definitions for the Web UI Config HTTP server. More...

#include <algorithm>
#include <filesystem>
#include <format>
#include <fstream>
#include <string_view>
#include <boost/algorithm/string.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/filesystem.hpp>
#include <nlohmann/json.hpp>
#include <Simple-Web-Server/crypto.hpp>
#include <Simple-Web-Server/server_https.hpp>
#include "platform/windows/misc.h"
#include <vector>
#include <Windows.h>
#include "config.h"
#include "confighttp.h"
#include "crypto.h"
#include "display_device.h"
#include "file_handler.h"
#include "globals.h"
#include "httpcommon.h"
#include "logging.h"
#include "network.h"
#include "nvhttp.h"
#include "platform/common.h"
#include "process.h"
#include "rtsp.h"
#include "utility.h"
#include "uuid.h"
Include dependency graph for confighttp.cpp:

Classes

struct  confighttp::csrf_token_t
 CSRF token value and its expiration deadline. More...
 

Typedefs

using confighttp::args_t = SimpleWeb::CaseInsensitiveMultimap
 Case-insensitive map used for HTTP headers and query parameters.
 
using confighttp::https_handler_t = std::function<void(resp_https_t, req_https_t)>
 Handler signature for configuration UI HTTPS routes.
 
using confighttp::https_server_t = SimpleWeb::Server<SimpleWeb::HTTPS>
 HTTPS server type used for Sunshine's configuration UI.
 
using confighttp::req_https_t = std::shared_ptr<SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Request>
 Shared HTTPS request object received by configuration handlers.
 
using confighttp::resp_https_t = std::shared_ptr<SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Response>
 Shared HTTPS response object passed to configuration handlers.
 

Enumerations

enum class  confighttp::op_e { ADD , REMOVE }
 Client certificate operations accepted by the configuration API. More...
 

Functions

bool confighttp::authenticate (const resp_https_t &response, const req_https_t &request)
 Authenticate the user.
 
void confighttp::bad_request (const resp_https_t &response, const req_https_t &request, const std::string &error_message)
 Send a 400 Bad Request response.
 
void confighttp::browseDirectory (const resp_https_t &response, const req_https_t &request)
 Browse the server filesystem.
 
nlohmann::json confighttp::build_browse_entries (const fs::path &dir_path, const std::string &type_str)
 Lists, filters, and sorts the entries of a directory for the browse API.
 
bool confighttp::check_app_index (const resp_https_t &response, const req_https_t &request, int index)
 Validates the application index and sends an error response if invalid.
 
bool confighttp::check_content_type (const resp_https_t &response, const req_https_t &request, const std::string_view &contentType)
 Validate the request content type and send a bad request when mismatched.
 
void confighttp::closeApp (const resp_https_t &response, const req_https_t &request)
 Close the currently running application.
 
void confighttp::deleteApp (const resp_https_t &response, const req_https_t &request)
 Delete an application.
 
std::string confighttp::generate_csrf_token (const std::string &client_id)
 Generate a new CSRF token for a client.
 
std::string confighttp::get_client_id (const req_https_t &request)
 Get a unique client identifier for CSRF token management.
 
nlohmann::json confighttp::get_windows_drives ()
 Builds a JSON array of available Windows drive letters.
 
void confighttp::getApps (const resp_https_t &response, const req_https_t &request)
 Get the list of available applications.
 
void confighttp::getAsset (const resp_https_t &response, const req_https_t &request)
 Get an asset.
 
void confighttp::getClients (const resp_https_t &response, const req_https_t &request)
 Get the list of paired clients.
 
void confighttp::getConfig (const resp_https_t &response, const req_https_t &request)
 Get the configuration settings.
 
void confighttp::getCover (const resp_https_t &response, const req_https_t &request)
 Get an application's image.
 
void confighttp::getCSRFToken (const resp_https_t &response, const req_https_t &request)
 Get a CSRF token for the authenticated user.
 
void confighttp::getFaviconImage (const resp_https_t &response, const req_https_t &request)
 Get the favicon image.
 
void confighttp::getLocale (const resp_https_t &response, const req_https_t &request)
 Get the locale setting. This endpoint does not require authentication.
 
void confighttp::getLogs (const resp_https_t &response, const req_https_t &request)
 Get the logs from the log file.
 
void confighttp::getPage (const resp_https_t &response, const req_https_t &request, const char *html_file, const bool require_auth, const bool redirect_if_username)
 Get an HTML page.
 
void confighttp::getSunshineLogoImage (const resp_https_t &response, const req_https_t &request)
 Get the Sunshine logo image.
 
void confighttp::getViGEmBusStatus (const resp_https_t &response, const req_https_t &request)
 Get ViGEmBus driver version and installation status.
 
void confighttp::installViGEmBus (const resp_https_t &response, const req_https_t &request)
 Install ViGEmBus driver with elevated permissions.
 
bool confighttp::is_browsable_executable (const fs::directory_entry &entry, const fs::file_status &status)
 Checks whether a directory entry qualifies as an executable file.
 
bool confighttp::isChildPath (fs::path const &base, fs::path const &query)
 Check if a path is a child of another path.
 
void confighttp::not_found (const resp_https_t &response, const req_https_t &request, const std::string &error_message)
 Send a 404 Not Found response.
 
void confighttp::print_req (const req_https_t &request)
 Log the request details.
 
void confighttp::resetDisplayDevicePersistence (const resp_https_t &response, const req_https_t &request)
 Reset the display device persistence.
 
void confighttp::restart (const resp_https_t &response, const req_https_t &request)
 Authenticate a Web UI request and restart the Sunshine process.
 
void confighttp::saveApp (const resp_https_t &response, const req_https_t &request)
 Save an application. To save a new application, the index must be -1. To update an existing application, you must provide the current index of the application.
 
void confighttp::saveConfig (const resp_https_t &response, const req_https_t &request)
 Save the configuration settings.
 
void confighttp::savePassword (const resp_https_t &response, const req_https_t &request)
 Update existing credentials.
 
void confighttp::savePin (const resp_https_t &response, const req_https_t &request)
 Send a pin code to the host. The pin is generated from the Moonlight client during the pairing process.
 
void confighttp::send_redirect (const resp_https_t &response, const req_https_t &request, const char *path)
 Send a redirect response.
 
void confighttp::send_response (const resp_https_t &response, const nlohmann::json &output_tree)
 Send a response.
 
void confighttp::send_unauthorized (const resp_https_t &response, const req_https_t &request)
 Send a 401 Unauthorized response.
 
void confighttp::start ()
 Start the HTTPS configuration server.
 
void confighttp::unpair (const resp_https_t &response, const req_https_t &request)
 Unpair a client.
 
void confighttp::unpairAll (const resp_https_t &response, const req_https_t &request)
 Unpair all clients.
 
void confighttp::updateClient (resp_https_t response, req_https_t request)
 Enable or disable a client.
 
void confighttp::uploadCover (const resp_https_t &response, const req_https_t &request)
 Upload a cover image.
 
bool confighttp::validate_csrf_token (const resp_https_t &response, const req_https_t &request, const std::string &client_id)
 Validate CSRF token.
 
bool confighttp::validate_stored_csrf_token (const resp_https_t &response, const req_https_t &request, const std::string_view client_id, const std::string_view provided_token)
 Validate a stored CSRF token for a client against a provided token string.
 

Variables

constexpr auto confighttp::CSRF_TOKEN_LIFETIME = std::chrono::hours(1)
 Amount of time a generated CSRF token remains valid.
 
constexpr auto confighttp::CSRF_TOKEN_SIZE = 32
 Number of random bytes used when generating a CSRF token.
 
std::map< std::string, csrf_token_t, std::less<> > confighttp::csrf_tokens
 CSRF tokens by client identifier. NOSONAR(cpp:S5421) - intentionally mutable global.
 
std::mutex confighttp::csrf_tokens_mutex
 Mutex protecting CSRF token storage. NOSONAR(cpp:S5421) - intentionally mutable global.
 

Detailed Description

Definitions for the Web UI Config HTTP server.

Todo
Authentication, better handling of routes common to nvhttp, cleanup

Enumeration Type Documentation

◆ op_e

enum class confighttp::op_e
strong

Client certificate operations accepted by the configuration API.

Enumerator
ADD 

Add client.

REMOVE 

Remove client.

Function Documentation

◆ authenticate()

bool confighttp::authenticate ( const resp_https_t & response,
const req_https_t & request )

Authenticate the user.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
Returns
True if the user is authenticated, false otherwise.

◆ bad_request()

void confighttp::bad_request ( const resp_https_t & response,
const req_https_t & request,
const std::string & error_message )

Send a 400 Bad Request response.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
error_messageThe error message to include in the response.

◆ browseDirectory()

void confighttp::browseDirectory ( const resp_https_t & response,
const req_https_t & request )

Browse the server filesystem.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
Note
On Windows, an empty or root path returns the list of available drive letters.
On non-Windows, an empty path defaults to the filesystem root ("/").

◆ build_browse_entries()

nlohmann::json confighttp::build_browse_entries ( const fs::path & dir_path,
const std::string & type_str )

Lists, filters, and sorts the entries of a directory for the browse API.

Parameters
dir_pathThe directory to list.
type_strFilter type: "directory", "executable", "file", or "any".
Returns
Sorted JSON array of entry objects with name/type/path fields.

◆ check_app_index()

bool confighttp::check_app_index ( const resp_https_t & response,
const req_https_t & request,
int index )

Validates the application index and sends an error response if invalid.

Check app index.

Parameters
responseHTTP response object to populate.
requestHTTP request data from the client.
indexZero-based index of the item being addressed.
Returns
True when the request passes validation and processing may continue.

◆ check_content_type()

bool confighttp::check_content_type ( const resp_https_t & response,
const req_https_t & request,
const std::string_view & contentType )

Validate the request content type and send a bad request when mismatched.

Check content type.

Parameters
responseHTTP response object to populate.
requestHTTP request data from the client.
contentTypeExpected HTTP content type.
Returns
True when the request passes validation and processing may continue.

◆ closeApp()

void confighttp::closeApp ( const resp_https_t & response,
const req_https_t & request )

Close the currently running application.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ deleteApp()

void confighttp::deleteApp ( const resp_https_t & response,
const req_https_t & request )

Delete an application.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ generate_csrf_token()

std::string confighttp::generate_csrf_token ( const std::string & client_id)

Generate a new CSRF token for a client.

Parameters
client_idA unique identifier for the client (e.g., session ID or username).
Returns
The generated CSRF token.

◆ get_client_id()

std::string confighttp::get_client_id ( const req_https_t & request)

Get a unique client identifier for CSRF token management.

Parameters
requestThe HTTP request object.
Returns
A unique identifier based on username or IP address.

◆ get_windows_drives()

nlohmann::json confighttp::get_windows_drives ( )

Builds a JSON array of available Windows drive letters.

Returns
JSON array of drive-letter entries.

◆ getApps()

void confighttp::getApps ( const resp_https_t & response,
const req_https_t & request )

Get the list of available applications.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ getAsset()

void confighttp::getAsset ( const resp_https_t & response,
const req_https_t & request )

Get an asset.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ getClients()

void confighttp::getClients ( const resp_https_t & response,
const req_https_t & request )

Get the list of paired clients.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ getConfig()

void confighttp::getConfig ( const resp_https_t & response,
const req_https_t & request )

Get the configuration settings.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ getCover()

void confighttp::getCover ( const resp_https_t & response,
const req_https_t & request )

Get an application's image.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
Note
The index in the url path is the application index.

◆ getCSRFToken()

void confighttp::getCSRFToken ( const resp_https_t & response,
const req_https_t & request )

Get a CSRF token for the authenticated user.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ getFaviconImage()

void confighttp::getFaviconImage ( const resp_https_t & response,
const req_https_t & request )

Get the favicon image.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
Todo

combine function with getSunshineLogoImage and possibly getNodeModules

use mime_types map

◆ getLocale()

void confighttp::getLocale ( const resp_https_t & response,
const req_https_t & request )

Get the locale setting. This endpoint does not require authentication.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ getLogs()

void confighttp::getLogs ( const resp_https_t & response,
const req_https_t & request )

Get the logs from the log file.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ getPage()

void confighttp::getPage ( const resp_https_t & response,
const req_https_t & request,
const char * html_file,
const bool require_auth,
const bool redirect_if_username )

Get an HTML page.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
html_fileThe HTML file to serve (relative to WEB_DIR).
require_authWhether to require authentication (default: true).
redirect_if_usernameIf true, redirect to "/" when the username is set (for welcome page).

◆ getSunshineLogoImage()

void confighttp::getSunshineLogoImage ( const resp_https_t & response,
const req_https_t & request )

Get the Sunshine logo image.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
Todo

combine function with getFaviconImage and possibly getNodeModules

use mime_types map

◆ getViGEmBusStatus()

void confighttp::getViGEmBusStatus ( const resp_https_t & response,
const req_https_t & request )

Get ViGEmBus driver version and installation status.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ installViGEmBus()

void confighttp::installViGEmBus ( const resp_https_t & response,
const req_https_t & request )

Install ViGEmBus driver with elevated permissions.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ is_browsable_executable()

bool confighttp::is_browsable_executable ( const fs::directory_entry & entry,
const fs::file_status & status )

Checks whether a directory entry qualifies as an executable file.

Parameters
entryThe directory entry to check.
statusThe cached file status for the entry.
Returns
True if the file should be included in an executable-type listing.

◆ isChildPath()

bool confighttp::isChildPath ( fs::path const & base,
fs::path const & query )

Check if a path is a child of another path.

Parameters
baseThe base path.
queryThe path to check.
Returns
True if the path is a child of the base path, false otherwise.

◆ not_found()

void confighttp::not_found ( const resp_https_t & response,
const req_https_t & request,
const std::string & error_message )

Send a 404 Not Found response.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
error_messageThe error message to include in the response.

◆ print_req()

void confighttp::print_req ( const req_https_t & request)

Log the request details.

Parameters
requestThe HTTP request object.

◆ resetDisplayDevicePersistence()

void confighttp::resetDisplayDevicePersistence ( const resp_https_t & response,
const req_https_t & request )

Reset the display device persistence.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ restart()

void confighttp::restart ( const resp_https_t & response,
const req_https_t & request )

Authenticate a Web UI request and restart the Sunshine process.

Parameters
responseHTTP response used for authentication or CSRF failures.
requestHTTP request carrying the client identity and CSRF token.

◆ saveApp()

void confighttp::saveApp ( const resp_https_t & response,
const req_https_t & request )

Save an application. To save a new application, the index must be -1. To update an existing application, you must provide the current index of the application.

Parameters
responseThe HTTP response object.
requestThe HTTP request object. The body for the post request should be JSON serialized in the following format:
{
"name": "Application Name",
"output": "Log Output Path",
"cmd": "Command to run the application",
"index": -1,
"exclude-global-prep-cmd": false,
"elevated": false,
"auto-detach": true,
"wait-all": true,
"exit-timeout": 5,
"prep-cmd": [
{
"do": "Command to prepare",
"undo": "Command to undo preparation",
"elevated": false
}
],
"detached": [
"Detached command"
],
"image-path": "Full path to the application image. Must be a png file."
}

◆ saveConfig()

void confighttp::saveConfig ( const resp_https_t & response,
const req_https_t & request )

Save the configuration settings.

Parameters
responseThe HTTP response object.
requestThe HTTP request object. The body for the POST request should be JSON serialized in the following format:
{
"key": "value"
}
Attention
It is recommended to ONLY save the config settings that differ from the default behavior.

◆ savePassword()

void confighttp::savePassword ( const resp_https_t & response,
const req_https_t & request )

Update existing credentials.

Parameters
responseThe HTTP response object.
requestThe HTTP request object. The body for the post request should be JSON serialized in the following format:
{
"currentUsername": "Current Username",
"currentPassword": "Current Password",
"newUsername": "New Username",
"newPassword": "New Password",
"confirmNewPassword": "Confirm New Password"
}

◆ savePin()

void confighttp::savePin ( const resp_https_t & response,
const req_https_t & request )

Send a pin code to the host. The pin is generated from the Moonlight client during the pairing process.

Parameters
responseThe HTTP response object.
requestThe HTTP request object. The body for the post request should be JSON serialized in the following format:
{
"pin": "<pin>",
"name": "Friendly Client Name"
}

◆ send_redirect()

void confighttp::send_redirect ( const resp_https_t & response,
const req_https_t & request,
const char * path )

Send a redirect response.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
pathThe path to redirect to.

◆ send_response()

void confighttp::send_response ( const resp_https_t & response,
const nlohmann::json & output_tree )

Send a response.

Parameters
responseThe HTTP response object.
output_treeThe JSON tree to send.

◆ send_unauthorized()

void confighttp::send_unauthorized ( const resp_https_t & response,
const req_https_t & request )

Send a 401 Unauthorized response.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ unpair()

void confighttp::unpair ( const resp_https_t & response,
const req_https_t & request )

Unpair a client.

Parameters
responseThe HTTP response object.
requestThe HTTP request object. The body for the POST request should be JSON serialized in the following format:
{
"uuid": "<uuid>"
}

◆ unpairAll()

void confighttp::unpairAll ( const resp_https_t & response,
const req_https_t & request )

Unpair all clients.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.

◆ updateClient()

void confighttp::updateClient ( resp_https_t response,
req_https_t request )

Enable or disable a client.

Parameters
responseThe HTTP response object.
requestThe HTTP request object. The body for the POST request should be JSON serialized in the following format:
{
"uuid": "<uuid>",
"enabled": true
}

◆ uploadCover()

void confighttp::uploadCover ( const resp_https_t & response,
const req_https_t & request )

Upload a cover image.

Parameters
responseThe HTTP response object.
requestThe HTTP request object. The body for the post request should be JSON serialized in the following format:
{
"key": "igdb_<game_id>",
"url": "https://images.igdb.com/igdb/image/upload/t_cover_big_2x/<slug>.png"
}

◆ validate_csrf_token()

bool confighttp::validate_csrf_token ( const resp_https_t & response,
const req_https_t & request,
const std::string & client_id )

Validate CSRF token.

Parameters
responseHTTP response object to populate.
requestHTTP request data from the client.
client_idClient identifier used to look up the CSRF token.
Returns
True when the request passes validation and processing may continue.

◆ validate_stored_csrf_token()

bool confighttp::validate_stored_csrf_token ( const resp_https_t & response,
const req_https_t & request,
const std::string_view client_id,
const std::string_view provided_token )

Validate a stored CSRF token for a client against a provided token string.

Parameters
responseThe HTTP response object.
requestThe HTTP request object.
client_idA unique identifier for the client.
provided_tokenThe token string to validate.
Returns
True if the token is valid, false otherwise.