fix(hysteria2): restore missing masquerade config in inbound form (#4316)

* fix(hysteria2): restore missing masquerade config in inbound form

Fixes #4303

The Hysteria2 Masquerade option was missing from the Stream settings
tab after the v3.0.0 form rewrite. Added the UI form and ensured the
masquerade block is passed through in subscription JSON generation.
This commit is contained in:
Abdalrahman
2026-05-13 02:25:00 +03:00
committed by GitHub
parent 0dbadf82c0
commit 60e6b12f4c
3 changed files with 73 additions and 1 deletions
+2 -1
View File
@@ -687,8 +687,9 @@ export class HysteriaMasquerade extends XrayCommonClass {
}
static fromJson(json = {}) {
const type = ['proxy', 'file', 'string'].includes(json.type) ? json.type : 'proxy';
return new HysteriaMasquerade(
json.type,
type,
json.dir,
json.url,
json.rewriteHost,
@@ -1671,6 +1671,74 @@ watch(
</a-select>
</a-form-item>
</template>
<!-- ====== Hysteria Masquerade ====== -->
<!-- Per https://xtls.github.io/config/transports/hysteria.html#masqobject -->
<template v-if="protocol === Protocols.HYSTERIA">
<a-form-item label="Masquerade">
<a-switch v-model:checked="inbound.stream.hysteria.masqueradeSwitch" />
</a-form-item>
<template v-if="inbound.stream.hysteria.masqueradeSwitch">
<a-form-item label="Type">
<a-select v-model:value="inbound.stream.hysteria.masquerade.type" :style="{ width: '50%' }">
<a-select-option value="proxy">Proxy</a-select-option>
<a-select-option value="file">File</a-select-option>
<a-select-option value="string">String</a-select-option>
</a-select>
</a-form-item>
<!-- Proxy type: url / rewriteHost / insecure -->
<template v-if="inbound.stream.hysteria.masquerade.type === 'proxy'">
<a-form-item label="URL">
<a-input v-model:value="inbound.stream.hysteria.masquerade.url" placeholder="https://example.com" />
</a-form-item>
<a-form-item label="Rewrite Host">
<a-switch v-model:checked="inbound.stream.hysteria.masquerade.rewriteHost" />
</a-form-item>
<a-form-item label="Insecure">
<a-switch v-model:checked="inbound.stream.hysteria.masquerade.insecure" />
</a-form-item>
</template>
<!-- File type: dir -->
<a-form-item v-if="inbound.stream.hysteria.masquerade.type === 'file'" label="Directory">
<a-input v-model:value="inbound.stream.hysteria.masquerade.dir" placeholder="/path/to/www" />
</a-form-item>
<!-- String type: content / statusCode / headers -->
<template v-if="inbound.stream.hysteria.masquerade.type === 'string'">
<a-form-item label="Content">
<a-textarea v-model:value="inbound.stream.hysteria.masquerade.content"
:auto-size="{ minRows: 2, maxRows: 6 }" />
</a-form-item>
<a-form-item label="Status Code">
<a-input-number v-model:value="inbound.stream.hysteria.masquerade.statusCode" :min="100" :max="599"
placeholder="200" />
</a-form-item>
<a-form-item label="Headers">
<a-button size="small" @click="inbound.stream.hysteria.masquerade.addHeader('', '')">
<template #icon>
<PlusOutlined />
</template>
</a-button>
</a-form-item>
<a-form-item v-if="inbound.stream.hysteria.masquerade.headers.length > 0" :wrapper-col="{ span: 24 }">
<a-input-group v-for="(h, idx) in inbound.stream.hysteria.masquerade.headers" :key="`mh-${idx}`"
compact class="mb-8">
<a-input :style="{ width: '45%' }" v-model:value="h.name" placeholder="Name">
<template #addonBefore>{{ idx + 1 }}</template>
</a-input>
<a-input :style="{ width: '45%' }" v-model:value="h.value" placeholder="Value" />
<a-button @click="inbound.stream.hysteria.masquerade.removeHeader(idx)">
<template #icon>
<MinusOutlined />
</template>
</a-button>
</a-input-group>
</a-form-item>
</template>
</template>
</template>
</a-form>
<!-- ====== FinalMask (TCP/UDP masks + QUIC params) ====== -->
+3
View File
@@ -447,6 +447,9 @@ func (s *SubJsonService) genHy(inbound *model.Inbound, newStream map[string]any,
if udpIdleTimeout, ok := hyStream["udpIdleTimeout"].(float64); ok {
outHyStream["udpIdleTimeout"] = int(udpIdleTimeout)
}
if masquerade, ok := hyStream["masquerade"].(map[string]any); ok {
outHyStream["masquerade"] = masquerade
}
newStream["hysteriaSettings"] = outHyStream
if finalmask, ok := hyStream["finalmask"].(map[string]any); ok {