mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-21 16:25:49 +00:00
更新大量功能
This commit is contained in:
@@ -1,535 +0,0 @@
|
||||
{{define "inboundModal"}}
|
||||
<a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" @ok="inModal.ok"
|
||||
:confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false"
|
||||
:ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'>
|
||||
|
||||
<!-- base -->
|
||||
<a-form layout="inline">
|
||||
<a-form-item label='{{ i18n "remark" }}'>
|
||||
<a-input v-model.trim="inModal.inbound.remark"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "enable" }}'>
|
||||
<a-switch v-model="inModal.inbound.enable"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "protocol" }}'>
|
||||
<a-select v-model="inModal.inbound.protocol" style="width: 160px;"
|
||||
@change="protocolChange">
|
||||
<a-select-option v-for="p in Protocols" :key="p" :value="p">[[ p ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
监听 IP
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
不懂请保持默认
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-input v-model.trim="inModal.inbound.listen"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="端口">
|
||||
<a-input type="number" v-model.number="inModal.inbound.port"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess settings -->
|
||||
<a-form v-if="inModal.inbound.protocol === Protocols.VMESS"
|
||||
layout="inline">
|
||||
<a-form-item label="id">
|
||||
<a-input v-model.trim="inModal.inbound.settings.vmesses[0].id"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="额外 ID">
|
||||
<a-input type="number" v-model.number="inModal.inbound.settings.vmesses[0].alterId"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="禁用不安全加密">
|
||||
<a-switch v-model.number="inModal.inbound.settings.disableInsecure"></a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vless settings -->
|
||||
<a-form v-if="inModal.inbound.protocol === Protocols.VLESS"
|
||||
layout="inline">
|
||||
<a-form-item label="id">
|
||||
<a-input v-model.trim="inModal.inbound.settings.vlesses[0].id"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="flow">
|
||||
<a-select v-model="inModal.inbound.settings.vlesses[0].flow" style="width: 150px">
|
||||
<a-select-option value="">无</a-select-option>
|
||||
<a-select-option v-for="key in VLESS_FLOW" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<a-form v-if="inModal.inbound.protocol === Protocols.VLESS"
|
||||
layout="inline">
|
||||
<a-form-item label="fallbacks">
|
||||
<a-row>
|
||||
<a-button type="primary" size="small"
|
||||
@click="inModal.inbound.settings.addFallback()">
|
||||
+
|
||||
</a-button>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vless fallbacks -->
|
||||
<a-form v-for="(fallback, index) in inModal.inbound.settings.fallbacks" layout="inline">
|
||||
<a-form-item>
|
||||
<a-divider>
|
||||
fallback[[ index + 1 ]]
|
||||
<a-icon type="delete" @click="() => inModal.inbound.settings.delFallback(index)" style="color: rgb(255, 77, 79);cursor: pointer;"/>
|
||||
</a-divider>
|
||||
</a-form-item>
|
||||
<a-form-item label="name">
|
||||
<a-input v-model="fallback.name"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="alpn">
|
||||
<a-input v-model="fallback.alpn"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="path">
|
||||
<a-input v-model="fallback.path"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="dest">
|
||||
<a-input v-model="fallback.dest"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="xver">
|
||||
<a-input type="number" v-model.number="fallback.xver"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- trojan settings -->
|
||||
<a-form v-if="inModal.inbound.protocol === Protocols.TROJAN"
|
||||
layout="inline">
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inModal.inbound.settings.clients[0].password"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- shadowsocks -->
|
||||
<a-form v-if="inModal.inbound.protocol === Protocols.SHADOWSOCKS"
|
||||
layout="inline">
|
||||
<a-form-item label="加密">
|
||||
<a-select v-model="inModal.inbound.settings.method" style="width: 165px;">
|
||||
<a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inModal.inbound.settings.password"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="网络">
|
||||
<a-select v-model="inModal.inbound.settings.network" style="width: 100px;">
|
||||
<a-select-option value="tcp,udp">tcp+udp</a-select-option>
|
||||
<a-select-option value="tcp">tcp</a-select-option>
|
||||
<a-select-option value="udp">udp</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- stream settings -->
|
||||
<template v-if="inModal.inbound.protocol === Protocols.VMESS
|
||||
|| inModal.inbound.protocol === Protocols.VLESS
|
||||
|| inModal.inbound.protocol === Protocols.SHADOWSOCKS">
|
||||
|
||||
<!-- select stream network -->
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="传输">
|
||||
<a-select v-model="inModal.inbound.stream.network" @change="streamNetworkChange">
|
||||
<a-select-option value="tcp">tcp</a-select-option>
|
||||
<a-select-option value="kcp">kcp</a-select-option>
|
||||
<a-select-option value="ws">ws</a-select-option>
|
||||
<a-select-option value="http">http</a-select-option>
|
||||
<a-select-option value="quic">quic</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess tcp -->
|
||||
<template v-if="inModal.inbound.stream.network === 'tcp'">
|
||||
<!-- vmess tcp type -->
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="http 伪装">
|
||||
<a-switch
|
||||
:checked="inModal.inbound.stream.tcp.type === 'http'"
|
||||
@change="checked => inModal.inbound.stream.tcp.type = checked ? 'http' : 'none'">
|
||||
</a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess tcp request -->
|
||||
<a-form v-if="inModal.inbound.stream.tcp.type === 'http'"
|
||||
layout="inline">
|
||||
<a-form-item label="请求版本">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tcp.request.version"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求方法">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tcp.request.method"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求路径">
|
||||
<a-row v-for="(path, index) in inModal.inbound.stream.tcp.request.path">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tcp.request.path[index]"></a-input>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求头">
|
||||
<a-row>
|
||||
<a-button size="small"
|
||||
@click="inModal.inbound.stream.tcp.request.addHeader('Host', 'xxx.com')">
|
||||
+
|
||||
</a-button>
|
||||
</a-row>
|
||||
<a-input-group v-for="(header, index) in inModal.inbound.stream.tcp.request.headers">
|
||||
<a-input style="width: 50%" v-model.trim="header.name"
|
||||
addon-before="名称"></a-input>
|
||||
<a-input style="width: 50%" v-model.trim="header.value"
|
||||
addon-before="值">
|
||||
<template slot="addonAfter">
|
||||
<a-button size="small"
|
||||
@click="inModal.inbound.stream.tcp.request.removeHeader(index)">
|
||||
-
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess tcp response -->
|
||||
<a-form v-if="inModal.inbound.stream.tcp.type === 'http'"
|
||||
layout="inline">
|
||||
<a-form-item label="响应版本">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tcp.response.version"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="响应状态">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tcp.response.status"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="响应状态说明">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tcp.response.reason"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="响应头">
|
||||
<a-row>
|
||||
<a-button size="small"
|
||||
@click="inModal.inbound.stream.tcp.response.addHeader('Content-Type', 'application/octet-stream')">
|
||||
+
|
||||
</a-button>
|
||||
</a-row>
|
||||
<a-input-group v-for="(header, index) in inModal.inbound.stream.tcp.response.headers">
|
||||
<a-input style="width: 50%" v-model.trim="header.name"
|
||||
addon-before="名称"></a-input>
|
||||
<a-input style="width: 50%" v-model.trim="header.value"
|
||||
addon-before="值">
|
||||
<template slot="addonAfter">
|
||||
<a-button size="small"
|
||||
@click="inModal.inbound.stream.tcp.response.removeHeader(index)">
|
||||
-
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<!-- vmess kcp -->
|
||||
<a-form v-if="inModal.inbound.stream.network === 'kcp'"
|
||||
layout="inline">
|
||||
<a-form-item label="伪装">
|
||||
<a-select v-model="inModal.inbound.stream.kcp.type" style="width: 280px;">
|
||||
<a-select-option value="none">none(not camouflage)</a-select-option>
|
||||
<a-select-option value="srtp">srtp(camouflage video call)</a-select-option>
|
||||
<a-select-option value="utp">utp(camouflage BT download)</a-select-option>
|
||||
<a-select-option value="wechat-video">wechat-video(camouflage WeChat video)</a-select-option>
|
||||
<a-select-option value="dtls">dtls(camouflage DTLS 1.2 packages)</a-select-option>
|
||||
<a-select-option value="wireguard">wireguard(camouflage wireguard packages)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.number="inModal.inbound.stream.kcp.seed"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="mtu">
|
||||
<a-input type="number" v-model.number="inModal.inbound.stream.kcp.mtu"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="tti (ms)">
|
||||
<a-input type="number" v-model.number="inModal.inbound.stream.kcp.tti"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="uplink capacity (MB/S)">
|
||||
<a-input type="number" v-model.number="inModal.inbound.stream.kcp.upCap"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="downlink capacity (MB/S)">
|
||||
<a-input type="number" v-model.number="inModal.inbound.stream.kcp.downCap"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="congestion">
|
||||
<a-switch v-model="inModal.inbound.stream.kcp.congestion"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label="read buffer size (MB)">
|
||||
<a-input type="number" v-model.number="inModal.inbound.stream.kcp.readBuffer"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="write buffer size (MB)">
|
||||
<a-input type="number" v-model.number="inModal.inbound.stream.kcp.writeBuffer"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess ws -->
|
||||
<a-form v-if="inModal.inbound.stream.network === 'ws'"
|
||||
layout="inline">
|
||||
<a-form-item label="路径">
|
||||
<a-input v-model.trim="inModal.inbound.stream.ws.path"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求头">
|
||||
<a-row>
|
||||
<a-button size="small"
|
||||
@click="inModal.inbound.stream.ws.addHeader('Host', '')">
|
||||
+
|
||||
</a-button>
|
||||
</a-row>
|
||||
<a-input-group v-for="(header, index) in inModal.inbound.stream.ws.headers">
|
||||
<a-input style="width: 50%" v-model.trim="header.name"
|
||||
addon-before="名称"></a-input>
|
||||
<a-input style="width: 50%" v-model.trim="header.value"
|
||||
addon-before="值">
|
||||
<template slot="addonAfter">
|
||||
<a-button size="small"
|
||||
@click="inModal.inbound.stream.ws.removeHeader(index)">
|
||||
-
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess http -->
|
||||
<a-form v-if="inModal.inbound.stream.network === 'http'"
|
||||
layout="inline">
|
||||
<a-form-item label="路径">
|
||||
<a-input v-model.trim="inModal.inbound.stream.http.path"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="host">
|
||||
<a-row v-for="(host, index) in inModal.inbound.stream.http.host">
|
||||
<a-input v-model.trim="inModal.inbound.stream.http.host[index]"></a-input>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess quic -->
|
||||
<a-form v-if="inModal.inbound.stream.network === 'quic'"
|
||||
layout="inline">
|
||||
<a-form-item label="加密">
|
||||
<a-select v-model="inModal.inbound.stream.quic.security" style="width: 165px;">
|
||||
<a-select-option value="none">none</a-select-option>
|
||||
<a-select-option value="aes-128-gcm">aes-128-gcm</a-select-option>
|
||||
<a-select-option value="chacha20-poly1305">chacha20-poly1305</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inModal.inbound.stream.quic.key"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="伪装">
|
||||
<a-select v-model="inModal.inbound.stream.quic.type" style="width: 280px;">
|
||||
<a-select-option value="none">none(not camouflage)</a-select-option>
|
||||
<a-select-option value="srtp">srtp(camouflage video call)</a-select-option>
|
||||
<a-select-option value="utp">utp(camouflage BT download)</a-select-option>
|
||||
<a-select-option value="wechat-video">wechat-video(camouflage WeChat video)</a-select-option>
|
||||
<a-select-option value="dtls">dtls(camouflage DTLS 1.2 packages)</a-select-option>
|
||||
<a-select-option value="wireguard">wireguard(camouflage wireguard packages)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<!-- dokodemo-door -->
|
||||
<a-form v-if="inModal.inbound.protocol === Protocols.DOKODEMO"
|
||||
layout="inline">
|
||||
<a-form-item label="目标地址">
|
||||
<a-input v-model.trim="inModal.inbound.settings.address"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="目标端口">
|
||||
<a-input type="number" v-model.number="inModal.inbound.settings.port"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="网络">
|
||||
<a-select v-model="inModal.inbound.settings.network" style="width: 100px;">
|
||||
<a-select-option value="tcp,udp">tcp+udp</a-select-option>
|
||||
<a-select-option value="tcp">tcp</a-select-option>
|
||||
<a-select-option value="udp">udp</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- socks -->
|
||||
<a-form v-if="inModal.inbound.protocol === Protocols.SOCKS"
|
||||
layout="inline">
|
||||
<a-form-item label="密码认证">
|
||||
<a-switch :checked="inModal.inbound.settings.auth === 'password'"
|
||||
@change="checked => inModal.inbound.settings.auth = checked ? 'password' : 'noauth'"></a-switch>
|
||||
</a-form-item>
|
||||
<template v-if="inModal.inbound.settings.auth === 'password'">
|
||||
<a-form-item label="用户名">
|
||||
<a-input v-model.trim="inModal.inbound.settings.accounts[0].user"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inModal.inbound.settings.accounts[0].pass"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<a-form-item label="启用 udp">
|
||||
<a-switch v-model="inModal.inbound.settings.udp"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inModal.inbound.settings.udp"
|
||||
label="IP">
|
||||
<a-input v-model.trim="inModal.inbound.settings.ip"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- http -->
|
||||
<a-form v-if="inModal.inbound.protocol === Protocols.HTTP"
|
||||
layout="inline">
|
||||
<a-form-item label="用户名">
|
||||
<a-input v-model.trim="inModal.inbound.settings.accounts[0].user"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inModal.inbound.settings.accounts[0].pass"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- tls settings -->
|
||||
<template v-if="(inModal.inbound.protocol === Protocols.VMESS
|
||||
|| inModal.inbound.protocol === Protocols.VLESS
|
||||
|| inModal.inbound.protocol === Protocols.TROJAN
|
||||
|| inModal.inbound.protocol === Protocols.SHADOWSOCKS)
|
||||
&& ['tcp', 'ws', 'http', 'quic'].indexOf(inModal.inbound.stream.network) >= 0">
|
||||
|
||||
<!-- tls enable -->
|
||||
<a-form layout="inline" v-if="inModal.inbound.protocol !== Protocols.TROJAN">
|
||||
<a-form-item label="tls">
|
||||
<a-switch
|
||||
:checked="inModal.inbound.stream.security === 'tls'"
|
||||
@change="checked => inModal.inbound.stream.security = checked ? 'tls' : 'none'">
|
||||
</a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inModal.inbound.protocol === Protocols.VLESS && inModal.inbound.stream.security === 'tls' && inModal.inbound.stream.network === 'tcp'" label="xtls">
|
||||
<a-switch v-model="inModal.inbound.stream.is_xtls"></a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- tls settings -->
|
||||
<a-form v-if="inModal.inbound.stream.security === 'tls'"
|
||||
layout="inline">
|
||||
<a-form-item label="域名">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tls.server"></a-input>
|
||||
</a-form-item>
|
||||
{# <a-form-item label="允许不安全">#}
|
||||
{# <a-switch v-model="inModal.inbound.stream.tls.allowInsecure"></a-switch>#}
|
||||
{# </a-form-item>#}
|
||||
<a-form-item label="证书">
|
||||
<a-radio-group v-model="inModal.inbound.stream.tls.certs[0].useFile"
|
||||
button-style="solid">
|
||||
<a-radio-button :value="true">certificate file path</a-radio-button>
|
||||
<a-radio-button :value="false">certificate file content</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<template v-if="inModal.inbound.stream.tls.certs[0].useFile">
|
||||
<a-form-item label="公钥文件路径">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tls.certs[0].certFile"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="密钥文件路径">
|
||||
<a-input v-model.trim="inModal.inbound.stream.tls.certs[0].keyFile"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-form-item label="公钥内容">
|
||||
<a-input type="textarea" :rows="2"
|
||||
v-model="inModal.inbound.stream.tls.certs[0].cert"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="密钥内容">
|
||||
<a-input type="textarea" :rows="2"
|
||||
v-model="inModal.inbound.stream.tls.certs[0].key"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<!-- sniffing -->
|
||||
<a-form layout="inline">
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
sniffing
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
没有特殊需求保持默认即可
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-switch v-model="inModal.inbound.sniffing.enabled"></a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
<script>
|
||||
|
||||
const inModal = {
|
||||
title: '',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
okText: '确定',
|
||||
confirm: null,
|
||||
inbound: new Inbound(),
|
||||
ok() {
|
||||
ObjectUtil.execute(inModal.confirm);
|
||||
},
|
||||
show({ title='', okText='确定', inbound=null, confirm=()=>{} }) {
|
||||
this.title = title;
|
||||
this.okText = okText;
|
||||
if (inbound) {
|
||||
this.inbound = Inbound.fromJson(inbound.toJson());
|
||||
} else {
|
||||
this.inbound = new Inbound();
|
||||
}
|
||||
this.confirm = confirm;
|
||||
this.visible = true;
|
||||
},
|
||||
close() {
|
||||
inModal.visible = false;
|
||||
inModal.closeLoading();
|
||||
},
|
||||
loading() {
|
||||
inModal.confirmLoading = true;
|
||||
},
|
||||
closeLoading() {
|
||||
inModal.confirmLoading = false;
|
||||
}
|
||||
};
|
||||
|
||||
const protocols = {
|
||||
VMESS: Protocols.VMESS,
|
||||
VLESS: Protocols.VLESS,
|
||||
TROJAN: Protocols.TROJAN,
|
||||
SHADOWSOCKS: Protocols.SHADOWSOCKS,
|
||||
DOKODEMO: Protocols.DOKODEMO,
|
||||
SOCKS: Protocols.SOCKS,
|
||||
HTTP: Protocols.HTTP,
|
||||
};
|
||||
|
||||
new Vue({
|
||||
delimiters: ['[[', ']]'],
|
||||
el: '#inbound-modal',
|
||||
data: {
|
||||
inModal: inModal,
|
||||
Protocols: protocols,
|
||||
SSMethods: SSMethods,
|
||||
},
|
||||
methods: {
|
||||
streamNetworkChange(oldValue) {
|
||||
if (oldValue === 'kcp') {
|
||||
this.inModal.inbound.stream.security = 'none';
|
||||
}
|
||||
},
|
||||
protocolChange(value) {
|
||||
this.inModal.inbound.settings = Inbound.Settings.getSettings(value);
|
||||
if (value === Protocols.TROJAN) {
|
||||
this.inModal.inbound.stream.security = 'tls';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
{{end}}
|
||||
81
web/html/xui/form/inbound.html
Normal file
81
web/html/xui/form/inbound.html
Normal file
@@ -0,0 +1,81 @@
|
||||
{{define "form/inbound"}}
|
||||
<!-- base -->
|
||||
<a-form layout="inline">
|
||||
<a-form-item label='{{ i18n "remark" }}'>
|
||||
<a-input v-model.trim="dbInbound.remark"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "enable" }}'>
|
||||
<a-switch v-model="dbInbound.enable"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "protocol" }}'>
|
||||
<a-select v-model="inbound.protocol" style="width: 160px;">
|
||||
<a-select-option v-for="p in Protocols" :key="p" :value="p">[[ p ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
监听 IP
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
默认留空即可
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-input v-model.trim="inbound.listen"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="端口">
|
||||
<a-input type="number" v-model.number="inbound.port"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess settings -->
|
||||
<template v-if="inbound.protocol === Protocols.VMESS">
|
||||
{{template "form/vmess"}}
|
||||
</template>
|
||||
|
||||
<!-- vless settings -->
|
||||
<template v-if="inbound.protocol === Protocols.VLESS">
|
||||
{{template "form/vless"}}
|
||||
</template>
|
||||
|
||||
<!-- trojan settings -->
|
||||
<template v-if="inbound.protocol === Protocols.TROJAN">
|
||||
{{template "form/trojan"}}
|
||||
</template>
|
||||
|
||||
<!-- shadowsocks -->
|
||||
<template v-if="inbound.protocol === Protocols.SHADOWSOCKS">
|
||||
{{template "form/shadowsocks"}}
|
||||
</template>
|
||||
|
||||
<!-- dokodemo-door -->
|
||||
<template v-if="inbound.protocol === Protocols.DOKODEMO">
|
||||
{{template "form/dokodemo"}}
|
||||
</template>
|
||||
|
||||
<!-- socks -->
|
||||
<template v-if="inbound.protocol === Protocols.SOCKS">
|
||||
{{template "form/socks"}}
|
||||
</template>
|
||||
|
||||
<!-- http -->
|
||||
<template v-if="inbound.protocol === Protocols.HTTP">
|
||||
{{template "form/http"}}
|
||||
</template>
|
||||
|
||||
<!-- stream settings -->
|
||||
<template v-if="inbound.canEnableStream()">
|
||||
{{template "form/streamSettings"}}
|
||||
</template>
|
||||
|
||||
<!-- tls settings -->
|
||||
<template v-if="inbound.canEnableTls()">
|
||||
{{template "form/tlsSettings"}}
|
||||
</template>
|
||||
|
||||
<!-- sniffing -->
|
||||
<template v-if="inbound.canSniffing()">
|
||||
{{template "form/sniffing"}}
|
||||
</template>
|
||||
{{end}}
|
||||
17
web/html/xui/form/protocol/dokodemo.html
Normal file
17
web/html/xui/form/protocol/dokodemo.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{{define "form/dokodemo"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="目标地址">
|
||||
<a-input v-model.trim="inbound.settings.address"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="目标端口">
|
||||
<a-input type="number" v-model.number="inbound.settings.port"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="网络">
|
||||
<a-select v-model="inbound.settings.network" style="width: 100px;">
|
||||
<a-select-option value="tcp,udp">tcp+udp</a-select-option>
|
||||
<a-select-option value="tcp">tcp</a-select-option>
|
||||
<a-select-option value="udp">udp</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
10
web/html/xui/form/protocol/http.html
Normal file
10
web/html/xui/form/protocol/http.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{{define "form/http"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="用户名">
|
||||
<a-input v-model.trim="inbound.settings.accounts[0].user"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inbound.settings.accounts[0].pass"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
19
web/html/xui/form/protocol/shadowsocks.html
Normal file
19
web/html/xui/form/protocol/shadowsocks.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{{define "form/shadowsocks"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="加密">
|
||||
<a-select v-model="inbound.settings.method" style="width: 165px;">
|
||||
<a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inbound.settings.password"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="网络">
|
||||
<a-select v-model="inbound.settings.network" style="width: 100px;">
|
||||
<a-select-option value="tcp,udp">tcp+udp</a-select-option>
|
||||
<a-select-option value="tcp">tcp</a-select-option>
|
||||
<a-select-option value="udp">udp</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
23
web/html/xui/form/protocol/socks.html
Normal file
23
web/html/xui/form/protocol/socks.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{{define "form/socks"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="密码认证">
|
||||
<a-switch :checked="inbound.settings.auth === 'password'"
|
||||
@change="checked => inbound.settings.auth = checked ? 'password' : 'noauth'"></a-switch>
|
||||
</a-form-item>
|
||||
<template v-if="inbound.settings.auth === 'password'">
|
||||
<a-form-item label="用户名">
|
||||
<a-input v-model.trim="inbound.settings.accounts[0].user"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inbound.settings.accounts[0].pass"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<a-form-item label="启用 udp">
|
||||
<a-switch v-model="inbound.settings.udp"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inbound.settings.udp"
|
||||
label="IP">
|
||||
<a-input v-model.trim="inbound.settings.ip"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
7
web/html/xui/form/protocol/trojan.html
Normal file
7
web/html/xui/form/protocol/trojan.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{{define "form/trojan"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inbound.settings.clients[0].password"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
49
web/html/xui/form/protocol/vless.html
Normal file
49
web/html/xui/form/protocol/vless.html
Normal file
@@ -0,0 +1,49 @@
|
||||
{{define "form/vless"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="id">
|
||||
<a-input v-model.trim="inbound.settings.vlesses[0].id"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="flow">
|
||||
<a-select v-model="inbound.settings.vlesses[0].flow" style="width: 150px">
|
||||
<a-select-option value="">无</a-select-option>
|
||||
<a-select-option v-for="key in VLESS_FLOW" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="fallbacks">
|
||||
<a-row>
|
||||
<a-button type="primary" size="small"
|
||||
@click="inbound.settings.addFallback()">
|
||||
+
|
||||
</a-button>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vless fallbacks -->
|
||||
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" layout="inline">
|
||||
<a-divider>
|
||||
fallback[[ index + 1 ]]
|
||||
<a-icon type="delete" @click="() => inbound.settings.delFallback(index)"
|
||||
style="color: rgb(255, 77, 79);cursor: pointer;"/>
|
||||
</a-divider>
|
||||
<a-form-item label="name">
|
||||
<a-input v-model="fallback.name"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="alpn">
|
||||
<a-input v-model="fallback.alpn"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="path">
|
||||
<a-input v-model="fallback.path"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="dest">
|
||||
<a-input v-model="fallback.dest"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="xver">
|
||||
<a-input type="number" v-model.number="fallback.xver"></a-input>
|
||||
</a-form-item>
|
||||
<a-divider v-if="inbound.settings.fallbacks.length - 1 === index"/>
|
||||
</a-form>
|
||||
{{end}}
|
||||
13
web/html/xui/form/protocol/vmess.html
Normal file
13
web/html/xui/form/protocol/vmess.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{{define "form/vmess"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="id">
|
||||
<a-input v-model.trim="inbound.settings.vmesses[0].id"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="额外 ID">
|
||||
<a-input type="number" v-model.number="inbound.settings.vmesses[0].alterId"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="禁用不安全加密">
|
||||
<a-switch v-model.number="inbound.settings.disableInsecure"></a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
16
web/html/xui/form/sniffing.html
Normal file
16
web/html/xui/form/sniffing.html
Normal file
@@ -0,0 +1,16 @@
|
||||
{{define "form/sniffing"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
sniffing
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
没有特殊需求保持默认即可
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-switch v-model="inbound.sniffing.enabled"></a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
7
web/html/xui/form/stream/stream_grpc.html
Normal file
7
web/html/xui/form/stream/stream_grpc.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{{define "form/streamGRPC"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="serviceName">
|
||||
<a-input v-model.trim="inbound.stream.grpc.serviceName"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
12
web/html/xui/form/stream/stream_http.html
Normal file
12
web/html/xui/form/stream/stream_http.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{{define "form/streamHTTP"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="路径">
|
||||
<a-input v-model.trim="inbound.stream.http.path"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="host">
|
||||
<a-row v-for="(host, index) in inbound.stream.http.host">
|
||||
<a-input v-model.trim="inbound.stream.http.host[index]"></a-input>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
38
web/html/xui/form/stream/stream_kcp.html
Normal file
38
web/html/xui/form/stream/stream_kcp.html
Normal file
@@ -0,0 +1,38 @@
|
||||
{{define "form/streamKCP"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="伪装">
|
||||
<a-select v-model="inbound.stream.kcp.type" style="width: 280px;">
|
||||
<a-select-option value="none">none(not camouflage)</a-select-option>
|
||||
<a-select-option value="srtp">srtp(camouflage video call)</a-select-option>
|
||||
<a-select-option value="utp">utp(camouflage BT download)</a-select-option>
|
||||
<a-select-option value="wechat-video">wechat-video(camouflage WeChat video)</a-select-option>
|
||||
<a-select-option value="dtls">dtls(camouflage DTLS 1.2 packages)</a-select-option>
|
||||
<a-select-option value="wireguard">wireguard(camouflage wireguard packages)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.number="inbound.stream.kcp.seed"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="mtu">
|
||||
<a-input type="number" v-model.number="inbound.stream.kcp.mtu"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="tti (ms)">
|
||||
<a-input type="number" v-model.number="inbound.stream.kcp.tti"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="uplink capacity (MB/S)">
|
||||
<a-input type="number" v-model.number="inbound.stream.kcp.upCap"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="downlink capacity (MB/S)">
|
||||
<a-input type="number" v-model.number="inbound.stream.kcp.downCap"></a-input>
|
||||
</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 size (MB)">
|
||||
<a-input type="number" v-model.number="inbound.stream.kcp.readBuffer"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="write buffer size (MB)">
|
||||
<a-input type="number" v-model.number="inbound.stream.kcp.writeBuffer"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
24
web/html/xui/form/stream/stream_quic.html
Normal file
24
web/html/xui/form/stream/stream_quic.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{{define "form/streamQUIC"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="加密">
|
||||
<a-select v-model="inbound.stream.quic.security" style="width: 165px;">
|
||||
<a-select-option value="none">none</a-select-option>
|
||||
<a-select-option value="aes-128-gcm">aes-128-gcm</a-select-option>
|
||||
<a-select-option value="chacha20-poly1305">chacha20-poly1305</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input v-model.trim="inbound.stream.quic.key"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="伪装">
|
||||
<a-select v-model="inbound.stream.quic.type" style="width: 280px;">
|
||||
<a-select-option value="none">none(not camouflage)</a-select-option>
|
||||
<a-select-option value="srtp">srtp(camouflage video call)</a-select-option>
|
||||
<a-select-option value="utp">utp(camouflage BT download)</a-select-option>
|
||||
<a-select-option value="wechat-video">wechat-video(camouflage WeChat video)</a-select-option>
|
||||
<a-select-option value="dtls">dtls(camouflage DTLS 1.2 packages)</a-select-option>
|
||||
<a-select-option value="wireguard">wireguard(camouflage wireguard packages)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
45
web/html/xui/form/stream/stream_settings.html
Normal file
45
web/html/xui/form/stream/stream_settings.html
Normal file
@@ -0,0 +1,45 @@
|
||||
{{define "form/streamSettings"}}
|
||||
<!-- select stream network -->
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="传输">
|
||||
<a-select v-model="inbound.stream.network" @change="streamNetworkChange">
|
||||
<a-select-option value="tcp">tcp</a-select-option>
|
||||
<a-select-option value="kcp">kcp</a-select-option>
|
||||
<a-select-option value="ws">ws</a-select-option>
|
||||
<a-select-option value="http">http</a-select-option>
|
||||
<a-select-option value="quic">quic</a-select-option>
|
||||
<a-select-option value="grpc">grpc</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- tcp -->
|
||||
<template v-if="inbound.stream.network === 'tcp'">
|
||||
{{template "form/streamTCP"}}
|
||||
</template>
|
||||
|
||||
<!-- kcp -->
|
||||
<template v-if="inbound.stream.network === 'kcp'">
|
||||
{{template "form/streamKCP"}}
|
||||
</template>
|
||||
|
||||
<!-- ws -->
|
||||
<template v-if="inbound.stream.network === 'ws'">
|
||||
{{template "form/streamWS"}}
|
||||
</template>
|
||||
|
||||
<!-- http -->
|
||||
<template v-if="inbound.stream.network === 'http'">
|
||||
{{template "form/streamHTTP"}}
|
||||
</template>
|
||||
|
||||
<!-- quic -->
|
||||
<template v-if="inbound.stream.network === 'quic'">
|
||||
{{template "form/streamQUIC"}}
|
||||
</template>
|
||||
|
||||
<!-- grpc -->
|
||||
<template v-if="inbound.stream.network === 'grpc'">
|
||||
{{template "form/streamGRPC"}}
|
||||
</template>
|
||||
{{end}}
|
||||
83
web/html/xui/form/stream/stream_tcp.html
Normal file
83
web/html/xui/form/stream/stream_tcp.html
Normal file
@@ -0,0 +1,83 @@
|
||||
{{define "form/streamTCP"}}
|
||||
<!-- tcp type -->
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="http 伪装">
|
||||
<a-switch
|
||||
:checked="inbound.stream.tcp.type === 'http'"
|
||||
@change="checked => inbound.stream.tcp.type = checked ? 'http' : 'none'">
|
||||
</a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- tcp request -->
|
||||
<a-form v-if="inbound.stream.tcp.type === 'http'"
|
||||
layout="inline">
|
||||
<a-form-item label="请求版本">
|
||||
<a-input v-model.trim="inbound.stream.tcp.request.version"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求方法">
|
||||
<a-input v-model.trim="inbound.stream.tcp.request.method"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求路径">
|
||||
<a-row v-for="(path, index) in inbound.stream.tcp.request.path">
|
||||
<a-input v-model.trim="inbound.stream.tcp.request.path[index]"></a-input>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求头">
|
||||
<a-row>
|
||||
<a-button size="small"
|
||||
@click="inbound.stream.tcp.request.addHeader('Host', 'xxx.com')">
|
||||
+
|
||||
</a-button>
|
||||
</a-row>
|
||||
<a-input-group v-for="(header, index) in inbound.stream.tcp.request.headers">
|
||||
<a-input style="width: 50%" v-model.trim="header.name"
|
||||
addon-before="名称"></a-input>
|
||||
<a-input style="width: 50%" v-model.trim="header.value"
|
||||
addon-before="值">
|
||||
<template slot="addonAfter">
|
||||
<a-button size="small"
|
||||
@click="inbound.stream.tcp.request.removeHeader(index)">
|
||||
-
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- tcp response -->
|
||||
<a-form v-if="inbound.stream.tcp.type === 'http'"
|
||||
layout="inline">
|
||||
<a-form-item label="响应版本">
|
||||
<a-input v-model.trim="inbound.stream.tcp.response.version"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="响应状态">
|
||||
<a-input v-model.trim="inbound.stream.tcp.response.status"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="响应状态说明">
|
||||
<a-input v-model.trim="inbound.stream.tcp.response.reason"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="响应头">
|
||||
<a-row>
|
||||
<a-button size="small"
|
||||
@click="inbound.stream.tcp.response.addHeader('Content-Type', 'application/octet-stream')">
|
||||
+
|
||||
</a-button>
|
||||
</a-row>
|
||||
<a-input-group v-for="(header, index) in inbound.stream.tcp.response.headers">
|
||||
<a-input style="width: 50%" v-model.trim="header.name"
|
||||
addon-before="名称"></a-input>
|
||||
<a-input style="width: 50%" v-model.trim="header.value"
|
||||
addon-before="值">
|
||||
<template slot="addonAfter">
|
||||
<a-button size="small"
|
||||
@click="inbound.stream.tcp.response.removeHeader(index)">
|
||||
-
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
28
web/html/xui/form/stream/stream_ws.html
Normal file
28
web/html/xui/form/stream/stream_ws.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{{define "form/streamWS"}}
|
||||
<a-form layout="inline">
|
||||
<a-form-item label="路径">
|
||||
<a-input v-model.trim="inbound.stream.ws.path"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求头">
|
||||
<a-row>
|
||||
<a-button size="small"
|
||||
@click="inbound.stream.ws.addHeader('Host', '')">
|
||||
+
|
||||
</a-button>
|
||||
</a-row>
|
||||
<a-input-group v-for="(header, index) in inbound.stream.ws.headers">
|
||||
<a-input style="width: 50%" v-model.trim="header.name"
|
||||
addon-before="名称"></a-input>
|
||||
<a-input style="width: 50%" v-model.trim="header.value"
|
||||
addon-before="值">
|
||||
<template slot="addonAfter">
|
||||
<a-button size="small"
|
||||
@click="inbound.stream.ws.removeHeader(index)">
|
||||
-
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
45
web/html/xui/form/tls_settings.html
Normal file
45
web/html/xui/form/tls_settings.html
Normal file
@@ -0,0 +1,45 @@
|
||||
{{define "form/tlsSettings"}}
|
||||
<!-- tls enable -->
|
||||
<a-form layout="inline" v-if="inbound.canSetTls()">
|
||||
<a-form-item label="tls">
|
||||
<a-switch v-model="inbound.tls">
|
||||
</a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inbound.canEnableXTls()" label="xtls">
|
||||
<a-switch v-model="inbound.xtls"></a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- tls settings -->
|
||||
<a-form v-if="inbound.tls || inbound.xtls"
|
||||
layout="inline">
|
||||
<a-form-item label="域名">
|
||||
<a-input v-model.trim="inbound.stream.tls.server"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="证书">
|
||||
<a-radio-group v-model="inbound.stream.tls.certs[0].useFile"
|
||||
button-style="solid">
|
||||
<a-radio-button :value="true">certificate file path</a-radio-button>
|
||||
<a-radio-button :value="false">certificate file content</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<template v-if="inbound.stream.tls.certs[0].useFile">
|
||||
<a-form-item label="公钥文件路径">
|
||||
<a-input v-model.trim="inbound.stream.tls.certs[0].certFile"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="密钥文件路径">
|
||||
<a-input v-model.trim="inbound.stream.tls.certs[0].keyFile"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-form-item label="公钥内容">
|
||||
<a-input type="textarea" :rows="2"
|
||||
v-model="inbound.stream.tls.certs[0].cert"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="密钥内容">
|
||||
<a-input type="textarea" :rows="2"
|
||||
v-model="inbound.stream.tls.certs[0].key"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-form>
|
||||
{{end}}
|
||||
79
web/html/xui/inbound_modal.html
Normal file
79
web/html/xui/inbound_modal.html
Normal file
@@ -0,0 +1,79 @@
|
||||
{{define "inboundModal"}}
|
||||
<a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" @ok="inModal.ok"
|
||||
:confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false"
|
||||
:ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'>
|
||||
{{template "form/inbound"}}
|
||||
</a-modal>
|
||||
<script>
|
||||
|
||||
const inModal = {
|
||||
title: '',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
okText: '确定',
|
||||
confirm: null,
|
||||
inbound: new Inbound(),
|
||||
dbInbound: new DBInbound(),
|
||||
ok() {
|
||||
ObjectUtil.execute(inModal.confirm, inModal.inbound, inModal.dbInbound);
|
||||
},
|
||||
show({ title='', okText='确定', inbound=null, dbInbound=null, confirm=(inbound, dbInbound)=>{} }) {
|
||||
this.title = title;
|
||||
this.okText = okText;
|
||||
if (inbound) {
|
||||
this.inbound = Inbound.fromJson(inbound.toJson());
|
||||
} else {
|
||||
this.inbound = new Inbound();
|
||||
}
|
||||
if (dbInbound) {
|
||||
this.dbInbound = new DBInbound(dbInbound);
|
||||
} else {
|
||||
this.dbInbound = new DBInbound();
|
||||
}
|
||||
this.confirm = confirm;
|
||||
this.visible = true;
|
||||
},
|
||||
close() {
|
||||
inModal.visible = false;
|
||||
inModal.loading(false);
|
||||
},
|
||||
loading(loading) {
|
||||
inModal.confirmLoading = loading;
|
||||
},
|
||||
};
|
||||
|
||||
const protocols = {
|
||||
VMESS: Protocols.VMESS,
|
||||
VLESS: Protocols.VLESS,
|
||||
TROJAN: Protocols.TROJAN,
|
||||
SHADOWSOCKS: Protocols.SHADOWSOCKS,
|
||||
DOKODEMO: Protocols.DOKODEMO,
|
||||
SOCKS: Protocols.SOCKS,
|
||||
HTTP: Protocols.HTTP,
|
||||
};
|
||||
|
||||
new Vue({
|
||||
delimiters: ['[[', ']]'],
|
||||
el: '#inbound-modal',
|
||||
data: {
|
||||
inModal: inModal,
|
||||
Protocols: protocols,
|
||||
SSMethods: SSMethods,
|
||||
get inbound() {
|
||||
return inModal.inbound;
|
||||
},
|
||||
get dbInbound() {
|
||||
return inModal.dbInbound;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
streamNetworkChange(oldValue) {
|
||||
if (oldValue === 'kcp') {
|
||||
this.inModal.inbound.tls = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
{{end}}
|
||||
@@ -23,12 +23,6 @@
|
||||
</transition>
|
||||
<transition name="list" appear>
|
||||
<a-card hoverable style="margin-bottom: 20px;">
|
||||
<div slot="title">
|
||||
<a-button type="primary" icon="plus" @click="openAddInbound"></a-button>
|
||||
</div>
|
||||
<a-row>
|
||||
<a-input v-model="searchKey" placeholder="search" autofocus></a-input>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :xs="24" :sm="24" :lg="12">
|
||||
upload / download:
|
||||
@@ -51,36 +45,37 @@
|
||||
</transition>
|
||||
<transition name="list" appear>
|
||||
<a-card hoverable>
|
||||
<a-table :columns="columns" :row-key="inbound => inbound.id"
|
||||
<div slot="title">
|
||||
<a-button type="primary" icon="plus" @click="openAddInbound"></a-button>
|
||||
</div>
|
||||
<a-input v-model="searchKey" placeholder="search" autofocus style="max-width: 300px"></a-input>
|
||||
<a-table :columns="columns" :row-key="dbInbound => dbInbound.id"
|
||||
:data-source="dbInbounds"
|
||||
:loading="spinning" :scroll="{ x: 1500 }"
|
||||
:pagination="false"
|
||||
style="margin-top: 20px"
|
||||
@change="() => getDBInbounds()">
|
||||
<template slot="protocol" slot-scope="text, inbound">
|
||||
<a-tag color="blue">[[ inbound.protocol ]]</a-tag>
|
||||
<template slot="protocol" slot-scope="text, dbInbound">
|
||||
<a-tag color="blue">[[ dbInbound.protocol ]]</a-tag>
|
||||
</template>
|
||||
<template slot="settings" slot-scope="text, inbound">
|
||||
<template slot="settings" slot-scope="text, dbInbound">
|
||||
<a-button type="link">查看</a-button>
|
||||
</template>
|
||||
<template slot="streamSettings" slot-scope="text, inbound">
|
||||
<template slot="streamSettings" slot-scope="text, dbInbound">
|
||||
<a-button type="link">查看</a-button>
|
||||
</template>
|
||||
<template slot="enable" slot-scope="text, inbound">
|
||||
<a-tag v-if="inbound.enable" color="green">启用</a-tag>
|
||||
<template slot="enable" slot-scope="text, dbInbound">
|
||||
<a-tag v-if="dbInbound.enable" color="green">启用</a-tag>
|
||||
<a-tag v-else color="red">禁用</a-tag>
|
||||
</template>
|
||||
<template slot="expiryTime" slot-scope="text, inbound">
|
||||
<span v-if="inbound.expiryTime > 0" color="red">[[ DateUtil.formatMillis(inbound.expiryTime) ]]</span>
|
||||
<template slot="expiryTime" slot-scope="text, dbInbound">
|
||||
<span v-if="dbInbound.expiryTime > 0" color="red">[[ DateUtil.formatMillis(dbInbound.expiryTime) ]]</span>
|
||||
<span v-else>无限期</span>
|
||||
</template>
|
||||
<template slot="action" slot-scope="text, inbound">
|
||||
<a-button type="primary" icon="qrcode"></a-button>
|
||||
<a-button type="primary" icon="edit"></a-button>
|
||||
<a-button type="danger" icon="delete" @click="delInbound(inbound)"></a-button>
|
||||
</template>
|
||||
|
||||
<template slot="expandedRowRender" slot-scope="inbound" style="margin: 0">
|
||||
[[ inbound.id ]]
|
||||
<template slot="action" slot-scope="text, dbInbound">
|
||||
<a-button v-if="dbInbound.hasLink()" type="primary" icon="qrcode" @click="showQrcode(dbInbound)"></a-button>
|
||||
<a-button type="primary" icon="edit" @click="openEditInbound(dbInbound)"></a-button>
|
||||
<a-button type="danger" icon="delete" @click="delInbound(dbInbound)"></a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
@@ -147,7 +142,6 @@
|
||||
loading(spinning=true) {
|
||||
this.spinning = spinning;
|
||||
},
|
||||
empDefault(o, defaultValue='') {return ObjectUtil.isEmpty(o) ? defaultValue : o},
|
||||
async getDBInbounds() {
|
||||
this.loading();
|
||||
const msg = await HttpUtil.post('/xui/inbounds');
|
||||
@@ -179,60 +173,72 @@
|
||||
inModal.show({
|
||||
title: 'add account',
|
||||
okText: 'add',
|
||||
confirm: async () => {
|
||||
confirm: async (inbound, dbInbound) => {
|
||||
inModal.loading();
|
||||
await this.addInbound(inModal.inbound);
|
||||
inModal.closeLoading();
|
||||
await this.addInbound(inbound, dbInbound);
|
||||
inModal.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
openEditInbound(inbound) {
|
||||
openEditInbound(dbInbound) {
|
||||
const inbound = dbInbound.toInbound();
|
||||
inModal.show({
|
||||
title: 'update account',
|
||||
okText: 'update',
|
||||
inbound: inbound,
|
||||
confirm: async () => {
|
||||
dbInbound: dbInbound,
|
||||
confirm: async (inbound, dbInbound) => {
|
||||
inModal.loading();
|
||||
inModal.inbound.id = inbound.id;
|
||||
await this.updateInbound(inModal.inbound);
|
||||
inModal.closeLoading();
|
||||
await this.updateInbound(inbound, dbInbound);
|
||||
inModal.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
async addInbound(inbound) {
|
||||
let data = {
|
||||
port: inbound.port,
|
||||
async addInbound(inbound, dbInbound) {
|
||||
const data = {
|
||||
remark: dbInbound.remark,
|
||||
enable: dbInbound.enable,
|
||||
|
||||
listen: inbound.listen,
|
||||
port: inbound.port,
|
||||
protocol: inbound.protocol,
|
||||
settings: inbound.settings.toString(false),
|
||||
stream_settings: inbound.stream.toString(false),
|
||||
sniffing: [Protocols.VMESS, Protocols.VLESS, Protocols.SHADOWSOCKS].indexOf(inbound.protocol) >= 0 ? inbound.sniffing.toString(false) : '{}',
|
||||
remark: inbound.remark,
|
||||
settings: inbound.settings.toString(),
|
||||
stream_settings: inbound.stream.toString(),
|
||||
sniffing: inbound.canSniffing() ? inbound.sniffing.toString() : '{}',
|
||||
};
|
||||
await this.submit('/xui/inbound/add', data, inModal);
|
||||
},
|
||||
async updateInbound(inbound) {
|
||||
async updateInbound(inbound, dbInbound) {
|
||||
const data = {
|
||||
port: inbound.port,
|
||||
remark: dbInbound.remark,
|
||||
enable: dbInbound.enable,
|
||||
|
||||
listen: inbound.listen,
|
||||
port: inbound.port,
|
||||
protocol: inbound.protocol,
|
||||
settings: inbound.settings.toString(false),
|
||||
stream_settings: inbound.stream.toString(false),
|
||||
sniffing: [Protocols.VMESS, Protocols.VLESS, Protocols.SHADOWSOCKS].indexOf(inbound.protocol) >= 0 ? inbound.sniffing.toString(false) : '{}',
|
||||
remark: inbound.remark,
|
||||
enable: inbound.enable,
|
||||
settings: inbound.settings.toString(),
|
||||
stream_settings: inbound.stream.toString(),
|
||||
sniffing: inbound.canSniffing() ? inbound.sniffing.toString() : '{}',
|
||||
};
|
||||
await this.submit(`/xui/inbound/update/${inbound.id}`, data, inModal);
|
||||
await this.submit(`/xui/inbound/update/${dbInbound.id}`, data, inModal);
|
||||
},
|
||||
delInbound(inbound) {
|
||||
delInbound(dbInbound) {
|
||||
this.$confirm({
|
||||
title: 'delete account',
|
||||
content: 'Cannot be restored after deletion, confirm deletion?',
|
||||
okText: 'delete',
|
||||
cancelText: 'cancel',
|
||||
onOk: () => this.submit('/xui/inbound/del/' + inbound.id),
|
||||
onOk: () => this.submit('/xui/inbound/del/' + dbInbound.id),
|
||||
});
|
||||
},
|
||||
showQrcode(dbInbound) {
|
||||
let address = location.hostname;
|
||||
if (!ObjectUtil.isEmpty(dbInbound.listen) || dbInbound.listen !== "0.0.0.0") {
|
||||
address = dbInbound.listen;
|
||||
}
|
||||
const link = dbInbound.genLink(address);
|
||||
qrModal.show('二维码', link);
|
||||
},
|
||||
resetTraffic(inbound) {
|
||||
this.submit(`/xui/reset_traffic/${inbound.id}`);
|
||||
},
|
||||
@@ -244,14 +250,10 @@
|
||||
this.submit(`/xui/inbound/update/${inbound.id}`, data);
|
||||
},
|
||||
async submit(url, data, modal) {
|
||||
const msg = await HttpUtil.post(url, data);
|
||||
const msg = await HttpUtil.postWithModal(url, data, modal);
|
||||
if (msg.success) {
|
||||
this.getDBInbounds();
|
||||
if (modal != null) {
|
||||
modal.close();
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
Reference in New Issue
Block a user