fix(links): bracket ipv6 hosts in share links and qr codes (#5310)

* fix(sub): bracket ipv6 hosts in share links

* fix(frontend): bracket ipv6 hosts in share links
This commit is contained in:
Nikan Zeyaei
2026-06-15 01:08:58 +03:30
committed by GitHub
parent 335470607f
commit 7c737820d1
4 changed files with 135 additions and 13 deletions
+85
View File
@@ -437,6 +437,91 @@ describe('genShadowsocksLink', () => {
}
});
describe('IPv6 bracket wrapping in share-link authority', () => {
it('genVlessLink brackets a bare IPv6 address', () => {
const [, raw] = fixturesForProtocol('vless')[0];
const typed = InboundSchema.parse(raw);
const clientId = (raw as { settings: { clients: Array<{ id: string }> } }).settings.clients[0].id;
const link = genVlessLink({
inbound: typed,
address: '2001:db8::1',
port: 443,
clientId,
});
expect(new URL(link).host).toBe('[2001:db8::1]:443');
});
it('genTrojanLink brackets a bare IPv6 address', () => {
const [, raw] = fixturesForProtocol('trojan')[0];
const typed = InboundSchema.parse(raw);
const clientPassword = (raw as { settings: { clients: Array<{ password: string }> } }).settings.clients[0].password;
const link = genTrojanLink({
inbound: typed,
address: '2001:db8::1',
port: 443,
clientPassword,
});
expect(new URL(link).host).toBe('[2001:db8::1]:443');
});
it('genShadowsocksLink brackets a bare IPv6 address', () => {
const [, raw] = fixturesForProtocol('shadowsocks')[0];
const typed = InboundSchema.parse(raw);
const clientPassword = (raw as { settings: { clients?: Array<{ password: string }> } }).settings.clients?.[0]?.password ?? '';
const link = genShadowsocksLink({
inbound: typed,
address: '2001:db8::1',
port: 443,
clientPassword,
});
expect(new URL(link).host).toBe('[2001:db8::1]:443');
});
it('genHysteriaLink brackets a bare IPv6 address', () => {
const [, raw] = fixturesForProtocol('hysteria')[0];
const typed = InboundSchema.parse(raw);
const clientAuth = (raw as { settings: { clients: Array<{ auth: string }> } }).settings.clients[0].auth;
const link = genHysteriaLink({
inbound: typed,
address: '2001:db8::1',
port: 443,
clientAuth,
});
expect(new URL(link).host).toBe('[2001:db8::1]:443');
});
it('genWireguardLink brackets a bare IPv6 address', () => {
const [, raw] = fixturesForProtocol('wireguard')[0];
const typed = InboundSchema.parse(raw);
if (typed.protocol !== 'wireguard') throw new Error('not a wireguard fixture');
const settings = typed.settings as WireguardInboundSettings;
const link = genWireguardLink({
settings,
address: '2001:db8::1',
port: 443,
peerIndex: 0,
});
expect(new URL(link).host).toBe('[2001:db8::1]:443');
});
it('does not bracket IPv4 addresses or hostnames', () => {
const [, raw] = fixturesForProtocol('vless')[0];
const typed = InboundSchema.parse(raw);
const clientId = (raw as { settings: { clients: Array<{ id: string }> } }).settings.clients[0].id;
const v4 = genVlessLink({ inbound: typed, address: '203.0.113.7', port: 443, clientId });
expect(new URL(v4).host).toBe('203.0.113.7:443');
const host = genVlessLink({ inbound: typed, address: 'example.test', port: 443, clientId });
expect(new URL(host).host).toBe('example.test:443');
});
});
describe('external proxy pinned cert (pcs)', () => {
const [, raw] = fixturesForProtocol('vless').find(([name]) => name === 'vless-ws-tls')!;
const typed = InboundSchema.parse(raw);