mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 20:44:38 +03:00
Add hysteria gui
This commit is contained in:
@@ -213,6 +213,10 @@ set(PROJECT_SOURCES
|
|||||||
ui/edit/edit_naive.cpp
|
ui/edit/edit_naive.cpp
|
||||||
ui/edit/edit_naive.ui
|
ui/edit/edit_naive.ui
|
||||||
|
|
||||||
|
ui/edit/edit_hysteria.h
|
||||||
|
ui/edit/edit_hysteria.cpp
|
||||||
|
ui/edit/edit_hysteria.ui
|
||||||
|
|
||||||
ui/edit/edit_custom.h
|
ui/edit/edit_custom.h
|
||||||
ui/edit/edit_custom.cpp
|
ui/edit/edit_custom.cpp
|
||||||
ui/edit/edit_custom.ui
|
ui/edit/edit_custom.ui
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
#define BOX_UNDERLYING_DNS NekoRay::dataStore->core_box_underlying_dns.isEmpty() ? "underlying://0.0.0.0" : NekoRay::dataStore->core_box_underlying_dns
|
#define BOX_UNDERLYING_DNS NekoRay::dataStore->core_box_underlying_dns.isEmpty() ? "underlying://0.0.0.0" : NekoRay::dataStore->core_box_underlying_dns
|
||||||
|
#define BOX_UNDERLYING_DNS_EXPORT NekoRay::dataStore->core_box_underlying_dns.isEmpty() ? "local" : NekoRay::dataStore->core_box_underlying_dns
|
||||||
|
|
||||||
namespace NekoRay {
|
namespace NekoRay {
|
||||||
|
|
||||||
@@ -769,7 +770,7 @@ namespace NekoRay {
|
|||||||
|
|
||||||
// Direct
|
// Direct
|
||||||
auto directDNSAddress = dataStore->direct_dns;
|
auto directDNSAddress = dataStore->direct_dns;
|
||||||
if (directDNSAddress == "localhost") directDNSAddress = BOX_UNDERLYING_DNS;
|
if (directDNSAddress == "localhost") directDNSAddress = BOX_UNDERLYING_DNS_EXPORT;
|
||||||
if (!status->forTest)
|
if (!status->forTest)
|
||||||
dnsServers += QJsonObject{
|
dnsServers += QJsonObject{
|
||||||
{"tag", "dns-direct"},
|
{"tag", "dns-direct"},
|
||||||
@@ -782,7 +783,7 @@ namespace NekoRay {
|
|||||||
// Underlying 100% Working DNS
|
// Underlying 100% Working DNS
|
||||||
dnsServers += QJsonObject{
|
dnsServers += QJsonObject{
|
||||||
{"tag", "dns-local"},
|
{"tag", "dns-local"},
|
||||||
{"address", BOX_UNDERLYING_DNS},
|
{"address", BOX_UNDERLYING_DNS_EXPORT},
|
||||||
{"detour", "direct"},
|
{"detour", "direct"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ namespace NekoRay {
|
|||||||
bean = new fmt::TrojanVLESSBean(fmt::TrojanVLESSBean::proxy_VLESS);
|
bean = new fmt::TrojanVLESSBean(fmt::TrojanVLESSBean::proxy_VLESS);
|
||||||
} else if (type == "naive") {
|
} else if (type == "naive") {
|
||||||
bean = new fmt::NaiveBean();
|
bean = new fmt::NaiveBean();
|
||||||
|
} else if (type == "hysteria") {
|
||||||
|
bean = new fmt::HysteriaBean();
|
||||||
} else if (type == "custom") {
|
} else if (type == "custom") {
|
||||||
bean = new fmt::CustomBean();
|
bean = new fmt::CustomBean();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ namespace NekoRay {
|
|||||||
|
|
||||||
class NaiveBean;
|
class NaiveBean;
|
||||||
|
|
||||||
|
class HysteriaBean;
|
||||||
|
|
||||||
class CustomBean;
|
class CustomBean;
|
||||||
|
|
||||||
class ChainBean;
|
class ChainBean;
|
||||||
@@ -63,6 +65,10 @@ namespace NekoRay {
|
|||||||
return (fmt::NaiveBean *) bean.get();
|
return (fmt::NaiveBean *) bean.get();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] fmt::HysteriaBean *HysteriaBean() const {
|
||||||
|
return (fmt::HysteriaBean *) bean.get();
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]] fmt::CustomBean *CustomBean() const {
|
[[nodiscard]] fmt::CustomBean *CustomBean() const {
|
||||||
return (fmt::CustomBean *) bean.get();
|
return (fmt::CustomBean *) bean.get();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -135,6 +135,34 @@ namespace NekoRay::fmt {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoreObjOutboundBuildResult HysteriaBean::BuildCoreObjSingBox() {
|
||||||
|
CoreObjOutboundBuildResult result;
|
||||||
|
|
||||||
|
QJsonObject coreTlsObj{
|
||||||
|
{"enabled", true},
|
||||||
|
{"insecure", allowInsecure},
|
||||||
|
};
|
||||||
|
if (!alpn.trimmed().isEmpty()) coreTlsObj["alpn"] = QJsonArray{alpn};
|
||||||
|
|
||||||
|
QJsonObject coreHysteriaObj{
|
||||||
|
{"type", "hysteria"},
|
||||||
|
{"server", serverAddress},
|
||||||
|
{"server_port", serverPort},
|
||||||
|
{"disable_mtu_discovery", disableMtuDiscovery},
|
||||||
|
{"recv_window", streamReceiveWindow},
|
||||||
|
{"recv_window_conn", connectionReceiveWindow},
|
||||||
|
{"up_mbps", uploadMbps},
|
||||||
|
{"down_mbps", downloadMbps},
|
||||||
|
{"tls", coreTlsObj},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (authPayloadType == hysteria_auth_base64) coreHysteriaObj["auth"] = authPayload;
|
||||||
|
if (authPayloadType == hysteria_auth_string) coreHysteriaObj["auth_str"] = authPayload;
|
||||||
|
|
||||||
|
result.outbound = coreHysteriaObj;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
CoreObjOutboundBuildResult CustomBean::BuildCoreObjSingBox() {
|
CoreObjOutboundBuildResult CustomBean::BuildCoreObjSingBox() {
|
||||||
CoreObjOutboundBuildResult result;
|
CoreObjOutboundBuildResult result;
|
||||||
|
|
||||||
|
|||||||
@@ -31,13 +31,28 @@ namespace NekoRay::fmt {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CustomBean::NeedExternal(bool isFirstProfile, bool isVPN) {
|
int HysteriaBean::NeedExternal(bool isFirstProfile, bool isVPN) {
|
||||||
if (core == "internal" || core == "internal-full") return 0;
|
if (IS_NEKO_BOX) {
|
||||||
if (core == "hysteria") {
|
if (protocol == hysteria_protocol_udp && hopPort.trimmed().isEmpty()) {
|
||||||
|
// sing-box support
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
// hysteria core support
|
||||||
|
if (isFirstProfile && !isVPN) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (isFirstProfile && !isVPN) {
|
if (isFirstProfile && !isVPN) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CustomBean::NeedExternal(bool isFirstProfile, bool isVPN) {
|
||||||
|
if (core == "internal" || core == "internal-full") return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +79,8 @@ namespace NekoRay::fmt {
|
|||||||
if (domain_address != connect_address)
|
if (domain_address != connect_address)
|
||||||
result.arguments += "--host-resolver-rules=MAP " + domain_address + " " + connect_address;
|
result.arguments += "--host-resolver-rules=MAP " + domain_address + " " + connect_address;
|
||||||
if (insecure_concurrency > 0) result.arguments += "--insecure-concurrency=" + Int2String(insecure_concurrency);
|
if (insecure_concurrency > 0) result.arguments += "--insecure-concurrency=" + Int2String(insecure_concurrency);
|
||||||
if (!extra_headers.isEmpty()) result.arguments += "--extra-headers=" + extra_headers;
|
if (!extra_headers.trimmed().isEmpty()) result.arguments += "--extra-headers=" + extra_headers;
|
||||||
if (!certificate.isEmpty()) {
|
if (!certificate.trimmed().isEmpty()) {
|
||||||
WriteTempFile("naive_" + GetRandomString(10) + ".crt", certificate.toUtf8());
|
WriteTempFile("naive_" + GetRandomString(10) + ".crt", certificate.toUtf8());
|
||||||
result.env += "SSL_CERT_FILE=" + TempFile;
|
result.env += "SSL_CERT_FILE=" + TempFile;
|
||||||
}
|
}
|
||||||
@@ -77,6 +92,67 @@ namespace NekoRay::fmt {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExternalBuildResult HysteriaBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
|
||||||
|
ExternalBuildResult result{dataStore->extraCore->Get("hysteria")};
|
||||||
|
|
||||||
|
QJsonObject config;
|
||||||
|
|
||||||
|
// determine server format
|
||||||
|
auto is_direct = external_stat == 2;
|
||||||
|
auto sni2 = sni;
|
||||||
|
if (sni.isEmpty() && is_direct) sni2 = serverAddress;
|
||||||
|
|
||||||
|
auto server = serverAddress;
|
||||||
|
if (!hopPort.trimmed().isEmpty()) {
|
||||||
|
server = WrapIPV6Host(server) + ":" + hopPort;
|
||||||
|
} else {
|
||||||
|
server = WrapIPV6Host(server) + ":" + Int2String(serverPort);
|
||||||
|
}
|
||||||
|
config["server"] = is_direct ? server : "127.0.0.1:" + Int2String(mapping_port);
|
||||||
|
|
||||||
|
// listen
|
||||||
|
config["socks5"] = QJsonObject{
|
||||||
|
{"listen", "127.0.0.1:" + Int2String(socks_port)},
|
||||||
|
};
|
||||||
|
|
||||||
|
// misc
|
||||||
|
|
||||||
|
config["retry"] = 5;
|
||||||
|
config["fast_open"] = true;
|
||||||
|
config["lazy_start"] = true;
|
||||||
|
config["obfs"] = obfsPassword;
|
||||||
|
config["up_mbps"] = uploadMbps;
|
||||||
|
config["down_mbps"] = downloadMbps;
|
||||||
|
|
||||||
|
if (authPayloadType == hysteria_auth_base64) config["auth"] = authPayload;
|
||||||
|
if (authPayloadType == hysteria_auth_string) config["auth_str"] = authPayload;
|
||||||
|
|
||||||
|
if (protocol == hysteria_protocol_facktcp) config["protocol"] = "faketcp";
|
||||||
|
if (protocol == hysteria_protocol_wechat_video) config["protocol"] = "wechat-video";
|
||||||
|
|
||||||
|
if (!sni2.isEmpty()) config["server_name"] = sni2;
|
||||||
|
if (!alpn.isEmpty()) config["alpn"] = alpn;
|
||||||
|
|
||||||
|
if (!caText.trimmed().isEmpty()) {
|
||||||
|
WriteTempFile("hysteria_" + GetRandomString(10) + ".crt", caText.toUtf8());
|
||||||
|
config["ca"] = TempFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowInsecure) config["insecure"] = true;
|
||||||
|
if (streamReceiveWindow > 0) config["recv_window_conn"] = streamReceiveWindow;
|
||||||
|
if (connectionReceiveWindow > 0) config["recv_window"] = connectionReceiveWindow;
|
||||||
|
if (disableMtuDiscovery) config["disable_mtu_discovery"] = true;
|
||||||
|
config["hop_interval"] = hopInterval;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
result.config_export = QJsonObject2QString(config, false);
|
||||||
|
WriteTempFile("hysteria_" + GetRandomString(10) + ".json", result.config_export.toUtf8());
|
||||||
|
result.arguments = QStringList{"--no-check", "-c", TempFile};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
|
ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
|
||||||
ExternalBuildResult result{dataStore->extraCore->Get(core)};
|
ExternalBuildResult result{dataStore->extraCore->Get(core)};
|
||||||
|
|
||||||
@@ -107,14 +183,6 @@ namespace NekoRay::fmt {
|
|||||||
suffix = ".json";
|
suffix = ".json";
|
||||||
}
|
}
|
||||||
|
|
||||||
// known core direct out
|
|
||||||
if (external_stat == 2) {
|
|
||||||
if (core == "hysteria") {
|
|
||||||
config = config.replace(QString("\"127.0.0.1:%1\"").arg(mapping_port),
|
|
||||||
"\"" + DisplayAddress() + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write config
|
// write config
|
||||||
WriteTempFile("custom_" + GetRandomString(10) + suffix, config.toUtf8());
|
WriteTempFile("custom_" + GetRandomString(10) + suffix, config.toUtf8());
|
||||||
for (int i = 0; i < result.arguments.count(); i++) {
|
for (int i = 0; i < result.arguments.count(); i++) {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ namespace NekoRay::fmt {
|
|||||||
{"tls", stream->security == "tls" ? "tls" : ""},
|
{"tls", stream->security == "tls" ? "tls" : ""},
|
||||||
{"sni", stream->sni},
|
{"sni", stream->sni},
|
||||||
};
|
};
|
||||||
return "vmess://" + QJsonObject2QString(N, false).toUtf8().toBase64();
|
return "vmess://" + QJsonObject2QString(N, true).toUtf8().toBase64();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString NaiveBean::ToShareLink() {
|
QString NaiveBean::ToShareLink() {
|
||||||
@@ -116,4 +116,30 @@ namespace NekoRay::fmt {
|
|||||||
return url.toString(QUrl::FullyEncoded);
|
return url.toString(QUrl::FullyEncoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString HysteriaBean::ToShareLink() {
|
||||||
|
QUrl url;
|
||||||
|
url.setScheme("hysteria");
|
||||||
|
url.setHost(serverAddress);
|
||||||
|
url.setPort(serverPort);
|
||||||
|
QUrlQuery q;
|
||||||
|
q.addQueryItem("upmbps", Int2String(uploadMbps));
|
||||||
|
q.addQueryItem("downmbps", Int2String(downloadMbps));
|
||||||
|
if (!obfsPassword.isEmpty()) {
|
||||||
|
q.addQueryItem("obfs", "xplus");
|
||||||
|
q.addQueryItem("obfsParam", obfsPassword);
|
||||||
|
}
|
||||||
|
if (authPayloadType == hysteria_auth_string) q.addQueryItem("auth", authPayload);
|
||||||
|
if (protocol == hysteria_protocol_facktcp) q.addQueryItem("protocol", "faketcp");
|
||||||
|
if (protocol == hysteria_protocol_wechat_video) q.addQueryItem("protocol", "wechat-video");
|
||||||
|
if (!hopPort.trimmed().isEmpty()) q.addQueryItem("mport", hopPort);
|
||||||
|
if (allowInsecure) q.addQueryItem("insecure", "1");
|
||||||
|
if (!sni.isEmpty()) q.addQueryItem("peer", sni);
|
||||||
|
if (!alpn.isEmpty()) q.addQueryItem("alpn", alpn);
|
||||||
|
if (connectionReceiveWindow > 0) q.addQueryItem("recv_window", Int2String(connectionReceiveWindow));
|
||||||
|
if (streamReceiveWindow > 0) q.addQueryItem("recv_window_conn", Int2String(streamReceiveWindow));
|
||||||
|
if (!q.isEmpty()) url.setQuery(q);
|
||||||
|
if (!name.isEmpty()) url.setFragment(name);
|
||||||
|
return url.toString(QUrl::FullyEncoded);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace NekoRay::fmt
|
} // namespace NekoRay::fmt
|
||||||
80
fmt/HysteriaBean.hpp
Normal file
80
fmt/HysteriaBean.hpp
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fmt/AbstractBean.hpp"
|
||||||
|
|
||||||
|
namespace NekoRay::fmt {
|
||||||
|
class HysteriaBean : public AbstractBean {
|
||||||
|
public:
|
||||||
|
static constexpr int hysteria_protocol_udp = 0;
|
||||||
|
static constexpr int hysteria_protocol_facktcp = 1;
|
||||||
|
static constexpr int hysteria_protocol_wechat_video = 2;
|
||||||
|
|
||||||
|
int protocol = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
static constexpr int hysteria_auth_none = 0;
|
||||||
|
static constexpr int hysteria_auth_string = 1;
|
||||||
|
static constexpr int hysteria_auth_base64 = 2;
|
||||||
|
|
||||||
|
int authPayloadType = 0;
|
||||||
|
QString authPayload = "";
|
||||||
|
QString obfsPassword = "";
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
int uploadMbps = 100;
|
||||||
|
int downloadMbps = 100;
|
||||||
|
|
||||||
|
qint64 streamReceiveWindow = 0;
|
||||||
|
qint64 connectionReceiveWindow = 0;
|
||||||
|
bool disableMtuDiscovery = false;
|
||||||
|
|
||||||
|
bool allowInsecure = false;
|
||||||
|
QString sni = "";
|
||||||
|
QString alpn = ""; // only 1
|
||||||
|
QString caText = "";
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
int hopInterval = 10;
|
||||||
|
QString hopPort = "";
|
||||||
|
|
||||||
|
HysteriaBean() : AbstractBean(0) {
|
||||||
|
_add(new configItem("protocol", &protocol, itemType::integer));
|
||||||
|
_add(new configItem("authPayloadType", &authPayloadType, itemType::integer));
|
||||||
|
_add(new configItem("authPayload", &authPayload, itemType::string));
|
||||||
|
_add(new configItem("obfsPassword", &obfsPassword, itemType::string));
|
||||||
|
_add(new configItem("uploadMbps", &uploadMbps, itemType::integer));
|
||||||
|
_add(new configItem("downloadMbps", &downloadMbps, itemType::integer));
|
||||||
|
_add(new configItem("streamReceiveWindow", &streamReceiveWindow, itemType::integer64));
|
||||||
|
_add(new configItem("connectionReceiveWindow", &connectionReceiveWindow, itemType::integer64));
|
||||||
|
_add(new configItem("disableMtuDiscovery", &disableMtuDiscovery, itemType::boolean));
|
||||||
|
_add(new configItem("allowInsecure", &allowInsecure, itemType::boolean));
|
||||||
|
_add(new configItem("sni", &sni, itemType::string));
|
||||||
|
_add(new configItem("alpn", &alpn, itemType::string));
|
||||||
|
_add(new configItem("caText", &caText, itemType::string));
|
||||||
|
_add(new configItem("hopInterval", &hopInterval, itemType::integer));
|
||||||
|
_add(new configItem("hopPort", &hopPort, itemType::string));
|
||||||
|
};
|
||||||
|
|
||||||
|
QString DisplayAddress() override {
|
||||||
|
if (!hopPort.trimmed().isEmpty()) return WrapIPV6Host(serverAddress) + ":" + hopPort;
|
||||||
|
return ::DisplayAddress(serverAddress, serverPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DisplayCoreType() override { return NeedExternal(false, false) == 0 ? software_core_name : "Hysteria"; };
|
||||||
|
|
||||||
|
QString DisplayType() override { return "Hysteria"; };
|
||||||
|
|
||||||
|
int NeedExternal(bool isFirstProfile, bool isVPN) override;
|
||||||
|
|
||||||
|
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;
|
||||||
|
|
||||||
|
CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
|
||||||
|
|
||||||
|
bool TryParseLink(const QString &link);
|
||||||
|
|
||||||
|
QString ToShareLink() override;
|
||||||
|
};
|
||||||
|
} // namespace NekoRay::fmt
|
||||||
@@ -176,4 +176,41 @@ namespace NekoRay::fmt {
|
|||||||
return !(username.isEmpty() || password.isEmpty());
|
return !(username.isEmpty() || password.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HysteriaBean::TryParseLink(const QString &link) {
|
||||||
|
// https://hysteria.network/docs/uri-scheme/
|
||||||
|
auto url = QUrl(link);
|
||||||
|
auto query = QUrlQuery(url.query());
|
||||||
|
if (url.host().isEmpty() || url.port() == -1 || !query.hasQueryItem("upmbps") || !query.hasQueryItem("downmbps")) return false;
|
||||||
|
|
||||||
|
name = url.fragment();
|
||||||
|
serverAddress = url.host();
|
||||||
|
serverPort = url.port();
|
||||||
|
serverAddress = url.host(); // default sni
|
||||||
|
hopPort = query.queryItemValue("mport");
|
||||||
|
obfsPassword = query.queryItemValue("obfsParam");
|
||||||
|
allowInsecure = query.queryItemValue("insecure") == "1";
|
||||||
|
uploadMbps = query.queryItemValue("upmbps").toInt();
|
||||||
|
downloadMbps = query.queryItemValue("downmbps").toInt();
|
||||||
|
|
||||||
|
auto protocolStr = (query.hasQueryItem("protocol") ? query.queryItemValue("protocol") : "udp").toLower();
|
||||||
|
if (protocolStr == "faketcp") {
|
||||||
|
protocol = fmt::HysteriaBean::hysteria_protocol_facktcp;
|
||||||
|
} else if (protocolStr.startsWith("wechat")) {
|
||||||
|
protocol = fmt::HysteriaBean::hysteria_protocol_wechat_video;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.hasQueryItem("auth")) {
|
||||||
|
authPayload = query.queryItemValue("auth");
|
||||||
|
authPayloadType = fmt::HysteriaBean::hysteria_auth_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
alpn = query.queryItemValue("alpn");
|
||||||
|
sni = FIRST_OR_SECOND(query.queryItemValue("peer"), query.queryItemValue("sni"));
|
||||||
|
|
||||||
|
connectionReceiveWindow = query.queryItemValue("recv_window").toInt();
|
||||||
|
streamReceiveWindow = query.queryItemValue("recv_window_conn").toInt();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace NekoRay::fmt
|
} // namespace NekoRay::fmt
|
||||||
|
|||||||
@@ -1,21 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Preset {
|
namespace Preset {
|
||||||
namespace Hysteria {
|
|
||||||
inline const char *command = "--no-check -c %config%";
|
|
||||||
inline const char *config =
|
|
||||||
"{\n"
|
|
||||||
" \"server\": \"127.0.0.1:%mapping_port%\",\n"
|
|
||||||
" \"server_name\": \"example.com\",\n"
|
|
||||||
" \"obfs\": \"fuck me till the daylight\",\n"
|
|
||||||
" \"up_mbps\": 10,\n"
|
|
||||||
" \"down_mbps\": 50,\n"
|
|
||||||
" \"socks5\": {\n"
|
|
||||||
" \"listen\": \"127.0.0.1:%socks_port%\"\n"
|
|
||||||
" }\n"
|
|
||||||
"}";
|
|
||||||
} // namespace Hysteria
|
|
||||||
|
|
||||||
namespace V2Ray {
|
namespace V2Ray {
|
||||||
inline QStringList UtlsFingerPrint = {"", "randomized", "randomizedalpn", "randomizednoalpn", "firefox_auto", "firefox_55", "firefox_56", "firefox_63", "firefox_65", "firefox_99", "firefox_102", "firefox_105", "chrome_auto", "chrome_58", "chrome_62", "chrome_70", "chrome_72", "chrome_83", "chrome_87", "chrome_96", "chrome_100", "chrome_102", "ios_auto", "ios_11_1", "ios_12_1", "ios_13", "ios_14", "android_11_okhttp", "edge_auto", "edge_85", "edge_106", "safari_auto", "safari_16_0", "360_auto", "360_7_5", "360_11_0", "qq_auto", "qq_11_1"};
|
inline QStringList UtlsFingerPrint = {"", "randomized", "randomizedalpn", "randomizednoalpn", "firefox_auto", "firefox_55", "firefox_56", "firefox_63", "firefox_65", "firefox_99", "firefox_102", "firefox_105", "chrome_auto", "chrome_58", "chrome_62", "chrome_70", "chrome_72", "chrome_83", "chrome_87", "chrome_96", "chrome_100", "chrome_102", "ios_auto", "ios_11_1", "ios_12_1", "ios_13", "ios_14", "android_11_okhttp", "edge_auto", "edge_85", "edge_106", "safari_auto", "safari_16_0", "360_auto", "360_7_5", "360_11_0", "qq_auto", "qq_11_1"};
|
||||||
} // namespace V2Ray
|
} // namespace V2Ray
|
||||||
|
|||||||
@@ -6,4 +6,5 @@
|
|||||||
#include "VMessBean.hpp"
|
#include "VMessBean.hpp"
|
||||||
#include "TrojanVLESSBean.hpp"
|
#include "TrojanVLESSBean.hpp"
|
||||||
#include "NaiveBean.hpp"
|
#include "NaiveBean.hpp"
|
||||||
|
#include "HysteriaBean.hpp"
|
||||||
#include "CustomBean.hpp"
|
#include "CustomBean.hpp"
|
||||||
|
|||||||
@@ -17,16 +17,17 @@
|
|||||||
|
|
||||||
// NekoRay Save&Load
|
// NekoRay Save&Load
|
||||||
|
|
||||||
|
#define P_C_LOAD_STRING(a) CACHE.a = bean->a;
|
||||||
|
#define P_C_SAVE_STRING(a) bean->a = CACHE.a;
|
||||||
|
#define D_C_LOAD_STRING(a) CACHE.a = NekoRay::dataStore->a;
|
||||||
|
#define D_C_SAVE_STRING(a) NekoRay::dataStore->a = CACHE.a;
|
||||||
|
|
||||||
#define P_LOAD_STRING(a) ui->a->setText(bean->a);
|
#define P_LOAD_STRING(a) ui->a->setText(bean->a);
|
||||||
#define P_SAVE_STRING(a) bean->a = ui->a->text();
|
#define P_SAVE_STRING(a) bean->a = ui->a->text();
|
||||||
#define P_SAVE_STRING_QTEXTEDIT(a) bean->a = ui->a->toPlainText();
|
#define P_SAVE_STRING_QTEXTEDIT(a) bean->a = ui->a->toPlainText();
|
||||||
#define D_LOAD_STRING(a) ui->a->setText(NekoRay::dataStore->a);
|
#define D_LOAD_STRING(a) ui->a->setText(NekoRay::dataStore->a);
|
||||||
#define D_SAVE_STRING(a) NekoRay::dataStore->a = ui->a->text();
|
#define D_SAVE_STRING(a) NekoRay::dataStore->a = ui->a->text();
|
||||||
#define D_SAVE_STRING_QTEXTEDIT(a) NekoRay::dataStore->a = ui->a->toPlainText();
|
#define D_SAVE_STRING_QTEXTEDIT(a) NekoRay::dataStore->a = ui->a->toPlainText();
|
||||||
#define P_C_LOAD_STRING(a) CACHE.a = bean->a;
|
|
||||||
#define P_C_SAVE_STRING(a) bean->a = CACHE.a;
|
|
||||||
#define D_C_LOAD_STRING(a) CACHE.a = NekoRay::dataStore->a;
|
|
||||||
#define D_C_SAVE_STRING(a) NekoRay::dataStore->a = CACHE.a;
|
|
||||||
#define P_LOAD_INT(a) \
|
#define P_LOAD_INT(a) \
|
||||||
ui->a->setText(Int2String(bean->a)); \
|
ui->a->setText(Int2String(bean->a)); \
|
||||||
ui->a->setValidator(QRegExpValidator_Number);
|
ui->a->setValidator(QRegExpValidator_Number);
|
||||||
@@ -35,10 +36,14 @@
|
|||||||
ui->a->setText(Int2String(NekoRay::dataStore->a)); \
|
ui->a->setText(Int2String(NekoRay::dataStore->a)); \
|
||||||
ui->a->setValidator(QRegExpValidator_Number);
|
ui->a->setValidator(QRegExpValidator_Number);
|
||||||
#define D_SAVE_INT(a) NekoRay::dataStore->a = ui->a->text().toInt();
|
#define D_SAVE_INT(a) NekoRay::dataStore->a = ui->a->text().toInt();
|
||||||
#define P_LOAD_COMBO(a) ui->a->setCurrentText(bean->a);
|
#define P_LOAD_COMBO_STR(a) ui->a->setCurrentText(bean->a);
|
||||||
#define P_SAVE_COMBO(a) bean->a = ui->a->currentText();
|
#define P_SAVE_COMBO_STR(a) bean->a = ui->a->currentText();
|
||||||
|
#define P_LOAD_COMBO_INT(a) ui->a->setCurrentIndex(bean->a);
|
||||||
|
#define P_SAVE_COMBO_INT(a) bean->a = ui->a->currentIndex();
|
||||||
#define D_LOAD_BOOL(a) ui->a->setChecked(NekoRay::dataStore->a);
|
#define D_LOAD_BOOL(a) ui->a->setChecked(NekoRay::dataStore->a);
|
||||||
#define D_SAVE_BOOL(a) NekoRay::dataStore->a = ui->a->isChecked();
|
#define D_SAVE_BOOL(a) NekoRay::dataStore->a = ui->a->isChecked();
|
||||||
|
#define P_LOAD_BOOL(a) ui->a->setChecked(bean->a);
|
||||||
|
#define P_SAVE_BOOL(a) bean->a = ui->a->isChecked();
|
||||||
|
|
||||||
#define D_LOAD_INT_ENABLE(i, e) \
|
#define D_LOAD_INT_ENABLE(i, e) \
|
||||||
if (NekoRay::dataStore->i > 0) { \
|
if (NekoRay::dataStore->i > 0) { \
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ inline std::function<void(QString, QString)> MW_dialog_message;
|
|||||||
|
|
||||||
// String
|
// String
|
||||||
|
|
||||||
|
#define FIRST_OR_SECOND(a, b) a.isEmpty() ? b : a
|
||||||
|
|
||||||
inline const QString UNICODE_LRO = QString::fromUtf8(QByteArray::fromHex("E280AD"));
|
inline const QString UNICODE_LRO = QString::fromUtf8(QByteArray::fromHex("E280AD"));
|
||||||
|
|
||||||
#define Int2String(num) QString::number(num)
|
#define Int2String(num) QString::number(num)
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FIRST_OR_SECOND(a, b) a.isEmpty() ? b : a
|
|
||||||
|
|
||||||
namespace NekoRay::sub {
|
namespace NekoRay::sub {
|
||||||
|
|
||||||
GroupUpdater *groupUpdater = new GroupUpdater;
|
GroupUpdater *groupUpdater = new GroupUpdater;
|
||||||
@@ -130,28 +128,9 @@ namespace NekoRay::sub {
|
|||||||
// Hysteria
|
// Hysteria
|
||||||
if (str.startsWith("hysteria://")) {
|
if (str.startsWith("hysteria://")) {
|
||||||
needFix = false;
|
needFix = false;
|
||||||
// https://github.com/HyNetwork/hysteria/wiki/URI-Scheme
|
ent = ProfileManager::NewProxyEntity("hysteria");
|
||||||
ent = ProfileManager::NewProxyEntity("custom");
|
auto ok = ent->HysteriaBean()->TryParseLink(str);
|
||||||
auto bean = ent->CustomBean();
|
if (!ok) return;
|
||||||
auto url = QUrl(str);
|
|
||||||
auto query = QUrlQuery(url.query());
|
|
||||||
if (url.host().isEmpty() || url.port() == -1 || !query.hasQueryItem("upmbps")) return;
|
|
||||||
bean->name = url.fragment();
|
|
||||||
bean->serverAddress = url.host();
|
|
||||||
bean->serverPort = url.port();
|
|
||||||
bean->core = "hysteria";
|
|
||||||
bean->command = QString(Preset::Hysteria::command).split(" ");
|
|
||||||
auto result = QString2QJsonObject(Preset::Hysteria::config);
|
|
||||||
result["server_name"] = url.host(); // default sni
|
|
||||||
result["obfs"] = query.queryItemValue("obfsParam");
|
|
||||||
result["insecure"] = query.queryItemValue("insecure") == "1";
|
|
||||||
result["up_mbps"] = query.queryItemValue("upmbps").toInt();
|
|
||||||
result["down_mbps"] = query.queryItemValue("downmbps").toInt();
|
|
||||||
result["protocol"] = query.hasQueryItem("protocol") ? query.queryItemValue("protocol") : "udp";
|
|
||||||
if (query.hasQueryItem("auth")) result["auth_str"] = query.queryItemValue("auth");
|
|
||||||
if (query.hasQueryItem("alpn")) result["alpn"] = query.queryItemValue("alpn");
|
|
||||||
if (query.hasQueryItem("peer")) result["server_name"] = query.queryItemValue("peer");
|
|
||||||
bean->config_simple = QJsonObject2QString(result, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ent == nullptr) return;
|
if (ent == nullptr) return;
|
||||||
@@ -237,7 +216,6 @@ namespace NekoRay::sub {
|
|||||||
|
|
||||||
if (type == "ss" || type == "ssr") type = "shadowsocks";
|
if (type == "ss" || type == "ssr") type = "shadowsocks";
|
||||||
if (type == "socks5") type = "socks";
|
if (type == "socks5") type = "socks";
|
||||||
if (type == "hysteria") type = "custom";
|
|
||||||
|
|
||||||
auto ent = ProfileManager::NewProxyEntity(type);
|
auto ent = ProfileManager::NewProxyEntity(type);
|
||||||
if (ent->bean->version == -114514) continue;
|
if (ent->bean->version == -114514) continue;
|
||||||
@@ -379,45 +357,37 @@ namespace NekoRay::sub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type_clash == "hysteria") {
|
} else if (type_clash == "hysteria") {
|
||||||
if (!IS_NEKO_BOX) {
|
auto bean = ent->HysteriaBean();
|
||||||
MW_show_log("Found Clash Meta format hysteria. This is only supported in NekoBox, please switch the core.");
|
|
||||||
continue;
|
bean->allowInsecure = Node2Bool(proxy["skip-cert-verify"]);
|
||||||
|
auto alpn = Node2QStringList(proxy["alpn"]);
|
||||||
|
if (!alpn.isEmpty()) bean->alpn = alpn[0];
|
||||||
|
bean->sni = Node2QString(proxy["sni"]);
|
||||||
|
|
||||||
|
bean->name = Node2QString(proxy["name"]);
|
||||||
|
bean->serverAddress = Node2QString(proxy["server"]);
|
||||||
|
bean->serverPort = Node2Int(proxy["port"]);
|
||||||
|
if (bean->serverPort == 0) bean->hopPort = Node2QString(proxy["port"]);
|
||||||
|
|
||||||
|
auto auth_str = FIRST_OR_SECOND(Node2QString(proxy["auth_str"]), Node2QString(proxy["auth-str"]));
|
||||||
|
auto auth = Node2QString(proxy["auth"]);
|
||||||
|
if (!auth_str.isEmpty()) {
|
||||||
|
bean->authPayloadType = fmt::HysteriaBean::hysteria_auth_string;
|
||||||
|
bean->authPayload = auth_str;
|
||||||
|
}
|
||||||
|
if (!auth.isEmpty()) {
|
||||||
|
bean->authPayloadType = fmt::HysteriaBean::hysteria_auth_base64;
|
||||||
|
bean->authPayload = auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bean = ent->CustomBean();
|
if (Node2Bool(proxy["disable_mtu_discovery"]) || Node2Bool(proxy["disable-mtu-discovery"])) bean->disableMtuDiscovery = true;
|
||||||
bean->core = "internal";
|
bean->streamReceiveWindow = Node2Int(proxy["recv-window"]);
|
||||||
|
bean->connectionReceiveWindow = Node2Int(proxy["recv-window-conn"]);
|
||||||
|
|
||||||
QJsonObject coreTlsObj{
|
auto upMbps = Node2QString(proxy["up"]).split(" ")[0].toInt();
|
||||||
{"enabled", true},
|
auto downMbps = Node2QString(proxy["down"]).split(" ")[0].toInt();
|
||||||
{"insecure", Node2Bool(proxy["skip-cert-verify"])},
|
if (upMbps > 0) bean->uploadMbps = upMbps;
|
||||||
{"alpn", QList2QJsonArray(Node2QStringList(proxy["alpn"]))},
|
if (downMbps > 0) bean->downloadMbps = downMbps;
|
||||||
{"server_name", Node2QString(proxy["sni"])},
|
|
||||||
};
|
|
||||||
|
|
||||||
QJsonObject coreHysteriaObj{
|
|
||||||
{"type", "hysteria"},
|
|
||||||
{"tag", Node2QString(proxy["name"])},
|
|
||||||
{"server", Node2QString(proxy["server"])},
|
|
||||||
{"server_port", Node2Int(proxy["port"])},
|
|
||||||
{"auth_str", FIRST_OR_SECOND(Node2QString(proxy["auth_str"]), Node2QString(proxy["auth-str"]))},
|
|
||||||
{"disable_mtu_discovery", Node2Bool(proxy["disable_mtu_discovery"])},
|
|
||||||
{"recv_window", Node2Int(proxy["recv-window"])},
|
|
||||||
{"recv_window_conn", Node2Int(proxy["recv-window-conn"])},
|
|
||||||
{"tls", coreTlsObj},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!Node2QString(proxy["up"]).contains("bps")) {
|
|
||||||
coreHysteriaObj["up_mbps"] = Node2Int(proxy["up"]);
|
|
||||||
} else {
|
|
||||||
coreHysteriaObj["up"] = Node2QString(proxy["up"]);
|
|
||||||
}
|
|
||||||
if (!Node2QString(proxy["down"]).contains("bps")) {
|
|
||||||
coreHysteriaObj["down_mbps"] = Node2Int(proxy["down"]);
|
|
||||||
} else {
|
|
||||||
coreHysteriaObj["down"] = Node2QString(proxy["down"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
bean->config_simple = QJsonObject2QString(coreHysteriaObj, false);
|
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -719,10 +719,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</source>
|
|||||||
<source>Config Suffix</source>
|
<source>Config Suffix</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Please read the documentation. If you don't understand, use a share link instead.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Outbound JSON, please read the documentation.</source>
|
<source>Outbound JSON, please read the documentation.</source>
|
||||||
<translation>JSON خروجی، لطفاً مستندات را بخوانید.</translation>
|
<translation>JSON خروجی، لطفاً مستندات را بخوانید.</translation>
|
||||||
@@ -752,6 +748,57 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</source>
|
|||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>EditHysteria</name>
|
||||||
|
<message>
|
||||||
|
<source>Certificate</source>
|
||||||
|
<translation type="unfinished">گواهی</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Auth Type</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Protocol</source>
|
||||||
|
<translation type="unfinished">پروتکل</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Download (Mbps)</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Disable MTU Discovery</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Hop Interval (s)</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Allow Insecure</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Hop Port</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Upload (Mbps)</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Obfs Password</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>SNI</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Auth Payload</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>EditNaive</name>
|
<name>EditNaive</name>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
@@ -716,10 +716,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
|
|||||||
<source>Outbound JSON, please read the documentation.</source>
|
<source>Outbound JSON, please read the documentation.</source>
|
||||||
<translation>填写出站 JSON 对象,详细请看文档。</translation>
|
<translation>填写出站 JSON 对象,详细请看文档。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Please read the documentation. If you don't understand, use a share link instead.</source>
|
|
||||||
<translation>格式请看文档。如果不懂,直接导入 hysteria:// 链接。</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Config Suffix</source>
|
<source>Config Suffix</source>
|
||||||
<translation>配置文件后缀</translation>
|
<translation>配置文件后缀</translation>
|
||||||
@@ -745,6 +741,57 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
|
|||||||
<translation>请填写完整配置。</translation>
|
<translation>请填写完整配置。</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>EditHysteria</name>
|
||||||
|
<message>
|
||||||
|
<source>Certificate</source>
|
||||||
|
<translation>证书</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Auth Type</source>
|
||||||
|
<translation>认证类型</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Protocol</source>
|
||||||
|
<translation>协议</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Download (Mbps)</source>
|
||||||
|
<translation>下载速度 (Mbps)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Disable MTU Discovery</source>
|
||||||
|
<translation>禁用 MTU 探测</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Hop Interval (s)</source>
|
||||||
|
<translation>端口跳跃间隔 (秒)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Allow Insecure</source>
|
||||||
|
<translation>不检查服务器证书</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Hop Port</source>
|
||||||
|
<translation>跳跃端口</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Upload (Mbps)</source>
|
||||||
|
<translation>上传速度 (Mbps)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Obfs Password</source>
|
||||||
|
<translation>混淆密码</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>SNI</source>
|
||||||
|
<translation>SNI</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Auth Payload</source>
|
||||||
|
<translation>认证有效载荷</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>EditNaive</name>
|
<name>EditNaive</name>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "ui/edit/edit_vmess.h"
|
#include "ui/edit/edit_vmess.h"
|
||||||
#include "ui/edit/edit_trojan_vless.h"
|
#include "ui/edit/edit_trojan_vless.h"
|
||||||
#include "ui/edit/edit_naive.h"
|
#include "ui/edit/edit_naive.h"
|
||||||
|
#include "ui/edit/edit_hysteria.h"
|
||||||
#include "ui/edit/edit_custom.h"
|
#include "ui/edit/edit_custom.h"
|
||||||
|
|
||||||
#include "fmt/includes.h"
|
#include "fmt/includes.h"
|
||||||
@@ -123,7 +124,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
|
|||||||
LOAD_TYPE("vmess");
|
LOAD_TYPE("vmess");
|
||||||
LOAD_TYPE("vless");
|
LOAD_TYPE("vless");
|
||||||
LOAD_TYPE("naive");
|
LOAD_TYPE("naive");
|
||||||
ui->type->addItem("Hysteria", "hysteria");
|
LOAD_TYPE("hysteria");
|
||||||
ui->type->addItem(tr("Custom (%1 outbound)").arg(software_core_name), "internal");
|
ui->type->addItem(tr("Custom (%1 outbound)").arg(software_core_name), "internal");
|
||||||
ui->type->addItem(tr("Custom (%1 config)").arg(software_core_name), "internal-full");
|
ui->type->addItem(tr("Custom (%1 config)").arg(software_core_name), "internal-full");
|
||||||
ui->type->addItem(tr("Custom (Extra Core)"), "custom");
|
ui->type->addItem(tr("Custom (Extra Core)"), "custom");
|
||||||
@@ -177,7 +178,11 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
|||||||
auto _innerWidget = new EditNaive(this);
|
auto _innerWidget = new EditNaive(this);
|
||||||
innerWidget = _innerWidget;
|
innerWidget = _innerWidget;
|
||||||
innerEditor = _innerWidget;
|
innerEditor = _innerWidget;
|
||||||
} else if (type == "custom" || type == "internal" || type == "internal-full" || type == "hysteria") {
|
} else if (type == "hysteria") {
|
||||||
|
auto _innerWidget = new EditHysteria(this);
|
||||||
|
innerWidget = _innerWidget;
|
||||||
|
innerEditor = _innerWidget;
|
||||||
|
} else if (type == "custom" || type == "internal" || type == "internal-full") {
|
||||||
auto _innerWidget = new EditCustom(this);
|
auto _innerWidget = new EditCustom(this);
|
||||||
innerWidget = _innerWidget;
|
innerWidget = _innerWidget;
|
||||||
innerEditor = _innerWidget;
|
innerEditor = _innerWidget;
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ EditCustom::~EditCustom() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define SAVE_CUSTOM_BEAN \
|
#define SAVE_CUSTOM_BEAN \
|
||||||
P_SAVE_COMBO(core) \
|
P_SAVE_COMBO_STR(core) \
|
||||||
bean->command = ui->command->text().split(" "); \
|
bean->command = ui->command->text().split(" "); \
|
||||||
P_SAVE_STRING_QTEXTEDIT(config_simple) \
|
P_SAVE_STRING_QTEXTEDIT(config_simple) \
|
||||||
P_SAVE_COMBO(config_suffix) \
|
P_SAVE_COMBO_STR(config_suffix) \
|
||||||
P_SAVE_INT(mapping_port) \
|
P_SAVE_INT(mapping_port) \
|
||||||
P_SAVE_INT(socks_port)
|
P_SAVE_INT(socks_port)
|
||||||
|
|
||||||
@@ -43,13 +43,7 @@ void EditCustom::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
|||||||
if (key == "naive" || key == "hysteria") continue;
|
if (key == "naive" || key == "hysteria") continue;
|
||||||
ui->core->addItem(key);
|
ui->core->addItem(key);
|
||||||
}
|
}
|
||||||
if (preset_core == "hysteria") {
|
if (preset_core == "internal") {
|
||||||
preset_command = Preset::Hysteria::command;
|
|
||||||
preset_config = Preset::Hysteria::config;
|
|
||||||
ui->config_simple->setPlaceholderText("");
|
|
||||||
ui->core->hide();
|
|
||||||
ui->core_l->setText(tr("Please read the documentation. If you don't understand, use a share link instead."));
|
|
||||||
} else if (preset_core == "internal") {
|
|
||||||
preset_command = preset_config = "";
|
preset_command = preset_config = "";
|
||||||
ui->config_simple->setPlaceholderText(
|
ui->config_simple->setPlaceholderText(
|
||||||
"{\n"
|
"{\n"
|
||||||
@@ -66,10 +60,10 @@ void EditCustom::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// load core ui
|
// load core ui
|
||||||
P_LOAD_COMBO(core)
|
P_LOAD_COMBO_STR(core)
|
||||||
ui->command->setText(bean->command.join(" "));
|
ui->command->setText(bean->command.join(" "));
|
||||||
P_LOAD_STRING(config_simple)
|
P_LOAD_STRING(config_simple)
|
||||||
P_LOAD_COMBO(config_suffix)
|
P_LOAD_COMBO_STR(config_suffix)
|
||||||
P_LOAD_INT(mapping_port)
|
P_LOAD_INT(mapping_port)
|
||||||
P_LOAD_INT(socks_port)
|
P_LOAD_INT(socks_port)
|
||||||
|
|
||||||
|
|||||||
72
ui/edit/edit_hysteria.cpp
Normal file
72
ui/edit/edit_hysteria.cpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#include "edit_hysteria.h"
|
||||||
|
#include "ui_edit_hysteria.h"
|
||||||
|
|
||||||
|
#include "fmt/HysteriaBean.hpp"
|
||||||
|
|
||||||
|
#include <QInputDialog>
|
||||||
|
|
||||||
|
EditHysteria::EditHysteria(QWidget *parent) : QWidget(parent), ui(new Ui::EditHysteria) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditHysteria::~EditHysteria() {
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditHysteria::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
||||||
|
this->ent = _ent;
|
||||||
|
auto bean = this->ent->HysteriaBean();
|
||||||
|
|
||||||
|
P_LOAD_STRING(hopPort);
|
||||||
|
P_LOAD_INT(hopInterval);
|
||||||
|
P_LOAD_INT(uploadMbps);
|
||||||
|
P_LOAD_INT(downloadMbps);
|
||||||
|
P_LOAD_COMBO_INT(protocol);
|
||||||
|
P_LOAD_BOOL(disableMtuDiscovery)
|
||||||
|
P_LOAD_STRING(obfsPassword);
|
||||||
|
P_LOAD_COMBO_INT(authPayloadType);
|
||||||
|
P_LOAD_STRING(authPayload);
|
||||||
|
P_LOAD_STRING(sni);
|
||||||
|
P_LOAD_STRING(alpn);
|
||||||
|
P_LOAD_BOOL(allowInsecure)
|
||||||
|
P_C_LOAD_STRING(caText);
|
||||||
|
P_LOAD_INT(streamReceiveWindow);
|
||||||
|
P_LOAD_INT(connectionReceiveWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditHysteria::onEnd() {
|
||||||
|
auto bean = this->ent->HysteriaBean();
|
||||||
|
|
||||||
|
P_SAVE_STRING(hopPort);
|
||||||
|
P_SAVE_INT(hopInterval);
|
||||||
|
P_SAVE_INT(uploadMbps);
|
||||||
|
P_SAVE_INT(downloadMbps);
|
||||||
|
P_SAVE_COMBO_INT(protocol);
|
||||||
|
P_SAVE_BOOL(disableMtuDiscovery)
|
||||||
|
P_SAVE_STRING(obfsPassword);
|
||||||
|
P_SAVE_COMBO_INT(authPayloadType);
|
||||||
|
P_SAVE_STRING(authPayload);
|
||||||
|
P_SAVE_STRING(sni);
|
||||||
|
P_SAVE_STRING(alpn);
|
||||||
|
P_SAVE_BOOL(allowInsecure)
|
||||||
|
P_C_SAVE_STRING(caText);
|
||||||
|
P_SAVE_INT(streamReceiveWindow);
|
||||||
|
P_SAVE_INT(connectionReceiveWindow);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QPair<QPushButton *, QString>> EditHysteria::get_editor_cached() {
|
||||||
|
return {
|
||||||
|
{ui->certificate, CACHE.caText},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditHysteria::on_certificate_clicked() {
|
||||||
|
bool ok;
|
||||||
|
auto txt = QInputDialog::getMultiLineText(this, tr("Certificate"), "", CACHE.caText, &ok);
|
||||||
|
if (ok) {
|
||||||
|
CACHE.caText = txt;
|
||||||
|
editor_cache_updated();
|
||||||
|
}
|
||||||
|
}
|
||||||
37
ui/edit/edit_hysteria.h
Normal file
37
ui/edit/edit_hysteria.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include "profile_editor.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace Ui {
|
||||||
|
class EditHysteria;
|
||||||
|
}
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class EditHysteria : public QWidget, public ProfileEditor {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit EditHysteria(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
~EditHysteria() override;
|
||||||
|
|
||||||
|
void onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) override;
|
||||||
|
|
||||||
|
bool onEnd() override;
|
||||||
|
|
||||||
|
QList<QPair<QPushButton *, QString>> get_editor_cached() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::EditHysteria *ui;
|
||||||
|
QSharedPointer<NekoRay::ProxyEntity> ent;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
QString caText;
|
||||||
|
} CACHE;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void on_certificate_clicked();
|
||||||
|
};
|
||||||
231
ui/edit/edit_hysteria.ui
Normal file
231
ui/edit/edit_hysteria.ui
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>EditHysteria</class>
|
||||||
|
<widget class="QWidget" name="EditHysteria">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>500</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string notr="true">EditHysteria</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="MyLineEdit" name="hopPort"/>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Auth Type</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Protocol</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="MyLineEdit" name="obfsPassword"/>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="1">
|
||||||
|
<widget class="MyLineEdit" name="sni"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="MyLineEdit" name="uploadMbps"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Download (Mbps)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="protocol">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">QUIC</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">FakeTCP</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">wechat-video</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="disableMtuDiscovery">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Disable MTU Discovery</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hop Interval (s)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="MyLineEdit" name="hopInterval"/>
|
||||||
|
</item>
|
||||||
|
<item row="13" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Certificate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="1">
|
||||||
|
<widget class="QComboBox" name="authPayloadType">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">NONE</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">STRING</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">BASE64</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="12" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="MyLineEdit" name="alpn"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="allowInsecure">
|
||||||
|
<property name="text">
|
||||||
|
<string>Allow Insecure</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hop Port</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="13" column="1">
|
||||||
|
<widget class="QPushButton" name="certificate">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">PushButton</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Upload (Mbps)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Obfs Password</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>SNI</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="MyLineEdit" name="downloadMbps"/>
|
||||||
|
</item>
|
||||||
|
<item row="12" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string notr="true">Only 1 value</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">ALPN</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="14" column="1">
|
||||||
|
<widget class="MyLineEdit" name="streamReceiveWindow"/>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Auth Payload</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="1">
|
||||||
|
<widget class="MyLineEdit" name="authPayload"/>
|
||||||
|
</item>
|
||||||
|
<item row="15" column="1">
|
||||||
|
<widget class="MyLineEdit" name="connectionReceiveWindow"/>
|
||||||
|
</item>
|
||||||
|
<item row="14" column="0">
|
||||||
|
<widget class="QLabel" name="label_12">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">recv_window</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="15" column="0">
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">recv_window_conn</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>MyLineEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>ui/widget/MyLineEdit.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>uploadMbps</tabstop>
|
||||||
|
<tabstop>downloadMbps</tabstop>
|
||||||
|
<tabstop>sni</tabstop>
|
||||||
|
<tabstop>certificate</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -19,7 +19,7 @@ void EditNaive::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
|||||||
|
|
||||||
P_LOAD_STRING(username);
|
P_LOAD_STRING(username);
|
||||||
P_LOAD_STRING(password);
|
P_LOAD_STRING(password);
|
||||||
P_LOAD_COMBO(protocol);
|
P_LOAD_COMBO_STR(protocol);
|
||||||
P_C_LOAD_STRING(extra_headers);
|
P_C_LOAD_STRING(extra_headers);
|
||||||
P_LOAD_STRING(sni);
|
P_LOAD_STRING(sni);
|
||||||
P_C_LOAD_STRING(certificate);
|
P_C_LOAD_STRING(certificate);
|
||||||
@@ -31,7 +31,7 @@ bool EditNaive::onEnd() {
|
|||||||
|
|
||||||
P_SAVE_STRING(username);
|
P_SAVE_STRING(username);
|
||||||
P_SAVE_STRING(password);
|
P_SAVE_STRING(password);
|
||||||
P_SAVE_COMBO(protocol);
|
P_SAVE_COMBO_STR(protocol);
|
||||||
P_C_SAVE_STRING(extra_headers);
|
P_C_SAVE_STRING(extra_headers);
|
||||||
P_SAVE_STRING(sni);
|
P_SAVE_STRING(sni);
|
||||||
P_C_SAVE_STRING(certificate);
|
P_C_SAVE_STRING(certificate);
|
||||||
|
|||||||
Reference in New Issue
Block a user