Add server one time pin support to nvhttp
This commit is contained in:
@@ -740,6 +740,43 @@ namespace confighttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
getOTP(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;
|
||||||
|
pt::write_json(data, outputTree);
|
||||||
|
response->write(data.str());
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto args = request->parse_query_string();
|
||||||
|
auto it = args.find("passphrase");
|
||||||
|
if (it == std::end(args)) {
|
||||||
|
throw std::runtime_error("Passphrase not provided!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it->second.size() < 4) {
|
||||||
|
throw std::runtime_error("Passphrase too short!");
|
||||||
|
}
|
||||||
|
|
||||||
|
outputTree.put("otp", nvhttp::request_otp(it->second));
|
||||||
|
outputTree.put("statue", true);
|
||||||
|
outputTree.put("message", "OTP created, effective within 1 minute.")
|
||||||
|
}
|
||||||
|
catch (std::exception &e) {
|
||||||
|
BOOST_LOG(warning) << "OTP creation failed: "sv << e.what();
|
||||||
|
outputTree.put("status", false);
|
||||||
|
outputTree.put("message", e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
unpairAll(resp_https_t response, req_https_t request) {
|
unpairAll(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
@@ -847,6 +884,7 @@ namespace confighttp {
|
|||||||
server.resource["^/welcome/?$"]["GET"] = getWelcomePage;
|
server.resource["^/welcome/?$"]["GET"] = getWelcomePage;
|
||||||
server.resource["^/troubleshooting/?$"]["GET"] = getTroubleshootingPage;
|
server.resource["^/troubleshooting/?$"]["GET"] = getTroubleshootingPage;
|
||||||
server.resource["^/api/pin$"]["POST"] = savePin;
|
server.resource["^/api/pin$"]["POST"] = savePin;
|
||||||
|
server.resource["^/api/otp$"]["GET"] = getOTP;
|
||||||
server.resource["^/api/apps$"]["GET"] = getApps;
|
server.resource["^/api/apps$"]["GET"] = getApps;
|
||||||
server.resource["^/api/logs$"]["GET"] = getLogs;
|
server.resource["^/api/logs$"]["GET"] = getLogs;
|
||||||
server.resource["^/api/apps$"]["POST"] = saveApp;
|
server.resource["^/api/apps$"]["POST"] = saveApp;
|
||||||
|
|||||||
+46
-6
@@ -8,6 +8,7 @@
|
|||||||
// standard includes
|
// standard includes
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
// lib includes
|
// lib includes
|
||||||
#include <Simple-Web-Server/server_http.hpp>
|
#include <Simple-Web-Server/server_http.hpp>
|
||||||
@@ -17,7 +18,6 @@
|
|||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
#include <boost/property_tree/xml_parser.hpp>
|
#include <boost/property_tree/xml_parser.hpp>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -47,6 +47,9 @@ namespace nvhttp {
|
|||||||
namespace pt = boost::property_tree;
|
namespace pt = boost::property_tree;
|
||||||
|
|
||||||
crypto::cert_chain_t cert_chain;
|
crypto::cert_chain_t cert_chain;
|
||||||
|
static std::string one_time_pin;
|
||||||
|
static std::string otp_passphrase;
|
||||||
|
static std::chrono::time_point<std::chrono::steady_clock> otp_creation_time;
|
||||||
|
|
||||||
class SunshineHttpsServer: public SimpleWeb::Server<SimpleWeb::HTTPS> {
|
class SunshineHttpsServer: public SimpleWeb::Server<SimpleWeb::HTTPS> {
|
||||||
public:
|
public:
|
||||||
@@ -567,18 +570,19 @@ namespace nvhttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto uniqID { get_arg(args, "uniqueid") };
|
auto uniqID { get_arg(args, "uniqueid") };
|
||||||
auto deviceName { get_arg(args, "devicename") };
|
|
||||||
auto sess_it = map_id_sess.find(uniqID);
|
auto sess_it = map_id_sess.find(uniqID);
|
||||||
|
|
||||||
if (deviceName == "roth"sv) {
|
|
||||||
deviceName = "Legacy Moonlight Client";
|
|
||||||
}
|
|
||||||
|
|
||||||
args_t::const_iterator it;
|
args_t::const_iterator it;
|
||||||
if (it = args.find("phrase"); it != std::end(args)) {
|
if (it = args.find("phrase"); it != std::end(args)) {
|
||||||
if (it->second == "getservercert"sv) {
|
if (it->second == "getservercert"sv) {
|
||||||
pair_session_t sess;
|
pair_session_t sess;
|
||||||
|
|
||||||
|
auto deviceName { get_arg(args, "devicename") };
|
||||||
|
|
||||||
|
if (deviceName == "roth"sv) {
|
||||||
|
deviceName = "Legacy Moonlight Client";
|
||||||
|
}
|
||||||
|
|
||||||
sess.client.uniqueID = std::move(uniqID);
|
sess.client.uniqueID = std::move(uniqID);
|
||||||
sess.client.deviceName = std::move(deviceName);
|
sess.client.deviceName = std::move(deviceName);
|
||||||
sess.client.cert = util::from_hex_vec(get_arg(args, "clientcert"), true);
|
sess.client.cert = util::from_hex_vec(get_arg(args, "clientcert"), true);
|
||||||
@@ -587,6 +591,30 @@ namespace nvhttp {
|
|||||||
auto ptr = map_id_sess.emplace(sess.client.uniqueID, std::move(sess)).first;
|
auto ptr = map_id_sess.emplace(sess.client.uniqueID, std::move(sess)).first;
|
||||||
|
|
||||||
ptr->second.async_insert_pin.salt = std::move(get_arg(args, "salt"));
|
ptr->second.async_insert_pin.salt = std::move(get_arg(args, "salt"));
|
||||||
|
|
||||||
|
auto it = args.find("otpauth");
|
||||||
|
if (it != std::end(args)) {
|
||||||
|
if (one_time_pin.empty() || (std::chrono::steady_clock::now() - otp_creation_time > OTP_EXPIRE_DURATION)) {
|
||||||
|
one_time_pin.clear();
|
||||||
|
otp_passphrase.clear();
|
||||||
|
tree.put("root.<xmlattr>.status_code", 503);
|
||||||
|
tree.put("root.<xmlattr>.status_message", "OTP auth not available.");
|
||||||
|
} else {
|
||||||
|
auto hash = util::hex(crypto::hash(one_time_pin + ptr->second.async_insert_pin.salt + otp_passphrase));
|
||||||
|
|
||||||
|
if (hash.to_string_view() == it->second) {
|
||||||
|
getservercert(ptr->second, tree, one_time_pin);
|
||||||
|
one_time_pin.clear();
|
||||||
|
otp_passphrase.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always return positive, attackers will fail in the next steps.
|
||||||
|
getservercert(ptr->second, tree, crypto::rand(16));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (config::sunshine.flags[config::flag::PIN_STDIN]) {
|
if (config::sunshine.flags[config::flag::PIN_STDIN]) {
|
||||||
std::string pin;
|
std::string pin;
|
||||||
|
|
||||||
@@ -1183,6 +1211,18 @@ namespace nvhttp {
|
|||||||
tcp.join();
|
tcp.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string request_otp(const std::string& passphrase) {
|
||||||
|
if (passphrase.size() < 4) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
otp_passphrase = passphrase;
|
||||||
|
one_time_pin = crypto::rand_alphabet(4, "0123456789"sv);
|
||||||
|
otp_creation_time = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
return one_time_pin;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
erase_all_clients() {
|
erase_all_clients() {
|
||||||
client_t client;
|
client_t client;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
// standard includes
|
// standard includes
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
// lib includes
|
// lib includes
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
@@ -14,6 +15,8 @@
|
|||||||
// local includes
|
// local includes
|
||||||
#include "thread_safe.h"
|
#include "thread_safe.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Contains all the functions and variables related to the nvhttp (GameStream) server.
|
* @brief Contains all the functions and variables related to the nvhttp (GameStream) server.
|
||||||
*/
|
*/
|
||||||
@@ -41,6 +44,8 @@ namespace nvhttp {
|
|||||||
*/
|
*/
|
||||||
constexpr auto PORT_HTTPS = -5;
|
constexpr auto PORT_HTTPS = -5;
|
||||||
|
|
||||||
|
constexpr auto OTP_EXPIRE_DURATION = 60s;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start the nvhttp server.
|
* @brief Start the nvhttp server.
|
||||||
* @examples
|
* @examples
|
||||||
@@ -62,6 +67,8 @@ namespace nvhttp {
|
|||||||
bool
|
bool
|
||||||
pin(std::string pin, std::string name);
|
pin(std::string pin, std::string name);
|
||||||
|
|
||||||
|
std::string request_otp(const std::string& passphrase);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Remove single client.
|
* @brief Remove single client.
|
||||||
* @examples
|
* @examples
|
||||||
|
|||||||
Reference in New Issue
Block a user