diff --git a/src/main.cpp b/src/main.cpp index 2b2dede..2538251 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,6 +42,10 @@ string_array clash_extra_group; std::string surge_rule_base, surfboard_rule_base, mellow_rule_base; std::string surge_ssr_path; +//pre-compiled rule bases +YAML::Node clash_base; +INIReader surge_base, mellow_base; + #ifndef _WIN32 void SetConsoleTitle(std::string title) { @@ -245,6 +249,25 @@ void readConf() std::cerr<<"Read preference settings completed."< nodes; + string_array extra_group, extra_ruleset, include_remarks, exclude_remarks; + std::vector rca; + + if(!url.size()) + url = default_url; + if(!url.size() || argument.substr(0, 8) != "sublink=") + return "Invalid request!"; + if(url == "sublink") + return "Please insert your subscription link instead of clicking the default link."; + if(!api_mode || cfw_child_process) + readConf(); + + extra_group = clash_extra_group; + + if(update_ruleset_on_request || cfw_child_process) + refreshRulesets(rulesets, ruleset_content_array); + rca = ruleset_content_array; + + extra_settings ext = {add_emoji, remove_old_emoji, append_proxy_type, udp_flag, tfo_flag, false, do_sort, ""}; + + std::string proxy; + if(proxy_subscription == "SYSTEM") + proxy = getSystemProxy(); + else if(proxy_subscription == "NONE") + proxy = ""; + else + proxy = proxy_subscription; + + include_remarks = def_include_remarks; + exclude_remarks = def_exclude_remarks; + + std::cerr<<"Fetching node data from url '"< std::string { @@ -548,6 +635,8 @@ int main(int argc, char *argv[]) append_response("GET", "/sub", "text/plain;charset=utf-8", subconverter); + append_response("GET", "/sub2clashr", "text/plain;charset=utf-8", simpleToClashR); + append_response("GET", "/clash", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=clash", postdata); diff --git a/src/speedtestutil.cpp b/src/speedtestutil.cpp index cff7dbf..d239252 100644 --- a/src/speedtestutil.cpp +++ b/src/speedtestutil.cpp @@ -814,33 +814,35 @@ void explodeNetch(std::string netch, bool ss_libev, bool ssr_libev, std::string void explodeClash(Node yamlnode, std::string custom_port, int local_port, std::vector &nodes, bool ss_libev, bool ssr_libev) { nodeInfo node; + Node singleproxy; unsigned int index = nodes.size(); std::string proxytype, ps, server, port, cipher, group, password; //common std::string type = "none", id, aid = "0", net = "tcp", path, host, tls; //vmess - std::string plugin, pluginopts, pluginopts_mode, pluginopts_host; //ss + std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss std::string protocol, protoparam, obfs, obfsparam; //ssr std::string user; //socks for(unsigned int i = 0; i < yamlnode["Proxy"].size(); i++) { - yamlnode["Proxy"][i]["type"] >> proxytype; - yamlnode["Proxy"][i]["name"] >> ps; - yamlnode["Proxy"][i]["server"] >> server; - port = custom_port == "" ? yamlnode["Proxy"][i]["port"].as() : custom_port; + singleproxy = yamlnode["Proxy"][i]; + singleproxy["type"] >> proxytype; + singleproxy["name"] >> ps; + singleproxy["server"] >> server; + port = custom_port == "" ? singleproxy["port"].as() : custom_port; if(proxytype == "vmess") { group = V2RAY_DEFAULT_GROUP; - yamlnode["Proxy"][i]["uuid"] >> id; - yamlnode["Proxy"][i]["alterId"] >> aid; - yamlnode["Proxy"][i]["cipher"] >> cipher; - net = yamlnode["Proxy"][i]["network"].IsDefined() ? yamlnode["Proxy"][i]["network"].as() : "tcp"; - path = yamlnode["Proxy"][i]["ws-path"].IsDefined() ? yamlnode["Proxy"][i]["ws-path"].as() : "/"; - if(yamlnode["Proxy"][i]["tls"].IsDefined()) - tls = yamlnode["Proxy"][i]["tls"].as() == "true" ? "tls" : ""; + singleproxy["uuid"] >> id; + singleproxy["alterId"] >> aid; + singleproxy["cipher"] >> cipher; + net = singleproxy["network"].IsDefined() ? singleproxy["network"].as() : "tcp"; + path = singleproxy["ws-path"].IsDefined() ? singleproxy["ws-path"].as() : "/"; + if(singleproxy["tls"].IsDefined()) + tls = singleproxy["tls"].as() == "true" ? "tls" : ""; else tls = ""; - if(yamlnode["Proxy"][i]["ws-headers"].IsDefined()) - yamlnode["Proxy"][i]["ws-headers"]["Host"] >> host; + if(singleproxy["ws-headers"].IsDefined()) + singleproxy["ws-headers"]["Host"] >> host; else host = ""; @@ -852,33 +854,74 @@ void explodeClash(Node yamlnode, std::string custom_port, int local_port, std::v { group = SS_DEFAULT_GROUP; - yamlnode["Proxy"][i]["cipher"] >> cipher; - yamlnode["Proxy"][i]["password"] >> password; - if(yamlnode["Proxy"][i]["plugin"].IsDefined() && yamlnode["Proxy"][i]["plugin"].as() == "obfs") + singleproxy["cipher"] >> cipher; + singleproxy["password"] >> password; + if(singleproxy["plugin"].IsDefined()) { - plugin = "simple-obfs"; - if(yamlnode["Proxy"][i]["plugin-opts"].IsDefined()) + if(singleproxy["plugin"].as() == "obfs") { - yamlnode["Proxy"][i]["plugin-opts"]["mode"] >> pluginopts_mode; - if(yamlnode["Proxy"][i]["plugin-opts"]["host"].IsDefined()) - yamlnode["Proxy"][i]["plugin-opts"]["host"] >> pluginopts_host; + plugin = "simple-obfs"; + if(singleproxy["plugin-opts"].IsDefined()) + { + singleproxy["plugin-opts"]["mode"] >> pluginopts_mode; + if(singleproxy["plugin-opts"]["host"].IsDefined()) + singleproxy["plugin-opts"]["host"] >> pluginopts_host; + else + pluginopts_host = ""; + } + } + else if(singleproxy["plugin"].as() == "v2ray-plugin") + { + plugin = "v2ray-plugin"; + if(singleproxy["plugin-opts"].IsDefined()) + { + singleproxy["plugin-opts"]["mode"] >> pluginopts_mode; + if(singleproxy["plugin-opts"]["host"].IsDefined()) + singleproxy["plugin-opts"]["host"] >> pluginopts_host; + else + pluginopts_host = ""; + if(singleproxy["plugin-opts"]["tls"].IsDefined()) + tls = singleproxy["plugin-opts"]["tls"].as() ? "tls;" : ""; + else + tls = ""; + if(singleproxy["plugin-opts"]["path"].IsDefined()) + singleproxy["plugin-opts"]["path"] >> path; + else + path = ""; + if(singleproxy["plugin-opts"]["mux"].IsDefined()) + pluginopts_mux = singleproxy["plugin-opts"]["mux"].as() ? "mux=4;" : ""; + else + pluginopts_mux = ""; + } } } - else if(yamlnode["Proxy"][i]["obfs"].IsDefined()) + else if(singleproxy["obfs"].IsDefined()) { plugin = "simple-obfs"; - yamlnode["Proxy"][i]["obfs"] >> pluginopts_mode; - if(yamlnode["Proxy"][i]["obfs-host"].IsDefined()) - yamlnode["Proxy"][i]["obfs-host"] >> pluginopts_host; + singleproxy["obfs"] >> pluginopts_mode; + if(singleproxy["obfs-host"].IsDefined()) + singleproxy["obfs-host"] >> pluginopts_host; } else plugin = ""; - if(plugin != "") + if(plugin == "simple-obfs") { pluginopts = "obfs=" + pluginopts_mode; pluginopts += pluginopts_host == "" ? "" : ";obfs-host=" + pluginopts_host; } + else if(plugin == "v2ray-plugin") + { + pluginopts = "mode=" + pluginopts_mode + ";" + tls + pluginopts_mux; + if(pluginopts_host.size()) + pluginopts += "host=" + pluginopts_host + ";"; + if(path.size()) + pluginopts += "path=" + path + ";"; + if(pluginopts_mux.size()) + pluginopts += "mux=" + pluginopts_mux + ";"; + } + else + pluginopts = ""; //support for go-shadowsocks2 if(cipher == "AEAD_CHACHA20_POLY1305") @@ -896,10 +939,10 @@ void explodeClash(Node yamlnode, std::string custom_port, int local_port, std::v { group = SOCKS_DEFAULT_GROUP; - if(yamlnode["Proxy"][i]["username"].IsDefined() && yamlnode["Proxy"][i]["password"].IsDefined()) + if(singleproxy["username"].IsDefined() && singleproxy["password"].IsDefined()) { - yamlnode["Proxy"][i]["username"] >> user; - yamlnode["Proxy"][i]["password"] >> password; + singleproxy["username"] >> user; + singleproxy["password"] >> password; } node.linkType = SPEEDTEST_MESSAGE_FOUNDSOCKS; @@ -909,12 +952,12 @@ void explodeClash(Node yamlnode, std::string custom_port, int local_port, std::v { group = SSR_DEFAULT_GROUP; - yamlnode["Proxy"][i]["cipher"] >> cipher; - yamlnode["Proxy"][i]["password"] >> password; - yamlnode["Proxy"][i]["protocol"] >> protocol; - yamlnode["Proxy"][i]["protocolparam"] >> protoparam; - yamlnode["Proxy"][i]["obfs"] >> obfs; - yamlnode["Proxy"][i]["obfsparam"] >> obfsparam; + singleproxy["cipher"] >> cipher; + singleproxy["password"] >> password; + singleproxy["protocol"] >> protocol; + singleproxy["protocolparam"] >> protoparam; + singleproxy["obfs"] >> obfs; + singleproxy["obfsparam"] >> obfsparam; node.linkType = SPEEDTEST_MESSAGE_FOUNDSSR; node.proxyStr = ssrConstruct(group, ps, base64_encode(ps), server, port, protocol, cipher, obfs, password, obfsparam, protoparam, local_port, ssr_libev); @@ -923,10 +966,10 @@ void explodeClash(Node yamlnode, std::string custom_port, int local_port, std::v { group = HTTP_DEFAULT_GROUP; - if(yamlnode["Proxy"][i]["username"].IsDefined() && yamlnode["Proxy"][i]["password"].IsDefined()) + if(singleproxy["username"].IsDefined() && singleproxy["password"].IsDefined()) { - yamlnode["Proxy"][i]["username"] >> user; - yamlnode["Proxy"][i]["password"] >> password; + singleproxy["username"] >> user; + singleproxy["password"] >> password; } node.linkType = SPEEDTEST_MESSAGE_FOUNDHTTP; diff --git a/src/subexport.cpp b/src/subexport.cpp index 8935ac2..07de2ee 100644 --- a/src/subexport.cpp +++ b/src/subexport.cpp @@ -309,7 +309,7 @@ void rulesetToClash(YAML::Node &base_rule, std::vector &ruleset std::stringstream strStrm; YAML::Node Rules; - if(!overwrite_original_rules) + if(!overwrite_original_rules && base_rule["Rule"].IsDefined()) Rules = base_rule["Rule"]; for(ruleset_content &x : ruleset_content_array) @@ -403,11 +403,8 @@ void rulesetToSurge(INIReader &base_rule, std::vector &ruleset_ if(!strLine.size() || strLine.find("#") == 0 || strLine.find(";") == 0) //remove comments continue; strLine += "," + rule_group; - if(strLine.find("IP-CIDR") == 0) - strLine = regReplace(strLine, "^(.*)(,no-resolve)(.*)$", "$1$3$2"); - else if(strLine.find("DOMAIN-SUFFIX") == 0) - strLine = regReplace(strLine, "^(.*)(,force-remote-dns)(.*)$", "$1$3$2"); - //strLine = regReplace(strLine, "^(.*?)(,.*?)(,.*)(,.*)$", "$1$2$4$3") + if(std::count(strLine.begin(), strLine.end(), ',') > 2) + strLine = regReplace(strLine, "^(.*?,.*?)(,.*)(,.*)$", "$1$3$2"); allRules.emplace_back(strLine); } } @@ -419,10 +416,10 @@ void rulesetToSurge(INIReader &base_rule, std::vector &ruleset_ } } -std::string netchToClash(std::vector &nodes, std::string &base_conf, std::vector &ruleset_content_array, string_array &extra_proxy_group, bool clashR, extra_settings &ext) +YAML::Node netchToClash(std::vector &nodes, YAML::Node &yamlnode, std::vector &ruleset_content_array, string_array &extra_proxy_group, bool clashR, extra_settings &ext) { try_config_lock(); - YAML::Node yamlnode, proxies, singleproxy, singlegroup, original_groups; + YAML::Node proxies, singleproxy, singlegroup, original_groups; rapidjson::Document json; std::string type, remark, hostname, port, username, password, method; std::string plugin, pluginopts; @@ -433,15 +430,6 @@ std::string netchToClash(std::vector &nodes, std::string &base_conf, s bool tlssecure, replace_flag; string_array vArray, remarks_list, filtered_nodelist; - try - { - yamlnode = YAML::Load(base_conf); - } - catch (std::exception &e) - { - return std::string(); - } - std::for_each(nodes.begin(), nodes.end(), [ext](nodeInfo &x) { x.remarks = nodeRename(x.remarks); @@ -491,6 +479,15 @@ std::string netchToClash(std::vector &nodes, std::string &base_conf, s singleproxy["plugin-opts"]["mode"] = UrlDecode(getUrlArg(pluginopts, "obfs")); singleproxy["plugin-opts"]["host"] = UrlDecode(getUrlArg(pluginopts, "obfs-host")); } + else if(plugin == "v2ray-plugin") + { + singleproxy["plugin"] = "v2ray-plugin"; + singleproxy["plugin-opts"]["mode"] = getUrlArg(pluginopts, "mode"); + singleproxy["plugin-opts"]["host"] = getUrlArg(pluginopts, "host"); + singleproxy["plugin-opts"]["path"] = getUrlArg(pluginopts, "path"); + singleproxy["plugin-opts"]["tls"] = pluginopts.find("tls") != pluginopts.npos; + singleproxy["plugin-opts"]["mux"] = pluginopts.find("mux") != pluginopts.npos; + } } else if(x.linkType == SPEEDTEST_MESSAGE_FOUNDVMESS) { @@ -556,7 +553,7 @@ std::string netchToClash(std::vector &nodes, std::string &base_conf, s { YAML::Node provider; provider["proxies"] = proxies; - return YAML::Dump(provider); + return provider; } yamlnode["Proxy"] = proxies; @@ -645,6 +642,27 @@ std::string netchToClash(std::vector &nodes, std::string &base_conf, s yamlnode["Proxy Group"] = original_groups; + return yamlnode; +} + +std::string netchToClash(std::vector &nodes, std::string &base_conf, std::vector &ruleset_content_array, string_array &extra_proxy_group, bool clashR, extra_settings &ext) +{ + YAML::Node yamlnode; + + try + { + yamlnode = YAML::Load(base_conf); + } + catch (std::exception &e) + { + return std::string(); + } + + yamlnode = netchToClash(nodes, yamlnode, ruleset_content_array, extra_proxy_group, clashR, ext); + + if(ext.nodelist) + return YAML::Dump(yamlnode); + rulesetToClash(yamlnode, ruleset_content_array); return YAML::Dump(yamlnode); @@ -1362,10 +1380,21 @@ std::string netchToSSD(std::vector &nodes, std::string &group, extra_s } std::string netchToMellow(std::vector &nodes, std::string &base_conf, std::vector &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext) +{ + INIReader ini; + ini.store_any_line = true; + if(ini.Parse(base_conf) != 0) + return std::string(); + + netchToMellow(nodes, ini, ruleset_content_array, extra_proxy_group, ext); + + return ini.ToString(); +} + +void netchToMellow(std::vector &nodes, INIReader &ini, std::vector &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext) { try_config_lock(); rapidjson::Document json; - INIReader ini; std::string proxy; std::string type, remark, hostname, port, username, password, method; std::string plugin, pluginopts; @@ -1374,10 +1403,6 @@ std::string netchToMellow(std::vector &nodes, std::string &base_conf, std::vector nodelist; string_array vArray, remarks_list, filtered_nodelist; - ini.store_any_line = true; - if(ini.Parse(base_conf) != 0) - return std::string(); - ini.SetCurrentSection("Endpoint"); std::for_each(nodes.begin(), nodes.end(), [ext](nodeInfo &x) @@ -1546,8 +1571,6 @@ std::string netchToMellow(std::vector &nodes, std::string &base_conf, rulesetToSurge(ini, ruleset_content_array, 2); ini.RenameSection("Rule", "RoutingRule"); - - return ini.ToString(); } std::string buildGistData(std::string name, std::string content) @@ -1623,7 +1646,7 @@ int uploadGist(std::string name, std::string path, std::string content, bool wri url = "https://gist.githubusercontent.com/" + username + "/" + id + "/raw/" + path; std::cerr<<"Gist id provided. Modifying gist...\n"; if(writeManageURL) - content = "#!MANAGED-CONFIG "+ url + "\n" + content; + content = "#!MANAGED-CONFIG " + url + "\n" + content; retVal = curlPatch("https://api.github.com/gists/" + id, buildGistData(path, content), getSystemProxy(), token, &retData); if(retVal != 200) { diff --git a/src/subexport.h b/src/subexport.h index 65f4650..0a7a716 100644 --- a/src/subexport.h +++ b/src/subexport.h @@ -22,10 +22,13 @@ struct extra_settings std::string surge_ssr_path; }; - +void rulesetToClash(YAML::Node &base_rule, std::vector &ruleset_content_array); +void rulesetToSurge(INIReader &base_rule, std::vector &ruleset_content_array, int surge_ver); std::string netchToClash(std::vector &nodes, std::string &base_conf, std::vector &ruleset_content_array, string_array &extra_proxy_group, bool clashR, extra_settings &ext); +YAML::Node netchToClash(std::vector &nodes, YAML::Node &base, std::vector &ruleset_content_array, string_array &extra_proxy_group, bool clashR, extra_settings &ext); std::string netchToSurge(std::vector &nodes, std::string &base_conf, std::vector &ruleset_content_array, string_array &extra_proxy_group, int surge_ver, extra_settings &ext); std::string netchToMellow(std::vector &nodes, std::string &base_conf, std::vector &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext); +void netchToMellow(std::vector &nodes, INIReader &ini, std::vector &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext); std::string netchToSS(std::vector &nodes, extra_settings &ext); std::string netchToSSR(std::vector &nodes, extra_settings &ext); std::string netchToVMess(std::vector &nodes, extra_settings &ext);