mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-19 15:25:49 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f1f28cc0b | ||
|
|
70ff51d629 | ||
|
|
7472c31c34 | ||
|
|
04a8d5c177 | ||
|
|
7b2bd4247d | ||
|
|
5aee1c886b | ||
|
|
7a9a30a038 | ||
|
|
eb17cec289 | ||
|
|
22e107c746 | ||
|
|
36a93e2959 | ||
|
|
073247f054 | ||
|
|
96c8932961 | ||
|
|
5fac7df174 | ||
|
|
8bba9f3c25 | ||
|
|
268e8c7eb1 | ||
|
|
14e8f6cbfa | ||
|
|
7f0ba495db | ||
|
|
f829213dd1 | ||
|
|
4d5a73512e | ||
|
|
6dccc5b891 | ||
|
|
f642830dc8 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: 'stable'
|
||||||
- name: build linux amd64 version
|
- name: build linux amd64 version
|
||||||
run: |
|
run: |
|
||||||
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o xui-release -v main.go
|
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o xui-release -v main.go
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ Reference syntax:
|
|||||||
- CentOS 7+
|
- CentOS 7+
|
||||||
- Ubuntu 16+
|
- Ubuntu 16+
|
||||||
- Debian 8+
|
- Debian 8+
|
||||||
|
- Fedora 36+
|
||||||
|
|
||||||
# common problem
|
# common problem
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.4.1
|
0.4.2
|
||||||
66
install.sh
66
install.sh
@@ -10,24 +10,18 @@ cur_dir=$(pwd)
|
|||||||
# check root
|
# check root
|
||||||
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error:${plain} Please run this script with root privilege \n " && exit 1
|
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error:${plain} Please run this script with root privilege \n " && exit 1
|
||||||
|
|
||||||
# check os
|
# Check OS and set release variable
|
||||||
if [[ -f /etc/redhat-release ]]; then
|
if [[ -f /etc/os-release ]]; then
|
||||||
release="centos"
|
source /etc/os-release
|
||||||
elif cat /etc/issue | grep -Eqi "debian"; then
|
release=$ID
|
||||||
release="debian"
|
elif [[ -f /usr/lib/os-release ]]; then
|
||||||
elif cat /etc/issue | grep -Eqi "ubuntu"; then
|
source /usr/lib/os-release
|
||||||
release="ubuntu"
|
release=$ID
|
||||||
elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then
|
|
||||||
release="centos"
|
|
||||||
elif cat /proc/version | grep -Eqi "debian"; then
|
|
||||||
release="debian"
|
|
||||||
elif cat /proc/version | grep -Eqi "ubuntu"; then
|
|
||||||
release="ubuntu"
|
|
||||||
elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then
|
|
||||||
release="centos"
|
|
||||||
else
|
else
|
||||||
echo -e "${red} Check system OS failed, please contact the author! ${plain}\n" && exit 1
|
echo "Failed to check the system OS, please contact the author!" >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
echo "The OS release is: $release"
|
||||||
|
|
||||||
arch=$(arch)
|
arch=$(arch)
|
||||||
|
|
||||||
@@ -39,42 +33,44 @@ elif [[ $arch == "s390x" ]]; then
|
|||||||
arch="s390x"
|
arch="s390x"
|
||||||
else
|
else
|
||||||
arch="amd64"
|
arch="amd64"
|
||||||
echo -e "${red} Fail to check system arch, will use default arch: ${arch}${plain}"
|
echo -e "${red} Failed to check system arch, will use default arch: ${arch}${plain}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "arch: ${arch}"
|
echo "arch: ${arch}"
|
||||||
|
|
||||||
if [ $(getconf WORD_BIT) != '32' ] && [ $(getconf LONG_BIT) != '64' ]; then
|
if [ $(getconf WORD_BIT) != '32' ] && [ $(getconf LONG_BIT) != '64' ]; then
|
||||||
echo "x-ui dosen't support 32-bit(x86) system, please use 64 bit operating system(x86_64) instead,if there is something wrong, plz let me know"
|
echo "x-ui dosen't support 32-bit(x86) system, please use 64 bit operating system(x86_64) instead, if there is something wrong, please get in touch with me!"
|
||||||
exit -1
|
exit -1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
os_version=""
|
os_version=""
|
||||||
|
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
||||||
|
|
||||||
# os version
|
if [[ "${release}" == "centos" ]]; then
|
||||||
if [[ -f /etc/os-release ]]; then
|
if [[ ${os_version} -lt 7 ]]; then
|
||||||
os_version=$(awk -F'[= ."]' '/VERSION_ID/{print $3}' /etc/os-release)
|
echo -e "${red} Please use CentOS 7 or higher ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
if [[ -z "$os_version" && -f /etc/lsb-release ]]; then
|
elif [[ "${release}" == "ubuntu" ]]; then
|
||||||
os_version=$(awk -F'[= ."]+' '/DISTRIB_RELEASE/{print $2}' /etc/lsb-release)
|
if [[ ${os_version} -lt 18 ]]; then
|
||||||
fi
|
echo -e "${red}please use Ubuntu 18 or higher version!${plain}\n" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ x"${release}" == x"centos" ]]; then
|
elif [[ "${release}" == "fedora" ]]; then
|
||||||
if [[ ${os_version} -le 6 ]]; then
|
if [[ ${os_version} -lt 36 ]]; then
|
||||||
echo -e "${red} Please use CentOS 7 or higher version ${plain}\n" && exit 1
|
echo -e "${red}please use Fedora 36 or higher version!${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
elif [[ x"${release}" == x"ubuntu" ]]; then
|
|
||||||
if [[ ${os_version} -lt 16 ]]; then
|
elif [[ "${release}" == "debian" ]]; then
|
||||||
echo -e "${red} Please use Ubuntu 16 or higher version ${plain}\n" && exit 1
|
|
||||||
fi
|
|
||||||
elif [[ x"${release}" == x"debian" ]]; then
|
|
||||||
if [[ ${os_version} -lt 8 ]]; then
|
if [[ ${os_version} -lt 8 ]]; then
|
||||||
echo -e "${red} Please use Debian 8 or higher version ${plain}\n" && exit 1
|
echo -e "${red} Please use Debian 8 or higher ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${red}Failed to check the OS version, please contact the author!${plain}" && exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
install_base() {
|
install_base() {
|
||||||
if [[ x"${release}" == x"centos" ]]; then
|
if [[ "${release}" == "centos" ]]; then
|
||||||
yum install wget curl tar -y
|
yum install wget curl tar -y
|
||||||
else
|
else
|
||||||
apt install wget curl tar -y
|
apt install wget curl tar -y
|
||||||
|
|||||||
@@ -156,9 +156,19 @@
|
|||||||
padding:16px;
|
padding:16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-menu-dark,
|
||||||
|
.ant-menu-dark .ant-menu-sub,
|
||||||
|
.ant-layout-header,
|
||||||
|
.ant-layout-sider-dark,
|
||||||
|
.ant-layout-sider-zero-width-trigger,
|
||||||
|
.ant-dropdown-menu-dark,.ant-dropdown-menu-dark .ant-dropdown-menu,
|
||||||
|
.ant-menu-dark.ant-menu-horizontal>.ant-menu-item,.ant-menu-dark.ant-menu-horizontal>.ant-menu-submenu {
|
||||||
|
background:#161b22
|
||||||
|
}
|
||||||
|
|
||||||
.ant-card-dark {
|
.ant-card-dark {
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
background-color: #001529;
|
background-color: #1a212a;
|
||||||
border-color:rgba(0,0,0,.09);
|
border-color:rgba(0,0,0,.09);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +178,7 @@
|
|||||||
|
|
||||||
.ant-card-dark .ant-table-thead th {
|
.ant-card-dark .ant-table-thead th {
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
background-color: #000c17;
|
background-color: #161b22;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark .ant-table-tbody tr td,
|
.ant-card-dark .ant-table-tbody tr td,
|
||||||
@@ -180,7 +190,7 @@
|
|||||||
.ant-card-dark .ant-calendar,
|
.ant-card-dark .ant-calendar,
|
||||||
.ant-card-dark .ant-table-placeholder {
|
.ant-card-dark .ant-table-placeholder {
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
background-color: #001529;
|
background-color: #262f3d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark .ant-list-item-meta-title,
|
.ant-card-dark .ant-list-item-meta-title,
|
||||||
@@ -210,7 +220,7 @@
|
|||||||
|
|
||||||
.ant-card-dark tbody .ant-table-expanded-row {
|
.ant-card-dark tbody .ant-table-expanded-row {
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
background-color: #023366;
|
background-color: #1a212a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark .ant-input,
|
.ant-card-dark .ant-input,
|
||||||
@@ -219,12 +229,12 @@
|
|||||||
.ant-card-dark .ant-select-dropdown-menu-item-selected,
|
.ant-card-dark .ant-select-dropdown-menu-item-selected,
|
||||||
.ant-card-dark .ant-select-selection {
|
.ant-card-dark .ant-select-selection {
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
background-color: #023366;
|
background-color: #2e3b52;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark .ant-collapse-item {
|
.ant-card-dark .ant-collapse-item {
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
background-color: #000c17;
|
background-color: #161b22;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark .ant-modal-content,
|
.ant-card-dark .ant-modal-content,
|
||||||
@@ -232,7 +242,7 @@
|
|||||||
.ant-card-dark .ant-modal-header,
|
.ant-card-dark .ant-modal-header,
|
||||||
.ant-card-dark .ant-calendar-selected-day .ant-calendar-date {
|
.ant-card-dark .ant-calendar-selected-day .ant-calendar-date {
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
background-color: #1C262D;
|
background-color: #222a37;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-table-header {
|
.client-table-header {
|
||||||
@@ -244,13 +254,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark .client-table-header {
|
.ant-card-dark .client-table-header {
|
||||||
background-color: #023366;
|
background-color: #1a212a;
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark .client-table-odd-row {
|
.ant-card-dark .client-table-odd-row {
|
||||||
color: hsla(0,0%,100%,.65);
|
color: hsla(0,0%,100%,.65);
|
||||||
background-color: #1C262D;
|
background-color: #242c3a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-dark .ant-calendar-last-month-cell .ant-calendar-date,
|
.ant-card-dark .ant-calendar-last-month-cell .ant-calendar-date,
|
||||||
@@ -264,6 +274,58 @@
|
|||||||
|
|
||||||
.ant-drawer-dark .ant-drawer-wrapper-body,
|
.ant-drawer-dark .ant-drawer-wrapper-body,
|
||||||
.ant-drawer-dark .drawer-handle {
|
.ant-drawer-dark .drawer-handle {
|
||||||
background-color: #001529;
|
background-color: #1a212a;
|
||||||
border: 1px solid hsla(0,0%,100%,.30);
|
border: 1px solid hsla(0,0%,100%,.30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-blue {
|
||||||
|
color: #3c9ae8;
|
||||||
|
background: #111d2c;
|
||||||
|
border-color: #15395b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-green {
|
||||||
|
color: #6abe39;
|
||||||
|
background: #162312;
|
||||||
|
border-color: #274916;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-cyan {
|
||||||
|
color: #33bcb7;
|
||||||
|
background: #112123;
|
||||||
|
border-color: #144848;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-red {
|
||||||
|
color: #e84749;
|
||||||
|
background: #2a1215;
|
||||||
|
border-color: #58181c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-orange {
|
||||||
|
color: #e89a3c;
|
||||||
|
background: #2b1d11;
|
||||||
|
border-color: #593815;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-table-row-expand-icon {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-switch-checked {
|
||||||
|
background-color: #0c61b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-btn {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background: none;
|
||||||
|
border: 1px solid hsla(0,0%,100%,.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-btn-primary {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #073763;
|
||||||
|
border-color: #1890ff;
|
||||||
|
text-shadow: 0 -1px 0 rgba(0,0,0,.12);
|
||||||
|
box-shadow: 0 2px 0 rgba(0,0,0,.045);
|
||||||
|
}
|
||||||
@@ -1155,10 +1155,8 @@ class Inbound extends XrayCommonClass {
|
|||||||
if (this.xtls) {
|
if (this.xtls) {
|
||||||
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
||||||
address = this.stream.tls.server;
|
address = this.stream.tls.server;
|
||||||
if (type === "tcp") {
|
|
||||||
params.set("flow", this.settings.vlesses[clientIndex].flow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
params.set("flow", this.settings.vlesses[clientIndex].flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
const link = `vless://${uuid}@${address}:${port}`;
|
const link = `vless://${uuid}@${address}:${port}`;
|
||||||
@@ -1250,10 +1248,8 @@ class Inbound extends XrayCommonClass {
|
|||||||
if (this.xtls) {
|
if (this.xtls) {
|
||||||
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
||||||
address = this.stream.tls.server;
|
address = this.stream.tls.server;
|
||||||
if (type === "tcp" && this.settings.trojans[clientIndex].flow.length > 0) {
|
|
||||||
params.set("flow", this.settings.trojans[clientIndex].flow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
params.set("flow", this.settings.trojans[clientIndex].flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`;
|
const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`;
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
<a-form-item label='{{ i18n "pages.client.method" }}'>
|
<a-form-item label='{{ i18n "pages.client.method" }}'>
|
||||||
<a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" style="width: 350px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''">
|
<a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" style="width: 350px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''">
|
||||||
<a-select-option :value="0">Random</a-select-option>
|
<a-select-option :value="0">Random</a-select-option>
|
||||||
<a-select-option :value="1">Random_Prefix</a-select-option>
|
<a-select-option :value="1">Random+Prefix</a-select-option>
|
||||||
<a-select-option :value="2">Random_Prefix+Num</a-select-option>
|
<a-select-option :value="2">Random+Prefix+Num</a-select-option>
|
||||||
<a-select-option :value="3">Random_Prefix+Num+Postfix</a-select-option>
|
<a-select-option :value="3">Random+Prefix+Num+Postfix</a-select-option>
|
||||||
<a-select-option :value="4">Random_Prefix+Num@Telegram Username</a-select-option>
|
<a-select-option :value="4">Random+Prefix+Num@Telegram Username</a-select-option>
|
||||||
|
<a-select-option :value="5">Prefix+Num+Postfix [ BE CAREFUL! ]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item><br />
|
</a-form-item><br />
|
||||||
<a-form-item v-if="clientsBulkModal.emailMethod>1">
|
<a-form-item v-if="clientsBulkModal.emailMethod>1">
|
||||||
@@ -91,11 +92,12 @@
|
|||||||
start=0;
|
start=0;
|
||||||
end=clientsBulkModal.quantity;
|
end=clientsBulkModal.quantity;
|
||||||
}
|
}
|
||||||
prefix = (method>0 && clientsBulkModal.emailPrefix.length>0) ? "_" + clientsBulkModal.emailPrefix : "";
|
prefix = (method>0 && clientsBulkModal.emailPrefix.length>0) ? clientsBulkModal.emailPrefix : "";
|
||||||
useNum=(method>1);
|
useNum=(method>1);
|
||||||
postfix = (method>2 && clientsBulkModal.emailPostfix.length>0) ? (method == 4 ? "@" : "") + clientsBulkModal.emailPostfix : "";
|
postfix = (method>2 && clientsBulkModal.emailPostfix.length>0) ? (method == 4 ? "@" : "") + clientsBulkModal.emailPostfix : "";
|
||||||
for (let i = start; i < end; i++) {
|
for (let i = start; i < end; i++) {
|
||||||
newClient = clientsBulkModal.newClient(clientsBulkModal.dbInbound.protocol);
|
newClient = clientsBulkModal.newClient(clientsBulkModal.dbInbound.protocol);
|
||||||
|
if(method==5) newClient.email = "";
|
||||||
newClient.email += useNum ? prefix + i.toString() + postfix : prefix + postfix;
|
newClient.email += useNum ? prefix + i.toString() + postfix : prefix + postfix;
|
||||||
newClient._totalGB = clientsBulkModal.totalGB;
|
newClient._totalGB = clientsBulkModal.totalGB;
|
||||||
newClient._expiryTime = clientsBulkModal.expiryTime;
|
newClient._expiryTime = clientsBulkModal.expiryTime;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
</a-drawer>
|
</a-drawer>
|
||||||
<script>
|
<script>
|
||||||
const darkClass = "ant-card-dark";
|
const darkClass = "ant-card-dark";
|
||||||
const bgDarkStyle = "background-color: #1C262D";
|
const bgDarkStyle = "background-color: #242c3a";
|
||||||
const siderDrawer = {
|
const siderDrawer = {
|
||||||
visible: false,
|
visible: false,
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
|
|||||||
@@ -11,10 +11,6 @@
|
|||||||
.ant-col-sm-24 {
|
.ant-col-sm-24 {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-table-row-expand-icon {
|
|
||||||
color: rgba(0,0,0,.65);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<body>
|
<body>
|
||||||
<a-layout id="app" v-cloak>
|
<a-layout id="app" v-cloak>
|
||||||
|
|||||||
@@ -84,16 +84,16 @@
|
|||||||
</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" @click="openSelectV2rayVersion">[[ status.xray.version ]]</a-tag>
|
<a-tag color="green" style="cursor: pointer;" @click="openSelectV2rayVersion">[[ status.xray.version ]]</a-tag>
|
||||||
<a-tag color="blue" @click="stopXrayService">{{ i18n "pages.index.stopXray" }}</a-tag>
|
<a-tag color="blue" style="cursor: pointer;" @click="stopXrayService">{{ i18n "pages.index.stopXray" }}</a-tag>
|
||||||
<a-tag color="blue" @click="restartXrayService">{{ i18n "pages.index.restartXray" }}</a-tag>
|
<a-tag color="blue" style="cursor: pointer;" @click="restartXrayService">{{ i18n "pages.index.restartXray" }}</a-tag>
|
||||||
<a-tag color="blue" @click="openSelectV2rayVersion">{{ i18n "pages.index.xraySwitch" }}</a-tag>
|
<a-tag color="blue" style="cursor: pointer;" @click="openSelectV2rayVersion">{{ i18n "pages.index.xraySwitch" }}</a-tag>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
{{ i18n "pages.index.operationHours" }}:
|
{{ i18n "pages.index.operationHours" }}:
|
||||||
<a-tag color="#87d068">[[ formatSecond(status.uptime) ]]</a-tag>
|
<a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.operationHoursDesc" }}
|
{{ i18n "pages.index.operationHoursDesc" }}
|
||||||
|
|||||||
@@ -571,3 +571,13 @@ func (s *InboundService) SearchClientTraffic(query string) (traffic *xray.Client
|
|||||||
}
|
}
|
||||||
return traffic, err
|
return traffic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *InboundService) SearchInbounds(query string) ([]*model.Inbound, error) {
|
||||||
|
db := database.GetDB()
|
||||||
|
var inbounds []*model.Inbound
|
||||||
|
err := db.Model(model.Inbound{}).Preload("ClientStats").Where("remark like ?", "%"+query+"%").Find(&inbounds).Error
|
||||||
|
if err != nil && err != gorm.ErrRecordNotFound {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return inbounds, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -105,8 +105,6 @@ func (t *Tgbot) OnReceive() {
|
|||||||
} else {
|
} else {
|
||||||
if update.Message.IsCommand() {
|
if update.Message.IsCommand() {
|
||||||
t.answerCommand(update.Message, chatId, isAdmin)
|
t.answerCommand(update.Message, chatId, isAdmin)
|
||||||
} else {
|
|
||||||
t.aswerChat(update.Message.Text, chatId, isAdmin)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,16 +131,18 @@ func (t *Tgbot) answerCommand(message *tgbotapi.Message, chatId int64, isAdmin b
|
|||||||
} else {
|
} else {
|
||||||
t.searchForClient(chatId, message.CommandArguments())
|
t.searchForClient(chatId, message.CommandArguments())
|
||||||
}
|
}
|
||||||
|
case "inbound":
|
||||||
|
if isAdmin {
|
||||||
|
t.searchInbound(chatId, message.CommandArguments())
|
||||||
|
} else {
|
||||||
|
msg = "❗ Unknown command"
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
msg = "❗ Unknown command"
|
msg = "❗ Unknown command"
|
||||||
}
|
}
|
||||||
t.SendAnswer(chatId, msg, isAdmin)
|
t.SendAnswer(chatId, msg, isAdmin)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tgbot) aswerChat(message string, chatId int64, isAdmin bool) {
|
|
||||||
t.SendAnswer(chatId, "❗ Unknown message", isAdmin)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bool) {
|
func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bool) {
|
||||||
// Respond to the callback query, telling Telegram to show the user
|
// Respond to the callback query, telling Telegram to show the user
|
||||||
// a message with the data received.
|
// a message with the data received.
|
||||||
@@ -165,7 +165,7 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo
|
|||||||
case "client_commands":
|
case "client_commands":
|
||||||
t.SendMsgToTgbot(callbackQuery.From.ID, "To search for statistics, just use folowing command:\r\n \r\n<code>/usage [UID|Passowrd]</code>\r\n \r\nUse UID for vmess and vless and Password for Trojan.")
|
t.SendMsgToTgbot(callbackQuery.From.ID, "To search for statistics, just use folowing command:\r\n \r\n<code>/usage [UID|Passowrd]</code>\r\n \r\nUse UID for vmess and vless and Password for Trojan.")
|
||||||
case "commands":
|
case "commands":
|
||||||
t.SendMsgToTgbot(callbackQuery.From.ID, "To search for a client email, just use folowing command:\r\n \r\n<code>/usage email</code>")
|
t.SendMsgToTgbot(callbackQuery.From.ID, "Search for a client email:\r\n<code>/usage email</code>\r\n \r\nSearch for inbounds (with client stats):\r\n<code>/inbound [remark]</code>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,6 +423,45 @@ func (t *Tgbot) searchClient(chatId int64, email string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tgbot) searchInbound(chatId int64, remark string) {
|
||||||
|
inbouds, err := t.inboundService.SearchInbounds(remark)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warning(err)
|
||||||
|
msg := "❌ Something went wrong!"
|
||||||
|
t.SendMsgToTgbot(chatId, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, inbound := range inbouds {
|
||||||
|
info := ""
|
||||||
|
info += fmt.Sprintf("📍Inbound:%s\r\nPort:%d\r\n", inbound.Remark, inbound.Port)
|
||||||
|
info += fmt.Sprintf("Traffic: %s (↑%s,↓%s)\r\n", common.FormatTraffic((inbound.Up + inbound.Down)), common.FormatTraffic(inbound.Up), common.FormatTraffic(inbound.Down))
|
||||||
|
if inbound.ExpiryTime == 0 {
|
||||||
|
info += "Expire date: ♾ Unlimited\r\n \r\n"
|
||||||
|
} else {
|
||||||
|
info += fmt.Sprintf("Expire date:%s\r\n \r\n", time.Unix((inbound.ExpiryTime/1000), 0).Format("2006-01-02 15:04:05"))
|
||||||
|
}
|
||||||
|
t.SendMsgToTgbot(chatId, info)
|
||||||
|
for _, traffic := range inbound.ClientStats {
|
||||||
|
expiryTime := ""
|
||||||
|
if traffic.ExpiryTime == 0 {
|
||||||
|
expiryTime = "♾Unlimited"
|
||||||
|
} else {
|
||||||
|
expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
total := ""
|
||||||
|
if traffic.Total == 0 {
|
||||||
|
total = "♾Unlimited"
|
||||||
|
} else {
|
||||||
|
total = common.FormatTraffic((traffic.Total))
|
||||||
|
}
|
||||||
|
output := fmt.Sprintf("💡 Active: %t\r\n📧 Email: %s\r\n🔼 Upload↑: %s\r\n🔽 Download↓: %s\r\n🔄 Total: %s / %s\r\n📅 Expire in: %s\r\n",
|
||||||
|
traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
|
||||||
|
total, expiryTime)
|
||||||
|
t.SendMsgToTgbot(chatId, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tgbot) searchForClient(chatId int64, query string) {
|
func (t *Tgbot) searchForClient(chatId int64, query string) {
|
||||||
traffic, err := t.inboundService.SearchClientTraffic(query)
|
traffic, err := t.inboundService.SearchClientTraffic(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -543,4 +582,10 @@ func (t *Tgbot) sendBackup(chatId int64) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning("Error in uploading backup: ", err)
|
logger.Warning("Error in uploading backup: ", err)
|
||||||
}
|
}
|
||||||
|
file = tgbotapi.FilePath(xray.GetConfigPath())
|
||||||
|
msg = tgbotapi.NewDocument(chatId, file)
|
||||||
|
_, err = bot.Send(msg)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warning("Error in uploading config.json: ", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
x-ui.sh
59
x-ui.sh
@@ -20,46 +20,41 @@ function LOGI() {
|
|||||||
# check root
|
# check root
|
||||||
[[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1
|
[[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1
|
||||||
|
|
||||||
# check os
|
# Check OS and set release variable
|
||||||
if [[ -f /etc/redhat-release ]]; then
|
if [[ -f /etc/os-release ]]; then
|
||||||
release="centos"
|
source /etc/os-release
|
||||||
elif cat /etc/issue | grep -Eqi "debian"; then
|
release=$ID
|
||||||
release="debian"
|
elif [[ -f /usr/lib/os-release ]]; then
|
||||||
elif cat /etc/issue | grep -Eqi "ubuntu"; then
|
source /usr/lib/os-release
|
||||||
release="ubuntu"
|
release=$ID
|
||||||
elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then
|
|
||||||
release="centos"
|
|
||||||
elif cat /proc/version | grep -Eqi "debian"; then
|
|
||||||
release="debian"
|
|
||||||
elif cat /proc/version | grep -Eqi "ubuntu"; then
|
|
||||||
release="ubuntu"
|
|
||||||
elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then
|
|
||||||
release="centos"
|
|
||||||
else
|
else
|
||||||
LOGE "check system OS failed,please contact with author! \n" && exit 1
|
echo "Failed to check the system OS, please contact the author!" >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "The OS release is: $release"
|
||||||
|
|
||||||
|
|
||||||
os_version=""
|
os_version=""
|
||||||
|
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
||||||
|
|
||||||
# os version
|
if [[ "${release}" == "centos" ]]; then
|
||||||
if [[ -f /etc/os-release ]]; then
|
if [[ ${os_version} -lt 7 ]]; then
|
||||||
os_version=$(awk -F'[= ."]' '/VERSION_ID/{print $3}' /etc/os-release)
|
echo -e "${red} Please use CentOS 7 or higher ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
if [[ -z "$os_version" && -f /etc/lsb-release ]]; then
|
elif [[ "${release}" == "ubuntu" ]]; then
|
||||||
os_version=$(awk -F'[= ."]+' '/DISTRIB_RELEASE/{print $2}' /etc/lsb-release)
|
if [[ ${os_version} -lt 18 ]]; then
|
||||||
fi
|
echo -e "${red}please use Ubuntu 18 or higher version!${plain}\n" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ x"${release}" == x"centos" ]]; then
|
elif [[ "${release}" == "fedora" ]]; then
|
||||||
if [[ ${os_version} -le 6 ]]; then
|
if [[ ${os_version} -lt 36 ]]; then
|
||||||
LOGE "please use CentOS 7 or higher version! \n" && exit 1
|
echo -e "${red}please use Fedora 36 or higher version!${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
elif [[ x"${release}" == x"ubuntu" ]]; then
|
|
||||||
if [[ ${os_version} -lt 16 ]]; then
|
elif [[ "${release}" == "debian" ]]; then
|
||||||
LOGE "please use Ubuntu 16 or higher version!\n" && exit 1
|
|
||||||
fi
|
|
||||||
elif [[ x"${release}" == x"debian" ]]; then
|
|
||||||
if [[ ${os_version} -lt 8 ]]; then
|
if [[ ${os_version} -lt 8 ]]; then
|
||||||
LOGE "please use Debian 8 or higher version!\n" && exit 1
|
echo -e "${red} Please use Debian 8 or higher ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user