mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-20 11:36:06 +00:00
fix(frontend): TProxy schema, VLESS+XHTTP flow links, clearable Jalali date picker (#5339, #5322, #5313)
- #5339: accept transportless tunnel/TProxy streamSettings that carry no `security` key by adding a transportless branch to SecuritySettingsSchema, mirroring NetworkSettingsSchema. Fixes "streamSettings.security Invalid input". - #5322: emit XTLS Vision `flow` in panel VLESS share links for XHTTP+vlessenc via the shared canEnableTlsFlow predicate, so panel links match the form and the subscription output. - #5313: give the Jalali expiry date picker a working clear (X) button (remount on clear, since the library reads `value` only on mount) and a blank placeholder instead of the library's hardcoded Persian text.
This commit is contained in:
@@ -12,6 +12,7 @@ import type { FinalMaskStreamSettings } from '@/schemas/protocols/stream/finalma
|
||||
import type { XHttpStreamSettings } from '@/schemas/protocols/stream/xhttp';
|
||||
|
||||
import { getHeaderValue } from './headers';
|
||||
import { canEnableTlsFlow } from './protocol-capabilities';
|
||||
|
||||
// Share-link generators. Each per-protocol fn takes a typed inbound plus
|
||||
// client overrides and returns a URL (or '' when the protocol doesn't
|
||||
@@ -186,7 +187,7 @@ export function genVmessLink(input: GenVmessLinkInput): string {
|
||||
const stream = inbound.streamSettings;
|
||||
if (!stream) return '';
|
||||
|
||||
const tls = forceTls === 'same' ? stream.security : forceTls;
|
||||
const tls = forceTls === 'same' ? (stream.security ?? 'none') : forceTls;
|
||||
const obj: Record<string, unknown> = {
|
||||
v: '2',
|
||||
ps: remark,
|
||||
@@ -382,7 +383,6 @@ export function genVlessLink(input: GenVlessLinkInput): string {
|
||||
if (tls.settings.pinnedPeerCertSha256.length > 0) {
|
||||
params.set('pcs', tls.settings.pinnedPeerCertSha256.join(','));
|
||||
}
|
||||
if (stream.network === 'tcp' && flow.length > 0) params.set('flow', flow);
|
||||
}
|
||||
applyExternalProxyTLSParams(externalProxy, params, security);
|
||||
} else if (security === 'reality') {
|
||||
@@ -402,12 +402,23 @@ export function genVlessLink(input: GenVlessLinkInput): string {
|
||||
if (reality.shortIds.length > 0) params.set('sid', reality.shortIds[0]);
|
||||
if (reality.settings.spiderX.length > 0) params.set('spx', reality.settings.spiderX);
|
||||
if (reality.settings.mldsa65Verify.length > 0) params.set('pqv', reality.settings.mldsa65Verify);
|
||||
if (stream.network === 'tcp' && flow.length > 0) params.set('flow', flow);
|
||||
}
|
||||
} else {
|
||||
params.set('security', 'none');
|
||||
}
|
||||
|
||||
// XTLS Vision flow: TCP over tls/reality (classic) or XHTTP+vlessenc (the
|
||||
// VLESS-level encryption stands in for transport TLS). Mirrors the backend's
|
||||
// vlessFlowAllowed and the form's flow-field gating so panel link, share
|
||||
// link and subscription agree.
|
||||
if (flow.length > 0 && canEnableTlsFlow({
|
||||
protocol: inbound.protocol,
|
||||
settings: inbound.settings,
|
||||
streamSettings: stream,
|
||||
})) {
|
||||
params.set('flow', flow);
|
||||
}
|
||||
|
||||
const url = new URL(`vless://${clientId}@${formatUrlHost(address)}:${port}`);
|
||||
for (const [key, value] of params) url.searchParams.set(key, value);
|
||||
url.hash = encodeURIComponent(remark);
|
||||
|
||||
Reference in New Issue
Block a user