From ef8b4e39eff9fea62300951afbf1e88680936bc6 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Tue, 14 Apr 2020 11:32:21 +0800 Subject: [PATCH] Enhancements Add SNI host parsing support for Trojan subscriptions. Add detailed log report. Optimize codes. Update build scripts. --- CMakeLists.txt | 1 + scripts/build.clang.sh | 1 + src/interfaces.cpp | 12 +++++ src/speedtestutil.cpp | 8 ++- src/subexport.cpp | 111 -------------------------------------- src/subexport.h | 3 -- src/upload.cpp | 119 +++++++++++++++++++++++++++++++++++++++++ src/upload.h | 9 ++++ 8 files changed, 148 insertions(+), 116 deletions(-) create mode 100644 src/upload.cpp create mode 100644 src/upload.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6855ba1..58838bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ ADD_EXECUTABLE(subconverter src/speedtestutil.cpp src/subexport.cpp src/templates.cpp + src/upload.cpp src/webget.cpp src/webserver_libevent.cpp) INCLUDE_DIRECTORIES(src) diff --git a/scripts/build.clang.sh b/scripts/build.clang.sh index b69f397..7286c73 100644 --- a/scripts/build.clang.sh +++ b/scripts/build.clang.sh @@ -12,6 +12,7 @@ c++ -std=c++17 -Wall -fexceptions -c src/nodemanip.cpp -o obj/nodemanip.o c++ -std=c++17 -Wall -fexceptions -c src/rapidjson_extra.cpp -o obj/rapidjson_extra.o c++ -std=c++17 -Wall -fexceptions -c src/speedtestutil.cpp -o obj/speedtestutil.o c++ -std=c++17 -Wall -fexceptions -c src/subexport.cpp -o obj/subexport.o +c++ -std=c++17 -Wall -fexceptions -c src/upload.cpp -o obj/upload.o c++ -std=c++17 -Wall -fexceptions -c src/templates.cpp -o obj/templates.o c++ -std=c++17 -Wall -fexceptions -c src/webget.cpp -o obj/webget.o c++ -std=c++17 -Wall -fexceptions -c src/webserver_libevent.cpp -o obj/webserver_libevent.o diff --git a/src/interfaces.cpp b/src/interfaces.cpp index a638aa9..b306b84 100644 --- a/src/interfaces.cpp +++ b/src/interfaces.cpp @@ -18,6 +18,7 @@ #include "logger.h" #include "string_hash.h" #include "templates.h" +#include "upload.h" //common settings std::string pref_path = "pref.ini", def_ext_config; @@ -1580,6 +1581,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS) *status_code = 400; return "Please insert your subscription link instead of clicking the default link."; } + writeLog(0, "SurgeConfToClash called with url '" + url + "'.", LOG_LEVEL_INFO); std::string proxy = parseProxy(proxy_config); YAML::Node clash; @@ -1758,6 +1760,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS) } clash[rule_name] = rule; + writeLog(0, "Conversion completed.", LOG_LEVEL_INFO); return YAML::Dump(clash); } @@ -1917,12 +1920,14 @@ std::string parseHostname(inja::Arguments &args) std::string template_webGet(inja::Arguments &args) { std::string data = args.at(0)->get(), proxy = parseProxy(proxy_config); + writeLog(0, "Template called fetch with url '" + data + "'.", LOG_LEVEL_INFO); return webGet(data, proxy, cache_config); } std::string jinja2_webGet(const std::string &url) { std::string proxy = parseProxy(proxy_config); + writeLog(0, "Template called fetch with url '" + url + "'.", LOG_LEVEL_INFO); return webGet(url, proxy, cache_config); } @@ -2097,6 +2102,7 @@ int simpleGenerator() std::string renderTemplate(RESPONSE_CALLBACK_ARGS) { std::string path = UrlDecode(getUrlArg(argument, "path")); + writeLog(0, "Trying to render template '" + path + "'...", LOG_LEVEL_INFO); if(path.find(template_path) != 0) { @@ -2132,6 +2138,12 @@ std::string renderTemplate(RESPONSE_CALLBACK_ARGS) std::string output_content; if(render_template(template_content, tpl_args, output_content, template_path) != 0) + { *status_code = 400; + writeLog(0, "Render failed with error.", LOG_LEVEL_WARNING); + } + else + writeLog(0, "Render completed.", LOG_LEVEL_INFO); + return output_content; } diff --git a/src/speedtestutil.cpp b/src/speedtestutil.cpp index c18c4a5..d8b2b83 100644 --- a/src/speedtestutil.cpp +++ b/src/speedtestutil.cpp @@ -733,7 +733,7 @@ void explodeHTTPSub(std::string link, const std::string &custom_port, nodeInfo & void explodeTrojan(std::string trojan, const std::string &custom_port, int local_port, nodeInfo &node) { - std::string server, port, psk, addition, remark; + std::string server, port, psk, addition, remark, host; string_array vArray; trojan.erase(0, 9); string_size pos = trojan.rfind("#"); @@ -759,15 +759,19 @@ void explodeTrojan(std::string trojan, const std::string &custom_port, int local server = vArray[1]; port = custom_port.empty() ? vArray[2] : custom_port; + host = getUrlArg(addition, "peer"); + if(remark.empty()) remark = server + ":" + port; + if(host.empty() && !isIPv4(server) && !isIPv6(server)) + host = server; node.linkType = SPEEDTEST_MESSAGE_FOUNDTROJAN; node.group = TROJAN_DEFAULT_GROUP; node.remarks = remark; node.server = server; node.port = to_int(port, 0); - node.proxyStr = trojanConstruct(remark, server, port, psk, "", false); + node.proxyStr = trojanConstruct(remark, server, port, psk, host, true); } void explodeQuan(std::string quan, const std::string &custom_port, int local_port, nodeInfo &node) diff --git a/src/subexport.cpp b/src/subexport.cpp index 8dc9ab7..a50d008 100644 --- a/src/subexport.cpp +++ b/src/subexport.cpp @@ -583,7 +583,6 @@ void rulesetToSurge(INIReader &base_rule, std::vector &ruleset_ } } - const std::string rule_match_regex = "^(.*?,.*?)(,.*)(,.*)$"; for(ruleset_content &x : ruleset_content_array) @@ -2678,113 +2677,3 @@ std::string netchToLoon(std::vector &nodes, std::string &base_conf, st return ini.ToString(); } - -std::string buildGistData(std::string name, std::string content) -{ - rapidjson::StringBuffer sb; - rapidjson::Writer writer(sb); - writer.StartObject(); - writer.Key("description"); - writer.String("subconverter"); - writer.Key("public"); - writer.Bool(false); - writer.Key("files"); - writer.StartObject(); - writer.Key(name.data()); - writer.StartObject(); - writer.Key("content"); - writer.String(content.data()); - writer.EndObject(); - writer.EndObject(); - writer.EndObject(); - return sb.GetString(); -} - -int uploadGist(std::string name, std::string path, std::string content, bool writeManageURL) -{ - INIReader ini; - rapidjson::Document json; - std::string token, id, username, retData, url; - int retVal = 0; - - if(!fileExist("gistconf.ini")) - { - //std::cerr<<"gistconf.ini not found. Skipping...\n"; - writeLog(0, "gistconf.ini not found. Skipping...", LOG_LEVEL_ERROR); - return -1; - } - - ini.ParseFile("gistconf.ini"); - if(ini.EnterSection("common") != 0) - { - //std::cerr<<"gistconf.ini has incorrect format. Skipping...\n"; - writeLog(0, "gistconf.ini has incorrect format. Skipping...", LOG_LEVEL_ERROR); - return -1; - } - - token = ini.Get("token"); - if(!token.size()) - { - //std::cerr<<"No token is provided. Skipping...\n"; - writeLog(0, "No token is provided. Skipping...", LOG_LEVEL_ERROR); - return -1; - } - - id = ini.Get("id"); - username = ini.Get("username"); - if(!path.size()) - { - if(ini.ItemExist("path")) - path = ini.Get(name, "path"); - else - path = name; - } - - if(!id.size()) - { - //std::cerr<<"No gist id is provided. Creating new gist...\n"; - writeLog(0, "No Gist id is provided. Creating new Gist...", LOG_LEVEL_ERROR); - retVal = webPost("https://api.github.com/gists", buildGistData(path, content), getSystemProxy(), token, &retData); - if(retVal != 201) - { - //std::cerr<<"Create new Gist failed! Return data:\n"< &nodes, std::string &base_conf, st void netchToQuan(std::vector &nodes, INIReader &ini, std::vector &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext); std::string netchToSSD(std::vector &nodes, std::string &group, std::string &userinfo, extra_settings &ext); -std::string buildGistData(std::string name, std::string content); -int uploadGist(std::string name, std::string path, std::string content, bool writeManageURL); - #endif // SUBEXPORT_H_INCLUDED diff --git a/src/upload.cpp b/src/upload.cpp new file mode 100644 index 0000000..301e681 --- /dev/null +++ b/src/upload.cpp @@ -0,0 +1,119 @@ +#include + +#include +#include + +#include "webget.h" +#include "ini_reader.h" +#include "logger.h" +#include "rapidjson_extra.h" + +std::string buildGistData(std::string name, std::string content) +{ + rapidjson::StringBuffer sb; + rapidjson::Writer writer(sb); + writer.StartObject(); + writer.Key("description"); + writer.String("subconverter"); + writer.Key("public"); + writer.Bool(false); + writer.Key("files"); + writer.StartObject(); + writer.Key(name.data()); + writer.StartObject(); + writer.Key("content"); + writer.String(content.data()); + writer.EndObject(); + writer.EndObject(); + writer.EndObject(); + return sb.GetString(); +} + +int uploadGist(std::string name, std::string path, std::string content, bool writeManageURL) +{ + INIReader ini; + rapidjson::Document json; + std::string token, id, username, retData, url; + int retVal = 0; + + if(!fileExist("gistconf.ini")) + { + //std::cerr<<"gistconf.ini not found. Skipping...\n"; + writeLog(0, "gistconf.ini not found. Skipping...", LOG_LEVEL_ERROR); + return -1; + } + + ini.ParseFile("gistconf.ini"); + if(ini.EnterSection("common") != 0) + { + //std::cerr<<"gistconf.ini has incorrect format. Skipping...\n"; + writeLog(0, "gistconf.ini has incorrect format. Skipping...", LOG_LEVEL_ERROR); + return -1; + } + + token = ini.Get("token"); + if(!token.size()) + { + //std::cerr<<"No token is provided. Skipping...\n"; + writeLog(0, "No token is provided. Skipping...", LOG_LEVEL_ERROR); + return -1; + } + + id = ini.Get("id"); + username = ini.Get("username"); + if(!path.size()) + { + if(ini.ItemExist("path")) + path = ini.Get(name, "path"); + else + path = name; + } + + if(!id.size()) + { + //std::cerr<<"No gist id is provided. Creating new gist...\n"; + writeLog(0, "No Gist id is provided. Creating new Gist...", LOG_LEVEL_ERROR); + retVal = webPost("https://api.github.com/gists", buildGistData(path, content), getSystemProxy(), token, &retData); + if(retVal != 201) + { + //std::cerr<<"Create new Gist failed! Return data:\n"< + +std::string buildGistData(std::string name, std::string content); +int uploadGist(std::string name, std::string path, std::string content, bool writeManageURL); + +#endif // UPLOAD_H_INCLUDED