mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-16 23:27:14 +00:00
fix(link): read the vmess certificate checks on import (#6507)
* fix(link): read the vmess certificate checks on import applyVmessTLSParams writes ech, vcn and pcs into the vmess share object, but parseVmess only read sni, fp and alpn back. Importing a link the panel had just exported therefore dropped all three: no pinned certificate, no verify-by-name, no ECH. On a server whose certificate is only trusted through a pin, the imported outbound falls back to public-CA verification against the system roots and cannot connect to the inbound the link came from. The url-param protocols already read the same three in applySecurity, and the core takes pinnedPeerCertSha256 as one joined string there, so the vmess path now fills them the same way. * fix(frontend): read the vmess certificate checks on import The panel parses share links twice: link.ParseLink in Go and parseVmessLink in outbound-link-parser.ts, which is what the Add Outbound button calls. Reading ech, vcn and pcs in Go alone would have made the two sides disagree on one link, leaving the UI path — the one an operator uses by hand — still dropping the pin the panel had just exported.
This commit is contained in:
@@ -458,6 +458,11 @@ export function parseVmessLink(link: string): Raw | null {
|
||||
tls.serverName = json.sni ?? '';
|
||||
tls.fingerprint = json.fp ?? '';
|
||||
if (json.alpn) tls.alpn = (json.alpn as string).split(',');
|
||||
// The vmess object names the certificate checks the url-param protocols
|
||||
// pass through applySecurityParams, under the same short names.
|
||||
if (typeof json.ech === 'string') tls.echConfigList = json.ech;
|
||||
if (typeof json.vcn === 'string') tls.verifyPeerCertByName = json.vcn;
|
||||
if (typeof json.pcs === 'string') tls.pinnedPeerCertSha256 = json.pcs;
|
||||
}
|
||||
|
||||
const port = Number(json.port) || 443;
|
||||
|
||||
@@ -57,6 +57,34 @@ describe('parseVmessLink', () => {
|
||||
expect((stream.tlsSettings as Record<string, unknown>).alpn).toEqual(['h2', 'http/1.1']);
|
||||
});
|
||||
|
||||
// The exporter writes ech/vcn/pcs into the vmess object, so the importer has
|
||||
// to read them instead of leaving the tls checks it seeded empty.
|
||||
it('keeps the ech, vcn and pcs certificate checks', () => {
|
||||
const json = {
|
||||
v: '2',
|
||||
ps: 'pinned-vmess',
|
||||
add: '1.2.3.4',
|
||||
port: 8443,
|
||||
id: '11111111-2222-4333-8444-555555555555',
|
||||
scy: 'auto',
|
||||
net: 'tcp',
|
||||
tls: 'tls',
|
||||
sni: 'vmess.example.com',
|
||||
fp: 'chrome',
|
||||
ech: 'AEX+DQBB',
|
||||
vcn: 'vcn.example.com',
|
||||
pcs: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
||||
};
|
||||
const link = `vmess://${Base64.encode(JSON.stringify(json))}`;
|
||||
const out = parseVmessLink(link);
|
||||
expect(out).not.toBeNull();
|
||||
const stream = out?.streamSettings as Record<string, unknown>;
|
||||
const tls = stream.tlsSettings as Record<string, unknown>;
|
||||
expect(tls.echConfigList).toBe('AEX+DQBB');
|
||||
expect(tls.verifyPeerCertByName).toBe('vcn.example.com');
|
||||
expect(tls.pinnedPeerCertSha256).toBe('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=');
|
||||
});
|
||||
|
||||
it('returns null for non-vmess links', () => {
|
||||
expect(parseVmessLink('vless://x@y:1')).toBeNull();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user