Enhancements

Fix support for parsing some Surge configurations.
Fix adding extra blank line to section end when exporting some configurations.
Fix adding real internal link as MANAGED-CONFIG URL when using profile.
Fix not filtering load-balance group in Surfboard configurations. (Issue [#128](https://github.com/tindy2013/subconverter/issues/128)).
Fix rule type filter not working properly.
Add support for using template in external configurations.
Add relay group support for Clash configurations.
Optimize codes.
This commit is contained in:
Tindy X committed 2020-04-09 21:07:50 +08:00
1 parent 3d2c8c8038
commit 025d0eb4e1
5 files changed
+70 -49

No files matched your search

+11 -6
View File
@@ -22,6 +22,7 @@ enum
typedef std::map<std::string, std::multimap<std::string, std::string>> ini_data_struct;
typedef std::multimap<std::string, std::string> string_multimap;
typedef std::vector<std::string> string_array;
typedef std::string::size_type string_size;
class INIReader
{
@@ -898,6 +899,7 @@ public:
std::string ToString()
{
std::string content;
string_size strsize;
if(!parsed)
return std::string();
@@ -907,16 +909,19 @@ public:
content += "[" + x + "]\n";
if(ini_content.find(x) != ini_content.end())
{
for(auto &y : ini_content.at(x))
auto section = ini_content.at(x);
for(auto iter = section.begin(); iter != section.end(); iter++)
{
if(y.first != "{NONAME}")
content += y.first + "=";
content += y.second + "\n";
if(iter->first != "{NONAME}")
content += iter->first + "=";
content += iter->second + "\n";
if(std::next(iter) == section.end())
strsize = iter->second.size();
}
}
content += "\n";
if(strsize)
content += "\n";
}
return content.erase(content.size() - 2);
}
+27 -33
View File
@@ -125,9 +125,12 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
while(getline(ss, strLine, delimiter))
{
if(type_int == 2 && !std::any_of(quanx_rule_type.begin(), quanx_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
continue;
else if(!std::any_of(surge_rule_type.begin(), surge_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
if(type_int == 2)
{
if(!std::any_of(quanx_rule_type.begin(), quanx_rule_type.end(), [&strLine](std::string type){return startsWith(strLine, type);}))
continue;
}
else if(!std::any_of(surge_rule_type.begin(), surge_rule_type.end(), [&strLine](std::string type){return startsWith(strLine, type);}))
continue;
lineSize = strLine.size();
@@ -175,8 +178,10 @@ int importItems(string_array &target, bool scope_limit = true)
if(fileExist(path))
content = fileGet(path, scope_limit);
else
else if(startsWith(path, "http://") || startsWith(path, "https://") || startsWith(path, "data:"))
content = webGet(path, proxy, dummy, cache_config);
else
writeLog(0, "File not found or not a valid URL: " + path, LOG_LEVEL_ERROR);
if(!content.size())
return -1;
@@ -831,7 +836,7 @@ struct ExternalConfig
string_array emoji;
string_array include;
string_array exclude;
string_map template_args;
template_args *tpl_args = NULL;
bool overwrite_original_rules = false;
bool enable_rule_generator = true;
};
@@ -866,14 +871,14 @@ int loadExternalYAML(YAML::Node &node, ExternalConfig &ext)
section["include_remarks"] >> ext.include;
section["exclude_remarks"] >> ext.exclude;
if(node["template_args"].IsSequence())
if(node["template_args"].IsSequence() && ext.tpl_args != NULL)
{
std::string key, value;
for(size_t i = 0; i < node["template_args"].size(); i++)
{
node["template_args"][i]["key"] >> key;
node["template_args"][i]["value"] >> value;
ext.template_args[key] = value;
ext.tpl_args->local_vars[key] = value;
}
}
@@ -882,9 +887,9 @@ int loadExternalYAML(YAML::Node &node, ExternalConfig &ext)
int loadExternalConfig(std::string &path, ExternalConfig &ext)
{
std::string base_content, dummy;
std::string proxy = parseProxy(proxy_config);
base_content = fetchFile(path, proxy, cache_config);
std::string base_content, dummy, proxy = parseProxy(proxy_config), config = fetchFile(path, proxy, cache_config);
if(render_template(config, *ext.tpl_args, base_content, template_path) != 0)
base_content = config;
try
{
@@ -946,13 +951,13 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
if(ini.ItemPrefixExist("exclude_remarks"))
ini.GetAll("exclude_remarks", ext.exclude);
if(ini.SectionExist("template"))
if(ini.SectionExist("template") && ext.tpl_args != NULL)
{
ini.EnterSection("template");
string_multimap tempmap;
ini.GetItems(tempmap);
for(auto &x : tempmap)
ext.template_args[x.first] = x.second;
ext.tpl_args->local_vars[x.first] = x.second;
}
return 0;
@@ -1094,6 +1099,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
extra_ruleset = rulesets;
//then load external configuration
ExternalConfig extconf;
extconf.tpl_args = &tpl_args;
loadExternalConfig(config, extconf);
if(!ext.nodelist)
{
@@ -1118,8 +1124,6 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
ext.rename_array = extconf.rename;
if(extconf.emoji.size())
ext.emoji_array = extconf.emoji;
if(extconf.template_args.size())
tpl_args.local_vars = extconf.template_args;
ext.enable_rule_generator = extconf.enable_rule_generator;
//load custom group
if(extconf.custom_proxy_group.size())
@@ -1230,6 +1234,9 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
string_array dummy_group;
std::vector<ruleset_content> dummy_ruleset;
std::string managed_url = base64_decode(UrlDecode(getUrlArg(argument, "profile_data")));
if(managed_url.empty())
managed_url = managed_config_prefix + "/sub?" + argument;
//std::cerr<<"Generate target: ";
int surge_ver;
@@ -1292,7 +1299,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
uploadGist("surge" + version, upload_path, output_content, true);
if(write_managed_config && managed_config_prefix.size())
output_content = "#!MANAGED-CONFIG " + managed_config_prefix + "/sub?" + argument + (interval ? " interval=" + std::to_string(interval) : "") \
output_content = "#!MANAGED-CONFIG " + managed_url + (interval ? " interval=" + std::to_string(interval) : "") \
+ " strict=" + std::string(strict ? "true" : "false") + "\n\n" + output_content;
}
break;
@@ -1311,7 +1318,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
uploadGist("surfboard", upload_path, output_content, true);
if(write_managed_config && managed_config_prefix.size())
output_content = "#!MANAGED-CONFIG " + managed_config_prefix + "/sub?" + argument + (interval ? " interval=" + std::to_string(interval) : "") \
output_content = "#!MANAGED-CONFIG " + managed_url + (interval ? " interval=" + std::to_string(interval) : "") \
+ " strict=" + std::string(strict ? "true" : "false") + "\n\n" + output_content;
break;
case "mellow"_hash:
@@ -1801,27 +1808,14 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
}
}
string_map sub_args;
for(auto &x : contents)
{
sub_args[x.first] = x.second;
}
string_array args = split(argument, "&");
string_size pos;
for(std::string &x : args)
{
pos = x.find("=");
if(pos == x.npos)
continue;
sub_args[x.substr(0, pos)] = UrlDecode(x.substr(pos + 1));
}
sub_args["token"] = token;
contents.emplace("token", token);
contents.emplace("profile_data", base64_encode(managed_config_prefix + "/getprofile?" + argument));
std::string query;
for(auto &x : sub_args)
for(auto &x : contents)
{
query += x.first + "=" + UrlEncode(x.second) + "&";
}
query.erase(query.size() - 1);
query += argument;
return subconverter(query, postdata, status_code, extra_headers);
}
+2 -1
View File
@@ -1211,7 +1211,8 @@ bool explodeSurge(std::string surge, const std::string &custom_port, int local_p
ini.SetIsolatedItemsSection("Proxy");
ini.IncludeSection("Proxy");
ini.AddDirectSaveSection("Proxy");
surge = regReplace(surge, "^#!.*$\\r?\\n", "");
if(surge.find("[Proxy]") != surge.npos)
surge = regReplace(surge, "^[\\S\\s]*?\\[", "[");
ini.Parse(surge);
if(!ini.SectionExist("Proxy"))
+28 -7
View File
@@ -28,6 +28,7 @@ const string_array clashr_obfs = {"plain", "http_simple", "http_post", "tls1.2_t
/// rule type lists
#define basic_types "DOMAIN", "DOMAIN-SUFFIX", "DOMAIN-KEYWORD", "IP-CIDR", "SRC-IP-CIDR", "GEOIP", "MATCH", "FINAL"
const string_array clash_rule_type = {basic_types, "IP-CIDR6", "SRC-PORT", "DST-PORT"};
const string_array surge2_rule_type = {basic_types, "IP-CIDR6", "USER-AGENT", "URL-REGEX", "PROCESS-NAME", "IN-PORT", "DEST-PORT", "SRC-IP"};
const string_array surge_rule_type = {basic_types, "IP-CIDR6", "USER-AGENT", "URL-REGEX", "AND", "OR", "NOT", "PROCESS-NAME", "IN-PORT", "DEST-PORT", "SRC-IP"};
const string_array quanx_rule_type = {basic_types, "USER-AGENT", "URL-REGEX", "PROCESS-NAME", "HOST", "HOST-SUFFIX", "HOST-KEYWORD"};
const string_array surfb_rule_type = {basic_types, "IP-CIDR6", "PROCESS-NAME", "IN-PORT", "DEST-PORT", "SRC-IP"};
@@ -688,12 +689,29 @@ void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_
continue;
/// remove unsupported types
if((surge_ver == -1 || surge_ver == -2) && !std::any_of(quanx_rule_type.begin(), quanx_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
continue;
else if(surge_ver == -3 && !std::any_of(surfb_rule_type.begin(), surfb_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
continue;
else if(!std::any_of(surge_rule_type.begin(), surge_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
continue;
switch(surge_ver)
{
case -1:
case -2:
if(!std::any_of(quanx_rule_type.begin(), quanx_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
continue;
break;
case -3:
if(!std::any_of(surfb_rule_type.begin(), surfb_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
continue;
break;
default:
if(surge_ver > 2)
{
if(!std::any_of(surge_rule_type.begin(), surge_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
continue;
}
else
{
if(!std::any_of(surge2_rule_type.begin(), surge2_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
continue;
}
}
strLine += "," + rule_group;
if(surge_ver == -1 || surge_ver == -2)
@@ -1036,6 +1054,7 @@ void netchToClash(std::vector<nodeInfo> &nodes, YAML::Node &yamlnode, string_arr
switch(hash_(vArray[1]))
{
case "select"_hash:
case "relay"_hash:
break;
case "url-test"_hash:
case "fallback"_hash:
@@ -1298,9 +1317,11 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, s
{
case "select"_hash:
break;
case "load-balance"_hash:
if(surge_ver < 1)
continue;
case "url-test"_hash:
case "fallback"_hash:
case "load-balance"_hash:
if(rules_upper_bound < 5)
continue;
rules_upper_bound -= 2;
+2 -2
View File
@@ -70,8 +70,8 @@ int render_template(const std::string &content, const template_args &vars, std::
});
m_callbacks.add_callback("join", 3, [](inja::Arguments &args)
{
std::string str1 = args.at(0)->get<std::string>(), str2 = args.at(1)->get<std::string>(), delim = args.at(2)->get<std::string>();
return std::move(str1) + std::move(delim) + std::move(str2);
std::string str1 = args.at(0)->get<std::string>(), str2 = args.at(1)->get<std::string>(), str3 = args.at(2)->get<std::string>();
return std::move(str1) + std::move(str2) + std::move(str3);
});
m_callbacks.add_callback("fetch", 1, template_webGet);
m_callbacks.add_callback("parseHostname", 1, parseHostname);