289 lines
10 KiB
C++
289 lines
10 KiB
C++
#include "httpserver.h"
|
|
#include "../tunnelconstructor.h"
|
|
#include "crow/mustache.h"
|
|
#include "../htmldata.h"
|
|
#include "../tunnelconstructor.h"
|
|
#include "../versionnumber.h"
|
|
|
|
HttpServer::HttpServer(const std::string &address, uint16_t port) : address_(address), port_(port)
|
|
{
|
|
app_.loglevel(crow::LogLevel::Critical);
|
|
|
|
setup();
|
|
}
|
|
|
|
void HttpServer::run()
|
|
{
|
|
app_.bindaddr(address_).port(port_).multithreaded().run();
|
|
}
|
|
|
|
void HttpServer::setup()
|
|
{
|
|
CROW_CATCHALL_ROUTE(app_)
|
|
([](crow::response& res) {
|
|
res.code = 303;
|
|
res.set_header("Location", "/");
|
|
res.end();
|
|
});
|
|
|
|
CROW_ROUTE(app_, "/generate/html")([&](const crow::request& req, crow::response& res){
|
|
res.set_header("Content-Type", "text/html");
|
|
|
|
const auto language = lang(req);
|
|
|
|
auto constructor = initTunnelConstructorViaUrlQuery(req, language);
|
|
if (constructor.second == false)
|
|
{
|
|
res.code = 400;
|
|
res.write( errorPage(reinterpret_cast<const char*>(constructor.first.errorString().c_str()), language, query(req)));
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
const auto text = configPage( reinterpret_cast<const char*>(constructor.first.generate().c_str()) , language, constructor.first.isCommentsEnabled(), query(req));
|
|
res.write(text);
|
|
res.end();
|
|
});
|
|
|
|
CROW_ROUTE(app_, "/favicon.png")([&](const crow::request& req, crow::response& res){
|
|
res.set_header("Content-Type", "image/png");
|
|
res.add_header("Content-Length", std::to_string(sizeof(faviconB64)));
|
|
res.write(std::string(reinterpret_cast<const char*>(faviconB64), sizeof(faviconB64)));
|
|
res.end();
|
|
});
|
|
|
|
CROW_ROUTE(app_, "/")([&](const crow::request& req, crow::response& res){
|
|
res.set_header("Content-Type", "text/html");
|
|
|
|
const auto language = lang(req);
|
|
|
|
const auto text = mainPage(language);
|
|
res.write(text);
|
|
res.end();
|
|
});
|
|
}
|
|
|
|
Notepad::Lang HttpServer::lang(const crow::request &req)
|
|
{
|
|
const auto lang = req.url_params.get("lang");
|
|
if (lang)
|
|
{
|
|
auto& ctx = app_.get_context<crow::CookieParser>(req);
|
|
ctx.set_cookie("lang", lang).path("/").max_age(60*60*24).httponly();
|
|
return Notepad::stringToLang(lang);
|
|
}
|
|
|
|
auto& ctxCookie = app_.get_context<crow::CookieParser>(req);
|
|
const std::string langFromCookie = ctxCookie.get_cookie("lang");
|
|
if (langFromCookie.empty())
|
|
{
|
|
auto& ctxFromHeader = app_.get_context<LanguageHandler>(req);
|
|
return ctxFromHeader.lang;
|
|
}
|
|
|
|
return langFromCookie == "en" ? Notepad::Lang::en : Notepad::Lang::ru;
|
|
}
|
|
|
|
std::pair<TunnelConstructor, bool> HttpServer::initTunnelConstructorViaUrlQuery(const crow::request &req, Notepad::Lang lang)
|
|
{
|
|
TunnelConstructor constructor;
|
|
constructor.setLang(lang);
|
|
|
|
bool comments = false;
|
|
int8_t inbound_length = 3;
|
|
int8_t outbound_length = 3;
|
|
int8_t inbound_quantity = 5;
|
|
int8_t outbound_quantity = 5;
|
|
int8_t inbound_lengthVariance = 0;
|
|
int8_t outbound_lengthVariance = 0;
|
|
int8_t keepalive = 0;
|
|
|
|
for (const auto& key: req.url_params.keys())
|
|
{
|
|
if (key == "name" and not constructor.setName(req.url_params.get("name")))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
else if (key == "type" and not constructor.setTunnelType( TunnelConstructor::stringToTunnelType(req.url_params.get("type")) ))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
else if (key == "inbound.length")
|
|
{
|
|
try { inbound_length = std::stoi(req.url_params.get("inbound.length")); } catch (...) { }
|
|
}
|
|
else if (key == "outbound.length")
|
|
{
|
|
try { outbound_length = std::stoi(req.url_params.get("outbound.length")); } catch (...) { }
|
|
}
|
|
else if (key == "inbound.quntity")
|
|
{
|
|
try { inbound_quantity = std::stoi(req.url_params.get("inbound.quntity")); } catch (...) { }
|
|
}
|
|
else if (key == "outbound.quntity")
|
|
{
|
|
try { outbound_quantity = std::stoi(req.url_params.get("outbound.quntity")); } catch (...) { }
|
|
}
|
|
else if (key == "inbound.lengthVariance")
|
|
{
|
|
try { inbound_lengthVariance = std::stoi(req.url_params.get("inbound.lengthVariance")); } catch (...) { }
|
|
}
|
|
else if (key == "outbound.lengthVariance")
|
|
{
|
|
try { outbound_lengthVariance = std::stoi(req.url_params.get("outbound.lengthVariance")); } catch (...) { }
|
|
}
|
|
else if (key == "blinded" and not constructor.setBlindedLeaseSet(std::string(req.url_params.get("blinded")) == "true"))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
else if (key == "transient" and not constructor.setTransient(std::string(req.url_params.get("transient")) == "true"))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
else if (key == "comments")
|
|
{
|
|
comments = std::string(req.url_params.get("comments")) == "true";
|
|
}
|
|
else if (key == "keepalive")
|
|
{
|
|
try { keepalive = std::stoi(req.url_params.get("keepalive")); } catch (...) { }
|
|
}
|
|
}
|
|
|
|
if (not constructor.setComments(comments))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
|
|
if (not constructor.setLength(inbound_length, outbound_length))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
|
|
if (not constructor.setQuantity(inbound_quantity, outbound_quantity))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
|
|
if (not constructor.setLengthVariance(inbound_lengthVariance, outbound_lengthVariance))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
|
|
if (not constructor.setKeepAlive(keepalive))
|
|
{
|
|
return { constructor, false };
|
|
}
|
|
|
|
return { constructor, true };
|
|
}
|
|
|
|
std::string HttpServer::query(const crow::request &req)
|
|
{
|
|
std::string q;
|
|
for (const auto& key: req.url_params.keys())
|
|
{
|
|
if (key == "lang") continue;
|
|
|
|
if (q.empty())
|
|
{
|
|
q = "?";
|
|
}
|
|
else
|
|
{
|
|
q += "&";
|
|
}
|
|
|
|
q += key + "=" + req.url_params.get(key);
|
|
}
|
|
return q;
|
|
}
|
|
|
|
std::string HttpServer::configPage(const std::string& generated, Notepad::Lang lang, bool comments, const std::string& query)
|
|
{
|
|
crow::mustache::context ctx;
|
|
ctx["lang_code"] = Notepad::langToCode(lang);
|
|
ctx["tagline"] = reinterpret_cast<const char*>(Notepad::WebUi::tagline(lang));
|
|
ctx["payload"] = generated;
|
|
ctx["go_back"] = reinterpret_cast<const char*>(Notepad::WebUi::configGoBack(lang));
|
|
ctx["url"] = query;
|
|
ctx["version"] = VERSION;
|
|
|
|
static const auto templ = crow::mustache::compile(HTML_CONFIG_PAGE);
|
|
std::string pageWithoutCommentsHighlight = templ.render_string(ctx);
|
|
|
|
if (! comments) return pageWithoutCommentsHighlight;
|
|
|
|
std::istringstream stream(pageWithoutCommentsHighlight);
|
|
std::string buffer;
|
|
std::string result;
|
|
|
|
while (std::getline(stream, buffer))
|
|
{
|
|
if (!buffer.empty() && buffer[0] == '#')
|
|
{
|
|
buffer = "<span class=\"code-block-comment\">" + buffer + "</span>";
|
|
}
|
|
result += buffer + "\n";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string HttpServer::errorPage(const std::string &text, Notepad::Lang lang, const std::string& query)
|
|
{
|
|
crow::mustache::context ctx;
|
|
ctx["lang_code"] = Notepad::langToCode(lang);
|
|
ctx["tagline"] = reinterpret_cast<const char*>(Notepad::WebUi::tagline(lang));
|
|
ctx["text"] = text;
|
|
ctx["go_back"] = reinterpret_cast<const char*>(Notepad::WebUi::configGoBack(lang));
|
|
ctx["url"] = query;
|
|
ctx["version"] = VERSION;
|
|
|
|
static const auto templ = crow::mustache::compile(HTML_ERROR_PAGE);
|
|
return templ.render_string(ctx);
|
|
}
|
|
|
|
std::string HttpServer::mainPage(Notepad::Lang lang)
|
|
{
|
|
static std::map<Notepad::Lang, std::string> map;
|
|
auto iter = map.find(lang);
|
|
if (iter != map.end())
|
|
{
|
|
return iter->second;
|
|
}
|
|
|
|
crow::mustache::context ctx;
|
|
ctx["lang_code"] = Notepad::langToCode(lang);
|
|
ctx["tagline"] = reinterpret_cast<const char*>(Notepad::WebUi::tagline(lang));
|
|
ctx["th_option"] = reinterpret_cast<const char*>(Notepad::WebUi::mainThOption(lang));
|
|
ctx["th_value"] = reinterpret_cast<const char*>(Notepad::WebUi::mainThInput(lang));
|
|
ctx["tunnel_name"] = reinterpret_cast<const char*>(Notepad::WebUi::mainTunnelName(lang));
|
|
ctx["tunnel_name_p"] = reinterpret_cast<const char*>(Notepad::WebUi::mainTunnelName(lang));
|
|
ctx["tunnel_type"] = reinterpret_cast<const char*>(Notepad::WebUi::mainTunnelType(lang));
|
|
ctx["client_tcp"] = reinterpret_cast<const char*>(Notepad::WebUi::mainDropdownClientTCP(lang));
|
|
ctx["client_udp"] = reinterpret_cast<const char*>(Notepad::WebUi::mainDropdownClientUDP(lang));
|
|
ctx["server_tcp"] = reinterpret_cast<const char*>(Notepad::WebUi::mainDropdownServerTCP(lang));
|
|
ctx["server_udp"] = reinterpret_cast<const char*>(Notepad::WebUi::mainDropdownServerUDP(lang));
|
|
ctx["server_http"] = reinterpret_cast<const char*>(Notepad::WebUi::mainDropdownServerHTTP(lang));
|
|
ctx["server_irc"] = reinterpret_cast<const char*>(Notepad::WebUi::mainDropdownServerIRC(lang));
|
|
ctx["socks_proxy"] = reinterpret_cast<const char*>(Notepad::WebUi::mainDropdownSOCKSProxy(lang));
|
|
ctx["http_proxy"] = reinterpret_cast<const char*>(Notepad::WebUi::mainDropdownHTTPProxy(lang));
|
|
ctx["inbound"] = reinterpret_cast<const char*>(Notepad::WebUi::mainInbound(lang));
|
|
ctx["outbound"] = reinterpret_cast<const char*>(Notepad::WebUi::mainOutbound(lang));
|
|
ctx["length"] = reinterpret_cast<const char*>(Notepad::WebUi::mainLength(lang));
|
|
ctx["quantity"] = reinterpret_cast<const char*>(Notepad::WebUi::mainQuantity(lang));
|
|
ctx["variance"] = reinterpret_cast<const char*>(Notepad::WebUi::mainVariance(lang));
|
|
ctx["b33"] = reinterpret_cast<const char*>(Notepad::WebUi::mainB33(lang));
|
|
ctx["transient"] = reinterpret_cast<const char*>(Notepad::WebUi::mainTransient(lang));
|
|
ctx["keepalive"] = reinterpret_cast<const char*>(Notepad::WebUi::mainKeepalive(lang));
|
|
ctx["comments"] = reinterpret_cast<const char*>(Notepad::WebUi::mainComments(lang));
|
|
ctx["generate"] = reinterpret_cast<const char*>(Notepad::WebUi::mainGenerate(lang));
|
|
ctx["version"] = VERSION;
|
|
|
|
const auto templ = crow::mustache::compile(HTML_MAIN_PAGE);
|
|
map[lang] = templ.render_string(ctx);
|
|
|
|
return map[lang];
|
|
}
|