diff --git a/frontend/src/lib/xray/inbound-link.ts b/frontend/src/lib/xray/inbound-link.ts index 2f2908d6..7615b56a 100644 --- a/frontend/src/lib/xray/inbound-link.ts +++ b/frontend/src/lib/xray/inbound-link.ts @@ -358,13 +358,14 @@ export function genVlessLink(input: GenVlessLinkInput): string { const reality = stream.realitySettings; params.set('pbk', reality.settings.publicKey); params.set('fp', reality.settings.fingerprint); - // Legacy parity quirk: the old class stored realitySettings.serverNames - // as a comma-joined string and gated SNI on `!ObjectUtil.isArrEmpty(s)` - // — which returns true for any string, so SNI was never written into - // Reality share links. Existing deployed clients rely on receiving - // the SNI from realitySettings.target instead; we keep the omission - // here so this extraction stays byte-stable with the legacy URL. - // Fixing the bug is a separate intentional commit. + + const sni = + reality.settings.serverName || + reality.serverNames?.[0] || + reality.target?.split(':')[0]; + + if (sni && sni.length > 0) params.set('sni', sni); + 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); @@ -436,6 +437,14 @@ function writeRealityParams(stream: NonNullable, para const reality = stream.realitySettings; params.set('pbk', reality.settings.publicKey); params.set('fp', reality.settings.fingerprint); + + const sni = + reality.settings.serverName || + reality.serverNames?.[0] || + reality.target?.split(':')[0]; + + if (sni && sni.length > 0) params.set('sni', sni); + 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); diff --git a/frontend/src/test/__snapshots__/inbound-link.test.ts.snap b/frontend/src/test/__snapshots__/inbound-link.test.ts.snap index 8a2fec07..50851a76 100644 --- a/frontend/src/test/__snapshots__/inbound-link.test.ts.snap +++ b/frontend/src/test/__snapshots__/inbound-link.test.ts.snap @@ -8,7 +8,7 @@ exports[`genInboundLinks orchestrator > shadowsocks-tcp-2022: byte-stable 1`] = exports[`genInboundLinks orchestrator > trojan-ws-tls: byte-stable 1`] = `"trojan://trojan-test-pw-XYZ@override.test:443?type=ws&path=%2Ftrojan&host=trojan.example.test&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=trojan.example.test#parity-test"`; -exports[`genInboundLinks orchestrator > vless-tcp-reality: byte-stable 1`] = `"vless://22222222-3333-4444-9555-666666666666@override.test:443?type=tcp&encryption=none&security=reality&pbk=Tx5yj1bRcOPHkdvT2pIAQ2zh0gQ8m4OPdnzqXJxxV3o&fp=chrome&sid=a3f1&spx=%2F&flow=xtls-rprx-vision#parity-test"`; +exports[`genInboundLinks orchestrator > vless-tcp-reality: byte-stable 1`] = `"vless://22222222-3333-4444-9555-666666666666@override.test:443?type=tcp&encryption=none&security=reality&pbk=Tx5yj1bRcOPHkdvT2pIAQ2zh0gQ8m4OPdnzqXJxxV3o&fp=chrome&sni=yahoo.com&sid=a3f1&spx=%2F&flow=xtls-rprx-vision#parity-test"`; exports[`genInboundLinks orchestrator > vless-ws-tls: byte-stable 1`] = `"vless://8c14d6f7-2e3b-4a91-9d24-3f7a6b8c1e02@override.test:443?type=ws&encryption=none&path=%2Fws&host=cdn.example.test&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=cdn.example.test#parity-test"`; @@ -34,7 +34,7 @@ exports[`genShadowsocksLink > shadowsocks-tcp-2022: byte-stable 1`] = `"ss://MjA exports[`genTrojanLink > trojan-ws-tls: byte-stable 1`] = `"trojan://trojan-test-pw-XYZ@example.test:443?type=ws&path=%2Ftrojan&host=trojan.example.test&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=trojan.example.test#parity-test"`; -exports[`genVlessLink > vless-tcp-reality: byte-stable 1`] = `"vless://22222222-3333-4444-9555-666666666666@example.test:443?type=tcp&encryption=none&security=reality&pbk=Tx5yj1bRcOPHkdvT2pIAQ2zh0gQ8m4OPdnzqXJxxV3o&fp=chrome&sid=a3f1&spx=%2F&flow=xtls-rprx-vision#parity-test"`; +exports[`genVlessLink > vless-tcp-reality: byte-stable 1`] = `"vless://22222222-3333-4444-9555-666666666666@example.test:443?type=tcp&encryption=none&security=reality&pbk=Tx5yj1bRcOPHkdvT2pIAQ2zh0gQ8m4OPdnzqXJxxV3o&fp=chrome&sni=yahoo.com&sid=a3f1&spx=%2F&flow=xtls-rprx-vision#parity-test"`; exports[`genVlessLink > vless-ws-tls: byte-stable 1`] = `"vless://8c14d6f7-2e3b-4a91-9d24-3f7a6b8c1e02@example.test:443?type=ws&encryption=none&path=%2Fws&host=cdn.example.test&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=cdn.example.test#parity-test"`;