From 572c415a23a0cbaa5a19d49553f266aaa96ec4cb Mon Sep 17 00:00:00 2001 From: arm64v8a <48624112+arm64v8a@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:53:41 +0900 Subject: [PATCH] update to clash meta format --- main/NekoRay_DataStore.hpp | 2 +- main/main.cpp | 10 ++++++ sub/GroupUpdater.cpp | 70 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/main/NekoRay_DataStore.hpp b/main/NekoRay_DataStore.hpp index 1961467d0..d353c10b0 100644 --- a/main/NekoRay_DataStore.hpp +++ b/main/NekoRay_DataStore.hpp @@ -93,7 +93,7 @@ namespace NekoRay { QString splitter_state = ""; // Subscription - QString user_agent = "Nekoray/1.0 (Prefer Clash Format)"; + QString user_agent = ""; // set at main.cpp bool sub_use_proxy = false; bool sub_clear = false; bool sub_insecure = false; diff --git a/main/main.cpp b/main/main.cpp index 2c1b3c0a8..35fb37947 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -244,6 +244,16 @@ int main(int argc, char* argv[]) { MW_dialog_message("", "Raise"); }); + // Do preset update + if (NekoRay::dataStore->user_agent.isEmpty() || NekoRay::dataStore->user_agent.startsWith("Nekoray/1.0") || NekoRay::dataStore->user_agent.startsWith("ClashForAndroid")) { + if (IS_NEKO_BOX) { + NekoRay::dataStore->user_agent = "NekoBox/PC/2.0 (Prefer ClashMeta Format)"; + } else { + NekoRay::dataStore->user_agent = "NekoRay/PC/2.0 (Prefer ClashMeta Format)"; + } + NekoRay::dataStore->Save(); + } + UI_InitMainWindow(); return QApplication::exec(); } diff --git a/sub/GroupUpdater.cpp b/sub/GroupUpdater.cpp index 7dac2f276..a7a88e70d 100644 --- a/sub/GroupUpdater.cpp +++ b/sub/GroupUpdater.cpp @@ -175,6 +175,23 @@ namespace NekoRay::sub { } } + QStringList Node2QStringList(const YAML::Node &n) { + try { + if (n.IsSequence()) { + QStringList list; + for (auto item: n) { + list << item.as().c_str(); + } + return list; + } else { + return {}; + } + } catch (const YAML::Exception &ex) { + qDebug() << ex.what(); + return {}; + } + } + int Node2Int(const YAML::Node &n, const int &def = 0) { try { return n.as(); @@ -188,6 +205,11 @@ namespace NekoRay::sub { try { return n.as(); } catch (const YAML::Exception &ex) { + try { + return n.as(); + } catch (const YAML::Exception &ex2) { + ex2.what(); + } qDebug() << ex.what(); return def; } @@ -211,8 +233,11 @@ namespace NekoRay::sub { auto proxies = YAML::Load(str.toStdString())["proxies"]; for (auto proxy: proxies) { auto type = Node2QString(proxy["type"]); + auto type_clash = type; + if (type == "ss" || type == "ssr") type = "shadowsocks"; if (type == "socks5") type = "socks"; + if (type == "hysteria") type = "custom"; auto ent = ProfileManager::NewProxyEntity(type); if (ent->bean->version == -114514) continue; @@ -261,14 +286,20 @@ namespace NekoRay::sub { bean->password = Node2QString(proxy["password"]); if (Node2Bool(proxy["tls"])) bean->stream->security = "tls"; if (Node2Bool(proxy["skip-cert-verify"])) bean->stream->allow_insecure = true; - } else if (type == "trojan") { + } else if (type == "trojan" || type == "vless") { needFix = true; auto bean = ent->TrojanVLESSBean(); - bean->password = Node2QString(proxy["password"]); + if (type == "vless") { + bean->flow = Node2QString(proxy["flow"]); + bean->password = Node2QString(proxy["uuid"]); + } else { + bean->password = Node2QString(proxy["password"]); + } bean->stream->security = "tls"; bean->stream->network = Node2QString(proxy["network"], "tcp"); bean->stream->sni = FIRST_OR_SECOND(Node2QString(proxy["sni"]), Node2QString(proxy["servername"])); if (Node2Bool(proxy["skip-cert-verify"])) bean->stream->allow_insecure = true; + if (IS_NEKO_BOX) bean->stream->utlsFingerprint = Node2QString(proxy["client-fingerprint"]); // opts auto ws = NodeChild(proxy, {"ws-opts", "ws-opt"}); @@ -286,6 +317,12 @@ namespace NekoRay::sub { if (grpc.IsMap()) { bean->stream->path = Node2QString(grpc["grpc-service-name"]); } + + auto reality = NodeChild(proxy, {"reality-opts"}); + if (reality.IsMap()) { + bean->stream->reality_pbk = Node2QString(reality["public-key"]); + bean->stream->reality_sid = Node2QString(reality["short-id"]); + } } else if (type == "vmess") { needFix = true; auto bean = ent->VMessBean(); @@ -341,6 +378,35 @@ namespace NekoRay::sub { break; } } + } else if (type_clash == "hysteria") { + if (!IS_NEKO_BOX) { + MW_show_log("Found Clash Meta format hysteria. This is only supported in NekoBox, please switch the core."); + continue; + } + + auto bean = ent->CustomBean(); + bean->core = "internal"; + + QJsonObject coreTlsObj{ + {"enabled", true}, + {"insecure", Node2Bool(proxy["skip-cert-verify"])}, + {"alpn", QList2QJsonArray(Node2QStringList(proxy["alpn"]))}, + {"server_name", Node2QString(proxy["sni"])}, + }; + + QJsonObject coreHysteriaObj{ + {"type", "hysteria"}, + {"tag", Node2QString(proxy["name"])}, + {"server", Node2QString(proxy["server"])}, + {"server_port", Node2Int(proxy["port"])}, + {"auth_str", Node2QString(proxy["auth_str"])}, + {"up_mbps", Node2Int(proxy["up"])}, + {"down_mbps", Node2Int(proxy["down"])}, + {"disable_mtu_discovery", Node2Bool(proxy["disable_mtu_discovery"])}, + {"tls", coreTlsObj}, + }; + + bean->config_simple = QJsonObject2QString(coreHysteriaObj, false); } else { continue; }