mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-07-01 12:32:09 +00:00
Merge 0de2b9edbf
into 29f950046a
This commit is contained in:
commit
fd61c42cef
14 changed files with 283 additions and 80 deletions
|
@ -9,10 +9,10 @@
|
|||
|
||||
**لوحة تحكم ويب متقدمة • مبنية على Xray Core**
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
> **تنبيه:** المشروع ده للتعلم الشخصي والتواصل فقط. رجاءً استخدمه بشكل قانوني.
|
||||
|
@ -33,14 +33,14 @@
|
|||
|
||||
لتثبيت المشروع أو تحديثه، نفذ الأمر ده:
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/refs/tags/v2.6.0/install.sh)
|
||||
```
|
||||
|
||||
## تثبيت النسخة القديمة (مش موصى بيها)
|
||||
|
||||
لو عايز تثبت نسخة معينة، استخدم الأمر ده، مثلاً نسخة `v1.7.9`:
|
||||
```bash
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
## شهادة SSL
|
||||
|
@ -112,7 +112,7 @@ case "${ARCH}" in
|
|||
*) XUI_ARCH="amd64" ;;
|
||||
esac
|
||||
|
||||
wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
wget https://github.com/itboyhan1/3x-ui-xdsb/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
```
|
||||
|
||||
2. بعد تحميل الباكدج، نفذ الأوامر دي للتثبيت أو التحديث:
|
||||
|
@ -157,7 +157,7 @@ systemctl restart x-ui
|
|||
|
||||
2. **نسخ مستودع المشروع:**
|
||||
```sh
|
||||
git clone https://github.com/MHSanaei/3x-ui.git
|
||||
git clone https://github.com/itboyhan1/3x-ui-xdsb.git
|
||||
cd 3x-ui
|
||||
```
|
||||
|
||||
|
@ -176,7 +176,7 @@ systemctl restart x-ui
|
|||
--network=host \
|
||||
--restart=unless-stopped \
|
||||
--name 3x-ui \
|
||||
ghcr.io/mhsanaei/3x-ui:latest
|
||||
ghcr.io/itboyhan1/3x-ui-xdsb:latest
|
||||
```
|
||||
|
||||
4. **التحديث إلى أحدث نسخة:**
|
||||
|
@ -566,4 +566,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
|
|||
|
||||
## عدد النجوم مع مرور الوقت
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
|
||||
**Un Panel Web Avanzado • Construido sobre Xray Core**
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
> **Descargo de responsabilidad:** Este proyecto es solo para aprendizaje personal y comunicación, por favor no lo uses con fines ilegales, por favor no lo uses en un entorno de producción
|
||||
|
@ -32,7 +32,7 @@
|
|||
## Instalar y Actualizar
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/refs/tags/v2.6.0/install.sh)
|
||||
```
|
||||
|
||||
## Instalar versión antigua (no recomendamos)
|
||||
|
@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.
|
|||
Para instalar la versión deseada, utiliza el siguiente comando de instalación. Por ejemplo, ver `v1.7.9`:
|
||||
|
||||
```
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
## Certificado SSL
|
||||
|
@ -116,7 +116,7 @@ case "${ARCH}" in
|
|||
esac
|
||||
|
||||
|
||||
wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
wget https://github.com/itboyhan1/3x-ui-xdsb/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
```
|
||||
|
||||
2. Una vez que se haya descargado el paquete comprimido, ejecuta los siguientes comandos para instalar o actualizar x-ui:
|
||||
|
@ -163,7 +163,7 @@ systemctl restart x-ui
|
|||
2. Clona el Repositorio del Proyecto:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/MHSanaei/3x-ui.git
|
||||
git clone https://github.com/itboyhan1/3x-ui-xdsb.git
|
||||
cd 3x-ui
|
||||
```
|
||||
|
||||
|
@ -183,7 +183,7 @@ systemctl restart x-ui
|
|||
--network=host \
|
||||
--restart=unless-stopped \
|
||||
--name 3x-ui \
|
||||
ghcr.io/mhsanaei/3x-ui:latest
|
||||
ghcr.io/itboyhan1/3x-ui-xdsb:latest
|
||||
```
|
||||
|
||||
actualizar a la última versión
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
|
||||
**یک پنل وب پیشرفته • ساخته شده بر پایه Xray Core**
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
> **سلب مسئولیت:** این پروژه صرفاً برای اهداف آموزشی و تحقیقاتی است. استفاده از آن برای مقاصد غیرقانونی یا در محیطهای عملیاتی ممنوع است.
|
||||
|
@ -32,7 +32,7 @@
|
|||
## نصب و ارتقا
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/refs/tags/v2.6.0/install.sh)
|
||||
```
|
||||
|
||||
## نصب نسخههای قدیمی (توصیه نمیشود)
|
||||
|
@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.
|
|||
برای نصب نسخه خاصی از دستور زیر استفاده کنید. مثال برای نسخه `v1.7.9`:
|
||||
|
||||
```
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
## گواهی SSL
|
||||
|
@ -116,7 +116,7 @@ case "${ARCH}" in
|
|||
*) XUI_ARCH="amd64" ;;
|
||||
esac
|
||||
|
||||
wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
wget https://github.com/itboyhan1/3x-ui-xdsb/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
```
|
||||
|
||||
2. نصب یا ارتقا:
|
||||
|
@ -164,7 +164,7 @@ systemctl restart x-ui
|
|||
2. **کلون پروژه:**
|
||||
|
||||
```sh
|
||||
git clone https://github.com/MHSanaei/3x-ui.git
|
||||
git clone https://github.com/itboyhan1/3x-ui-xdsb.git
|
||||
cd 3x-ui
|
||||
```
|
||||
|
||||
|
@ -184,7 +184,7 @@ systemctl restart x-ui
|
|||
--network=host \
|
||||
--restart=unless-stopped \
|
||||
--name 3x-ui \
|
||||
ghcr.io/mhsanaei/3x-ui:latest
|
||||
ghcr.io/itboyhan1/3x-ui-xdsb:latest
|
||||
```
|
||||
|
||||
4. **بهروزرسانی:**
|
||||
|
@ -525,4 +525,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
|
|||
|
||||
## Stargazers over Time
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
|
|
20
README.md
20
README.md
|
@ -9,10 +9,10 @@
|
|||
|
||||
**An Advanced Web Panel • Built on Xray Core**
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
> **Disclaimer:** This project is only for personal learning and communication, please do not use it for illegal purposes, please do not use it in a production environment
|
||||
|
@ -32,7 +32,7 @@
|
|||
## Install & Upgrade
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/refs/tags/v2.6.0/install.sh)
|
||||
```
|
||||
|
||||
## Install legacy Version (we don't recommend)
|
||||
|
@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.
|
|||
To install your desired version, use following installation command. e.g., ver `v1.7.9`:
|
||||
|
||||
```
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
## SSL Certificate
|
||||
|
@ -118,7 +118,7 @@ case "${ARCH}" in
|
|||
esac
|
||||
|
||||
|
||||
wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
wget https://github.com/itboyhan1/3x-ui-xdsb/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
```
|
||||
|
||||
2. Once the compressed package is downloaded, execute the following commands to install or upgrade x-ui:
|
||||
|
@ -166,7 +166,7 @@ systemctl restart x-ui
|
|||
2. **Clone the Project Repository:**
|
||||
|
||||
```sh
|
||||
git clone https://github.com/MHSanaei/3x-ui.git
|
||||
git clone https://github.com/itboyhan1/3x-ui-xdsb.git
|
||||
cd 3x-ui
|
||||
```
|
||||
|
||||
|
@ -188,7 +188,7 @@ systemctl restart x-ui
|
|||
--network=host \
|
||||
--restart=unless-stopped \
|
||||
--name 3x-ui \
|
||||
ghcr.io/mhsanaei/3x-ui:latest
|
||||
ghcr.io/itboyhan1/3x-ui-xdsb:latest
|
||||
```
|
||||
|
||||
4. **Update to the Latest Version:**
|
||||
|
@ -595,4 +595,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
|
|||
|
||||
## Stargazers over Time
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
|
||||
**Продвинутая веб-панель • Построена на основе Xray Core**
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
> **Отказ от ответственности:** Этот проект предназначен только для личного обучения и общения. Пожалуйста, не используйте его в незаконных целях и не применяйте в производственной среде.
|
||||
|
@ -32,7 +32,7 @@
|
|||
## Установка и обновление
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/refs/tags/v2.6.0/install.sh)
|
||||
```
|
||||
|
||||
## Установить старую версию (мы не рекомендуем)
|
||||
|
@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.
|
|||
Чтобы установить желаемую версию, используйте следующую команду установки. Например, ver `v1.7.9`:
|
||||
|
||||
```
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
## SSL Сертификат
|
||||
|
@ -117,7 +117,7 @@ case "${ARCH}" in
|
|||
esac
|
||||
|
||||
|
||||
wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
wget https://github.com/itboyhan1/3x-ui-xdsb/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
```
|
||||
|
||||
2. После загрузки архива выполните следующие команды для установки или обновления x-ui:
|
||||
|
@ -165,7 +165,7 @@ systemctl restart x-ui
|
|||
2. **Склонируйте репозиторий проекта:**
|
||||
|
||||
```sh
|
||||
git clone https://github.com/MHSanaei/3x-ui.git
|
||||
git clone https://github.com/itboyhan1/3x-ui-xdsb.git
|
||||
cd 3x-ui
|
||||
```
|
||||
|
||||
|
@ -187,7 +187,7 @@ systemctl restart x-ui
|
|||
--network=host \
|
||||
--restart=unless-stopped \
|
||||
--name 3x-ui \
|
||||
ghcr.io/mhsanaei/3x-ui:latest
|
||||
ghcr.io/itboyhan1/3x-ui-xdsb:latest
|
||||
```
|
||||
|
||||
4. **Обновление до последней версии:**
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
|
||||
**一个更好的面板 • 基于Xray Core构建**
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
> **Disclaimer:** 此项目仅供个人学习交流,请不要用于非法目的,请不要在生产环境中使用。
|
||||
|
@ -32,7 +32,7 @@
|
|||
## 安装 & 升级
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/refs/tags/v2.6.0/install.sh)
|
||||
```
|
||||
|
||||
## 安装旧版本 (我们不建议)
|
||||
|
@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.
|
|||
要安装您想要的版本,请使用以下安装命令。例如,ver `v1.7.9`:
|
||||
|
||||
```
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
### SSL证书
|
||||
|
@ -116,7 +116,7 @@ case "${ARCH}" in
|
|||
esac
|
||||
|
||||
|
||||
wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
wget https://github.com/itboyhan1/3x-ui-xdsb/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
```
|
||||
|
||||
2. 下载压缩包后,执行以下命令安装或升级 x-ui:
|
||||
|
@ -163,7 +163,7 @@ systemctl restart x-ui
|
|||
2. 克隆仓库:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/MHSanaei/3x-ui.git
|
||||
git clone https://github.com/itboyhan1/3x-ui-xdsb.git
|
||||
cd 3x-ui
|
||||
```
|
||||
|
||||
|
@ -183,7 +183,7 @@ systemctl restart x-ui
|
|||
--network=host \
|
||||
--restart=unless-stopped \
|
||||
--name 3x-ui \
|
||||
ghcr.io/mhsanaei/3x-ui:latest
|
||||
ghcr.io/itboyhan1/3x-ui-xdsb:latest
|
||||
```
|
||||
|
||||
更新至最新版本
|
||||
|
|
|
@ -104,4 +104,6 @@ type Client struct {
|
|||
SubID string `json:"subId" form:"subId"`
|
||||
Comment string `json:"comment" form:"comment"`
|
||||
Reset int `json:"reset" form:"reset"`
|
||||
MaxDevices int `json:"maxDevices" form:"maxDevices" gorm:"default:0"` // 新增:最大设备数量限制, 0表示不限制
|
||||
ActiveIPs string `json:"activeIPs" form:"activeIPs" gorm:"type:text"` // 新增:当前活动的IP列表 (JSON字符串)
|
||||
}
|
||||
|
|
|
@ -142,13 +142,13 @@ install_x-ui() {
|
|||
cd /usr/local/
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
tag_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
tag_version=$(curl -Ls "https://api.github.com/repos/itboyhan1/3x-ui-xdsb/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [[ ! -n "$tag_version" ]]; then
|
||||
echo -e "${red}Failed to fetch x-ui version, it may be due to GitHub API restrictions, please try it later${plain}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
|
||||
wget -N -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz
|
||||
wget -N -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/itboyhan1/3x-ui-xdsb/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo -e "${red}Downloading x-ui failed, please be sure that your server can access GitHub ${plain}"
|
||||
exit 1
|
||||
|
@ -163,7 +163,7 @@ install_x-ui() {
|
|||
exit 1
|
||||
fi
|
||||
|
||||
url="https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz"
|
||||
url="https://github.com/itboyhan1/3x-ui-xdsb/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz"
|
||||
echo -e "Beginning to install x-ui $1"
|
||||
wget -N -O /usr/local/x-ui-linux-$(arch).tar.gz ${url}
|
||||
if [[ $? -ne 0 ]]; then
|
||||
|
@ -190,7 +190,7 @@ install_x-ui() {
|
|||
|
||||
chmod +x x-ui bin/xray-linux-$(arch)
|
||||
cp -f x-ui.service /etc/systemd/system/
|
||||
wget -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
|
||||
wget -O /usr/bin/x-ui https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/main/x-ui.sh
|
||||
chmod +x /usr/local/x-ui/x-ui.sh
|
||||
chmod +x /usr/bin/x-ui
|
||||
config_after_install
|
||||
|
|
|
@ -83,6 +83,18 @@
|
|||
</template>
|
||||
<a-input-number v-model.number="client.limitIp" min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<template slot="label">
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<span>{{ i18n "pages.inbounds.maxDevicesDesc" }}</span> <!-- 需要添加新的i18n条目 -->
|
||||
</template>
|
||||
<span>{{ i18n "pages.inbounds.maxDevices" }}</span> <!-- 需要添加新的i18n条目 -->
|
||||
<a-icon type="question-circle"></a-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input-number v-model.number="client.maxDevices" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="app.ipLimitEnable && client.limitIp > 0 && client.email && isEdit">
|
||||
<template slot="label">
|
||||
<a-tooltip>
|
||||
|
@ -169,4 +181,4 @@
|
|||
<a-input-number v-model.number="client.reset" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"slices"
|
||||
"x-ui/database"
|
||||
"x-ui/web/service"
|
||||
"x-ui/database/model"
|
||||
"x-ui/logger"
|
||||
"x-ui/xray"
|
||||
|
@ -36,7 +37,7 @@ func (j *CheckClientIpJob) Run() {
|
|||
}
|
||||
|
||||
shouldClearAccessLog := false
|
||||
iplimitActive := j.hasLimitIp()
|
||||
iplimitActive := j.hasLimitOrDeviceLimit() // 修改:检查LimitIP或MaxDevices
|
||||
f2bInstalled := j.checkFail2BanInstalled()
|
||||
isAccessLogAvailable := j.checkAccessLogAvailable(iplimitActive)
|
||||
|
||||
|
@ -45,7 +46,7 @@ func (j *CheckClientIpJob) Run() {
|
|||
shouldClearAccessLog = j.processLogFile()
|
||||
} else {
|
||||
if !f2bInstalled {
|
||||
logger.Warning("[LimitIP] Fail2Ban is not installed, Please install Fail2Ban from the x-ui bash menu.")
|
||||
logger.Warning("[LimitIP/MaxDevices] Fail2Ban is not installed, Please install Fail2Ban from the x-ui bash menu.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ func (j *CheckClientIpJob) clearAccessLog() {
|
|||
j.lastClear = time.Now().Unix()
|
||||
}
|
||||
|
||||
func (j *CheckClientIpJob) hasLimitIp() bool {
|
||||
func (j *CheckClientIpJob) hasLimitOrDeviceLimit() bool { // 修改函数名和逻辑
|
||||
db := database.GetDB()
|
||||
var inbounds []*model.Inbound
|
||||
|
||||
|
@ -96,7 +97,8 @@ func (j *CheckClientIpJob) hasLimitIp() bool {
|
|||
|
||||
for _, client := range clients {
|
||||
limitIp := client.LimitIP
|
||||
if limitIp > 0 {
|
||||
maxDevices := client.MaxDevices // 新增:获取MaxDevices
|
||||
if limitIp > 0 || maxDevices > 0 { // 修改:检查LimitIP或MaxDevices
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -144,21 +146,120 @@ func (j *CheckClientIpJob) processLogFile() bool {
|
|||
}
|
||||
|
||||
shouldCleanLog := false
|
||||
db := database.GetDB()
|
||||
var clientInboundID uint
|
||||
|
||||
for email, uniqueIps := range inboundClientIps {
|
||||
var clientData model.Client
|
||||
// Find the client by email. This requires iterating through inbounds and their clients.
|
||||
// This is a simplified representation. In a real scenario, you'd need a more efficient way to get client by email.
|
||||
foundClient := false
|
||||
var allInbounds []*model.Inbound
|
||||
db.Find(&allInbounds)
|
||||
for _, inbound := range allInbounds {
|
||||
if inbound.Settings == "" {
|
||||
continue
|
||||
}
|
||||
settings := map[string][]model.Client{}
|
||||
json.Unmarshal([]byte(inbound.Settings), &settings)
|
||||
clients := settings["clients"]
|
||||
for _, c := range clients {
|
||||
// Match client by email, or ID, or password based on what's available and matches 'email' (which is clientIdentifier in this context)
|
||||
clientIdentifierInLog := email // email from log is the clientIdentifier
|
||||
matched := false
|
||||
if c.Email != "" && c.Email == clientIdentifierInLog {
|
||||
matched = true
|
||||
} else if c.ID != "" && c.ID == clientIdentifierInLog { // For vmess/vless if email is used as ID in logs
|
||||
matched = true
|
||||
} else if c.Password != "" && c.Password == clientIdentifierInLog { // For trojan if email is used as password in logs
|
||||
matched = true
|
||||
}
|
||||
|
||||
ips := make([]string, 0, len(uniqueIps))
|
||||
for ip := range uniqueIps {
|
||||
ips = append(ips, ip)
|
||||
if matched {
|
||||
clientData = c
|
||||
clientInboundID = inbound.Id // Store the inbound ID
|
||||
foundClient = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if foundClient {
|
||||
break
|
||||
}
|
||||
}
|
||||
sort.Strings(ips)
|
||||
|
||||
clientIpsRecord, err := j.getInboundClientIps(email)
|
||||
if err != nil {
|
||||
j.addInboundClientIps(email, ips)
|
||||
if !foundClient {
|
||||
logger.Warningf("Client with identifier %s not found for IP processing", email)
|
||||
continue
|
||||
}
|
||||
|
||||
shouldCleanLog = j.updateInboundClientIps(clientIpsRecord, email, ips) || shouldCleanLog
|
||||
currentLoggedIps := make([]string, 0, len(uniqueIps))
|
||||
for ip := range uniqueIps {
|
||||
currentLoggedIps = append(currentLoggedIps, ip)
|
||||
}
|
||||
sort.Strings(currentLoggedIps)
|
||||
|
||||
clientIpsRecord, err := j.getInboundClientIps(email) // This function likely needs to be adapted or clientData used directly
|
||||
|
||||
activeIPs := []string{}
|
||||
if clientData.ActiveIPs != "" {
|
||||
errUnmarshal := json.Unmarshal([]byte(clientData.ActiveIPs), &activeIPs)
|
||||
if errUnmarshal != nil {
|
||||
logger.Warningf("Error unmarshalling ActiveIPs for client %s: %v", email, errUnmarshal)
|
||||
activeIPs = []string{} // Reset if unmarshalling fails
|
||||
}
|
||||
}
|
||||
|
||||
newActiveIPs := make([]string, len(activeIPs))
|
||||
copy(newActiveIPs, activeIPs)
|
||||
changedActiveIPs := false
|
||||
|
||||
for _, loggedIp := range currentLoggedIps {
|
||||
isExistingActiveIP := j.contains(newActiveIPs, loggedIp)
|
||||
|
||||
if clientData.MaxDevices > 0 {
|
||||
if !isExistingActiveIP {
|
||||
if len(newActiveIPs) < clientData.MaxDevices {
|
||||
newActiveIPs = append(newActiveIPs, loggedIp)
|
||||
changedActiveIPs = true
|
||||
} else {
|
||||
if !j.contains(j.disAllowedIps, loggedIp) {
|
||||
j.disAllowedIps = append(j.disAllowedIps, loggedIp)
|
||||
logger.Infof("[MaxDevices] IP %s for client %s banned due to exceeding max device limit (%d)", loggedIp, email, clientData.MaxDevices)
|
||||
shouldCleanLog = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} // End MaxDevices check
|
||||
} // End loop currentLoggedIps
|
||||
|
||||
if changedActiveIPs {
|
||||
activeIPsBytes, marshalErr := json.Marshal(newActiveIPs)
|
||||
if marshalErr != nil {
|
||||
logger.Warningf("Error marshalling new ActiveIPs for client %s: %v", email, marshalErr)
|
||||
} else {
|
||||
// Update clientData.ActiveIPs in the database
|
||||
// This part is complex because clientData is part of a JSON string in Inbound.Settings
|
||||
// A proper solution would involve updating the specific client within the Inbound's settings JSON
|
||||
// and then saving the Inbound object.
|
||||
// For simplicity, we'll log it. A full implementation needs to update the DB.
|
||||
logger.Infof("Client %s ActiveIPs updated to: %s", email, string(activeIPsBytes))
|
||||
// Placeholder for actual DB update logic for clientData.ActiveIPs
|
||||
// Example: err := s.updateClientActiveIPsInDB(inbound.Id, clientData.ID_or_Email, string(activeIPsBytes)); if err != nil { ... }
|
||||
inboundService := service.InboundService{} // Create an instance of InboundService
|
||||
dbUpdateErr := inboundService.UpdateClientActiveIPsInDB(clientInboundID, email, string(activeIPsBytes))
|
||||
if dbUpdateErr != nil {
|
||||
logger.Warningf("Failed to update ActiveIPs in DB for client %s: %v", email, dbUpdateErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil { // This 'err' is from j.getInboundClientIps(email)
|
||||
j.addInboundClientIps(email, currentLoggedIps) // This function likely needs to be adapted
|
||||
continue
|
||||
}
|
||||
|
||||
// Original LimitIP logic (needs to be integrated with new ActiveIPs logic if LimitIP is also active)
|
||||
shouldCleanLog = j.updateInboundClientIps(clientIpsRecord, email, currentLoggedIps) || shouldCleanLog
|
||||
}
|
||||
|
||||
return shouldCleanLog
|
||||
|
@ -179,7 +280,7 @@ func (j *CheckClientIpJob) checkAccessLogAvailable(iplimitActive bool) bool {
|
|||
|
||||
if accessLogPath == "none" || accessLogPath == "" {
|
||||
if iplimitActive {
|
||||
logger.Warning("[LimitIP] Access log path is not set, Please configure the access log path in Xray configs.")
|
||||
logger.Warning("[LimitIP/MaxDevices] Access log path is not set, Please configure the access log path in Xray configs.") // Updated log message
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -21,6 +21,90 @@ type InboundService struct {
|
|||
xrayApi xray.XrayAPI
|
||||
}
|
||||
|
||||
func (s *InboundService) UpdateClientActiveIPsInDB(inboundID int, clientIdentifier string, newActiveIPsJSON string) error {
|
||||
db := database.GetDB()
|
||||
var inbound model.Inbound
|
||||
err := db.First(&inbound, inboundID).Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("inbound with ID %d not found: %w", inboundID, err)
|
||||
}
|
||||
|
||||
if inbound.Settings == "" {
|
||||
return fmt.Errorf("inbound settings for ID %d are empty", inboundID)
|
||||
}
|
||||
|
||||
settingsMap := make(map[string]interface{})
|
||||
err = json.Unmarshal([]byte(inbound.Settings), &settingsMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unmarshalling settings for inbound ID %d: %w", inboundID, err)
|
||||
}
|
||||
|
||||
clientsRaw, ok := settingsMap["clients"]
|
||||
if !ok {
|
||||
return fmt.Errorf("no 'clients' field in settings for inbound ID %d", inboundID)
|
||||
}
|
||||
|
||||
clients, ok := clientsRaw.([]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("'clients' field is not an array in settings for inbound ID %d", inboundID)
|
||||
}
|
||||
|
||||
clientFound := false
|
||||
for i, clientInterface := range clients {
|
||||
clientMap, ok := clientInterface.(map[string]interface{})
|
||||
if !ok {
|
||||
logger.Warningf("Client entry is not a map for inbound ID %d, index %d", inboundID, i)
|
||||
continue
|
||||
}
|
||||
|
||||
// Try to match by email first
|
||||
clientEmail, emailOk := clientMap["email"].(string)
|
||||
if emailOk && clientEmail == clientIdentifier {
|
||||
clientMap["activeIPs"] = newActiveIPsJSON
|
||||
clients[i] = clientMap
|
||||
clientFound = true
|
||||
break
|
||||
}
|
||||
|
||||
// If not matched by email, try to match by ID (for vmess/vless etc.)
|
||||
clientID, idOk := clientMap["id"].(string)
|
||||
if idOk && clientID == clientIdentifier {
|
||||
clientMap["activeIPs"] = newActiveIPsJSON
|
||||
clients[i] = clientMap
|
||||
clientFound = true
|
||||
break
|
||||
}
|
||||
|
||||
// If not matched by email or ID, try to match by Password (for trojan etc.)
|
||||
clientPassword, passwordOk := clientMap["password"].(string)
|
||||
if passwordOk && clientPassword == clientIdentifier {
|
||||
clientMap["activeIPs"] = newActiveIPsJSON
|
||||
clients[i] = clientMap
|
||||
clientFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !clientFound {
|
||||
return fmt.Errorf("client with identifier '%s' not found in inbound ID %d", clientIdentifier, inboundID)
|
||||
}
|
||||
|
||||
settingsMap["clients"] = clients
|
||||
updatedSettingsBytes, err := json.Marshal(settingsMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling updated settings for inbound ID %d: %w", inboundID, err)
|
||||
}
|
||||
|
||||
inbound.Settings = string(updatedSettingsBytes)
|
||||
err = db.Save(&inbound).Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("error saving updated inbound settings for ID %d: %w", inboundID, err)
|
||||
}
|
||||
|
||||
logger.Infof("Successfully updated ActiveIPs for client '%s' in inbound ID %d", clientIdentifier, inboundID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) {
|
||||
db := database.GetDB()
|
||||
var inbounds []*model.Inbound
|
||||
|
|
|
@ -220,7 +220,9 @@
|
|||
"inboundData" = "Inbound's Data"
|
||||
"exportInbound" = "Export Inbound"
|
||||
"import" = "Import"
|
||||
"importInbound" = "Import an Inbound"
|
||||
"importInbound = "Import Inbound"
|
||||
maxDevices = "Max Devices"
|
||||
maxDevicesDesc = "Maximum number of simultaneously connected devices (0 = unlimited)"
|
||||
|
||||
[pages.client]
|
||||
"add" = "Add Client"
|
||||
|
|
|
@ -225,6 +225,8 @@
|
|||
"exportInbound" = "导出入站规则"
|
||||
"import"="导入"
|
||||
"importInbound" = "导入入站规则"
|
||||
"maxDevices" = "最大设备数"
|
||||
"maxDevicesDesc" = "允许同时连接的最大设备数量(0 = 无限制)"
|
||||
|
||||
[pages.client]
|
||||
"add" = "添加客户端"
|
||||
|
|
8
x-ui.sh
8
x-ui.sh
|
@ -74,7 +74,7 @@ before_show_menu() {
|
|||
}
|
||||
|
||||
install() {
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/main/install.sh)
|
||||
if [[ $? == 0 ]]; then
|
||||
if [[ $# == 0 ]]; then
|
||||
start
|
||||
|
@ -93,7 +93,7 @@ update() {
|
|||
fi
|
||||
return 0
|
||||
fi
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/main/install.sh)
|
||||
if [[ $? == 0 ]]; then
|
||||
LOGI "Update is complete, Panel has automatically restarted "
|
||||
before_show_menu
|
||||
|
@ -133,7 +133,7 @@ legacy_version() {
|
|||
exit 1
|
||||
fi
|
||||
# Use the entered panel version in the download link
|
||||
install_command="bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/v$tag_version/install.sh") v$tag_version"
|
||||
install_command="bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/v$tag_version/install.sh") v$tag_version"
|
||||
|
||||
echo "Downloading and installing panel version $tag_version..."
|
||||
eval $install_command
|
||||
|
@ -164,7 +164,7 @@ uninstall() {
|
|||
echo ""
|
||||
echo -e "Uninstalled Successfully.\n"
|
||||
echo "If you need to install this panel again, you can use below command:"
|
||||
echo -e "${green}bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)${plain}"
|
||||
echo -e "${green}bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/master/install.sh)${plain}"
|
||||
echo ""
|
||||
# Trap the SIGTERM signal
|
||||
trap delete_script SIGTERM
|
||||
|
|
Loading…
Reference in a new issue