mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2026-11-04 02:34:06 +00:00
Enhancements
Add basic support for generating sing-box configs. Use cpp-httplib as web server. Optimize codes.
This commit is contained in:
32 files changed
+10286
-234
No files matched your search
@@ -5,6 +5,7 @@
|
||||
#include "../../utils/network.h"
|
||||
#include "../../utils/regexp.h"
|
||||
#include "../../utils/string.h"
|
||||
#include "../../utils/rapidjson_extra.h"
|
||||
#include "subexport.h"
|
||||
|
||||
/// rule type lists
|
||||
@@ -28,7 +29,7 @@ std::string convertRuleset(const std::string &content, int type)
|
||||
|
||||
if(regFind(content, "^payload:\\r?\\n")) /// Clash
|
||||
{
|
||||
output = regReplace(regReplace(content, "payload:\\r?\\n", "", true), "\\s?^\\s*-\\s+('|\"?)(.*)\\1$", "\n$2", true);
|
||||
output = regReplace(regReplace(content, "payload:\\r?\\n", "", true), R"(\s?^\s*-\s+('|"?)(.*)\1$)", "\n$2", true);
|
||||
if(type == RULESET_CLASH_CLASSICAL) /// classical type
|
||||
return output;
|
||||
std::stringstream ss;
|
||||
@@ -51,8 +52,8 @@ std::string convertRuleset(const std::string &content, int type)
|
||||
|
||||
if(!strLine.empty() && (strLine[0] != ';' && strLine[0] != '#' && !(lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')))
|
||||
{
|
||||
pos = strLine.find("/");
|
||||
if(pos != strLine.npos) /// ipcidr
|
||||
pos = strLine.find('/');
|
||||
if(pos != std::string::npos) /// ipcidr
|
||||
{
|
||||
if(isIPv4(strLine.substr(0, pos)))
|
||||
output += "IP-CIDR,";
|
||||
@@ -143,7 +144,7 @@ void rulesetToClash(YAML::Node &base_rule, std::vector<RulesetContent> &ruleset_
|
||||
lineSize = strLine.size();
|
||||
if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored
|
||||
continue;
|
||||
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
|
||||
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
if(strFind(strLine, "//"))
|
||||
{
|
||||
@@ -218,7 +219,7 @@ std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<RulesetContent>
|
||||
lineSize = strLine.size();
|
||||
if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored
|
||||
continue;
|
||||
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](std::string type){ return startsWith(strLine, type); }))
|
||||
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](const std::string& type){ return startsWith(strLine, type); }))
|
||||
continue;
|
||||
if(strFind(strLine, "//"))
|
||||
{
|
||||
@@ -235,7 +236,7 @@ std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<RulesetContent>
|
||||
return output_content;
|
||||
}
|
||||
|
||||
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, std::string remote_path_prefix)
|
||||
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, const std::string &remote_path_prefix)
|
||||
{
|
||||
string_array allRules;
|
||||
std::string rule_group, rule_path, rule_path_typed, retrieved_rules, strLine;
|
||||
@@ -268,6 +269,8 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
|
||||
case -4:
|
||||
base_rule.erase_section("Remote Rule");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +316,7 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
|
||||
}
|
||||
if(fileExist(rule_path))
|
||||
{
|
||||
if(surge_ver > 2 && remote_path_prefix.size())
|
||||
if(surge_ver > 2 && !remote_path_prefix.empty())
|
||||
{
|
||||
strLine = "RULE-SET," + remote_path_prefix + "/getruleset?type=1&url=" + urlSafeBase64Encode(rule_path_typed) + "," + rule_group;
|
||||
if(x.update_interval)
|
||||
@@ -321,14 +324,14 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
|
||||
allRules.emplace_back(std::move(strLine));
|
||||
continue;
|
||||
}
|
||||
else if(surge_ver == -1 && remote_path_prefix.size())
|
||||
else if(surge_ver == -1 && !remote_path_prefix.empty())
|
||||
{
|
||||
strLine = remote_path_prefix + "/getruleset?type=2&url=" + urlSafeBase64Encode(rule_path_typed) + "&group=" + urlSafeBase64Encode(rule_group);
|
||||
strLine += ", tag=" + rule_group + ", enabled=true";
|
||||
base_rule.set("filter_remote", "{NONAME}", strLine);
|
||||
continue;
|
||||
}
|
||||
else if(surge_ver == -4 && remote_path_prefix.size())
|
||||
else if(surge_ver == -4 && !remote_path_prefix.empty())
|
||||
{
|
||||
strLine = remote_path_prefix + "/getruleset?type=1&url=" + urlSafeBase64Encode(rule_path_typed) + "," + rule_group;
|
||||
base_rule.set("Remote Rule", "{NONAME}", strLine);
|
||||
@@ -341,7 +344,7 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
|
||||
{
|
||||
if(x.rule_type != RULESET_SURGE)
|
||||
{
|
||||
if(remote_path_prefix.size())
|
||||
if(!remote_path_prefix.empty())
|
||||
strLine = "RULE-SET," + remote_path_prefix + "/getruleset?type=1&url=" + urlSafeBase64Encode(rule_path_typed) + "," + rule_group;
|
||||
else
|
||||
continue;
|
||||
@@ -355,7 +358,7 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
|
||||
allRules.emplace_back(std::move(strLine));
|
||||
continue;
|
||||
}
|
||||
else if(surge_ver == -1 && remote_path_prefix.size())
|
||||
else if(surge_ver == -1 && !remote_path_prefix.empty())
|
||||
{
|
||||
strLine = remote_path_prefix + "/getruleset?type=2&url=" + urlSafeBase64Encode(rule_path_typed) + "&group=" + urlSafeBase64Encode(rule_group);
|
||||
strLine += ", tag=" + rule_group + ", enabled=true";
|
||||
@@ -401,22 +404,22 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
|
||||
continue;
|
||||
[[fallthrough]];
|
||||
case -1:
|
||||
if(!std::any_of(QuanXRuleTypes.begin(), QuanXRuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
|
||||
if(!std::any_of(QuanXRuleTypes.begin(), QuanXRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
break;
|
||||
case -3:
|
||||
if(!std::any_of(SurfRuleTypes.begin(), SurfRuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
|
||||
if(!std::any_of(SurfRuleTypes.begin(), SurfRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
if(surge_ver > 2)
|
||||
{
|
||||
if(!std::any_of(SurgeRuleTypes.begin(), SurgeRuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
|
||||
if(!std::any_of(SurgeRuleTypes.begin(), SurgeRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!std::any_of(Surge2RuleTypes.begin(), Surge2RuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
|
||||
if(!std::any_of(Surge2RuleTypes.begin(), Surge2RuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -453,3 +456,100 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
|
||||
base_rule.set("{NONAME}", x);
|
||||
}
|
||||
}
|
||||
|
||||
static rapidjson::Value transformRuleToSingBox(const std::string& rule, rapidjson::MemoryPoolAllocator<>& allocator)
|
||||
{
|
||||
std::string type, value, group, option;
|
||||
|
||||
regGetMatch(rule, "^(.*?),(.*?)(?:,(.*?))?(,.*)?$", 5, nullptr, &type, &value, &group, &option);
|
||||
rapidjson::Value rule_obj(rapidjson::kObjectType);
|
||||
type = replaceAllDistinct(toLower(type), "-", "_");
|
||||
type = replaceAllDistinct(type, "ip_cidr6", "ip_cidr");
|
||||
if (type == "match" || type == "final") {
|
||||
rule_obj.AddMember("outbound", rapidjson::Value(value.c_str(), allocator), allocator);
|
||||
} else {
|
||||
rule_obj.AddMember(rapidjson::Value(type.c_str(), allocator), rapidjson::Value(value.c_str(), allocator), allocator);
|
||||
rule_obj.AddMember("outbound", rapidjson::Value(group.c_str(), allocator), allocator);
|
||||
}
|
||||
return rule_obj;
|
||||
}
|
||||
|
||||
void rulesetToSingBox(rapidjson::Document &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules)
|
||||
{
|
||||
std::string rule_group, retrieved_rules, strLine, final;
|
||||
std::stringstream strStrm;
|
||||
size_t total_rules = 0;
|
||||
rapidjson::MemoryPoolAllocator<>& allocator = base_rule.GetAllocator();
|
||||
|
||||
rapidjson::Value rules(rapidjson::kArrayType);
|
||||
if (!overwrite_original_rules)
|
||||
{
|
||||
if (base_rule.HasMember("route") && base_rule["route"].HasMember("rules") && base_rule["route"]["rules"].IsArray())
|
||||
rules.Swap(base_rule["route"]["rules"]);
|
||||
}
|
||||
|
||||
for(RulesetContent &x : ruleset_content_array)
|
||||
{
|
||||
if(global.maxAllowedRules && total_rules > global.maxAllowedRules)
|
||||
break;
|
||||
rule_group = x.rule_group;
|
||||
retrieved_rules = x.rule_content.get();
|
||||
if(retrieved_rules.empty())
|
||||
{
|
||||
writeLog(0, "Failed to fetch ruleset or ruleset is empty: '" + x.rule_path + "'!", LOG_LEVEL_WARNING);
|
||||
continue;
|
||||
}
|
||||
if(startsWith(retrieved_rules, "[]"))
|
||||
{
|
||||
strLine = retrieved_rules.substr(2);
|
||||
if(startsWith(strLine, "FINAL") || startsWith(strLine, "MATCH"))
|
||||
{
|
||||
final = rule_group;
|
||||
continue;
|
||||
}
|
||||
strLine += "," + rule_group;
|
||||
if(count_least(strLine, ',', 3))
|
||||
strLine = regReplace(strLine, "^(.*?,.*?)(,.*)(,.*)$", "$1$3$2");
|
||||
rules.PushBack(transformRuleToSingBox(strLine, allocator), allocator);
|
||||
total_rules++;
|
||||
continue;
|
||||
}
|
||||
retrieved_rules = convertRuleset(retrieved_rules, x.rule_type);
|
||||
char delimiter = getLineBreak(retrieved_rules);
|
||||
|
||||
strStrm.clear();
|
||||
strStrm<<retrieved_rules;
|
||||
std::string::size_type lineSize;
|
||||
while(getline(strStrm, strLine, delimiter))
|
||||
{
|
||||
if(global.maxAllowedRules && total_rules > global.maxAllowedRules)
|
||||
break;
|
||||
strLine = trimWhitespace(strLine, true, true); //remove whitespaces
|
||||
lineSize = strLine.size();
|
||||
if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored
|
||||
continue;
|
||||
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
if(strFind(strLine, "//"))
|
||||
{
|
||||
strLine.erase(strLine.find("//"));
|
||||
strLine = trimWhitespace(strLine);
|
||||
}
|
||||
strLine += "," + rule_group;
|
||||
if(count_least(strLine, ',', 3))
|
||||
strLine = regReplace(strLine, "^(.*?,.*?)(,.*)(,.*)$", "$1$3$2");
|
||||
rules.PushBack(transformRuleToSingBox(strLine, allocator), allocator);
|
||||
}
|
||||
}
|
||||
|
||||
if (!base_rule.HasMember("route"))
|
||||
base_rule.AddMember("route", rapidjson::Value(rapidjson::kObjectType), allocator);
|
||||
if (!base_rule["route"].HasMember("rules"))
|
||||
base_rule["route"].AddMember("rules", rapidjson::Value(rapidjson::kArrayType), allocator);
|
||||
base_rule["route"]["rules"].Swap(rules);
|
||||
|
||||
if (!base_rule["route"].HasMember("final"))
|
||||
base_rule["route"].AddMember("final", rapidjson::Value(final.c_str(), allocator), allocator);
|
||||
else
|
||||
base_rule["route"]["final"].SetString(final.c_str(), allocator);
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <future>
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include "../../utils/ini_reader/ini_reader.h"
|
||||
|
||||
@@ -31,6 +32,7 @@ struct RulesetContent
|
||||
std::string convertRuleset(const std::string &content, int type);
|
||||
void rulesetToClash(YAML::Node &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name);
|
||||
std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name);
|
||||
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, std::string remote_path_prefix);
|
||||
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, const std::string& remote_path_prefix);
|
||||
void rulesetToSingBox(rapidjson::Document &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules);
|
||||
|
||||
#endif // RULECONVERT_H_INCLUDED
|
||||
@@ -1817,7 +1817,6 @@ void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Rulese
|
||||
|
||||
std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
rapidjson::Document json;
|
||||
INIReader ini;
|
||||
std::string output_nodelist;
|
||||
std::vector<Proxy> nodelist;
|
||||
@@ -2042,3 +2041,303 @@ std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf,
|
||||
|
||||
return ini.to_string();
|
||||
}
|
||||
|
||||
static std::string formatSingBoxInterval(Integer interval)
|
||||
{
|
||||
std::string result;
|
||||
if(interval >= 3600)
|
||||
{
|
||||
result += std::to_string(interval / 3600) + "h";
|
||||
interval %= 3600;
|
||||
}
|
||||
if(interval >= 60)
|
||||
{
|
||||
result += std::to_string(interval / 60) + "m";
|
||||
interval %= 60;
|
||||
}
|
||||
if(interval > 0)
|
||||
result += std::to_string(interval) + "s";
|
||||
return result;
|
||||
}
|
||||
|
||||
static rapidjson::Value buildV2RayTransport(const Proxy& proxy, rapidjson::MemoryPoolAllocator<>& allocator)
|
||||
{
|
||||
rapidjson::Value transport(rapidjson::kObjectType);
|
||||
switch (hash_(proxy.TransferProtocol))
|
||||
{
|
||||
case "http"_hash:
|
||||
{
|
||||
if (!proxy.Host.empty())
|
||||
transport.AddMember("host", rapidjson::StringRef(proxy.Host.c_str()), allocator);
|
||||
[[fallthrough]];
|
||||
}
|
||||
case "ws"_hash:
|
||||
{
|
||||
transport.AddMember("type", rapidjson::StringRef(proxy.TransferProtocol.c_str()), allocator);
|
||||
if (proxy.Path.empty())
|
||||
transport.AddMember("path", "/", allocator);
|
||||
else
|
||||
transport.AddMember("path", rapidjson::StringRef(proxy.Path.c_str()), allocator);
|
||||
|
||||
rapidjson::Value headers(rapidjson::kObjectType);
|
||||
if (!proxy.Host.empty())
|
||||
headers.AddMember("Host", rapidjson::StringRef(proxy.Host.c_str()), allocator);
|
||||
if (!proxy.Edge.empty())
|
||||
headers.AddMember("Edge", rapidjson::StringRef(proxy.Edge.c_str()), allocator);
|
||||
transport.AddMember("headers", headers, allocator);
|
||||
break;
|
||||
}
|
||||
case "grpc"_hash:
|
||||
{
|
||||
transport.AddMember("type", "grpc", allocator);
|
||||
if (!proxy.Path.empty())
|
||||
transport.AddMember("service_name", rapidjson::StringRef(proxy.Path.c_str()), allocator);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return transport;
|
||||
}
|
||||
|
||||
void proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext) {
|
||||
rapidjson::Document::AllocatorType &allocator = json.GetAllocator();
|
||||
rapidjson::Value outbounds(rapidjson::kArrayType), route(rapidjson::kArrayType);
|
||||
std::vector<Proxy> nodelist;
|
||||
|
||||
auto direct = buildObject(allocator, "type", "direct", "tag", "DIRECT");
|
||||
outbounds.PushBack(direct, allocator);
|
||||
auto reject = buildObject(allocator, "type", "block", "tag", "REJECT");
|
||||
outbounds.PushBack(reject, allocator);
|
||||
|
||||
for (Proxy &x : nodes)
|
||||
{
|
||||
std::string type = getProxyTypeName(x.Type);
|
||||
if (ext.append_proxy_type)
|
||||
x.Remark = "[" + type + "] " + x.Remark;
|
||||
|
||||
tribool udp = ext.udp, tfo = ext.tfo, scv = ext.skip_cert_verify;
|
||||
udp.define(x.UDP);
|
||||
tfo.define(x.TCPFastOpen);
|
||||
scv.define(x.AllowInsecure);
|
||||
|
||||
rapidjson::Value proxy(rapidjson::kObjectType);
|
||||
switch (x.Type)
|
||||
{
|
||||
case ProxyType::Shadowsocks:
|
||||
{
|
||||
proxy.AddMember("type", "shadowsocks", allocator);
|
||||
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
|
||||
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
|
||||
proxy.AddMember("server_port", x.Port, allocator);
|
||||
proxy.AddMember("method", rapidjson::StringRef(x.EncryptMethod.c_str()), allocator);
|
||||
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
|
||||
if(!x.Plugin.empty() && !x.PluginOption.empty())
|
||||
{
|
||||
proxy.AddMember("plugin", rapidjson::StringRef(x.Plugin.c_str()), allocator);
|
||||
proxy.AddMember("plugin_opts", rapidjson::StringRef(x.PluginOption.c_str()), allocator);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ProxyType::ShadowsocksR:
|
||||
{
|
||||
proxy.AddMember("type", "shadowsocksr", allocator);
|
||||
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
|
||||
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
|
||||
proxy.AddMember("server_port", x.Port, allocator);
|
||||
proxy.AddMember("method", rapidjson::StringRef(x.EncryptMethod.c_str()), allocator);
|
||||
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
|
||||
proxy.AddMember("protocol", rapidjson::StringRef(x.Protocol.c_str()), allocator);
|
||||
proxy.AddMember("protocol_param", rapidjson::StringRef(x.ProtocolParam.c_str()), allocator);
|
||||
proxy.AddMember("obfs", rapidjson::StringRef(x.OBFS.c_str()), allocator);
|
||||
proxy.AddMember("obfs_param", rapidjson::StringRef(x.OBFSParam.c_str()), allocator);
|
||||
break;
|
||||
}
|
||||
case ProxyType::VMess:
|
||||
{
|
||||
proxy.AddMember("type", "vmess", allocator);
|
||||
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
|
||||
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
|
||||
proxy.AddMember("server_port", x.Port, allocator);
|
||||
proxy.AddMember("uuid", rapidjson::StringRef(x.UserId.c_str()), allocator);
|
||||
proxy.AddMember("alter_id", x.AlterId, allocator);
|
||||
proxy.AddMember("cipher", rapidjson::StringRef(x.EncryptMethod.c_str()), allocator);
|
||||
|
||||
auto transport = buildV2RayTransport(x, allocator);
|
||||
proxy.AddMember("transport", transport, allocator);
|
||||
break;
|
||||
}
|
||||
case ProxyType::Trojan:
|
||||
{
|
||||
proxy.AddMember("type", "trojan", allocator);
|
||||
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
|
||||
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
|
||||
proxy.AddMember("server_port", x.Port, allocator);
|
||||
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
|
||||
|
||||
auto transport = buildV2RayTransport(x, allocator);
|
||||
proxy.AddMember("transport", transport, allocator);
|
||||
break;
|
||||
}
|
||||
case ProxyType::WireGuard:
|
||||
{
|
||||
proxy.AddMember("type", "wireguard", allocator);
|
||||
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
|
||||
rapidjson::Value addresses(rapidjson::kArrayType);
|
||||
addresses.PushBack(rapidjson::StringRef(x.SelfIP.c_str()), allocator);
|
||||
if (!x.SelfIPv6.empty())
|
||||
addresses.PushBack(rapidjson::StringRef(x.SelfIPv6.c_str()), allocator);
|
||||
proxy.AddMember("local_address", addresses, allocator);
|
||||
proxy.AddMember("private_key", rapidjson::StringRef(x.PrivateKey.c_str()), allocator);
|
||||
|
||||
rapidjson::Value peer(rapidjson::kObjectType);
|
||||
peer.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
|
||||
peer.AddMember("server_port", x.Port, allocator);
|
||||
peer.AddMember("public_key", rapidjson::StringRef(x.PublicKey.c_str()), allocator);
|
||||
if (!x.PreSharedKey.empty())
|
||||
peer.AddMember("pre_shared_key", rapidjson::StringRef(x.PreSharedKey.c_str()), allocator);
|
||||
|
||||
if (!x.AllowedIPs.empty())
|
||||
{
|
||||
auto allowed = split(x.AllowedIPs, ",");
|
||||
rapidjson::Value allowed_ips(rapidjson::kArrayType);
|
||||
for (const auto &ip: allowed) {
|
||||
allowed_ips.PushBack(rapidjson::Value(trim(ip).c_str(), allocator), allocator);
|
||||
}
|
||||
peer.AddMember("allowed_ips", allowed_ips, allocator);
|
||||
}
|
||||
|
||||
if (!x.ClientId.empty())
|
||||
{
|
||||
auto client_id = split(x.ClientId, ",");
|
||||
rapidjson::Value reserved(rapidjson::kArrayType);
|
||||
for (const auto &id : client_id)
|
||||
{
|
||||
reserved.PushBack(to_int(trim(id)), allocator);
|
||||
}
|
||||
peer.AddMember("reserved", reserved, allocator);
|
||||
}
|
||||
|
||||
rapidjson::Value peers(rapidjson::kArrayType);
|
||||
peers.PushBack(peer, allocator);
|
||||
proxy.AddMember("peers", peers, allocator);
|
||||
proxy.AddMember("mtu", x.Mtu, allocator);
|
||||
break;
|
||||
}
|
||||
case ProxyType::HTTP:
|
||||
case ProxyType::HTTPS:
|
||||
{
|
||||
proxy.AddMember("type", "http", allocator);
|
||||
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
|
||||
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
|
||||
proxy.AddMember("server_port", x.Port, allocator);
|
||||
if (x.TLSSecure)
|
||||
{
|
||||
proxy.AddMember("username", rapidjson::StringRef(x.Username.c_str()), allocator);
|
||||
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ProxyType::SOCKS5:
|
||||
{
|
||||
proxy.AddMember("type", "socks", allocator);
|
||||
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
|
||||
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
|
||||
proxy.AddMember("port", x.Port, allocator);
|
||||
proxy.AddMember("version", 5, allocator);
|
||||
proxy.AddMember("username", rapidjson::StringRef(x.Username.c_str()), allocator);
|
||||
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (x.TLSSecure)
|
||||
{
|
||||
rapidjson::Value tls(rapidjson::kObjectType);
|
||||
tls.AddMember("enable", true, allocator);
|
||||
if (!x.ServerName.empty())
|
||||
tls.AddMember("server_name", rapidjson::StringRef(x.ServerName.c_str()), allocator);
|
||||
tls.AddMember("insecure", buildBooleanValue(scv), allocator);
|
||||
proxy.AddMember("tls", tls, allocator);
|
||||
}
|
||||
if (!udp.is_undef() && !udp)
|
||||
{
|
||||
proxy.AddMember("network", "tcp", allocator);
|
||||
}
|
||||
if (!tfo.is_undef())
|
||||
{
|
||||
proxy.AddMember("tcp_fast_open", buildBooleanValue(tfo), allocator);
|
||||
}
|
||||
nodelist.push_back(x);
|
||||
outbounds.PushBack(proxy, allocator);
|
||||
}
|
||||
for (const ProxyGroupConfig& x: extra_proxy_group)
|
||||
{
|
||||
string_array filtered_nodelist;
|
||||
std::string type;
|
||||
switch (x.Type)
|
||||
{
|
||||
case ProxyGroupType::Select:
|
||||
{
|
||||
type = "selector";
|
||||
break;
|
||||
}
|
||||
case ProxyGroupType::URLTest:
|
||||
case ProxyGroupType::Fallback:
|
||||
case ProxyGroupType::LoadBalance:
|
||||
{
|
||||
type = "urltest";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
for (const auto &y : x.Proxies)
|
||||
groupGenerate(y, nodelist, filtered_nodelist, true, ext);
|
||||
|
||||
if (filtered_nodelist.empty())
|
||||
filtered_nodelist.emplace_back("DIRECT");
|
||||
|
||||
rapidjson::Value group(rapidjson::kObjectType);
|
||||
|
||||
group.AddMember("type", rapidjson::Value(type.c_str(), allocator), allocator);
|
||||
group.AddMember("tag", rapidjson::Value(x.Name.c_str(), allocator), allocator);
|
||||
|
||||
rapidjson::Value group_outbounds(rapidjson::kArrayType);
|
||||
for (const std::string& y: filtered_nodelist)
|
||||
{
|
||||
group_outbounds.PushBack(rapidjson::Value(y.c_str(), allocator), allocator);
|
||||
}
|
||||
group.AddMember("outbounds", group_outbounds, allocator);
|
||||
|
||||
if (x.Type == ProxyGroupType::URLTest)
|
||||
{
|
||||
group.AddMember("url", rapidjson::Value(x.Url.c_str(), allocator), allocator);
|
||||
group.AddMember("interval", rapidjson::Value(formatSingBoxInterval(x.Interval).c_str(), allocator), allocator);
|
||||
if (x.Tolerance > 0)
|
||||
group.AddMember("tolerance", x.Tolerance, allocator);
|
||||
}
|
||||
|
||||
outbounds.PushBack(group, allocator);
|
||||
}
|
||||
if (json.HasMember("outbounds"))
|
||||
json.RemoveMember("outbounds");
|
||||
json.AddMember("outbounds", outbounds, allocator);
|
||||
}
|
||||
|
||||
std::string proxyToSingBox(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
rapidjson::Document json;
|
||||
json.Parse(base_conf.data());
|
||||
if(json.HasParseError())
|
||||
{
|
||||
writeLog(0, "sing-box base loader failed with error: " + std::string(rapidjson::GetParseError_En(json.GetParseError())), LOG_LEVEL_ERROR);
|
||||
return "";
|
||||
}
|
||||
|
||||
proxyToSingBox(nodes, json, ruleset_content_array, extra_proxy_group, ext);
|
||||
rulesetToSingBox(json, ruleset_content_array, ext.overwrite_original_rules);
|
||||
|
||||
return SerializeObject(json);
|
||||
}
|
||||
@@ -37,11 +37,11 @@ struct extra_settings
|
||||
tribool skip_cert_verify = tribool();
|
||||
tribool tls13 = tribool();
|
||||
bool clash_classical_ruleset = false;
|
||||
std::string sort_script = "";
|
||||
std::string sort_script;
|
||||
std::string clash_proxies_style = "flow";
|
||||
bool authorized = false;
|
||||
|
||||
extra_settings() {};
|
||||
extra_settings() = default;
|
||||
extra_settings(const extra_settings&) = delete;
|
||||
extra_settings(extra_settings&&) = delete;
|
||||
|
||||
@@ -57,9 +57,6 @@ struct extra_settings
|
||||
#endif // NO_JS_RUNTIME
|
||||
};
|
||||
|
||||
void rulesetToClash(YAML::Node &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name);
|
||||
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, std::string remote_path_prefix);
|
||||
|
||||
std::string proxyToClash(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, bool clashR, extra_settings &ext);
|
||||
void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupConfigs &extra_proxy_group, bool clashR, extra_settings &ext);
|
||||
std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, int surge_ver, extra_settings &ext);
|
||||
@@ -73,5 +70,6 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Ruleset
|
||||
std::string proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToSSD(std::vector<Proxy> &nodes, std::string &group, std::string &userinfo, extra_settings &ext);
|
||||
std::string proxyToSingBox(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
|
||||
#endif // SUBEXPORT_H_INCLUDED
|
||||
Reference in new issue
Block a user