mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-19 07:15:48 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e3c7b1db6 | ||
|
|
ab6c6c0ca6 | ||
|
|
9c0890dd9b | ||
|
|
eee0503200 | ||
|
|
f3c539dd73 | ||
|
|
c0464f1d97 | ||
|
|
b87474d70c | ||
|
|
063309dbb7 | ||
|
|
294b680972 | ||
|
|
f55478422b | ||
|
|
619e0c69cd | ||
|
|
da5dc3a04f |
@@ -1 +1 @@
|
|||||||
1.5.2
|
1.5.3
|
||||||
6
go.mod
6
go.mod
@@ -12,10 +12,10 @@ require (
|
|||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/pelletier/go-toml/v2 v2.0.9
|
github.com/pelletier/go-toml/v2 v2.0.9
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/shirou/gopsutil/v3 v3.23.6
|
github.com/shirou/gopsutil/v3 v3.23.7
|
||||||
github.com/xtls/xray-core v1.8.3
|
github.com/xtls/xray-core v1.8.3
|
||||||
go.uber.org/atomic v1.11.0
|
go.uber.org/atomic v1.11.0
|
||||||
golang.org/x/text v0.11.0
|
golang.org/x/text v0.12.0
|
||||||
google.golang.org/grpc v1.57.0
|
google.golang.org/grpc v1.57.0
|
||||||
gorm.io/driver/sqlite v1.5.2
|
gorm.io/driver/sqlite v1.5.2
|
||||||
gorm.io/gorm v1.25.2
|
gorm.io/gorm v1.25.2
|
||||||
@@ -80,7 +80,7 @@ require (
|
|||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||||
golang.org/x/mod v0.11.0 // indirect
|
golang.org/x/mod v0.11.0 // indirect
|
||||||
golang.org/x/net v0.11.0 // indirect
|
golang.org/x/net v0.11.0 // indirect
|
||||||
golang.org/x/sys v0.9.0 // indirect
|
golang.org/x/sys v0.10.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
golang.org/x/tools v0.10.0 // indirect
|
golang.org/x/tools v0.10.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||||
|
|||||||
12
go.sum
12
go.sum
@@ -220,8 +220,8 @@ github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:eu
|
|||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08=
|
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
|
||||||
github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU=
|
github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4=
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||||
@@ -366,8 +366,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -376,8 +376,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
|
|||||||
@@ -113,7 +113,6 @@ config_after_install() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_x-ui() {
|
install_x-ui() {
|
||||||
systemctl stop x-ui
|
|
||||||
cd /usr/local/
|
cd /usr/local/
|
||||||
|
|
||||||
if [ $# == 0 ]; then
|
if [ $# == 0 ]; then
|
||||||
@@ -140,6 +139,7 @@ install_x-ui() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -e /usr/local/x-ui/ ]]; then
|
if [[ -e /usr/local/x-ui/ ]]; then
|
||||||
|
systemctl stop x-ui
|
||||||
rm /usr/local/x-ui/ -rf
|
rm /usr/local/x-ui/ -rf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -1279,8 +1279,8 @@ class Inbound extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let password = new Array();
|
let password = new Array();
|
||||||
if (this.isSSMultiUser) password.push(settings.shadowsockses[clientIndex].password);
|
|
||||||
if (this.isSS2022) password.push(settings.password);
|
if (this.isSS2022) password.push(settings.password);
|
||||||
|
if (this.isSSMultiUser) password.push(settings.shadowsockses[clientIndex].password);
|
||||||
|
|
||||||
let link = `ss://${safeBase64(settings.method + ':' + password.join(':'))}@${address}:${this.port}`;
|
let link = `ss://${safeBase64(settings.method + ':' + password.join(':'))}@${address}:${this.port}`;
|
||||||
const url = new URL(link);
|
const url = new URL(link);
|
||||||
|
|||||||
@@ -1,22 +1,19 @@
|
|||||||
{{define "form/http"}}
|
{{define "form/http"}}
|
||||||
<a-form layout="inline">
|
<a-form layout="inline">
|
||||||
<table width="100%" class="ant-table-tbody">
|
<a-form-item>
|
||||||
<tr>
|
<a-row>
|
||||||
<td>{{ i18n "username"}}</td>
|
<a-button size="small" @click="inbound.settings.addAccount(new Inbound.SocksSettings.SocksAccount())">+</a-button>
|
||||||
<td>
|
</a-row>
|
||||||
<a-form-item>
|
<a-input-group v-for="(account, index) in inbound.settings.accounts">
|
||||||
<a-input v-model.trim="inbound.settings.accounts[0].user"></a-input>
|
<a-input style="width: 45%" v-model.trim="account.user"
|
||||||
</a-form-item>
|
addon-before='{{ i18n "username" }}'></a-input>
|
||||||
</td>
|
<a-input style="width: 55%" v-model.trim="account.pass"
|
||||||
</tr>
|
addon-before='{{ i18n "password" }}'>
|
||||||
<tr>
|
<template slot="addonAfter">
|
||||||
<td>{{ i18n "password" }}</td>
|
<a-button size="small" @click="inbound.settings.delAccount(index)">-</a-button>
|
||||||
<td>
|
</template>
|
||||||
<a-form-item>
|
</a-input>
|
||||||
<a-input v-model.trim="inbound.settings.accounts[0].pass"></a-input>
|
</a-input-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</a-form>
|
</a-form>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -10,24 +10,25 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<template v-if="inbound.settings.auth === 'password'">
|
<tr v-if="inbound.settings.auth === 'password'">
|
||||||
<tr>
|
<td colspan="2">
|
||||||
<td>{{ i18n "username" }}</td>
|
|
||||||
<td>
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-input v-model.trim="inbound.settings.accounts[0].user"></a-input>
|
<a-row>
|
||||||
|
<a-button size="small" @click="inbound.settings.addAccount(new Inbound.SocksSettings.SocksAccount())">+</a-button>
|
||||||
|
</a-row>
|
||||||
|
<a-input-group v-for="(account, index) in inbound.settings.accounts">
|
||||||
|
<a-input style="width: 45%" v-model.trim="account.user"
|
||||||
|
addon-before='{{ i18n "username" }}'></a-input>
|
||||||
|
<a-input style="width: 55%" v-model.trim="account.pass"
|
||||||
|
addon-before='{{ i18n "password" }}'>
|
||||||
|
<template slot="addonAfter">
|
||||||
|
<a-button size="small" @click="inbound.settings.delAccount(index)">-</a-button>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-input-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>{{ i18n "password" }}</td>
|
|
||||||
<td>
|
|
||||||
<a-form-item>
|
|
||||||
<a-input v-model.trim="inbound.settings.accounts[0].pass"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</template>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ i18n "pages.inbounds.enable" }} udp</td>
|
<td>{{ i18n "pages.inbounds.enable" }} udp</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -36,10 +37,10 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr v-if="inbound.settings.udp">
|
||||||
<td>IP</td>
|
<td>IP</td>
|
||||||
<td>
|
<td>
|
||||||
<a-form-item v-if="inbound.settings.udp">
|
<a-form-item>
|
||||||
<a-input v-model.trim="inbound.settings.ip"></a-input>
|
<a-input v-model.trim="inbound.settings.ip"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -45,17 +45,28 @@
|
|||||||
</template>
|
</template>
|
||||||
</table>
|
</table>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr colspan="2" v-if="dbInbound.hasLink()">
|
<tr colspan="2" v-if="dbInbound.hasLink()">
|
||||||
<td v-if="inbound.tls">
|
<td v-if="inbound.tls">
|
||||||
tls: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br />
|
tls: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br />
|
||||||
tls {{ i18n "domainName" }}: <a-tag :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag>
|
tls {{ i18n "domainName" }}: <a-tag :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag>
|
||||||
</td>
|
|
||||||
<td v-else-if="inbound.reality">
|
|
||||||
reality: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br />
|
|
||||||
reality Destination: <a-tag :color="inbound.stream.reality.dest ? 'green' : 'orange'">[[ inbound.stream.reality.dest ]]</a-tag>
|
|
||||||
</td>
|
|
||||||
<td v-else>tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag>
|
|
||||||
</td>
|
</td>
|
||||||
|
<td v-else-if="inbound.reality">
|
||||||
|
reality: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br />
|
||||||
|
reality Destination: <a-tag :color="inbound.stream.reality.dest ? 'green' : 'orange'">[[ inbound.stream.reality.dest ]]</a-tag>
|
||||||
|
</td>
|
||||||
|
<td v-else>tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table v-if="dbInbound.isSS" style="margin-bottom: 10px; width: 100%;">
|
||||||
|
<tr>
|
||||||
|
<td>{{ i18n "encryption" }}</td>
|
||||||
|
<td><a-tag color="green">[[ inbound.settings.method ]]</a-tag></td>
|
||||||
|
</tr><tr v-if="inbound.isSS2022">
|
||||||
|
<td>{{ i18n "password" }}</td>
|
||||||
|
<td><a-tag color="blue">[[ inbound.settings.password ]]</a-tag></td>
|
||||||
|
</tr><tr>
|
||||||
|
<td>{{ i18n "pages.inbounds.network" }}</td>
|
||||||
|
<td><a-tag color="green">[[ inbound.settings.network ]]</a-tag></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<template v-if="infoModal.clientSettings">
|
<template v-if="infoModal.clientSettings">
|
||||||
@@ -163,19 +174,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a-divider></a-divider>
|
<template v-if="dbInbound.isSS && !inbound.isSSMultiUser">
|
||||||
<table v-if="inbound.protocol == Protocols.SHADOWSOCKS" style="margin-bottom: 10px; width: 100%;">
|
|
||||||
<tr>
|
|
||||||
<th>{{ i18n "encryption" }}</th>
|
|
||||||
<th>{{ i18n "password" }}</th>
|
|
||||||
<th>{{ i18n "pages.inbounds.network" }}</th>
|
|
||||||
</tr><tr>
|
|
||||||
<td><a-tag color="green">[[ inbound.settings.method ]]</a-tag></td>
|
|
||||||
<td><a-tag color="blue">[[ inbound.settings.password ]]</a-tag></td>
|
|
||||||
<td><a-tag color="green">[[ inbound.settings.network ]]</a-tag></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<template v-if="inbound.protocol == Protocols.SHADOWSOCKS && !inbound.isSSMultiUser">
|
|
||||||
<a-divider>URL</a-divider>
|
<a-divider>URL</a-divider>
|
||||||
<a-row v-for="(link,index) in infoModal.links">
|
<a-row v-for="(link,index) in infoModal.links">
|
||||||
<a-col :span="22"><a-tag color="cyan">[[ link.remark ]]</a-tag><br />[[ link.link ]]</a-col>
|
<a-col :span="22"><a-tag color="cyan">[[ link.remark ]]</a-tag><br />[[ link.link ]]</a-col>
|
||||||
@@ -201,17 +200,19 @@
|
|||||||
<td><a-tag color="blue">[[ inbound.settings.followRedirect ]]</a-tag></td>
|
<td><a-tag color="blue">[[ inbound.settings.followRedirect ]]</a-tag></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</table>
|
<table v-if="dbInbound.isSocks" style="margin-bottom: 10px; width: 100%;">
|
||||||
<table v-if="inbound.protocol == Protocols.SOCKS" style="margin-bottom: 10px; width: 100%;">
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ i18n "password" }} Auth</th>
|
<th>{{ i18n "password" }} Auth</th>
|
||||||
<th>{{ i18n "pages.inbounds.enable" }} udp</th>
|
<th>{{ i18n "pages.inbounds.enable" }} udp</th>
|
||||||
<th>IP</th>
|
<th>IP</th>
|
||||||
</tr><tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
<td><a-tag color="green">[[ inbound.settings.auth ]]</a-tag></td>
|
<td><a-tag color="green">[[ inbound.settings.auth ]]</a-tag></td>
|
||||||
<td><a-tag color="blue">[[ inbound.settings.udp]]</a-tag></td>
|
<td><a-tag color="blue">[[ inbound.settings.udp]]</a-tag></td>
|
||||||
<td><a-tag color="green">[[ inbound.settings.ip ]]</a-tag></td>
|
<td><a-tag color="green">[[ inbound.settings.ip ]]</a-tag></td>
|
||||||
</tr><tr v-if="inbound.settings.auth == 'password'">
|
</tr>
|
||||||
|
<template v-if="inbound.settings.auth == 'password'">
|
||||||
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td>{{ i18n "username" }}</td>
|
<td>{{ i18n "username" }}</td>
|
||||||
<td>{{ i18n "password" }}</td>
|
<td>{{ i18n "password" }}</td>
|
||||||
@@ -220,9 +221,9 @@
|
|||||||
<td><a-tag color="blue">[[ account.user ]]</a-tag></td>
|
<td><a-tag color="blue">[[ account.user ]]</a-tag></td>
|
||||||
<td><a-tag color="green">[[ account.pass ]]</a-tag></td>
|
<td><a-tag color="green">[[ account.pass ]]</a-tag></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</template>
|
||||||
</table>
|
</table>
|
||||||
</table>
|
<table v-if="dbInbound.isHTTP" style="margin-bottom: 10px; width: 100%;">
|
||||||
<table v-if="inbound.protocol == Protocols.HTTP" style="margin-bottom: 10px; width: 100%;">
|
|
||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th>{{ i18n "username" }}</th>
|
<th>{{ i18n "username" }}</th>
|
||||||
@@ -233,7 +234,6 @@
|
|||||||
<td><a-tag color="green">[[ account.pass ]]</a-tag></td>
|
<td><a-tag color="green">[[ account.pass ]]</a-tag></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</table>
|
|
||||||
</template>
|
</template>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
.ant-col-sm-24 {
|
.ant-col-sm-24 {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
tr.hideExpandIcon .ant-table-row-expand-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -121,8 +124,12 @@
|
|||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
<a-table :columns="columns" :row-key="dbInbound => dbInbound.id"
|
<a-table :columns="columns" :row-key="dbInbound => dbInbound.id"
|
||||||
:data-source="searchedInbounds"
|
:data-source="searchedInbounds"
|
||||||
:loading="spinning" :scroll="{ x: 1300 }"
|
:loading="spinning" :scroll="{ x: 1200 }"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
|
:expand-icon-as-cell="false"
|
||||||
|
:expand-row-by-click="false"
|
||||||
|
:expand-icon-column-index="0"
|
||||||
|
:row-class-name="dbInbound => (dbInbound.isTrojan || dbInbound.isVLess || dbInbound.isVMess || (dbInbound.isSS && dbInbound.toInbound().isSSMultiUser) ? '' : 'hideExpandIcon')"
|
||||||
style="margin-top: 20px"
|
style="margin-top: 20px"
|
||||||
@change="() => getDBInbounds()">
|
@change="() => getDBInbounds()">
|
||||||
<template slot="action" slot-scope="text, dbInbound">
|
<template slot="action" slot-scope="text, dbInbound">
|
||||||
@@ -137,7 +144,7 @@
|
|||||||
<a-icon type="qrcode"></a-icon>
|
<a-icon type="qrcode"></a-icon>
|
||||||
{{ i18n "qrCode" }}
|
{{ i18n "qrCode" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<template v-if="dbInbound.isTrojan || dbInbound.isVLess || dbInbound.isVMess || dbInbound.toInbound().isSSMultiUser">
|
<template v-if="dbInbound.isTrojan || dbInbound.isVLess || dbInbound.isVMess || (dbInbound.isSS && dbInbound.toInbound().isSSMultiUser)">
|
||||||
<a-menu-item key="addClient">
|
<a-menu-item key="addClient">
|
||||||
<a-icon type="user-add"></a-icon>
|
<a-icon type="user-add"></a-icon>
|
||||||
{{ i18n "pages.client.add"}}
|
{{ i18n "pages.client.add"}}
|
||||||
@@ -254,6 +261,7 @@
|
|||||||
:columns="innerColumns"
|
:columns="innerColumns"
|
||||||
:data-source="getInboundClients(record)"
|
:data-source="getInboundClients(record)"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
|
style="margin-left: 20px;"
|
||||||
>
|
>
|
||||||
{{template "client_table"}}
|
{{template "client_table"}}
|
||||||
</a-table>
|
</a-table>
|
||||||
@@ -263,6 +271,7 @@
|
|||||||
:columns="innerTrojanColumns"
|
:columns="innerTrojanColumns"
|
||||||
:data-source="getInboundClients(record)"
|
:data-source="getInboundClients(record)"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
|
style="margin-left: 20px;"
|
||||||
>
|
>
|
||||||
{{template "client_table"}}
|
{{template "client_table"}}
|
||||||
</a-table>
|
</a-table>
|
||||||
@@ -278,6 +287,11 @@
|
|||||||
{{template "component/themeSwitcher" .}}
|
{{template "component/themeSwitcher" .}}
|
||||||
<script>
|
<script>
|
||||||
const columns = [{
|
const columns = [{
|
||||||
|
title: "ID",
|
||||||
|
align: 'right',
|
||||||
|
dataIndex: "id",
|
||||||
|
width: 30,
|
||||||
|
}, {
|
||||||
title: '{{ i18n "pages.inbounds.operate" }}',
|
title: '{{ i18n "pages.inbounds.operate" }}',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 30,
|
width: 30,
|
||||||
@@ -287,11 +301,6 @@
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
width: 30,
|
width: 30,
|
||||||
scopedSlots: { customRender: 'enable' },
|
scopedSlots: { customRender: 'enable' },
|
||||||
}, {
|
|
||||||
title: "ID",
|
|
||||||
align: 'center',
|
|
||||||
dataIndex: "id",
|
|
||||||
width: 20,
|
|
||||||
}, {
|
}, {
|
||||||
title: '{{ i18n "pages.inbounds.remark" }}',
|
title: '{{ i18n "pages.inbounds.remark" }}',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
@@ -328,8 +337,8 @@
|
|||||||
{ title: '{{ i18n "pages.inbounds.operate" }}', width: 70, scopedSlots: { customRender: 'actions' } },
|
{ title: '{{ i18n "pages.inbounds.operate" }}', width: 70, scopedSlots: { customRender: 'actions' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.enable" }}', width: 30, scopedSlots: { customRender: 'enable' } },
|
{ title: '{{ i18n "pages.inbounds.enable" }}', width: 30, scopedSlots: { customRender: 'enable' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
|
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 50, scopedSlots: { customRender: 'traffic' } },
|
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 60, scopedSlots: { customRender: 'traffic' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 50, scopedSlots: { customRender: 'expiryTime' } },
|
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 55, scopedSlots: { customRender: 'expiryTime' } },
|
||||||
{ title: 'UUID', width: 120, dataIndex: "id" },
|
{ title: 'UUID', width: 120, dataIndex: "id" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -338,8 +347,8 @@
|
|||||||
{ title: '{{ i18n "pages.inbounds.enable" }}', width: 30, scopedSlots: { customRender: 'enable' } },
|
{ title: '{{ i18n "pages.inbounds.enable" }}', width: 30, scopedSlots: { customRender: 'enable' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
|
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 50, scopedSlots: { customRender: 'traffic' } },
|
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 50, scopedSlots: { customRender: 'traffic' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 50, scopedSlots: { customRender: 'expiryTime' } },
|
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 55, scopedSlots: { customRender: 'expiryTime' } },
|
||||||
{ title: 'Password', width: 120, dataIndex: "password" },
|
{ title: '{{ i18n "password" }}', width: 165, dataIndex: "password" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
:stroke-color="status.cpu.color"
|
:stroke-color="status.cpu.color"
|
||||||
:class="themeSwitcher.darkCardClass"
|
:class="themeSwitcher.darkCardClass"
|
||||||
:percent="status.cpu.percent"></a-progress>
|
:percent="status.cpu.percent"></a-progress>
|
||||||
<div>CPU</div>
|
<div>CPU ([[ status.cpuCount ]]core)</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12" style="text-align: center">
|
<a-col :span="12" style="text-align: center">
|
||||||
<a-progress type="dashboard" status="normal"
|
<a-progress type="dashboard" status="normal"
|
||||||
@@ -92,13 +92,16 @@
|
|||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
||||||
{{ i18n "pages.index.operationHours" }}:
|
{{ i18n "pages.index.operationHours" }}:
|
||||||
<a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag>
|
xray
|
||||||
|
<a-tag color="green">[[ formatSecond(status.appStats.uptime) ]]</a-tag>
|
||||||
|
os
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.operationHoursDesc" }}
|
{{ i18n "pages.index.operationHoursDesc" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
<a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
@@ -131,7 +134,36 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
||||||
tcp / udp {{ i18n "pages.index.connectionCount" }}: [[ status.tcpCount ]] / [[ status.udpCount ]]
|
{{ i18n "usage"}}:
|
||||||
|
Memory [[ sizeFormat(status.appStats.mem) ]] -
|
||||||
|
Threads [[ status.appStats.threads ]]
|
||||||
|
</a-tooltip>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :sm="24" :md="12">
|
||||||
|
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
||||||
|
Host: [[ status.hostInfo.hostname ]] -
|
||||||
|
<template v-if="status.hostInfo.ipv4">IPv4:
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
[[ status.hostInfo.ipv4 ]]
|
||||||
|
</template>
|
||||||
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<template v-if="status.hostInfo.ipv6">IPv6:
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
[[ status.hostInfo.ipv6 ]]
|
||||||
|
</template>
|
||||||
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :sm="24" :md="12">
|
||||||
|
<a-card hoverable :class="themeSwitcher.darkCardClass">
|
||||||
|
{{ i18n "pages.index.connectionCount" }}: tcp: [[ status.tcpCount ]] udp: [[ status.udpCount ]]
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.connectionCountDesc" }}
|
{{ i18n "pages.index.connectionCountDesc" }}
|
||||||
@@ -315,6 +347,7 @@
|
|||||||
class Status {
|
class Status {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
this.cpu = new CurTotal(0, 0);
|
this.cpu = new CurTotal(0, 0);
|
||||||
|
this.cpuCount = 0;
|
||||||
this.disk = new CurTotal(0, 0);
|
this.disk = new CurTotal(0, 0);
|
||||||
this.loads = [0, 0, 0];
|
this.loads = [0, 0, 0];
|
||||||
this.mem = new CurTotal(0, 0);
|
this.mem = new CurTotal(0, 0);
|
||||||
@@ -324,12 +357,16 @@
|
|||||||
this.tcpCount = 0;
|
this.tcpCount = 0;
|
||||||
this.udpCount = 0;
|
this.udpCount = 0;
|
||||||
this.uptime = 0;
|
this.uptime = 0;
|
||||||
|
this.appUptime = 0;
|
||||||
|
this.appStats = {threads: 0, mem: 0, uptime: 0};
|
||||||
|
this.hostInfo = {hostname:"", ipv4: "", ipv6: ""};
|
||||||
this.xray = {state: State.Stop, errorMsg: "", version: "", color: ""};
|
this.xray = {state: State.Stop, errorMsg: "", version: "", color: ""};
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.cpu = new CurTotal(data.cpu, 100);
|
this.cpu = new CurTotal(data.cpu, 100);
|
||||||
|
this.cpuCount = data.cpuCount;
|
||||||
this.disk = new CurTotal(data.disk.current, data.disk.total);
|
this.disk = new CurTotal(data.disk.current, data.disk.total);
|
||||||
this.loads = data.loads.map(load => toFixed(load, 2));
|
this.loads = data.loads.map(load => toFixed(load, 2));
|
||||||
this.mem = new CurTotal(data.mem.current, data.mem.total);
|
this.mem = new CurTotal(data.mem.current, data.mem.total);
|
||||||
@@ -339,6 +376,9 @@
|
|||||||
this.tcpCount = data.tcpCount;
|
this.tcpCount = data.tcpCount;
|
||||||
this.udpCount = data.udpCount;
|
this.udpCount = data.udpCount;
|
||||||
this.uptime = data.uptime;
|
this.uptime = data.uptime;
|
||||||
|
this.appUptime = data.appUptime;
|
||||||
|
this.appStats = data.appStats;
|
||||||
|
this.hostInfo = data.hostInfo;
|
||||||
this.xray = data.xray;
|
this.xray = data.xray;
|
||||||
switch (this.xray.state) {
|
switch (this.xray.state) {
|
||||||
case State.Running:
|
case State.Running:
|
||||||
|
|||||||
@@ -39,9 +39,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
T time.Time `json:"-"`
|
T time.Time `json:"-"`
|
||||||
Cpu float64 `json:"cpu"`
|
Cpu float64 `json:"cpu"`
|
||||||
Mem struct {
|
CpuCount int `json:"cpuCount"`
|
||||||
|
Mem struct {
|
||||||
Current uint64 `json:"current"`
|
Current uint64 `json:"current"`
|
||||||
Total uint64 `json:"total"`
|
Total uint64 `json:"total"`
|
||||||
} `json:"mem"`
|
} `json:"mem"`
|
||||||
@@ -70,6 +71,16 @@ type Status struct {
|
|||||||
Sent uint64 `json:"sent"`
|
Sent uint64 `json:"sent"`
|
||||||
Recv uint64 `json:"recv"`
|
Recv uint64 `json:"recv"`
|
||||||
} `json:"netTraffic"`
|
} `json:"netTraffic"`
|
||||||
|
AppStats struct {
|
||||||
|
Threads uint32 `json:"threads"`
|
||||||
|
Mem uint64 `json:"mem"`
|
||||||
|
Uptime uint64 `json:"uptime"`
|
||||||
|
} `json:"appStats"`
|
||||||
|
HostInfo struct {
|
||||||
|
HostName string `json:"hostname"`
|
||||||
|
Ipv4 string `json:"ipv4"`
|
||||||
|
Ipv6 string `json:"ipv6"`
|
||||||
|
} `json:"hostInfo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Release struct {
|
type Release struct {
|
||||||
@@ -176,6 +187,36 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status {
|
|||||||
}
|
}
|
||||||
status.Xray.Version = s.xrayService.GetXrayVersion()
|
status.Xray.Version = s.xrayService.GetXrayVersion()
|
||||||
|
|
||||||
|
var rtm runtime.MemStats
|
||||||
|
runtime.ReadMemStats(&rtm)
|
||||||
|
|
||||||
|
status.AppStats.Mem = rtm.Sys
|
||||||
|
status.AppStats.Threads = uint32(runtime.NumGoroutine())
|
||||||
|
status.CpuCount = runtime.NumCPU()
|
||||||
|
if p.IsRunning() {
|
||||||
|
status.AppStats.Uptime = p.GetUptime()
|
||||||
|
} else {
|
||||||
|
status.AppStats.Uptime = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
status.HostInfo.HostName, _ = os.Hostname()
|
||||||
|
|
||||||
|
// get ip address
|
||||||
|
netInterfaces, _ := net.Interfaces()
|
||||||
|
for i := 0; i < len(netInterfaces); i++ {
|
||||||
|
if len(netInterfaces[i].Flags) > 2 && netInterfaces[i].Flags[0] == "up" && netInterfaces[i].Flags[1] != "loopback" {
|
||||||
|
addrs := netInterfaces[i].Addrs
|
||||||
|
|
||||||
|
for _, address := range addrs {
|
||||||
|
if strings.Contains(address.Addr, ".") {
|
||||||
|
status.HostInfo.Ipv4 += address.Addr + " "
|
||||||
|
} else if address.Addr[0:6] != "fe80::" {
|
||||||
|
status.HostInfo.Ipv6 += address.Addr + " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
154
x-ui.sh
154
x-ui.sh
@@ -403,7 +403,139 @@ show_xray_status() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_acme() {
|
||||||
|
cd ~
|
||||||
|
LOGI "install acme..."
|
||||||
|
curl https://get.acme.sh | sh
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
LOGE "install acme failed"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
LOGI "install acme succeed"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_cert_issue_main() {
|
||||||
|
echo -e "${green}\t1.${plain} Get SSL"
|
||||||
|
echo -e "${green}\t2.${plain} Revoke"
|
||||||
|
echo -e "${green}\t3.${plain} Force Renew"
|
||||||
|
read -p "Choose an option: " choice
|
||||||
|
case "$choice" in
|
||||||
|
1) ssl_cert_issue ;;
|
||||||
|
2)
|
||||||
|
local domain=""
|
||||||
|
read -p "Please enter your domain name to revoke the certificate: " domain
|
||||||
|
~/.acme.sh/acme.sh --revoke -d ${domain}
|
||||||
|
LOGI "Certificate revoked"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
local domain=""
|
||||||
|
read -p "Please enter your domain name to forcefully renew an SSL certificate: " domain
|
||||||
|
~/.acme.sh/acme.sh --renew -d ${domain} --force ;;
|
||||||
|
*) echo "Invalid choice" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
ssl_cert_issue() {
|
ssl_cert_issue() {
|
||||||
|
# check for acme.sh first
|
||||||
|
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
|
||||||
|
echo "acme.sh could not be found. we will install it"
|
||||||
|
install_acme
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
LOGE "install acme failed, please check logs"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# install socat second
|
||||||
|
case "${release}" in
|
||||||
|
ubuntu|debian)
|
||||||
|
apt update && apt install socat -y ;;
|
||||||
|
centos)
|
||||||
|
yum -y update && yum -y install socat ;;
|
||||||
|
fedora)
|
||||||
|
dnf -y update && dnf -y install socat ;;
|
||||||
|
*)
|
||||||
|
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
|
||||||
|
exit 1 ;;
|
||||||
|
esac
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
LOGE "install socat failed, please check logs"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
LOGI "install socat succeed..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# get the domain here,and we need verify it
|
||||||
|
local domain=""
|
||||||
|
read -p "Please enter your domain name:" domain
|
||||||
|
LOGD "your domain is:${domain},check it..."
|
||||||
|
# here we need to judge whether there exists cert already
|
||||||
|
local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
|
||||||
|
|
||||||
|
if [ ${currentCert} == ${domain} ]; then
|
||||||
|
local certInfo=$(~/.acme.sh/acme.sh --list)
|
||||||
|
LOGE "system already has certs here,can not issue again,current certs details:"
|
||||||
|
LOGI "$certInfo"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
LOGI "your domain is ready for issuing cert now..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create a directory for install cert
|
||||||
|
certPath="/root/cert/${domain}"
|
||||||
|
if [ ! -d "$certPath" ]; then
|
||||||
|
mkdir -p "$certPath"
|
||||||
|
else
|
||||||
|
rm -rf "$certPath"
|
||||||
|
mkdir -p "$certPath"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# get needed port here
|
||||||
|
local WebPort=80
|
||||||
|
read -p "please choose which port do you use,default will be 80 port:" WebPort
|
||||||
|
if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then
|
||||||
|
LOGE "your input ${WebPort} is invalid,will use default port"
|
||||||
|
fi
|
||||||
|
LOGI "will use port:${WebPort} to issue certs,please make sure this port is open..."
|
||||||
|
# NOTE:This should be handled by user
|
||||||
|
# open the port and kill the occupied progress
|
||||||
|
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
|
||||||
|
~/.acme.sh/acme.sh --issue -d ${domain} --standalone --httpport ${WebPort}
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
LOGE "issue certs failed,please check logs"
|
||||||
|
rm -rf ~/.acme.sh/${domain}
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
LOGE "issue certs succeed,installing certs..."
|
||||||
|
fi
|
||||||
|
# install cert
|
||||||
|
~/.acme.sh/acme.sh --installcert -d ${domain} \
|
||||||
|
--key-file /root/cert/${domain}/privkey.pem \
|
||||||
|
--fullchain-file /root/cert/${domain}/fullchain.pem
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
LOGE "install certs failed,exit"
|
||||||
|
rm -rf ~/.acme.sh/${domain}
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
LOGI "install certs succeed,enable auto renew..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
~/.acme.sh/acme.sh --upgrade --auto-upgrade
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
LOGE "auto renew failed, certs details:"
|
||||||
|
ls -lah cert/*
|
||||||
|
chmod 755 $certPath/*
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
LOGI "auto renew succeed, certs details:"
|
||||||
|
ls -lah cert/*
|
||||||
|
chmod 755 $certPath/*
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_cert_issue_CF() {
|
||||||
echo -E ""
|
echo -E ""
|
||||||
LOGD "******Instructions for use******"
|
LOGD "******Instructions for use******"
|
||||||
LOGI "This Acme script requires the following data:"
|
LOGI "This Acme script requires the following data:"
|
||||||
@@ -413,12 +545,14 @@ ssl_cert_issue() {
|
|||||||
LOGI "4.The script applies for a certificate. The default installation path is /root/cert "
|
LOGI "4.The script applies for a certificate. The default installation path is /root/cert "
|
||||||
confirm "Confirmed?[y/n]" "y"
|
confirm "Confirmed?[y/n]" "y"
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
cd ~
|
# check for acme.sh first
|
||||||
LOGI "Install Acme-Script"
|
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
|
||||||
curl https://get.acme.sh | sh
|
echo "acme.sh could not be found. we will install it"
|
||||||
if [ $? -ne 0 ]; then
|
install_acme
|
||||||
LOGE "Failed to install acme script"
|
if [ $? -ne 0 ]; then
|
||||||
exit 1
|
LOGE "install acme failed, please check logs"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
CF_Domain=""
|
CF_Domain=""
|
||||||
CF_GlobalKey=""
|
CF_GlobalKey=""
|
||||||
@@ -520,7 +654,8 @@ show_menu() {
|
|||||||
${green}14.${plain} Cancel x-ui Autostart
|
${green}14.${plain} Cancel x-ui Autostart
|
||||||
————————————————
|
————————————————
|
||||||
${green}15.${plain} 一A key installation bbr (latest kernel)
|
${green}15.${plain} 一A key installation bbr (latest kernel)
|
||||||
${green}16.${plain} 一Apply for a SSL certificate with one click(acme script)
|
${green}16.${plain} 一SSL Certificate Management
|
||||||
|
${green}17.${plain} 一Cloudflare SSL Certificate
|
||||||
"
|
"
|
||||||
show_status
|
show_status
|
||||||
echo && read -p "Please enter your selection [0-16]: " num
|
echo && read -p "Please enter your selection [0-16]: " num
|
||||||
@@ -575,7 +710,10 @@ show_menu() {
|
|||||||
install_bbr
|
install_bbr
|
||||||
;;
|
;;
|
||||||
16)
|
16)
|
||||||
ssl_cert_issue
|
ssl_cert_issue_main
|
||||||
|
;;
|
||||||
|
17)
|
||||||
|
ssl_cert_issue_CF
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
LOGE "Please enter the correct number [0-16]"
|
LOGE "Please enter the correct number [0-16]"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
"x-ui/config"
|
"x-ui/config"
|
||||||
"x-ui/util/common"
|
"x-ui/util/common"
|
||||||
|
|
||||||
@@ -58,16 +59,18 @@ type process struct {
|
|||||||
version string
|
version string
|
||||||
apiPort int
|
apiPort int
|
||||||
|
|
||||||
config *Config
|
config *Config
|
||||||
lines *queue.Queue
|
lines *queue.Queue
|
||||||
exitErr error
|
exitErr error
|
||||||
|
startTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProcess(config *Config) *process {
|
func newProcess(config *Config) *process {
|
||||||
return &process{
|
return &process{
|
||||||
version: "Unknown",
|
version: "Unknown",
|
||||||
config: config,
|
config: config,
|
||||||
lines: queue.New(100),
|
lines: queue.New(100),
|
||||||
|
startTime: time.Now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +114,10 @@ func (p *Process) GetConfig() *Config {
|
|||||||
return p.config
|
return p.config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Process) GetUptime() uint64 {
|
||||||
|
return uint64(time.Since(p.startTime).Seconds())
|
||||||
|
}
|
||||||
|
|
||||||
func (p *process) refreshAPIPort() {
|
func (p *process) refreshAPIPort() {
|
||||||
for _, inbound := range p.config.InboundConfigs {
|
for _, inbound := range p.config.InboundConfigs {
|
||||||
if inbound.Tag == "api" {
|
if inbound.Tag == "api" {
|
||||||
|
|||||||
Reference in New Issue
Block a user