feat: add TUIC protocol (#781)

---------

Co-authored-by: 2022-blake3-chacha8-poly1305 <139959885+xchacha20-ietf-poly1305@users.noreply.github.com>
Co-authored-by: arm64v8a <48624112+arm64v8a@users.noreply.github.com>
This commit is contained in:
HystericalDragon
2023-08-10 14:16:44 +08:00
committed by GitHub
parent 03257676e5
commit d8bf56a1ad
25 changed files with 1087 additions and 610 deletions

View File

@@ -213,9 +213,9 @@ 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_quic.h
ui/edit/edit_hysteria.cpp ui/edit/edit_quic.cpp
ui/edit/edit_hysteria.ui ui/edit/edit_quic.ui
ui/edit/edit_custom.h ui/edit/edit_custom.h
ui/edit/edit_custom.cpp ui/edit/edit_custom.cpp

View File

@@ -45,6 +45,7 @@ https://matsuridayo.github.io
* VMess * VMess
* VLESS * VLESS
* Trojan * Trojan
* TUIC ( sing-box )
* NaïveProxy ( Custom Core ) * NaïveProxy ( Custom Core )
* Hysteria ( Custom Core or sing-box ) * Hysteria ( Custom Core or sing-box )
* Custom Outbound * Custom Outbound

View File

@@ -185,7 +185,9 @@ namespace NekoGui {
} else if (type == "naive") { } else if (type == "naive") {
bean = new NekoGui_fmt::NaiveBean(); bean = new NekoGui_fmt::NaiveBean();
} else if (type == "hysteria") { } else if (type == "hysteria") {
bean = new NekoGui_fmt::HysteriaBean(); bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria);
} else if (type == "tuic") {
bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_TUIC);
} else if (type == "custom") { } else if (type == "custom") {
bean = new NekoGui_fmt::CustomBean(); bean = new NekoGui_fmt::CustomBean();
} else { } else {

View File

@@ -15,7 +15,7 @@ namespace NekoGui_fmt {
class NaiveBean; class NaiveBean;
class HysteriaBean; class QUICBean;
class CustomBean; class CustomBean;
@@ -65,8 +65,8 @@ namespace NekoGui {
return (NekoGui_fmt::NaiveBean *) bean.get(); return (NekoGui_fmt::NaiveBean *) bean.get();
}; };
[[nodiscard]] NekoGui_fmt::HysteriaBean *HysteriaBean() const { [[nodiscard]] NekoGui_fmt::QUICBean *QUICBean() const {
return (NekoGui_fmt::HysteriaBean *) bean.get(); return (NekoGui_fmt::QUICBean *) bean.get();
}; };
[[nodiscard]] NekoGui_fmt::CustomBean *CustomBean() const { [[nodiscard]] NekoGui_fmt::CustomBean *CustomBean() const {

View File

@@ -169,36 +169,47 @@ namespace NekoGui_fmt {
return result; return result;
} }
CoreObjOutboundBuildResult HysteriaBean::BuildCoreObjSingBox() { CoreObjOutboundBuildResult QUICBean::BuildCoreObjSingBox() {
CoreObjOutboundBuildResult result; CoreObjOutboundBuildResult result;
QJsonObject coreTlsObj{ QJsonObject coreTlsObj{
{"enabled", true}, {"enabled", true},
{"disable_sni", disableSni},
{"insecure", allowInsecure}, {"insecure", allowInsecure},
{"certificate", caText.trimmed()}, {"certificate", caText.trimmed()},
{"server_name", sni}, {"server_name", sni},
}; };
if (!alpn.trimmed().isEmpty()) coreTlsObj["alpn"] = QJsonArray{alpn}; if (!alpn.trimmed().isEmpty()) coreTlsObj["alpn"] = QList2QJsonArray(alpn.split(","));
QJsonObject coreHysteriaObj{ QJsonObject outbound{
{"type", "hysteria"},
{"server", serverAddress}, {"server", serverAddress},
{"server_port", serverPort}, {"server_port", serverPort},
{"obfs", obfsPassword},
{"disable_mtu_discovery", disableMtuDiscovery},
{"recv_window", streamReceiveWindow},
{"recv_window_conn", connectionReceiveWindow},
{"up_mbps", uploadMbps},
{"down_mbps", downloadMbps},
{"tls", coreTlsObj}, {"tls", coreTlsObj},
}; };
if (!hopPort.trimmed().isEmpty()) coreHysteriaObj["hop_ports"] = hopPort; if (proxy_type == proxy_Hysteria) {
outbound["type"] = "hysteria";
outbound["obfs"] = obfsPassword;
outbound["disable_mtu_discovery"] = disableMtuDiscovery;
outbound["recv_window"] = streamReceiveWindow;
outbound["recv_window_conn"] = connectionReceiveWindow;
outbound["up_mbps"] = uploadMbps;
outbound["down_mbps"] = downloadMbps;
if (authPayloadType == hysteria_auth_base64) coreHysteriaObj["auth"] = authPayload; if (!hopPort.trimmed().isEmpty()) outbound["hop_ports"] = hopPort;
if (authPayloadType == hysteria_auth_string) coreHysteriaObj["auth_str"] = authPayload; if (authPayloadType == hysteria_auth_base64) outbound["auth"] = authPayload;
if (authPayloadType == hysteria_auth_string) outbound["auth_str"] = authPayload;
} else if (proxy_type == proxy_TUIC) {
outbound["type"] = "tuic";
outbound["uuid"] = uuid;
outbound["password"] = password;
outbound["congestion_control"] = congestionControl;
outbound["udp_relay_mode"] = udpRelayMode;
outbound["zero_rtt_handshake"] = zeroRttHandshake;
if (!heartbeat.trimmed().isEmpty()) outbound["heartbeat"] = heartbeat;
}
result.outbound = coreHysteriaObj; result.outbound = outbound;
return result; return result;
} }

View File

@@ -35,29 +35,41 @@ namespace NekoGui_fmt {
return 1; return 1;
} }
int HysteriaBean::NeedExternal(bool isFirstProfile) { int QUICBean::NeedExternal(bool isFirstProfile) {
auto hysteriaCore = [=] { auto hysteriaCore = [=] {
if (isFirstProfile) { if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn && protocol != hysteria_protocol_facktcp && hopPort.trimmed().isEmpty()) { if (NekoGui::dataStore->spmode_vpn && hyProtocol != hysteria_protocol_facktcp && hopPort.trimmed().isEmpty()) {
return 1; return 1;
} }
return 2; return 2;
} else { } else {
if (protocol == hysteria_protocol_facktcp || !hopPort.trimmed().isEmpty()) { if (hyProtocol == hysteria_protocol_facktcp || !hopPort.trimmed().isEmpty()) {
return -1; return -1;
} }
} }
return 1; return 1;
}; };
auto tuicCore = [=] {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn) {
return 1;
}
return 2;
}
return 1;
};
if (IS_NEKO_BOX) { if (IS_NEKO_BOX) {
if (protocol == hysteria_protocol_udp) { if (proxy_type == proxy_TUIC || hyProtocol == hysteria_protocol_udp) {
// sing-box support // sing-box support
return 0; return 0;
} else { } else {
// hysteria core support // hysteria core support
return hysteriaCore(); return hysteriaCore();
} }
} else if (proxy_type == proxy_TUIC) {
return tuicCore();
} else { } else {
return hysteriaCore(); return hysteriaCore();
} }
@@ -104,65 +116,112 @@ namespace NekoGui_fmt {
return result; return result;
} }
ExternalBuildResult HysteriaBean::BuildExternal(int mapping_port, int socks_port, int external_stat) { ExternalBuildResult QUICBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria")}; if (proxy_type == proxy_TUIC) {
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("tuic")};
QJsonObject config; QJsonObject relay;
// determine server format relay["uuid"] = uuid;
auto is_direct = external_stat == 2; relay["password"] = password;
auto sniGen = sni; relay["udp_relay_mode"] = udpRelayMode;
if (sni.isEmpty() && !IsIpAddress(serverAddress)) sniGen = serverAddress; relay["congestion_control"] = congestionControl;
relay["zero_rtt_handshake"] = zeroRttHandshake;
relay["disable_sni"] = disableSni;
if (!heartbeat.trimmed().isEmpty()) relay["heartbeat"] = heartbeat;
if (!alpn.trimmed().isEmpty()) relay["alpn"] = QList2QJsonArray(alpn.split(","));
auto server = serverAddress; if (!caText.trimmed().isEmpty()) {
if (!hopPort.trimmed().isEmpty()) { WriteTempFile("tuic_" + GetRandomString(10) + ".crt", caText.toUtf8());
server = WrapIPV6Host(server) + ":" + hopPort; QJsonArray certificate;
} else { certificate.append(TempFile);
server = WrapIPV6Host(server) + ":" + Int2String(serverPort); relay["certificates"] = certificate;
}
// The most confused part of TUIC......
if (serverAddress == sni) {
relay["server"] = serverAddress + ":" + Int2String(serverPort);
} else {
relay["server"] = sni + ":" + Int2String(serverPort);
relay["ip"] = serverAddress;
}
QJsonObject local{
{"server", "127.0.0.1:" + Int2String(socks_port)},
};
QJsonObject config{
{"relay", relay},
{"local", local},
};
//
result.config_export = QJsonObject2QString(config, false);
WriteTempFile("tuic_" + GetRandomString(10) + ".json", result.config_export.toUtf8());
result.arguments = QStringList{"-c", TempFile};
return result;
} else { // Hysteria
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria")};
QJsonObject config;
// determine server format
auto is_direct = external_stat == 2;
auto sniGen = sni;
if (sni.isEmpty() && !IsIpAddress(serverAddress)) sniGen = 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 (hyProtocol == hysteria_protocol_facktcp) config["protocol"] = "faketcp";
if (hyProtocol == hysteria_protocol_wechat_video) config["protocol"] = "wechat-video";
if (!sniGen.isEmpty()) config["server_name"] = sniGen;
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;
} }
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 (!sniGen.isEmpty()) config["server_name"] = sniGen;
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) {
@@ -206,4 +265,5 @@ namespace NekoGui_fmt {
return result; return result;
} }
} // namespace NekoGui_fmt
} // namespace NekoGui_fmt

