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:
MHSanaei
2026-06-15 17:20:54 +02:00
parent cdaf5f80db
commit f00512d12e
5 changed files with 187 additions and 9 deletions
+91
View File
@@ -567,3 +567,94 @@ describe('external proxy pinned cert (pcs)', () => {
expect(new URL(link).searchParams.has('pcs')).toBe(false);
});
});
// #5322: the panel copy-link must carry XTLS Vision `flow` for VLESS+XHTTP
// when VLESS encryption (vlessenc) is on, matching the form's flow display
// and the backend subscription. Gating is via canEnableTlsFlow.
describe('genVlessLink flow gating (#5322)', () => {
function vlessXhttp(encryption: string) {
return InboundSchema.parse({
id: 1,
up: 0,
down: 0,
total: 0,
remark: 'vlessenc',
enable: true,
expiryTime: 0,
listen: '',
port: 443,
tag: 'inbound-vless-xhttp',
sniffing: {
enabled: false,
destOverride: [],
metadataOnly: false,
routeOnly: false,
ipsExcluded: [],
domainsExcluded: [],
},
protocol: 'vless',
settings: {
clients: [
{
id: '11111111-2222-3333-4444-555555555555',
email: 'a@example.test',
flow: 'xtls-rprx-vision',
limitIp: 0,
totalGB: 0,
expiryTime: 0,
enable: true,
tgId: 0,
subId: 's1',
comment: '',
reset: 0,
},
],
decryption: 'none',
encryption,
fallbacks: [],
},
streamSettings: {
network: 'xhttp',
xhttpSettings: {},
security: 'none',
},
});
}
const clientId = '11111111-2222-3333-4444-555555555555';
it('emits flow for VLESS+XHTTP when vless encryption is enabled', () => {
const link = genVlessLink({
inbound: vlessXhttp('mlkem768x25519plus.native.0rtt.SGVsbG8'),
address: 'example.test',
port: 443,
clientId,
flow: 'xtls-rprx-vision',
});
expect(new URL(link).searchParams.get('flow')).toBe('xtls-rprx-vision');
});
it('omits flow for VLESS+XHTTP without vless encryption', () => {
const link = genVlessLink({
inbound: vlessXhttp('none'),
address: 'example.test',
port: 443,
clientId,
flow: 'xtls-rprx-vision',
});
expect(new URL(link).searchParams.has('flow')).toBe(false);
});
it('still emits flow for classic TCP+REALITY Vision', () => {
const [, raw] = fixturesForProtocol('vless').find(([name]) => name === 'vless-tcp-reality')!;
const typed = InboundSchema.parse(raw);
const link = genVlessLink({
inbound: typed,
address: 'example.test',
port: 443,
clientId: (raw as { settings: { clients: Array<{ id: string }> } }).settings.clients[0].id,
flow: 'xtls-rprx-vision',
});
expect(new URL(link).searchParams.get('flow')).toBe('xtls-rprx-vision');
});
});