fix: default hysteria tls to no utls fingerprint

This commit is contained in:
Sanaei
2026-06-08 13:15:51 +02:00
parent 98ba88037c
commit af3c808444
7 changed files with 145 additions and 28 deletions
@@ -16,6 +16,7 @@ import {
createDefaultVmessInboundSettings,
createDefaultWireguardInboundSettings,
} from '@/lib/xray/inbound-defaults';
import { createHysteriaTlsSettingsWithDefaultCert } from '@/lib/xray/inbound-tls-defaults';
import { HttpInboundSettingsSchema } from '@/schemas/protocols/inbound/http';
import { HysteriaClientSchema, HysteriaInboundSettingsSchema } from '@/schemas/protocols/inbound/hysteria';
import { MixedInboundSettingsSchema } from '@/schemas/protocols/inbound/mixed';
@@ -147,3 +148,18 @@ describe('createDefault*InboundSettings factories', () => {
expect(WireguardInboundSettingsSchema.parse(s)).toEqual(s);
});
});
describe('createHysteriaTlsSettingsWithDefaultCert', () => {
it('defaults Hysteria TLS to uTLS None and h3 ALPN', () => {
const tls = createHysteriaTlsSettingsWithDefaultCert();
expect(tls.alpn).toEqual(['h3']);
expect((tls.settings as Record<string, unknown>).fingerprint).toBe('');
expect(tls.certificates).toEqual([
expect.objectContaining({
useFile: true,
certificateFile: '',
keyFile: '',
}),
]);
});
});
@@ -9,6 +9,7 @@ import {
normalizeXhttpForWire,
validateRealityTarget,
} from '@/lib/xray/stream-wire-normalize';
import { InboundFormSchema } from '@/schemas/forms/inbound-form';
import type { InboundFormValues } from '@/schemas/forms/inbound-form';
describe('validateRealityTarget', () => {
@@ -150,6 +151,28 @@ describe('normalizeStreamSettingsForWire reality', () => {
});
});
describe('normalizeStreamSettingsForWire tls', () => {
it('drops empty uTLS fingerprints from inbound and outbound TLS shapes', () => {
const out = normalizeStreamSettingsForWire({
network: 'hysteria',
security: 'tls',
tlsSettings: {
fingerprint: '',
settings: {
fingerprint: '',
echConfigList: '',
},
},
}, { side: 'inbound' });
const tls = out.tlsSettings as Record<string, unknown>;
const settings = tls.settings as Record<string, unknown>;
expect(tls).not.toHaveProperty('fingerprint');
expect(settings).not.toHaveProperty('fingerprint');
expect(settings.echConfigList).toBe('');
});
});
describe('inbound formValuesToWirePayload integration', () => {
it('emits lean stream-one xhttp + sockopt on save', () => {
const values = {
@@ -209,6 +232,51 @@ describe('inbound formValuesToWirePayload integration', () => {
const realitySettings = reality.settings as Record<string, unknown>;
expect(realitySettings.publicKey).toBe('pub');
});
it('accepts Hysteria TLS with uTLS None and omits fingerprint on save', () => {
const values = {
remark: 'hy2',
enable: true,
port: 443,
listen: '',
tag: 'hy2-443',
expiryTime: 0,
sniffing: { enabled: false },
up: 0,
down: 0,
total: 0,
trafficReset: 'never',
lastTrafficResetTime: 0,
nodeId: null,
protocol: 'hysteria',
settings: { version: 2, clients: [] },
streamSettings: {
network: 'hysteria',
security: 'tls',
hysteriaSettings: {
version: 2,
auth: 'auth',
udpIdleTimeout: 60,
},
tlsSettings: {
alpn: ['h3'],
settings: {
fingerprint: '',
},
},
},
};
const parsed = InboundFormSchema.safeParse(values);
expect(parsed.success).toBe(true);
if (!parsed.success) throw parsed.error;
const payload = formValuesToWirePayload(parsed.data);
const stream = JSON.parse(payload.streamSettings) as Record<string, unknown>;
const tls = stream.tlsSettings as Record<string, unknown>;
const settings = tls.settings as Record<string, unknown>;
expect(settings).not.toHaveProperty('fingerprint');
});
});
describe('freedom outbound sockopt wire payload', () => {