Add support for exporting complete Quantumult configuration file

Fix incorrect generation of Quantumult X configuratios.
Fix broken group name option.
Add external configuration support for customize Quantumult(X) base.
Update Travis CI build script.
Tweak Emoji match rules.
Clean up codes.
This commit is contained in:
Tindy X committed 2020-01-31 19:30:04 +08:00
1 parent c5fa786500
commit b085c0d0c1
8 files changed
+226 -51

No files matched your search

+146 -18
View File
@@ -363,6 +363,9 @@ void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_
case -1:
base_rule.SetCurrentSection("filter_local"); //Quantumult X
break;
case -2:
base_rule.SetCurrentSection("TCP"); //Quantumult
break;
default:
base_rule.SetCurrentSection("Rule");
}
@@ -382,7 +385,7 @@ void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_
if(strLine == "MATCH")
strLine = "FINAL";
strLine += "," + rule_group;
if(surge_ver == -1)
if(surge_ver == -1 || surge_ver == -2)
{
if(std::count(strLine.begin(), strLine.end(), ',') > 2 && regReplace(strLine, rule_match_regex, "$2") == ",no-resolve")
strLine = regReplace(strLine, rule_match_regex, "$1$3$2");
@@ -416,13 +419,13 @@ void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_
strStrm<<retrived_rules;
while(getline(strStrm, strLine, delimiter))
{
if(surge_ver == -1 && (strLine.find("IP-CIDR6") == 0 || strLine.find("URL-REGEX") == 0 || strLine.find("PROCESS-NAME") == 0 || strLine.find("AND") == 0 || strLine.find("OR") == 0)) //remove unsupported types
if((surge_ver == -1 || surge_ver == -2) && (strLine.find("IP-CIDR6") == 0 || strLine.find("URL-REGEX") == 0 || strLine.find("PROCESS-NAME") == 0 || strLine.find("AND") == 0 || strLine.find("OR") == 0)) //remove unsupported types
continue;
strLine = replace_all_distinct(strLine, "\r", ""); //remove line break
if(!strLine.size() || strLine.find("#") == 0 || strLine.find(";") == 0) //remove comments
continue;
strLine += "," + rule_group;
if(surge_ver == -1)
if(surge_ver == -1 || surge_ver == -2)
{
if(std::count(strLine.begin(), strLine.end(), ',') > 2 && regReplace(strLine, rule_match_regex, "$2") == ",no-resolve")
strLine = regReplace(strLine, rule_match_regex, "$1$3$2");
@@ -1246,7 +1249,29 @@ std::string netchToVMess(std::vector<nodeInfo> &nodes, extra_settings &ext)
return base64_encode(allLinks);
}
std::string netchToQuan(std::vector<nodeInfo> &nodes, extra_settings &ext)
std::string netchToQuan(std::vector<nodeInfo> &nodes, std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext)
{
INIReader ini;
ini.store_any_line = true;
if(!ext.nodelist && ini.Parse(base_conf) != 0)
return std::string();
netchToQuan(nodes, ini, ruleset_content_array, extra_proxy_group, ext);
if(ext.nodelist)
{
string_array allnodes;
ini.GetAll("SERVER", "{NONAME}", allnodes);
std::string allLinks = std::accumulate(allnodes.begin(), allnodes.end(), allnodes[0], [](std::string a, std::string b)
{
return std::move(a) + "\n" + std::move(b);
});
return base64_encode(allLinks);
}
return ini.ToString();
}
void netchToQuan(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext)
{
rapidjson::Document json;
std::string type;
@@ -1256,6 +1281,7 @@ std::string netchToQuan(std::vector<nodeInfo> &nodes, extra_settings &ext)
std::string id, aid, transproto, faketype, host, path, quicsecure, quicsecret;
std::string proxyStr, allLinks;
bool tlssecure;
std::vector<nodeInfo> nodelist;
std::for_each(nodes.begin(), nodes.end(), [ext](nodeInfo &x)
{
@@ -1275,6 +1301,8 @@ std::string netchToQuan(std::vector<nodeInfo> &nodes, extra_settings &ext)
});
}
ini.SetCurrentSection("SERVER");
ini.EraseSection();
for(nodeInfo &x : nodes)
{
json.Parse(x.proxyStr.data());
@@ -1309,7 +1337,9 @@ std::string netchToQuan(std::vector<nodeInfo> &nodes, extra_settings &ext)
proxyStr += ", certificate=0";
if(transproto == "ws")
proxyStr += ", obfs=ws, obfs-path=\"" + path + "\", obfs-header=\"Host: " + host + "\"";
proxyStr = "vmess://" + urlsafe_base64_encode(proxyStr);
if(ext.nodelist)
proxyStr = "vmess://" + urlsafe_base64_encode(proxyStr);
break;
case SPEEDTEST_MESSAGE_FOUNDSSR:
protocol = GetMember(json, "Protocol");
@@ -1317,27 +1347,121 @@ std::string netchToQuan(std::vector<nodeInfo> &nodes, extra_settings &ext)
obfs = GetMember(json, "OBFS");
obfsparam = GetMember(json, "OBFSParam");
proxyStr = "ssr://" + urlsafe_base64_encode(hostname + ":" + port + ":" + protocol + ":" + method + ":" + obfs + ":" + urlsafe_base64_encode(password) \
+ "/?group=" + urlsafe_base64_encode(x.group) + "&remarks=" + urlsafe_base64_encode(remark) \
+ "&obfsparam=" + urlsafe_base64_encode(obfsparam) + "&protoparam=" + urlsafe_base64_encode(protoparam));
if(ext.nodelist)
{
proxyStr = "ssr://" + urlsafe_base64_encode(hostname + ":" + port + ":" + protocol + ":" + method + ":" + obfs + ":" + urlsafe_base64_encode(password) \
+ "/?group=" + urlsafe_base64_encode(x.group) + "&remarks=" + urlsafe_base64_encode(remark) \
+ "&obfsparam=" + urlsafe_base64_encode(obfsparam) + "&protoparam=" + urlsafe_base64_encode(protoparam));
}
else
{
proxyStr = remark + " = shadowsocksr, " + hostname + ", " + port + ", " + method + ", \"" + password + "\", group=" + x.group + ", protocol=" + protocol + ", obfs=" + obfs;
if(protoparam.size())
proxyStr += ", protocol_param=" + protoparam;
if(obfsparam.size())
proxyStr += ", obfs_param=" + obfsparam;
}
break;
case SPEEDTEST_MESSAGE_FOUNDSS:
plugin = GetMember(json, "Plugin");
pluginopts = GetMember(json, "PluginOption");
proxyStr = "ss://" + urlsafe_base64_encode(method + ":" + password) + "@" + hostname + ":" + port;
if(plugin.size() & pluginopts.size())
if(ext.nodelist)
{
proxyStr += "/?plugin=" + UrlEncode(plugin + ";" +pluginopts);
proxyStr = "ss://" + urlsafe_base64_encode(method + ":" + password) + "@" + hostname + ":" + port;
if(plugin.size() && pluginopts.size())
{
proxyStr += "/?plugin=" + UrlEncode(plugin + ";" + pluginopts);
}
proxyStr += "&group=" + urlsafe_base64_encode(x.group) + "#" + UrlEncode(remark);
}
else
{
proxyStr = remark + " = shadowsocks, " + hostname + ", " + port + ", " + method + ", \"" + password + "\", group=" + x.group;
if(plugin == "simple-obfs" && pluginopts.size())
{
proxyStr += ", " + replace_all_distinct(pluginopts, ";", ", ");
}
}
proxyStr += "&group=" + urlsafe_base64_encode(x.group) + "#" + UrlEncode(remark);
break;
default:
continue;
}
allLinks += proxyStr + "\n";
ini.Set("{NONAME}", proxyStr);
nodelist.emplace_back(x);
}
return base64_encode(allLinks);
if(ext.nodelist)
return;
string_array filtered_nodelist;
ini.SetCurrentSection("POLICY");
ini.EraseSection();
std::string singlegroup;
std::string name, proxies;
string_array vArray;
for(std::string &x : extra_proxy_group)
{
eraseElements(filtered_nodelist);
unsigned int rules_upper_bound = 0;
vArray = split(x, "`");
if(vArray.size() < 3)
continue;
if(vArray[1] == "select")
{
type = "static";
rules_upper_bound = vArray.size();
}
else if(vArray[1] == "url-test")
{
if(vArray.size() < 5)
continue;
type = "auto";
rules_upper_bound = vArray.size() - 2;
}
else if(vArray[1] == "fallback")
{
if(vArray.size() < 5)
continue;
type = "static";
rules_upper_bound = vArray.size() - 2;
}
else if(vArray[1] == "load-balance")
{
if(vArray.size() < 5)
continue;
type = "balance, round-robin";
rules_upper_bound = vArray.size() - 2;
}
else
continue;
name = vArray[0];
for(unsigned int i = 2; i < rules_upper_bound; i++)
groupGenerate(vArray[i], nodelist, filtered_nodelist, true);
if(!filtered_nodelist.size())
filtered_nodelist.emplace_back("direct");
proxies = std::accumulate(std::next(filtered_nodelist.begin()), filtered_nodelist.end(), filtered_nodelist[0], [](std::string a, std::string b)
{
return std::move(a) + "\n" + std::move(b);
});
singlegroup = name + " : " + type;
if(type == "static")
singlegroup += ", " + filtered_nodelist[0];
singlegroup += "\n" + proxies + "\n";
ini.Set("{NONAME}", base64_encode(singlegroup));
}
if(ext.enable_rule_generator)
rulesetToSurge(ini, ruleset_content_array, -2, ext.overwrite_original_rules);
}
std::string netchToQuanX(std::vector<nodeInfo> &nodes, std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, string_array &extra_proxy_group, extra_settings &ext)
@@ -1349,7 +1473,7 @@ std::string netchToQuanX(std::vector<nodeInfo> &nodes, std::string &base_conf, s
netchToQuanX(nodes, ini, ruleset_content_array, extra_proxy_group, ext);
if(!ext.nodelist)
if(ext.nodelist)
{
string_array allnodes;
ini.GetAll("server_local", "{NONAME}", allnodes);
@@ -1419,11 +1543,15 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
method = "chacha20-ietf-poly1305";
proxyStr = "vmess = " + hostname + ":" + port + ", method=" + method + ", password=" + id;
if(transproto == "ws")
proxyStr += ", obfs=ws, obfs-host=" + host + ", obfs-uri=" + path;
{
if(tlssecure)
proxyStr += ", obfs=wss";
else
proxyStr += ", obfs=ws";
proxyStr += ", obfs-host=" + host + ", obfs-uri=" + path;
}
else if(tlssecure)
proxyStr += ", obfs=over-tls, obfs-host=" + host;
if(ext.skip_cert_verify)
proxyStr += ", certificate=0";
break;
case SPEEDTEST_MESSAGE_FOUNDSS:
password = GetMember(json, "Password");