mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2026-11-02 01:33:04 +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::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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user