Fix VMess HTTP nodes missing in exported Clash configurations

Add support for parsing VMess HTTP nodes in Clash configurations.
Clean up codes.
This commit is contained in:
Tindy X committed 2020-07-04 14:14:55 +08:00
1 parent ff9820b0a3
commit 8d10020f89
6 files changed
+119 -224

No files matched your search

+42 -120
View File
@@ -104,9 +104,9 @@ void explodeVmessConf(std::string content, const std::string &custom_port, bool
std::map<std::string, std::string> subdata;
std::map<std::string, std::string>::iterator iter;
std::string streamset = "streamSettings", tcpset = "tcpSettings", wsset = "wsSettings";
regGetMatch(content, "((?i)streamsettings)", 2, NULL, &streamset);
regGetMatch(content, "((?i)tcpsettings)", 2, NULL, &tcpset);
regGetMatch(content, "((?1)wssettings)", 2, NULL, &wsset);
regGetMatch(content, "((?i)streamsettings)", 2, 0, &streamset);
regGetMatch(content, "((?i)tcpsettings)", 2, 0, &tcpset);
regGetMatch(content, "((?1)wssettings)", 2, 0, &wsset);
json.Parse(content.data());
if(json.HasParseError())
@@ -276,37 +276,14 @@ 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]), ":");
if(args.size() < 3 || secret.size() < 2)
if(regGetMatch(ss, "(.*?)@(.*):(.*)", 4, 0, &secret, &server, &port))
return;
method = secret[0];
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))
if(regGetMatch(urlsafe_base64_decode(secret), "(.*?):(.*)", 3, 0, &method, &password))
return;
}
else
{
/*
if(!regMatch(urlsafe_base64_decode(ss), "(.*?):(.*?)@(.*):(.*)"))
return;
ss = regReplace(urlsafe_base64_decode(ss), "(.*?):(.*?)@(.*):(.*)", "$1|$2|$3|$4");
args = split(ss, "|");
if(args.size() < 4)
return;
method = args[0];
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))
if(regGetMatch(urlsafe_base64_decode(ss), "(.*?):(.*)@(.*):(.*)", 5, 0, &method, &password, &server, &port))
return;
}
if(custom_port.size())
@@ -496,7 +473,6 @@ void explodeSSConf(std::string content, const std::string &custom_port, bool lib
void explodeSSR(std::string ssr, bool ss_libev, bool ssr_libev, const std::string &custom_port, nodeInfo &node)
{
std::string strobfs;
std::vector<std::string> strcfg;
std::string remarks, group, server, port, method, password, protocol, protoparam, obfs, obfsparam, remarks_base64;
ssr = replace_all_distinct(ssr.substr(6), "\r", "");
ssr = urlsafe_base64_decode(ssr);
@@ -511,21 +487,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, "|");
if(strcfg.size() != 6)
return;
server = strcfg[0];
port = custom_port.empty() ? strcfg[1] : custom_port;
protocol = strcfg[2];
method = strcfg[3];
obfs = strcfg[4];
password = urlsafe_base64_decode(strcfg[5]);
*/
if(regGetMatch(ssr, "(.*):(.*?):(.*?):(.*?):(.*?):(.*)", 7, NULL, &server, &port, &protocol, &method, &obfs, &password))
if(regGetMatch(ssr, "(.*):(.*?):(.*?):(.*?):(.*?):(.*)", 7, 0, &server, &port, &protocol, &method, &obfs, &password))
return;
password = urlsafe_base64_decode(password);
if(custom_port.size())
@@ -677,7 +639,7 @@ void explodeSocks(std::string link, const std::string &custom_port, nodeInfo &no
node.proxyStr = socksConstruct(group, remarks, server, port, username, password);
}
void explodeHTTP(std::string link, const std::string &custom_port, nodeInfo &node)
void explodeHTTP(const std::string link, const std::string &custom_port, nodeInfo &node)
{
std::string group, remarks, server, port, username, password;
server = getUrlArg(link, "server");
@@ -708,7 +670,6 @@ void explodeHTTPSub(std::string link, const std::string &custom_port, nodeInfo &
{
std::string group, remarks, server, port, username, password;
std::string addition;
string_array configs;
bool tls = strFind(link, "https://");
string_size pos = link.find("?");
if(pos != link.npos)
@@ -722,30 +683,12 @@ 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)
return;
username = configs[0];
password = configs[1];
server = configs[2];
port = configs[3];
*/
if(regGetMatch(link, "(.*?):(.*?)@(.*):(.*)", 5, NULL, &username, &password, &server, &port))
if(regGetMatch(link, "(.*?):(.*?)@(.*):(.*)", 5, 0, &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))
if(regGetMatch(link, "(.*):(.*)", 3, 0, &server, &port))
return;
}
@@ -770,7 +713,6 @@ void explodeTrojan(std::string trojan, const std::string &custom_port, nodeInfo
{
std::string server, port, psk, addition, remark, host;
tribool tfo, scv;
string_array vArray;
trojan.erase(0, 9);
string_size pos = trojan.rfind("#");
@@ -786,17 +728,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)
return;
psk = vArray[0];
server = vArray[1];
port = custom_port.empty() ? vArray[2] : custom_port;
*/
if(regGetMatch(trojan, "(.*?)@(.*):(.*)", 4, NULL, &psk, &server, &port))
if(regGetMatch(trojan, "(.*?)@(.*):(.*)", 4, 0, &psk, &server, &port))
return;
if(custom_port.size())
port = custom_port;
@@ -820,10 +752,10 @@ void explodeTrojan(std::string trojan, const std::string &custom_port, nodeInfo
node.proxyStr = trojanConstruct(node.group, remark, server, port, psk, host, true, tribool(), tfo, scv);
}
void explodeQuan(std::string quan, const std::string &custom_port, nodeInfo &node)
void explodeQuan(const std::string &quan, const std::string &custom_port, nodeInfo &node)
{
std::string strTemp, itemName, itemVal;
std::string group = V2RAY_DEFAULT_GROUP, ps, add, port, cipher = "auto", type = "none", id, aid = "0", net = "tcp", path, host, edge, tls;
std::string group = V2RAY_DEFAULT_GROUP, ps, add, port, cipher, type = "none", id, aid = "0", net = "tcp", path, host, edge, tls;
string_array configs, vArray, headers;
strTemp = regReplace(quan, "(.*?) = (.*)", "$1,$2");
configs = split(strTemp, ",");
@@ -980,7 +912,7 @@ void explodeNetch(std::string netch, bool ss_libev, bool ssr_libev, const std::s
if(group.empty())
group = TROJAN_DEFAULT_GROUP;
node.group = group;
node.proxyStr = trojanConstruct(group, remark, address, port, username, password, tls == "true", udp, tfo, scv);
node.proxyStr = trojanConstruct(group, remark, address, port, password, host, tls == "true", udp, tfo, scv);
break;
case "Snell"_hash:
obfs = GetMember(json, "OBFS");
@@ -1032,13 +964,22 @@ void explodeClash(Node yamlnode, const std::string &custom_port, std::vector<nod
singleproxy["alterId"] >>= aid;
singleproxy["cipher"] >>= cipher;
net = singleproxy["network"].IsDefined() ? safe_as<std::string>(singleproxy["network"]) : "tcp";
path = singleproxy["ws-path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-path"]) : "/";
if(net == "http")
{
singleproxy["http-opts"]["path"][0] >>= path;
singleproxy["http-opts"]["headers"]["Host"][0] >>= host;
edge.clear();
}
else
{
path = singleproxy["ws-path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-path"]) : "/";
singleproxy["ws-headers"]["Host"] >>= host;
singleproxy["ws-headers"]["Edge"] >>= edge;
}
tls = safe_as<std::string>(singleproxy["tls"]) == "true" ? "tls" : "";
singleproxy["ws-headers"]["Host"] >>= host;
singleproxy["ws-headers"]["Edge"] >>= edge;
node.linkType = SPEEDTEST_MESSAGE_FOUNDVMESS;
node.proxyStr = vmessConstruct(group, ps, server, port, type, id, aid, net, cipher, path, host, edge, tls, udp, tfo, scv);
node.proxyStr = vmessConstruct(group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls, udp, tfo, scv);
break;
case "ss"_hash:
group = SS_DEFAULT_GROUP;
@@ -1179,22 +1120,12 @@ void explodeShadowrocket(std::string rocket, const std::string &custom_port, nod
std::string add, port, type, id, aid, net = "tcp", path, host, tls, cipher, remarks;
std::string obfs; //for other style of link
std::string addition;
string_array userinfo;
rocket = rocket.substr(8);
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;
cipher = userinfo[0];
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))
if(regGetMatch(urlsafe_base64_decode(rocket), "(.*?):(.*)@(.*):(.*)", 5, 0, &cipher, &id, &add, &port))
return;
if(custom_port.size())
port = custom_port;
@@ -1239,7 +1170,6 @@ void explodeKitsunebi(std::string kit, const std::string &custom_port, nodeInfo
std::string add, port, type, id, aid = "0", net = "tcp", path, host, tls, cipher = "auto", remarks;
std::string addition;
string_size pos;
string_array userinfo;
kit = kit.substr(9);
pos = kit.find("#");
@@ -1253,15 +1183,7 @@ 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(regGetMatch(kit, "(.*?)@(.*):(.*)", 4, NULL, &id, &add, &port))
if(regGetMatch(kit, "(.*?)@(.*):(.*)", 4, 0, &id, &add, &port))
return;
pos = port.find("/");
if(pos != port.npos)
@@ -1331,7 +1253,7 @@ bool explodeSurge(std::string surge, const std::string &custom_port, std::vector
remarks = regReplace(x.second, proxystr, "$1");
configs = split(regReplace(x.second, proxystr, "$2"), ",");
*/
regGetMatch(x.second, proxystr, 3, NULL, &remarks, &config);
regGetMatch(x.second, proxystr, 3, 0, &remarks, &config);
configs = split(config, ",");
if(configs.size() < 3)
continue;
@@ -1880,14 +1802,14 @@ bool chkIgnore(const nodeInfo &node, string_array &exclude_remarks, string_array
//std::string remarks = UTF8ToACP(node.remarks);
std::string remarks = node.remarks;
//writeLog(LOG_TYPE_INFO, "Comparing exclude remarks...");
excluded = std::any_of(exclude_remarks.cbegin(), exclude_remarks.cend(), [&remarks](auto &x)
excluded = std::any_of(exclude_remarks.cbegin(), exclude_remarks.cend(), [&remarks](const auto &x)
{
return regFind(remarks, x);
});
if(include_remarks.size() != 0)
{
//writeLog(LOG_TYPE_INFO, "Comparing include remarks...");
included = std::any_of(include_remarks.cbegin(), include_remarks.cend(), [&remarks](auto &x)
included = std::any_of(include_remarks.cbegin(), include_remarks.cend(), [&remarks](const auto &x)
{
return regFind(remarks, x);
});
@@ -1912,7 +1834,7 @@ int explodeConf(std::string filepath, const std::string &custom_port, bool sslib
return explodeConfContent(contentstrm.str(), custom_port, sslibev, ssrlibev, nodes);
}
int explodeConfContent(std::string content, const std::string &custom_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes)
int explodeConfContent(const std::string &content, const std::string &custom_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes)
{
int filetype = -1;
@@ -2071,7 +1993,7 @@ void filterNodes(std::vector<nodeInfo> &nodes, string_array &exclude_remarks, st
}
*/
bool excluded = false, included = false;
bool excluded, included;
std::vector<std::unique_ptr<pcre2_code, decltype(&pcre2_code_free)>> exclude_patterns, include_patterns;
std::vector<std::unique_ptr<pcre2_match_data, decltype(&pcre2_match_data_free)>> exclude_match_data, include_match_data;
unsigned int i = 0;
@@ -2208,12 +2130,12 @@ time_t dateStringToTimestamp(std::string date)
}
}
bool getSubInfoFromHeader(std::string &header, std::string &result)
bool getSubInfoFromHeader(const std::string &header, std::string &result)
{
std::string pattern = R"(^(?i:Subscription-UserInfo): (.*?)\s*?$)", retStr;
if(regFind(header, pattern))
{
regGetMatch(header, pattern, 2, NULL, &retStr);
regGetMatch(header, pattern, 2, 0, &retStr);
if(retStr.size())
{
result = retStr;
@@ -2223,17 +2145,17 @@ bool getSubInfoFromHeader(std::string &header, std::string &result)
return false;
}
bool getSubInfoFromNodes(std::vector<nodeInfo> &nodes, string_array &stream_rules, string_array &time_rules, std::string &result)
bool getSubInfoFromNodes(const std::vector<nodeInfo> &nodes, const string_array &stream_rules, const string_array &time_rules, std::string &result)
{
std::string remarks, pattern, target, stream_info, time_info, retStr;
string_size spos;
for(nodeInfo &x : nodes)
for(const nodeInfo &x : nodes)
{
remarks = x.remarks;
if(!stream_info.size())
{
for(std::string &y : stream_rules)
for(const std::string &y : stream_rules)
{
spos = y.rfind("|");
if(spos == y.npos)
@@ -2257,7 +2179,7 @@ bool getSubInfoFromNodes(std::vector<nodeInfo> &nodes, string_array &stream_rule
remarks = x.remarks;
if(!time_info.size())
{
for(std::string &y : time_rules)
for(const std::string &y : time_rules)
{
spos = y.rfind("|");
if(spos == y.npos)
@@ -2286,7 +2208,7 @@ bool getSubInfoFromNodes(std::vector<nodeInfo> &nodes, string_array &stream_rule
return false;
//calculate how much stream left
unsigned long long total = 0, left = 0, used = 0, expire = 0;
unsigned long long total = 0, left, used = 0, expire = 0;
std::string total_str = getUrlArg(stream_info, "total"), left_str = getUrlArg(stream_info, "left"), used_str = getUrlArg(stream_info, "used");
if(strFind(total_str, "%"))
{
@@ -2326,7 +2248,7 @@ bool getSubInfoFromNodes(std::vector<nodeInfo> &nodes, string_array &stream_rule
return true;
}
bool getSubInfoFromSSD(std::string &sub, std::string &result)
bool getSubInfoFromSSD(const std::string &sub, std::string &result)
{
rapidjson::Document json;
json.Parse(urlsafe_base64_decode(sub.substr(6)).data());