From 62c293e0348e87ee058a36baf3b52754aeeb7e23 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Fri, 29 May 2026 17:18:21 +0200 Subject: [PATCH] fix(outbounds): support proxyProtocol on freedom outbound MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xray's freedom outbound accepts a numeric proxyProtocol (0 disabled, 1 or 2 for the PROXY protocol version), but the panel had no field for it and the typed form adapter dropped the key on save — so a value set via the JSON editor disappeared the moment the outbound was saved. Model proxyProtocol through the freedom wire schema, the form schema, and both adapter directions (clamped to 0/1/2, omitted from the wire when 0), and add a Select (none / v1 / v2) to the freedom section of the outbound form. Add round-trip test coverage and the proxyProtocol label across all locales. Closes #4486 --- frontend/src/lib/xray/outbound-form-adapter.ts | 5 +++++ frontend/src/pages/xray/OutboundFormModal.tsx | 9 +++++++++ frontend/src/schemas/forms/outbound-form.ts | 1 + frontend/src/schemas/protocols/outbound/freedom.ts | 1 + frontend/src/test/outbound-form-adapter.test.ts | 10 ++++++++++ web/translation/ar-EG.json | 1 + web/translation/en-US.json | 1 + web/translation/es-ES.json | 1 + web/translation/fa-IR.json | 1 + web/translation/id-ID.json | 1 + web/translation/ja-JP.json | 1 + web/translation/pt-BR.json | 1 + web/translation/ru-RU.json | 1 + web/translation/tr-TR.json | 1 + web/translation/uk-UA.json | 1 + web/translation/vi-VN.json | 1 + web/translation/zh-CN.json | 1 + web/translation/zh-TW.json | 1 + 18 files changed, 39 insertions(+) diff --git a/frontend/src/lib/xray/outbound-form-adapter.ts b/frontend/src/lib/xray/outbound-form-adapter.ts index 86c69697..5ecc41b6 100644 --- a/frontend/src/lib/xray/outbound-form-adapter.ts +++ b/frontend/src/lib/xray/outbound-form-adapter.ts @@ -265,6 +265,10 @@ function freedomFromWire(raw: Raw): FreedomOutboundFormSettings { return (allowed.includes(s) ? s : '') as FreedomOutboundFormSettings['domainStrategy']; })(), redirect: asString(raw.redirect), + proxyProtocol: ((): FreedomOutboundFormSettings['proxyProtocol'] => { + const n = asNumber(raw.proxyProtocol, 0); + return (n === 1 || n === 2) ? n : 0; + })(), fragment: wireHasFragment ? { packets: asString(fragment.packets, '1-3'), @@ -489,6 +493,7 @@ function freedomToWire(s: FreedomOutboundFormSettings) { return { domainStrategy: s.domainStrategy || undefined, redirect: s.redirect || undefined, + proxyProtocol: s.proxyProtocol || undefined, fragment: fragmentEnabled ? Object.fromEntries(fragmentEntries) : undefined, noises: s.noises.length > 0 ? s.noises : undefined, finalRules: s.finalRules.length > 0 diff --git a/frontend/src/pages/xray/OutboundFormModal.tsx b/frontend/src/pages/xray/OutboundFormModal.tsx index 8bd90bc6..29f2f2bc 100644 --- a/frontend/src/pages/xray/OutboundFormModal.tsx +++ b/frontend/src/pages/xray/OutboundFormModal.tsx @@ -664,6 +664,15 @@ export default function OutboundFormModal({ + +