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.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.cpp
|
||||
ui/edit/edit_custom.ui
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#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_EXPORT NekoRay::dataStore->core_box_underlying_dns.isEmpty() ? "local" : NekoRay::dataStore->core_box_underlying_dns
|
||||
|
||||
namespace NekoRay {
|
||||
|
||||
@@ -769,7 +770,7 @@ namespace NekoRay {
|
||||
|
||||
// Direct
|
||||
auto directDNSAddress = dataStore->direct_dns;
|
||||
if (directDNSAddress == "localhost") directDNSAddress = BOX_UNDERLYING_DNS;
|
||||
if (directDNSAddress == "localhost") directDNSAddress = BOX_UNDERLYING_DNS_EXPORT;
|
||||
if (!status->forTest)
|
||||
dnsServers += QJsonObject{
|
||||
{"tag", "dns-direct"},
|
||||
@@ -782,7 +783,7 @@ namespace NekoRay {
|
||||
// Underlying 100% Working DNS
|
||||
dnsServers += QJsonObject{
|
||||
{"tag", "dns-local"},
|
||||
{"address", BOX_UNDERLYING_DNS},
|
||||
{"address", BOX_UNDERLYING_DNS_EXPORT},
|
||||
{"detour", "direct"},
|
||||
};
|
||||
|
||||
|
||||
@@ -85,6 +85,8 @@ namespace NekoRay {
|
||||
bean = new fmt::TrojanVLESSBean(fmt::TrojanVLESSBean::proxy_VLESS);
|
||||
} else if (type == "naive") {
|
||||
bean = new fmt::NaiveBean();
|
||||
} else if (type == "hysteria") {
|
||||
bean = new fmt::HysteriaBean();
|
||||
} else if (type == "custom") {
|
||||
bean = new fmt::CustomBean();
|
||||
} else {
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace NekoRay {
|
||||
|
||||
class NaiveBean;
|
||||
|
||||
class HysteriaBean;
|
||||
|
||||
class CustomBean;
|
||||
|
||||
class ChainBean;
|
||||
@@ -63,6 +65,10 @@ namespace NekoRay {
|
||||
return (fmt::NaiveBean *) bean.get();
|
||||
};
|
||||
|
||||
[[nodiscard]] fmt::HysteriaBean *HysteriaBean() const {
|
||||
return (fmt::HysteriaBean *) bean.get();
|
||||
};
|
||||
|
||||
[[nodiscard]] fmt::CustomBean *CustomBean() const {
|
||||
return (fmt::CustomBean *) bean.get();
|
||||
};
|
||||
|
||||
@@ -135,6 +135,34 @@ namespace NekoRay::fmt {
|
||||
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 result;
|
||||
|
||||
|
||||
@@ -31,13 +31,28 @@ namespace NekoRay::fmt {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CustomBean::NeedExternal(bool isFirstProfile, bool isVPN) {
|
||||
if (core == "internal" || core == "internal-full") return 0;
|
||||
if (core == "hysteria") {
|
||||
int HysteriaBean::NeedExternal(bool isFirstProfile, bool isVPN) {
|
||||
if (IS_NEKO_BOX) {
|
||||
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) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int CustomBean::NeedExternal(bool isFirstProfile, bool isVPN) {
|
||||
if (core == "internal" || core == "internal-full") return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -64,8 +79,8 @@ namespace NekoRay::fmt {
|
||||
if (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 (!extra_headers.isEmpty()) result.arguments += "--extra-headers=" + extra_headers;
|
||||
if (!certificate.isEmpty()) {
|
||||
if (!extra_headers.trimmed().isEmpty()) result.arguments += "--extra-headers=" + extra_headers;
|
||||
if (!certificate.trimmed().isEmpty()) {
|
||||
WriteTempFile("naive_" + GetRandomString(10) + ".crt", certificate.toUtf8());
|
||||
result.env += "SSL_CERT_FILE=" + TempFile;
|
||||
}
|
||||
@@ -77,6 +92,67 @@ namespace NekoRay::fmt {
|
||||
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 result{dataStore->extraCore->Get(core)};
|
||||
|
||||
@@ -107,14 +183,6 @@ namespace NekoRay::fmt {
|
||||
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
|
||||
WriteTempFile("custom_" + GetRandomString(10) + suffix, config.toUtf8());
|
||||
for (int i = 0; i < result.arguments.count(); i++) {
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace NekoRay::fmt {
|
||||
{"tls", stream->security == "tls" ? "tls" : ""},
|
||||
{"sni", stream->sni},
|
||||
};
|
||||
return "vmess://" + QJsonObject2QString(N, false).toUtf8().toBase64();
|
||||
return "vmess://" + QJsonObject2QString(N, true).toUtf8().toBase64();
|
||||
}
|
||||
|
||||
QString NaiveBean::ToShareLink() {
|
||||
@@ -116,4 +116,30 @@ namespace NekoRay::fmt {
|
||||
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
|
||||
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());
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -1,21 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
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 {
|
||||
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
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
#include "VMessBean.hpp"
|
||||
#include "TrojanVLESSBean.hpp"
|
||||
#include "NaiveBean.hpp"
|
||||
#include "HysteriaBean.hpp"
|
||||
#include "CustomBean.hpp"
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
|
||||
// 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_SAVE_STRING(a) bean->a = ui->a->text();
|
||||
#define P_SAVE_STRING_QTEXTEDIT(a) bean->a = ui->a->toPlainText();
|
||||
#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_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) \
|
||||
ui->a->setText(Int2String(bean->a)); \
|
||||
ui->a->setValidator(QRegExpValidator_Number);
|
||||
@@ -35,10 +36,14 @@
|
||||
ui->a->setText(Int2String(NekoRay::dataStore->a)); \
|
||||
ui->a->setValidator(QRegExpValidator_Number);
|
||||
#define D_SAVE_INT(a) NekoRay::dataStore->a = ui->a->text().toInt();
|
||||
#define P_LOAD_COMBO(a) ui->a->setCurrentText(bean->a);
|
||||
#define P_SAVE_COMBO(a) bean->a = ui->a->currentText();
|
||||
#define P_LOAD_COMBO_STR(a) ui->a->setCurrentText(bean->a);
|
||||
#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_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) \
|
||||
if (NekoRay::dataStore->i > 0) { \
|
||||
|
||||
@@ -25,6 +25,8 @@ inline std::function<void(QString, QString)> MW_dialog_message;
|
||||
|
||||
// String
|
||||
|
||||
#define FIRST_OR_SECOND(a, b) a.isEmpty() ? b : a
|
||||
|
||||
inline const QString UNICODE_LRO = QString::fromUtf8(QByteArray::fromHex("E280AD"));
|
||||
|
||||
#define Int2String(num) QString::number(num)
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#endif
|
||||
|
||||
#define FIRST_OR_SECOND(a, b) a.isEmpty() ? b : a
|
||||
|
||||
namespace NekoRay::sub {
|
||||
|
||||
GroupUpdater *groupUpdater = new GroupUpdater;
|
||||
@@ -130,28 +128,9 @@ namespace NekoRay::sub {
|
||||
// Hysteria
|
||||
if (str.startsWith("hysteria://")) {
|
||||
needFix = false;
|
||||
// https://github.com/HyNetwork/hysteria/wiki/URI-Scheme
|
||||
ent = ProfileManager::NewProxyEntity("custom");
|
||||
auto bean = ent->CustomBean();
|
||||
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);
|
||||
ent = ProfileManager::NewProxyEntity("hysteria");
|
||||
auto ok = ent->HysteriaBean()->TryParseLink(str);
|
||||
if (!ok) return;
|
||||
}
|
||||
|
||||
if (ent == nullptr) return;
|
||||
@@ -237,7 +216,6 @@ namespace NekoRay::sub {
|
||||
|
||||
if (type == "ss" || type == "ssr") type = "shadowsocks";
|
||||
if (type == "socks5") type = "socks";
|
||||
if (type == "hysteria") type = "custom";
|
||||
|
||||
auto ent = ProfileManager::NewProxyEntity(type);
|
||||
if (ent->bean->version == -114514) continue;
|
||||
@@ -379,45 +357,37 @@ namespace NekoRay::sub {
|
||||
}
|
||||
}
|
||||
} else if (type_clash == "hysteria") {
|
||||
if (!IS_NEKO_BOX) {
|
||||
MW_show_log("Found Clash Meta format hysteria. This is only supported in NekoBox, please switch the core.");
|
||||
continue;
|
||||
auto bean = ent->HysteriaBean();
|
||||
|
||||
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();
|
||||
bean->core = "internal";
|
||||
if (Node2Bool(proxy["disable_mtu_discovery"]) || Node2Bool(proxy["disable-mtu-discovery"])) bean->disableMtuDiscovery = true;
|
||||
bean->streamReceiveWindow = Node2Int(proxy["recv-window"]);
|
||||
bean->connectionReceiveWindow = Node2Int(proxy["recv-window-conn"]);
|
||||
|
||||
QJsonObject coreTlsObj{
|
||||
{"enabled", true},
|
||||
{"insecure", Node2Bool(proxy["skip-cert-verify"])},
|
||||
{"alpn", QList2QJsonArray(Node2QStringList(proxy["alpn"]))},
|
||||
{"server_name", Node2QString(proxy["sni"])},
|
||||
};
|
||||
|
||||
QJsonObject coreHysteriaObj{
|
||||
{"type", "hysteria"},
|
||||
{"tag", Node2QString(proxy["name"])},
|
||||
{"server", Node2QString(proxy["server"])},
|
||||
{"server_port", Node2Int(proxy["port"])},
|
||||
{"auth_str", 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);
|
||||
auto upMbps = Node2QString(proxy["up"]).split(" ")[0].toInt();
|
||||
auto downMbps = Node2QString(proxy["down"]).split(" ")[0].toInt();
|
||||
if (upMbps > 0) bean->uploadMbps = upMbps;
|
||||
if (downMbps > 0) bean->downloadMbps = downMbps;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -719,10 +719,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</source>
|
||||
<source>Config Suffix</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please read the documentation. If you don't understand, use a share link instead.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Outbound JSON, please read the documentation.</source>
|
||||
<translation>JSON خروجی، لطفاً مستندات را بخوانید.</translation>
|
||||
@@ -752,6 +748,57 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>EditNaive</name>
|
||||
<message>
|
||||
|
||||
@@ -716,10 +716,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
|
||||
<source>Outbound JSON, please read the documentation.</source>
|
||||
<translation>填写出站 JSON 对象,详细请看文档。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please read the documentation. If you don't understand, use a share link instead.</source>
|
||||
<translation>格式请看文档。如果不懂,直接导入 hysteria:// 链接。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Config Suffix</source>
|
||||
<translation>配置文件后缀</translation>
|
||||
@@ -745,6 +741,57 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
|
||||
<translation>请填写完整配置。</translation>
|
||||
</message>
|
||||
</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>
|
||||
<name>EditNaive</name>
|
||||
<message>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ui/edit/edit_vmess.h"
|
||||
#include "ui/edit/edit_trojan_vless.h"
|
||||
#include "ui/edit/edit_naive.h"
|
||||
#include "ui/edit/edit_hysteria.h"
|
||||
#include "ui/edit/edit_custom.h"
|
||||
|
||||
#include "fmt/includes.h"
|
||||
@@ -123,7 +124,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
|
||||
LOAD_TYPE("vmess");
|
||||
LOAD_TYPE("vless");
|
||||
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 config)").arg(software_core_name), "internal-full");
|
||||
ui->type->addItem(tr("Custom (Extra Core)"), "custom");
|
||||
@@ -177,7 +178,11 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
||||
auto _innerWidget = new EditNaive(this);
|
||||
innerWidget = _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);
|
||||
innerWidget = _innerWidget;
|
||||
innerEditor = _innerWidget;
|
||||
|
||||
@@ -26,10 +26,10 @@ EditCustom::~EditCustom() {
|
||||
}
|
||||
|
||||
#define SAVE_CUSTOM_BEAN \
|
||||
P_SAVE_COMBO(core) \
|
||||
P_SAVE_COMBO_STR(core) \
|
||||
bean->command = ui->command->text().split(" "); \
|
||||
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(socks_port)
|
||||
|
||||
@@ -43,13 +43,7 @@ void EditCustom::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
||||
if (key == "naive" || key == "hysteria") continue;
|
||||
ui->core->addItem(key);
|
||||
}
|
||||
if (preset_core == "hysteria") {
|
||||
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") {
|
||||
if (preset_core == "internal") {
|
||||
preset_command = preset_config = "";
|
||||
ui->config_simple->setPlaceholderText(
|
||||
"{\n"
|
||||
@@ -66,10 +60,10 @@ void EditCustom::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
||||
}
|
||||
|
||||
// load core ui
|
||||
P_LOAD_COMBO(core)
|
||||
P_LOAD_COMBO_STR(core)
|
||||
ui->command->setText(bean->command.join(" "));
|
||||
P_LOAD_STRING(config_simple)
|
||||
P_LOAD_COMBO(config_suffix)
|
||||
P_LOAD_COMBO_STR(config_suffix)
|
||||
P_LOAD_INT(mapping_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(password);
|
||||
P_LOAD_COMBO(protocol);
|
||||
P_LOAD_COMBO_STR(protocol);
|
||||
P_C_LOAD_STRING(extra_headers);
|
||||
P_LOAD_STRING(sni);
|
||||
P_C_LOAD_STRING(certificate);
|
||||
@@ -31,7 +31,7 @@ bool EditNaive::onEnd() {
|
||||
|
||||
P_SAVE_STRING(username);
|
||||
P_SAVE_STRING(password);
|
||||
P_SAVE_COMBO(protocol);
|
||||
P_SAVE_COMBO_STR(protocol);
|
||||
P_C_SAVE_STRING(extra_headers);
|
||||
P_SAVE_STRING(sni);
|
||||
P_C_SAVE_STRING(certificate);
|
||||
|
||||
Reference in New Issue
Block a user