reset button for auth password

This commit is contained in:
MHSanaei 2026-04-20 17:25:18 +02:00
parent 04b4fb4384
commit 6d0e7ec495
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
12 changed files with 1215 additions and 710 deletions

View file

@ -1,191 +1,256 @@
{{define "form/client"}} {{define "form/client"}}
<a-form layout="horizontal" v-if="client" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
<a-form-item label='{{ i18n "pages.inbounds.enable" }}'> layout="horizontal"
<a-switch v-model="client.enable"></a-switch> v-if="client"
</a-form-item> :colon="false"
<a-form-item> :label-col="{ md: {span:8} }"
<template slot="label"> :wrapper-col="{ md: {span:14} }"
<a-tooltip> >
<template slot="title"> <a-form-item label='{{ i18n "pages.inbounds.enable" }}'>
<span>{{ i18n "pages.inbounds.emailDesc" }}</span> <a-switch v-model="client.enable"></a-switch>
</template> </a-form-item>
{{ i18n "pages.inbounds.email" }} <a-form-item>
<a-icon type="sync" @click="client.email = RandomUtil.randomLowerAndNum(9)"></a-icon> <template slot="label">
</a-tooltip> <a-tooltip>
<template slot="title">
<span>{{ i18n "pages.inbounds.emailDesc" }}</span>
</template> </template>
<a-input v-model.trim="client.email"></a-input> {{ i18n "pages.inbounds.email" }}
</a-form-item> <a-icon
<a-form-item v-if="inbound.protocol === Protocols.TROJAN || inbound.protocol === Protocols.SHADOWSOCKS"> type="sync"
<template slot="label"> @click="client.email = RandomUtil.randomLowerAndNum(9)"
<a-tooltip> ></a-icon>
<template slot="title"> </a-tooltip>
<span>{{ i18n "reset" }}</span> </template>
</template> <a-input v-model.trim="client.email"></a-input>
{{ i18n "password" }} </a-form-item>
<a-icon v-if="inbound.protocol === Protocols.SHADOWSOCKS" <a-form-item
@click="client.password = RandomUtil.randomShadowsocksPassword(inbound.settings.method)" v-if="inbound.protocol === Protocols.TROJAN || inbound.protocol === Protocols.SHADOWSOCKS"
type="sync"></a-icon> >
<a-icon v-if="inbound.protocol === Protocols.TROJAN" @click="client.password = RandomUtil.randomSeq(10)" <template slot="label">
type="sync"> </a-icon> <a-tooltip>
</a-tooltip> <template slot="title">
<span>{{ i18n "reset" }}</span>
</template> </template>
<a-input v-model.trim="client.password"></a-input> {{ i18n "password" }}
</a-form-item> <a-icon
<a-form-item v-if="inbound.protocol === Protocols.HYSTERIA"> v-if="inbound.protocol === Protocols.SHADOWSOCKS"
<template slot="label"> @click="client.password = RandomUtil.randomShadowsocksPassword(inbound.settings.method)"
<a-tooltip> type="sync"
<template slot="title"> ></a-icon>
<span>{{ i18n "reset" }}</span> <a-icon
</template> v-if="inbound.protocol === Protocols.TROJAN"
Auth Password @click="client.password = RandomUtil.randomSeq(10)"
<a-icon @click="client.auth = RandomUtil.randomSeq(10)" type="sync"></a-icon> type="sync"
</a-tooltip> >
</a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="client.password"></a-input>
</a-form-item>
<a-form-item v-if="inbound.protocol === Protocols.HYSTERIA">
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "reset" }}</span>
</template> </template>
<a-input v-model.trim="client.auth"></a-input> Auth Password
</a-form-item> <a-icon
<a-form-item v-if="inbound.protocol === Protocols.VMESS || inbound.protocol === Protocols.VLESS"> @click="client.auth = RandomUtil.randomSeq(10)"
<template slot="label"> type="sync"
<a-tooltip> ></a-icon>
<template slot="title"> </a-tooltip>
<span>{{ i18n "reset" }}</span> </template>
</template> <a-input v-model.trim="client.auth"></a-input>
ID <a-icon @click="client.id = RandomUtil.randomUUID()" type="sync"></a-icon> </a-form-item>
</a-tooltip> <a-form-item
v-if="inbound.protocol === Protocols.VMESS || inbound.protocol === Protocols.VLESS"
>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "reset" }}</span>
</template> </template>
<a-input v-model.trim="client.id"></a-input> ID
</a-form-item> <a-icon
<a-form-item v-if="inbound.protocol === Protocols.VMESS" label='{{ i18n "security" }}'> @click="client.id = RandomUtil.randomUUID()"
<a-select v-model="client.security" :dropdown-class-name="themeSwitcher.currentTheme"> type="sync"
<a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ></a-icon>
]]</a-select-option> </a-tooltip>
</a-select> </template>
</a-form-item> <a-input v-model.trim="client.id"></a-input>
<a-form-item v-if="client.email && app.subSettings?.enable"> </a-form-item>
<template slot="label"> <a-form-item
<a-tooltip> v-if="inbound.protocol === Protocols.VMESS"
<template slot="title"> label='{{ i18n "security" }}'
<span>{{ i18n "pages.inbounds.subscriptionDesc" }}</span> >
</template> <a-select
Subscription v-model="client.security"
<a-icon @click="client.subId = RandomUtil.randomLowerAndNum(16)" type="sync"></a-icon> :dropdown-class-name="themeSwitcher.currentTheme"
</a-tooltip> >
<a-select-option v-for="key in USERS_SECURITY" :value="key"
>[[ key ]]</a-select-option
>
</a-select>
</a-form-item>
<a-form-item v-if="client.email && app.subSettings?.enable">
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.inbounds.subscriptionDesc" }}</span>
</template> </template>
<a-input v-model.trim="client.subId"></a-input> Subscription
</a-form-item> <a-icon
<a-form-item v-if="client.email && app.tgBotEnable"> @click="client.subId = RandomUtil.randomLowerAndNum(16)"
<template slot="label"> type="sync"
<a-tooltip> ></a-icon>
<template slot="title"> </a-tooltip>
<span>{{ i18n "pages.inbounds.telegramDesc" }}</span> </template>
</template> <a-input v-model.trim="client.subId"></a-input>
Telegram ChatID </a-form-item>
<a-icon type="question-circle"></a-icon> <a-form-item v-if="client.email && app.tgBotEnable">
</a-tooltip> <template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.inbounds.telegramDesc" }}</span>
</template> </template>
<a-input-number :style="{ width: '50%' }" v-model.number="client.tgId" min="0"></a-input-number> Telegram ChatID
</a-form-item> <a-icon type="question-circle"></a-icon>
<a-form-item v-if="client.email" label='{{ i18n "comment" }}'> </a-tooltip>
<a-input v-model.trim="client.comment"></a-input> </template>
</a-form-item> <a-input-number
<a-form-item v-if="app.ipLimitEnable"> :style="{ width: '50%' }"
<template slot="label"> v-model.number="client.tgId"
<a-tooltip> min="0"
<template slot="title"> ></a-input-number>
<span>{{ i18n "pages.inbounds.IPLimitDesc"}}</span> </a-form-item>
</template> <a-form-item v-if="client.email" label='{{ i18n "comment" }}'>
<span>{{ i18n "pages.inbounds.IPLimit"}} </span> <a-input v-model.trim="client.comment"></a-input>
<a-icon type="question-circle"></a-icon> </a-form-item>
</a-tooltip> <a-form-item v-if="app.ipLimitEnable">
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.inbounds.IPLimitDesc"}}</span>
</template> </template>
<a-input-number v-model.number="client.limitIp" min="0"></a-input-number> <span>{{ i18n "pages.inbounds.IPLimit"}} </span>
</a-form-item> <a-icon type="question-circle"></a-icon>
<a-form-item v-if="app.ipLimitEnable && client.limitIp > 0 && client.email && isEdit"> </a-tooltip>
<template slot="label"> </template>
<a-tooltip> <a-input-number v-model.number="client.limitIp" min="0"></a-input-number>
<template slot="title"> </a-form-item>
<span>{{ i18n "pages.inbounds.IPLimitlogDesc" }}</span> <a-form-item
</template> v-if="app.ipLimitEnable && client.limitIp > 0 && client.email && isEdit"
<span>{{ i18n "pages.inbounds.IPLimitlog" }} </span> >
<a-icon type="question-circle"></a-icon> <template slot="label">
</a-tooltip> <a-tooltip>
<template slot="title">
<span>{{ i18n "pages.inbounds.IPLimitlogDesc" }}</span>
</template> </template>
<a-tooltip> <span>{{ i18n "pages.inbounds.IPLimitlog" }} </span>
<template slot="title"> <a-icon type="question-circle"></a-icon>
<span>{{ i18n "pages.inbounds.IPLimitlogclear" }}</span> </a-tooltip>
</template> </template>
<span :style="{ color: '#FF4D4F' }"> <a-tooltip>
<a-icon type="delete" @click="clearDBClientIps(client.email)"></a-icon> <template slot="title">
</span> <span>{{ i18n "pages.inbounds.IPLimitlogclear" }}</span>
</a-tooltip> </template>
<a-form layout="block"> <span :style="{ color: '#FF4D4F' }">
<a-textarea id="clientIPs" readonly @click="getDBClientIps(client.email)" placeholder="Click To Get IPs" <a-icon type="delete" @click="clearDBClientIps(client.email)"></a-icon>
:auto-size="{ minRows: 5, maxRows: 10 }"> </span>
</a-textarea> </a-tooltip>
</a-form> <a-form layout="block">
</a-form-item> <a-textarea
<a-form-item v-if="inbound.canEnableTlsFlow()" label='Flow'> id="clientIPs"
<a-select v-model="client.flow" :dropdown-class-name="themeSwitcher.currentTheme"> readonly
<a-select-option value selected>{{ i18n "none" }}</a-select-option> @click="getDBClientIps(client.email)"
<a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key placeholder="Click To Get IPs"
]]</a-select-option> :auto-size="{ minRows: 5, maxRows: 10 }"
</a-select> >
</a-form-item> </a-textarea>
<a-form-item> </a-form>
<template slot="label"> </a-form-item>
<a-tooltip> <a-form-item v-if="inbound.canEnableTlsFlow()" label="Flow">
<template slot="title"> <a-select
0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span> v-model="client.flow"
</template> :dropdown-class-name="themeSwitcher.currentTheme"
{{ i18n "pages.inbounds.totalFlow" }} >
<a-icon type="question-circle"></a-icon> <a-select-option value selected>{{ i18n "none" }}</a-select-option>
</a-tooltip> <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key"
>[[ key ]]</a-select-option
>
</a-select>
</a-form-item>
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
</template> </template>
<a-input-number v-model.number="client._totalGB" :min="0"></a-input-number> {{ i18n "pages.inbounds.totalFlow" }}
</a-form-item> <a-icon type="question-circle"></a-icon>
<a-form-item v-if="isEdit && clientStats" label='{{ i18n "usage" }}'> </a-tooltip>
<a-tag :color="ColorUtils.clientUsageColor(clientStats, app.trafficDiff)"> </template>
[[ SizeFormatter.sizeFormat(clientStats.up) ]] / <a-input-number v-model.number="client._totalGB" :min="0"></a-input-number>
[[ SizeFormatter.sizeFormat(clientStats.down) ]] </a-form-item>
([[ SizeFormatter.sizeFormat(clientStats.up + clientStats.down) ]]) <a-form-item v-if="isEdit && clientStats" label='{{ i18n "usage" }}'>
</a-tag> <a-tag :color="ColorUtils.clientUsageColor(clientStats, app.trafficDiff)">
<a-tooltip> [[ SizeFormatter.sizeFormat(clientStats.up) ]] / [[
<template slot="title">{{ i18n "pages.inbounds.resetTraffic" SizeFormatter.sizeFormat(clientStats.down) ]] ([[
}}</template> SizeFormatter.sizeFormat(clientStats.up + clientStats.down) ]])
<a-icon type="retweet" @click="resetClientTraffic(client.email,clientStats.inboundId,$event.target)" </a-tag>
v-if="client.email.length > 0"></a-icon> <a-tooltip>
</a-tooltip> <template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template>
</a-form-item> <a-icon
<a-form-item label='{{ i18n "pages.client.delayedStart" }}'> type="retweet"
<a-switch v-model="delayedStart" @click="client._expiryTime=0"></a-switch> @click="resetClientTraffic(client.email,clientStats.inboundId,$event.target)"
</a-form-item> v-if="client.email.length > 0"
<a-form-item v-if="delayedStart" label='{{ i18n "pages.client.expireDays" }}'> ></a-icon>
<a-input-number v-model.number="delayedExpireDays" :min="0"></a-input-number> </a-tooltip>
</a-form-item> </a-form-item>
<a-form-item v-else> <a-form-item label='{{ i18n "pages.client.delayedStart" }}'>
<template slot="label"> <a-switch v-model="delayedStart" @click="client._expiryTime=0"></a-switch>
<a-tooltip> </a-form-item>
<template slot="title">{{ i18n <a-form-item v-if="delayedStart" label='{{ i18n "pages.client.expireDays" }}'>
"pages.inbounds.leaveBlankToNeverExpire" }}</template> <a-input-number
{{ i18n "pages.inbounds.expireDate" }} v-model.number="delayedExpireDays"
<a-icon type="question-circle"></a-icon> :min="0"
</a-tooltip> ></a-input-number>
</template> </a-form-item>
<a-date-picker v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" <a-form-item v-else>
:dropdown-class-name="themeSwitcher.currentTheme" v-model="client._expiryTime"></a-date-picker> <template slot="label">
<a-persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}' <a-tooltip>
value="client._expiryTime" v-model="client._expiryTime"></a-persian-datepicker> <template slot="title"
<a-tag color="red" v-if="isEdit && isExpiry">Expired</a-tag> >{{ i18n "pages.inbounds.leaveBlankToNeverExpire" }}</template
</a-form-item> >
<a-form-item v-if="client.expiryTime != 0"> {{ i18n "pages.inbounds.expireDate" }}
<template slot="label"> <a-icon type="question-circle"></a-icon>
<a-tooltip> </a-tooltip>
<template slot="title">{{ i18n "pages.client.renewDesc" </template>
}}</template> <a-date-picker
{{ i18n "pages.client.renew" }} v-if="datepicker == 'gregorian'"
<a-icon type="question-circle"></a-icon> :show-time="{ format: 'HH:mm:ss' }"
</a-tooltip> format="YYYY-MM-DD HH:mm:ss"
</template> :dropdown-class-name="themeSwitcher.currentTheme"
<a-input-number v-model.number="client.reset" :min="0"></a-input-number> v-model="client._expiryTime"
</a-form-item> ></a-date-picker>
<a-persian-datepicker
v-else
placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
value="client._expiryTime"
v-model="client._expiryTime"
></a-persian-datepicker>
<a-tag color="red" v-if="isEdit && isExpiry">Expired</a-tag>
</a-form-item>
<a-form-item v-if="client.expiryTime != 0">
<template slot="label">
<a-tooltip>
<template slot="title">{{ i18n "pages.client.renewDesc" }}</template>
{{ i18n "pages.client.renew" }}
<a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input-number v-model.number="client.reset" :min="0"></a-input-number>
</a-form-item>
</a-form> </a-form>
{{end}} {{end}}

