From 1cf2582e6dccd7aeef90d8a27551fba6aec085ea Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Thu, 14 May 2026 12:30:48 +0200 Subject: [PATCH 01/16] fix: hide QR code for mldsa65 links (too long for QR generation) --- frontend/src/pages/inbounds/QrCodeModal.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/inbounds/QrCodeModal.vue b/frontend/src/pages/inbounds/QrCodeModal.vue index 9d7db272..ebb7f1d0 100644 --- a/frontend/src/pages/inbounds/QrCodeModal.vue +++ b/frontend/src/pages/inbounds/QrCodeModal.vue @@ -111,7 +111,8 @@ function close() { From ae6f13b53300ae4c6d7f8dedee4c09fa016d037c Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Thu, 14 May 2026 12:34:23 +0200 Subject: [PATCH 02/16] fix: also hide QR code for ML-KEM-768 links (too long for QR generation) --- frontend/src/pages/inbounds/QrCodeModal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/inbounds/QrCodeModal.vue b/frontend/src/pages/inbounds/QrCodeModal.vue index ebb7f1d0..6e01f8d7 100644 --- a/frontend/src/pages/inbounds/QrCodeModal.vue +++ b/frontend/src/pages/inbounds/QrCodeModal.vue @@ -112,7 +112,7 @@ function close() { + :show-qr="!item.value.includes('mldsa65') && !item.value.includes('ML-KEM-768')" /> From 1f052c0e8f0c354b922211cf20c5e8a0557a9313 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Thu, 14 May 2026 12:41:08 +0200 Subject: [PATCH 03/16] fix: preserve TLS cert file paths when deploying inbound to remote node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When creating a Hysteria (or any TLS-required) inbound from the central panel and deploying it to a remote node, sanitizeStreamSettingsForRemote was unconditionally stripping certificateFile / keyFile from the TLS settings. This left Xray on the remote node with a TLS block containing no certificate, causing Xray to crash and the inbounds page to hang. The fix: only strip cert file paths when inline certificate content (certificate / key arrays) is also present in the same entry — those file paths are then truly redundant. When only file paths are present the user explicitly entered paths that live on the remote node's filesystem; they are now passed through untouched. Fixes #4370 --- web/runtime/remote.go | 39 +++++++++++++--- web/runtime/remote_test.go | 96 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 web/runtime/remote_test.go diff --git a/web/runtime/remote.go b/web/runtime/remote.go index c71714e7..9cc83f32 100644 --- a/web/runtime/remote.go +++ b/web/runtime/remote.go @@ -344,10 +344,15 @@ func wireInbound(ib *model.Inbound) url.Values { } // sanitizeStreamSettingsForRemote strips file-based TLS certificate paths -// from the StreamSettings before sending to a remote node. File paths -// (certificateFile / keyFile) are local to the main panel's filesystem -// and will cause Xray on the remote node to crash if they don't exist there. -// Inline certificate content (certificate / key) is kept intact. +// from the StreamSettings before sending to a remote node, but ONLY when +// inline certificate content (certificate / key) is also present in the same +// entry. In that case the file paths are redundant and stripping them avoids +// confusion when the central panel's local paths don't exist on the remote. +// +// When a certificate entry contains ONLY file paths (no inline content) the +// paths are left untouched: the user explicitly entered paths that exist on +// the remote node's filesystem, and removing them would leave Xray with TLS +// configured but no certificate, causing Xray to crash on the remote node. func sanitizeStreamSettingsForRemote(streamSettings string) string { if streamSettings == "" { return streamSettings @@ -368,18 +373,40 @@ func sanitizeStreamSettingsForRemote(streamSettings string) string { return streamSettings } + changed := false for _, cert := range certificates { c, ok := cert.(map[string]any) if !ok { continue } - delete(c, "certificateFile") - delete(c, "keyFile") + // Only strip file paths when inline content is present so that the + // remote Xray still has a valid certificate to use. + hasCertFile := c["certificateFile"] != nil && c["certificateFile"] != "" + hasKeyFile := c["keyFile"] != nil && c["keyFile"] != "" + hasCertInline := isNonEmptySlice(c["certificate"]) + hasKeyInline := isNonEmptySlice(c["key"]) + if hasCertFile && hasCertInline { + delete(c, "certificateFile") + changed = true + } + if hasKeyFile && hasKeyInline { + delete(c, "keyFile") + changed = true + } } + if !changed { + return streamSettings + } out, err := json.Marshal(stream) if err != nil { return streamSettings } return string(out) } + +// isNonEmptySlice reports whether v is a non-nil, non-empty JSON array value. +func isNonEmptySlice(v any) bool { + s, ok := v.([]any) + return ok && len(s) > 0 +} diff --git a/web/runtime/remote_test.go b/web/runtime/remote_test.go new file mode 100644 index 00000000..dd966792 --- /dev/null +++ b/web/runtime/remote_test.go @@ -0,0 +1,96 @@ +package runtime + +import ( + "encoding/json" + "testing" +) + +func TestSanitizeStreamSettingsForRemote(t *testing.T) { + tests := []struct { + name string + input string + // wantCertFile / wantKeyFile: expected presence after sanitize + wantCertFile bool + wantKeyFile bool + }{ + { + name: "file paths only — kept intact (remote node paths)", + input: `{ + "tlsSettings": { + "certificates": [{ + "certificateFile": "/etc/ssl/cert.crt", + "keyFile": "/etc/ssl/key.key" + }] + } + }`, + wantCertFile: true, + wantKeyFile: true, + }, + { + name: "inline content only — unchanged", + input: `{ + "tlsSettings": { + "certificates": [{ + "certificate": ["-----BEGIN CERTIFICATE-----"], + "key": ["-----BEGIN PRIVATE KEY-----"] + }] + } + }`, + wantCertFile: false, + wantKeyFile: false, + }, + { + name: "both file paths and inline content — file paths stripped (redundant)", + input: `{ + "tlsSettings": { + "certificates": [{ + "certificateFile": "/etc/ssl/cert.crt", + "keyFile": "/etc/ssl/key.key", + "certificate": ["-----BEGIN CERTIFICATE-----"], + "key": ["-----BEGIN PRIVATE KEY-----"] + }] + } + }`, + wantCertFile: false, + wantKeyFile: false, + }, + { + name: "empty stream settings", + input: "", + // empty input returns empty, nothing to check + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if tc.input == "" { + if got := sanitizeStreamSettingsForRemote(tc.input); got != "" { + t.Errorf("expected empty string, got %q", got) + } + return + } + got := sanitizeStreamSettingsForRemote(tc.input) + var out map[string]any + if err := json.Unmarshal([]byte(got), &out); err != nil { + t.Fatalf("output is not valid JSON: %v\noutput: %s", err, got) + } + + tls, _ := out["tlsSettings"].(map[string]any) + certs, _ := tls["certificates"].([]any) + if len(certs) == 0 { + t.Fatal("certificates array missing in output") + } + cert, _ := certs[0].(map[string]any) + + _, hasCertFile := cert["certificateFile"] + _, hasKeyFile := cert["keyFile"] + + if hasCertFile != tc.wantCertFile { + t.Errorf("certificateFile present=%v, want %v", hasCertFile, tc.wantCertFile) + } + if hasKeyFile != tc.wantKeyFile { + t.Errorf("keyFile present=%v, want %v", hasKeyFile, tc.wantKeyFile) + } + }) + } +} From 1284756f8a1f7313f1132ebf97d7686ec2e55214 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Thu, 14 May 2026 13:27:55 +0200 Subject: [PATCH 04/16] fix(outbound): restore TLS, QUIC params and TCP masks when importing share links - fromHysteriaLink: parse security= URL param and populate stream.tls (SNI, fingerprint, ALPN, ECH) when security=tls; previously always forced security to 'none' - fromHysteriaLink: parse fm JSON param and populate both stream.finalmask.quicParams (drives the QUIC Params toggle in FinalMaskForm) and the mirrored stream.hysteria fields - fromParamLink (VLESS/Trojan/SS): parse fm JSON param and restore stream.finalmask (TCP masks, UDP masks, QUIC params) - fromVmessLink (VMess): same fm handling for the base64-JSON path Closes #4376 --- frontend/src/models/outbound.js | 61 +++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/frontend/src/models/outbound.js b/frontend/src/models/outbound.js index f2cabf3e..8277590e 100644 --- a/frontend/src/models/outbound.js +++ b/frontend/src/models/outbound.js @@ -1397,6 +1397,13 @@ export class Outbound extends CommonClass { const port = json.port * 1; + // Parse fm (finalmask) JSON string — TCP/UDP masks + QUIC params from 3x-ui share links + if (json.fm) { + try { + stream.finalmask = FinalMaskStreamSettings.fromJson(JSON.parse(json.fm)); + } catch (_) { /* ignore malformed fm */ } + } + return new Outbound(json.ps, Protocols.VMess, new Outbound.VmessSettings(json.add, port, json.id, json.scy), stream); } @@ -1496,6 +1503,14 @@ export class Outbound extends CommonClass { default: return null; } + // Parse fm (finalmask) JSON param — TCP/UDP masks + QUIC params from 3x-ui share links + const fmRaw = url.searchParams.get('fm'); + if (fmRaw) { + try { + stream.finalmask = FinalMaskStreamSettings.fromJson(JSON.parse(fmRaw)); + } catch (_) { /* ignore malformed fm */ } + } + let remark = decodeURIComponent(url.hash); // Remove '#' from url.hash remark = remark.length > 0 ? remark.substring(1) : 'out-' + protocol + '-' + port; @@ -1516,7 +1531,17 @@ export class Outbound extends CommonClass { let urlParams = new URLSearchParams(params); // Create stream settings with hysteria network - let stream = new StreamSettings('hysteria', 'none'); + let security = urlParams.get('security') ?? 'none'; + let stream = new StreamSettings('hysteria', security); + + // Parse TLS settings when security=tls + if (security === 'tls') { + let fp = urlParams.get('fp') ?? 'none'; + let alpn = urlParams.get('alpn'); + let sni = urlParams.get('sni') ?? ''; + let ech = urlParams.get('ech') ?? ''; + stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, ech); + } // Set hysteria stream settings stream.hysteria.auth = password; @@ -1534,7 +1559,7 @@ export class Outbound extends CommonClass { stream.hysteria.udphopIntervalMax = parseInt(urlParams.get('udphopIntervalMax') ?? '30'); } - // Optional QUIC parameters + // Optional QUIC parameters for FinalMask support and hysteria2 share links if (urlParams.has('initStreamReceiveWindow')) { stream.hysteria.initStreamReceiveWindow = parseInt(urlParams.get('initStreamReceiveWindow')); } @@ -1557,6 +1582,38 @@ export class Outbound extends CommonClass { stream.hysteria.disablePathMTUDiscovery = urlParams.get('disablePathMTUDiscovery') === 'true'; } + // Parse fm (finalmask) JSON param — TCP/UDP masks + QUIC params from 3x-ui share links, with special handling to mirror QUIC params into both stream.finalmask and stream.hysteria + const fmRaw = urlParams.get('fm'); + if (fmRaw) { + try { + const fm = JSON.parse(fmRaw); + const qp = fm.quicParams; + if (qp && typeof qp === 'object') { + // Populate stream.finalmask.quicParams — this enables the "QUIC Params" + // toggle in FinalMaskForm and carries all QUIC tuning settings. + stream.finalmask.quicParams = QuicParams.fromJson(qp); + + // Also mirror the overlapping fields into stream.hysteria so the + // Hysteria transport section of the form shows consistent values. + if (qp.congestion) stream.hysteria.congestion = qp.congestion; + if (Number.isInteger(qp.initStreamReceiveWindow)) stream.hysteria.initStreamReceiveWindow = qp.initStreamReceiveWindow; + if (Number.isInteger(qp.maxStreamReceiveWindow)) stream.hysteria.maxStreamReceiveWindow = qp.maxStreamReceiveWindow; + if (Number.isInteger(qp.initConnectionReceiveWindow)) stream.hysteria.initConnectionReceiveWindow = qp.initConnectionReceiveWindow; + if (Number.isInteger(qp.maxConnectionReceiveWindow)) stream.hysteria.maxConnectionReceiveWindow = qp.maxConnectionReceiveWindow; + if (Number.isInteger(qp.maxIdleTimeout)) stream.hysteria.maxIdleTimeout = qp.maxIdleTimeout; + if (Number.isInteger(qp.keepAlivePeriod)) stream.hysteria.keepAlivePeriod = qp.keepAlivePeriod; + if (qp.disablePathMTUDiscovery === true) stream.hysteria.disablePathMTUDiscovery = true; + if (qp.udpHop) { + stream.hysteria.udphopPort = qp.udpHop.ports ?? stream.hysteria.udphopPort; + if (qp.udpHop.interval !== undefined) { + stream.hysteria.udphopIntervalMin = qp.udpHop.interval; + stream.hysteria.udphopIntervalMax = qp.udpHop.interval; + } + } + } + } catch (_) { /* ignore malformed fm */ } + } + // Create settings let settings = new Outbound.HysteriaSettings(address, port, 2); From 7065d41be6faa9e3fed662204143ebe85ff4b4eb Mon Sep 17 00:00:00 2001 From: Fedor Batonogov Date: Thu, 14 May 2026 16:54:52 +0300 Subject: [PATCH 05/16] docs(readme): add Community Tools section (#4114) 3x-ui has a growing ecosystem of community tools (Terraform, scripts, exporters, etc.). This adds a Community Tools section between Acknowledgment and Support project in all 6 localized READMEs so users can discover them from the main project page. The format mirrors the existing Acknowledgment section so future maintainers of 3x-ui-related tools can extend it with one-line PRs. --- README.ar_EG.md | 6 ++++++ README.es_ES.md | 6 ++++++ README.fa_IR.md | 6 ++++++ README.md | 6 ++++++ README.ru_RU.md | 6 ++++++ README.zh_CN.md | 6 ++++++ 6 files changed, 36 insertions(+) diff --git a/README.ar_EG.md b/README.ar_EG.md index 0dd359f8..45858626 100644 --- a/README.ar_EG.md +++ b/README.ar_EG.md @@ -39,6 +39,12 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. - [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (الترخيص: **GPL-3.0**): _قواعد توجيه v2ray/xray و v2ray/xray-clients المحسنة مع النطاقات الإيرانية المدمجة وتركيز على الأمان وحظر الإعلانات._ - [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (الترخيص: **GPL-3.0**): _يحتوي هذا المستودع على قواعد توجيه V2Ray محدثة تلقائيًا بناءً على بيانات النطاقات والعناوين المحظورة في روسيا._ +## أدوات المجتمع + +أدوات وتكاملات بناها المجتمع حول 3x-ui. + +- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (الترخيص: **MIT**): _إدارة الاتصالات الواردة والعملاء وإعدادات اللوحة وتكوين Xray كرمز باستخدام Terraform / OpenTofu._ + ## دعم المشروع **إذا كان هذا المشروع مفيدًا لك، فقد ترغب في إعطائه**:star2: diff --git a/README.es_ES.md b/README.es_ES.md index 50758f08..84d012a5 100644 --- a/README.es_ES.md +++ b/README.es_ES.md @@ -39,6 +39,12 @@ Para documentación completa, visita la [Wiki del proyecto](https://github.com/M - [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (Licencia: **GPL-3.0**): _Reglas de enrutamiento mejoradas para v2ray/xray y v2ray/xray-clients con dominios iraníes incorporados y un enfoque en seguridad y bloqueo de anuncios._ - [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (Licencia: **GPL-3.0**): _Este repositorio contiene reglas de enrutamiento V2Ray actualizadas automáticamente basadas en datos de dominios y direcciones bloqueadas en Rusia._ +## Herramientas de la Comunidad + +Herramientas e integraciones construidas por la comunidad alrededor de 3x-ui. + +- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (Licencia: **MIT**): _Gestiona inbounds, clientes, configuración del panel y configuración de Xray como código con Terraform / OpenTofu._ + ## Apoyar el Proyecto **Si este proyecto te es útil, puedes darle una**:star2: diff --git a/README.fa_IR.md b/README.fa_IR.md index e08fd8c2..a6f4956b 100644 --- a/README.fa_IR.md +++ b/README.fa_IR.md @@ -39,6 +39,12 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. - [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (مجوز: **GPL-3.0**): _قوانین مسیریابی بهبود یافته v2ray/xray و v2ray/xray-clients با دامنه‌های ایرانی داخلی و تمرکز بر امنیت و مسدود کردن تبلیغات._ - [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (مجوز: **GPL-3.0**): _این مخزن شامل قوانین مسیریابی V2Ray به‌روزرسانی شده خودکار بر اساس داده‌های دامنه‌ها و آدرس‌های مسدود شده در روسیه است._ +## ابزارهای جامعه + +ابزارها و یکپارچه‌سازی‌هایی که توسط جامعه پیرامون 3x-ui ساخته شده‌اند. + +- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (مجوز: **MIT**): _مدیریت اینباندها، کلاینت‌ها، تنظیمات پنل و پیکربندی Xray به‌صورت کد با Terraform / OpenTofu._ + ## پشتیبانی از پروژه **اگر این پروژه برای شما مفید است، می‌توانید به آن یک**:star2: بدهید diff --git a/README.md b/README.md index 4009acdb..c678ad92 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,12 @@ For full documentation, please visit the [project Wiki](https://github.com/MHSan - [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (License: **GPL-3.0**): _Enhanced v2ray/xray and v2ray/xray-clients routing rules with built-in Iranian domains and a focus on security and adblocking._ - [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (License: **GPL-3.0**): _This repository contains automatically updated V2Ray routing rules based on data on blocked domains and addresses in Russia._ +## Community Tools + +Tools and integrations built by the community around 3x-ui. + +- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (License: **MIT**): _Manage inbounds, clients, panel settings, and Xray configuration as code with Terraform / OpenTofu._ + ## Support project **If this project is helpful to you, you may wish to give it a**:star2: diff --git a/README.ru_RU.md b/README.ru_RU.md index 8ec606a7..d303a306 100644 --- a/README.ru_RU.md +++ b/README.ru_RU.md @@ -39,6 +39,12 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. - [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (Лицензия: **GPL-3.0**): _Улучшенные правила маршрутизации для v2ray/xray и v2ray/xray-clients со встроенными иранскими доменами и фокусом на безопасность и блокировку рекламы._ - [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (Лицензия: **GPL-3.0**): _Этот репозиторий содержит автоматически обновляемые правила маршрутизации V2Ray на основе данных о заблокированных доменах и адресах в России._ +## Инструменты сообщества + +Инструменты и интеграции, созданные сообществом вокруг 3x-ui. + +- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (Лицензия: **MIT**): _Управление входящими, клиентами, настройками панели и конфигурацией Xray через код с помощью Terraform / OpenTofu._ + ## Поддержка проекта **Если этот проект полезен для вас, вы можете поставить ему**:star2: diff --git a/README.zh_CN.md b/README.zh_CN.md index 12c7f9cb..731cf785 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -39,6 +39,12 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. - [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (许可证: **GPL-3.0**): _增强的 v2ray/xray 和 v2ray/xray-clients 路由规则,内置伊朗域名,专注于安全性和广告拦截。_ - [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (许可证: **GPL-3.0**): _此仓库包含基于俄罗斯被阻止域名和地址数据自动更新的 V2Ray 路由规则。_ +## 社区工具 + +社区围绕 3x-ui 构建的工具和集成。 + +- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (许可证: **MIT**): _使用 Terraform / OpenTofu 通过代码管理入站、客户端、面板设置和 Xray 配置。_ + ## 支持项目 **如果这个项目对您有帮助,您可以给它一个**:star2: From e4218a1029a762a224abf0fdd07856a9adfaee11 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Thu, 14 May 2026 17:40:40 +0200 Subject: [PATCH 06/16] feat: click QR to copy/save image instead of link text --- frontend/src/pages/inbounds/QrPanel.vue | 69 +++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/inbounds/QrPanel.vue b/frontend/src/pages/inbounds/QrPanel.vue index 4535137a..dae967f9 100644 --- a/frontend/src/pages/inbounds/QrPanel.vue +++ b/frontend/src/pages/inbounds/QrPanel.vue @@ -1,6 +1,7 @@ + + + + + From 9b0fd047cb52742d171346fde88ace3f8d05a55c Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Thu, 14 May 2026 17:46:24 +0200 Subject: [PATCH 07/16] fix: guard certificate and key against undefined before join --- frontend/src/models/inbound.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/models/inbound.js b/frontend/src/models/inbound.js index 29b0057a..cd789023 100644 --- a/frontend/src/models/inbound.js +++ b/frontend/src/models/inbound.js @@ -827,8 +827,8 @@ TlsStreamSettings.Cert = class extends XrayCommonClass { } else { return new TlsStreamSettings.Cert( false, '', '', - json.certificate.join('\n'), - json.key.join('\n'), + Array.isArray(json.certificate) ? json.certificate.join('\n') : (json.certificate ?? ''), + Array.isArray(json.key) ? json.key.join('\n') : (json.key ?? ''), json.oneTimeLoading, json.usage, json.buildChain, From f3c7660f849cfd4a44a21b5ecd1e7d2bfeac5338 Mon Sep 17 00:00:00 2001 From: Abdalrahman Date: Thu, 14 May 2026 19:53:04 +0300 Subject: [PATCH 08/16] fix: correct Hysteria2 Obfs password label to Auth password (#4388) The Obfs password field in the Hysteria2 stream settings tab was incorrectly labeled. It binds to hysteriaSettings.auth (the server-wide authentication password), not to the salamander obfuscation password. Per Xray-core docs, Hysteria2 salamander obfuscation belongs in finalmask.udp[].salamander.password, which is correctly handled by the FinalMaskForm (UDP Masks section). Fixed the label to Auth password with an accurate tooltip explaining that salamander obfuscation is configured via the UDP Masks section below. --- frontend/src/pages/inbounds/InboundFormModal.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/inbounds/InboundFormModal.vue b/frontend/src/pages/inbounds/InboundFormModal.vue index 022693ec..b7815d2a 100644 --- a/frontend/src/pages/inbounds/InboundFormModal.vue +++ b/frontend/src/pages/inbounds/InboundFormModal.vue @@ -1836,8 +1836,8 @@ watch( From 05b68c3b1346c5c07faa407920ddcb3520403ed9 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Thu, 14 May 2026 19:28:09 +0200 Subject: [PATCH 09/16] fix: remove Auth password #4388 --- frontend/src/pages/inbounds/InboundFormModal.vue | 8 -------- 1 file changed, 8 deletions(-) diff --git a/frontend/src/pages/inbounds/InboundFormModal.vue b/frontend/src/pages/inbounds/InboundFormModal.vue index b7815d2a..c01b8323 100644 --- a/frontend/src/pages/inbounds/InboundFormModal.vue +++ b/frontend/src/pages/inbounds/InboundFormModal.vue @@ -1834,14 +1834,6 @@ watch( - - - -