diff --git a/CMakeLists.txt b/CMakeLists.txt index 58838bb..ad26af4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,8 @@ ELSE() ADD_COMPILE_OPTIONS(/W4) ENDIF() -OPTION(USING_STD_REGEX "Use std::regex from C++ library instead of PCRE2." OFF) +#remove std::regex support since it is not compatible with group modifiers and slow +#OPTION(USING_STD_REGEX "Use std::regex from C++ library instead of PCRE2." OFF) OPTION(USING_MALLOC_TRIM "Call malloc_trim after processing request to lower memory usage (Your system must support malloc_trim)." OFF) OPTION(USING_MBEDTLS "Use mbedTLS instead of OpenSSL for MD5 calculation." OFF) @@ -92,14 +93,14 @@ LINK_DIRECTORIES(${YAML_CPP_LIBRARY_DIRS}) INCLUDE_DIRECTORIES(${YAML_CPP_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(subconverter ${YAML_CPP_LIBRARY}) -IF(USING_STD_REGEX STREQUAL "ON") - ADD_DEFINITIONS(-DUSE_STD_REGEX) -ELSE() +#IF(USING_STD_REGEX STREQUAL "ON") +# ADD_DEFINITIONS(-DUSE_STD_REGEX) +#ELSE() FIND_PACKAGE(PCRE2 REQUIRED) INCLUDE_DIRECTORIES(${PCRE2_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(subconverter ${PCRE2_LIBRARY}) ADD_DEFINITIONS(-DPCRE2_STATIC) -ENDIF() +#ENDIF() IF(WIN32) TARGET_LINK_LIBRARIES(subconverter wsock32 ws2_32) diff --git a/src/interfaces.cpp b/src/interfaces.cpp index 9cf2ab5..3572414 100644 --- a/src/interfaces.cpp +++ b/src/interfaces.cpp @@ -2038,7 +2038,8 @@ std::string getRewriteRemote(RESPONSE_CALLBACK_ARGS) std::string parseHostname(inja::Arguments &args) { - std::string data = args.at(0)->get(); + std::string data = args.at(0)->get(), hostname; + const std::string matcher = R"(^(?i:hostname\s*?=\s*?)(.*?)\s$)"; string_array urls = split(data, ","); if(!urls.size()) return std::string(); @@ -2047,7 +2048,12 @@ std::string parseHostname(inja::Arguments &args) for(std::string &x : urls) { input_content = webGet(x, proxy, cache_config); - output_content += regReplace(input_content, "(?:[\\s\\S]*?)^(?i:hostname\\s*?=\\s*?)(.*?)\\s$(?:[\\s\\S]*)", "$1") + ","; + regGetMatch(input_content, matcher, 2, NULL, &hostname); + if(hostname.size()) + { + output_content += hostname + ","; + hostname.clear(); + } } string_array vArray = split(output_content, ","); std::set hostnames; diff --git a/src/misc.cpp b/src/misc.cpp index b874dcd..ce9d680 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -1,5 +1,4 @@ #include -//#include #include #include #include @@ -9,12 +8,14 @@ //#include #include +/* #ifdef USE_STD_REGEX #include #else +*/ #include typedef jpcre2::select jp; -#endif // USE_STD_REGEX +//#endif // USE_STD_REGEX #include @@ -534,7 +535,7 @@ std::string replace_all_distinct(std::string str, const std::string &old_value, } return str; } - +/* #ifdef USE_STD_REGEX bool regValid(const std::string ®) { @@ -611,42 +612,113 @@ bool regMatch(const std::string &src, const std::string &match) } } +int regGetMatch(const std::string &src, const std::string &match, size_t group_count, ...) +{ + try + { + std::regex::flag_type flags = std::regex::extended | std::regex::ECMAScript; + std::string target = match; + if(match.find("(?i)") == 0) + { + target.erase(0, 4); + flags |= std::regex::icase; + } + std::regex reg(target, flags); + std::smatch result; + if(regex_search(src.cbegin(), src.cend(), result, reg)) + { + if(result.size() < group_count - 1) + return -1; + va_list vl; + va_start(vl, group_count); + size_t index = 0; + while(group_count) + { + std::string* arg = va_arg(vl, std::string*); + if(arg != NULL) + *arg = result[index]; + index++; + group_count--; + } + va_end(vl); + } + else + return -2; + return 0; + } + catch (std::regex_error&) + { + return -3; + } +} + #else - -bool regMatch(const std::string &src, const std::string &target) +*/ +bool regMatch(const std::string &src, const std::string &match) { jp::Regex reg; - reg.setPattern(target).addModifier("gm").addPcre2Option(PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_UTF).compile(); + reg.setPattern(match).addModifier("gm").addPcre2Option(PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_UTF).compile(); if(!reg) return false; return reg.match(src); } -bool regFind(const std::string &src, const std::string &target) +bool regFind(const std::string &src, const std::string &match) { jp::Regex reg; - reg.setPattern(target).addModifier("gm").addPcre2Option(PCRE2_UTF).compile(); + reg.setPattern(match).addModifier("gm").addPcre2Option(PCRE2_UTF).compile(); if(!reg) return false; return reg.match(src); } -std::string regReplace(const std::string &src, const std::string &target, const std::string &rep) +std::string regReplace(const std::string &src, const std::string &match, const std::string &rep) { jp::Regex reg; - reg.setPattern(target).addModifier("gm").addPcre2Option(PCRE2_UTF).compile(); + reg.setPattern(match).addModifier("gm").addPcre2Option(PCRE2_UTF).compile(); if(!reg) return src; - return reg.replace(src, rep); + return reg.replace(src, rep, "g"); } -bool regValid(const std::string &target) +bool regValid(const std::string ®) { - jp::Regex reg(target); - return !!reg; + jp::Regex r(reg); + return !!r; } -#endif // USE_STD_REGEX +int regGetMatch(const std::string &src, const std::string &match, size_t group_count, ...) +{ + jp::Regex reg; + reg.setPattern(match).addModifier("gm").addPcre2Option(PCRE2_UTF).compile(); + jp::VecNum vec_num; + jp::RegexMatch rm; + size_t count = rm.setRegexObject(®).setSubject(src).setNumberedSubstringVector(&vec_num).match(); + if(!count || count < group_count - 1) + return -1; + va_list vl; + va_start(vl, group_count); + size_t index = 0, match_index = 0; + while(group_count) + { + std::string* arg = va_arg(vl, std::string*); + if(arg != NULL) + *arg = vec_num[match_index][index]; + index++; + group_count--; + if(vec_num[match_index].size() <= index) + { + match_index++; + index = 0; + } + if(vec_num.size() <= match_index) + break; + } + va_end(vl); + return 0; +} + +//#endif // USE_STD_REGEX std::string regTrim(const std::string &src) { diff --git a/src/misc.h b/src/misc.h index c16d4f3..f2959e8 100644 --- a/src/misc.h +++ b/src/misc.h @@ -126,10 +126,11 @@ bool is_str_utf8(const std::string &data); std::string getFormData(const std::string &raw_data); void sleep(int interval); -bool regValid(const std::string &target); +bool regValid(const std::string ®); bool regFind(const std::string &src, const std::string &match); std::string regReplace(const std::string &src, const std::string &match, const std::string &rep); bool regMatch(const std::string &src, const std::string &match); +int regGetMatch(const std::string &src, const std::string &match, size_t group_count, ...); std::string regTrim(const std::string &src); std::string speedCalc(double speed); std::string getMD5(const std::string &data); diff --git a/src/speedtestutil.cpp b/src/speedtestutil.cpp index e626457..e7804cf 100644 --- a/src/speedtestutil.cpp +++ b/src/speedtestutil.cpp @@ -43,7 +43,6 @@ template T safe_as (const YAML::Node& node) void explodeVmess(std::string vmess, const std::string &custom_port, nodeInfo &node) { std::string version, ps, add, port, type, id, aid, net, path, host, tls; - tribool udp, tfo, scv; Document jsondata; std::vector vArray; if(regMatch(vmess, "vmess://(.*?)\\?(.*)")) //shadowrocket style link @@ -105,7 +104,7 @@ void explodeVmess(std::string vmess, const std::string &custom_port, nodeInfo &n node.remarks = ps; node.server = add; node.port = to_int(port, 0); - node.proxyStr = vmessConstruct(add, port, type, id, aid, net, "auto", path, host, "", tls, udp, tfo, scv); + node.proxyStr = vmessConstruct(add, port, type, id, aid, net, "auto", path, host, "", tls); } void explodeVmessConf(std::string content, const std::string &custom_port, bool libev, std::vector &nodes) @@ -260,8 +259,8 @@ void explodeVmessConf(std::string content, const std::string &custom_port, bool void explodeSS(std::string ss, bool libev, const std::string &custom_port, nodeInfo &node) { - std::string ps, password, method, server, port, plugins, plugin, pluginopts, addition, group = SS_DEFAULT_GROUP; - std::vector args, secret; + std::string ps, password, method, server, port, plugins, plugin, pluginopts, addition, group = SS_DEFAULT_GROUP, secret; + //std::vector args, secret; ss = replace_all_distinct(ss.substr(5), "/?", "?"); if(strFind(ss, "#")) { @@ -281,6 +280,7 @@ void explodeSS(std::string ss, bool libev, const std::string &custom_port, nodeI } if(strFind(ss, "@")) { + /* ss = regReplace(ss, "(.*?)@(.*):(.*)", "$1|$2|$3"); args = split(ss, "|"); secret = split(urlsafe_base64_decode(args[0]), ":"); @@ -290,9 +290,15 @@ void explodeSS(std::string ss, bool libev, const std::string &custom_port, nodeI password = secret[1]; server = args[1]; port = custom_port.empty() ? args[2] : custom_port; + */ + if(regGetMatch(ss, "(.*?)@(.*):(.*)", 4, NULL, &secret, &server, &port)) + return; + if(regGetMatch(urlsafe_base64_decode(secret), "(.*?):(.*)", 3, NULL, &method, &password)) + return; } else { + /* if(!regMatch(urlsafe_base64_decode(ss), "(.*?):(.*?)@(.*):(.*)")) return; ss = regReplace(urlsafe_base64_decode(ss), "(.*?):(.*?)@(.*):(.*)", "$1|$2|$3|$4"); @@ -303,7 +309,12 @@ void explodeSS(std::string ss, bool libev, const std::string &custom_port, nodeI password = args[1]; server = args[2]; port = custom_port.empty() ? args[3] : custom_port; + */ + if(regGetMatch(urlsafe_base64_decode(ss), "(.*?):(.*)@(.*):(.*)", 5, NULL, &method, &password, &server, &port)) + return; } + if(custom_port.size()) + port = custom_port; if(ps.empty()) ps = server + ":" + port; @@ -501,6 +512,7 @@ void explodeSSR(std::string ssr, bool ss_libev, bool ssr_libev, const std::strin protoparam = regReplace(urlsafe_base64_decode(getUrlArg(strobfs, "protoparam")), "\\s", ""); } + /* ssr = regReplace(ssr, "(.*):(.*?):(.*?):(.*?):(.*?):(.*)", "$1|$2|$3|$4|$5|$6"); strcfg = split(ssr, "|"); @@ -513,6 +525,12 @@ void explodeSSR(std::string ssr, bool ss_libev, bool ssr_libev, const std::strin method = strcfg[3]; obfs = strcfg[4]; password = urlsafe_base64_decode(strcfg[5]); + */ + if(regGetMatch(ssr, "(.*):(.*?):(.*?):(.*?):(.*?):(.*)", 7, NULL, &server, &port, &protocol, &method, &obfs, &password)) + return; + password = urlsafe_base64_decode(password); + if(custom_port.size()) + port = custom_port; if(group.empty()) group = SSR_DEFAULT_GROUP; @@ -700,6 +718,7 @@ void explodeHTTPSub(std::string link, const std::string &custom_port, nodeInfo & link = urlsafe_base64_decode(link); if(strFind(link, "@")) { + /* link = regReplace(link, "(.*?):(.*?)@(.*):(.*)", "$1|$2|$3|$4"); configs = split(link, "|"); if(configs.size() != 4) @@ -708,15 +727,22 @@ void explodeHTTPSub(std::string link, const std::string &custom_port, nodeInfo & password = configs[1]; server = configs[2]; port = configs[3]; + */ + if(regGetMatch(link, "(.*?):(.*?)@(.*):(.*)", 5, NULL, &username, &password, &server, &port)) + return; } else { + /* link = regReplace(link, "(.*):(.*)", "$1|$2"); configs = split(link, "|"); if(configs.size() != 2) return; server = configs[1]; port = configs[2]; + */ + if(regGetMatch(link, "(.*):(.*)", 3, NULL, &server, &port)) + return; } if(group.empty()) @@ -753,6 +779,7 @@ void explodeTrojan(std::string trojan, const std::string &custom_port, nodeInfo trojan.erase(pos); } + /* trojan = regReplace(trojan, "(.*?)@(.*):(.*)", "$1|$2|$3"); vArray = split(trojan, "|"); if(vArray.size() != 3) @@ -761,6 +788,11 @@ void explodeTrojan(std::string trojan, const std::string &custom_port, nodeInfo psk = vArray[0]; server = vArray[1]; port = custom_port.empty() ? vArray[2] : custom_port; + */ + if(regGetMatch(trojan, "(.*?)@(.*):(.*)", 4, NULL, &psk, &server, &port)) + return; + if(custom_port.size()) + port = custom_port; host = getUrlArg(addition, "peer"); @@ -1148,6 +1180,7 @@ void explodeShadowrocket(std::string rocket, const std::string &custom_port, nod addition = rocket.substr(rocket.find("?") + 1); rocket = rocket.substr(0, rocket.find("?")); + /* userinfo = split(regReplace(urlsafe_base64_decode(rocket), "(.*?):(.*?)@(.*):(.*)", "$1,$2,$3,$4"), ","); if(userinfo.size() != 4) // broken link return; @@ -1155,6 +1188,11 @@ void explodeShadowrocket(std::string rocket, const std::string &custom_port, nod id = userinfo[1]; add = userinfo[2]; port = custom_port.size() ? custom_port : userinfo[3]; + */ + if(regGetMatch(urlsafe_base64_decode(rocket), "(.*?):(.*)@(.*):(.*)", 5, NULL, &cipher, &id, &add, &port)) + return; + if(custom_port.size()) + port = custom_port; remarks = UrlDecode(getUrlArg(addition, "remark")); obfs = getUrlArg(addition, "obfs"); if(obfs.size()) @@ -1208,20 +1246,21 @@ void explodeKitsunebi(std::string kit, const std::string &custom_port, nodeInfo addition = kit.substr(pos + 1); kit = kit.substr(0, pos); + /* userinfo = split(regReplace(kit, "(.*?)@(.*):(.*)", "$1,$2,$3"), ","); if(userinfo.size() != 3) return; id = userinfo[0]; add = userinfo[1]; pos = userinfo[2].find("/"); - if(pos != userinfo[2].npos) + */ + if(regGetMatch(kit, "(.*?)@(.*):(.*)", 4, NULL, &id, &add, &port)) + return; + pos = port.find("/"); + if(pos != port.npos) { - port = userinfo[2].substr(0, pos); - path = userinfo[2].substr(pos); - } - else - { - port = userinfo[2]; + path = port.substr(pos); + port.erase(pos); } if(custom_port.size()) port = custom_port; @@ -1275,16 +1314,24 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector std::string plugin, pluginopts, pluginopts_mode, pluginopts_host = "cloudfront.net", mod_url, mod_md5; //ss std::string id, net, tls, host, edge, path; //v2 std::string protocol, protoparam; //ssr - std::string itemName, itemVal; + std::string itemName, itemVal, config; std::vector configs, vArray, headers, header; tribool udp, tfo, scv; + /* remarks = regReplace(x.second, proxystr, "$1"); configs = split(regReplace(x.second, proxystr, "$2"), ","); - if(configs.size() < 2 || configs[0] == "direct") + */ + regGetMatch(x.second, proxystr, 3, NULL, &remarks, &config); + configs = split(config, ","); + if(configs.size() < 2) continue; switch(hash_(configs[0])) { + case "direct"_hash: + case "reject"_hash: + case "reject-tinygif"_hash: + continue; case "custom"_hash: //surge 2 style custom proxy //remove module detection to speed up parsing and compatible with broken module /* @@ -2132,11 +2179,11 @@ time_t dateStringToTimestamp(std::string date) bool getSubInfoFromHeader(std::string &header, std::string &result) { - std::string pattern = R"((?:[\s\S]*?)^(?i:Subscription-UserInfo): (.*?)\s$(?:[\s\S]*))", retStr; + std::string pattern = R"(^(?i:Subscription-UserInfo): (.*?)\s*?$)", retStr; if(regFind(header, pattern)) { - retStr = regReplace(header, pattern, "$1"); - if(retStr != header) + regGetMatch(header, pattern, 2, NULL, &retStr); + if(retStr.size()) { result = retStr; return true; diff --git a/src/subexport.cpp b/src/subexport.cpp index b690123..7a05388 100644 --- a/src/subexport.cpp +++ b/src/subexport.cpp @@ -405,6 +405,7 @@ bool matchRange(std::string &range, int target) { string_array vArray = split(range, ","); bool match = false; + std::string range_begin_str, range_end_str; int range_begin = 0, range_end = 0; const std::string reg_num = "-?\\d+", reg_range = "(\\d+)-(\\d+)", reg_not = "\\!(\\d+)", reg_not_range = "\\!(\\d+)-(\\d+)", reg_less = "(\\d+)-", reg_more = "(\\d+)\\+"; for(std::string &x : vArray) @@ -416,8 +417,13 @@ bool matchRange(std::string &range, int target) } else if(regMatch(x, reg_range)) { + /* range_begin = to_int(regReplace(x, reg_range, "$1"), INT_MAX); range_end = to_int(regReplace(x, reg_range, "$2"), INT_MIN); + */ + regGetMatch(x, reg_range, 3, NULL, &range_begin_str, &range_end_str); + range_begin = to_int(range_begin_str, INT_MAX); + range_end = to_int(range_end_str, INT_MIN); if(target >= range_begin && target <= range_end) match = true; } @@ -428,8 +434,13 @@ bool matchRange(std::string &range, int target) } else if(regMatch(x, reg_not_range)) { + /* range_begin = to_int(regReplace(x, reg_range, "$1"), INT_MAX); range_end = to_int(regReplace(x, reg_range, "$2"), INT_MIN); + */ + regGetMatch(x, reg_range, 3, NULL, &range_begin_str, &range_end_str); + range_begin = to_int(range_begin_str, INT_MAX); + range_end = to_int(range_end_str, INT_MIN); if(target >= range_begin && target <= range_end) match = false; }