mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2026-11-03 02:02:24 +00:00
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:
5 files changed
+70
-49
No files matched your search
+11
-6
@@ -22,6 +22,7 @@ enum
|
|||||||
typedef std::map<std::string, std::multimap<std::string, std::string>> ini_data_struct;
|
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::multimap<std::string, std::string> string_multimap;
|
||||||
typedef std::vector<std::string> string_array;
|
typedef std::vector<std::string> string_array;
|
||||||
|
typedef std::string::size_type string_size;
|
||||||
|
|
||||||
class INIReader
|
class INIReader
|
||||||
{
|
{
|
||||||
@@ -898,6 +899,7 @@ public:
|
|||||||
std::string ToString()
|
std::string ToString()
|
||||||
{
|
{
|
||||||
std::string content;
|
std::string content;
|
||||||
|
string_size strsize;
|
||||||
|
|
||||||
if(!parsed)
|
if(!parsed)
|
||||||
return std::string();
|
return std::string();
|
||||||
@@ -907,16 +909,19 @@ public:
|
|||||||
content += "[" + x + "]\n";
|
content += "[" + x + "]\n";
|
||||||
if(ini_content.find(x) != ini_content.end())
|
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}")
|
if(iter->first != "{NONAME}")
|
||||||
content += y.first + "=";
|
content += iter->first + "=";
|
||||||
content += y.second + "\n";
|
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);
|
return content.erase(content.size() - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-33
@@ -125,9 +125,12 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
|
|||||||
|
|
||||||
while(getline(ss, strLine, delimiter))
|
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);}))
|
if(type_int == 2)
|
||||||
continue;
|
{
|
||||||
else if(!std::any_of(surge_rule_type.begin(), surge_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
|
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;
|
continue;
|
||||||
|
|
||||||
lineSize = strLine.size();
|
lineSize = strLine.size();
|
||||||
@@ -175,8 +178,10 @@ int importItems(string_array &target, bool scope_limit = true)
|
|||||||
|
|
||||||
if(fileExist(path))
|
if(fileExist(path))
|
||||||
content = fileGet(path, scope_limit);
|
content = fileGet(path, scope_limit);
|
||||||
else
|
else if(startsWith(path, "http://") || startsWith(path, "https://") || startsWith(path, "data:"))
|
||||||
content = webGet(path, proxy, dummy, cache_config);
|
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())
|
if(!content.size())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -831,7 +836,7 @@ struct ExternalConfig
|
|||||||
string_array emoji;
|
string_array emoji;
|
||||||
string_array include;
|
string_array include;
|
||||||
string_array exclude;
|
string_array exclude;
|
||||||
string_map template_args;
|
template_args *tpl_args = NULL;
|
||||||
bool overwrite_original_rules = false;
|
bool overwrite_original_rules = false;
|
||||||
bool enable_rule_generator = true;
|
bool enable_rule_generator = true;
|
||||||
};
|
};
|
||||||
@@ -866,14 +871,14 @@ int loadExternalYAML(YAML::Node &node, ExternalConfig &ext)
|
|||||||
section["include_remarks"] >> ext.include;
|
section["include_remarks"] >> ext.include;
|
||||||
section["exclude_remarks"] >> ext.exclude;
|
section["exclude_remarks"] >> ext.exclude;
|
||||||
|
|
||||||
if(node["template_args"].IsSequence())
|
if(node["template_args"].IsSequence() && ext.tpl_args != NULL)
|
||||||
{
|
{
|
||||||
std::string key, value;
|
std::string key, value;
|
||||||
for(size_t i = 0; i < node["template_args"].size(); i++)
|
for(size_t i = 0; i < node["template_args"].size(); i++)
|
||||||
{
|
{
|
||||||
node["template_args"][i]["key"] >> key;
|
node["template_args"][i]["key"] >> key;
|
||||||
node["template_args"][i]["value"] >> value;
|
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)
|
int loadExternalConfig(std::string &path, ExternalConfig &ext)
|
||||||
{
|
{
|
||||||
std::string base_content, dummy;
|
std::string base_content, dummy, proxy = parseProxy(proxy_config), config = fetchFile(path, proxy, cache_config);
|
||||||
std::string proxy = parseProxy(proxy_config);
|
if(render_template(config, *ext.tpl_args, base_content, template_path) != 0)
|
||||||
base_content = fetchFile(path, proxy, cache_config);
|
base_content = config;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -946,13 +951,13 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
|
|||||||
if(ini.ItemPrefixExist("exclude_remarks"))
|
if(ini.ItemPrefixExist("exclude_remarks"))
|
||||||
ini.GetAll("exclude_remarks", ext.exclude);
|
ini.GetAll("exclude_remarks", ext.exclude);
|
||||||
|
|
||||||
if(ini.SectionExist("template"))
|
if(ini.SectionExist("template") && ext.tpl_args != NULL)
|
||||||
{
|
{
|
||||||
ini.EnterSection("template");
|
ini.EnterSection("template");
|
||||||
string_multimap tempmap;
|
string_multimap tempmap;
|
||||||
ini.GetItems(tempmap);
|
ini.GetItems(tempmap);
|
||||||
for(auto &x : tempmap)
|
for(auto &x : tempmap)
|
||||||
ext.template_args[x.first] = x.second;
|
ext.tpl_args->local_vars[x.first] = x.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1094,6 +1099,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
extra_ruleset = rulesets;
|
extra_ruleset = rulesets;
|
||||||
//then load external configuration
|
//then load external configuration
|
||||||
ExternalConfig extconf;
|
ExternalConfig extconf;
|
||||||
|
extconf.tpl_args = &tpl_args;
|
||||||
loadExternalConfig(config, extconf);
|
loadExternalConfig(config, extconf);
|
||||||
if(!ext.nodelist)
|
if(!ext.nodelist)
|
||||||
{
|
{
|
||||||
@@ -1118,8 +1124,6 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
ext.rename_array = extconf.rename;
|
ext.rename_array = extconf.rename;
|
||||||
if(extconf.emoji.size())
|
if(extconf.emoji.size())
|
||||||
ext.emoji_array = extconf.emoji;
|
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;
|
ext.enable_rule_generator = extconf.enable_rule_generator;
|
||||||
//load custom group
|
//load custom group
|
||||||
if(extconf.custom_proxy_group.size())
|
if(extconf.custom_proxy_group.size())
|
||||||
@@ -1230,6 +1234,9 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
|
|
||||||
string_array dummy_group;
|
string_array dummy_group;
|
||||||
std::vector<ruleset_content> dummy_ruleset;
|
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: ";
|
//std::cerr<<"Generate target: ";
|
||||||
int surge_ver;
|
int surge_ver;
|
||||||
@@ -1292,7 +1299,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
uploadGist("surge" + version, upload_path, output_content, true);
|
uploadGist("surge" + version, upload_path, output_content, true);
|
||||||
|
|
||||||
if(write_managed_config && managed_config_prefix.size())
|
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;
|
+ " strict=" + std::string(strict ? "true" : "false") + "\n\n" + output_content;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1311,7 +1318,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
|||||||
uploadGist("surfboard", upload_path, output_content, true);
|
uploadGist("surfboard", upload_path, output_content, true);
|
||||||
|
|
||||||
if(write_managed_config && managed_config_prefix.size())
|
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;
|
+ " strict=" + std::string(strict ? "true" : "false") + "\n\n" + output_content;
|
||||||
break;
|
break;
|
||||||
case "mellow"_hash:
|
case "mellow"_hash:
|
||||||
@@ -1801,27 +1808,14 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string_map sub_args;
|
contents.emplace("token", token);
|
||||||
for(auto &x : contents)
|
contents.emplace("profile_data", base64_encode(managed_config_prefix + "/getprofile?" + argument));
|
||||||
{
|
|
||||||
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;
|
|
||||||
std::string query;
|
std::string query;
|
||||||
for(auto &x : sub_args)
|
for(auto &x : contents)
|
||||||
{
|
{
|
||||||
query += x.first + "=" + UrlEncode(x.second) + "&";
|
query += x.first + "=" + UrlEncode(x.second) + "&";
|
||||||
}
|
}
|
||||||
query.erase(query.size() - 1);
|
query += argument;
|
||||||
return subconverter(query, postdata, status_code, extra_headers);
|
return subconverter(query, postdata, status_code, extra_headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1211,7 +1211,8 @@ bool explodeSurge(std::string surge, const std::string &custom_port, int local_p
|
|||||||
ini.SetIsolatedItemsSection("Proxy");
|
ini.SetIsolatedItemsSection("Proxy");
|
||||||
ini.IncludeSection("Proxy");
|
ini.IncludeSection("Proxy");
|
||||||
ini.AddDirectSaveSection("Proxy");
|
ini.AddDirectSaveSection("Proxy");
|
||||||
surge = regReplace(surge, "^#!.*$\\r?\\n", "");
|
if(surge.find("[Proxy]") != surge.npos)
|
||||||
|
surge = regReplace(surge, "^[\\S\\s]*?\\[", "[");
|
||||||
ini.Parse(surge);
|
ini.Parse(surge);
|
||||||
|
|
||||||
if(!ini.SectionExist("Proxy"))
|
if(!ini.SectionExist("Proxy"))
|
||||||
|
|||||||
+28
-7
@@ -28,6 +28,7 @@ const string_array clashr_obfs = {"plain", "http_simple", "http_post", "tls1.2_t
|
|||||||
/// rule type lists
|
/// rule type lists
|
||||||
#define basic_types "DOMAIN", "DOMAIN-SUFFIX", "DOMAIN-KEYWORD", "IP-CIDR", "SRC-IP-CIDR", "GEOIP", "MATCH", "FINAL"
|
#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 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 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 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"};
|
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;
|
continue;
|
||||||
|
|
||||||
/// remove unsupported types
|
/// 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);}))
|
switch(surge_ver)
|
||||||
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);}))
|
case -1:
|
||||||
continue;
|
case -2:
|
||||||
else if(!std::any_of(surge_rule_type.begin(), surge_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
|
if(!std::any_of(quanx_rule_type.begin(), quanx_rule_type.end(), [strLine](std::string type){return startsWith(strLine, type);}))
|
||||||
continue;
|
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;
|
strLine += "," + rule_group;
|
||||||
if(surge_ver == -1 || surge_ver == -2)
|
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]))
|
switch(hash_(vArray[1]))
|
||||||
{
|
{
|
||||||
case "select"_hash:
|
case "select"_hash:
|
||||||
|
case "relay"_hash:
|
||||||
break;
|
break;
|
||||||
case "url-test"_hash:
|
case "url-test"_hash:
|
||||||
case "fallback"_hash:
|
case "fallback"_hash:
|
||||||
@@ -1298,9 +1317,11 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, s
|
|||||||
{
|
{
|
||||||
case "select"_hash:
|
case "select"_hash:
|
||||||
break;
|
break;
|
||||||
|
case "load-balance"_hash:
|
||||||
|
if(surge_ver < 1)
|
||||||
|
continue;
|
||||||
case "url-test"_hash:
|
case "url-test"_hash:
|
||||||
case "fallback"_hash:
|
case "fallback"_hash:
|
||||||
case "load-balance"_hash:
|
|
||||||
if(rules_upper_bound < 5)
|
if(rules_upper_bound < 5)
|
||||||
continue;
|
continue;
|
||||||
rules_upper_bound -= 2;
|
rules_upper_bound -= 2;
|
||||||
|
|||||||
+2
-2
@@ -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)
|
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>();
|
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(delim) + std::move(str2);
|
return std::move(str1) + std::move(str2) + std::move(str3);
|
||||||
});
|
});
|
||||||
m_callbacks.add_callback("fetch", 1, template_webGet);
|
m_callbacks.add_callback("fetch", 1, template_webGet);
|
||||||
m_callbacks.add_callback("parseHostname", 1, parseHostname);
|
m_callbacks.add_callback("parseHostname", 1, parseHostname);
|
||||||
|
|||||||
Reference in new issue
Block a user