mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-17 03:15:01 +03:00
fix(xray): keep XDRIVE storage and Vision flow within what xray-core runs
xray-core opens an XDRIVE stream's storage only when the inbound starts listening, so a Google Drive inbound saved with the form's defaults (no folder, no secrets), a local one without a folder, or a template one whose template xray cannot use stopped xray and every other inbound with it. validateXDriveStorage applies the core's storage rules at save, on inbound add/update and on the xray template's inbounds and outbounds: the service must be local, Google Drive or template; local and Google Drive need a remoteFolder; Google Drive needs its three non-empty secrets; a template must pass newTemplateStorage's checks (put, get, list and delete urls, and a list namesRegex with one capture group). A VLESS client kept its xtls-rprx-vision flow when its inbound moved to a transport that cannot carry it, and GetXrayConfig only honoured DisableFlow, so the server demanded Vision there and refused every client. GetXrayConfig and the outbound form now apply the Vision gate, and that gate now follows the core in the backend, the subscription service and the frontend: TLS/REALITY on raw TCP, or VLESS encryption on any transport (xray runs Vision inside encryption.CommonConn whatever the transport, not only on XHTTP). The outbound modal passes the VLESS encryption into the gate and gates Mux on the effective flow.
This commit is contained in:
@@ -503,10 +503,8 @@ export function genVlessLink(input: GenVlessLinkInput): string {
|
||||
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.
|
||||
// Same gate as the backend's vlessFlowAllowed and the form's flow field, so the
|
||||
// panel link, share link and subscription agree.
|
||||
if (
|
||||
flow.length > 0 &&
|
||||
canEnableTlsFlow({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { XHttpXmuxSchema } from '@/schemas/protocols/stream/xhttp';
|
||||
import { OutboundDomainStrategySchema } from '@/schemas/protocols/outbound';
|
||||
import { AmneziaWGOutboundSettingsSchema } from '@/schemas/protocols/outbound';
|
||||
import { canEnableTlsFlow } from '@/lib/xray/protocol-capabilities';
|
||||
import {
|
||||
dropEmptyFinalMask,
|
||||
normalizeStreamSettingsForWire,
|
||||
@@ -902,10 +903,23 @@ function stripUiOnlyStreamFields(stream: unknown): Raw {
|
||||
return normalizeStreamSettingsForWire(next, { side: 'outbound' }) as Raw;
|
||||
}
|
||||
|
||||
// The flow select only hides off a Vision-capable transport; its stale value must not reach xray.
|
||||
export function effectiveVlessFlow(
|
||||
settings: Pick<VlessOutboundFormSettings, 'flow' | 'encryption'>,
|
||||
stream: { network?: string; security?: string } | undefined,
|
||||
): string {
|
||||
const allowed = canEnableTlsFlow({
|
||||
protocol: 'vless',
|
||||
settings: { encryption: settings.encryption },
|
||||
streamSettings: { network: stream?.network, security: stream?.security },
|
||||
});
|
||||
return allowed ? settings.flow : '';
|
||||
}
|
||||
|
||||
function muxAllowed(values: OutboundFormValues): boolean {
|
||||
if (!MUX_PROTOCOLS.has(values.protocol)) return false;
|
||||
const flow =
|
||||
values.protocol === 'vless' ? (values.settings as VlessOutboundFormSettings).flow : '';
|
||||
values.protocol === 'vless' ? effectiveVlessFlow(values.settings, values.streamSettings) : '';
|
||||
if (flow) return false;
|
||||
const network =
|
||||
values.streamSettings && 'network' in values.streamSettings
|
||||
@@ -924,7 +938,10 @@ export function formValuesToWirePayload(values: OutboundFormValues): WireOutboun
|
||||
settings = vmessToWire(values.settings);
|
||||
break;
|
||||
case 'vless':
|
||||
settings = vlessToWire(values.settings);
|
||||
settings = vlessToWire({
|
||||
...values.settings,
|
||||
flow: effectiveVlessFlow(values.settings, values.streamSettings),
|
||||
});
|
||||
break;
|
||||
case 'trojan':
|
||||
settings = trojanToWire(values.settings);
|
||||
|
||||
@@ -74,10 +74,8 @@ export function canEnableTlsFlow(values: CapabilityProtocolSlice): boolean {
|
||||
// Classic XTLS Vision: raw TCP carried over TLS or REALITY.
|
||||
if (network === 'tcp' && (security === 'tls' || security === 'reality')) return true;
|
||||
|
||||
// vlessenc carries Vision over XHTTP without transport TLS.
|
||||
if (network === 'xhttp' && hasVlessEncryption(values.settings)) return true;
|
||||
|
||||
return false;
|
||||
// xray-core runs Vision inside VLESS encryption (encryption.CommonConn) on any transport.
|
||||
return hasVlessEncryption(values.settings);
|
||||
}
|
||||
|
||||
export function canEnableStream(values: { protocol: string }): boolean {
|
||||
|
||||
Reference in New Issue
Block a user