diff --git a/frontend/src/pages/inbounds/InboundFormModal.new.tsx b/frontend/src/pages/inbounds/InboundFormModal.new.tsx index d51e93f2..9459a290 100644 --- a/frontend/src/pages/inbounds/InboundFormModal.new.tsx +++ b/frontend/src/pages/inbounds/InboundFormModal.new.tsx @@ -24,7 +24,12 @@ import { formValuesToWirePayload, } from '@/lib/xray/inbound-form-adapter'; import { createDefaultInboundSettings } from '@/lib/xray/inbound-defaults'; -import { canEnableStream, isSS2022 } from '@/lib/xray/protocol-capabilities'; +import { + canEnableReality, + canEnableStream, + canEnableTls, + isSS2022, +} from '@/lib/xray/protocol-capabilities'; import { SSMethodSchema } from '@/schemas/protocols/inbound/shadowsocks'; import { InboundFormBaseSchema, @@ -38,9 +43,13 @@ import { Protocols, SNIFFING_OPTION, TCP_CONGESTION_OPTION, + TLS_CIPHER_OPTION, + TLS_VERSION_OPTION, UTLS_FINGERPRINT, } from '@/schemas/primitives'; import { SockoptStreamSettingsSchema } from '@/schemas/protocols/stream/sockopt'; +import { TlsStreamSettingsSchema } from '@/schemas/protocols/security/tls'; +import { RealityStreamSettingsSchema } from '@/schemas/protocols/security/reality'; import DateTimePicker from '@/components/DateTimePicker'; import InputAddon from '@/components/InputAddon'; import type { DBInbound } from '@/models/dbinbound'; @@ -114,7 +123,20 @@ export default function InboundFormModalNew({ }); const mixedUdpOn = Form.useWatch(['settings', 'udp'], form) ?? false; const network = Form.useWatch(['streamSettings', 'network'], form) ?? ''; + const security = Form.useWatch(['streamSettings', 'security'], form) ?? 'none'; const streamEnabled = canEnableStream({ protocol }); + const tlsAllowed = canEnableTls({ protocol, streamSettings: { network, security } }); + const realityAllowed = canEnableReality({ protocol, streamSettings: { network, security } }); + + const onSecurityChange = (next: string) => { + const current = (form.getFieldValue('streamSettings') as Record) ?? {}; + const cleaned: Record = { ...current, security: next }; + delete cleaned.tlsSettings; + delete cleaned.realitySettings; + if (next === 'tls') cleaned.tlsSettings = TlsStreamSettingsSchema.parse({}); + if (next === 'reality') cleaned.realitySettings = RealityStreamSettingsSchema.parse({}); + form.setFieldValue('streamSettings', cleaned); + }; const xhttpMode = Form.useWatch(['streamSettings', 'xhttpSettings', 'mode'], form); const xhttpObfsMode = Form.useWatch(['streamSettings', 'xhttpSettings', 'xPaddingObfsMode'], form) ?? false; const xhttpSessionPlacement = Form.useWatch(['streamSettings', 'xhttpSettings', 'sessionPlacement'], form); @@ -1361,6 +1383,108 @@ export default function InboundFormModalNew({ ); + const securityTab = ( + <> + + + prev.streamSettings?.security !== curr.streamSettings?.security + } + > + {({ getFieldValue }) => { + const sec = getFieldValue(['streamSettings', 'security']) ?? 'none'; + return ( + + ); + }} + + + + {security === 'tls' && ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )} + + ); + const sniffingTab = ( <> @@ -1457,7 +1581,10 @@ export default function InboundFormModalNew({ ? [{ key: 'protocol', label: t('pages.inbounds.protocol'), children: protocolTab }] : []), ...(streamEnabled - ? [{ key: 'stream', label: t('pages.inbounds.streamTab'), children: streamTab }] + ? [ + { key: 'stream', label: t('pages.inbounds.streamTab'), children: streamTab }, + { key: 'security', label: t('pages.inbounds.securityTab'), children: securityTab }, + ] : []), { key: 'sniffing', label: t('pages.inbounds.sniffingTab'), children: sniffingTab }, ]} />