View file

@ -1,29 +1,65 @@
{{define "form/externalProxy"}} {{define "form/externalProxy"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
:colon="false"
:label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }"
>
<a-divider :style="{ margin: '5px 0 0' }"></a-divider> <a-divider :style="{ margin: '5px 0 0' }"></a-divider>
<a-form-item label="External Proxy"> <a-form-item label="External Proxy">
<a-switch v-model="externalProxy"></a-switch> <a-switch v-model="externalProxy"></a-switch>
<a-button icon="plus" v-if="externalProxy" type="primary" :style="{ marginLeft: '10px' }" size="small" <a-button
@click="inbound.stream.externalProxy.push({forceTls: 'same', dest: '', port: 443, remark: ''})"></a-button> icon="plus"
v-if="externalProxy"
type="primary"
:style="{ marginLeft: '10px' }"
size="small"
@click="inbound.stream.externalProxy.push({forceTls: 'same', dest: '', port: 443, remark: ''})"
></a-button>
</a-form-item> </a-form-item>
<a-input-group :style="{ margin: '8px 0' }" compact v-for="(row, index) in inbound.stream.externalProxy"> <a-input-group
:style="{ margin: '8px 0' }"
compact
v-for="(row, index) in inbound.stream.externalProxy"
>
<template> <template>
<a-tooltip title="Force TLS"> <a-tooltip title="Force TLS">
<a-select v-model="row.forceTls" :style="{ width: '20%', margin: '0px' }" <a-select
:dropdown-class-name="themeSwitcher.currentTheme"> v-model="row.forceTls"
<a-select-option value="same">{{ i18n "pages.inbounds.same" }}</a-select-option> :style="{ width: '20%', margin: '0px' }"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value="same"
>{{ i18n "pages.inbounds.same" }}</a-select-option
>
<a-select-option value="none">{{ i18n "none" }}</a-select-option> <a-select-option value="none">{{ i18n "none" }}</a-select-option>
<a-select-option value="tls">TLS</a-select-option> <a-select-option value="tls">TLS</a-select-option>
</a-select> </a-select>
</a-tooltip> </a-tooltip>
</template> </template>
<a-input :style="{ width: '30%' }" v-model.trim="row.dest" placeholder='{{ i18n "host" }}'></a-input> <a-input
:style="{ width: '30%' }"
v-model.trim="row.dest"
placeholder='{{ i18n "host" }}'
></a-input>
<a-tooltip title='{{ i18n "pages.inbounds.port" }}'> <a-tooltip title='{{ i18n "pages.inbounds.port" }}'>
<a-input-number :style="{ width: '15%' }" v-model.number="row.port" min="1" max="65535"></a-input-number> <a-input-number
:style="{ width: '15%' }"
v-model.number="row.port"
min="1"
max="65535"
></a-input-number>
</a-tooltip> </a-tooltip>
<a-input :style="{ width: '30%', top: '0' }" v-model.trim="row.remark" placeholder='{{ i18n "remark" }}'> <a-input
:style="{ width: '30%', top: '0' }"
v-model.trim="row.remark"
placeholder='{{ i18n "remark" }}'
>
<template slot="addonAfter"> <template slot="addonAfter">
<a-button icon="minus" size="small" @click="inbound.stream.externalProxy.splice(index, 1)"></a-button> <a-button
icon="minus"
size="small"
@click="inbound.stream.externalProxy.splice(index, 1)"
></a-button>
</template> </template>
</a-input> </a-input>
</a-input-group> </a-input-group>

View file

@ -1,167 +1,252 @@
{{define "form/streamFinalMask"}} {{define "form/streamFinalMask"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }" <a-form
v-if="inbound.protocol == Protocols.HYSTERIA || inbound.stream.network == 'kcp'"> :colon="false"
<a-divider :style="{ margin: '5px 0 0' }"></a-divider> :label-col="{ md: {span:8} }"
<a-form-item label="UDP Masks"> :wrapper-col="{ md: {span:14} }"
<a-button icon="plus" type="primary" size="small" v-if="inbound.protocol == Protocols.HYSTERIA || inbound.stream.network == 'kcp'"
@click="inbound.stream.addUdpMask(inbound.protocol === Protocols.HYSTERIA ? 'salamander' : 'mkcp-aes128gcm')"></a-button> >
</a-form-item> <a-divider :style="{ margin: '5px 0 0' }"></a-divider>
<template v-if="inbound.stream.finalmask.udp && inbound.stream.finalmask.udp.length > 0"> <a-form-item label="UDP Masks">
<a-form v-for="(mask, index) in inbound.stream.finalmask.udp" :key="index" :colon="false" <a-button
:label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> icon="plus"
<a-divider :style="{ margin: '0' }"> type="primary"
UDP Mask [[ index + 1 ]] size="small"
<a-icon type="delete" @click="() => inbound.stream.delUdpMask(index)" @click="inbound.stream.addUdpMask(inbound.protocol === Protocols.HYSTERIA ? 'salamander' : 'mkcp-aes128gcm')"
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon> ></a-button>
</a-divider> </a-form-item>
<a-form-item label='{{ i18n "pages.xray.outbound.type" }}'> <template
<a-select v-model="mask.type" v-if="inbound.stream.finalmask.udp && inbound.stream.finalmask.udp.length > 0"
@change="(type) => { mask.settings = mask._getDefaultSettings(type, {}); if(inbound.stream.network === 'kcp') { inbound.stream.kcp.mtu = type === 'xdns' ? 900 : 1350; } }" >
:dropdown-class-name="themeSwitcher.currentTheme"> <a-form
<template v-if="inbound.protocol === Protocols.HYSTERIA"> v-for="(mask, index) in inbound.stream.finalmask.udp"
<a-select-option value="salamander">Salamander (Hysteria2)</a-select-option> :key="index"
</template> :colon="false"
<template v-else> :label-col="{ md: {span:8} }"
<a-select-option value="mkcp-aes128gcm">mKCP AES-128-GCM</a-select-option> :wrapper-col="{ md: {span:14} }"
<a-select-option value="header-dns">Header DNS</a-select-option> >
<a-select-option value="header-dtls">Header DTLS 1.2</a-select-option> <a-divider :style="{ margin: '0' }">
<a-select-option value="header-srtp">Header SRTP</a-select-option> UDP Mask [[ index + 1 ]]
<a-select-option value="header-utp">Header uTP</a-select-option> <a-icon
<a-select-option value="header-wechat">Header WeChat Video</a-select-option> type="delete"
<a-select-option value="header-wireguard">Header WireGuard</a-select-option> @click="() => inbound.stream.delUdpMask(index)"
<a-select-option value="mkcp-original">mKCP Original</a-select-option> :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"
<a-select-option value="xdns">xDNS</a-select-option> ></a-icon>
<a-select-option value="xicmp">xICMP</a-select-option> </a-divider>
<a-select-option value="header-custom">Header Custom</a-select-option> <a-form-item label='{{ i18n "pages.xray.outbound.type" }}'>
<a-select-option value="noise">Noise</a-select-option> <a-select
<a-select-option value="sudoku">Sudoku</a-select-option> v-model="mask.type"
</template> @change="(type) => { mask.settings = mask._getDefaultSettings(type, {}); if(inbound.stream.network === 'kcp') { inbound.stream.kcp.mtu = type === 'xdns' ? 900 : 1350; } }"
</a-select> :dropdown-class-name="themeSwitcher.currentTheme"
</a-form-item> >
<a-form-item label="Password" v-if="['mkcp-aes128gcm', 'salamander', 'sudoku'].includes(mask.type)"> <template v-if="inbound.protocol === Protocols.HYSTERIA">
<a-input v-model.trim="mask.settings.password" placeholder="Obfuscation password"></a-input> <a-select-option value="salamander"
</a-form-item> >Salamander (Hysteria2)</a-select-option
<a-form-item label="Domain" v-if="['header-dns', 'xdns'].includes(mask.type)"> >
<a-input v-model.trim="mask.settings.domain" placeholder="e.g., www.example.com"></a-input> </template>
</a-form-item> <template v-else>
<template v-if="mask.type === 'header-custom'"> <a-select-option value="mkcp-aes128gcm"
<a-form-item label='Client'> >mKCP AES-128-GCM</a-select-option
<a-icon type="plus" type="primary" size="small" >
@click="mask.settings.client.push({rand: 0, randRange: '0-255', type: 'array', packet: []})" /> <a-select-option value="header-dns">Header DNS</a-select-option>
</a-form-item> <a-select-option value="header-dtls"
<template v-for="(c, index) in mask.settings.client" :key="index"> >Header DTLS 1.2</a-select-option
<a-divider :style="{ margin: '0' }"> Client [[ index + 1 ]] >
<a-icon type="delete" @click="() => mask.settings.client.splice(index, 1)" <a-select-option value="header-srtp">Header SRTP</a-select-option>
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon> <a-select-option value="header-utp">Header uTP</a-select-option>
</a-divider> <a-select-option value="header-wechat"
<a-form-item label='Rand'> >Header WeChat Video</a-select-option
<a-input-number v-model.number="c.rand" /> >
</a-form-item> <a-select-option value="header-wireguard"
<a-form-item label='Rand Range'> >Header WireGuard</a-select-option
<a-input v-model.trim="c.randRange" placeholder="0-255" /> >
</a-form-item> <a-select-option value="mkcp-original"
<a-form-item label='{{ i18n "pages.xray.outbound.type" }}'> >mKCP Original</a-select-option
<a-select v-model="c.type" :dropdown-class-name="themeSwitcher.currentTheme"> >
<a-select-option value="array">Array</a-select-option> <a-select-option value="xdns">xDNS</a-select-option>
<a-select-option value="str">String</a-select-option> <a-select-option value="xicmp">xICMP</a-select-option>
<a-select-option value="hex">Hex</a-select-option> <a-select-option value="header-custom"
<a-select-option value="base64">Base64</a-select-option> >Header Custom</a-select-option
</a-select> >
</a-form-item> <a-select-option value="noise">Noise</a-select-option>
<a-form-item label='Packet'> <a-select-option value="sudoku">Sudoku</a-select-option>
<a-input v-model.trim="c.packet" placeholder="binary data" /> </template>
</a-form-item> </a-select>
</template> </a-form-item>
<a-divider :style="{ margin: '0' }"></a-divider> <a-form-item
<a-form-item label='Server'> label="Password"
<a-icon type="plus" type="primary" size="small" v-if="['mkcp-aes128gcm', 'salamander', 'sudoku'].includes(mask.type)"
@click="mask.settings.server.push({rand: 0, randRange: '0-255', type: 'array', packet: []})" /> >
</a-form-item> <a-input
<template v-for="(s, index) in mask.settings.server" :key="index"> v-model.trim="mask.settings.password"
<a-divider :style="{ margin: '0' }"> Server [[ index + 1 ]] placeholder="Obfuscation password"
<a-icon type="delete" @click="() => mask.settings.server.splice(index, 1)" ></a-input>
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon> </a-form-item>
</a-divider> <a-form-item
<a-form-item label='Rand'> label="Domain"
<a-input-number v-model.number="s.rand" /> v-if="['header-dns', 'xdns'].includes(mask.type)"
</a-form-item> >
<a-form-item label='Rand Range'> <a-input
<a-input v-model.trim="s.randRange" placeholder="0-255" /> v-model.trim="mask.settings.domain"
</a-form-item> placeholder="e.g., www.example.com"
<a-form-item label='{{ i18n "pages.xray.outbound.type" }}'> ></a-input>
<a-select v-model="s.type" :dropdown-class-name="themeSwitcher.currentTheme"> </a-form-item>
<a-select-option value="array">Array</a-select-option> <template v-if="mask.type === 'header-custom'">
<a-select-option value="str">String</a-select-option> <a-form-item label="Client">
<a-select-option value="hex">Hex</a-select-option> <a-icon
<a-select-option value="base64">Base64</a-select-option> type="plus"
</a-select> type="primary"
</a-form-item> size="small"
<a-form-item label='Packet'> @click="mask.settings.client.push({rand: 0, randRange: '0-255', type: 'array', packet: []})"
<a-input v-model.trim="s.packet" placeholder="binary data" /> />
</a-form-item> </a-form-item>
</template> <template v-for="(c, index) in mask.settings.client" :key="index">
</template> <a-divider :style="{ margin: '0' }">
<template v-if="mask.type === 'noise'"> Client [[ index + 1 ]]
<a-form-item label='Reset'> <a-icon
<a-input-number v-model.number="mask.settings.reset" :min="0" /> type="delete"
</a-form-item> @click="() => mask.settings.client.splice(index, 1)"
<a-form-item label='Noise'> :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"
<a-icon type="plus" type="primary" size="small" ></a-icon>
@click="mask.settings.noise.push({rand: '1-8192', randRange: '0-255', type: 'array', packet: '', delay: ''})" /> </a-divider>
</a-form-item> <a-form-item label="Rand">
<template v-for="(n, index) in mask.settings.noise" :key="index"> <a-input-number v-model.number="c.rand" />
<a-divider :style="{ margin: '0' }"> Noise [[ index + 1 ]] </a-form-item>
<a-icon type="delete" @click="() => mask.settings.noise.splice(index, 1)" <a-form-item label="Rand Range">
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon> <a-input v-model.trim="c.randRange" placeholder="0-255" />
</a-divider> </a-form-item>
<a-form-item label='Rand'> <a-form-item label='{{ i18n "pages.xray.outbound.type" }}'>
<a-input v-model.trim="n.rand" placeholder="1-8192" /> <a-select
</a-form-item> v-model="c.type"
<a-form-item label='Rand Range'> :dropdown-class-name="themeSwitcher.currentTheme"
<a-input v-model.trim="n.randRange" placeholder="0-255" /> >
</a-form-item> <a-select-option value="array">Array</a-select-option>
<a-form-item label='{{ i18n "pages.xray.outbound.type" }}'> <a-select-option value="str">String</a-select-option>
<a-select v-model="n.type" :dropdown-class-name="themeSwitcher.currentTheme"> <a-select-option value="hex">Hex</a-select-option>
<a-select-option value="array">Array</a-select-option> <a-select-option value="base64">Base64</a-select-option>
<a-select-option value="str">String</a-select-option> </a-select>
<a-select-option value="hex">Hex</a-select-option> </a-form-item>
<a-select-option value="base64">Base64</a-select-option> <a-form-item label="Packet">
</a-select> <a-input v-model.trim="c.packet" placeholder="binary data" />
</a-form-item> </a-form-item>
<a-form-item label='Packet'> </template>
<a-input v-model.trim="n.packet" placeholder="binary data" /> <a-divider :style="{ margin: '0' }"></a-divider>
</a-form-item> <a-form-item label="Server">
<a-form-item label='Delay'> <a-icon
<a-input v-model.trim="n.delay" placeholder="10-20" /> type="plus"
</a-form-item> type="primary"
</template> size="small"
</template> @click="mask.settings.server.push({rand: 0, randRange: '0-255', type: 'array', packet: []})"
<template v-if="mask.type === 'sudoku'"> />
<a-form-item label='ASCII'> </a-form-item>
<a-input v-model.trim="mask.settings.ascii" placeholder="ASCII" /> <template v-for="(s, index) in mask.settings.server" :key="index">
</a-form-item> <a-divider :style="{ margin: '0' }">
<a-form-item label='Custom Table'> Server [[ index + 1 ]]
<a-input v-model.trim="mask.settings.customTable" placeholder="Custom Table" /> <a-icon
</a-form-item> type="delete"
<a-form-item label='Custom Tables'> @click="() => mask.settings.server.splice(index, 1)"
<a-input v-model.trim="mask.settings.customTables" placeholder="Custom Tables" /> :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"
</a-form-item> ></a-icon>
<a-form-item label='Padding Min'> </a-divider>
<a-input-number v-model.number="mask.settings.paddingMin" :min="0" /> <a-form-item label="Rand">
</a-form-item> <a-input-number v-model.number="s.rand" />
<a-form-item label='Padding Max'> </a-form-item>
<a-input-number v-model.number="mask.settings.paddingMax" :min="0" /> <a-form-item label="Rand Range">
</a-form-item> <a-input v-model.trim="s.randRange" placeholder="0-255" />
</template> </a-form-item>
<template v-if="mask.type === 'xicmp'"> <a-form-item label='{{ i18n "pages.xray.outbound.type" }}'>
<a-form-item label='IP'> <a-select
<a-input v-model.trim="mask.settings.ip" placeholder="0.0.0.0" /> v-model="s.type"
</a-form-item> :dropdown-class-name="themeSwitcher.currentTheme"
<a-form-item label='ID'> >
<a-input-number v-model.number="mask.settings.id" :min="0" /> <a-select-option value="array">Array</a-select-option>
</a-form-item> <a-select-option value="str">String</a-select-option>
</template> <a-select-option value="hex">Hex</a-select-option>
</a-form> <a-select-option value="base64">Base64</a-select-option>
</template> </a-select>
</a-form-item>
<a-form-item label="Packet">
<a-input v-model.trim="s.packet" placeholder="binary data" />
</a-form-item>
</template>
</template>
<template v-if="mask.type === 'noise'">
<a-form-item label="Reset">
<a-input-number v-model.number="mask.settings.reset" :min="0" />
</a-form-item>
<a-form-item label="Noise">
<a-icon
type="plus"
type="primary"
size="small"
@click="mask.settings.noise.push({rand: '1-8192', randRange: '0-255', type: 'array', packet: '', delay: ''})"
/>
</a-form-item>
<template v-for="(n, index) in mask.settings.noise" :key="index">
<a-divider :style="{ margin: '0' }">
Noise [[ index + 1 ]]
<a-icon
type="delete"
@click="() => mask.settings.noise.splice(index, 1)"
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"
></a-icon>
</a-divider>
<a-form-item label="Rand">
<a-input v-model.trim="n.rand" placeholder="1-8192" />
</a-form-item>
<a-form-item label="Rand Range">
<a-input v-model.trim="n.randRange" placeholder="0-255" />
</a-form-item>
<a-form-item label='{{ i18n "pages.xray.outbound.type" }}'>
<a-select
v-model="n.type"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value="array">Array</a-select-option>
<a-select-option value="str">String</a-select-option>
<a-select-option value="hex">Hex</a-select-option>
<a-select-option value="base64">Base64</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Packet">
<a-input v-model.trim="n.packet" placeholder="binary data" />
</a-form-item>
<a-form-item label="Delay">
<a-input v-model.trim="n.delay" placeholder="10-20" />
</a-form-item>
</template>
</template>
<template v-if="mask.type === 'sudoku'">
<a-form-item label="ASCII">
<a-input v-model.trim="mask.settings.ascii" placeholder="ASCII" />
</a-form-item>
<a-form-item label="Custom Table">
<a-input
v-model.trim="mask.settings.customTable"
placeholder="Custom Table"
/>
</a-form-item>
<a-form-item label="Custom Tables">
<a-input
v-model.trim="mask.settings.customTables"
placeholder="Custom Tables"
/>
</a-form-item>
<a-form-item label="Padding Min">
<a-input-number v-model.number="mask.settings.paddingMin" :min="0" />
</a-form-item>
<a-form-item label="Padding Max">
<a-input-number v-model.number="mask.settings.paddingMax" :min="0" />
</a-form-item>
</template>
<template v-if="mask.type === 'xicmp'">
<a-form-item label="IP">
<a-input v-model.trim="mask.settings.ip" placeholder="0.0.0.0" />
</a-form-item>
<a-form-item label="ID">
<a-input-number v-model.number="mask.settings.id" :min="0" />
</a-form-item>
</template>
</a-form>
</template>
</a-form> </a-form>
{{end}} {{end}}

View file

@ -1,13 +1,17 @@
{{define "form/streamGRPC"}} {{define "form/streamGRPC"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
<a-form-item label="Service Name"> :colon="false"
<a-input v-model.trim="inbound.stream.grpc.serviceName"></a-input> :label-col="{ md: {span:8} }"
</a-form-item> :wrapper-col="{ md: {span:14} }"
<a-form-item label="Authority"> >
<a-input v-model.trim="inbound.stream.grpc.authority"></a-input> <a-form-item label="Service Name">
</a-form-item> <a-input v-model.trim="inbound.stream.grpc.serviceName"></a-input>
<a-form-item label="Multi Mode"> </a-form-item>
<a-switch v-model="inbound.stream.grpc.multiMode"></a-switch> <a-form-item label="Authority">
</a-form-item> <a-input v-model.trim="inbound.stream.grpc.authority"></a-input>
</a-form-item>
<a-form-item label="Multi Mode">
<a-switch v-model="inbound.stream.grpc.multiMode"></a-switch>
</a-form-item>
</a-form> </a-form>
{{end}} {{end}}

View file

@ -1,7 +1,13 @@
{{define "form/streamHTTPUpgrade"}} {{define "form/streamHTTPUpgrade"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
:colon="false"
:label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }"
>
<a-form-item label="Proxy Protocol"> <a-form-item label="Proxy Protocol">
<a-switch v-model="inbound.stream.httpupgrade.acceptProxyProtocol"></a-switch> <a-switch
v-model="inbound.stream.httpupgrade.acceptProxyProtocol"
></a-switch>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "host" }}'> <a-form-item label='{{ i18n "host" }}'>
<a-input v-model.trim="inbound.stream.httpupgrade.host"></a-input> <a-input v-model.trim="inbound.stream.httpupgrade.host"></a-input>
@ -10,18 +16,37 @@
<a-input v-model.trim="inbound.stream.httpupgrade.path"></a-input> <a-input v-model.trim="inbound.stream.httpupgrade.path"></a-input>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'> <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button icon="plus" size="small" @click="inbound.stream.httpupgrade.addHeader('', '')"></a-button> <a-button
icon="plus"
size="small"
@click="inbound.stream.httpupgrade.addHeader('', '')"
></a-button>
</a-form-item> </a-form-item>
<a-form-item :wrapper-col="{span:24}"> <a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.httpupgrade.headers"> <a-input-group
<a-input :style="{ width: '50%' }" v-model.trim="header.name" compact
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'> v-for="(header, index) in inbound.stream.httpupgrade.headers"
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template> >
<a-input
:style="{ width: '50%' }"
v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'
>
<template slot="addonBefore" :style="{ margin: '0' }"
>[[ index+1 ]]</template
>
</a-input> </a-input>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" <a-input
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'> :style="{ width: '50%' }"
<a-button icon="minus" slot="addonAfter" size="small" v-model.trim="header.value"
@click="inbound.stream.httpupgrade.removeHeader(index)"></a-button> placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'
>
<a-button
icon="minus"
slot="addonAfter"
size="small"
@click="inbound.stream.httpupgrade.removeHeader(index)"
></a-button>
</a-input> </a-input>
</a-input-group> </a-input-group>
</a-form-item> </a-form-item>

View file

@ -1,62 +1,115 @@
{{define "form/streamHysteria"}} {{define "form/streamHysteria"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
<a-form-item label='Auth Password'> :colon="false"
<a-input v-model.trim="inbound.stream.hysteria.auth"></a-input> :label-col="{ md: {span:8} }"
</a-form-item> :wrapper-col="{ md: {span:14} }"
<a-form-item label='UDP Idle Timeout'> >
<a-input-number v-model.number="inbound.stream.hysteria.udpIdleTimeout" :min="0"></a-input-number> <a-form-item>
</a-form-item> <template slot="label">
<a-form-item label='Masquerade'> <a-tooltip>
<a-switch v-model="inbound.stream.hysteria.masqueradeSwitch"></a-switch> <template slot="title">
</a-form-item> <span>{{ i18n "reset" }}</span>
<template v-if="inbound.stream.hysteria.masqueradeSwitch">
<a-divider :style="{ margin: '5px 0 0' }">Masquerade</a-divider>
<a-form-item label='Type'>
<a-select v-model="inbound.stream.hysteria.masquerade.type"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="file">File</a-select-option>
<a-select-option value="proxy">Proxy</a-select-option>
<a-select-option value="string">String</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='Dir' v-if="inbound.stream.hysteria.masquerade.type === 'file'">
<a-input v-model.trim="inbound.stream.hysteria.masquerade.dir"></a-input>
</a-form-item>
<template v-if="inbound.stream.hysteria.masquerade.type === 'proxy'">
<a-form-item label='URL'>
<a-input v-model.trim="inbound.stream.hysteria.masquerade.url"></a-input>
</a-form-item>
<a-form-item label='Rewrite Host'>
<a-switch v-model="inbound.stream.hysteria.masquerade.rewriteHost"></a-switch>
</a-form-item>
<a-form-item label='Insecure'>
<a-switch v-model="inbound.stream.hysteria.masquerade.insecure"></a-switch>
</a-form-item>
</template>
<template v-if="inbound.stream.hysteria.masquerade.type === 'string'">
<a-form-item label='Content'>
<a-input v-model.trim="inbound.stream.hysteria.masquerade.content"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button size="small" @click="inbound.stream.hysteria.masquerade.addHeader('', '')">+</a-button>
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.hysteria.masquerade.headers">
<a-input style="width: 50%" v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="header.value"
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button slot="addonAfter" size="small"
@click="inbound.stream.hysteria.masquerade.removeHeader(index)">-</a-button>
</a-input>
</a-input-group>
</a-form-item>
<a-form-item label='Status Code'>
<a-input-number v-model.number="inbound.stream.hysteria.masquerade.statusCode"></a-input-number>
</a-form-item>
</template> </template>
Auth Password
<a-icon
@click="inbound.stream.hysteria.auth = RandomUtil.randomSeq(10)"
type="sync"
></a-icon>
</a-tooltip>
</template> </template>
<a-input v-model.trim="inbound.stream.hysteria.auth"></a-input>
</a-form-item>
<a-form-item label="UDP Idle Timeout">
<a-input-number
v-model.number="inbound.stream.hysteria.udpIdleTimeout"
:min="0"
></a-input-number>
</a-form-item>
<a-form-item label="Masquerade">
<a-switch v-model="inbound.stream.hysteria.masqueradeSwitch"></a-switch>
</a-form-item>
<template v-if="inbound.stream.hysteria.masqueradeSwitch">
<a-divider :style="{ margin: '5px 0 0' }">Masquerade</a-divider>
<a-form-item label="Type">
<a-select
v-model="inbound.stream.hysteria.masquerade.type"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value="file">File</a-select-option>
<a-select-option value="proxy">Proxy</a-select-option>
<a-select-option value="string">String</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="Dir"
v-if="inbound.stream.hysteria.masquerade.type === 'file'"
>
<a-input v-model.trim="inbound.stream.hysteria.masquerade.dir"></a-input>
</a-form-item>
<template v-if="inbound.stream.hysteria.masquerade.type === 'proxy'">
<a-form-item label="URL">
<a-input
v-model.trim="inbound.stream.hysteria.masquerade.url"
></a-input>
</a-form-item>
<a-form-item label="Rewrite Host">
<a-switch
v-model="inbound.stream.hysteria.masquerade.rewriteHost"
></a-switch>
</a-form-item>
<a-form-item label="Insecure">
<a-switch
v-model="inbound.stream.hysteria.masquerade.insecure"
></a-switch>
</a-form-item>
</template>
<template v-if="inbound.stream.hysteria.masquerade.type === 'string'">
<a-form-item label="Content">
<a-input
v-model.trim="inbound.stream.hysteria.masquerade.content"
></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button
size="small"
@click="inbound.stream.hysteria.masquerade.addHeader('', '')"
>+</a-button
>
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group
compact
v-for="(header, index) in inbound.stream.hysteria.masquerade.headers"
>
<a-input
style="width: 50%"
v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'
>
<template slot="addonBefore" style="margin: 0"
>[[ index+1 ]]</template
>
</a-input>
<a-input
style="width: 50%"
v-model.trim="header.value"
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'
>
<a-button
slot="addonAfter"
size="small"
@click="inbound.stream.hysteria.masquerade.removeHeader(index)"
>-</a-button
>
</a-input>
</a-input-group>
</a-form-item>
<a-form-item label="Status Code">
<a-input-number
v-model.number="inbound.stream.hysteria.masquerade.statusCode"
></a-input-number>
</a-form-item>
</template>
</template>
</a-form> </a-form>
{{end}} {{end}}

View file

@ -1,25 +1,49 @@
{{define "form/streamKCP"}} {{define "form/streamKCP"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
<a-form-item label='MTU'> :colon="false"
<a-input-number v-model.number="inbound.stream.kcp.mtu" :min="576" :max="1460"></a-input-number> :label-col="{ md: {span:8} }"
</a-form-item> :wrapper-col="{ md: {span:14} }"
<a-form-item label='TTI (ms)'> >
<a-input-number v-model.number="inbound.stream.kcp.tti" :min="10" :max="100"></a-input-number> <a-form-item label="MTU">
</a-form-item> <a-input-number
<a-form-item label='Uplink (MB/s)'> v-model.number="inbound.stream.kcp.mtu"
<a-input-number v-model.number="inbound.stream.kcp.upCap" :min="0"></a-input-number> :min="576"
</a-form-item> :max="1460"
<a-form-item label='Downlink (MB/s)'> ></a-input-number>
<a-input-number v-model.number="inbound.stream.kcp.downCap" :min="0"></a-input-number> </a-form-item>
</a-form-item> <a-form-item label="TTI (ms)">
<a-form-item label='Congestion'> <a-input-number
<a-switch v-model="inbound.stream.kcp.congestion"></a-switch> v-model.number="inbound.stream.kcp.tti"
</a-form-item> :min="10"
<a-form-item label='Read Buffer (MB)'> :max="100"
<a-input-number v-model.number="inbound.stream.kcp.readBuffer" :min="0"></a-input-number> ></a-input-number>
</a-form-item> </a-form-item>
<a-form-item label='Write Buffer (MB)'> <a-form-item label="Uplink (MB/s)">
<a-input-number v-model.number="inbound.stream.kcp.writeBuffer" :min="0"></a-input-number> <a-input-number
</a-form-item> v-model.number="inbound.stream.kcp.upCap"
:min="0"
></a-input-number>
</a-form-item>
<a-form-item label="Downlink (MB/s)">
<a-input-number
v-model.number="inbound.stream.kcp.downCap"
:min="0"
></a-input-number>
</a-form-item>
<a-form-item label="Congestion">
<a-switch v-model="inbound.stream.kcp.congestion"></a-switch>
</a-form-item>
<a-form-item label="Read Buffer (MB)">
<a-input-number
v-model.number="inbound.stream.kcp.readBuffer"
:min="0"
></a-input-number>
</a-form-item>
<a-form-item label="Write Buffer (MB)">
<a-input-number
v-model.number="inbound.stream.kcp.writeBuffer"
:min="0"
></a-input-number>
</a-form-item>
</a-form> </a-form>
{{end}} {{end}}

View file

@ -1,10 +1,18 @@
{{define "form/streamSettings"}} {{define "form/streamSettings"}}
<!-- select stream network --> <!-- select stream network -->
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }" <a-form
v-if="inbound.protocol != Protocols.HYSTERIA"> :colon="false"
:label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }"
v-if="inbound.protocol != Protocols.HYSTERIA"
>
<a-form-item label='{{ i18n "transmission" }}'> <a-form-item label='{{ i18n "transmission" }}'>
<a-select v-model="inbound.stream.network" :style="{ width: '75%' }" @change="streamNetworkChange" <a-select
:dropdown-class-name="themeSwitcher.currentTheme"> v-model="inbound.stream.network"
:style="{ width: '75%' }"
@change="streamNetworkChange"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value="tcp">TCP (RAW)</a-select-option> <a-select-option value="tcp">TCP (RAW)</a-select-option>
<a-select-option value="kcp">mKCP</a-select-option> <a-select-option value="kcp">mKCP</a-select-option>
<a-select-option value="ws">WebSocket</a-select-option> <a-select-option value="ws">WebSocket</a-select-option>
@ -51,12 +59,8 @@
</template> </template>
<!-- sockopt --> <!-- sockopt -->
<template> <template> {{template "form/streamSockopt"}} </template>
{{template "form/streamSockopt"}}
</template>
<!-- finalmask --> <!-- finalmask -->
<template> <template> {{template "form/streamFinalMask"}} </template>
{{template "form/streamFinalMask"}}
</template>
{{end}} {{end}}

View file

@ -1,78 +1,119 @@
{{define "form/streamSockopt"}} {{define "form/streamSockopt"}}
<a-divider :style="{ margin: '5px 0 0' }"></a-divider> <a-divider :style="{ margin: '5px 0 0' }"></a-divider>
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
<a-form-item label="Sockopt"> :colon="false"
<a-switch v-model="inbound.stream.sockoptSwitch"></a-switch> :label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }"
>
<a-form-item label="Sockopt">
<a-switch v-model="inbound.stream.sockoptSwitch"></a-switch>
</a-form-item>
<template v-if="inbound.stream.sockoptSwitch">
<a-form-item label="Route Mark">
<a-input-number
v-model.number="inbound.stream.sockopt.mark"
:min="0"
></a-input-number>
</a-form-item> </a-form-item>
<template v-if="inbound.stream.sockoptSwitch"> <a-form-item label="TCP Keep Alive Interval">
<a-form-item label="Route Mark"> <a-input-number
<a-input-number v-model.number="inbound.stream.sockopt.mark" :min="0"></a-input-number> v-model.number="inbound.stream.sockopt.tcpKeepAliveInterval"
</a-form-item> :min="0"
<a-form-item label="TCP Keep Alive Interval"> ></a-input-number>
<a-input-number v-model.number="inbound.stream.sockopt.tcpKeepAliveInterval" :min="0"></a-input-number> </a-form-item>
</a-form-item> <a-form-item label="TCP Keep Alive Idle">
<a-form-item label="TCP Keep Alive Idle"> <a-input-number
<a-input-number v-model.number="inbound.stream.sockopt.tcpKeepAliveIdle" :min="0"></a-input-number> v-model.number="inbound.stream.sockopt.tcpKeepAliveIdle"
</a-form-item> :min="0"
<a-form-item label="TCP Max Seg"> ></a-input-number>
<a-input-number v-model.number="inbound.stream.sockopt.tcpMaxSeg" :min="0"></a-input-number> </a-form-item>
</a-form-item> <a-form-item label="TCP Max Seg">
<a-form-item label="TCP User Timeout"> <a-input-number
<a-input-number v-model.number="inbound.stream.sockopt.tcpUserTimeout" :min="0"></a-input-number> v-model.number="inbound.stream.sockopt.tcpMaxSeg"
</a-form-item> :min="0"
<a-form-item label="TCP Window Clamp"> ></a-input-number>
<a-input-number v-model.number="inbound.stream.sockopt.tcpWindowClamp" :min="0"></a-input-number> </a-form-item>
</a-form-item> <a-form-item label="TCP User Timeout">
<a-form-item label="Proxy Protocol"> <a-input-number
<a-switch v-model="inbound.stream.sockopt.acceptProxyProtocol"></a-switch> v-model.number="inbound.stream.sockopt.tcpUserTimeout"
</a-form-item> :min="0"
<a-form-item label="TCP Fast Open"> ></a-input-number>
<a-switch v-model.trim="inbound.stream.sockopt.tcpFastOpen"></a-switch> </a-form-item>
</a-form-item> <a-form-item label="TCP Window Clamp">
<a-form-item label="Multipath TCP"> <a-input-number
<a-switch v-model.trim="inbound.stream.sockopt.tcpMptcp"></a-switch> v-model.number="inbound.stream.sockopt.tcpWindowClamp"
</a-form-item> :min="0"
<a-form-item label="Penetrate"> ></a-input-number>
<a-switch v-model.trim="inbound.stream.sockopt.penetrate"></a-switch> </a-form-item>
</a-form-item> <a-form-item label="Proxy Protocol">
<a-form-item label="V6 Only"> <a-switch v-model="inbound.stream.sockopt.acceptProxyProtocol"></a-switch>
<a-switch v-model.trim="inbound.stream.sockopt.V6Only"></a-switch> </a-form-item>
</a-form-item> <a-form-item label="TCP Fast Open">
<a-form-item label='Domain Strategy'> <a-switch v-model.trim="inbound.stream.sockopt.tcpFastOpen"></a-switch>
<a-select v-model="inbound.stream.sockopt.domainStrategy" :style="{ width: '50%' }" </a-form-item>
:dropdown-class-name="themeSwitcher.currentTheme"> <a-form-item label="Multipath TCP">
<a-select-option v-for="key in DOMAIN_STRATEGY_OPTION" :value="key">[[ key ]]</a-select-option> <a-switch v-model.trim="inbound.stream.sockopt.tcpMptcp"></a-switch>
</a-select> </a-form-item>
</a-form-item> <a-form-item label="Penetrate">
<a-form-item label='TCP Congestion'> <a-switch v-model.trim="inbound.stream.sockopt.penetrate"></a-switch>
<a-select v-model="inbound.stream.sockopt.tcpcongestion" :style="{ width: '50%' }" </a-form-item>
:dropdown-class-name="themeSwitcher.currentTheme"> <a-form-item label="V6 Only">
<a-select-option v-for="key in TCP_CONGESTION_OPTION" :value="key">[[ key ]]</a-select-option> <a-switch v-model.trim="inbound.stream.sockopt.V6Only"></a-switch>
</a-select> </a-form-item>
</a-form-item> <a-form-item label="Domain Strategy">
<a-form-item label="TProxy"> <a-select
<a-select v-model="inbound.stream.sockopt.tproxy" :style="{ width: '50%' }" v-model="inbound.stream.sockopt.domainStrategy"
:dropdown-class-name="themeSwitcher.currentTheme"> :style="{ width: '50%' }"
<a-select-option value="off">Off</a-select-option> :dropdown-class-name="themeSwitcher.currentTheme"
<a-select-option value="redirect">Redirect</a-select-option> >
<a-select-option value="tproxy">TProxy</a-select-option> <a-select-option v-for="key in DOMAIN_STRATEGY_OPTION" :value="key"
</a-select> >[[ key ]]</a-select-option
</a-form-item> >
<a-form-item label="Dialer Proxy"> </a-select>
<a-input v-model="inbound.stream.sockopt.dialerProxy"></a-input> </a-form-item>
</a-form-item> <a-form-item label="TCP Congestion">
<a-form-item label="Interface Name"> <a-select
<a-input v-model="inbound.stream.sockopt.interfaceName"></a-input> v-model="inbound.stream.sockopt.tcpcongestion"
</a-form-item> :style="{ width: '50%' }"
<a-form-item label="Trusted X-Forwarded-For"> :dropdown-class-name="themeSwitcher.currentTheme"
<a-select mode="tags" v-model="inbound.stream.sockopt.trustedXForwardedFor" :style="{ width: '100%' }" >
:dropdown-class-name="themeSwitcher.currentTheme"> <a-select-option v-for="key in TCP_CONGESTION_OPTION" :value="key"
<a-select-option value="CF-Connecting-IP">CF-Connecting-IP</a-select-option> >[[ key ]]</a-select-option
<a-select-option value="X-Real-IP">X-Real-IP</a-select-option> >
<a-select-option value="True-Client-IP">True-Client-IP</a-select-option> </a-select>
<a-select-option value="X-Client-IP">X-Client-IP</a-select-option> </a-form-item>
</a-select> <a-form-item label="TProxy">
</a-form-item> <a-select
</template> v-model="inbound.stream.sockopt.tproxy"
:style="{ width: '50%' }"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value="off">Off</a-select-option>
<a-select-option value="redirect">Redirect</a-select-option>
<a-select-option value="tproxy">TProxy</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Dialer Proxy">
<a-input v-model="inbound.stream.sockopt.dialerProxy"></a-input>
</a-form-item>
<a-form-item label="Interface Name">
<a-input v-model="inbound.stream.sockopt.interfaceName"></a-input>
</a-form-item>
<a-form-item label="Trusted X-Forwarded-For">
<a-select
mode="tags"
v-model="inbound.stream.sockopt.trustedXForwardedFor"
:style="{ width: '100%' }"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value="CF-Connecting-IP"
>CF-Connecting-IP</a-select-option
>
<a-select-option value="X-Real-IP">X-Real-IP</a-select-option>
<a-select-option value="True-Client-IP">True-Client-IP</a-select-option>
<a-select-option value="X-Client-IP">X-Client-IP</a-select-option>
</a-select>
</a-form-item>
</template>
</a-form> </a-form>
{{end}} {{end}}

View file

@ -1,19 +1,31 @@
{{define "form/streamTCP"}} {{define "form/streamTCP"}}
<!-- tcp type --> <!-- tcp type -->
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
:colon="false"
:label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }"
>
<a-form-item label="Proxy Protocol" v-if="inbound.canEnableTls()"> <a-form-item label="Proxy Protocol" v-if="inbound.canEnableTls()">
<a-switch v-model="inbound.stream.tcp.acceptProxyProtocol"></a-switch> <a-switch v-model="inbound.stream.tcp.acceptProxyProtocol"></a-switch>
</a-form-item> </a-form-item>
<a-form-item label='HTTP {{ i18n "camouflage" }}'> <a-form-item label='HTTP {{ i18n "camouflage" }}'>
<a-switch :checked="inbound.stream.tcp.type === 'http'" <a-switch
@change="checked => inbound.stream.tcp.type = checked ? 'http' : 'none'"></a-switch> :checked="inbound.stream.tcp.type === 'http'"
@change="checked => inbound.stream.tcp.type = checked ? 'http' : 'none'"
></a-switch>
</a-form-item> </a-form-item>
</a-form> </a-form>
<a-form v-if="inbound.stream.tcp.type === 'http'" :colon="false" :label-col="{ md: {span:8} }" <a-form
:wrapper-col="{ md: {span:14} }"> v-if="inbound.stream.tcp.type === 'http'"
:colon="false"
:label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }"
>
<!-- tcp request --> <!-- tcp request -->
<a-divider :style="{ margin: '0' }">{{ i18n "pages.inbounds.stream.general.request" }}</a-divider> <a-divider :style="{ margin: '0' }"
>{{ i18n "pages.inbounds.stream.general.request" }}</a-divider
>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.version" }}'> <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.version" }}'>
<a-input v-model.trim="inbound.stream.tcp.request.version"></a-input> <a-input v-model.trim="inbound.stream.tcp.request.version"></a-input>
</a-form-item> </a-form-item>
@ -21,35 +33,66 @@
<a-input v-model.trim="inbound.stream.tcp.request.method"></a-input> <a-input v-model.trim="inbound.stream.tcp.request.method"></a-input>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<template slot="label">{{ i18n "pages.inbounds.stream.tcp.path" }} <template slot="label"
<a-button icon="plus" size="small" @click="inbound.stream.tcp.request.addPath('/')"></a-button> >{{ i18n "pages.inbounds.stream.tcp.path" }}
<a-button
icon="plus"
size="small"
@click="inbound.stream.tcp.request.addPath('/')"
></a-button>
</template> </template>
<template v-for="(path, index) in inbound.stream.tcp.request.path"> <template v-for="(path, index) in inbound.stream.tcp.request.path">
<a-input v-model.trim="inbound.stream.tcp.request.path[index]"> <a-input v-model.trim="inbound.stream.tcp.request.path[index]">
<a-button icon="minus" size="small" slot="addonAfter" @click="inbound.stream.tcp.request.removePath(index)" <a-button
v-if="inbound.stream.tcp.request.path.length>1"></a-button> icon="minus"
size="small"
slot="addonAfter"
@click="inbound.stream.tcp.request.removePath(index)"
v-if="inbound.stream.tcp.request.path.length>1"
></a-button>
</a-input> </a-input>
</template> </template>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'> <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button icon="plus" size="small" @click="inbound.stream.tcp.request.addHeader('Host', '')"></a-button> <a-button
icon="plus"
size="small"
@click="inbound.stream.tcp.request.addHeader('Host', '')"
></a-button>
</a-form-item> </a-form-item>
<a-form-item :wrapper-col="{span:24}"> <a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.tcp.request.headers"> <a-input-group
<a-input :style="{ width: '50%' }" v-model.trim="header.name" compact
placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'> v-for="(header, index) in inbound.stream.tcp.request.headers"
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template> >
<a-input
:style="{ width: '50%' }"
v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'
>
<template slot="addonBefore" :style="{ margin: '0' }"
>[[ index+1 ]]</template
>
</a-input> </a-input>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" <a-input
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'> :style="{ width: '50%' }"
<a-button icon="minus" slot="addonAfter" size="small" v-model.trim="header.value"
@click="inbound.stream.tcp.request.removeHeader(index)"></a-button> placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'
>
<a-button
icon="minus"
slot="addonAfter"
size="small"
@click="inbound.stream.tcp.request.removeHeader(index)"
></a-button>
</a-input> </a-input>
</a-input-group> </a-input-group>
</a-form-item> </a-form-item>
<!-- tcp response --> <!-- tcp response -->
<a-divider :style="{ margin: '0' }">{{ i18n "pages.inbounds.stream.general.response" }}</a-divider> <a-divider :style="{ margin: '0' }"
>{{ i18n "pages.inbounds.stream.general.response" }}</a-divider
>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.version" }}'> <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.version" }}'>
<a-input v-model.trim="inbound.stream.tcp.response.version"></a-input> <a-input v-model.trim="inbound.stream.tcp.response.version"></a-input>
</a-form-item> </a-form-item>
@ -60,19 +103,37 @@
<a-input v-model.trim="inbound.stream.tcp.response.reason"></a-input> <a-input v-model.trim="inbound.stream.tcp.response.reason"></a-input>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseHeader" }}'> <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseHeader" }}'>
<a-button icon="plus" size="small" <a-button
@click="inbound.stream.tcp.response.addHeader('Content-Type', 'application/octet-stream')"></a-button> icon="plus"
size="small"
@click="inbound.stream.tcp.response.addHeader('Content-Type', 'application/octet-stream')"
></a-button>
</a-form-item> </a-form-item>
<a-form-item :wrapper-col="{span:24}"> <a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.tcp.response.headers"> <a-input-group
<a-input :style="{ width: '50%' }" v-model.trim="header.name" compact
placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'> v-for="(header, index) in inbound.stream.tcp.response.headers"
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template> >
<a-input
:style="{ width: '50%' }"
v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'
>
<template slot="addonBefore" :style="{ margin: '0' }"
>[[ index+1 ]]</template
>
</a-input> </a-input>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" <a-input
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'> :style="{ width: '50%' }"
v-model.trim="header.value"
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'
>
<template slot="addonAfter"> <template slot="addonAfter">
<a-button icon="minus" size="small" @click="inbound.stream.tcp.response.removeHeader(index)"></a-button> <a-button
icon="minus"
size="small"
@click="inbound.stream.tcp.response.removeHeader(index)"
></a-button>
</template> </template>
</a-input> </a-input>
</a-input-group> </a-input-group>

