mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-17 00:31:00 +00:00
d8221a8153
The Host VLESS Route field was stored and shown in the panel but never applied to any generated subscription (raw, JSON, Clash), so the UUID was emitted unmodified (#5655). Xray reads the route from the UUID's 3rd group (bytes 6-7, net.PortFromBytes) and masks those bytes to zero before authenticating, so a value can be baked into the share/JSON/Clash UUIDs without breaking the user match. A shared applyVlessRoute helper encodes a single 0-65535 value as the 3rd group; empty/invalid/non-UUID input is left unchanged, so legacy data never yields a broken link and no DB migration is needed. The field was wrongly validated as a multi-segment port spec (that form belongs to the separate server-side routing rule). It is now a single value 0-65535, with frontend validation, link-preview parity (genVlessLink/hostToExternalProxyEntry), hint + error translations across all 13 locales, and tests on every path. Closes #5655
63 lines
2.3 KiB
TypeScript
63 lines
2.3 KiB
TypeScript
/// <reference types="vite/client" />
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
import { hostToExternalProxyEntry } from '@/lib/hosts/host-link';
|
|
|
|
describe('hostToExternalProxyEntry', () => {
|
|
const base = {
|
|
security: 'tls' as const,
|
|
address: 'cdn.example.com',
|
|
port: 8443,
|
|
remark: 'R',
|
|
sni: 'sni.example.com',
|
|
alpn: ['h2'] as ('h2' | 'h3' | 'http/1.1')[],
|
|
fingerprint: 'chrome' as const,
|
|
pinnedPeerCertSha256: ['AAAA'],
|
|
verifyPeerCertByName: 'verify.example.com',
|
|
echConfigList: 'ECH',
|
|
overrideSniFromAddress: false,
|
|
keepSniBlank: false,
|
|
vlessRoute: '',
|
|
};
|
|
|
|
it('maps the overlapping fields onto an external-proxy entry', () => {
|
|
const ep = hostToExternalProxyEntry(base);
|
|
expect(ep.forceTls).toBe('tls');
|
|
expect(ep.dest).toBe('cdn.example.com');
|
|
expect(ep.port).toBe(8443);
|
|
expect(ep.remark).toBe('R');
|
|
expect(ep.sni).toBe('sni.example.com');
|
|
expect(ep.alpn).toEqual(['h2']);
|
|
expect(ep.fingerprint).toBe('chrome');
|
|
expect(ep.pinnedPeerCertSha256).toEqual(['AAAA']);
|
|
expect(ep.verifyPeerCertByName).toBe('verify.example.com');
|
|
expect(ep.echConfigList).toBe('ECH');
|
|
});
|
|
|
|
it('maps reality/same security to forceTls "same"', () => {
|
|
expect(hostToExternalProxyEntry({ ...base, security: 'reality' }).forceTls).toBe('same');
|
|
expect(hostToExternalProxyEntry({ ...base, security: 'same' }).forceTls).toBe('same');
|
|
expect(hostToExternalProxyEntry({ ...base, security: 'none' }).forceTls).toBe('none');
|
|
});
|
|
|
|
it('uses the address as sni when overrideSniFromAddress is set', () => {
|
|
const ep = hostToExternalProxyEntry({ ...base, overrideSniFromAddress: true });
|
|
expect(ep.sni).toBe('cdn.example.com');
|
|
});
|
|
|
|
it('omits sni when keepSniBlank is set', () => {
|
|
const ep = hostToExternalProxyEntry({ ...base, keepSniBlank: true });
|
|
expect(ep.sni).toBeUndefined();
|
|
});
|
|
|
|
it('falls back to port 443 when the host port is 0 (inherit)', () => {
|
|
const ep = hostToExternalProxyEntry({ ...base, port: 0 });
|
|
expect(ep.port).toBe(443);
|
|
});
|
|
|
|
it('carries a single vlessRoute value through to the entry', () => {
|
|
expect(hostToExternalProxyEntry({ ...base, vlessRoute: '443' }).vlessRoute).toBe('443');
|
|
expect(hostToExternalProxyEntry({ ...base, vlessRoute: '' }).vlessRoute).toBeUndefined();
|
|
});
|
|
});
|