From 38fd0da1ba17cadf157c466f6d82350fa19cb8f9 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Mon, 27 Nov 2023 00:52:00 +0800 Subject: [PATCH] Enhancements Add support for parsing authentication info in SOCKS5 links. (#652) Optimize codes. --- src/generator/config/nodemanip.cpp | 2 +- src/handler/webget.cpp | 2 +- src/parser/infoparser.cpp | 26 +++++---- src/parser/subparser.cpp | 91 ++++++++++++++++-------------- src/script/script.cpp | 2 +- src/utils/string.h | 39 +++++++++---- 6 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/generator/config/nodemanip.cpp b/src/generator/config/nodemanip.cpp index c178410e6..60ebf8694 100644 --- a/src/generator/config/nodemanip.cpp +++ b/src/generator/config/nodemanip.cpp @@ -157,7 +157,7 @@ int addNodes(std::string link, std::vector &allNodes, int groupID, parse_ writeLog(LOG_TYPE_WARN, "No system proxy is set. Skipping."); } */ - if(strSub.size()) + if(!strSub.empty()) { writeLog(LOG_TYPE_INFO, "Parsing subscription data..."); if(explodeConfContent(strSub, nodes) == 0) diff --git a/src/handler/webget.cpp b/src/handler/webget.cpp index 78ad4f977..c82003ad3 100644 --- a/src/handler/webget.cpp +++ b/src/handler/webget.cpp @@ -29,7 +29,7 @@ std::mutex cache_rw_lock; class RWLock { -#define WRITE_LOCK_STATUS -1 +#define WRITE_LOCK_STATUS (-1) #define FREE_STATUS 0 private: const std::thread::id NULL_THREAD; diff --git a/src/parser/infoparser.cpp b/src/parser/infoparser.cpp index be01a0dfc..155469956 100644 --- a/src/parser/infoparser.cpp +++ b/src/parser/infoparser.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "../config/regmatch.h" #include "../parser/config/proxy.h" @@ -12,7 +12,7 @@ unsigned long long streamToInt(const std::string &stream) { - if(!stream.size()) + if(stream.empty()) return 0; double streamval = 1.0; std::vector units = {"B", "KB", "MB", "GB", "TB", "PB", "EB"}; @@ -74,7 +74,7 @@ bool getSubInfoFromHeader(const std::string &header, std::string &result) if(regFind(header, pattern)) { regGetMatch(header, pattern, 2, 0, &retStr); - if(retStr.size()) + if(!retStr.empty()) { result = retStr; return true; @@ -90,7 +90,7 @@ bool getSubInfoFromNodes(const std::vector &nodes, const RegexMatchConfig for(const Proxy &x : nodes) { remarks = x.Remark; - if(!stream_info.size()) + if(stream_info.empty()) { for(const RegexMatchConfig &y : stream_rules) { @@ -109,7 +109,7 @@ bool getSubInfoFromNodes(const std::vector &nodes, const RegexMatchConfig } remarks = x.Remark; - if(!time_info.size()) + if(time_info.empty()) { for(const RegexMatchConfig &y : time_rules) { @@ -127,11 +127,11 @@ bool getSubInfoFromNodes(const std::vector &nodes, const RegexMatchConfig } } - if(stream_info.size() && time_info.size()) + if(!stream_info.empty() && !time_info.empty()) break; } - if(!stream_info.size() && !time_info.size()) + if(stream_info.empty() && time_info.empty()) return false; //calculate how much stream left @@ -139,28 +139,30 @@ bool getSubInfoFromNodes(const std::vector &nodes, const RegexMatchConfig std::string total_str = getUrlArg(stream_info, "total"), left_str = getUrlArg(stream_info, "left"), used_str = getUrlArg(stream_info, "used"); if(strFind(total_str, "%")) { - if(used_str.size()) + if(!used_str.empty()) { used = streamToInt(used_str); total = used / (1 - percentToDouble(total_str)); } - else if(left_str.size()) + else if(!left_str.empty()) { left = streamToInt(left_str); total = left / percentToDouble(total_str); + if (left > total) left = 0; used = total - left; } } else { total = streamToInt(total_str); - if(used_str.size()) + if(!used_str.empty()) { used = streamToInt(used_str); } - else if(left_str.size()) + else if(!left_str.empty()) { left = streamToInt(left_str); + if (left > total) left = 0; used = total - left; } } @@ -183,7 +185,7 @@ bool getSubInfoFromSSD(const std::string &sub, std::string &result) return false; std::string used_str = GetMember(json, "traffic_used"), total_str = GetMember(json, "traffic_total"), expire_str = GetMember(json, "expiry"); - if(!used_str.size() || !total_str.size()) + if(used_str.empty() || total_str.empty()) return false; unsigned long long used = stod(used_str) * std::pow(1024, 3), total = stod(total_str) * std::pow(1024, 3), expire; result = "upload=0; download=" + std::to_string(used) + "; total=" + std::to_string(total) + ";"; diff --git a/src/parser/subparser.cpp b/src/parser/subparser.cpp index ec6d27bf8..1465b16d4 100644 --- a/src/parser/subparser.cpp +++ b/src/parser/subparser.cpp @@ -346,7 +346,6 @@ void explodeVmessConf(std::string content, std::vector &nodes) nodes.emplace_back(std::move(node)); index++; } - return; } void explodeSS(std::string ss, Proxy &node) @@ -356,20 +355,22 @@ void explodeSS(std::string ss, Proxy &node) ss = replaceAllDistinct(ss.substr(5), "/?", "?"); if(strFind(ss, "#")) { - ps = urlDecode(ss.substr(ss.find("#") + 1)); - ss.erase(ss.find("#")); + auto sspos = ss.find('#'); + ps = urlDecode(ss.substr(sspos + 1)); + ss.erase(sspos); } if(strFind(ss, "?")) { - addition = ss.substr(ss.find("?") + 1); + addition = ss.substr(ss.find('?') + 1); plugins = urlDecode(getUrlArg(addition, "plugin")); - plugin = plugins.substr(0, plugins.find(";")); - pluginopts = plugins.substr(plugins.find(";") + 1); + auto pluginpos = plugins.find(';'); + plugin = plugins.substr(0, pluginpos); + pluginopts = plugins.substr(pluginpos + 1); group = getUrlArg(addition, "group"); if(!group.empty()) group = urlSafeBase64Decode(group); - ss.erase(ss.find("?")); + ss.erase(ss.find('?')); } if(strFind(ss, "@")) { @@ -465,7 +466,6 @@ void explodeSSD(std::string link, std::vector &nodes) nodes.emplace_back(std::move(node)); index++; } - return; } void explodeSSAndroid(std::string ss, std::vector &nodes) @@ -474,7 +474,7 @@ void explodeSSAndroid(std::string ss, std::vector &nodes) std::string plugin, pluginopts; Document json; - int index = nodes.size(); + auto index = nodes.size(); //first add some extra data before parsing ss = "{\"nodes\":" + ss + "}"; json.Parse(ss.data()); @@ -509,7 +509,7 @@ void explodeSSConf(std::string content, std::vector &nodes) { Document json; std::string ps, password, method, server, port, plugin, pluginopts, group = SS_DEFAULT_GROUP; - int index = nodes.size(); + auto index = nodes.size(); json.Parse(content.data()); if(json.HasParseError() || !json.IsObject()) @@ -540,7 +540,6 @@ void explodeSSConf(std::string content, std::vector &nodes) nodes.emplace_back(std::move(node)); index++; } - return; } void explodeSSR(std::string ssr, Proxy &node) @@ -584,7 +583,7 @@ void explodeSSRConf(std::string content, std::vector &nodes) { Document json; std::string remarks, group, server, port, method, password, protocol, protoparam, obfs, obfsparam, plugin, pluginopts; - int index = nodes.size(); + auto index = nodes.size(); json.Parse(content.data()); if(json.HasParseError() || !json.IsObject()) @@ -642,7 +641,6 @@ void explodeSSRConf(std::string content, std::vector &nodes) nodes.emplace_back(std::move(node)); index++; } - return; } void explodeSocks(std::string link, Proxy &node) @@ -650,14 +648,26 @@ void explodeSocks(std::string link, Proxy &node) std::string group, remarks, server, port, username, password; if(strFind(link, "socks://")) //v2rayn socks link { - std::vector arguments; if(strFind(link, "#")) { - remarks = urlDecode(link.substr(link.find("#") + 1)); - link.erase(link.find("#")); + auto pos = link.find('#'); + remarks = urlDecode(link.substr(pos + 1)); + link.erase(pos); } link = urlSafeBase64Decode(link.substr(8)); - arguments = split(link, ":"); + if(strFind(link, "@")) + { + auto userinfo = split(link, '@'); + if(userinfo.size() < 2) + return; + link = userinfo[1]; + userinfo = split(userinfo[0], ':'); + if(userinfo.size() < 2) + return; + username = userinfo[0]; + password = userinfo[1]; + } + auto arguments = split(link, ':'); if(arguments.size() < 2) return; server = arguments[0]; @@ -707,8 +717,8 @@ void explodeHTTPSub(std::string link, Proxy &node) std::string group, remarks, server, port, username, password; std::string addition; bool tls = strFind(link, "https://"); - string_size pos = link.find("?"); - if(pos != link.npos) + auto pos = link.find('?'); + if(pos != std::string::npos) { addition = link.substr(pos + 1); link.erase(pos); @@ -1188,7 +1198,6 @@ void explodeClash(Node yamlnode, std::vector &nodes) nodes.emplace_back(std::move(node)); index++; } - return; } void explodeStdVMess(std::string vmess, Proxy &node) @@ -1198,8 +1207,8 @@ void explodeStdVMess(std::string vmess, Proxy &node) vmess = vmess.substr(8); string_size pos; - pos = vmess.rfind("#"); - if(pos != vmess.npos) + pos = vmess.rfind('#'); + if(pos != std::string::npos) { remarks = urlDecode(vmess.substr(pos + 1)); vmess.erase(pos); @@ -1232,7 +1241,6 @@ void explodeStdVMess(std::string vmess, Proxy &node) remarks = add + ":" + port; vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, "auto", path, host, "", tls, ""); - return; } void explodeShadowrocket(std::string rocket, Proxy &node) @@ -1286,21 +1294,21 @@ void explodeKitsunebi(std::string kit, Proxy &node) string_size pos; kit = kit.substr(9); - pos = kit.find("#"); - if(pos != kit.npos) + pos = kit.find('#'); + if(pos != std::string::npos) { remarks = kit.substr(pos + 1); kit = kit.substr(0, pos); } - pos = kit.find("?"); + pos = kit.find('?'); addition = kit.substr(pos + 1); kit = kit.substr(0, pos); if(regGetMatch(kit, "(.*?)@(.*):(.*)", 4, 0, &id, &add, &port)) return; - pos = port.find("/"); - if(pos != port.npos) + pos = port.find('/'); + if(pos != std::string::npos) { path = port.substr(pos); port.erase(pos); @@ -1958,8 +1966,8 @@ bool explodeSurge(std::string surge, std::vector &nodes) vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, server, port, "", id, aead, net, method, path, host, "", tls, "", udp, tfo, scv, tls13); break; case "trojan"_hash: //quantumult x style trojan link - server = trim(configs[0].substr(0, configs[0].rfind(":"))); - port = trim(configs[0].substr(configs[0].rfind(":") + 1)); + server = trim(configs[0].substr(0, configs[0].rfind(':'))); + port = trim(configs[0].substr(configs[0].rfind(':') + 1)); if(port == "0") continue; @@ -2006,8 +2014,8 @@ bool explodeSurge(std::string surge, std::vector &nodes) trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, "", host, "", tls == "true", udp, tfo, scv, tls13); break; case "http"_hash: //quantumult x style http links - server = trim(configs[0].substr(0, configs[0].rfind(":"))); - port = trim(configs[0].substr(configs[0].rfind(":") + 1)); + server = trim(configs[0].substr(0, configs[0].rfind(':'))); + port = trim(configs[0].substr(configs[0].rfind(':') + 1)); if(port == "0") continue; @@ -2113,7 +2121,7 @@ void explodeSSTap(std::string sstap, std::vector &nodes) { json["configs"][i]["obfsparam"] >> obfsparam; json["configs"][i]["protocolparam"] >> protoparam; - ssrConstruct(node, group, remarks, base64Encode(remarks), server, port, protocol, cipher, obfs, pass, obfsparam, protoparam); + ssrConstruct(node, group, remarks, server, port, protocol, cipher, obfs, pass, obfsparam, protoparam); } break; default: @@ -2198,20 +2206,19 @@ int explodeConfContent(const std::string &content, std::vector &nodes) void explode(const std::string &link, Proxy &node) { - // TODO: replace strFind with startsWith if appropriate - if(strFind(link, "ssr://")) + if(startsWith(link, "ssr://")) explodeSSR(link, node); - else if(strFind(link, "vmess://") || strFind(link, "vmess1://")) + else if(startsWith(link, "vmess://") || startsWith(link, "vmess1://")) explodeVmess(link, node); - else if(strFind(link, "ss://")) + else if(startsWith(link, "ss://")) explodeSS(link, node); - else if(strFind(link, "socks://") || strFind(link, "https://t.me/socks") || strFind(link, "tg://socks")) + else if(startsWith(link, "socks://") || startsWith(link, "https://t.me/socks") || startsWith(link, "tg://socks")) explodeSocks(link, node); - else if(strFind(link, "https://t.me/http") || strFind(link, "tg://http")) //telegram style http link + else if(startsWith(link, "https://t.me/http") || startsWith(link, "tg://http")) //telegram style http link explodeHTTP(link, node); - else if(strFind(link, "Netch://")) + else if(startsWith(link, "Netch://")) explodeNetch(link, node); - else if(strFind(link, "trojan://")) + else if(startsWith(link, "trojan://")) explodeTrojan(link, node); else if(isLink(link)) explodeHTTPSub(link, node); @@ -2271,7 +2278,7 @@ void explodeSub(std::string sub, std::vector &nodes) while(getline(strstream, strLink, delimiter)) { Proxy node; - if(strLink.rfind("\r") != strLink.npos) + if(strLink.rfind('\r') != std::string::npos) strLink.erase(strLink.size() - 1); explode(strLink, node); if(strLink.empty() || node.Type == ProxyType::Unknown) diff --git a/src/script/script.cpp b/src/script/script.cpp index 02161fb57..4fb0b341e 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -255,7 +255,7 @@ int duktape_get_res_int(duk_context *ctx) std::string duktape_get_res_str(duk_context *ctx) { if(duk_is_null_or_undefined(ctx, -1)) - return std::string(); + return ""; std::string retstr = duk_safe_to_string(ctx, -1); duk_pop(ctx); return retstr; diff --git a/src/utils/string.h b/src/utils/string.h index 931c11459..cf820bb68 100644 --- a/src/utils/string.h +++ b/src/utils/string.h @@ -50,24 +50,40 @@ int parseCommaKeyValue(const std::string &input, const std::string &separator, s inline bool strFind(const std::string &str, const std::string &target) { - return str.find(target) != str.npos; + return str.find(target) != std::string::npos; } +#if __cpp_lib_starts_ends_with >= 201711L + inline bool startsWith(const std::string &hay, const std::string &needle) { - return hay.substr(0, needle.length()) == needle; + return hay.starts_with(needle); } inline bool endsWith(const std::string &hay, const std::string &needle) { - std::string::size_type hl = hay.length(), nl = needle.length(); - return hl >= nl && hay.substr(hl - nl, nl) == needle; + return hay.ends_with(needle); } +#else + +inline bool startsWith(const std::string &hay, const std::string &needle) +{ + return hay.find(needle) == 0; +} + +inline bool endsWith(const std::string &hay, const std::string &needle) +{ + auto hay_size = hay.size(), needle_size = needle.size(); + return hay_size >= needle_size && hay.rfind(needle) == hay_size - needle_size; +} + +#endif + inline bool count_least(const std::string &hay, const char needle, size_t cnt) { string_size pos = hay.find(needle); - while(pos != hay.npos) + while(pos != std::string::npos) { cnt--; if(!cnt) @@ -82,15 +98,18 @@ inline char getLineBreak(const std::string &str) return count_least(str, '\n', 1) ? '\n' : '\r'; } -template static inline T to_number(const U &value, T def_value = T()) +template +concept Arithmetic = std::is_arithmetic_v; + +template +requires Arithmetic +inline OutType to_number(const InType &value, OutType def_value = 0) { - T retval = 0.0; + OutType retval = 0; char c; std::stringstream ss; ss << value; - if(!(ss >> retval)) - return def_value; - else if(ss >> c) + if(!(ss >> retval) || ss >> c) return def_value; else return retval;