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