View File

@@ -1,3 +1,4 @@
#include "QUICBean.hpp"
#include "db/ProxyEntity.hpp" #include "db/ProxyEntity.hpp"
#include "fmt/includes.h" #include "fmt/includes.h"
@@ -127,29 +128,33 @@ namespace NekoGui_fmt {
return url.toString(QUrl::FullyEncoded); return url.toString(QUrl::FullyEncoded);
} }
QString HysteriaBean::ToShareLink() { QString QUICBean::ToShareLink() {
QUrl url; QUrl url;
url.setScheme("hysteria"); if (proxy_type == proxy_Hysteria) {
url.setHost(serverAddress); url.setScheme("hysteria");
url.setPort(serverPort); url.setHost(serverAddress);
QUrlQuery q; url.setPort(serverPort);
q.addQueryItem("upmbps", Int2String(uploadMbps)); QUrlQuery q;
q.addQueryItem("downmbps", Int2String(downloadMbps)); q.addQueryItem("upmbps", Int2String(uploadMbps));
if (!obfsPassword.isEmpty()) { q.addQueryItem("downmbps", Int2String(downloadMbps));
q.addQueryItem("obfs", "xplus"); if (!obfsPassword.isEmpty()) {
q.addQueryItem("obfsParam", obfsPassword); q.addQueryItem("obfs", "xplus");
q.addQueryItem("obfsParam", obfsPassword);
}
if (authPayloadType == hysteria_auth_string) q.addQueryItem("auth", authPayload);
if (hyProtocol == hysteria_protocol_facktcp) q.addQueryItem("protocol", "faketcp");
if (hyProtocol == 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);
} else if (proxy_type == proxy_TUIC) {
// TODO std link
} }
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); return url.toString(QUrl::FullyEncoded);
} }

