mirror of
https://github.com/MetaCubeX/subconverter.git
synced 2025-11-04 18:19:42 +08:00
Enhancements
Fix potential segmentation fault error due to some incorrect copy assignments. Fix potential crash due to incorrect usage of cURL library. Fix potential memory leak causing memory usage to be too high. Add /qx-rewrite and /qx-script interface to add device ID to scripts for some version of Quantumult X. Add policy-path parsing support for /surge2clash interface. Add interval/strict options support for managed config. Add filename option for setting file name when downloading exported subscriptions. Optimize codes.
This commit is contained in:
parent
452c9299f1
commit
c6920fbbc3
@ -39,6 +39,9 @@ node_pref:
|
|||||||
managed_config:
|
managed_config:
|
||||||
write_managed_config: true
|
write_managed_config: true
|
||||||
managed_config_prefix: "http://127.0.0.1:25500"
|
managed_config_prefix: "http://127.0.0.1:25500"
|
||||||
|
config_update_interval: 86400
|
||||||
|
config_update_strict: false
|
||||||
|
quanx_device_id: ""
|
||||||
|
|
||||||
surge_external_proxy:
|
surge_external_proxy:
|
||||||
surge_ssr_path: "" # /usr/bin/ssr-local
|
surge_ssr_path: "" # /usr/bin/ssr-local
|
||||||
|
|||||||
@ -83,6 +83,15 @@ write_managed_config=true
|
|||||||
;This address will also be used for generating /getruleset addresses.
|
;This address will also be used for generating /getruleset addresses.
|
||||||
managed_config_prefix=http://127.0.0.1:25500
|
managed_config_prefix=http://127.0.0.1:25500
|
||||||
|
|
||||||
|
;Managed config update interval, determine how long the config will be updated.
|
||||||
|
config_update_interval=86400
|
||||||
|
|
||||||
|
;If config_update_struct is true, Surge will require a force update after the interval.
|
||||||
|
config_update_struct=false
|
||||||
|
|
||||||
|
;Device ID to be written to rewrite scripts for some version of Quantumult X
|
||||||
|
quanx_device_id=
|
||||||
|
|
||||||
[surge_external_proxy]
|
[surge_external_proxy]
|
||||||
;surge_ssr_path=/usr/bin/ssr-local
|
;surge_ssr_path=/usr/bin/ssr-local
|
||||||
|
|
||||||
|
|||||||
@ -34,13 +34,14 @@ std::mutex on_configuring;
|
|||||||
//preferences
|
//preferences
|
||||||
string_array renames, emojis;
|
string_array renames, emojis;
|
||||||
bool add_emoji = false, remove_old_emoji = false, append_proxy_type = false, filter_deprecated = true;
|
bool add_emoji = false, remove_old_emoji = false, append_proxy_type = false, filter_deprecated = true;
|
||||||
bool udp_flag = false, tfo_flag = false, scv_flag = false, do_sort = false;
|
bool udp_flag = false, tfo_flag = false, scv_flag = false, do_sort = false, config_update_strict = false;
|
||||||
std::string proxy_config, proxy_ruleset, proxy_subscription;
|
std::string proxy_config, proxy_ruleset, proxy_subscription;
|
||||||
|
int config_update_interval = 0;
|
||||||
|
|
||||||
std::string clash_rule_base;
|
std::string clash_rule_base;
|
||||||
string_array clash_extra_group;
|
string_array clash_extra_group;
|
||||||
std::string surge_rule_base, surfboard_rule_base, mellow_rule_base, quan_rule_base, quanx_rule_base;
|
std::string surge_rule_base, surfboard_rule_base, mellow_rule_base, quan_rule_base, quanx_rule_base;
|
||||||
std::string surge_ssr_path;
|
std::string surge_ssr_path, quanx_script_id;
|
||||||
|
|
||||||
//pre-compiled rule bases
|
//pre-compiled rule bases
|
||||||
YAML::Node clash_base;
|
YAML::Node clash_base;
|
||||||
@ -448,6 +449,9 @@ void readYAMLConf(YAML::Node &node)
|
|||||||
section = node["managed_config"];
|
section = node["managed_config"];
|
||||||
section["write_managed_config"] >> write_managed_config;
|
section["write_managed_config"] >> write_managed_config;
|
||||||
section["managed_config_prefix"] >> managed_config_prefix;
|
section["managed_config_prefix"] >> managed_config_prefix;
|
||||||
|
section["config_update_interval"] >> config_update_interval;
|
||||||
|
section["config_update_strict"] >> config_update_strict;
|
||||||
|
section["quanx_device_id"] >> quanx_script_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["surge_external_proxy"].IsDefined())
|
if(node["surge_external_proxy"].IsDefined())
|
||||||
@ -634,6 +638,12 @@ void readConf()
|
|||||||
write_managed_config = ini.GetBool("write_managed_config");
|
write_managed_config = ini.GetBool("write_managed_config");
|
||||||
if(ini.ItemExist("managed_config_prefix"))
|
if(ini.ItemExist("managed_config_prefix"))
|
||||||
managed_config_prefix = ini.Get("managed_config_prefix");
|
managed_config_prefix = ini.Get("managed_config_prefix");
|
||||||
|
if(ini.ItemExist("config_update_interval"))
|
||||||
|
config_update_interval = ini.GetInt("config_update_interval");
|
||||||
|
if(ini.ItemExist("config_update_strict"))
|
||||||
|
config_update_strict = ini.GetBool("config_update_strict");
|
||||||
|
if(ini.ItemExist("quanx_device_id"))
|
||||||
|
quanx_script_id = ini.Get("quanx_device_id");
|
||||||
|
|
||||||
ini.EnterSection("emojis");
|
ini.EnterSection("emojis");
|
||||||
if(ini.ItemExist("add_emoji"))
|
if(ini.ItemExist("add_emoji"))
|
||||||
@ -878,13 +888,15 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
std::string append_type = getUrlArg(argument, "append_type"), tfo = getUrlArg(argument, "tfo"), udp = getUrlArg(argument, "udp"), nodelist = getUrlArg(argument, "list");
|
std::string append_type = getUrlArg(argument, "append_type"), tfo = getUrlArg(argument, "tfo"), udp = getUrlArg(argument, "udp"), nodelist = getUrlArg(argument, "list");
|
||||||
std::string include = UrlDecode(getUrlArg(argument, "include")), exclude = UrlDecode(getUrlArg(argument, "exclude")), sort_flag = getUrlArg(argument, "sort");
|
std::string include = UrlDecode(getUrlArg(argument, "include")), exclude = UrlDecode(getUrlArg(argument, "exclude")), sort_flag = getUrlArg(argument, "sort");
|
||||||
std::string scv = getUrlArg(argument, "scv"), fdn = getUrlArg(argument, "fdn"), expand = getUrlArg(argument, "expand"), append_sub_userinfo = getUrlArg(argument, "append_info");
|
std::string scv = getUrlArg(argument, "scv"), fdn = getUrlArg(argument, "fdn"), expand = getUrlArg(argument, "expand"), append_sub_userinfo = getUrlArg(argument, "append_info");
|
||||||
|
std::string dev_id = getUrlArg(argument, "dev_id"), filename = UrlDecode(getUrlArg(argument, "filename")), interval_str = getUrlArg(argument, "interval"), strict_str = getUrlArg(argument, "strict");
|
||||||
std::string base_content, output_content;
|
std::string base_content, output_content;
|
||||||
string_array extra_group, extra_ruleset, include_remarks, exclude_remarks;
|
string_array extra_group, extra_ruleset, include_remarks, exclude_remarks;
|
||||||
std::string groups = urlsafe_base64_decode(getUrlArg(argument, "groups")), ruleset = urlsafe_base64_decode(getUrlArg(argument, "ruleset")), config = UrlDecode(getUrlArg(argument, "config"));
|
std::string groups = urlsafe_base64_decode(getUrlArg(argument, "groups")), ruleset = urlsafe_base64_decode(getUrlArg(argument, "ruleset")), config = UrlDecode(getUrlArg(argument, "config"));
|
||||||
std::vector<ruleset_content> rca;
|
std::vector<ruleset_content> rca;
|
||||||
extra_settings ext;
|
extra_settings ext;
|
||||||
std::string subInfo, dummy;
|
std::string subInfo, dummy;
|
||||||
bool ruleset_updated = false, authorized = getUrlArg(argument, "token") == access_token;
|
int interval = interval_str.size() ? to_int(interval_str, config_update_interval) : config_update_interval;
|
||||||
|
bool ruleset_updated = false, authorized = getUrlArg(argument, "token") == access_token, strict = strict_str.size() ? strict_str == "true" : config_update_strict;
|
||||||
|
|
||||||
if(std::find(regex_blacklist.cbegin(), regex_blacklist.cend(), include) != regex_blacklist.cend() || std::find(regex_blacklist.cbegin(), regex_blacklist.cend(), exclude) != regex_blacklist.cend())
|
if(std::find(regex_blacklist.cbegin(), regex_blacklist.cend(), include) != regex_blacklist.cend() || std::find(regex_blacklist.cbegin(), regex_blacklist.cend(), exclude) != regex_blacklist.cend())
|
||||||
return "Invalid request!";
|
return "Invalid request!";
|
||||||
@ -944,6 +956,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
|
|
||||||
ext.nodelist = nodelist == "true";
|
ext.nodelist = nodelist == "true";
|
||||||
ext.surge_ssr_path = surge_ssr_path;
|
ext.surge_ssr_path = surge_ssr_path;
|
||||||
|
ext.quanx_dev_id = dev_id.size() ? dev_id : quanx_script_id;
|
||||||
ext.enable_rule_generator = enable_rule_generator;
|
ext.enable_rule_generator = enable_rule_generator;
|
||||||
if(expand != "true")
|
if(expand != "true")
|
||||||
ext.managed_config_prefix = managed_config_prefix;
|
ext.managed_config_prefix = managed_config_prefix;
|
||||||
@ -1135,7 +1148,8 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
uploadGist("surge" + version, upload_path, output_content, true);
|
uploadGist("surge" + version, upload_path, output_content, true);
|
||||||
|
|
||||||
if(write_managed_config && managed_config_prefix.size())
|
if(write_managed_config && managed_config_prefix.size())
|
||||||
output_content = "#!MANAGED-CONFIG " + managed_config_prefix + "/sub?" + argument + "\n\n" + output_content;
|
output_content = "#!MANAGED-CONFIG " + managed_config_prefix + "/sub?" + argument + (interval ? " interval=" + std::to_string(interval) : "") \
|
||||||
|
+ " strict=" + std::string(strict ? "true" : "false") + "\n\n" + output_content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(target == "surfboard")
|
else if(target == "surfboard")
|
||||||
@ -1151,7 +1165,8 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
uploadGist("surfboard", upload_path, output_content, true);
|
uploadGist("surfboard", upload_path, output_content, true);
|
||||||
|
|
||||||
if(write_managed_config && managed_config_prefix.size())
|
if(write_managed_config && managed_config_prefix.size())
|
||||||
output_content = "#!MANAGED-CONFIG " + managed_config_prefix + "/sub?" + argument + "\n\n" + output_content;
|
output_content = "#!MANAGED-CONFIG " + managed_config_prefix + "/sub?" + argument + (interval ? " interval=" + std::to_string(interval) : "") \
|
||||||
|
+ " strict=" + std::string(strict ? "true" : "false") + "\n\n" + output_content;
|
||||||
}
|
}
|
||||||
else if(target == "mellow")
|
else if(target == "mellow")
|
||||||
{
|
{
|
||||||
@ -1247,14 +1262,18 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr<<"Unspecified"<<std::endl;
|
std::cerr<<"Unspecified"<<std::endl;
|
||||||
|
*status_code = 500;
|
||||||
|
return "Unrecognized target";
|
||||||
}
|
}
|
||||||
|
if(filename.size())
|
||||||
|
extra_headers.emplace("Content-Disposition", "attachment; filename=\"" + filename + "\"");
|
||||||
return output_content;
|
return output_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
|
std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
|
||||||
{
|
{
|
||||||
std::string url = argument.size() <= 8 ? "" : argument.substr(8);
|
std::string url = argument.size() <= 8 ? "" : argument.substr(8);
|
||||||
std::string base_content, output_content;
|
std::string base_content;
|
||||||
std::vector<nodeInfo> nodes;
|
std::vector<nodeInfo> nodes;
|
||||||
string_array extra_group, extra_ruleset, include_remarks, exclude_remarks;
|
string_array extra_group, extra_ruleset, include_remarks, exclude_remarks;
|
||||||
std::vector<ruleset_content> rca;
|
std::vector<ruleset_content> rca;
|
||||||
@ -1283,7 +1302,7 @@ std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
|
|||||||
refreshRulesets(rulesets, ruleset_content_array);
|
refreshRulesets(rulesets, ruleset_content_array);
|
||||||
rca = ruleset_content_array;
|
rca = ruleset_content_array;
|
||||||
|
|
||||||
extra_settings ext = {true, overwrite_original_rules, safe_get_renames(), safe_get_emojis(), add_emoji, remove_old_emoji, append_proxy_type, udp_flag, tfo_flag, false, do_sort, scv_flag, filter_deprecated, "", ""};
|
extra_settings ext = {true, overwrite_original_rules, safe_get_renames(), safe_get_emojis(), add_emoji, remove_old_emoji, append_proxy_type, udp_flag, tfo_flag, false, do_sort, scv_flag, filter_deprecated, "", "", ""};
|
||||||
|
|
||||||
std::string proxy;
|
std::string proxy;
|
||||||
if(proxy_subscription == "SYSTEM")
|
if(proxy_subscription == "SYSTEM")
|
||||||
@ -1382,28 +1401,12 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
|||||||
else
|
else
|
||||||
proxy = proxy_subscription;
|
proxy = proxy_subscription;
|
||||||
|
|
||||||
std::string subInfo;
|
//scan groups first, get potential policy-path
|
||||||
std::cerr<<"Fetching node data from url '"<<url<<"'."<<std::endl;
|
|
||||||
if(addNodes(url, nodes, 0, proxy, dummy_str_array, dummy_str_array, dummy_str_array, dummy_str_array, subInfo, false) == -1)
|
|
||||||
{
|
|
||||||
*status_code = 400;
|
|
||||||
return std::string("The following link doesn't contain any valid node info: " + url);
|
|
||||||
}
|
|
||||||
|
|
||||||
//exit if found nothing
|
|
||||||
if(!nodes.size())
|
|
||||||
{
|
|
||||||
*status_code = 400;
|
|
||||||
return "No nodes were found!";
|
|
||||||
}
|
|
||||||
|
|
||||||
extra_settings ext = {true, true, dummy_str_array, dummy_str_array, false, false, false, udp_flag, tfo_flag, false, do_sort, scv_flag, filter_deprecated, "", ""};
|
|
||||||
|
|
||||||
netchToClash(nodes, clash, dummy_str_array, false, ext);
|
|
||||||
|
|
||||||
string_multimap section;
|
string_multimap section;
|
||||||
ini.GetItems("Proxy Group", section);
|
ini.GetItems("Proxy Group", section);
|
||||||
std::string name, type, content;
|
std::string name, type, content;
|
||||||
|
string_array links;
|
||||||
|
links.emplace_back(url);
|
||||||
YAML::Node singlegroup;
|
YAML::Node singlegroup;
|
||||||
for(auto &x : section)
|
for(auto &x : section)
|
||||||
{
|
{
|
||||||
@ -1424,11 +1427,36 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
|||||||
singlegroup["url"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1));
|
singlegroup["url"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1));
|
||||||
else if(dummy_str_array[i].find("interval") == 0)
|
else if(dummy_str_array[i].find("interval") == 0)
|
||||||
singlegroup["interval"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1));
|
singlegroup["interval"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1));
|
||||||
|
else if(dummy_str_array[i].find("policy-path") == 0)
|
||||||
|
links.emplace_back(trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1)));
|
||||||
else
|
else
|
||||||
singlegroup["proxies"].push_back(trim(dummy_str_array[i]));
|
singlegroup["proxies"].push_back(trim(dummy_str_array[i]));
|
||||||
}
|
}
|
||||||
clash["Proxy Group"].push_back(singlegroup);
|
clash["Proxy Group"].push_back(singlegroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string subInfo;
|
||||||
|
for(std::string &x : links)
|
||||||
|
{
|
||||||
|
std::cerr<<"Fetching node data from url '"<<x<<"'."<<std::endl;
|
||||||
|
if(addNodes(x, nodes, 0, proxy, dummy_str_array, dummy_str_array, dummy_str_array, dummy_str_array, subInfo, false) == -1)
|
||||||
|
{
|
||||||
|
*status_code = 400;
|
||||||
|
return std::string("The following link doesn't contain any valid node info: " + x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//exit if found nothing
|
||||||
|
if(!nodes.size())
|
||||||
|
{
|
||||||
|
*status_code = 400;
|
||||||
|
return "No nodes were found!";
|
||||||
|
}
|
||||||
|
|
||||||
|
extra_settings ext = {true, true, dummy_str_array, dummy_str_array, false, false, false, udp_flag, tfo_flag, false, do_sort, scv_flag, filter_deprecated, "", "", ""};
|
||||||
|
|
||||||
|
netchToClash(nodes, clash, dummy_str_array, false, ext);
|
||||||
|
|
||||||
section.clear();
|
section.clear();
|
||||||
ini.GetItems("Proxy", section);
|
ini.GetItems("Proxy", section);
|
||||||
for(auto &x : section)
|
for(auto &x : section)
|
||||||
@ -1509,7 +1537,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
|||||||
|
|
||||||
std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||||
{
|
{
|
||||||
std::string name = UrlDecode(getUrlArg(argument, "name")), token = getUrlArg(argument, "token");
|
std::string name = UrlDecode(getUrlArg(argument, "name")), token = UrlDecode(getUrlArg(argument, "token"));
|
||||||
if(token != access_token)
|
if(token != access_token)
|
||||||
{
|
{
|
||||||
*status_code = 403;
|
*status_code = 403;
|
||||||
@ -1546,3 +1574,86 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
|||||||
query.erase(query.size() - 1);
|
query.erase(query.size() - 1);
|
||||||
return subconverter(query, postdata, status_code, extra_headers);
|
return subconverter(query, postdata, status_code, extra_headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getScript(RESPONSE_CALLBACK_ARGS)
|
||||||
|
{
|
||||||
|
std::string url = urlsafe_base64_decode(getUrlArg(argument, "url")), dev_id = getUrlArg(argument, "id");
|
||||||
|
std::string output_content, dummy;
|
||||||
|
|
||||||
|
std::string proxy;
|
||||||
|
if(proxy_config == "SYSTEM")
|
||||||
|
proxy = getSystemProxy();
|
||||||
|
else if(proxy_config == "NONE")
|
||||||
|
proxy = "";
|
||||||
|
else
|
||||||
|
proxy = proxy_config;
|
||||||
|
|
||||||
|
if(fileExist(url))
|
||||||
|
output_content = fileGet(url, true, true);
|
||||||
|
else
|
||||||
|
output_content = webGet(url, proxy, dummy, cache_config);
|
||||||
|
|
||||||
|
if(!dev_id.size())
|
||||||
|
dev_id = quanx_script_id;
|
||||||
|
|
||||||
|
const std::string pattern = "(\\/\\*[\\s\\S]*?)^(.*?@supported )(.*?\\s?)$([\\s\\S]*\\*\\/\\s?";
|
||||||
|
if(dev_id.size())
|
||||||
|
{
|
||||||
|
if(regFind(output_content, pattern))
|
||||||
|
output_content = regReplace(output_content, pattern, "$1$2" + dev_id + "$4");
|
||||||
|
else
|
||||||
|
output_content = "/**\n * @supported " + dev_id + "\n * THIS COMMENT IS GENERATED BY SUBCONVERTER\n */\n\n" + output_content;
|
||||||
|
}
|
||||||
|
return output_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getRewriteRemote(RESPONSE_CALLBACK_ARGS)
|
||||||
|
{
|
||||||
|
std::string url = urlsafe_base64_decode(getUrlArg(argument, "url")), dev_id = getUrlArg(argument, "id");
|
||||||
|
std::string output_content, dummy;
|
||||||
|
|
||||||
|
std::string proxy;
|
||||||
|
if(proxy_config == "SYSTEM")
|
||||||
|
proxy = getSystemProxy();
|
||||||
|
else if(proxy_config == "NONE")
|
||||||
|
proxy = "";
|
||||||
|
else
|
||||||
|
proxy = proxy_config;
|
||||||
|
|
||||||
|
if(fileExist(url))
|
||||||
|
output_content = fileGet(url, true, true);
|
||||||
|
else
|
||||||
|
output_content = webGet(url, proxy, dummy, cache_config);
|
||||||
|
|
||||||
|
if(!dev_id.size())
|
||||||
|
dev_id = quanx_script_id;
|
||||||
|
|
||||||
|
if(dev_id.size())
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
std::string strLine;
|
||||||
|
const std::string pattern = "^(.*? url script-.*? )(.*?)$";
|
||||||
|
string_size lineSize;
|
||||||
|
char delimiter = count(output_content.begin(), output_content.end(), '\n') < 1 ? '\r' : '\n';
|
||||||
|
|
||||||
|
ss << output_content;
|
||||||
|
output_content.clear();
|
||||||
|
while(getline(ss, strLine, delimiter))
|
||||||
|
{
|
||||||
|
lineSize = strLine.size();
|
||||||
|
if(lineSize && strLine[lineSize - 1] == '\r') //remove line break
|
||||||
|
{
|
||||||
|
strLine.erase(lineSize - 1);
|
||||||
|
lineSize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strLine.empty() && regMatch(strLine, pattern))
|
||||||
|
{
|
||||||
|
url = managed_config_prefix + "/qx-script?id=" + dev_id + "&url=" + urlsafe_base64_encode(regReplace(strLine, pattern, "$2"));
|
||||||
|
strLine = regReplace(strLine, pattern, "$1") + url;
|
||||||
|
}
|
||||||
|
output_content.append(strLine + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output_content;
|
||||||
|
}
|
||||||
|
|||||||
@ -10,8 +10,12 @@
|
|||||||
void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &rca);
|
void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &rca);
|
||||||
void readConf();
|
void readConf();
|
||||||
void generateBase();
|
void generateBase();
|
||||||
|
|
||||||
|
std::string getScript(RESPONSE_CALLBACK_ARGS);
|
||||||
std::string getProfile(RESPONSE_CALLBACK_ARGS);
|
std::string getProfile(RESPONSE_CALLBACK_ARGS);
|
||||||
std::string getRuleset(RESPONSE_CALLBACK_ARGS);
|
std::string getRuleset(RESPONSE_CALLBACK_ARGS);
|
||||||
|
std::string getRewriteRemote(RESPONSE_CALLBACK_ARGS);
|
||||||
|
|
||||||
std::string subconverter(RESPONSE_CALLBACK_ARGS);
|
std::string subconverter(RESPONSE_CALLBACK_ARGS);
|
||||||
std::string simpleToClashR(RESPONSE_CALLBACK_ARGS);
|
std::string simpleToClashR(RESPONSE_CALLBACK_ARGS);
|
||||||
std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS);
|
std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS);
|
||||||
|
|||||||
@ -185,6 +185,10 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
append_response("GET", "/getprofile", "text/plain;charset=utf-8", getProfile);
|
append_response("GET", "/getprofile", "text/plain;charset=utf-8", getProfile);
|
||||||
|
|
||||||
|
append_response("GET", "/qx-script", "text/plain;charset=utf-8", getScript);
|
||||||
|
|
||||||
|
append_response("GET", "/qx-rewrite", "text/plain;charset=utf-8", getRewriteRemote);
|
||||||
|
|
||||||
append_response("GET", "/clash", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
append_response("GET", "/clash", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||||
{
|
{
|
||||||
return subconverter(argument + "&target=clash", postdata, status_code, extra_headers);
|
return subconverter(argument + "&target=clash", postdata, status_code, extra_headers);
|
||||||
|
|||||||
@ -35,7 +35,7 @@ string_array safe_get_times()
|
|||||||
YAML::Node safe_get_clash_base()
|
YAML::Node safe_get_clash_base()
|
||||||
{
|
{
|
||||||
guarded_mutex guard(clash_base_mutex);
|
guarded_mutex guard(clash_base_mutex);
|
||||||
return clash_base;
|
return YAML::Clone(clash_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
INIReader safe_get_mellow_base()
|
INIReader safe_get_mellow_base()
|
||||||
|
|||||||
@ -1758,6 +1758,63 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
|
|||||||
|
|
||||||
if(ext.enable_rule_generator)
|
if(ext.enable_rule_generator)
|
||||||
rulesetToSurge(ini, ruleset_content_array, -1, ext.overwrite_original_rules, ext.managed_config_prefix);
|
rulesetToSurge(ini, ruleset_content_array, -1, ext.overwrite_original_rules, ext.managed_config_prefix);
|
||||||
|
|
||||||
|
//process scripts
|
||||||
|
string_multimap scripts;
|
||||||
|
std::string content, title, url;
|
||||||
|
const std::string pattern = "^(.*? url script-.*? )(.*?)$";
|
||||||
|
if(ini.SectionExist("rewrite_local") && ext.quanx_dev_id.size())
|
||||||
|
{
|
||||||
|
ini.GetItems("rewrite_local", scripts);
|
||||||
|
ini.EraseSection("rewrite_local");
|
||||||
|
ini.SetCurrentSection("rewrite_local");
|
||||||
|
for(auto &x : scripts)
|
||||||
|
{
|
||||||
|
title = x.first;
|
||||||
|
if(title != "{NONAME}")
|
||||||
|
content = title + "=" + x.second;
|
||||||
|
else
|
||||||
|
content = x.second;
|
||||||
|
|
||||||
|
if(regMatch(content, pattern))
|
||||||
|
{
|
||||||
|
url = regReplace(content, pattern, "$2");
|
||||||
|
if(startsWith(url, "https://") || startsWith(url, "http://"))
|
||||||
|
{
|
||||||
|
url = ext.managed_config_prefix + "/qx-script?id=" + ext.quanx_dev_id + "&url=" + urlsafe_base64_encode(url);
|
||||||
|
content = regReplace(content, pattern, "$1") + url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ini.Set("{NONAME}", content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eraseElements(scripts);
|
||||||
|
string_size pos;
|
||||||
|
if(ini.SectionExist("rewrite_remote") && ext.quanx_dev_id.size())
|
||||||
|
{
|
||||||
|
ini.GetItems("rewrite_remote", scripts);
|
||||||
|
ini.EraseSection("rewrite_remote");
|
||||||
|
ini.SetCurrentSection("rewrite_remote");
|
||||||
|
for(auto &x : scripts)
|
||||||
|
{
|
||||||
|
title = x.first;
|
||||||
|
if(title != "{NONAME}")
|
||||||
|
content = title + "=" + x.second;
|
||||||
|
else
|
||||||
|
content = x.second;
|
||||||
|
|
||||||
|
if(startsWith(content, "https://") || startsWith(content, "http://"))
|
||||||
|
{
|
||||||
|
pos = content.find(",");
|
||||||
|
url = ext.managed_config_prefix + "/qx-rewrite?id=" + ext.quanx_dev_id + "&url=" + urlsafe_base64_encode(content.substr(0, pos));
|
||||||
|
if(pos != content.npos)
|
||||||
|
content = url + content.substr(content.find(","));
|
||||||
|
else
|
||||||
|
content = url;
|
||||||
|
}
|
||||||
|
ini.Set("{NONAME}", content);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string netchToSSD(std::vector<nodeInfo> &nodes, std::string &group, std::string &userinfo, extra_settings &ext)
|
std::string netchToSSD(std::vector<nodeInfo> &nodes, std::string &group, std::string &userinfo, extra_settings &ext)
|
||||||
|
|||||||
@ -32,6 +32,7 @@ struct extra_settings
|
|||||||
bool filter_deprecated = false;
|
bool filter_deprecated = false;
|
||||||
std::string surge_ssr_path;
|
std::string surge_ssr_path;
|
||||||
std::string managed_config_prefix;
|
std::string managed_config_prefix;
|
||||||
|
std::string quanx_dev_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset_content_array, bool overwrite_original_rules);
|
void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset_content_array, bool overwrite_original_rules);
|
||||||
|
|||||||
@ -18,6 +18,16 @@ extern bool print_debug_info;
|
|||||||
//std::string user_agent_str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36";
|
//std::string user_agent_str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36";
|
||||||
std::string user_agent_str = "subconverter/" + std::string(VERSION) + " cURL/" + std::string(LIBCURL_VERSION);
|
std::string user_agent_str = "subconverter/" + std::string(VERSION) + " cURL/" + std::string(LIBCURL_VERSION);
|
||||||
|
|
||||||
|
static inline void curl_init()
|
||||||
|
{
|
||||||
|
static bool init = false;
|
||||||
|
if(!init)
|
||||||
|
{
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
init = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int writer(char *data, size_t size, size_t nmemb, std::string *writerData)
|
static int writer(char *data, size_t size, size_t nmemb, std::string *writerData)
|
||||||
{
|
{
|
||||||
if(writerData == NULL)
|
if(writerData == NULL)
|
||||||
@ -28,22 +38,28 @@ static int writer(char *data, size_t size, size_t nmemb, std::string *writerData
|
|||||||
return size * nmemb;
|
return size * nmemb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string curlGet(std::string url, std::string proxy, std::string &response_headers, CURLcode &return_code)
|
static inline void curl_set_common_options(CURL *curl_handle, const char *url)
|
||||||
{
|
{
|
||||||
CURL *curl_handle;
|
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
|
||||||
std::string data;
|
|
||||||
|
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
|
||||||
|
|
||||||
curl_handle = curl_easy_init();
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_URL, url.data());
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, print_debug_info ? 1L : 0L);
|
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, print_debug_info ? 1L : 0L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
|
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
|
||||||
|
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
|
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 15L);
|
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 15L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, user_agent_str.data());
|
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, user_agent_str.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string curlGet(std::string url, std::string proxy, std::string &response_headers, CURLcode &return_code)
|
||||||
|
{
|
||||||
|
CURL *curl_handle;
|
||||||
|
std::string data;
|
||||||
|
|
||||||
|
curl_init();
|
||||||
|
|
||||||
|
curl_handle = curl_easy_init();
|
||||||
|
curl_set_common_options(curl_handle, url.data());
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writer);
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writer);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &data);
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &data);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, writer);
|
curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, writer);
|
||||||
@ -132,27 +148,20 @@ std::string webGet(std::string url, std::string proxy)
|
|||||||
int curlPost(std::string url, std::string data, std::string proxy, std::string auth_token, std::string *retData)
|
int curlPost(std::string url, std::string data, std::string proxy, std::string auth_token, std::string *retData)
|
||||||
{
|
{
|
||||||
CURL *curl_handle;
|
CURL *curl_handle;
|
||||||
|
CURLcode res;
|
||||||
struct curl_slist *list = NULL;
|
struct curl_slist *list = NULL;
|
||||||
int retVal = 0;
|
int retVal = 0;
|
||||||
|
|
||||||
CURLcode res;
|
curl_init();
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
|
||||||
|
|
||||||
curl_handle = curl_easy_init();
|
curl_handle = curl_easy_init();
|
||||||
list = curl_slist_append(list, "Content-Type: application/json;charset='utf-8'");
|
list = curl_slist_append(list, "Content-Type: application/json;charset='utf-8'");
|
||||||
if(auth_token.size())
|
if(auth_token.size())
|
||||||
list = curl_slist_append(list, std::string("Authorization: token " + auth_token).data());
|
list = curl_slist_append(list, std::string("Authorization: token " + auth_token).data());
|
||||||
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_URL, url.data());
|
curl_set_common_options(curl_handle, url.data());
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, print_debug_info ? 1L : 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
|
curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data.data());
|
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data.data());
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, data.size());
|
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, data.size());
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 15L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writer);
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writer);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, retData);
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, retData);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list);
|
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list);
|
||||||
@ -169,17 +178,18 @@ int curlPost(std::string url, std::string data, std::string proxy, std::string a
|
|||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_cleanup(curl_handle);
|
curl_easy_cleanup(curl_handle);
|
||||||
curl_global_cleanup();
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
int curlPatch(std::string url, std::string data, std::string proxy, std::string auth_token, std::string *retData)
|
int curlPatch(std::string url, std::string data, std::string proxy, std::string auth_token, std::string *retData)
|
||||||
{
|
{
|
||||||
CURL *curl_handle;
|
CURL *curl_handle;
|
||||||
|
CURLcode res;
|
||||||
int retVal = 0;
|
int retVal = 0;
|
||||||
struct curl_slist *list = NULL;
|
struct curl_slist *list = NULL;
|
||||||
|
|
||||||
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
|
curl_init();
|
||||||
|
|
||||||
curl_handle = curl_easy_init();
|
curl_handle = curl_easy_init();
|
||||||
|
|
||||||
@ -187,16 +197,10 @@ int curlPatch(std::string url, std::string data, std::string proxy, std::string
|
|||||||
if(auth_token.size())
|
if(auth_token.size())
|
||||||
list = curl_slist_append(list, std::string("Authorization: token " + auth_token).data());
|
list = curl_slist_append(list, std::string("Authorization: token " + auth_token).data());
|
||||||
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_URL, url.data());
|
curl_set_common_options(curl_handle, url.data());
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, print_debug_info ? 1L : 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "PATCH");
|
curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "PATCH");
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data.data());
|
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data.data());
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, data.size());
|
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, data.size());
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 15L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writer);
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writer);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, retData);
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, retData);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list);
|
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list);
|
||||||
@ -212,6 +216,6 @@ int curlPatch(std::string url, std::string data, std::string proxy, std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_cleanup(curl_handle);
|
curl_easy_cleanup(curl_handle);
|
||||||
curl_global_cleanup();
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ std::vector<responseRoute> responses;
|
|||||||
|
|
||||||
static inline void buffer_cleanup(struct evbuffer *eb)
|
static inline void buffer_cleanup(struct evbuffer *eb)
|
||||||
{
|
{
|
||||||
evbuffer_free(eb);
|
//evbuffer_free(eb);
|
||||||
#ifdef MALLOC_TRIM
|
#ifdef MALLOC_TRIM
|
||||||
malloc_trim(0);
|
malloc_trim(0);
|
||||||
#endif // MALLOC_TRIM
|
#endif // MALLOC_TRIM
|
||||||
@ -102,8 +102,8 @@ void OnReq(evhttp_request *req, void *args)
|
|||||||
std::map<std::string, std::string> extra_headers;
|
std::map<std::string, std::string> extra_headers;
|
||||||
retVal = process_request(req_method, uri, postdata, content_type, return_data, &status_code, extra_headers);
|
retVal = process_request(req_method, uri, postdata, content_type, return_data, &status_code, extra_headers);
|
||||||
|
|
||||||
//auto *OutBuf = evhttp_request_get_output_buffer(req);
|
auto *OutBuf = evhttp_request_get_output_buffer(req);
|
||||||
struct evbuffer *OutBuf = evbuffer_new();
|
//struct evbuffer *OutBuf = evbuffer_new();
|
||||||
if (!OutBuf)
|
if (!OutBuf)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -168,6 +168,7 @@ int start_web_server(void *argv)
|
|||||||
|
|
||||||
evhttp_set_allowed_methods(Server.get(), EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS);
|
evhttp_set_allowed_methods(Server.get(), EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS);
|
||||||
evhttp_set_gencb(Server.get(), OnReq, nullptr);
|
evhttp_set_gencb(Server.get(), OnReq, nullptr);
|
||||||
|
evhttp_set_timeout(Server.get(), 30);
|
||||||
if (event_dispatch() == -1)
|
if (event_dispatch() == -1)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to run message loop." << std::endl;
|
std::cerr << "Failed to run message loop." << std::endl;
|
||||||
@ -253,6 +254,7 @@ int start_web_server_multi(void *argv)
|
|||||||
|
|
||||||
evhttp_set_allowed_methods(httpd, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS);
|
evhttp_set_allowed_methods(httpd, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS);
|
||||||
evhttp_set_gencb(httpd, OnReq, nullptr);
|
evhttp_set_gencb(httpd, OnReq, nullptr);
|
||||||
|
evhttp_set_timeout(httpd, 30);
|
||||||
ret = pthread_create(&ths[i], NULL, httpserver_dispatch, base[i]);
|
ret = pthread_create(&ths[i], NULL, httpserver_dispatch, base[i]);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user