View file

@ -1,5 +1,9 @@
{{define "form/streamWS"}} {{define "form/streamWS"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
:colon="false"
:label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }"
>
<a-form-item label="Proxy Protocol"> <a-form-item label="Proxy Protocol">
<a-switch v-model="inbound.stream.ws.acceptProxyProtocol"></a-switch> <a-switch v-model="inbound.stream.ws.acceptProxyProtocol"></a-switch>
</a-form-item> </a-form-item>
@ -9,21 +13,41 @@
<a-form-item label='{{ i18n "path" }}'> <a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="inbound.stream.ws.path"></a-input> <a-input v-model.trim="inbound.stream.ws.path"></a-input>
</a-form-item> </a-form-item>
<a-form-item label='Heartbeat Period'> <a-form-item label="Heartbeat Period">
<a-input-number v-model.number="inbound.stream.ws.heartbeatPeriod" :min="0"></a-input-number> <a-input-number
v-model.number="inbound.stream.ws.heartbeatPeriod"
:min="0"
></a-input-number>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'> <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button icon="plus" size="small" @click="inbound.stream.ws.addHeader('', '')"></a-button> <a-button
icon="plus"
size="small"
@click="inbound.stream.ws.addHeader('', '')"
></a-button>
</a-form-item> </a-form-item>
<a-form-item :wrapper-col="{span:24}"> <a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.ws.headers"> <a-input-group compact v-for="(header, index) in inbound.stream.ws.headers">
<a-input :style="{ width: '50%' }" v-model.trim="header.name" <a-input
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'> :style="{ width: '50%' }"
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template> v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'
>
<template slot="addonBefore" :style="{ margin: '0' }"
>[[ index+1 ]]</template
>
</a-input> </a-input>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" <a-input
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'> :style="{ width: '50%' }"
<a-button icon="minus" slot="addonAfter" size="small" @click="inbound.stream.ws.removeHeader(index)"></a-button> v-model.trim="header.value"
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'
>
<a-button
icon="minus"
slot="addonAfter"
size="small"
@click="inbound.stream.ws.removeHeader(index)"
></a-button>
</a-input> </a-input>
</a-input-group> </a-input-group>
</a-form-item> </a-form-item>

View file

@ -1,129 +1,212 @@
{{define "form/streamXHTTP"}} {{define "form/streamXHTTP"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form
<a-form-item label='{{ i18n "host" }}'> :colon="false"
<a-input v-model.trim="inbound.stream.xhttp.host"></a-input> :label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }"
>
<a-form-item label='{{ i18n "host" }}'>
<a-input v-model.trim="inbound.stream.xhttp.host"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="inbound.stream.xhttp.path"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button
icon="plus"
size="small"
@click="inbound.stream.xhttp.addHeader('', '')"
></a-button>
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group
compact
v-for="(header, index) in inbound.stream.xhttp.headers"
>
<a-input
:style="{ width: '50%' }"
v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'
>
<template slot="addonBefore" :style="{ margin: '0' }"
>[[ index+1 ]]</template
>
</a-input>
<a-input
:style="{ width: '50%' }"
v-model.trim="header.value"
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'
>
<a-button
icon="minus"
slot="addonAfter"
size="small"
@click="inbound.stream.xhttp.removeHeader(index)"
></a-button>
</a-input>
</a-input-group>
</a-form-item>
<a-form-item label="Mode">
<a-select
v-model="inbound.stream.xhttp.mode"
:style="{ width: '50%' }"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option v-for="key in MODE_OPTION" :value="key"
>[[ key ]]</a-select-option
>
</a-select>
</a-form-item>
<a-form-item
label="Max Buffered Upload"
v-if="inbound.stream.xhttp.mode === 'packet-up'"
>
<a-input-number
v-model.number="inbound.stream.xhttp.scMaxBufferedPosts"
></a-input-number>
</a-form-item>
<a-form-item
label="Max Upload Size (Byte)"
v-if="inbound.stream.xhttp.mode === 'packet-up'"
>
<a-input v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input>
</a-form-item>
<a-form-item
label="Stream-Up Server"
v-if="inbound.stream.xhttp.mode === 'stream-up'"
>
<a-input v-model.trim="inbound.stream.xhttp.scStreamUpServerSecs"></a-input>
</a-form-item>
<a-form-item label="Padding Bytes">
<a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input>
</a-form-item>
<a-form-item label="Padding Obfs Mode">
<a-switch v-model="inbound.stream.xhttp.xPaddingObfsMode"></a-switch>
</a-form-item>
<template v-if="inbound.stream.xhttp.xPaddingObfsMode">
<a-form-item label="Padding Key">
<a-input
v-model.trim="inbound.stream.xhttp.xPaddingKey"
placeholder="x_padding"
></a-input>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "path" }}'> <a-form-item label="Padding Header">
<a-input v-model.trim="inbound.stream.xhttp.path"></a-input> <a-input
v-model.trim="inbound.stream.xhttp.xPaddingHeader"
placeholder="X-Padding"
></a-input>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'> <a-form-item label="Padding Placement">
<a-button icon="plus" size="small" @click="inbound.stream.xhttp.addHeader('', '')"></a-button> <a-select
v-model="inbound.stream.xhttp.xPaddingPlacement"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value>Default (queryInHeader)</a-select-option>
<a-select-option value="queryInHeader">queryInHeader</a-select-option>
<a-select-option value="header">header</a-select-option>
<a-select-option value="cookie">cookie</a-select-option>
<a-select-option value="query">query</a-select-option>
</a-select>
</a-form-item> </a-form-item>
<a-form-item :wrapper-col="{span:24}"> <a-form-item label="Padding Method">
<a-input-group compact v-for="(header, index) in inbound.stream.xhttp.headers"> <a-select
<a-input :style="{ width: '50%' }" v-model.trim="header.name" v-model="inbound.stream.xhttp.xPaddingMethod"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'> :dropdown-class-name="themeSwitcher.currentTheme"
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 >
]]</template> <a-select-option value>Default (repeat-x)</a-select-option>
</a-input> <a-select-option value="repeat-x">repeat-x</a-select-option>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" <a-select-option value="tokenish">tokenish</a-select-option>
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'> </a-select>
<a-button icon="minus" slot="addonAfter" size="small"
@click="inbound.stream.xhttp.removeHeader(index)"></a-button>
</a-input>
</a-input-group>
</a-form-item>
<a-form-item label='Mode'>
<a-select v-model="inbound.stream.xhttp.mode" :style="{ width: '50%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key
]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Max Buffered Upload" v-if="inbound.stream.xhttp.mode === 'packet-up'">
<a-input-number v-model.number="inbound.stream.xhttp.scMaxBufferedPosts"></a-input-number>
</a-form-item>
<a-form-item label="Max Upload Size (Byte)" v-if="inbound.stream.xhttp.mode === 'packet-up'">
<a-input v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input>
</a-form-item>
<a-form-item label="Stream-Up Server" v-if="inbound.stream.xhttp.mode === 'stream-up'">
<a-input v-model.trim="inbound.stream.xhttp.scStreamUpServerSecs"></a-input>
</a-form-item>
<a-form-item label="Padding Bytes">
<a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input>
</a-form-item>
<a-form-item label="Padding Obfs Mode">
<a-switch v-model="inbound.stream.xhttp.xPaddingObfsMode"></a-switch>
</a-form-item>
<template v-if="inbound.stream.xhttp.xPaddingObfsMode">
<a-form-item label="Padding Key">
<a-input v-model.trim="inbound.stream.xhttp.xPaddingKey" placeholder="x_padding"></a-input>
</a-form-item>
<a-form-item label="Padding Header">
<a-input v-model.trim="inbound.stream.xhttp.xPaddingHeader" placeholder="X-Padding"></a-input>
</a-form-item>
<a-form-item label="Padding Placement">
<a-select v-model="inbound.stream.xhttp.xPaddingPlacement"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value>Default (queryInHeader)</a-select-option>
<a-select-option value="queryInHeader">queryInHeader</a-select-option>
<a-select-option value="header">header</a-select-option>
<a-select-option value="cookie">cookie</a-select-option>
<a-select-option value="query">query</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Padding Method">
<a-select v-model="inbound.stream.xhttp.xPaddingMethod" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value>Default (repeat-x)</a-select-option>
<a-select-option value="repeat-x">repeat-x</a-select-option>
<a-select-option value="tokenish">tokenish</a-select-option>
</a-select>
</a-form-item>
</template>
<a-form-item label="Uplink HTTP Method">
<a-select v-model="inbound.stream.xhttp.uplinkHTTPMethod" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value>Default (POST)</a-select-option>
<a-select-option value="POST">POST</a-select-option>
<a-select-option value="PUT">PUT</a-select-option>
<a-select-option value="GET">GET (packet-up only)</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Session Placement">
<a-select v-model="inbound.stream.xhttp.sessionPlacement" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value>Default (path)</a-select-option>
<a-select-option value="path">path</a-select-option>
<a-select-option value="header">header</a-select-option>
<a-select-option value="cookie">cookie</a-select-option>
<a-select-option value="query">query</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Session Key"
v-if="inbound.stream.xhttp.sessionPlacement && inbound.stream.xhttp.sessionPlacement !== 'path'">
<a-input v-model.trim="inbound.stream.xhttp.sessionKey" placeholder="x_session"></a-input>
</a-form-item>
<a-form-item label="Sequence Placement">
<a-select v-model="inbound.stream.xhttp.seqPlacement" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value>Default (path)</a-select-option>
<a-select-option value="path">path</a-select-option>
<a-select-option value="header">header</a-select-option>
<a-select-option value="cookie">cookie</a-select-option>
<a-select-option value="query">query</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Sequence Key"
v-if="inbound.stream.xhttp.seqPlacement && inbound.stream.xhttp.seqPlacement !== 'path'">
<a-input v-model.trim="inbound.stream.xhttp.seqKey" placeholder="x_seq"></a-input>
</a-form-item>
<a-form-item label="Uplink Data Placement" v-if="inbound.stream.xhttp.mode === 'packet-up'">
<a-select v-model="inbound.stream.xhttp.uplinkDataPlacement" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value>Default (body)</a-select-option>
<a-select-option value="body">body</a-select-option>
<a-select-option value="header">header</a-select-option>
<a-select-option value="cookie">cookie</a-select-option>
<a-select-option value="query">query</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Uplink Data Key"
v-if="inbound.stream.xhttp.mode === 'packet-up' && inbound.stream.xhttp.uplinkDataPlacement && inbound.stream.xhttp.uplinkDataPlacement !== 'body'">
<a-input v-model.trim="inbound.stream.xhttp.uplinkDataKey" placeholder="x_data"></a-input>
</a-form-item>
<a-form-item label="Uplink Chunk Size"
v-if="inbound.stream.xhttp.mode === 'packet-up' && inbound.stream.xhttp.uplinkDataPlacement && inbound.stream.xhttp.uplinkDataPlacement !== 'body'">
<a-input-number v-model.number="inbound.stream.xhttp.uplinkChunkSize" :min="0"
placeholder="0 (unlimited)"></a-input-number>
</a-form-item>
<a-form-item label="No SSE Header">
<a-switch v-model="inbound.stream.xhttp.noSSEHeader"></a-switch>
</a-form-item> </a-form-item>
</template>
<a-form-item label="Uplink HTTP Method">
<a-select
v-model="inbound.stream.xhttp.uplinkHTTPMethod"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value>Default (POST)</a-select-option>
<a-select-option value="POST">POST</a-select-option>
<a-select-option value="PUT">PUT</a-select-option>
<a-select-option value="GET">GET (packet-up only)</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Session Placement">
<a-select
v-model="inbound.stream.xhttp.sessionPlacement"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value>Default (path)</a-select-option>
<a-select-option value="path">path</a-select-option>
<a-select-option value="header">header</a-select-option>
<a-select-option value="cookie">cookie</a-select-option>
<a-select-option value="query">query</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="Session Key"
v-if="inbound.stream.xhttp.sessionPlacement && inbound.stream.xhttp.sessionPlacement !== 'path'"
>
<a-input
v-model.trim="inbound.stream.xhttp.sessionKey"
placeholder="x_session"
></a-input>
</a-form-item>
<a-form-item label="Sequence Placement">
<a-select
v-model="inbound.stream.xhttp.seqPlacement"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value>Default (path)</a-select-option>
<a-select-option value="path">path</a-select-option>
<a-select-option value="header">header</a-select-option>
<a-select-option value="cookie">cookie</a-select-option>
<a-select-option value="query">query</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="Sequence Key"
v-if="inbound.stream.xhttp.seqPlacement && inbound.stream.xhttp.seqPlacement !== 'path'"
>
<a-input
v-model.trim="inbound.stream.xhttp.seqKey"
placeholder="x_seq"
></a-input>
</a-form-item>
<a-form-item
label="Uplink Data Placement"
v-if="inbound.stream.xhttp.mode === 'packet-up'"
>
<a-select
v-model="inbound.stream.xhttp.uplinkDataPlacement"
:dropdown-class-name="themeSwitcher.currentTheme"
>
<a-select-option value>Default (body)</a-select-option>
<a-select-option value="body">body</a-select-option>
<a-select-option value="header">header</a-select-option>
<a-select-option value="cookie">cookie</a-select-option>
<a-select-option value="query">query</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="Uplink Data Key"
v-if="inbound.stream.xhttp.mode === 'packet-up' && inbound.stream.xhttp.uplinkDataPlacement && inbound.stream.xhttp.uplinkDataPlacement !== 'body'"
>
<a-input
v-model.trim="inbound.stream.xhttp.uplinkDataKey"
placeholder="x_data"
></a-input>
</a-form-item>
<a-form-item
label="Uplink Chunk Size"
v-if="inbound.stream.xhttp.mode === 'packet-up' && inbound.stream.xhttp.uplinkDataPlacement && inbound.stream.xhttp.uplinkDataPlacement !== 'body'"
>
<a-input-number
v-model.number="inbound.stream.xhttp.uplinkChunkSize"
:min="0"
placeholder="0 (unlimited)"
></a-input-number>
</a-form-item>
<a-form-item label="No SSE Header">
<a-switch v-model="inbound.stream.xhttp.noSSEHeader"></a-switch>
</a-form-item>
</a-form> </a-form>
{{end}} {{end}}