View File

@@ -1,80 +0,0 @@
#pragma once
#include "fmt/AbstractBean.hpp"
namespace NekoGui_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(true) == 0 ? software_core_name : "Hysteria"; };
QString DisplayType() override { return "Hysteria"; };
int NeedExternal(bool isFirstProfile) 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 NekoGui_fmt

View File

@@ -1,3 +1,4 @@
#include "QUICBean.hpp"
#include "db/ProxyEntity.hpp" #include "db/ProxyEntity.hpp"
#include "fmt/includes.h" #include "fmt/includes.h"
@@ -174,40 +175,47 @@ namespace NekoGui_fmt {
return !(username.isEmpty() || password.isEmpty() || serverAddress.isEmpty()); return !(username.isEmpty() || password.isEmpty() || serverAddress.isEmpty());
} }
bool HysteriaBean::TryParseLink(const QString &link) { bool QUICBean::TryParseLink(const QString &link) {
// https://hysteria.network/docs/uri-scheme/ // https://hysteria.network/docs/uri-scheme/
auto url = QUrl(link); auto url = QUrl(link);
auto query = QUrlQuery(url.query()); auto query = QUrlQuery(url.query());
if (url.host().isEmpty() || url.port() == -1 || !query.hasQueryItem("upmbps") || !query.hasQueryItem("downmbps")) return false; if (url.host().isEmpty() || url.port() == -1) return false;
name = url.fragment(); if (url.scheme() == "hysteria") {
serverAddress = url.host(); if (!query.hasQueryItem("upmbps") || !query.hasQueryItem("downmbps")) return false;
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(); name = url.fragment();
if (protocolStr == "faketcp") { serverAddress = url.host();
protocol = NekoGui_fmt::HysteriaBean::hysteria_protocol_facktcp; serverPort = url.port();
} else if (protocolStr.startsWith("wechat")) { serverAddress = url.host(); // default sni
protocol = NekoGui_fmt::HysteriaBean::hysteria_protocol_wechat_video; 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") {
hyProtocol = NekoGui_fmt::QUICBean::hysteria_protocol_facktcp;
} else if (protocolStr.startsWith("wechat")) {
hyProtocol = NekoGui_fmt::QUICBean::hysteria_protocol_wechat_video;
}
if (query.hasQueryItem("auth")) {
authPayload = query.queryItemValue("auth");
authPayloadType = NekoGui_fmt::QUICBean::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();
} else {
// TODO TUIC std link
return false;
} }
if (query.hasQueryItem("auth")) {
authPayload = query.queryItemValue("auth");
authPayloadType = NekoGui_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; return true;
} }

103
fmt/QUICBean.hpp Normal file
View File

@@ -0,0 +1,103 @@
#pragma once
#include "fmt/AbstractBean.hpp"
namespace NekoGui_fmt {
class QUICBean : public AbstractBean {
public:
static constexpr int proxy_Hysteria = 0;
static constexpr int proxy_TUIC = 1;
int proxy_type = proxy_Hysteria;
// Hysteria
static constexpr int hysteria_protocol_udp = 0;
static constexpr int hysteria_protocol_facktcp = 1;
static constexpr int hysteria_protocol_wechat_video = 2;
int hyProtocol = 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;
int hopInterval = 10;
QString hopPort = "";
// TUIC
QString uuid = "";
QString password = "";
QString congestionControl = "bbr";
QString udpRelayMode = "native";
bool zeroRttHandshake = false;
QString heartbeat = "10s";
// TLS
bool allowInsecure = false;
QString sni = "";
QString alpn = "";
QString caText = "";
bool disableSni = false;
explicit QUICBean(int _proxy_type) : AbstractBean(0) {
proxy_type = _proxy_type;
if (proxy_type == proxy_Hysteria) {
_add(new configItem("protocol", &hyProtocol, 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("hopInterval", &hopInterval, itemType::integer));
_add(new configItem("hopPort", &hopPort, itemType::string));
} else if (proxy_type == proxy_TUIC) {
_add(new configItem("uuid", &uuid, itemType::string));
_add(new configItem("password", &password, itemType::string));
_add(new configItem("congestionControl", &congestionControl, itemType::string));
_add(new configItem("udpRelayMode", &udpRelayMode, itemType::string));
_add(new configItem("zeroRttHandshake", &zeroRttHandshake, itemType::boolean));
_add(new configItem("heartbeat", &heartbeat, itemType::string));
}
// TLS
_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("disableSni", &disableSni, itemType::boolean));
};
QString DisplayAddress() override {
if (!hopPort.trimmed().isEmpty()) return WrapIPV6Host(serverAddress) + ":" + hopPort;
return ::DisplayAddress(serverAddress, serverPort);
}
QString DisplayCoreType() override { return NeedExternal(true) == 0 ? software_core_name : "Hysteria"; };
QString DisplayType() override { return proxy_type == proxy_TUIC ? "TUIC" : "Hysteria"; };
int NeedExternal(bool isFirstProfile) 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 NekoGui_fmt

View File

@@ -6,5 +6,5 @@
#include "VMessBean.hpp" #include "VMessBean.hpp"
#include "TrojanVLESSBean.hpp" #include "TrojanVLESSBean.hpp"
#include "NaiveBean.hpp" #include "NaiveBean.hpp"
#include "HysteriaBean.hpp" #include "QUICBean.hpp"
#include "CustomBean.hpp" #include "CustomBean.hpp"

View File

@@ -28,6 +28,7 @@ require (
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.1.2 // indirect github.com/google/btree v1.1.2 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
@@ -48,14 +49,12 @@ require (
github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/pires/go-proxyproto v0.7.0 // indirect github.com/pires/go-proxyproto v0.7.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.1 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 // indirect github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 // indirect
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 // indirect github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 // indirect
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
github.com/sagernet/quic-go v0.0.0-20230731154841-cdc97aca6239 // indirect github.com/sagernet/quic-go v0.0.0-20230809023643-d720ed35ac2b // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a // indirect github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a // indirect
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659 // indirect github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659 // indirect
@@ -63,7 +62,7 @@ require (
github.com/sagernet/sing-shadowsocks v0.2.4 // indirect github.com/sagernet/sing-shadowsocks v0.2.4 // indirect
github.com/sagernet/sing-shadowsocks2 v0.1.3 // indirect github.com/sagernet/sing-shadowsocks2 v0.1.3 // indirect
github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect
github.com/sagernet/sing-tun v0.1.12-0.20230808064040-326c20ab22af // indirect github.com/sagernet/sing-tun v0.1.12-0.20230808120247-47ab78d303db // indirect
github.com/sagernet/sing-vmess v0.1.7 // indirect github.com/sagernet/sing-vmess v0.1.7 // indirect
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect

View File

@@ -60,6 +60,7 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
@@ -120,12 +121,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U= github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg=
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc= github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt1Jtp5vW2ohNvstvQffTOQ/s5vENuGXzdA+TM= github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt1Jtp5vW2ohNvstvQffTOQ/s5vENuGXzdA+TM=
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I= github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I=
@@ -135,8 +132,8 @@ github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 h1:dnkKrzapqtAwjTS
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nGuf++YFm9eWZ8q2lrwHmhcUGzptMl/vL1+LA= github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nGuf++YFm9eWZ8q2lrwHmhcUGzptMl/vL1+LA=
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/quic-go v0.0.0-20230731154841-cdc97aca6239 h1:UwKDwYDzGc9FGBYm3pr7SpaEQcjYdnfjtRDvePHtcBA= github.com/sagernet/quic-go v0.0.0-20230809023643-d720ed35ac2b h1:+hpCW1zw03nnJDx+5tF9ETb6bKl2VSftv4KMGZAHC2Q=
github.com/sagernet/quic-go v0.0.0-20230731154841-cdc97aca6239/go.mod h1:5rilP6WxqIl/4ypZbMjr+MK+STxuCEvO5yVtEyYNZ6g= github.com/sagernet/quic-go v0.0.0-20230809023643-d720ed35ac2b/go.mod h1:w+nln6f/ZtyPpGbFxmgd5iYFVMmgS+gpD5hu5GAqC1I=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
@@ -153,8 +150,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.3 h1:WXoLvCFi5JTFBRYorf1YePGYIQyJ/zbs
github.com/sagernet/sing-shadowsocks2 v0.1.3/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw= github.com/sagernet/sing-shadowsocks2 v0.1.3/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
github.com/sagernet/sing-tun v0.1.12-0.20230808064040-326c20ab22af h1:gC2vTbt2wrfPv3P33fLIrtM6YUt1w7muRrMk62g6Ykk= github.com/sagernet/sing-tun v0.1.12-0.20230808120247-47ab78d303db h1:jOwG+7u4NtQVwXj5pFnGeNnDoa2cv83O5x4NLKN8y/c=
github.com/sagernet/sing-tun v0.1.12-0.20230808064040-326c20ab22af/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck= github.com/sagernet/sing-tun v0.1.12-0.20230808120247-47ab78d303db/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck=
github.com/sagernet/sing-vmess v0.1.7 h1:TM8FFLsXmlXH9XT8/oDgc6PC5BOzrg6OzyEe01is2r4= github.com/sagernet/sing-vmess v0.1.7 h1:TM8FFLsXmlXH9XT8/oDgc6PC5BOzrg6OzyEe01is2r4=
github.com/sagernet/sing-vmess v0.1.7/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss= github.com/sagernet/sing-vmess v0.1.7/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss=
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
@@ -188,6 +185,7 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695AP
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
@@ -221,6 +219,7 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -232,6 +231,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
@@ -242,6 +242,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -253,7 +254,9 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -277,6 +280,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -1,5 +1,5 @@
if [ ! -z $ENV_NEKORAY ]; then if [ ! -z $ENV_NEKORAY ]; then
export COMMIT_SING_BOX_EXTRA="00286b4baa9dabdce79d40ccd63a90c862a72254" export COMMIT_SING_BOX_EXTRA="df902756f9c50257c48c580e2b5f1b5b190f89bc"
export COMMIT_MATSURI_XRAY="f6843e4e1442341e88ac34c09ca2d243cdcc09f6" export COMMIT_MATSURI_XRAY="f6843e4e1442341e88ac34c09ca2d243cdcc09f6"
fi fi

View File

@@ -129,7 +129,7 @@ namespace NekoGui_sub {
if (str.startsWith("hysteria://")) { if (str.startsWith("hysteria://")) {
needFix = false; needFix = false;
ent = NekoGui::ProfileManager::NewProxyEntity("hysteria"); ent = NekoGui::ProfileManager::NewProxyEntity("hysteria");
auto ok = ent->HysteriaBean()->TryParseLink(str); auto ok = ent->QUICBean()->TryParseLink(str);
if (!ok) return; if (!ok) return;
} }
@@ -373,28 +373,26 @@ namespace NekoGui_sub {
break; break;
} }
} }
} else if (type_clash == "hysteria") { } else if (type == "hysteria") {
auto bean = ent->HysteriaBean(); auto bean = ent->QUICBean();
bean->hopPort = Node2QString(proxy["ports"]);
if (bean->serverPort == 0) bean->hopPort = Node2QString(proxy["port"]);
bean->allowInsecure = Node2Bool(proxy["skip-cert-verify"]); bean->allowInsecure = Node2Bool(proxy["skip-cert-verify"]);
auto alpn = Node2QStringList(proxy["alpn"]); auto alpn = Node2QStringList(proxy["alpn"]);
bean->caText = Node2QString(proxy["ca-str"]);
if (!alpn.isEmpty()) bean->alpn = alpn[0]; if (!alpn.isEmpty()) bean->alpn = alpn[0];
bean->sni = Node2QString(proxy["sni"]); bean->sni = Node2QString(proxy["sni"]);
bean->name = Node2QString(proxy["name"]);
bean->serverAddress = Node2QString(proxy["server"]);
bean->serverPort = Node2Int(proxy["port"]);
bean->hopPort = Node2QString(proxy["ports"]);
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_str = FIRST_OR_SECOND(Node2QString(proxy["auth_str"]), Node2QString(proxy["auth-str"]));
auto auth = Node2QString(proxy["auth"]); auto auth = Node2QString(proxy["auth"]);
if (!auth_str.isEmpty()) { if (!auth_str.isEmpty()) {
bean->authPayloadType = NekoGui_fmt::HysteriaBean::hysteria_auth_string; bean->authPayloadType = NekoGui_fmt::QUICBean::hysteria_auth_string;
bean->authPayload = auth_str; bean->authPayload = auth_str;
} }
if (!auth.isEmpty()) { if (!auth.isEmpty()) {
bean->authPayloadType = NekoGui_fmt::HysteriaBean::hysteria_auth_base64; bean->authPayloadType = NekoGui_fmt::QUICBean::hysteria_auth_base64;
bean->authPayload = auth; bean->authPayload = auth;
} }
bean->obfsPassword = Node2QString(proxy["obfs"]); bean->obfsPassword = Node2QString(proxy["obfs"]);
@@ -407,6 +405,30 @@ namespace NekoGui_sub {
auto downMbps = Node2QString(proxy["down"]).split(" ")[0].toInt(); auto downMbps = Node2QString(proxy["down"]).split(" ")[0].toInt();
if (upMbps > 0) bean->uploadMbps = upMbps; if (upMbps > 0) bean->uploadMbps = upMbps;
if (downMbps > 0) bean->downloadMbps = downMbps; if (downMbps > 0) bean->downloadMbps = downMbps;
} else if (type == "tuic") {
auto bean = ent->QUICBean();
bean->uuid = Node2QString(proxy["uuid"]);
bean->password = Node2QString(proxy["password"]);
if (Node2Int(proxy["heartbeat-interval"]) != 0) {
bean->heartbeat = Int2String(Node2Int(proxy["heartbeat-interval"])) + "ms";
}
bean->udpRelayMode = Node2QString(proxy["udp-relay-mode"]);
bean->congestionControl = Node2QString(proxy["congestion-controller"]);
bean->disableSni = Node2Bool(proxy["disable-sni"]);
bean->zeroRttHandshake = Node2Bool(proxy["reduce-rtt"]);
bean->allowInsecure = Node2Bool(proxy["skip-cert-verify"]);
bean->alpn = Node2QStringList(proxy["alpn"]).join(",");
bean->caText = Node2QString(proxy["ca-str"]);
bean->sni = Node2QString(proxy["sni"]);
if (!Node2QString(proxy["ip"]).isEmpty()) {
if (bean->sni.isEmpty()) bean->sni = bean->serverAddress;
bean->serverAddress = Node2QString(proxy["ip"]);
}
} else { } else {
continue; continue;
} }

View File

@@ -856,7 +856,38 @@ This needs to be run NekoBox with administrator privileges.</source>
</message> </message>
</context> </context>
<context> <context>
<name>EditHysteria</name> <name>EditNaive</name>
<message>
<source>Protocol</source>
<translation>پروتکل</translation>
</message>
<message>
<source>Password</source>
<translation>رمزعبور</translation>
</message>
<message>
<source>Extra headers</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SNI</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Username</source>
<translation>نام کاربری</translation>
</message>
<message>
<source>Certificate</source>
<translation type="unfinished">گواهی</translation>
</message>
<message>
<source>Insecure concurrency</source>
<translation>همزمانی ناامن</translation>
</message>
</context>
<context>
<name>EditQUIC</name>
<message> <message>
<source>Certificate</source> <source>Certificate</source>
<translation type="unfinished">گواهی</translation> <translation type="unfinished">گواهی</translation>
@@ -905,36 +936,33 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Auth Payload</source> <source>Auth Payload</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context>
<context>
<name>EditNaive</name>
<message> <message>
<source>Protocol</source> <source>Disable SNI</source>
<translation>پروتکل</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Password</source> <source>Password</source>
<translation>رمزعبور</translation>
</message>
<message>
<source>Extra headers</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>SNI</source> <source>Generate UUID</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Username</source> <source>Heartbeat</source>
<translation>نام کاربری</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Certificate</source> <source>Zero Rtt Handshake</source>
<translation type="unfinished">گواهی</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Insecure concurrency</source> <source>Congestion Control</source>
<translation>همزمانی ناامن</translation> <translation type="unfinished"></translation>
</message>
<message>
<source>UDP Relay Mode</source>
<translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View File

@@ -852,7 +852,38 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
</message> </message>
</context> </context>
<context> <context>
<name>EditHysteria</name> <name>EditNaive</name>
<message>
<source>Protocol</source>
<translation>Протокол</translation>
</message>
<message>
<source>Password</source>
<translation>Пароль</translation>
</message>
<message>
<source>Extra headers</source>
<translation>Дополнительные заголовки</translation>
</message>
<message>
<source>SNI</source>
<translation>SNI</translation>
</message>
<message>
<source>Username</source>
<translation>Имя пользователя</translation>
</message>
<message>
<source>Certificate</source>
<translation>Сертификат</translation>
</message>
<message>
<source>Insecure concurrency</source>
<translation></translation>
</message>
</context>
<context>
<name>EditQUIC</name>
<message> <message>
<source>Auth Type</source> <source>Auth Type</source>
<translation>Тип авторизации</translation> <translation>Тип авторизации</translation>
@@ -901,36 +932,33 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
<source>Auth Payload</source> <source>Auth Payload</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context>
<context>
<name>EditNaive</name>
<message> <message>
<source>Protocol</source> <source>Disable SNI</source>
<translation>Протокол</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Password</source> <source>Password</source>
<translation>Пароль</translation> <translation type="unfinished">Пароль</translation>
</message> </message>
<message> <message>
<source>Extra headers</source> <source>Generate UUID</source>
<translation>Дополнительные заголовки</translation> <translation type="unfinished">Сгенерировать</translation>
</message> </message>
<message> <message>
<source>SNI</source> <source>Heartbeat</source>
<translation>SNI</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Username</source> <source>Zero Rtt Handshake</source>
<translation>Имя пользователя</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Certificate</source> <source>Congestion Control</source>
<translation>Сертификат</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Insecure concurrency</source> <source>UDP Relay Mode</source>
<translation></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View File

@@ -856,7 +856,38 @@ This needs to be run NekoBox with administrator privileges.</source>
</message> </message>
</context> </context>
<context> <context>
<name>EditHysteria</name> <name>EditNaive</name>
<message>
<source>Protocol</source>
<translation></translation>
</message>
<message>
<source>Password</source>
<translation></translation>
</message>
<message>
<source>Extra headers</source>
<translation></translation>
</message>
<message>
<source>SNI</source>
<translation></translation>
</message>
<message>
<source>Username</source>
<translation></translation>
</message>
<message>
<source>Certificate</source>
<translation></translation>
</message>
<message>
<source>Insecure concurrency</source>
<translation></translation>
</message>
</context>
<context>
<name>EditQUIC</name>
<message> <message>
<source>Certificate</source> <source>Certificate</source>
<translation></translation> <translation></translation>
@@ -905,36 +936,33 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Auth Payload</source> <source>Auth Payload</source>
<translation></translation> <translation></translation>
</message> </message>
</context>
<context>
<name>EditNaive</name>
<message> <message>
<source>Protocol</source> <source>Generate UUID</source>
<translation></translation> <translation> UUID</translation>
</message> </message>
<message> <message>
<source>Password</source> <source>Password</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>Extra headers</source> <source>Zero Rtt Handshake</source>
<translation></translation> <translation>0-Rtt </translation>
</message> </message>
<message> <message>
<source>SNI</source> <source>UDP Relay Mode</source>
<translation></translation> <translation>UDP </translation>
</message> </message>
<message> <message>
<source>Username</source> <source>Congestion Control</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>Certificate</source> <source>Heartbeat</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>Insecure concurrency</source> <source>Disable SNI</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context> <context>

View File

@@ -169,6 +169,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map); CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map);
if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", ""); if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", "");
if (!CACHE.extraCore.contains("hysteria")) CACHE.extraCore.insert("hysteria", ""); if (!CACHE.extraCore.contains("hysteria")) CACHE.extraCore.insert("hysteria", "");
if (!CACHE.extraCore.contains("tuic")) CACHE.extraCore.insert("tuic", "");
// //
auto extra_core_layout = ui->extra_core_box_scrollAreaWidgetContents->layout(); auto extra_core_layout = ui->extra_core_box_scrollAreaWidgetContents->layout();
for (const auto &s: CACHE.extraCore.keys()) { for (const auto &s: CACHE.extraCore.keys()) {

View File

@@ -7,7 +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_quic.h"
#include "ui/edit/edit_custom.h" #include "ui/edit/edit_custom.h"
#include "fmt/includes.h" #include "fmt/includes.h"
@@ -32,7 +32,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
connect(ui->network, &QComboBox::currentTextChanged, this, [=](const QString &txt) { connect(ui->network, &QComboBox::currentTextChanged, this, [=](const QString &txt) {
ui->network_box->setTitle(network_title_base.arg(txt)); ui->network_box->setTitle(network_title_base.arg(txt));
// 传输设置 // 传输设置
if (txt == "tcp" || (!IS_NEKO_BOX && txt == "quic")) { if (txt == "tcp") {
ui->header_type->setVisible(true); ui->header_type->setVisible(true);
ui->header_type_l->setVisible(true); ui->header_type_l->setVisible(true);
ui->path->setVisible(true); ui->path->setVisible(true);
@@ -121,6 +121,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
LOAD_TYPE("vless") LOAD_TYPE("vless")
LOAD_TYPE("naive") LOAD_TYPE("naive")
LOAD_TYPE("hysteria") LOAD_TYPE("hysteria")
LOAD_TYPE("tuic")
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");
@@ -176,8 +177,8 @@ 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 == "hysteria") { } else if (type == "hysteria" || type == "tuic") {
auto _innerWidget = new EditHysteria(this); auto _innerWidget = new EditQUIC(this);
innerWidget = _innerWidget; innerWidget = _innerWidget;
innerEditor = _innerWidget; innerEditor = _innerWidget;
} else if (type == "custom" || type == "internal" || type == "internal-full") { } else if (type == "custom" || type == "internal" || type == "internal-full") {

View File

@@ -1,72 +0,0 @@
#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(std::shared_ptr<NekoGui::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();
}
}

View File

@@ -1,242 +0,0 @@
<?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">
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Hop Port</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="MyLineEdit" name="hopPort"/>
</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="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Upload (Mbps)</string>
</property>
</widget>
</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="3" column="1">
<widget class="MyLineEdit" name="downloadMbps"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Protocol</string>
</property>
</widget>
</item>
<item row="4" 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="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Obfs Password</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="MyLineEdit" name="obfsPassword"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Auth Type</string>
</property>
</widget>
</item>
<item row="6" 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="7" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Auth Payload</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="MyLineEdit" name="authPayload"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>SNI</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="MyLineEdit" name="sni"/>
</item>
<item row="9" 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="9" 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="10" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Certificate</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QPushButton" name="certificate">
<property name="text">
<string notr="true">PushButton</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string notr="true">recv_window</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="MyLineEdit" name="streamReceiveWindow"/>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string notr="true">recv_window_conn</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="MyLineEdit" name="connectionReceiveWindow"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>MyLineEdit</class>
<extends>QLineEdit</extends>
<header>ui/widget/MyLineEdit.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>hopPort</tabstop>
<tabstop>hopInterval</tabstop>
<tabstop>uploadMbps</tabstop>
<tabstop>downloadMbps</tabstop>
<tabstop>protocol</tabstop>
<tabstop>disableMtuDiscovery</tabstop>
<tabstop>obfsPassword</tabstop>
<tabstop>authPayloadType</tabstop>
<tabstop>authPayload</tabstop>
<tabstop>sni</tabstop>
<tabstop>alpn</tabstop>
<tabstop>allowInsecure</tabstop>
<tabstop>certificate</tabstop>
<tabstop>streamReceiveWindow</tabstop>
<tabstop>connectionReceiveWindow</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

132
ui/edit/edit_quic.cpp Normal file
View File

@@ -0,0 +1,132 @@
#include "edit_quic.h"
#include "ui_edit_quic.h"
#include "fmt/QUICBean.hpp"
#include <QInputDialog>
#include <QUuid>
EditQUIC::EditQUIC(QWidget *parent) : QWidget(parent), ui(new Ui::EditQUIC) {
ui->setupUi(this);
connect(ui->uuidgen, &QPushButton::clicked, this, [=] { ui->uuid->setText(QUuid::createUuid().toString().remove("{").remove("}")); });
}
EditQUIC::~EditQUIC() {
delete ui;
}
void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
this->ent = _ent;
auto bean = this->ent->QUICBean();
if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria) {
P_LOAD_STRING(hopPort);
P_LOAD_INT(hopInterval);
P_LOAD_INT(uploadMbps);
P_LOAD_INT(downloadMbps);
P_LOAD_COMBO_INT(hyProtocol);
P_LOAD_BOOL(disableMtuDiscovery)
P_LOAD_STRING(obfsPassword);
P_LOAD_COMBO_INT(authPayloadType);
P_LOAD_STRING(authPayload);
P_LOAD_INT(streamReceiveWindow);
P_LOAD_INT(connectionReceiveWindow);
ui->uuid->hide();
ui->uuid_l->hide();
ui->uuidgen->hide();
ui->password->hide();
ui->password_l->hide();
ui->congestionControl->hide();
ui->congestionControl_l->hide();
ui->udpRelayMode->hide();
ui->udpRelayMode_l->hide();
ui->zeroRttHandshake->hide();
ui->heartbeat->hide();
ui->heartbeat_l->hide();
} else if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_TUIC) {
P_LOAD_STRING(uuid);
P_LOAD_STRING(password);
P_LOAD_COMBO_STRING(congestionControl);
P_LOAD_COMBO_STRING(udpRelayMode);
P_LOAD_BOOL(zeroRttHandshake);
P_LOAD_STRING(heartbeat);
ui->hopPort->hide();
ui->hopPort_l->hide();
ui->hopInterval->hide();
ui->hopInterval_l->hide();
ui->uploadMbps->hide();
ui->uploadMbps_l->hide();
ui->downloadMbps->hide();
ui->downloadMbps_l->hide();
ui->hyProtocol->hide();
ui->hyProtocol_l->hide();
ui->disableMtuDiscovery->hide();
ui->obfsPassword->hide();
ui->obfsPassword_l->hide();
ui->authPayload->hide();
ui->authPayload_l->hide();
ui->authPayloadType->hide();
ui->authPayloadType_l->hide();
ui->streamReceiveWindow->hide();
ui->streamReceiveWindow_l->hide();
ui->connectionReceiveWindow->hide();
ui->connectionReceiveWindow_l->hide();
}
// TLS
P_LOAD_STRING(sni);
P_LOAD_STRING(alpn);
P_C_LOAD_STRING(caText);
P_LOAD_BOOL(allowInsecure);
P_LOAD_BOOL(disableSni);
}
bool EditQUIC::onEnd() {
auto bean = this->ent->QUICBean();
// Hysteria
P_SAVE_STRING(hopPort);
P_SAVE_INT(hopInterval);
P_SAVE_INT(uploadMbps);
P_SAVE_INT(downloadMbps);
P_SAVE_COMBO_INT(hyProtocol);
P_SAVE_BOOL(disableMtuDiscovery)
P_SAVE_STRING(obfsPassword);
P_SAVE_COMBO_INT(authPayloadType);
P_SAVE_STRING(authPayload);
P_SAVE_INT(streamReceiveWindow);
P_SAVE_INT(connectionReceiveWindow);
// TUIC
P_SAVE_STRING(uuid);
P_SAVE_STRING(password);
P_SAVE_COMBO_STRING(congestionControl);
P_SAVE_COMBO_STRING(udpRelayMode);
P_SAVE_BOOL(zeroRttHandshake);
P_SAVE_STRING(heartbeat);
// TLS
P_SAVE_STRING(sni);
P_SAVE_STRING(alpn);
P_SAVE_BOOL(allowInsecure);
P_C_SAVE_STRING(caText);
P_SAVE_BOOL(disableSni);
return true;
}
QList<QPair<QPushButton *, QString>> EditQUIC::get_editor_cached() {
return {
{ui->certificate, CACHE.caText},
};
}
void EditQUIC::on_certificate_clicked() {
bool ok;
auto txt = QInputDialog::getMultiLineText(this, tr("Certificate"), "", CACHE.caText, &ok);
if (ok) {
CACHE.caText = txt;
editor_cache_updated();
}
}

View File

@@ -1,21 +1,23 @@
#pragma once #pragma once
#include <QWidget> #include <QWidget>
#include <QGridLayout>
#include <QHBoxLayout>
#include "profile_editor.h" #include "profile_editor.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { namespace Ui {
class EditHysteria; class EditQUIC;
} }
QT_END_NAMESPACE QT_END_NAMESPACE
class EditHysteria : public QWidget, public ProfileEditor { class EditQUIC : public QWidget, public ProfileEditor {
Q_OBJECT Q_OBJECT
public: public:
explicit EditHysteria(QWidget *parent = nullptr); explicit EditQUIC(QWidget *parent = nullptr);
~EditHysteria() override; ~EditQUIC() override;
void onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) override; void onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) override;
@@ -24,7 +26,7 @@ public:
QList<QPair<QPushButton *, QString>> get_editor_cached() override; QList<QPair<QPushButton *, QString>> get_editor_cached() override;
private: private:
Ui::EditHysteria *ui; Ui::EditQUIC *ui;
std::shared_ptr<NekoGui::ProxyEntity> ent; std::shared_ptr<NekoGui::ProxyEntity> ent;
struct { struct {

436
ui/edit/edit_quic.ui Normal file
View File

@@ -0,0 +1,436 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditQUIC</class>
<widget class="QWidget" name="EditQUIC">
<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="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="upBox">
<item row="1" column="1">
<layout class="QHBoxLayout" name="downloadMbpsLay">
<item>
<widget class="QLabel" name="downloadMbps_l">
<property name="text">
<string>Download (Mbps)</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="downloadMbps"/>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="hopPortLay">
<item>
<widget class="QLabel" name="hopPort_l">
<property name="text">
<string>Hop Port</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="hopPort"/>
</item>
</layout>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="udpRelayModeLay">
<item>
<widget class="QLabel" name="udpRelayMode_l">
<property name="text">
<string>UDP Relay Mode</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="udpRelayMode">
<item>
<property name="text">
<string notr="true">native</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">quic</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="congestionControlLay">
<item>
<widget class="QLabel" name="congestionControl_l">
<property name="text">
<string>Congestion Control</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="congestionControl">
<item>
<property name="text">
<string notr="true">bbr</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">cubic</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">new_reno</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="uploadMbpsLay">
<item>
<widget class="QLabel" name="uploadMbps_l">
<property name="text">
<string>Upload (Mbps)</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="uploadMbps"/>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="hopIntervalLay">
<item>
<widget class="QLabel" name="hopInterval_l">
<property name="text">
<string>Hop Interval (s)</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="hopInterval"/>
</item>
</layout>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="zeroRttHandshake">
<property name="text">
<string>Zero Rtt Handshake</string>
</property>
</widget>
</item>
<item row="3" column="0">
<layout class="QHBoxLayout" name="heartbeatLay">
<item>
<widget class="QLabel" name="heartbeat_l">
<property name="text">
<string>Heartbeat</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="heartbeat">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="obfuscation">
<item row="1" column="1">
<widget class="MyLineEdit" name="obfsPassword"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="obfsPassword_l">
<property name="text">
<string>Obfs Password</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="hyProtocol_l">
<property name="text">
<string>Protocol</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="hyProtocol">
<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>
</layout>
</item>
<item>
<layout class="QGridLayout" name="authentication">
<item row="2" column="1">
<widget class="MyLineEdit" name="uuid"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="authPayloadType_l">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Auth Type</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="authPayload_l">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Auth Payload</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="password_l">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="uuid_l">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">UUID</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="uuidgen">
<property name="text">
<string>Generate UUID</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="MyLineEdit" name="password"/>
</item>
<item row="1" column="1" colspan="2">
<widget class="MyLineEdit" name="authPayload"/>
</item>
<item row="0" column="1" colspan="2">
<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>
</layout>
</item>
<item>
<layout class="QGridLayout" name="TLS" rowstretch="0,0,0">
<item row="2" column="0">
<widget class="QLabel" name="certificate_l">
<property name="text">
<string>Certificate</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="certificate">
<property name="text">
<string notr="true">PushButton</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="MyLineEdit" name="alpn"/>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="disableSni">
<property name="text">
<string>Disable SNI</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="MyLineEdit" name="sni"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="alpn_l">
<property name="text">
<string notr="true">ALPN</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="allowInsecure">
<property name="text">
<string>Allow Insecure</string>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="sni_l">
<property name="text">
<string>SNI</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="flowControlWindow">
<item>
<widget class="QLabel" name="streamReceiveWindow_l">
<property name="text">
<string notr="true">recv_window</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="streamReceiveWindow"/>
</item>
<item>
<widget class="QLabel" name="connectionReceiveWindow_l">
<property name="text">
<string notr="true">recv_window_conn</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="connectionReceiveWindow"/>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>MyLineEdit</class>
<extends>QLineEdit</extends>
<header>ui/widget/MyLineEdit.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>hopPort</tabstop>
<tabstop>hopInterval</tabstop>
<tabstop>uploadMbps</tabstop>
<tabstop>downloadMbps</tabstop>
<tabstop>congestionControl</tabstop>
<tabstop>udpRelayMode</tabstop>
<tabstop>heartbeat</tabstop>
<tabstop>zeroRttHandshake</tabstop>
<tabstop>hyProtocol</tabstop>
<tabstop>disableMtuDiscovery</tabstop>
<tabstop>obfsPassword</tabstop>
<tabstop>authPayloadType</tabstop>
<tabstop>authPayload</tabstop>
<tabstop>uuid</tabstop>
<tabstop>uuidgen</tabstop>
<tabstop>password</tabstop>
<tabstop>sni</tabstop>
<tabstop>disableSni</tabstop>
<tabstop>alpn</tabstop>
<tabstop>allowInsecure</tabstop>
<tabstop>certificate</tabstop>
<tabstop>streamReceiveWindow</tabstop>
<tabstop>connectionReceiveWindow</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>