소스 검색

Enhancements

Add "auto" target to automatically determine target and other options by User-Agent.
inja: Update to latest version.
Tindy X 5 년 전
부모
커밋
58ba0dae08
4개의 변경된 파일955개의 추가작업 그리고 630개의 파일을 삭제
  1. 334 437
      include/inja.hpp
  2. 507 184
      include/nlohmann/json.hpp
  3. 100 4
      src/interfaces.cpp
  4. 14 5
      src/templates.cpp

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 334 - 437
include/inja.hpp


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 507 - 184
include/nlohmann/json.hpp


+ 100 - 4
src/interfaces.cpp

@@ -94,6 +94,97 @@ const string_array quanx_rule_type = {basic_types, "USER-AGENT", "HOST", "HOST-S
 const std::map<std::string, ruleset_type> ruleset_types = {{"clash-domain:", RULESET_CLASH_DOMAIN}, {"clash-ipcidr:", RULESET_CLASH_IPCIDR}, {"clash-classic:", RULESET_CLASH_CLASSICAL}, \
             {"quanx:", RULESET_QUANX}, {"surge:", RULESET_SURGE}};
 
+struct UAProfile
+{
+    std::string head;
+    std::string version_match;
+    std::string version_target;
+    std::string target;
+    tribool clash_new_name;
+    int surge_ver = -1;
+};
+
+const std::vector<UAProfile> UAMatchList = {
+    {"ClashForAndroid","\\/([0-9.]+)","2.0","clash",true},
+    {"ClashForAndroid","\\/([0-9.]+)R","","clashr",false},
+    {"ClashForAndroid","","","clash",false},
+    {"ClashforWindows","\\/([0-9.]+)","0.11","clash",true},
+    {"ClashforWindows","","","clash",false},
+    {"ClashX Pro","","","clash",true},
+    {"ClashX","\\/([0-9.]+)","0.13","clash",true},
+    {"Clash","","","clash",true},
+    {"Kitsunebi","","","v2ray"},
+    {"LoonWidget","","","loon"},
+    {"Pharos","","","mixed"},
+    {"Potatso","","","mixed"},
+    {"Quantumult%20X","","","quanx"},
+    {"Quantumult","","","quan"},
+    {"Qv2ray","","","v2ray"},
+    {"Shadowrocket","","","mixed"},
+    {"Surfboard","","","surfboard"},
+    {"Surge","\\/([0-9.]+).*x86","906","surge",false,4}, /// Surge for Mac (supports VMess)
+    {"Surge","\\/([0-9.]+).*x86","368","surge",false,3}, /// Surge for Mac (supports new rule types and Shadowsocks without plugin)
+    {"Surge","\\/([0-9.]+)","1419","surge",false,4}, /// Surge iOS 4 (first version)
+    {"Surge","\\/([0-9.]+)","900","surge",false,3}, /// Surge iOS 3 (approx)
+    {"Surge","","","surge",false,2}, /// any version of Surge as fallback
+    {"Trojan-Qt5","","","trojan"},
+    {"V2rayU","","","v2ray"},
+    {"V2RayX","","","v2ray"}
+};
+
+bool verGreaterEqual(const std::string &src_ver, const std::string &target_ver)
+{
+    int part_src, part_target;
+    string_size src_pos_beg = 0, src_pos_end = 0, target_pos_beg = 0, target_pos_end = 0;
+    while(true)
+    {
+        src_pos_end = src_ver.find('.', src_pos_beg);
+        if(src_pos_end == src_ver.npos)
+            src_pos_end = src_ver.size();
+        part_src = std::stoi(src_ver.substr(src_pos_beg, src_pos_end - src_pos_beg));
+        target_pos_end = target_ver.find('.', target_pos_beg);
+        if(target_pos_end == target_ver.npos)
+            target_pos_end = target_ver.size();
+        part_target = std::stoi(target_ver.substr(target_pos_beg, target_pos_end - target_pos_beg));
+        if(part_src > part_target)
+            break;
+        else if(part_src < part_target)
+            return false;
+        else if(src_pos_end >= src_ver.size() - 1 || target_pos_end >= target_ver.size() - 1)
+            break;
+        src_pos_beg = src_pos_end + 1;
+        target_pos_beg = target_pos_end + 1;
+    }
+    return true;
+
+}
+
+void matchUserAgent(const std::string &user_agent, std::string &target, tribool &clash_new_name, int &surge_ver)
+{
+    if(user_agent.empty())
+        return;
+    for(const UAProfile &x : UAMatchList)
+    {
+        if(startsWith(user_agent, x.head))
+        {
+            if(!x.version_match.empty())
+            {
+                std::string version;
+                if(regGetMatch(user_agent, x.version_match, 2, 0, &version))
+                    continue;
+                if(!x.version_target.empty() && !verGreaterEqual(version, x.version_target))
+                    continue;
+            }
+            target = x.target;
+            clash_new_name = x.clash_new_name;
+            if(x.surge_ver != -1)
+                surge_ver = x.surge_ver;
+            return;
+        }
+    }
+    return;
+}
+
 std::string convertRuleset(const std::string &content, int type)
 {
     /// Target: Surge type,pattern[,flag]
@@ -1268,7 +1359,12 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
     std::string &argument = request.argument;
     int *status_code = &response.status_code;
 
-    std::string target = getUrlArg(argument, "target");
+    std::string target = getUrlArg(argument, "target"), version = getUrlArg(argument, "ver");
+    tribool clash_new_field = getUrlArg(argument, "new_name");
+    int surge_ver = version.size() ? to_int(version, 3) : 3;
+    if(target == "auto")
+        matchUserAgent(request.headers["X-User-Agent"], target, clash_new_field, surge_ver);
+
     switch(hash_(target))
     {
     case "clash"_hash: case "clashr"_hash: case "surge"_hash: case "quan"_hash: case "quanx"_hash: case "loon"_hash: case "surfboard"_hash: case "mellow"_hash: case "ss"_hash: case "ssd"_hash: case "ssr"_hash: case "sssub"_hash: case "v2ray"_hash: case "trojan"_hash: case "mixed"_hash:
@@ -1283,7 +1379,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
 
     /// string values
     std::string url = UrlDecode(getUrlArg(argument, "url"));
-    std::string group = UrlDecode(getUrlArg(argument, "group")), upload_path = getUrlArg(argument, "upload_path"), version = getUrlArg(argument, "ver");
+    std::string group = UrlDecode(getUrlArg(argument, "group")), upload_path = getUrlArg(argument, "upload_path");
     std::string include = UrlDecode(getUrlArg(argument, "include")), exclude = UrlDecode(getUrlArg(argument, "exclude"));
     std::string groups = urlsafe_base64_decode(getUrlArg(argument, "groups")), ruleset = urlsafe_base64_decode(getUrlArg(argument, "ruleset")), config = UrlDecode(getUrlArg(argument, "config"));
     std::string dev_id = getUrlArg(argument, "dev_id"), filename = getUrlArg(argument, "filename"), interval_str = getUrlArg(argument, "interval"), strict_str = getUrlArg(argument, "strict");
@@ -1293,7 +1389,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
     tribool upload = getUrlArg(argument, "upload"), emoji = getUrlArg(argument, "emoji"), emoji_add = getUrlArg(argument, "add_emoji"), emoji_remove = getUrlArg(argument, "remove_emoji");
     tribool append_type = getUrlArg(argument, "append_type"), tfo = getUrlArg(argument, "tfo"), udp = getUrlArg(argument, "udp"), nodelist = getUrlArg(argument, "list");
     tribool sort_flag = getUrlArg(argument, "sort"), use_sort_script = getUrlArg(argument, "sort_script");
-    tribool clash_new_field = getUrlArg(argument, "new_name"), clash_script = getUrlArg(argument, "script"), add_insert = getUrlArg(argument, "insert");
+    tribool clash_script = getUrlArg(argument, "script"), add_insert = getUrlArg(argument, "insert");
     tribool scv = getUrlArg(argument, "scv"), fdn = getUrlArg(argument, "fdn"), expand = getUrlArg(argument, "expand"), append_sub_userinfo = getUrlArg(argument, "append_info");
     tribool prepend_insert = getUrlArg(argument, "prepend"), classical = getUrlArg(argument, "classic"), tls13 = getUrlArg(argument, "tls13");
 
@@ -1632,7 +1728,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
             uploadGist(target, upload_path, output_content, false);
         break;
     case "surge"_hash:
-        surge_ver = version.size() ? to_int(version, 3) : 3;
+
         writeLog(0, "Generate target: Surge " + std::to_string(surge_ver), LOG_LEVEL_INFO);
 
         if(ext.nodelist)

+ 14 - 5
src/templates.cpp

@@ -13,6 +13,14 @@
 
 extern std::string managed_config_prefix;
 
+namespace inja
+{
+    void convert_dot_to_json_pointer(nonstd::string_view dot, std::string& out)
+    {
+        out = std::move(JsonNode(dot, 0).ptr);
+    }
+}
+
 static inline void parse_json_pointer(nlohmann::json &json, const std::string &path, const std::string &value)
 {
     std::string pointer;
@@ -52,6 +60,7 @@ int render_template(const std::string &content, const template_args &vars, std::
     inja::FunctionStorage m_callbacks;
     inja::TemplateStorage m_included_templates;
     inja::ParserConfig m_parser_config;
+    inja::RenderConfig m_render_config;
 
     m_lexer_config.trim_blocks = true;
     m_lexer_config.lstrip_blocks = true;
@@ -99,7 +108,7 @@ int render_template(const std::string &content, const template_args &vars, std::
             parse_json_pointer(data, dest + "." + std::to_string(index), vArray[index]);
         return std::string();
     });
-    m_callbacks.add_callback("join", INJA_VARARGS, [](inja::Arguments &args)
+    m_callbacks.add_callback("join", -1, [](inja::Arguments &args)
     {
         std::string result;
         for(auto iter = args.begin(); iter != args.end(); iter++)
@@ -134,14 +143,14 @@ int render_template(const std::string &content, const template_args &vars, std::
     {
         return endsWith(args.at(0)->get<std::string>(), args.at(1)->get<std::string>());
     });
-    m_callbacks.add_callback("or", INJA_VARARGS, [](inja::Arguments &args)
+    m_callbacks.add_callback("or", -1, [](inja::Arguments &args)
     {
         for(auto iter = args.begin(); iter != args.end(); iter++)
             if((*iter)->get<int>())
                 return true;
         return false;
     });
-    m_callbacks.add_callback("and", INJA_VARARGS, [](inja::Arguments &args)
+    m_callbacks.add_callback("and", -1, [](inja::Arguments &args)
     {
         for(auto iter = args.begin(); iter != args.end(); iter++)
             if(!(*iter)->get<int>())
@@ -169,8 +178,8 @@ int render_template(const std::string &content, const template_args &vars, std::
     m_parser_config.include_scope_limit = true;
     m_parser_config.include_scope = include_scope;
 
-    inja::Parser parser(m_parser_config, m_lexer_config, m_included_templates);
-    inja::Renderer renderer(m_included_templates, m_callbacks);
+    inja::Parser parser(m_parser_config, m_lexer_config, m_included_templates, m_callbacks);
+    inja::Renderer renderer(m_render_config, m_included_templates, m_callbacks);
 
     try
     {

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.