diff --git a/fmt/Bean2CoreObj_box.cpp b/fmt/Bean2CoreObj_box.cpp index 319a3d5..c13d743 100644 --- a/fmt/Bean2CoreObj_box.cpp +++ b/fmt/Bean2CoreObj_box.cpp @@ -41,6 +41,13 @@ namespace NekoRay::fmt { {"fingerprint", fp}, }; } + if (!reality_pbk.trimmed().isEmpty()) { + tls["reality"] = QJsonObject{ + {"enabled", true}, + {"public_key", reality_pbk}, + {"short_id", reality_sid}, + }; + } outbound->insert("tls", tls); } diff --git a/fmt/Bean2Link.cpp b/fmt/Bean2Link.cpp index 2bb3ada..874fa38 100644 --- a/fmt/Bean2Link.cpp +++ b/fmt/Bean2Link.cpp @@ -31,9 +31,21 @@ namespace NekoRay::fmt { url.setHost(serverAddress); url.setPort(serverPort); if (!name.isEmpty()) url.setFragment(name); + + // security + auto security = stream->security; + if (security == "tls" && !stream->reality_pbk.trimmed().isEmpty()) security = "reality"; + query.addQueryItem("security", security); + if (!stream->sni.isEmpty()) query.addQueryItem("sni", stream->sni); if (stream->allow_insecure) query.addQueryItem("allowInsecure", "1"); - query.addQueryItem("security", stream->security); + + if (security == "reality") { + query.addQueryItem("pbk", stream->reality_pbk); + query.addQueryItem("sid", stream->reality_sid); + } + + // type query.addQueryItem("type", stream->network); if (stream->network == "ws" || stream->network == "http") { diff --git a/fmt/Link2Bean.cpp b/fmt/Link2Bean.cpp index 71795d8..93d9b6d 100644 --- a/fmt/Link2Bean.cpp +++ b/fmt/Link2Bean.cpp @@ -38,6 +38,8 @@ namespace NekoRay::fmt { stream->security = GetQueryValue(query, "security", ""); stream->sni = GetQueryValue(query, "sni"); + + if (link.startsWith("https")) stream->security = "tls"; } return true; } @@ -54,14 +56,15 @@ namespace NekoRay::fmt { if (serverPort == -1) serverPort = 443; stream->network = GetQueryValue(query, "type", "tcp"); - stream->security = GetQueryValue(query, "security", "tls"); + stream->security = GetQueryValue(query, "security", "tls").replace("reality", "tls"); auto sni1 = GetQueryValue(query, "sni"); auto sni2 = GetQueryValue(query, "peer"); if (!sni1.isEmpty()) stream->sni = sni1; if (!sni2.isEmpty()) stream->sni = sni2; if (!query.queryItemValue("allowInsecure").isEmpty()) stream->allow_insecure = true; + stream->reality_pbk = GetQueryValue(query, "pbk", ""); + stream->reality_sid = GetQueryValue(query, "sid", ""); - // TODO header kcp quic if (stream->network == "ws") { stream->path = GetQueryValue(query, "path", ""); stream->host = GetQueryValue(query, "host", ""); diff --git a/fmt/V2RayStreamSettings.hpp b/fmt/V2RayStreamSettings.hpp index 01143eb..4d43f4d 100644 --- a/fmt/V2RayStreamSettings.hpp +++ b/fmt/V2RayStreamSettings.hpp @@ -22,6 +22,9 @@ namespace NekoRay::fmt { // ws early data QString ws_early_data_name = ""; int ws_early_data_length = 0; + // reality + QString reality_pbk = ""; + QString reality_sid = ""; V2rayStreamSettings() : JsonStore() { _add(new configItem("net", &network, itemType::string)); @@ -37,6 +40,8 @@ namespace NekoRay::fmt { _add(new configItem("ed_name", &ws_early_data_name, itemType::string)); _add(new configItem("ed_len", &ws_early_data_length, itemType::integer)); _add(new configItem("utls", &utlsFingerprint, itemType::string)); + _add(new configItem("pbk", &reality_pbk, itemType::string)); + _add(new configItem("sid", &reality_sid, itemType::string)); } QJsonObject BuildStreamSettingsV2Ray(); diff --git a/translations/fa_IR.ts b/translations/fa_IR.ts index 6ba9e82..45b9906 100644 --- a/translations/fa_IR.ts +++ b/translations/fa_IR.ts @@ -353,7 +353,7 @@ Security Settings - تنظیمات امنیت + تنظیمات امنیت When enabled, V2Ray will not check the validity of the TLS certificate provided by the remote host (the security is equivalent to plaintext) @@ -391,6 +391,18 @@ Already set تنظیم شده + + TLS Security Settings + + + + TLS Camouflage Settings + + + + Reality public key. If not empty, turn TLS into REALITY. + + DialogHotkey diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index f48efb8..44a765c 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -345,13 +345,9 @@ Application layer protocol negotiation, clear text. Please separate them with commas. 应用层协议协商,明文。多个请以英文逗号分隔。 - - Security Settings - 安全设置 - Allow insecure - 不检查服务器证书(不安全) + 不检查服务器证书 Certificate @@ -385,6 +381,18 @@ Custom (%1) 自定义 (%1) + + TLS Security Settings + TLS 安全设置 + + + TLS Camouflage Settings + TLS 伪装设置 + + + Reality public key. If not empty, turn TLS into REALITY. + Reality public key. 如果不为空,则将 TLS 变为 REALITY。 + DialogHotkey diff --git a/ui/dialog_basic_settings.ui b/ui/dialog_basic_settings.ui index 6b0e557..8937dfe 100644 --- a/ui/dialog_basic_settings.ui +++ b/ui/dialog_basic_settings.ui @@ -664,7 +664,7 @@ - + 0 diff --git a/ui/edit/dialog_edit_profile.cpp b/ui/edit/dialog_edit_profile.cpp index 21381b8..7809599 100644 --- a/ui/edit/dialog_edit_profile.cpp +++ b/ui/edit/dialog_edit_profile.cpp @@ -94,8 +94,16 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, connect(ui->security, &QComboBox::currentTextChanged, this, [=](const QString &txt) { if (txt == "tls") { ui->security_box->setVisible(true); + ui->reality_box->setVisible(true); + if (!IS_NEKO_BOX) { + ui->reality_pbk->hide(); + ui->reality_sid->hide(); + ui->reality_pbk_l->hide(); + ui->reality_sid_l->hide(); + } } else { ui->security_box->setVisible(false); + ui->reality_box->setVisible(false); } ADJUST_SIZE }); @@ -196,7 +204,7 @@ void DialogEditProfile::typeSelected(const QString &newType) { ui->port->setVisible(showAddressPort); ui->port_l->setVisible(showAddressPort); - // 右边 Outbound: settings + // 右边 stream auto stream = GetStreamSettings(ent->bean.data()); if (stream != nullptr) { ui->right_all_w->setVisible(true); @@ -212,6 +220,8 @@ void DialogEditProfile::typeSelected(const QString &newType) { ui->header_type->setCurrentText(stream->header_type); ui->ws_early_data_name->setText(stream->ws_early_data_name); ui->ws_early_data_length->setText(Int2String(stream->ws_early_data_length)); + ui->reality_pbk->setText(stream->reality_pbk); + ui->reality_sid->setText(stream->reality_sid); CACHE.certificate = stream->certificate; } else { ui->right_all_w->setVisible(false); @@ -310,7 +320,7 @@ void DialogEditProfile::accept() { return; } - // 右边 + // 右边 stream auto stream = GetStreamSettings(ent->bean.data()); if (stream != nullptr) { stream->network = ui->network->currentText(); @@ -326,7 +336,11 @@ void DialogEditProfile::accept() { stream->ws_early_data_name = ui->ws_early_data_name->text(); stream->ws_early_data_length = ui->ws_early_data_length->text().toInt(); stream->certificate = CACHE.certificate; + stream->reality_pbk = ui->reality_pbk->text(); + stream->reality_sid = ui->reality_sid->text(); } + + // cached custom auto custom_item = ent->bean->_get("custom"); if (custom_item != nullptr) { *((QString *) custom_item->ptr) = CACHE.custom; diff --git a/ui/edit/dialog_edit_profile.ui b/ui/edit/dialog_edit_profile.ui index c171d76..2685b3a 100644 --- a/ui/edit/dialog_edit_profile.ui +++ b/ui/edit/dialog_edit_profile.ui @@ -7,7 +7,7 @@ 0 0 1000 - 678 + 800 @@ -130,7 +130,7 @@ - Edit + Edit @@ -411,7 +411,7 @@ security (QUIC) - Security Settings + TLS Security Settings @@ -440,38 +440,13 @@ security (QUIC) - + 0 0 - - uTLS - - - - - - - true - - - - - - - - - - - PushButton - - - - - @@ -480,6 +455,17 @@ security (QUIC) + + + + Edit + + + + + + + @@ -511,6 +497,58 @@ security (QUIC) + + + + TLS Camouflage Settings + + + + + + Reality public key. If not empty, turn TLS into REALITY. + + + Realty Pbk + + + + + + + Reality Sid + + + + + + + + + + + + + + 0 + 0 + + + + uTLS + + + + + + + true + + + + + + @@ -538,10 +576,12 @@ security (QUIC) ws_early_data_length ws_early_data_name insecure - utlsFingerprint + certificate_edit sni alpn - certificate_edit + utlsFingerprint + reality_pbk + reality_sid