diff --git a/README.ar_EG.md b/README.ar_EG.md
index 50c3cdf5..4b68a84d 100644
--- a/README.ar_EG.md
+++ b/README.ar_EG.md
@@ -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)
\ No newline at end of file
+[](https://starchart.cc/MHSanaei/3x-ui)
diff --git a/README.es_ES.md b/README.es_ES.md
index 4b61d770..32fa58ea 100644
--- a/README.es_ES.md
+++ b/README.es_ES.md
@@ -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
diff --git a/README.fa_IR.md b/README.fa_IR.md
index 1216d6ad..7c370f28 100644
--- a/README.fa_IR.md
+++ b/README.fa_IR.md
@@ -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)
\ No newline at end of file
+[](https://starchart.cc/MHSanaei/3x-ui)
diff --git a/README.md b/README.md
index db5d6a18..4bb6fbc0 100644
--- a/README.md
+++ b/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)
\ No newline at end of file
+[](https://starchart.cc/MHSanaei/3x-ui)
diff --git a/README.ru_RU.md b/README.ru_RU.md
index 31db93b4..8f73f02a 100644
--- a/README.ru_RU.md
+++ b/README.ru_RU.md
@@ -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. **Обновление до последней версии:**
diff --git a/README.zh_CN.md b/README.zh_CN.md
index 025c5243..cfabc5be 100644
--- a/README.zh_CN.md
+++ b/README.zh_CN.md
@@ -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
```
更新至最新版本
diff --git a/database/model/model.go b/database/model/model.go
index 2e7095d3..452285c8 100644
--- a/database/model/model.go
+++ b/database/model/model.go
@@ -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字符串)
}
diff --git a/install.sh b/install.sh
index 0398285d..08712141 100644
--- a/install.sh
+++ b/install.sh
@@ -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
diff --git a/web/html/form/client.html b/web/html/form/client.html
index c67f1470..6a971a23 100644
--- a/web/html/form/client.html
+++ b/web/html/form/client.html
@@ -83,6 +83,18 @@
+
+
+
+
+ {{ i18n "pages.inbounds.maxDevicesDesc" }}
+
+ {{ i18n "pages.inbounds.maxDevices" }}
+
+
+
+
+
@@ -169,4 +181,4 @@
-{{end}}
\ No newline at end of file
+{{end}}
diff --git a/web/job/check_client_ip_job.go b/web/job/check_client_ip_job.go
index b95c8ee2..0f6b260a 100644
--- a/web/job/check_client_ip_job.go
+++ b/web/job/check_client_ip_job.go
@@ -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
}
diff --git a/web/service/inbound.go b/web/service/inbound.go
index f2646dbb..083b2fe6 100644
--- a/web/service/inbound.go
+++ b/web/service/inbound.go
@@ -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
diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml
index da9bedf1..fac8ef76 100644
--- a/web/translation/translate.en_US.toml
+++ b/web/translation/translate.en_US.toml
@@ -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"
diff --git a/web/translation/translate.zh_CN.toml b/web/translation/translate.zh_CN.toml
index 87181a09..cefcdbfe 100644
--- a/web/translation/translate.zh_CN.toml
+++ b/web/translation/translate.zh_CN.toml
@@ -225,6 +225,8 @@
"exportInbound" = "导出入站规则"
"import"="导入"
"importInbound" = "导入入站规则"
+"maxDevices" = "最大设备数"
+"maxDevicesDesc" = "允许同时连接的最大设备数量(0 = 无限制)"
[pages.client]
"add" = "添加客户端"
diff --git a/x-ui.sh b/x-ui.sh
index 88e5a7bb..bac8b38a 100644
--- a/x-ui.sh
+++ b/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