diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index 6e4fd399..00000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-version: 2
-updates:
- - package-ecosystem: "gomod" # See documentation for possible values
- directory: "/" # Location of package manifests
- schedule:
- interval: "daily"
- - package-ecosystem: "github-actions"
- directory: "/"
- schedule:
- interval: "daily"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8ad585a4..84a00cf6 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -83,7 +83,7 @@ jobs:
cd x-ui/bin
# Download dependencies
- Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.10.31/"
+ Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.12.15/"
if [ "${{ matrix.platform }}" == "amd64" ]; then
wget ${Xray_URL}Xray-linux-64.zip
unzip Xray-linux-64.zip
diff --git a/DockerInit.sh b/DockerInit.sh
index 90e83e9b..769c946f 100755
--- a/DockerInit.sh
+++ b/DockerInit.sh
@@ -27,7 +27,7 @@ case $1 in
esac
mkdir -p build/bin
cd build/bin
-wget "https://github.com/XTLS/Xray-core/releases/download/v24.10.31/Xray-linux-${ARCH}.zip"
+wget "https://github.com/XTLS/Xray-core/releases/download/v24.12.15/Xray-linux-${ARCH}.zip"
unzip "Xray-linux-${ARCH}.zip"
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
mv xray "xray-linux-${FNAME}"
diff --git a/README.es_ES.md b/README.es_ES.md
index a557d0cd..1efdddf0 100644
--- a/README.es_ES.md
+++ b/README.es_ES.md
@@ -1,6 +1,11 @@
[English](/README.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
-
+
+
+
+
+
+
**Un Panel Web Avanzado • Construido sobre Xray Core**
@@ -253,6 +258,7 @@ location /sub {
- Oracle Linux 8+
- OpenSUSE Tubleweed
- Amazon Linux 2023
+- Windows x64
## Arquitecturas y Dispositivos Compatibles
@@ -276,14 +282,18 @@ Nuestra plataforma ofrece compatibilidad con una amplia gama de arquitecturas y
## Idiomas
-- Inglés
-- Farsi
-- Chino
-- Ruso
-- Vietnamita
-- Español
-- Indonesio
-- Ucraniano
+- English (inglés)
+- Persian (persa)
+- Traditional Chinese (chino tradicional)
+- Simplified Chinese (chino simplificado)
+- Japanese (japonés)
+- Russian (ruso)
+- Vietnamese (vietnamita)
+- Spanish (español)
+- Indonesian (indonesio)
+- Ukrainian (ucraniano)
+- Turkish (turco)
+- Português (Brazil) (portugués (Brasil))
## Características
@@ -476,7 +486,7 @@ Ingresa el ID de chat de usuario en el campo de entrada número 4. Las cuentas d
#### Uso
-- [Documentación de API](https://documenter.getpostman.com/view/5146551/2sAXxP8Y12)
+- [Documentación de API](https://www.postman.com/hsanaei/3x-ui/collection/q1l5l0u/3x-ui)
- `/login` con `POST` datos de usuario: `{username: '', password: ''}` para iniciar sesión
- `/panel/api/inbounds` base para las siguientes acciones:
@@ -506,7 +516,7 @@ Ingresa el ID de chat de usuario en el campo de entrada número 4. Las cuentas d
- `client.password` para TROJAN
- `client.email` para Shadowsocks
-- [ ](https://god.gw.postman.com/run-collection/5146551-e6aac565-e0e2-46df-acff-2607a51bbd04?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-e6aac565-e0e2-46df-acff-2607a51bbd04%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
+- [ ](https://app.getpostman.com/run-collection/5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
## Variables de Entorno
@@ -534,13 +544,33 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Vista previa
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
## Un agradecimiento especial a
diff --git a/README.md b/README.md
index e60d5a95..36d083b3 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,11 @@
[English](/README.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
-
+
+
+
+
+
+
**An Advanced Web Panel • Built on Xray Core**
@@ -258,6 +263,7 @@ location /sub {
- Oracle Linux 8+
- OpenSUSE Tubleweed
- Amazon Linux 2023
+- Windows x64
## Supported Architectures and Devices
@@ -284,9 +290,10 @@ Our platform offers compatibility with a diverse range of architectures and devi
## Languages
- English
-- Farsi
+- Persian
- Traditional Chinese
- Simplified Chinese
+- Japanese
- Russian
- Vietnamese
- Spanish
@@ -487,7 +494,7 @@ Enter the user ID in input field number 4. The Telegram accounts with this id wi
#### Usage
-- [API Documentation](https://documenter.getpostman.com/view/5146551/2sAXxP8Y12)
+- [API Documentation](https://www.postman.com/hsanaei/3x-ui/collection/q1l5l0u/3x-ui)
- `/login` with `POST` user data: `{username: '', password: ''}` for login
- `/panel/api/inbounds` base for following actions:
@@ -518,7 +525,7 @@ Enter the user ID in input field number 4. The Telegram accounts with this id wi
- `client.password` for TROJAN
- `client.email` for Shadowsocks
-- [ ](https://god.gw.postman.com/run-collection/5146551-e6aac565-e0e2-46df-acff-2607a51bbd04?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-e6aac565-e0e2-46df-acff-2607a51bbd04%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
+- [ ](https://app.getpostman.com/run-collection/5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
## Environment Variables
@@ -546,13 +553,33 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Preview
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
## A Special Thanks to
diff --git a/README.ru_RU.md b/README.ru_RU.md
index e5b05dc0..251d7432 100644
--- a/README.ru_RU.md
+++ b/README.ru_RU.md
@@ -1,6 +1,11 @@
[English](/README.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
-
+
+
+
+
+
+
**Продвинутая веб-панель • Построена на основе Xray Core**
@@ -257,6 +262,7 @@ location /sub {
- Oracle Linux 8+
- OpenSUSE Tubleweed
- Amazon Linux 2023
+- Windows x64
## Поддерживаемые архитектуры и устройства
@@ -282,16 +288,18 @@ location /sub {
## Языки
-- Английский
-- Фарси
-- Китайский
-- Русский
-- Вьетнамский
-- Испанский
-- Индонезийский
-- Украинский
-- Турецкий
-- Португальский (Бразилия)
+- English (английский)
+- Persian (персидский)
+- Traditional Chinese (традиционный китайский)
+- Simplified Chinese (упрощенный китайский)
+- Japanese (японский)
+- Russian (русский)
+- Vietnamese (вьетнамский)
+- Spanish (испанский)
+- Indonesian (индонезийский)
+- Ukrainian (украинский)
+- Turkish (турецкий)
+- Português (Brazil) (португальский (Бразилия))
## Возможности
@@ -481,7 +489,7 @@ WARP встроен, и дополнительная установка не т
#### Использование
-- [API документация](https://documenter.getpostman.com/view/5146551/2sAXxP8Y12)
+- [API документация](https://www.postman.com/hsanaei/3x-ui/collection/q1l5l0u/3x-ui)
- `/login` с `POST`-данными: `{username: '', password: ''}` для входа
- `/panel/api/inbounds` это базовый путь для следующих действий:
@@ -515,7 +523,7 @@ WARP встроен, и дополнительная установка не т
-- [ ](https://god.gw.postman.com/run-collection/5146551-e6aac565-e0e2-46df-acff-2607a51bbd04?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-e6aac565-e0e2-46df-acff-2607a51bbd04%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
+- [ ](https://app.getpostman.com/run-collection/5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
## Переменные среды
@@ -543,13 +551,33 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Предварительный Просмотр
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
## Особая благодарность
diff --git a/README.zh_CN.md b/README.zh_CN.md
index 6ad22d0c..2dc0482e 100644
--- a/README.zh_CN.md
+++ b/README.zh_CN.md
@@ -1,6 +1,11 @@
[English](/README.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
-
+
+
+
+
+
+
**一个更好的面板 • 基于Xray Core构建**
@@ -254,6 +259,7 @@ location /sub {
- Oracle Linux 8+
- OpenSUSE Tubleweed
- Amazon Linux 2023
+- Windows x64
## 支持的架构和设备
@@ -276,14 +282,18 @@ location /sub {
## Languages
-- English(英语)
-- Farsi(伊朗语)
-- Chinese(中文)
-- Russian(俄语)
-- Vietnamese(越南语)
-- Spanish(西班牙语)
-- Indonesian (印度尼西亚语)
-- Ukrainian(乌克兰语)
+- English(英语)
+- Persian(波斯语)
+- Traditional Chinese(繁体中文)
+- Simplified Chinese(简体中文)
+- Japanese(日语)
+- Russian(俄语)
+- Vietnamese(越南语)
+- Spanish(西班牙语)
+- Indonesian(印尼语)
+- Ukrainian(乌克兰语)
+- Turkish(土耳其语)
+- Português (Brazil)(葡萄牙语(巴西))
## Features
@@ -476,7 +486,7 @@ Web 面板通过 Telegram Bot 支持每日流量、面板登录、数据库备
#### 使用
-- [API 文档](https://documenter.getpostman.com/view/5146551/2sAXxP8Y12)
+- [API 文档](https://www.postman.com/hsanaei/3x-ui/collection/q1l5l0u/3x-ui)
- `/login` 使用 `POST` 用户名称 & 密码: `{username: '', password: ''}` 登录
- `/panel/api/inbounds` 以下操作的基础:
@@ -506,7 +516,7 @@ Web 面板通过 Telegram Bot 支持每日流量、面板登录、数据库备
- `client.password` TROJAN
- `client.email` Shadowsocks
-- [ ](https://god.gw.postman.com/run-collection/5146551-e6aac565-e0e2-46df-acff-2607a51bbd04?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-e6aac565-e0e2-46df-acff-2607a51bbd04%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
+- [ ](https://app.getpostman.com/run-collection/5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
## 环境变量
@@ -534,13 +544,33 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## 预览
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
## 特别感谢
diff --git a/config/version b/config/version
index 62e64205..15834981 100644
--- a/config/version
+++ b/config/version
@@ -1 +1 @@
-2.4.6
\ No newline at end of file
+2.4.9
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 1a5c32ba..229326aa 100644
--- a/go.mod
+++ b/go.mod
@@ -1,46 +1,46 @@
module x-ui
-go 1.23.2
+go 1.23.4
require (
github.com/gin-contrib/gzip v1.0.1
github.com/gin-contrib/sessions v1.0.1
github.com/gin-gonic/gin v1.10.0
- github.com/goccy/go-json v0.10.3
- github.com/mymmrac/telego v0.31.3
+ github.com/goccy/go-json v0.10.4
+ github.com/mymmrac/telego v0.31.4
github.com/nicksnyder/go-i18n/v2 v2.4.1
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pelletier/go-toml/v2 v2.2.3
github.com/robfig/cron/v3 v3.0.1
- github.com/shirou/gopsutil/v4 v4.24.9
- github.com/valyala/fasthttp v1.57.0
- github.com/xtls/xray-core v1.8.25-0.20241031075831-4ec5c78c3453
+ github.com/shirou/gopsutil/v4 v4.24.11
+ github.com/valyala/fasthttp v1.58.0
+ github.com/xtls/xray-core v1.8.25-0.20241215123619-7d0a80b501d4
go.uber.org/atomic v1.11.0
- golang.org/x/text v0.19.0
- google.golang.org/grpc v1.67.1
- gorm.io/driver/sqlite v1.5.6
+ golang.org/x/text v0.21.0
+ google.golang.org/grpc v1.69.0
+ gorm.io/driver/sqlite v1.5.7
gorm.io/gorm v1.25.12
)
require (
github.com/andybalholm/brotli v1.1.1 // indirect
- github.com/bytedance/sonic v1.12.3 // indirect
+ github.com/bytedance/sonic v1.12.6 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect
github.com/cloudflare/circl v1.5.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/ebitengine/purego v0.8.1 // indirect
- github.com/fasthttp/router v1.5.2 // indirect
- github.com/gabriel-vasile/mimetype v1.4.6 // indirect
+ github.com/fasthttp/router v1.5.3 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.7 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.22.1 // indirect
+ github.com/go-playground/validator/v10 v10.23.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/google/btree v1.1.3 // indirect
- github.com/google/pprof v0.0.0-20241023014458-598669927662 // indirect
+ github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/sessions v1.4.0 // indirect
@@ -50,7 +50,7 @@ require (
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.11 // indirect
- github.com/klauspost/cpuid/v2 v2.2.8 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
@@ -58,15 +58,15 @@ require (
github.com/mattn/go-sqlite3 v1.14.24 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/onsi/ginkgo/v2 v2.20.2 // indirect
+ github.com/onsi/ginkgo/v2 v2.22.0 // indirect
github.com/pires/go-proxyproto v0.8.0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
- github.com/quic-go/quic-go v0.48.1 // indirect
+ github.com/quic-go/quic-go v0.48.2 // indirect
github.com/refraction-networking/utls v1.6.7 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
- github.com/sagernet/sing v0.4.3 // indirect
+ github.com/sagernet/sing v0.5.1 // indirect
github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect
@@ -78,24 +78,24 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
github.com/vishvananda/netlink v1.3.0 // indirect
- github.com/vishvananda/netns v0.0.4 // indirect
+ github.com/vishvananda/netns v0.0.5 // indirect
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.uber.org/mock v0.5.0 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
- golang.org/x/arch v0.11.0 // indirect
- golang.org/x/crypto v0.28.0 // indirect
- golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
- golang.org/x/mod v0.21.0 // indirect
- golang.org/x/net v0.30.0 // indirect
- golang.org/x/sync v0.8.0 // indirect
- golang.org/x/sys v0.26.0 // indirect
- golang.org/x/time v0.7.0 // indirect
- golang.org/x/tools v0.26.0 // indirect
+ golang.org/x/arch v0.12.0 // indirect
+ golang.org/x/crypto v0.31.0 // indirect
+ golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
+ golang.org/x/mod v0.22.0 // indirect
+ golang.org/x/net v0.32.0 // indirect
+ golang.org/x/sync v0.10.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/time v0.8.0 // indirect
+ golang.org/x/tools v0.28.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
- google.golang.org/protobuf v1.35.1 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
+ google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
diff --git a/go.sum b/go.sum
index ea99f6dd..c481e06a 100644
--- a/go.sum
+++ b/go.sum
@@ -4,8 +4,8 @@ github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJS
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
-github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU=
-github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
+github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
+github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
@@ -24,10 +24,10 @@ github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFP
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
-github.com/fasthttp/router v1.5.2 h1:ckJCCdV7hWkkrMeId3WfEhz+4Gyyf6QPwxi/RHIMZ6I=
-github.com/fasthttp/router v1.5.2/go.mod h1:C8EY53ozOwpONyevc/V7Gr8pqnEjwnkFFqPo1alAGs0=
-github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc=
-github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc=
+github.com/fasthttp/router v1.5.3 h1:BFWXqa3e4thRI3MgPKTNtz0Oiq6UYN2OsEtb+YQ5TMI=
+github.com/fasthttp/router v1.5.3/go.mod h1:b864KkDIapOYh77AVG/SNkwfRZ6k6ecWvD+ZRXmP5pw=
+github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
+github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
@@ -40,6 +40,8 @@ github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
@@ -49,14 +51,16 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
-github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
+github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
-github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
-github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
+github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -64,8 +68,10 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
-github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
@@ -85,8 +91,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
-github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
+github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -107,14 +113,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/mymmrac/telego v0.31.3 h1:yZlD+dm+1W6p3OmCG8K+MbS02Y6paUgwPnqfZN3RWQQ=
-github.com/mymmrac/telego v0.31.3/go.mod h1:coOoqXVmjFnwBlzusjfEezbQ7RH9wQnDowJdMm+bnEo=
+github.com/mymmrac/telego v0.31.4 h1:NpiNl0P/8eydknka/k6XaaaWVj5BKMlM3Ibba63QTBU=
+github.com/mymmrac/telego v0.31.4/go.mod h1:T12js1PgbYDYznvoN05MSMuPMfWTYo7D9LKl5cPFWiI=
github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g=
github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk=
-github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
-github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
-github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
-github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
+github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
+github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
+github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
+github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
@@ -129,8 +135,8 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA=
-github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
+github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
+github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
@@ -139,16 +145,16 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
-github.com/sagernet/sing v0.4.3 h1:Ty/NAiNnVd6844k7ujlL5lkzydhcTH5Psc432jXA4Y8=
-github.com/sagernet/sing v0.4.3/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
+github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
+github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4=
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
-github.com/shirou/gopsutil/v4 v4.24.9 h1:KIV+/HaHD5ka5f570RZq+2SaeFsb/pq+fp2DGNWYoOI=
-github.com/shirou/gopsutil/v4 v4.24.9/go.mod h1:3fkaHNeYsUFCGZ8+9vZVWtbyM1k2eRnlL+bWO8Bxa/Q=
+github.com/shirou/gopsutil/v4 v4.24.11 h1:WaU9xqGFKvFfsUv94SXcUPD7rCkU0vr/asVdQOBZNj8=
+github.com/shirou/gopsutil/v4 v4.24.11/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -158,8 +164,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
@@ -172,65 +178,75 @@ github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.57.0 h1:Xw8SjWGEP/+wAAgyy5XTvgrWlOD1+TxbbvNADYCm1Tg=
-github.com/valyala/fasthttp v1.57.0/go.mod h1:h6ZBaPRlzpZ6O3H5t2gEk1Qi33+TmLvfwgLLp0t9CpE=
+github.com/valyala/fasthttp v1.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE=
+github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
-github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
+github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
+github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
-github.com/xtls/xray-core v1.8.25-0.20241031075831-4ec5c78c3453 h1:2piT7IYX0SKhYjD+XiJMDZAbY01MkP1HYO54njmisaQ=
-github.com/xtls/xray-core v1.8.25-0.20241031075831-4ec5c78c3453/go.mod h1:OlJhs59caMUabGbOamwTc2khBSOfd34qtVJVXFhpfWM=
+github.com/xtls/xray-core v1.8.25-0.20241215123619-7d0a80b501d4 h1:zdd86FEjFZjAaRbWxiZQM2QPOzk/d6cig2DaE7c3MDQ=
+github.com/xtls/xray-core v1.8.25-0.20241215123619-7d0a80b501d4/go.mod h1:lduNPDkXku+Avphl8g7W0yJrHhWyxdOnPo0XGYdF0Aw=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
+go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
+go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
+go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
+go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
+go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
+go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
+go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
+go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
+go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
-golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4=
-golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
-golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
-golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
-golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
-golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
-golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
-golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
-golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
-golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
-golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
+golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
+golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
+golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
+golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
+golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
-golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
-golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
-golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
+golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
+golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
-google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
-google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
-google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
-google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
+google.golang.org/grpc v1.69.0 h1:quSiOM1GJPmPH5XtU+BCoVXcDVJJAzNcoyfC2cCjGkI=
+google.golang.org/grpc v1.69.0/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
+google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
+google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -240,8 +256,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
-gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
+gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I=
+gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 h1:ze1vwAdliUAr68RQ5NtufWaXaOg8WUO2OACzEV+TNdE=
diff --git a/media/01-overview-dark.png b/media/01-overview-dark.png
new file mode 100644
index 00000000..c8aeb6e5
Binary files /dev/null and b/media/01-overview-dark.png differ
diff --git a/media/01-overview-light.png b/media/01-overview-light.png
new file mode 100644
index 00000000..6b85d2a5
Binary files /dev/null and b/media/01-overview-light.png differ
diff --git a/media/02-inbounds-dark.png b/media/02-inbounds-dark.png
new file mode 100644
index 00000000..0d461102
Binary files /dev/null and b/media/02-inbounds-dark.png differ
diff --git a/media/02-inbounds-light.png b/media/02-inbounds-light.png
new file mode 100644
index 00000000..ceefabd5
Binary files /dev/null and b/media/02-inbounds-light.png differ
diff --git a/media/03-add-inbound-dark.png b/media/03-add-inbound-dark.png
new file mode 100644
index 00000000..476fa878
Binary files /dev/null and b/media/03-add-inbound-dark.png differ
diff --git a/media/03-add-inbound-light.png b/media/03-add-inbound-light.png
new file mode 100644
index 00000000..26e6e6fe
Binary files /dev/null and b/media/03-add-inbound-light.png differ
diff --git a/media/04-add-client-dark.png b/media/04-add-client-dark.png
new file mode 100644
index 00000000..bdcc52fa
Binary files /dev/null and b/media/04-add-client-dark.png differ
diff --git a/media/04-add-client-light.png b/media/04-add-client-light.png
new file mode 100644
index 00000000..3b5901ca
Binary files /dev/null and b/media/04-add-client-light.png differ
diff --git a/media/05-settings-dark.png b/media/05-settings-dark.png
new file mode 100644
index 00000000..dbc46f84
Binary files /dev/null and b/media/05-settings-dark.png differ
diff --git a/media/05-settings-light.png b/media/05-settings-light.png
new file mode 100644
index 00000000..db205773
Binary files /dev/null and b/media/05-settings-light.png differ
diff --git a/media/06-configs-dark.png b/media/06-configs-dark.png
new file mode 100644
index 00000000..769f3e3e
Binary files /dev/null and b/media/06-configs-dark.png differ
diff --git a/media/06-configs-light.png b/media/06-configs-light.png
new file mode 100644
index 00000000..687fb02f
Binary files /dev/null and b/media/06-configs-light.png differ
diff --git a/media/1.png b/media/1.png
deleted file mode 100644
index 301d4789..00000000
Binary files a/media/1.png and /dev/null differ
diff --git a/media/2.png b/media/2.png
deleted file mode 100644
index 607e2e37..00000000
Binary files a/media/2.png and /dev/null differ
diff --git a/media/3.png b/media/3.png
deleted file mode 100644
index 3c4a2bae..00000000
Binary files a/media/3.png and /dev/null differ
diff --git a/media/3X-UI.png b/media/3x-ui-dark.png
similarity index 100%
rename from media/3X-UI.png
rename to media/3x-ui-dark.png
diff --git a/media/3x-ui-light.png b/media/3x-ui-light.png
new file mode 100644
index 00000000..a77c830d
Binary files /dev/null and b/media/3x-ui-light.png differ
diff --git a/media/4.png b/media/4.png
deleted file mode 100644
index ab8773a8..00000000
Binary files a/media/4.png and /dev/null differ
diff --git a/media/5.png b/media/5.png
deleted file mode 100644
index c30356de..00000000
Binary files a/media/5.png and /dev/null differ
diff --git a/media/6.png b/media/6.png
deleted file mode 100644
index 030fa931..00000000
Binary files a/media/6.png and /dev/null differ
diff --git a/sub/default.json b/sub/default.json
index 931259ec..fff1b3ad 100644
--- a/sub/default.json
+++ b/sub/default.json
@@ -47,7 +47,7 @@
"tag": "direct",
"protocol": "freedom",
"settings": {
- "domainStrategy": "UseIP",
+ "domainStrategy": "AsIs",
"redirect": "",
"noises": []
}
diff --git a/sub/subService.go b/sub/subService.go
index 2838e932..f52d4b67 100644
--- a/sub/subService.go
+++ b/sub/subService.go
@@ -208,11 +208,6 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
headers, _ := ws["headers"].(map[string]interface{})
obj["host"] = searchHost(headers)
}
- case "http":
- obj["net"] = "h2"
- http, _ := stream["httpSettings"].(map[string]interface{})
- obj["path"], _ = http["path"].(string)
- obj["host"] = searchHost(http)
case "grpc":
grpc, _ := stream["grpcSettings"].(map[string]interface{})
obj["path"] = grpc["serviceName"].(string)
@@ -229,15 +224,16 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
headers, _ := httpupgrade["headers"].(map[string]interface{})
obj["host"] = searchHost(headers)
}
- case "splithttp":
- splithttp, _ := stream["splithttpSettings"].(map[string]interface{})
- obj["path"] = splithttp["path"].(string)
- if host, ok := splithttp["host"].(string); ok && len(host) > 0 {
+ case "xhttp":
+ xhttp, _ := stream["xhttpSettings"].(map[string]interface{})
+ obj["path"] = xhttp["path"].(string)
+ if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
obj["host"] = host
} else {
- headers, _ := splithttp["headers"].(map[string]interface{})
+ headers, _ := xhttp["headers"].(map[string]interface{})
obj["host"] = searchHost(headers)
}
+ obj["mode"] = xhttp["mode"].(string)
}
security, _ := stream["security"].(string)
obj["tls"] = security
@@ -360,10 +356,6 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
headers, _ := ws["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
- case "http":
- http, _ := stream["httpSettings"].(map[string]interface{})
- params["path"] = http["path"].(string)
- params["host"] = searchHost(http)
case "grpc":
grpc, _ := stream["grpcSettings"].(map[string]interface{})
params["serviceName"] = grpc["serviceName"].(string)
@@ -380,15 +372,16 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
headers, _ := httpupgrade["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
- case "splithttp":
- splithttp, _ := stream["splithttpSettings"].(map[string]interface{})
- params["path"] = splithttp["path"].(string)
- if host, ok := splithttp["host"].(string); ok && len(host) > 0 {
+ case "xhttp":
+ xhttp, _ := stream["xhttpSettings"].(map[string]interface{})
+ params["path"] = xhttp["path"].(string)
+ if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
params["host"] = host
} else {
- headers, _ := splithttp["headers"].(map[string]interface{})
+ headers, _ := xhttp["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
+ params["mode"] = xhttp["mode"].(string)
}
security, _ := stream["security"].(string)
if security == "tls" {
@@ -557,10 +550,6 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
headers, _ := ws["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
- case "http":
- http, _ := stream["httpSettings"].(map[string]interface{})
- params["path"] = http["path"].(string)
- params["host"] = searchHost(http)
case "grpc":
grpc, _ := stream["grpcSettings"].(map[string]interface{})
params["serviceName"] = grpc["serviceName"].(string)
@@ -577,15 +566,16 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
headers, _ := httpupgrade["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
- case "splithttp":
- splithttp, _ := stream["splithttpSettings"].(map[string]interface{})
- params["path"] = splithttp["path"].(string)
- if host, ok := splithttp["host"].(string); ok && len(host) > 0 {
+ case "xhttp":
+ xhttp, _ := stream["xhttpSettings"].(map[string]interface{})
+ params["path"] = xhttp["path"].(string)
+ if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
params["host"] = host
} else {
- headers, _ := splithttp["headers"].(map[string]interface{})
+ headers, _ := xhttp["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
+ params["mode"] = xhttp["mode"].(string)
}
security, _ := stream["security"].(string)
if security == "tls" {
@@ -754,10 +744,6 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
headers, _ := ws["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
- case "http":
- http, _ := stream["httpSettings"].(map[string]interface{})
- params["path"] = http["path"].(string)
- params["host"] = searchHost(http)
case "grpc":
grpc, _ := stream["grpcSettings"].(map[string]interface{})
params["serviceName"] = grpc["serviceName"].(string)
@@ -774,15 +760,16 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
headers, _ := httpupgrade["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
- case "splithttp":
- splithttp, _ := stream["splithttpSettings"].(map[string]interface{})
- params["path"] = splithttp["path"].(string)
- if host, ok := splithttp["host"].(string); ok && len(host) > 0 {
+ case "xhttp":
+ xhttp, _ := stream["xhttpSettings"].(map[string]interface{})
+ params["path"] = xhttp["path"].(string)
+ if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
params["host"] = host
} else {
- headers, _ := splithttp["headers"].(map[string]interface{})
+ headers, _ := xhttp["headers"].(map[string]interface{})
params["host"] = searchHost(headers)
}
+ params["mode"] = xhttp["mode"].(string)
}
security, _ := stream["security"].(string)
diff --git a/web/assets/codemirror/hint/javascript-hint.js b/web/assets/codemirror/hint/javascript-hint.js
index 95639798..f4396a79 100644
--- a/web/assets/codemirror/hint/javascript-hint.js
+++ b/web/assets/codemirror/hint/javascript-hint.js
@@ -63,7 +63,7 @@
return scriptHint(editor, javascriptKeywords,
function (e, cur) {return e.getTokenAt(cur);},
options);
- };
+ }
CodeMirror.registerHelper("hint", "javascript", javascriptHint);
function getCoffeeScriptToken(editor, cur) {
diff --git a/web/assets/codemirror/javascript.js b/web/assets/codemirror/javascript.js
index bb735ebc..3f65a26b 100644
--- a/web/assets/codemirror/javascript.js
+++ b/web/assets/codemirror/javascript.js
@@ -362,7 +362,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == wanted) return cont();
else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass();
else return cont(exp);
- };
+ }
return exp;
}
diff --git a/web/assets/codemirror/lint/lint.css b/web/assets/codemirror/lint/lint.css
index e1560db9..8bb5804b 100644
--- a/web/assets/codemirror/lint/lint.css
+++ b/web/assets/codemirror/lint/lint.css
@@ -6,7 +6,7 @@
.CodeMirror-lint-tooltip {
background-color: #ffd;
border: 1px solid black;
- border-radius: 4px 4px 4px 4px;
+ border-radius: 4px;
color: black;
font-family: monospace;
font-size: 10pt;
diff --git a/web/assets/js/langs.js b/web/assets/js/langs.js
index 1972d840..823160ad 100644
--- a/web/assets/js/langs.js
+++ b/web/assets/js/langs.js
@@ -19,6 +19,11 @@ const supportLangs = [
value: "zh-TW",
icon: "🇹🇼",
},
+ {
+ name: "日本語",
+ value: "ja-JP",
+ icon: "🇯🇵",
+ },
{
name: "Русский",
value: "ru-RU",
diff --git a/web/assets/js/model/inbound.js b/web/assets/js/model/inbound.js
index ea6f56fa..a36b9db2 100644
--- a/web/assets/js/model/inbound.js
+++ b/web/assets/js/model/inbound.js
@@ -113,6 +113,13 @@ const USERS_SECURITY = {
ZERO: "zero",
};
+const MODE_OPTION = {
+ AUTO: "auto",
+ PACKET_UP: "packet-up",
+ STREAM_UP: "stream-up",
+ STREAM_ONE: "stream-one",
+};
+
Object.freeze(Protocols);
Object.freeze(SSMethods);
Object.freeze(TLS_FLOW_CONTROL);
@@ -125,6 +132,7 @@ Object.freeze(USAGE_OPTION);
Object.freeze(DOMAIN_STRATEGY_OPTION);
Object.freeze(TCP_CONGESTION_OPTION);
Object.freeze(USERS_SECURITY);
+Object.freeze(MODE_OPTION);
class XrayCommonClass {
@@ -371,13 +379,15 @@ class WsStreamSettings extends XrayCommonClass {
acceptProxyProtocol = false,
path = '/',
host = '',
- headers = []
+ headers = [],
+ heartbeatPeriod = 0,
) {
super();
this.acceptProxyProtocol = acceptProxyProtocol;
this.path = path;
this.host = host;
this.headers = headers;
+ this.heartbeatPeriod = heartbeatPeriod;
}
addHeader(name, value) {
@@ -394,6 +404,7 @@ class WsStreamSettings extends XrayCommonClass {
json.path,
json.host,
XrayCommonClass.toHeaders(json.headers),
+ json.heartbeatPeriod,
);
}
@@ -403,46 +414,11 @@ class WsStreamSettings extends XrayCommonClass {
path: this.path,
host: this.host,
headers: XrayCommonClass.toV2Headers(this.headers, false),
+ heartbeatPeriod: this.heartbeatPeriod,
};
}
}
-class HttpStreamSettings extends XrayCommonClass {
- constructor(
- path = '/',
- host = [''],
- ) {
- super();
- this.path = path;
- this.host = host.length === 0 ? [''] : host;
- }
-
- addHost(host) {
- this.host.push(host);
- }
-
- removeHost(index) {
- this.host.splice(index, 1);
- }
-
- static fromJson(json = {}) {
- return new HttpStreamSettings(json.path, json.host);
- }
-
- toJson() {
- let host = [];
- for (let i = 0; i < this.host.length; ++i) {
- if (!ObjectUtil.isEmpty(this.host[i])) {
- host.push(this.host[i]);
- }
- }
- return {
- path: this.path,
- host: host,
- }
- }
-}
-
class GrpcStreamSettings extends XrayCommonClass {
constructor(
serviceName = "",
@@ -513,33 +489,39 @@ class HTTPUpgradeStreamSettings extends XrayCommonClass {
}
}
-class SplitHTTPStreamSettings extends XrayCommonClass {
+class xHTTPStreamSettings extends XrayCommonClass {
constructor(
path = '/',
host = '',
headers = [],
- scMaxConcurrentPosts = "100-200",
- scMaxEachPostBytes = "1000000-2000000",
- scMinPostsIntervalMs = "10-50",
+ scMaxBufferedPosts = 30,
+ scMaxEachPostBytes = "1000000",
+ scMinPostsIntervalMs = "30",
noSSEHeader = false,
xPaddingBytes = "100-1000",
xmux = {
maxConcurrency: "16-32",
maxConnections: 0,
cMaxReuseTimes: "64-128",
- cMaxLifetimeMs: 0
- }
+ cMaxLifetimeMs: 0,
+ hMaxRequestTimes: "800-900",
+ hKeepAlivePeriod: 0,
+ },
+ mode = MODE_OPTION.AUTO,
+ noGRPCHeader = false
) {
super();
this.path = path;
this.host = host;
this.headers = headers;
- this.scMaxConcurrentPosts = scMaxConcurrentPosts;
+ this.scMaxBufferedPosts = scMaxBufferedPosts;
this.scMaxEachPostBytes = scMaxEachPostBytes;
this.scMinPostsIntervalMs = scMinPostsIntervalMs;
this.noSSEHeader = noSSEHeader;
this.xPaddingBytes = xPaddingBytes;
this.xmux = xmux;
+ this.mode = mode;
+ this.noGRPCHeader = noGRPCHeader;
}
addHeader(name, value) {
@@ -551,16 +533,18 @@ class SplitHTTPStreamSettings extends XrayCommonClass {
}
static fromJson(json = {}) {
- return new SplitHTTPStreamSettings(
+ return new xHTTPStreamSettings(
json.path,
json.host,
XrayCommonClass.toHeaders(json.headers),
- json.scMaxConcurrentPosts,
+ json.scMaxBufferedPosts,
json.scMaxEachPostBytes,
json.scMinPostsIntervalMs,
json.noSSEHeader,
json.xPaddingBytes,
json.xmux,
+ json.mode,
+ json.noGRPCHeader,
);
}
@@ -569,7 +553,7 @@ class SplitHTTPStreamSettings extends XrayCommonClass {
path: this.path,
host: this.host,
headers: XrayCommonClass.toV2Headers(this.headers, false),
- scMaxConcurrentPosts: this.scMaxConcurrentPosts,
+ scMaxBufferedPosts: this.scMaxBufferedPosts,
scMaxEachPostBytes: this.scMaxEachPostBytes,
scMinPostsIntervalMs: this.scMinPostsIntervalMs,
noSSEHeader: this.noSSEHeader,
@@ -578,8 +562,12 @@ class SplitHTTPStreamSettings extends XrayCommonClass {
maxConcurrency: this.xmux.maxConcurrency,
maxConnections: this.xmux.maxConnections,
cMaxReuseTimes: this.xmux.cMaxReuseTimes,
- cMaxLifetimeMs: this.xmux.cMaxLifetimeMs
- }
+ cMaxLifetimeMs: this.xmux.cMaxLifetimeMs,
+ hMaxRequestTimes: this.xmux.hMaxRequestTimes,
+ hKeepAlivePeriod: this.xmux.hKeepAlivePeriod,
+ },
+ mode: this.mode,
+ noGRPCHeader: this.noGRPCHeader,
};
}
}
@@ -938,10 +926,9 @@ class StreamSettings extends XrayCommonClass {
tcpSettings = new TcpStreamSettings(),
kcpSettings = new KcpStreamSettings(),
wsSettings = new WsStreamSettings(),
- httpSettings = new HttpStreamSettings(),
grpcSettings = new GrpcStreamSettings(),
httpupgradeSettings = new HTTPUpgradeStreamSettings(),
- splithttpSettings = new SplitHTTPStreamSettings(),
+ xhttpSettings = new xHTTPStreamSettings(),
sockopt = undefined,
) {
super();
@@ -953,10 +940,9 @@ class StreamSettings extends XrayCommonClass {
this.tcp = tcpSettings;
this.kcp = kcpSettings;
this.ws = wsSettings;
- this.http = httpSettings;
this.grpc = grpcSettings;
this.httpupgrade = httpupgradeSettings;
- this.splithttp = splithttpSettings;
+ this.xhttp = xhttpSettings;
this.sockopt = sockopt;
}
@@ -1003,10 +989,9 @@ class StreamSettings extends XrayCommonClass {
TcpStreamSettings.fromJson(json.tcpSettings),
KcpStreamSettings.fromJson(json.kcpSettings),
WsStreamSettings.fromJson(json.wsSettings),
- HttpStreamSettings.fromJson(json.httpSettings),
GrpcStreamSettings.fromJson(json.grpcSettings),
HTTPUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
- SplitHTTPStreamSettings.fromJson(json.splithttpSettings),
+ xHTTPStreamSettings.fromJson(json.xhttpSettings),
SockoptStreamSettings.fromJson(json.sockopt),
);
}
@@ -1022,10 +1007,9 @@ class StreamSettings extends XrayCommonClass {
tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined,
kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined,
wsSettings: network === 'ws' ? this.ws.toJson() : undefined,
- httpSettings: network === 'http' ? this.http.toJson() : undefined,
grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined,
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
- splithttpSettings: network === 'splithttp' ? this.splithttp.toJson() : undefined,
+ xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
};
}
@@ -1154,16 +1138,12 @@ class Inbound extends XrayCommonClass {
return this.network === "grpc";
}
- get isH2() {
- return this.network === "http";
- }
-
get isHttpupgrade() {
return this.network === "httpupgrade";
}
- get isSplithttp() {
- return this.network === "splithttp";
+ get isXHTTP() {
+ return this.network === "xhttp";
}
// Shadowsocks
@@ -1202,12 +1182,10 @@ class Inbound extends XrayCommonClass {
return this.getHeader(this.stream.tcp.request, 'host');
} else if (this.isWs) {
return this.stream.ws.host?.length > 0 ? this.stream.ws.host : this.getHeader(this.stream.ws, 'host');
- } else if (this.isH2) {
- return this.stream.http.host[0];
} else if (this.isHttpupgrade) {
return this.stream.httpupgrade.host?.length > 0 ? this.stream.httpupgrade.host : this.getHeader(this.stream.httpupgrade, 'host');
- } else if (this.isSplithttp) {
- return this.stream.splithttp.host?.length > 0 ? this.stream.splithttp.host : this.getHeader(this.stream.splithttp, 'host');
+ } else if (this.isXHTTP) {
+ return this.stream.xhttp.host?.length > 0 ? this.stream.xhttp.host : this.getHeader(this.stream.xhttp, 'host');
}
return null;
}
@@ -1217,12 +1195,10 @@ class Inbound extends XrayCommonClass {
return this.stream.tcp.request.path[0];
} else if (this.isWs) {
return this.stream.ws.path;
- } else if (this.isH2) {
- return this.stream.http.path;
} else if (this.isHttpupgrade) {
return this.stream.httpupgrade.path;
- } else if (this.isSplithttp) {
- return this.stream.splithttp.path;
+ } else if (this.isXHTTP) {
+ return this.stream.xhttp.path;
}
return null;
}
@@ -1246,7 +1222,7 @@ class Inbound extends XrayCommonClass {
canEnableTls() {
if (![Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol)) return false;
- return ["tcp", "ws", "http", "grpc", "httpupgrade", "splithttp"].includes(this.network);
+ return ["tcp", "ws", "http", "grpc", "httpupgrade", "xhttp"].includes(this.network);
}
//this is used for xtls-rprx-vision
@@ -1259,7 +1235,7 @@ class Inbound extends XrayCommonClass {
canEnableReality() {
if (![Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false;
- return ["tcp", "http", "grpc", "splithttp"].includes(this.network);
+ return ["tcp", "http", "grpc", "xhttp"].includes(this.network);
}
canEnableStream() {
@@ -1311,10 +1287,6 @@ class Inbound extends XrayCommonClass {
const ws = this.stream.ws;
obj.path = ws.path;
obj.host = ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host');
- } else if (network === 'http') {
- obj.net = 'h2';
- obj.path = this.stream.http.path;
- obj.host = this.stream.http.host.join(',');
} else if (network === 'grpc') {
obj.path = this.stream.grpc.serviceName;
obj.authority = this.stream.grpc.authority;
@@ -1325,10 +1297,11 @@ class Inbound extends XrayCommonClass {
const httpupgrade = this.stream.httpupgrade;
obj.path = httpupgrade.path;
obj.host = httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host');
- } else if (network === 'splithttp') {
- const splithttp = this.stream.splithttp;
- obj.path = splithttp.path;
- obj.host = splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host');
+ } else if (network === 'xhttp') {
+ const xhttp = this.stream.xhttp;
+ obj.path = xhttp.path;
+ obj.host = xhttp.host?.length > 0 ? xhttp.host : this.getHeader(xhttp, 'host');
+ obj.mode = xhttp.mode;
}
if (security === 'tls') {
@@ -1379,11 +1352,6 @@ class Inbound extends XrayCommonClass {
params.set("path", ws.path);
params.set("host", ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host'));
break;
- case "http":
- const http = this.stream.http;
- params.set("path", http.path);
- params.set("host", http.host);
- break;
case "grpc":
const grpc = this.stream.grpc;
params.set("serviceName", grpc.serviceName);
@@ -1397,10 +1365,11 @@ class Inbound extends XrayCommonClass {
params.set("path", httpupgrade.path);
params.set("host", httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host'));
break;
- case "splithttp":
- const splithttp = this.stream.splithttp;
- params.set("path", splithttp.path);
- params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host'));
+ case "xhttp":
+ const xhttp = this.stream.xhttp;
+ params.set("path", xhttp.path);
+ params.set("host", xhttp.host?.length > 0 ? xhttp.host : this.getHeader(xhttp, 'host'));
+ params.set("mode", xhttp.mode);
break;
}
@@ -1482,11 +1451,6 @@ class Inbound extends XrayCommonClass {
params.set("path", ws.path);
params.set("host", ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host'));
break;
- case "http":
- const http = this.stream.http;
- params.set("path", http.path);
- params.set("host", http.host);
- break;
case "grpc":
const grpc = this.stream.grpc;
params.set("serviceName", grpc.serviceName);
@@ -1500,10 +1464,11 @@ class Inbound extends XrayCommonClass {
params.set("path", httpupgrade.path);
params.set("host", httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host'));
break;
- case "splithttp":
- const splithttp = this.stream.splithttp;
- params.set("path", splithttp.path);
- params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host'));
+ case "xhttp":
+ const xhttp = this.stream.xhttp;
+ params.set("path", xhttp.path);
+ params.set("host", xhttp.host?.length > 0 ? xhttp.host : this.getHeader(xhttp, 'host'));
+ params.set("mode", xhttp.mode);
break;
}
@@ -1564,11 +1529,6 @@ class Inbound extends XrayCommonClass {
params.set("path", ws.path);
params.set("host", ws.host?.length > 0 ? ws.host : this.getHeader(ws, 'host'));
break;
- case "http":
- const http = this.stream.http;
- params.set("path", http.path);
- params.set("host", http.host);
- break;
case "grpc":
const grpc = this.stream.grpc;
params.set("serviceName", grpc.serviceName);
@@ -1582,10 +1542,11 @@ class Inbound extends XrayCommonClass {
params.set("path", httpupgrade.path);
params.set("host", httpupgrade.host?.length > 0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host'));
break;
- case "splithttp":
- const splithttp = this.stream.splithttp;
- params.set("path", splithttp.path);
- params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host'));
+ case "xhttp":
+ const xhttp = this.stream.xhttp;
+ params.set("path", xhttp.path);
+ params.set("host", xhttp.host?.length > 0 ? xhttp.host : this.getHeader(xhttp, 'host'));
+ params.set("mode", xhttp.mode);
break;
}
@@ -2198,13 +2159,15 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
method = SSMethods.BLAKE3_AES_256_GCM,
password = RandomUtil.randomShadowsocksPassword(),
network = 'tcp,udp',
- shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()]
+ shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()],
+ ivCheck = false,
) {
super(protocol);
this.method = method;
this.password = password;
this.network = network;
this.shadowsockses = shadowsockses;
+ this.ivCheck = ivCheck;
}
static fromJson(json = {}) {
@@ -2214,6 +2177,7 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
json.password,
json.network,
json.clients.map(client => Inbound.ShadowsocksSettings.Shadowsocks.fromJson(client)),
+ json.ivCheck,
);
}
@@ -2222,7 +2186,8 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
method: this.method,
password: this.password,
network: this.network,
- clients: Inbound.ShadowsocksSettings.toJsonArray(this.shadowsockses)
+ clients: Inbound.ShadowsocksSettings.toJsonArray(this.shadowsockses),
+ ivCheck: this.ivCheck,
};
}
};
diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js
index d7338645..7a53383c 100644
--- a/web/assets/js/model/outbound.js
+++ b/web/assets/js/model/outbound.js
@@ -77,6 +77,13 @@ const USERS_SECURITY = {
ZERO: "zero",
};
+const MODE_OPTION = {
+ AUTO: "auto",
+ PACKET_UP: "packet-up",
+ STREAM_UP: "stream-up",
+ STREAM_ONE: "stream-one",
+};
+
Object.freeze(Protocols);
Object.freeze(SSMethods);
Object.freeze(TLS_FLOW_CONTROL);
@@ -85,6 +92,7 @@ Object.freeze(ALPN_OPTION);
Object.freeze(OutboundDomainStrategies);
Object.freeze(WireguardDomainStrategy);
Object.freeze(USERS_SECURITY);
+Object.freeze(MODE_OPTION);
class CommonClass {
@@ -198,16 +206,23 @@ class KcpStreamSettings extends CommonClass {
}
class WsStreamSettings extends CommonClass {
- constructor(path = '/', host = '') {
+ constructor(
+ path = '/',
+ host = '',
+ heartbeatPeriod = 0,
+
+ ) {
super();
this.path = path;
this.host = host;
+ this.heartbeatPeriod = heartbeatPeriod;
}
static fromJson(json = {}) {
return new WsStreamSettings(
json.path,
json.host,
+ json.heartbeatPeriod,
);
}
@@ -215,63 +230,11 @@ class WsStreamSettings extends CommonClass {
return {
path: this.path,
host: this.host,
+ heartbeatPeriod: this.heartbeatPeriod
};
}
}
-class HttpStreamSettings extends CommonClass {
- constructor(path = '/', host = '') {
- super();
- this.path = path;
- this.host = host;
- }
-
- static fromJson(json = {}) {
- return new HttpStreamSettings(
- json.path,
- json.host ? json.host.join(',') : '',
- );
- }
-
- toJson() {
- return {
- path: this.path,
- host: ObjectUtil.isEmpty(this.host) ? [''] : this.host.split(','),
- }
- }
-}
-
-class QuicStreamSettings extends CommonClass {
- constructor(
- security = 'none',
- key = '',
- type = 'none'
- ) {
- super();
- this.security = security;
- this.key = key;
- this.type = type;
- }
-
- static fromJson(json = {}) {
- return new QuicStreamSettings(
- json.security,
- json.key,
- json.header ? json.header.type : 'none',
- );
- }
-
- toJson() {
- return {
- security: this.security,
- key: this.key,
- header: {
- type: this.type,
- }
- }
- }
-}
-
class GrpcStreamSettings extends CommonClass {
constructor(
serviceName = "",
@@ -319,17 +282,23 @@ class HttpUpgradeStreamSettings extends CommonClass {
}
}
-class SplitHTTPStreamSettings extends CommonClass {
- constructor(path = '/', host = '') {
+class xHTTPStreamSettings extends CommonClass {
+ constructor(
+ path = '/',
+ host = '',
+ mode = '',
+ ) {
super();
this.path = path;
this.host = host;
+ this.mode = mode;
}
static fromJson(json = {}) {
- return new SplitHTTPStreamSettings(
+ return new xHTTPStreamSettings(
json.path,
json.host,
+ json.mode,
);
}
@@ -337,6 +306,7 @@ class SplitHTTPStreamSettings extends CommonClass {
return {
path: this.path,
host: this.host,
+ mode: this.mode,
};
}
}
@@ -455,11 +425,9 @@ class StreamSettings extends CommonClass {
tcpSettings = new TcpStreamSettings(),
kcpSettings = new KcpStreamSettings(),
wsSettings = new WsStreamSettings(),
- httpSettings = new HttpStreamSettings(),
- quicSettings = new QuicStreamSettings(),
grpcSettings = new GrpcStreamSettings(),
httpupgradeSettings = new HttpUpgradeStreamSettings(),
- splithttpSettings = new SplitHTTPStreamSettings(),
+ xhttpSettings = new xHTTPStreamSettings(),
sockopt = undefined,
) {
super();
@@ -470,10 +438,9 @@ class StreamSettings extends CommonClass {
this.tcp = tcpSettings;
this.kcp = kcpSettings;
this.ws = wsSettings;
- this.http = httpSettings;
this.grpc = grpcSettings;
this.httpupgrade = httpupgradeSettings;
- this.splithttp = splithttpSettings;
+ this.xhttp = xhttpSettings;
this.sockopt = sockopt;
}
@@ -502,11 +469,9 @@ class StreamSettings extends CommonClass {
TcpStreamSettings.fromJson(json.tcpSettings),
KcpStreamSettings.fromJson(json.kcpSettings),
WsStreamSettings.fromJson(json.wsSettings),
- HttpStreamSettings.fromJson(json.httpSettings),
- QuicStreamSettings.fromJson(json.quicSettings),
GrpcStreamSettings.fromJson(json.grpcSettings),
HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
- SplitHTTPStreamSettings.fromJson(json.splithttpSettings),
+ xHTTPStreamSettings.fromJson(json.xhttpSettings),
SockoptStreamSettings.fromJson(json.sockopt),
);
}
@@ -521,10 +486,9 @@ class StreamSettings extends CommonClass {
tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined,
kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined,
wsSettings: network === 'ws' ? this.ws.toJson() : undefined,
- httpSettings: network === 'http' ? this.http.toJson() : undefined,
grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined,
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
- splithttpSettings: network === 'splithttp' ? this.splithttp.toJson() : undefined,
+ xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
};
}
@@ -562,7 +526,7 @@ class Mux extends CommonClass {
class Outbound extends CommonClass {
constructor(
tag = '',
- protocol = Protocols.VMess,
+ protocol = Protocols.VLESS,
settings = null,
streamSettings = new StreamSettings(),
sendThrough,
@@ -589,7 +553,7 @@ class Outbound extends CommonClass {
canEnableTls() {
if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(this.protocol)) return false;
- return ["tcp", "ws", "http", "grpc", "httpupgrade", "splithttp"].includes(this.stream.network);
+ return ["tcp", "ws", "http", "grpc", "httpupgrade", "xhttp"].includes(this.stream.network);
}
//this is used for xtls-rprx-vision
@@ -602,7 +566,7 @@ class Outbound extends CommonClass {
canEnableReality() {
if (![Protocols.VLESS, Protocols.Trojan].includes(this.protocol)) return false;
- return ["tcp", "http", "grpc", "splithttp"].includes(this.stream.network);
+ return ["tcp", "http", "grpc", "xhttp"].includes(this.stream.network);
}
canEnableStream() {
@@ -700,17 +664,12 @@ class Outbound extends CommonClass {
stream.seed = json.path;
} else if (network === 'ws') {
stream.ws = new WsStreamSettings(json.path, json.host);
- } else if (network === 'http' || network == 'h2') {
- stream.network = 'http'
- stream.http = new HttpStreamSettings(
- json.path,
- json.host);
} else if (network === 'grpc') {
stream.grpc = new GrpcStreamSettings(json.path, json.authority, json.type == 'multi');
} else if (network === 'httpupgrade') {
stream.httpupgrade = new HttpUpgradeStreamSettings(json.path, json.host);
- } else if (network === 'splithttp') {
- stream.splithttp = new SplitHTTPStreamSettings(json.path, json.host);
+ } else if (network === 'xhttp') {
+ stream.xhttp = new xHTTPStreamSettings(json.path, json.host, json.mode);
}
if (json.tls && json.tls == 'tls') {
@@ -744,8 +703,6 @@ class Outbound extends CommonClass {
stream.kcp.seed = path;
} else if (type === 'ws') {
stream.ws = new WsStreamSettings(path, host);
- } else if (type === 'http' || type == 'h2') {
- stream.http = new HttpStreamSettings(path, host);
} else if (type === 'grpc') {
stream.grpc = new GrpcStreamSettings(
url.searchParams.get('serviceName') ?? '',
@@ -753,8 +710,8 @@ class Outbound extends CommonClass {
url.searchParams.get('mode') == 'multi');
} else if (type === 'httpupgrade') {
stream.httpupgrade = new HttpUpgradeStreamSettings(path, host);
- } else if (type === 'splithttp') {
- stream.splithttp = new SplitHTTPStreamSettings(path, host);
+ } else if (type === 'xhttp') {
+ stream.xhttp = new xHTTPStreamSettings(path, host, mode);
}
if (security == 'tls') {
@@ -960,7 +917,7 @@ Outbound.BlackholeSettings = class extends CommonClass {
Outbound.DNSSettings = class extends CommonClass {
constructor(
network = 'udp',
- address = '1.1.1.1',
+ address = '',
port = 53,
nonIPQuery = 'drop',
blockTypes = []
diff --git a/web/controller/index.go b/web/controller/index.go
index 2547570c..9af4ed7f 100644
--- a/web/controller/index.go
+++ b/web/controller/index.go
@@ -9,6 +9,7 @@ import (
"x-ui/web/service"
"x-ui/web/session"
+ "github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
)
@@ -49,8 +50,8 @@ func (a *IndexController) index(c *gin.Context) {
func (a *IndexController) login(c *gin.Context) {
var form LoginForm
- err := c.ShouldBind(&form)
- if err != nil {
+
+ if err := c.ShouldBind(&form); err != nil {
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.invalidFormData"))
return
}
@@ -68,29 +69,31 @@ func (a *IndexController) login(c *gin.Context) {
safeUser := template.HTMLEscapeString(form.Username)
safePass := template.HTMLEscapeString(form.Password)
safeSecret := template.HTMLEscapeString(form.LoginSecret)
+
if user == nil {
- logger.Warningf("wrong username or password or secret: \"%s\" \"%s\" \"%s\"", safeUser, safePass, safeSecret)
+ logger.Warningf("wrong username: \"%s\", password: \"%s\", secret: \"%s\", IP: \"%s\"", safeUser, safePass, safeSecret, getRemoteIp(c))
a.tgbot.UserLoginNotify(safeUser, safePass, getRemoteIp(c), timeStr, 0)
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword"))
return
- } else {
- logger.Infof("%s logged in successfully, Ip Address: %s\n", safeUser, getRemoteIp(c))
- a.tgbot.UserLoginNotify(safeUser, ``, getRemoteIp(c), timeStr, 1)
}
+ logger.Infof("%s logged in successfully, Ip Address: %s\n", safeUser, getRemoteIp(c))
+ a.tgbot.UserLoginNotify(safeUser, ``, getRemoteIp(c), timeStr, 1)
+
sessionMaxAge, err := a.settingService.GetSessionMaxAge()
if err != nil {
logger.Warning("Unable to get session's max age from DB")
}
- err = session.SetMaxAge(c, sessionMaxAge*60)
- if err != nil {
- logger.Warning("Unable to set session's max age")
+ session.SetMaxAge(c, sessionMaxAge*60)
+ session.SetLoginUser(c, user)
+ if err := sessions.Default(c).Save(); err != nil {
+ logger.Warning("Unable to save session: ", err)
+ return
}
- err = session.SetLoginUser(c, user)
- logger.Infof("%s logged in successfully", user.Username)
- jsonMsg(c, I18nWeb(c, "pages.login.toasts.successLogin"), err)
+ logger.Infof("%s logged in successfully", safeUser)
+ jsonMsg(c, I18nWeb(c, "pages.login.toasts.successLogin"), nil)
}
func (a *IndexController) logout(c *gin.Context) {
@@ -99,6 +102,9 @@ func (a *IndexController) logout(c *gin.Context) {
logger.Infof("%s logged out successfully", user.Username)
}
session.ClearSession(c)
+ if err := sessions.Default(c).Save(); err != nil {
+ logger.Warning("Unable to save session after clearing:", err)
+ }
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
}
diff --git a/web/html/xui/form/outbound.html b/web/html/xui/form/outbound.html
index 07b8f275..fb9e6f41 100644
--- a/web/html/xui/form/outbound.html
+++ b/web/html/xui/form/outbound.html
@@ -267,13 +267,12 @@
- TCP
+ TCP (RAW)
mKCP
WebSocket
- H2
gRPC
HTTPUpgrade
- SplitHTTP
+ XHTTP
@@ -337,15 +336,8 @@
-
-
-
-
-
-
-
-
-
+
+
@@ -372,13 +364,18 @@
-
-
+
+
-
+
-
+
+
+
+
+ [[ key ]]
+
diff --git a/web/html/xui/form/protocol/shadowsocks.html b/web/html/xui/form/protocol/shadowsocks.html
index b55a3d5c..1190b672 100644
--- a/web/html/xui/form/protocol/shadowsocks.html
+++ b/web/html/xui/form/protocol/shadowsocks.html
@@ -43,5 +43,8 @@
UDP
+
+
+
{{end}}
diff --git a/web/html/xui/form/stream/stream_http.html b/web/html/xui/form/stream/stream_http.html
deleted file mode 100644
index b562c112..00000000
--- a/web/html/xui/form/stream/stream_http.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{{define "form/streamHTTP"}}
-
-
-
-
-
- {{ i18n "host" }}
-
-
-
-
-
-
-
-
-
-{{end}}
\ No newline at end of file
diff --git a/web/html/xui/form/stream/stream_settings.html b/web/html/xui/form/stream/stream_settings.html
index 6d788090..a3119d9c 100644
--- a/web/html/xui/form/stream/stream_settings.html
+++ b/web/html/xui/form/stream/stream_settings.html
@@ -7,10 +7,9 @@
TCP (RAW)
mKCP
WebSocket
- HTTP
gRPC
HTTPUpgrade
- SplitHTTP
+ XHTTP
@@ -30,11 +29,6 @@
{{template "form/streamWS"}}
-
-
- {{template "form/streamHTTP"}}
-
-
{{template "form/streamGRPC"}}
@@ -45,9 +39,9 @@
{{template "form/streamHTTPUpgrade"}}
-
-
- {{template "form/streamSplitHTTP"}}
+
+
+ {{template "form/streamXHTTP"}}
diff --git a/web/html/xui/form/stream/stream_splithttp.html b/web/html/xui/form/stream/stream_splithttp.html
deleted file mode 100644
index 957720e9..00000000
--- a/web/html/xui/form/stream/stream_splithttp.html
+++ /dev/null
@@ -1,53 +0,0 @@
-{{define "form/streamSplitHTTP"}}
-
-
-
-
-
-
-
-
-
-
-
-
-
- [[ index+1 ]]
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{end}}
\ No newline at end of file
diff --git a/web/html/xui/form/stream/stream_ws.html b/web/html/xui/form/stream/stream_ws.html
index 80f44c50..65c87ae1 100644
--- a/web/html/xui/form/stream/stream_ws.html
+++ b/web/html/xui/form/stream/stream_ws.html
@@ -9,8 +9,11 @@
+
+
+
-
+
diff --git a/web/html/xui/form/stream/stream_xhttp.html b/web/html/xui/form/stream/stream_xhttp.html
new file mode 100644
index 00000000..1dd3c15c
--- /dev/null
+++ b/web/html/xui/form/stream/stream_xhttp.html
@@ -0,0 +1,67 @@
+{{define "form/streamXHTTP"}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [[ index+1 ]]
+
+
+ -
+
+
+
+
+
+ [[ key ]]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{{end}}
\ No newline at end of file
diff --git a/web/html/xui/inbound_info_modal.html b/web/html/xui/inbound_info_modal.html
index 36f165c6..7796cf1e 100644
--- a/web/html/xui/inbound_info_modal.html
+++ b/web/html/xui/inbound_info_modal.html
@@ -34,7 +34,7 @@
[[ inbound.network ]]
-
+
{{ i18n "host" }}
@@ -58,6 +58,14 @@
+
+
+ Mode
+
+ [[ inbound.stream.xhttp.mode ]]
+
+
+
kcp {{ i18n "encryption" }}
diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html
index a5a4c940..478f29de 100644
--- a/web/html/xui/inbounds.html
+++ b/web/html/xui/inbounds.html
@@ -15,7 +15,7 @@
overflow-y: hidden;
}
.ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper {
- margin:-10px 22px -10px !important;
+ margin:-10px 22px !important;
}
.ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper .ant-table {
border-bottom-left-radius: 1rem;
@@ -40,7 +40,7 @@
padding: .5rem;
}
.ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper {
- margin:-10px 2px -10px !important;
+ margin:-10px 2px !important;
}
}
.ant-col-sm-24 {
diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html
index d7383061..0c70ca1c 100644
--- a/web/html/xui/settings.html
+++ b/web/html/xui/settings.html
@@ -26,7 +26,7 @@
padding: .5rem 1rem;
text-align: center;
background: rgb(255 145 0 / 15%);
- margin: 1.5rem 2.5rem 0rem 2.5rem;
+ margin: 1.5rem 2.5rem 0rem;
border-radius: .5rem;
transition: all 0.5s;
animation: signal 3s cubic-bezier(0.18, 0.89, 0.32, 1.28) infinite;
diff --git a/web/html/xui/xray.html b/web/html/xui/xray.html
index ddb4d515..6bcd31b9 100644
--- a/web/html/xui/xray.html
+++ b/web/html/xui/xray.html
@@ -52,7 +52,7 @@
font-size: 24px;
}
.ant-collapse-content-box>li {
- padding: 12px 0 0 0 !important;
+ padding: 12px 0 0 !important;
}
.ant-list-item>li {
padding: 10px 20px !important;
diff --git a/web/job/check_client_ip_job.go b/web/job/check_client_ip_job.go
index 08899010..61f8b724 100644
--- a/web/job/check_client_ip_job.go
+++ b/web/job/check_client_ip_job.go
@@ -151,13 +151,13 @@ func (j *CheckClientIpJob) processLogFile() bool {
}
sort.Strings(ips)
- inboundClientIps, err := j.getInboundClientIps(email)
+ clientIpsRecord, err := j.getInboundClientIps(email)
if err != nil {
j.addInboundClientIps(email, ips)
continue
}
- shouldCleanLog = j.updateInboundClientIps(inboundClientIps, email, ips) || shouldCleanLog
+ shouldCleanLog = j.updateInboundClientIps(clientIpsRecord, email, ips) || shouldCleanLog
}
return shouldCleanLog
@@ -309,12 +309,12 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
func (j *CheckClientIpJob) getInboundByEmail(clientEmail string) (*model.Inbound, error) {
db := database.GetDB()
- var inbounds *model.Inbound
+ inbound := &model.Inbound{}
- err := db.Model(model.Inbound{}).Where("settings LIKE ?", "%"+clientEmail+"%").Find(&inbounds).Error
+ err := db.Model(&model.Inbound{}).Where("settings LIKE ?", "%"+clientEmail+"%").First(inbound).Error
if err != nil {
return nil, err
}
- return inbounds, nil
+ return inbound, nil
}
diff --git a/web/service/config.json b/web/service/config.json
index ea650f7b..54eecd54 100644
--- a/web/service/config.json
+++ b/web/service/config.json
@@ -30,7 +30,7 @@
"tag": "direct",
"protocol": "freedom",
"settings": {
- "domainStrategy": "UseIP",
+ "domainStrategy": "AsIs",
"redirect": "",
"noises": []
}
diff --git a/web/service/inbound.go b/web/service/inbound.go
index 7afcb140..4f28af21 100644
--- a/web/service/inbound.go
+++ b/web/service/inbound.go
@@ -588,8 +588,12 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool,
logger.Debug("Client deleted by api:", email)
needRestart = false
} else {
- logger.Debug("Unable to del client by api:", err1)
- needRestart = true
+ if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", email)) {
+ logger.Debug("User is already deleted. Nothing to do more...")
+ } else {
+ logger.Debug("Error in deleting client by api:", err1)
+ needRestart = true
+ }
}
s.xrayApi.Close()
}
@@ -713,10 +717,14 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
if oldClients[clientIndex].Enable {
err1 := s.xrayApi.RemoveUser(oldInbound.Tag, oldEmail)
if err1 == nil {
- logger.Debug("Old client deleted by api:", clients[0].Email)
+ logger.Debug("Old client deleted by api:", oldEmail)
} else {
- logger.Debug("Error in deleting client by api:", err1)
- needRestart = true
+ if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", oldEmail)) {
+ logger.Debug("User is already deleted. Nothing to do more...")
+ } else {
+ logger.Debug("Error in deleting client by api:", err1)
+ needRestart = true
+ }
}
}
if clients[0].Enable {
@@ -1037,12 +1045,8 @@ func (s *InboundService) disableInvalidInbounds(tx *gorm.DB) (bool, int64, error
if err1 == nil {
logger.Debug("Inbound disabled by api:", tag)
} else {
- if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", tag)) {
- logger.Debug("User is already disabled. Nothing to do more...")
- } else {
- logger.Debug("Error in disabling client by api:", err1)
- needRestart = true
- }
+ logger.Debug("Error in disabling inbound by api:", err1)
+ needRestart = true
}
}
s.xrayApi.Close()
diff --git a/web/service/server.go b/web/service/server.go
index de3eda9d..7eea7846 100644
--- a/web/service/server.go
+++ b/web/service/server.go
@@ -286,7 +286,7 @@ func (s *ServerService) GetXrayVersions() ([]string, error) {
}
if (major == 1 && minor == 8 && patch == 24) ||
- (major == 24 && ((minor > 10) || (minor == 10 && patch >= 16))) ||
+ (major == 24 && ((minor > 11) || (minor == 11 && patch >= 30))) ||
(major > 24) {
versions = append(versions, release.TagName)
}
diff --git a/web/service/warp.go b/web/service/warp.go
index a691d3c1..5b710f4a 100644
--- a/web/service/warp.go
+++ b/web/service/warp.go
@@ -8,6 +8,7 @@ import (
"os"
"time"
"x-ui/logger"
+ "x-ui/util/common"
)
type WarpService struct {
@@ -150,13 +151,23 @@ func (s *WarpService) SetWarpLicense(license string) (string, error) {
return "", err
}
+ var response map[string]interface{}
+ err = json.Unmarshal(buffer.Bytes(), &response)
+ if err != nil {
+ return "", err
+ }
+ if response["success"] == false {
+ errorArr, _ := response["errors"].([]interface{})
+ errorObj := errorArr[0].(map[string]interface{})
+ return "", common.NewError(errorObj["code"], errorObj["message"])
+ }
+
warpData["license_key"] = license
newWarpData, err := json.MarshalIndent(warpData, "", " ")
if err != nil {
return "", err
}
s.SettingService.SetWarp(string(newWarpData))
- println(string(newWarpData))
return string(newWarpData), nil
}
diff --git a/web/session/session.go b/web/session/session.go
index f5055efd..13aedad8 100644
--- a/web/session/session.go
+++ b/web/session/session.go
@@ -10,38 +10,41 @@ import (
)
const (
- loginUser = "LOGIN_USER"
- defaultPath = "/"
+ loginUserKey = "LOGIN_USER"
+ defaultPath = "/"
)
func init() {
gob.Register(model.User{})
}
-func SetLoginUser(c *gin.Context, user *model.User) error {
+func SetLoginUser(c *gin.Context, user *model.User) {
+ if user == nil {
+ return
+ }
s := sessions.Default(c)
- s.Set(loginUser, user)
- return s.Save()
+ s.Set(loginUserKey, *user)
}
-func SetMaxAge(c *gin.Context, maxAge int) error {
+func SetMaxAge(c *gin.Context, maxAge int) {
s := sessions.Default(c)
s.Options(sessions.Options{
Path: defaultPath,
MaxAge: maxAge,
HttpOnly: true,
})
- return s.Save()
}
func GetLoginUser(c *gin.Context) *model.User {
s := sessions.Default(c)
- obj := s.Get(loginUser)
+ obj := s.Get(loginUserKey)
if obj == nil {
return nil
}
user, ok := obj.(model.User)
if !ok {
+
+ s.Delete(loginUserKey)
return nil
}
return &user
@@ -51,7 +54,7 @@ func IsLogin(c *gin.Context) bool {
return GetLoginUser(c) != nil
}
-func ClearSession(c *gin.Context) error {
+func ClearSession(c *gin.Context) {
s := sessions.Default(c)
s.Clear()
s.Options(sessions.Options{
@@ -59,5 +62,4 @@ func ClearSession(c *gin.Context) error {
MaxAge: -1,
HttpOnly: true,
})
- return s.Save()
}
diff --git a/web/translation/translate.ja_JP.toml b/web/translation/translate.ja_JP.toml
new file mode 100644
index 00000000..01413171
--- /dev/null
+++ b/web/translation/translate.ja_JP.toml
@@ -0,0 +1,595 @@
+"username" = "ユーザー名"
+"password" = "パスワード"
+"login" = "ログイン"
+"confirm" = "確認"
+"cancel" = "キャンセル"
+"close" = "閉じる"
+"copy" = "コピー"
+"copied" = "コピー済み"
+"download" = "ダウンロード"
+"remark" = "備考"
+"enable" = "有効化"
+"protocol" = "プロトコル"
+"search" = "検索"
+"filter" = "フィルター"
+"loading" = "読み込み中..."
+"second" = "秒"
+"minute" = "分"
+"hour" = "時間"
+"day" = "日"
+"check" = "確認"
+"indefinite" = "無期限"
+"unlimited" = "無制限"
+"none" = "なし"
+"qrCode" = "QRコード"
+"info" = "詳細情報"
+"edit" = "編集"
+"delete" = "削除"
+"reset" = "リセット"
+"copySuccess" = "コピー成功"
+"sure" = "確定"
+"encryption" = "暗号化"
+"transmission" = "伝送"
+"host" = "ホスト"
+"path" = "パス"
+"camouflage" = "偽装"
+"status" = "ステータス"
+"enabled" = "有効"
+"disabled" = "無効"
+"depleted" = "消耗済み"
+"depletingSoon" = "間もなく消耗"
+"offline" = "オフライン"
+"online" = "オンライン"
+"domainName" = "ドメイン名"
+"monitor" = "監視"
+"certificate" = "証明書"
+"fail" = "失敗"
+"success" = "成功"
+"getVersion" = "バージョン取得"
+"install" = "インストール"
+"clients" = "クライアント"
+"usage" = "利用状況"
+"secretToken" = "シークレットトークン"
+"remained" = "残り"
+"security" = "セキュリティ"
+"secAlertTitle" = "セキュリティアラート"
+"secAlertSsl" = "この接続は安全ではありません。TLSを有効にしてデータ保護を行うまで、機密情報を入力しないでください。"
+"secAlertConf" = "一部の設定は脆弱です。潜在的な脆弱性を防ぐために、セキュリティプロトコルを強化することをお勧めします。"
+"secAlertSSL" = "セキュアな接続がありません。データ保護のためにTLS証明書をインストールしてください。"
+"secAlertPanelPort" = "デフォルトのポートにはセキュリティリスクがあります。ランダムなポートまたは特定のポートを設定してください。"
+"secAlertPanelURI" = "デフォルトのURIパスは安全ではありません。複雑なURIパスを設定してください。"
+"secAlertSubURI" = "サブスクリプションのデフォルトURIパスは安全ではありません。複雑なURIパスを設定してください。"
+"secAlertSubJsonURI" = "JSONサブスクリプションのデフォルトURIパスは安全ではありません。複雑なURIパスを設定してください。"
+
+[menu]
+"dashboard" = "ダッシュボード"
+"inbounds" = "インバウンド一覧"
+"settings" = "パネル設定"
+"xray" = "Xray設定"
+"logout" = "ログアウト"
+"link" = "リンク管理"
+
+[pages.login]
+"hello" = "こんにちは"
+"title" = "ようこそ"
+"loginAgain" = "ログインセッションが切れました。再度ログインしてください。"
+
+[pages.login.toasts]
+"invalidFormData" = "データ形式エラー"
+"emptyUsername" = "ユーザー名を入力してください"
+"emptyPassword" = "パスワードを入力してください"
+"wrongUsernameOrPassword" = "ユーザー名またはパスワードが間違っています"
+"successLogin" = "ログイン成功"
+
+[pages.index]
+"title" = "システムステータス"
+"memory" = "メモリ"
+"hard" = "ハードディスク"
+"xrayStatus" = "Xray"
+"stopXray" = "停止"
+"restartXray" = "再起動"
+"xraySwitch" = "バージョン"
+"xraySwitchClick" = "切り替えるバージョンを選択してください"
+"xraySwitchClickDesk" = "慎重に選択してください。古いバージョンは現在の設定と互換性がない可能性があります。"
+"operationHours" = "システム稼働時間"
+"systemLoad" = "システム負荷"
+"systemLoadDesc" = "過去1、5、15分間のシステム平均負荷"
+"connectionTcpCountDesc" = "システム内のすべてのTCP接続数"
+"connectionUdpCountDesc" = "システム内のすべてのUDP接続数"
+"connectionCount" = "接続数"
+"upSpeed" = "総アップロード速度"
+"downSpeed" = "総ダウンロード速度"
+"totalSent" = "システム起動以降の送信データ量"
+"totalReceive" = "システム起動以降の受信データ量"
+"xraySwitchVersionDialog" = "Xrayバージョン切り替え"
+"xraySwitchVersionDialogDesc" = "Xrayのバージョンを切り替えますか?"
+"dontRefresh" = "インストール中、このページをリロードしないでください"
+"logs" = "ログ"
+"config" = "設定"
+"backup" = "バックアップと復元"
+"backupTitle" = "データベースのバックアップと復元"
+"backupDescription" = "データベースを復元する前にバックアップすることをお勧めします"
+"exportDatabase" = "バックアップ"
+"importDatabase" = "復元"
+
+[pages.inbounds]
+"title" = "インバウンド一覧"
+"totalDownUp" = "総アップロード / ダウンロード"
+"totalUsage" = "総使用量"
+"inboundCount" = "インバウンド数"
+"operate" = "メニュー"
+"enable" = "有効化"
+"remark" = "備考"
+"protocol" = "プロトコル"
+"port" = "ポート"
+"traffic" = "トラフィック"
+"details" = "詳細情報"
+"transportConfig" = "トランスポート設定"
+"expireDate" = "有効期限"
+"resetTraffic" = "トラフィックリセット"
+"addInbound" = "インバウンド追加"
+"generalActions" = "一般操作"
+"create" = "追加"
+"update" = "更新"
+"modifyInbound" = "インバウンド修正"
+"deleteInbound" = "インバウンド削除"
+"deleteInboundContent" = "インバウンドを削除してもよろしいですか?"
+"deleteClient" = "クライアント削除"
+"deleteClientContent" = "クライアントを削除してもよろしいですか?"
+"resetTrafficContent" = "トラフィックをリセットしてもよろしいですか?"
+"copyLink" = "リンクをコピー"
+"address" = "アドレス"
+"network" = "ネットワーク"
+"destinationPort" = "宛先ポート"
+"targetAddress" = "宛先アドレス"
+"monitorDesc" = "空白にするとすべてのIPを監視"
+"meansNoLimit" = "= 無制限(単位:GB)"
+"totalFlow" = "総トラフィック"
+"leaveBlankToNeverExpire" = "空白にすると期限なし"
+"noRecommendKeepDefault" = "デフォルト値を保持することをお勧めします"
+"certificatePath" = "ファイルパス"
+"certificateContent" = "ファイル内容"
+"publicKey" = "公開鍵"
+"privatekey" = "秘密鍵"
+"clickOnQRcode" = "QRコードをクリックしてコピー"
+"client" = "クライアント"
+"export" = "リンクエクスポート"
+"clone" = "複製"
+"cloneInbound" = "複製"
+"cloneInboundContent" = "このインバウンドルールは、ポート(Port)、リスニングIP(Listening IP)、クライアント(Clients)を除くすべての設定がクローンされます"
+"cloneInboundOk" = "クローン作成"
+"resetAllTraffic" = "すべてのインバウンドトラフィックをリセット"
+"resetAllTrafficTitle" = "すべてのインバウンドトラフィックをリセット"
+"resetAllTrafficContent" = "すべてのインバウンドトラフィックをリセットしてもよろしいですか?"
+"resetInboundClientTraffics" = "クライアントトラフィックをリセット"
+"resetInboundClientTrafficTitle" = "すべてのクライアントトラフィックをリセット"
+"resetInboundClientTrafficContent" = "このインバウンドクライアントのすべてのトラフィックをリセットしてもよろしいですか?"
+"resetAllClientTraffics" = "すべてのクライアントトラフィックをリセット"
+"resetAllClientTrafficTitle" = "すべてのクライアントトラフィックをリセット"
+"resetAllClientTrafficContent" = "すべてのクライアントのトラフィックをリセットしてもよろしいですか?"
+"delDepletedClients" = "トラフィックが尽きたクライアントを削除"
+"delDepletedClientsTitle" = "トラフィックが尽きたクライアントを削除"
+"delDepletedClientsContent" = "トラフィックが尽きたすべてのクライアントを削除してもよろしいですか?"
+"email" = "メールアドレス"
+"emailDesc" = "メールアドレスは一意でなければなりません"
+"IPLimit" = "IP制限"
+"IPLimitDesc" = "設定値を超えるとインバウンドトラフィックが無効になります。(0 = 無効)"
+"IPLimitlog" = "IPログ"
+"IPLimitlogDesc" = "IP履歴ログ(無効なインバウンドトラフィックを有効にするには、ログをクリアしてください)"
+"IPLimitlogclear" = "ログをクリア"
+"setDefaultCert" = "パネル設定から証明書を設定"
+"telegramDesc" = "TelegramチャットIDを提供してください。(ボットで'/id'コマンドを使用)または(@userinfobot)"
+"subscriptionDesc" = "サブスクリプションURLを見つけるには、“詳細情報”に移動してください。また、複数のクライアントに同じ名前を使用することができます。"
+"info" = "情報"
+"same" = "同じ"
+"inboundData" = "インバウンドデータ"
+"exportInbound" = "インバウンドルールをエクスポート"
+"import" = "インポート"
+"importInbound" = "インバウンドルールをインポート"
+
+[pages.client]
+"add" = "クライアント追加"
+"edit" = "クライアント編集"
+"submitAdd" = "クライアント追加"
+"submitEdit" = "変更を保存"
+"clientCount" = "クライアント数"
+"bulk" = "一括作成"
+"method" = "方法"
+"first" = "最初"
+"last" = "最後"
+"prefix" = "プレフィックス"
+"postfix" = "サフィックス"
+"delayedStart" = "初回使用後に開始"
+"expireDays" = "期間"
+"days" = "日"
+"renew" = "自動更新"
+"renewDesc" = "期限が切れた後に自動更新。(0 = 無効)(単位:日)"
+
+[pages.inbounds.toasts]
+"obtain" = "取得"
+
+[pages.inbounds.stream.general]
+"request" = "リクエスト"
+"response" = "レスポンス"
+"name" = "名前"
+"value" = "値"
+
+[pages.inbounds.stream.tcp]
+"version" = "バージョン"
+"method" = "方法"
+"path" = "パス"
+"status" = "ステータス"
+"statusDescription" = "ステータス説明"
+"requestHeader" = "リクエストヘッダー"
+"responseHeader" = "レスポンスヘッダー"
+
+[pages.settings]
+"title" = "パネル設定"
+"save" = "保存"
+"infoDesc" = "ここでのすべての変更は、保存してパネルを再起動する必要があります"
+"restartPanel" = "パネル再起動"
+"restartPanelDesc" = "パネルを再起動してもよろしいですか?再起動後にパネルにアクセスできない場合は、サーバーでパネルログを確認してください"
+"actions" = "操作"
+"resetDefaultConfig" = "デフォルト設定にリセット"
+"panelSettings" = "一般"
+"securitySettings" = "セキュリティ設定"
+"TGBotSettings" = "Telegramボット設定"
+"panelListeningIP" = "パネル監視IP"
+"panelListeningIPDesc" = "デフォルトではすべてのIPを監視する"
+"panelListeningDomain" = "パネル監視ドメイン"
+"panelListeningDomainDesc" = "デフォルトで空白の場合、すべてのドメインとIPアドレスを監視する"
+"panelPort" = "パネル監視ポート"
+"panelPortDesc" = "再起動で有効"
+"publicKeyPath" = "パネル証明書公開鍵ファイルパス"
+"publicKeyPathDesc" = "'/'で始まる絶対パスを入力"
+"privateKeyPath" = "パネル証明書秘密鍵ファイルパス"
+"privateKeyPathDesc" = "'/'で始まる絶対パスを入力"
+"panelUrlPath" = "パネルURLルートパス"
+"panelUrlPathDesc" = "'/'で始まり、'/'で終わる必要があります"
+"pageSize" = "ページサイズ"
+"pageSizeDesc" = "インバウンドテーブルのページサイズを定義します。0を設定すると無効化されます"
+"remarkModel" = "備考モデルと区切り記号"
+"datepicker" = "日付ピッカー"
+"datepickerPlaceholder" = "日付を選択"
+"datepickerDescription" = "日付選択カレンダーで有効期限を指定する"
+"sampleRemark" = "備考の例"
+"oldUsername" = "旧ユーザー名"
+"currentPassword" = "旧パスワード"
+"newUsername" = "新しいユーザー名"
+"newPassword" = "新しいパスワード"
+"telegramBotEnable" = "Telegramボットを有効にする"
+"telegramBotEnableDesc" = "Telegramボット機能を有効にする"
+"telegramToken" = "Telegramボットトークン"
+"telegramTokenDesc" = "'@BotFather'から取得したTelegramボットトークン"
+"telegramProxy" = "SOCKS5プロキシ"
+"telegramProxyDesc" = "SOCKS5プロキシを有効にしてTelegramに接続する(ガイドに従って設定を調整)"
+"telegramAPIServer" = "Telegram APIサーバー"
+"telegramAPIServerDesc" = "使用するTelegram APIサーバー。空白の場合はデフォルトサーバーを使用する"
+"telegramChatId" = "管理者チャットID"
+"telegramChatIdDesc" = "Telegram管理者チャットID(複数の場合はカンマで区切る)@userinfobotで取得するか、ボットで'/id'コマンドを使用して取得する"
+"telegramNotifyTime" = "通知時間"
+"telegramNotifyTimeDesc" = "定期的なTelegramボット通知時間を設定する(crontab時間形式を使用)"
+"tgNotifyBackup" = "データベースバックアップ"
+"tgNotifyBackupDesc" = "レポート付きのデータベースバックアップファイルを送信"
+"tgNotifyLogin" = "ログイン通知"
+"tgNotifyLoginDesc" = "誰かがパネルにログインしようとしたときに、ユーザー名、IPアドレス、時間を表示する"
+"sessionMaxAge" = "セッション期間"
+"sessionMaxAgeDesc" = "ログイン状態を保持する期間(単位:分)"
+"expireTimeDiff" = "有効期限通知のしきい値"
+"expireTimeDiffDesc" = "このしきい値に達した場合、有効期限に関する通知を受け取る(単位:日)"
+"trafficDiff" = "トラフィック消耗しきい値"
+"trafficDiffDesc" = "このしきい値に達した場合、トラフィック消耗に関する通知を受け取る(単位:GB)"
+"tgNotifyCpu" = "CPU負荷通知しきい値"
+"tgNotifyCpuDesc" = "CPU負荷がこのしきい値を超えた場合、通知を受け取る(単位:%)"
+"timeZone" = "タイムゾーン"
+"timeZoneDesc" = "定時タスクはこのタイムゾーンの時間に従って実行される"
+"subSettings" = "サブスクリプション設定"
+"subEnable" = "サブスクリプションサービスを有効にする"
+"subEnableDesc" = "サブスクリプションサービス機能を有効にする"
+"subListen" = "監視IP"
+"subListenDesc" = "サブスクリプションサービスが監視するIPアドレス(空白にするとすべてのIPを監視)"
+"subPort" = "監視ポート"
+"subPortDesc" = "サブスクリプションサービスが監視するポート番号(使用されていないポートである必要があります)"
+"subCertPath" = "公開鍵パス"
+"subCertPathDesc" = "サブスクリプションサービスで使用する公開鍵ファイルのパス('/'で始まる)"
+"subKeyPath" = "秘密鍵パス"
+"subKeyPathDesc" = "サブスクリプションサービスで使用する秘密鍵ファイルのパス('/'で始まる)"
+"subPath" = "URIパス"
+"subPathDesc" = "サブスクリプションサービスで使用するURIパス('/'で始まり、'/'で終わる)"
+"subDomain" = "監視ドメイン"
+"subDomainDesc" = "サブスクリプションサービスが監視するドメイン(空白にするとすべてのドメインとIPを監視)"
+"subUpdates" = "更新間隔"
+"subUpdatesDesc" = "クライアントアプリケーションでサブスクリプションURLの更新間隔(単位:時間)"
+"subEncrypt" = "エンコード"
+"subEncryptDesc" = "サブスクリプションサービスが返す内容をBase64エンコードする"
+"subShowInfo" = "利用情報を表示"
+"subShowInfoDesc" = "クライアントアプリで残りのトラフィックと日付情報を表示する"
+"subURI" = "リバースプロキシURI"
+"subURIDesc" = "プロキシ後ろのサブスクリプションURLのURIパスに使用する"
+"fragment" = "フラグメント"
+"fragmentDesc" = "TLS helloパケットのフラグメントを有効にする"
+"fragmentSett" = "設定"
+"noisesDesc" = "Noisesを有効にする"
+"noisesSett" = "Noises設定"
+"mux" = "マルチプレクサ"
+"muxDesc" = "確立されたストリーム内で複数の独立したストリームを伝送する"
+"muxSett" = "マルチプレクサ設定"
+"direct" = "直接接続"
+"directDesc" = "特定の国のドメインまたはIP範囲に直接接続する"
+
+
+[pages.xray]
+"title" = "Xray 設定"
+"save" = "保存"
+"restart" = "Xray 再起動"
+"basicTemplate" = "基本設定"
+"advancedTemplate" = "高度な設定"
+"generalConfigs" = "一般設定"
+"generalConfigsDesc" = "これらのオプションは一般設定を決定します"
+"logConfigs" = "ログ"
+"logConfigsDesc" = "ログはサーバーのパフォーマンスに影響を与える可能性があるため、必要な場合にのみ有効にすることをお勧めします"
+"blockConfigs" = "防御フィルター"
+"blockConfigsDesc" = "これらのオプションは、特定のプロトコルやウェブサイトへのユーザー接続をブロックします"
+"basicRouting" = "基本ルーティング"
+"blockConnectionsConfigsDesc" = "これらのオプションにより、特定のリクエスト元の国に基づいてトラフィックをブロックします。"
+"directConnectionsConfigsDesc" = "直接接続により、特定のトラフィックが他のサーバーを経由しないようにします。"
+"blockips" = "IPをブロック"
+"blockdomains" = "ドメインをブロック"
+"directips" = "直接IP"
+"directdomains" = "直接ドメイン"
+"ipv4Routing" = "IPv4 ルーティング"
+"ipv4RoutingDesc" = "このオプションはIPv4のみを介してターゲットドメインへルーティングします"
+"warpRouting" = "WARP ルーティング"
+"warpRoutingDesc" = "注意:これらのオプションを使用する前に、パネルのGitHubの手順に従って、サーバーにsocks5プロキシモードでWARPをインストールしてください。WARPはCloudflareサーバー経由でトラフィックをウェブサイトにルーティングします。"
+"Template" = "高度なXray設定テンプレート"
+"TemplateDesc" = "最終的なXray設定ファイルはこのテンプレートに基づいて生成されます"
+"FreedomStrategy" = "Freedom プロトコル戦略"
+"FreedomStrategyDesc" = "Freedomプロトコル内のネットワークの出力戦略を設定する"
+"RoutingStrategy" = "ルーティングドメイン戦略設定"
+"RoutingStrategyDesc" = "DNS解決の全体的なルーティング戦略を設定する"
+"Torrent" = "BitTorrent プロトコルをブロック"
+"TorrentDesc" = "BitTorrentの使用を禁止する"
+"Family" = "ファミリー保護"
+"FamilyDesc" = "アダルトコンテンツや悪意のあるサイトをブロックする"
+"Inbounds" = "インバウンドルール"
+"InboundsDesc" = "特定のクライアントからのトラフィックを受け入れる"
+"Outbounds" = "アウトバウンドルール"
+"Balancers" = "負荷分散"
+"OutboundsDesc" = "アウトバウンドトラフィックの送信方法を設定する"
+"Routings" = "ルーティングルール"
+"RoutingsDesc" = "各ルールの優先順位が重要です"
+"completeTemplate" = "すべて"
+"logLevel" = "ログレベル"
+"logLevelDesc" = "エラーログのレベルを指定し、記録する情報を示します"
+"accessLog" = "アクセスログ"
+"accessLogDesc" = "アクセスログのファイルパス。特殊値 'none' はアクセスログを無効にします"
+"errorLog" = "エラーログ"
+"errorLogDesc" = "エラーログのファイルパス。特殊値 'none' はエラーログを無効にします"
+"dnsLog" = "DNS ログ"
+"dnsLogDesc" = "DNSクエリのログを有効にするかどうか"
+"maskAddress" = "アドレスをマスク"
+"maskAddressDesc" = "IPアドレスをマスクし、有効にするとログに表示されるIPアドレスを自動的に置き換えます"
+
+[pages.xray.rules]
+"first" = "最初"
+"last" = "最後"
+"up" = "上へ"
+"down" = "下へ"
+"source" = "ソース"
+"dest" = "宛先アドレス"
+"inbound" = "インバウンド"
+"outbound" = "アウトバウンド"
+"balancer" = "負荷分散"
+"info" = "情報"
+"add" = "ルール追加"
+"edit" = "ルール編集"
+"useComma" = "カンマ区切りの項目"
+
+[pages.xray.outbound]
+"addOutbound" = "アウトバウンド追加"
+"addReverse" = "リバース追加"
+"editOutbound" = "アウトバウンド編集"
+"editReverse" = "リバース編集"
+"tag" = "タグ"
+"tagDesc" = "一意のタグ"
+"address" = "アドレス"
+"reverse" = "リバース"
+"domain" = "ドメイン"
+"type" = "タイプ"
+"bridge" = "ブリッジ"
+"portal" = "ポータル"
+"intercon" = "インターコネクション"
+"settings" = "設定"
+"accountInfo" = "アカウント情報"
+"outboundStatus" = "アウトバウンドステータス"
+"sendThrough" = "送信経路"
+
+[pages.xray.balancer]
+"addBalancer" = "負荷分散追加"
+"editBalancer" = "負荷分散編集"
+"balancerStrategy" = "戦略"
+"balancerSelectors" = "セレクター"
+"tag" = "タグ"
+"tagDesc" = "一意のタグ"
+"balancerDesc" = "balancerTagとoutboundTagは同時に使用できません。同時に使用された場合、outboundTagのみが有効になります。"
+
+[pages.xray.wireguard]
+"secretKey" = "シークレットキー"
+"publicKey" = "公開鍵"
+"allowedIPs" = "許可されたIP"
+"endpoint" = "エンドポイント"
+"psk" = "共有キー"
+"domainStrategy" = "ドメイン戦略"
+
+[pages.xray.dns]
+"enable" = "DNSを有効にする"
+"enableDesc" = "組み込みDNSサーバーを有効にする"
+"tag" = "DNSインバウンドタグ"
+"tagDesc" = "このタグはルーティングルールでインバウンドタグとして使用できます"
+"strategy" = "クエリ戦略"
+"strategyDesc" = "ドメイン名解決の全体的な戦略"
+"add" = "サーバー追加"
+"edit" = "サーバー編集"
+"domains" = "ドメイン"
+"expectIPs" = "期待されるIP"
+
+[pages.xray.fakedns]
+"add" = "フェイクDNS追加"
+"edit" = "フェイクDNS編集"
+"ipPool" = "IPプールサブネット"
+"poolSize" = "プールサイズ"
+
+[pages.settings.security]
+"admin" = "管理者"
+"secret" = "セキュリティトークン"
+"loginSecurity" = "ログインセキュリティ"
+"loginSecurityDesc" = "追加の認証を追加してセキュリティを向上させる"
+"secretToken" = "セキュリティトークン"
+"secretTokenDesc" = "このトークンを安全な場所に保管してください。このトークンはログインに使用され、紛失すると回復できません。"
+
+[pages.settings.toasts]
+"modifySettings" = "設定を変更"
+"getSettings" = "設定を取得"
+"modifyUser" = "管理者を変更"
+"originalUserPassIncorrect" = "旧ユーザー名または旧パスワードが間違っています"
+"userPassMustBeNotEmpty" = "新しいユーザー名と新しいパスワードは空にできません"
+
+[tgbot]
+"keyboardClosed" = "❌ カスタムキーボードが閉じられました!"
+"noResult" = "❗ 結果がありません!"
+"noQuery" = "❌ クエリが見つかりませんでした!もう一度コマンドを使用してください!"
+"wentWrong" = "❌ 問題が発生しました!"
+"noIpRecord" = "❗ IP記録がありません!"
+"noInbounds" = "❗ インバウンド接続が見つかりません!"
+"unlimited" = "♾ 無制限"
+"add" = "追加"
+"month" = "月"
+"months" = "月"
+"day" = "日"
+"days" = "日"
+"hours" = "時間"
+"unknown" = "不明"
+"inbounds" = "インバウンド接続"
+"clients" = "クライアント"
+"offline" = "🔴 オフライン"
+"online" = "🟢 オンライン"
+
+[tgbot.commands]
+"unknown" = "❗ 不明なコマンド"
+"pleaseChoose" = "👇 選択してください:\r\n"
+"help" = "🤖 このボットをご利用いただきありがとうございます!サーバーから特定のデータを提供し、必要な変更を行うことができます。\r\n\r\n"
+"start" = "👋 こんにちは、{{ .Firstname }} 。\r\n"
+"welcome" = "🤖 {{ .Hostname }} 管理ボットへようこそ。\r\n"
+"status" = "✅ ボットは正常に動作しています!"
+"usage" = "❗ 検索するテキストを入力してください!"
+"getID" = "🆔 あなたのIDは:{{ .ID }}
"
+"helpAdminCommands" = "Xray Coreを再起動するには:\r\n/restart force
\r\n\r\nクライアントの電子メールを検索するには:\r\n/usage [電子メール]
\r\n\r\nインバウンド(クライアントの統計情報を含む)を検索するには:\r\n/inbound [備考]
\r\n\r\nTelegramチャットID:\r\n/id
"
+"helpClientCommands" = "統計情報を検索するには、次のコマンドを使用してください:\r\n/usage [電子メール]
\r\n\r\nTelegramチャットID:\r\n/id
"
+"restartUsage" = "\r\n\r\n/restart force
"
+"restartSuccess" = "✅ 操作成功!"
+"restartFailed" = "❗ 操作エラー。\r\n\r\nエラー: {{ .Error }}
"
+"xrayNotRunning" = "❗ Xray Core は動作していません。"
+
+[tgbot.messages]
+"cpuThreshold" = "🔴 CPU使用率は{{ .Percent }}%、しきい値{{ .Threshold }}%を超えました"
+"selectUserFailed" = "❌ ユーザーの選択に失敗しました!"
+"userSaved" = "✅ Telegramユーザーが保存されました。"
+"loginSuccess" = "✅ パネルに正常にログインしました。\r\n"
+"loginFailed" = "❗️ パネルのログインに失敗しました。\r\n"
+"report" = "🕰 定期報告:{{ .RunTime }}\r\n"
+"datetime" = "⏰ 日時:{{ .DateTime }}\r\n"
+"hostname" = "💻 ホスト名:{{ .Hostname }}\r\n"
+"version" = "🚀 X-UI バージョン:{{ .Version }}\r\n"
+"xrayVersion" = "📡 Xray バージョン: {{ .XrayVersion }}\r\n"
+"ipv6" = "🌐 IPv6:{{ .IPv6 }}\r\n"
+"ipv4" = "🌐 IPv4:{{ .IPv4 }}\r\n"
+"ip" = "🌐 IP:{{ .IP }}\r\n"
+"ips" = "🔢 IPアドレス:\r\n{{ .IPs }}\r\n"
+"serverUpTime" = "⏳ サーバー稼働時間:{{ .UpTime }} {{ .Unit }}\r\n"
+"serverLoad" = "📈 サーバー負荷:{{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n"
+"serverMemory" = "📋 サーバーメモリ:{{ .Current }}/{{ .Total }}\r\n"
+"tcpCount" = "🔹 TCP接続数:{{ .Count }}\r\n"
+"udpCount" = "🔸 UDP接続数:{{ .Count }}\r\n"
+"traffic" = "🚦 トラフィック:{{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
+"xrayStatus" = "ℹ️ Xrayステータス:{{ .State }}\r\n"
+"username" = "👤 ユーザー名:{{ .Username }}\r\n"
+"password" = "👤 パスワード: {{ .Password }}\r\n"
+"time" = "⏰ 時間:{{ .Time }}\r\n"
+"inbound" = "📍 インバウンド:{{ .Remark }}\r\n"
+"port" = "🔌 ポート:{{ .Port }}\r\n"
+"expire" = "📅 有効期限:{{ .Time }}\r\n"
+"expireIn" = "📅 残り時間:{{ .Time }}\r\n"
+"active" = "💡 有効:{{ .Enable }}\r\n"
+"enabled" = "🚨 有効化済み:{{ .Enable }}\r\n"
+"online" = "🌐 接続ステータス:{{ .Status }}\r\n"
+"email" = "📧 メール:{{ .Email }}\r\n"
+"upload" = "🔼 アップロード↑:{{ .Upload }}\r\n"
+"download" = "🔽 ダウンロード↓:{{ .Download }}\r\n"
+"total" = "📊 合計:{{ .UpDown }} / {{ .Total }}\r\n"
+"TGUser" = "👤 Telegramユーザー:{{ .TelegramID }}\r\n"
+"exhaustedMsg" = "🚨 消耗済みの {{ .Type }}:\r\n"
+"exhaustedCount" = "🚨 消耗済みの {{ .Type }} 数量:\r\n"
+"onlinesCount" = "🌐 オンラインクライアント:{{ .Count }}\r\n"
+"disabled" = "🛑 無効化:{{ .Disabled }}\r\n"
+"depleteSoon" = "🔜 間もなく消耗:{{ .Deplete }}\r\n\r\n"
+"backupTime" = "🗄 バックアップ時間:{{ .Time }}\r\n"
+"refreshedOn" = "\r\n📋🔄 更新時間:{{ .Time }}\r\n\r\n"
+"yes" = "✅ はい"
+"no" = "❌ いいえ"
+
+[tgbot.buttons]
+"closeKeyboard" = "❌ キーボードを閉じる"
+"cancel" = "❌ キャンセル"
+"cancelReset" = "❌ リセットをキャンセル"
+"cancelIpLimit" = "❌ IP制限をキャンセル"
+"confirmResetTraffic" = "✅ トラフィックをリセットしますか?"
+"confirmClearIps" = "✅ IPをクリアしますか?"
+"confirmRemoveTGUser" = "✅ Telegramユーザーを削除しますか?"
+"confirmToggle" = "✅ ユーザーを有効/無効にしますか?"
+"dbBackup" = "データベースバックアップを取得"
+"serverUsage" = "サーバーの使用状況"
+"getInbounds" = "インバウンド情報を取得"
+"depleteSoon" = "間もなく消耗"
+"clientUsage" = "使用状況を取得"
+"onlines" = "オンラインクライアント"
+"commands" = "コマンド"
+"refresh" = "🔄 更新"
+"clearIPs" = "❌ IPをクリア"
+"removeTGUser" = "❌ Telegramユーザーを削除"
+"selectTGUser" = "👤 Telegramユーザーを選択"
+"selectOneTGUser" = "👤 1人のTelegramユーザーを選択:"
+"resetTraffic" = "📈 トラフィックをリセット"
+"resetExpire" = "📅 有効期限を変更"
+"ipLog" = "🔢 IPログ"
+"ipLimit" = "🔢 IP制限"
+"setTGUser" = "👤 Telegramユーザーを設定"
+"toggle" = "🔘 有効/無効"
+"custom" = "🔢 カスタム"
+"confirmNumber" = "✅ 確認: {{ .Num }}"
+"confirmNumberAdd" = "✅ 追加を確認:{{ .Num }}"
+"limitTraffic" = "🚧 トラフィック制限"
+"getBanLogs" = "禁止ログ"
+"allClients" = "すべてのクライアント"
+
+[tgbot.answers]
+"successfulOperation" = "✅ 成功!"
+"errorOperation" = "❗ 操作エラー。"
+"getInboundsFailed" = "❌ インバウンド情報の取得に失敗しました。"
+"getClientsFailed" = "❌ クライアントの取得に失敗しました。"
+"canceled" = "❌ {{ .Email }}:操作がキャンセルされました。"
+"clientRefreshSuccess" = "✅ {{ .Email }}:クライアントが正常に更新されました。"
+"IpRefreshSuccess" = "✅ {{ .Email }}:IPが正常に更新されました。"
+"TGIdRefreshSuccess" = "✅ {{ .Email }}:クライアントのTelegramユーザーが正常に更新されました。"
+"resetTrafficSuccess" = "✅ {{ .Email }}:トラフィックが正常にリセットされました。"
+"setTrafficLimitSuccess" = "✅ {{ .Email }}:トラフィック制限が正常に保存されました。"
+"expireResetSuccess" = "✅ {{ .Email }}:有効期限の日数が正常にリセットされました。"
+"resetIpSuccess" = "✅ {{ .Email }}:IP制限数が正常に保存されました:{{ .Count }}。"
+"clearIpSuccess" = "✅ {{ .Email }}:IPが正常にクリアされました。"
+"getIpLog" = "✅ {{ .Email }}:IPログの取得。"
+"getUserInfo" = "✅ {{ .Email }}:Telegramユーザー情報の取得。"
+"removedTGUserSuccess" = "✅ {{ .Email }}:Telegramユーザーが正常に削除されました。"
+"enableSuccess" = "✅ {{ .Email }}:正常に有効化されました。"
+"disableSuccess" = "✅ {{ .Email }}:正常に無効化されました。"
+"askToAddUserId" = "設定が見つかりませんでした!\r\n管理者に問い合わせて、設定にTelegramユーザーのChatIDを使用してください。\r\n\r\nあなたのユーザーChatID:{{ .TgUserID }}
"
+"chooseClient" = "インバウンド {{ .Inbound }} のクライアントを選択"
+"chooseInbound" = "インバウンドを選択"
diff --git a/x-ui.sh b/x-ui.sh
index a3c0469b..f4a08862 100644
--- a/x-ui.sh
+++ b/x-ui.sh
@@ -164,7 +164,7 @@ update() {
bash <(curl -Ls https://raw.githubusercontent.com/Suiranoil/3x-ui/main/install.sh)
if [[ $? == 0 ]]; then
LOGI "Update is complete, Panel has automatically restarted "
- exit 0
+ before_show_menu
fi
}
@@ -185,7 +185,7 @@ update_menu() {
if [[ $? == 0 ]]; then
echo -e "${green}Update successful. The panel has automatically restarted.${plain}"
- exit 0
+ before_show_menu
else
echo -e "${red}Failed to update the menu.${plain}"
return 1
@@ -294,8 +294,8 @@ reset_config() {
return 0
fi
/usr/local/x-ui/x-ui setting -reset
- echo -e "All panel settings have been reset to default, Please restart the panel now, and use the default ${green}2053${plain} Port to Access the web Panel"
- confirm_restart
+ echo -e "All panel settings have been reset to default."
+ restart
}
check_config() {
@@ -309,9 +309,20 @@ check_config() {
local existing_webBasePath=$(echo "$info" | grep -Eo 'webBasePath: .+' | awk '{print $2}')
local existing_port=$(echo "$info" | grep -Eo 'port: .+' | awk '{print $2}')
+ local existing_cert=$(/usr/local/x-ui/x-ui setting -getCert true | grep -Eo 'cert: .+' | awk '{print $2}')
local server_ip=$(curl -s https://api.ipify.org)
- echo -e "${green}Access URL: http://${server_ip}:${existing_port}${existing_webBasePath}${plain}"
+ if [[ -n "$existing_cert" ]]; then
+ local domain=$(basename "$(dirname "$existing_cert")")
+
+ if [[ "$domain" =~ ^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
+ echo -e "${green}Access URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}"
+ else
+ echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}"
+ fi
+ else
+ echo -e "${green}Access URL: http://${server_ip}:${existing_port}${existing_webBasePath}${plain}"
+ fi
}
set_port() {
@@ -423,7 +434,7 @@ show_log() {
case "$choice" in
0)
- return
+ show_menu
;;
1)
journalctl -u x-ui -e --no-pager -f -p debug
@@ -438,21 +449,41 @@ show_log() {
restart
;;
*)
- echo "Invalid choice"
+ echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
+ show_log
;;
esac
}
show_banlog() {
- if test -f "${iplimit_banned_log_path}"; then
+ local system_log="/var/log/fail2ban.log"
+
+ echo -e "${green}Checking ban logs...${plain}\n"
+
+ if ! systemctl is-active --quiet fail2ban; then
+ echo -e "${red}Fail2ban service is not running!${plain}\n"
+ return 1
+ fi
+
+ if [[ -f "$system_log" ]]; then
+ echo -e "${green}Recent system ban activities from fail2ban.log:${plain}"
+ grep "3x-ipl" "$system_log" | grep -E "Ban|Unban" | tail -n 10 || echo -e "${yellow}No recent system ban activities found${plain}"
+ echo ""
+ fi
+
+ if [[ -f "${iplimit_banned_log_path}" ]]; then
+ echo -e "${green}3X-IPL ban log entries:${plain}"
if [[ -s "${iplimit_banned_log_path}" ]]; then
- cat ${iplimit_banned_log_path}
+ grep -v "INIT" "${iplimit_banned_log_path}" | tail -n 10 || echo -e "${yellow}No ban entries found${plain}"
else
- echo -e "${red}Log file is empty.${plain}\n"
+ echo -e "${yellow}Ban log file is empty${plain}"
fi
else
- echo -e "${red}Log file not found. Please Install Fail2ban and IP Limit first.${plain}\n"
+ echo -e "${red}Ban log file not found at: ${iplimit_banned_log_path}${plain}"
fi
+
+ echo -e "\n${green}Current jail status:${plain}"
+ fail2ban-client status 3x-ipl || echo -e "${yellow}Unable to get jail status${plain}"
}
bbr_menu() {
@@ -466,11 +497,16 @@ bbr_menu() {
;;
1)
enable_bbr
+ bbr_menu
;;
2)
disable_bbr
+ bbr_menu
+ ;;
+ *)
+ echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
+ bbr_menu
;;
- *) echo "Invalid choice" ;;
esac
}
@@ -478,7 +514,7 @@ disable_bbr() {
if ! grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf || ! grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
echo -e "${yellow}BBR is not currently enabled.${plain}"
- exit 0
+ before_show_menu
fi
# Replace BBR with CUBIC configurations
@@ -499,7 +535,7 @@ disable_bbr() {
enable_bbr() {
if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf && grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
echo -e "${green}BBR is already enabled!${plain}"
- exit 0
+ before_show_menu
fi
# Check the OS and install necessary packages
@@ -545,7 +581,8 @@ update_shell() {
before_show_menu
else
chmod +x /usr/bin/x-ui
- LOGI "Upgrade script succeeded, Please rerun the script" && exit 0
+ LOGI "Upgrade script succeeded, Please rerun the script"
+ before_show_menu
fi
}
@@ -657,17 +694,24 @@ firewall_menu() {
;;
1)
open_ports
+ firewall_menu
;;
2)
sudo ufw status
+ firewall_menu
;;
3)
delete_ports
+ firewall_menu
;;
4)
sudo ufw disable
+ firewall_menu
+ ;;
+ *)
+ echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
+ firewall_menu
;;
- *) echo "Invalid choice" ;;
esac
}
@@ -774,7 +818,6 @@ update_geo() {
echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " choice
- systemctl stop x-ui
cd /usr/local/x-ui/bin
case "$choice" in
@@ -782,29 +825,35 @@ update_geo() {
show_menu
;;
1)
+ systemctl stop x-ui
rm -f geoip.dat geosite.dat
wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
echo -e "${green}Loyalsoldier datasets have been updated successfully!${plain}"
+ restart
;;
2)
+ systemctl stop x-ui
rm -f geoip_IR.dat geosite_IR.dat
wget -O geoip_IR.dat -N https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
wget -O geosite_IR.dat -N https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
echo -e "${green}chocolate4u datasets have been updated successfully!${plain}"
+ restart
;;
3)
+ systemctl stop x-ui
rm -f geoip_VN.dat geosite_VN.dat
wget -O geoip_VN.dat -N https://github.com/vuong2023/vn-v2ray-rules/releases/latest/download/geoip.dat
wget -O geosite_VN.dat -N https://github.com/vuong2023/vn-v2ray-rules/releases/latest/download/geosite.dat
echo -e "${green}vuong2023 datasets have been updated successfully!${plain}"
+ restart
;;
*)
- echo "Invalid option selected! No updates made."
+ echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
+ update_geo
;;
esac
- systemctl start x-ui
before_show_menu
}
@@ -844,6 +893,7 @@ ssl_cert_issue_main() {
;;
1)
ssl_cert_issue
+ ssl_cert_issue_main
;;
2)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
@@ -860,6 +910,7 @@ ssl_cert_issue_main() {
echo "Invalid domain entered."
fi
fi
+ ssl_cert_issue_main
;;
3)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
@@ -876,6 +927,7 @@ ssl_cert_issue_main() {
echo "Invalid domain entered."
fi
fi
+ ssl_cert_issue_main
;;
4)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
@@ -895,6 +947,7 @@ ssl_cert_issue_main() {
fi
done
fi
+ ssl_cert_issue_main
;;
5)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
@@ -922,15 +975,19 @@ ssl_cert_issue_main() {
echo "Invalid domain entered."
fi
fi
+ ssl_cert_issue_main
;;
*)
- echo "Invalid choice"
+ echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
+ ssl_cert_issue_main
;;
esac
}
ssl_cert_issue() {
+ local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
+ local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
# 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"
@@ -1049,6 +1106,7 @@ ssl_cert_issue() {
LOGI "Panel paths set for domain: $domain"
LOGI " - Certificate File: $webCertFile"
LOGI " - Private Key File: $webKeyFile"
+ echo -e "${green}Access URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}"
restart
else
LOGE "Error: Certificate or private key file not found for domain: $domain."
@@ -1059,76 +1117,119 @@ ssl_cert_issue() {
}
ssl_cert_issue_CF() {
- echo -E ""
- LOGD "******Instructions for use******"
- LOGI "This Acme script requires the following data:"
- LOGI "1.Cloudflare Registered e-mail"
- LOGI "2.Cloudflare Global API Key"
- LOGI "3.The domain name that has been resolved dns to the current server by Cloudflare"
- LOGI "4.The script applies for a certificate. The default installation path is /root/cert "
- confirm "Confirmed?[y/n]" "y"
+ local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
+ local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
+ LOGI "****** Instructions for Use ******"
+ LOGI "Follow the steps below to complete the process:"
+ LOGI "1. Cloudflare Registered E-mail."
+ LOGI "2. Cloudflare Global API Key."
+ LOGI "3. The Domain Name."
+ LOGI "4. Once the certificate is issued, you will be prompted to set the certificate for the panel (optional)."
+ LOGI "5. The script also supports automatic renewal of the SSL certificate after installation."
+
+ confirm "Do you confirm the information and wish to proceed? [y/n]" "y"
+
if [ $? -eq 0 ]; then
- # check for acme.sh first
+ # 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"
+ echo "acme.sh could not be found. We will install it."
install_acme
if [ $? -ne 0 ]; then
- LOGE "install acme failed, please check logs"
+ LOGE "Install acme failed, please check logs."
exit 1
fi
fi
+
CF_Domain=""
- CF_GlobalKey=""
- CF_AccountEmail=""
- certPath=/root/cert
+ certPath="/root/cert-CF"
if [ ! -d "$certPath" ]; then
- mkdir $certPath
+ mkdir -p $certPath
else
rm -rf $certPath
- mkdir $certPath
+ mkdir -p $certPath
fi
+
LOGD "Please set a domain name:"
- read -p "Input your domain here:" CF_Domain
- LOGD "Your domain name is set to:${CF_Domain}"
+ read -p "Input your domain here: " CF_Domain
+ LOGD "Your domain name is set to: ${CF_Domain}"
+
+ # Set up Cloudflare API details
+ CF_GlobalKey=""
+ CF_AccountEmail=""
LOGD "Please set the API key:"
- read -p "Input your key here:" CF_GlobalKey
- LOGD "Your API key is:${CF_GlobalKey}"
+ read -p "Input your key here: " CF_GlobalKey
+ LOGD "Your API key is: ${CF_GlobalKey}"
+
LOGD "Please set up registered email:"
- read -p "Input your email here:" CF_AccountEmail
- LOGD "Your registered email address is:${CF_AccountEmail}"
+ read -p "Input your email here: " CF_AccountEmail
+ LOGD "Your registered email address is: ${CF_AccountEmail}"
+
+ # Set the default CA to Let's Encrypt
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
if [ $? -ne 0 ]; then
- LOGE "Default CA, Lets'Encrypt fail, script exiting..."
+ LOGE "Default CA, Let'sEncrypt fail, script exiting..."
exit 1
fi
+
export CF_Key="${CF_GlobalKey}"
- export CF_Email=${CF_AccountEmail}
+ export CF_Email="${CF_AccountEmail}"
+
+ # Issue the certificate using Cloudflare DNS
~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log
if [ $? -ne 0 ]; then
LOGE "Certificate issuance failed, script exiting..."
exit 1
else
- LOGI "Certificate issued Successfully, Installing..."
+ LOGI "Certificate issued successfully, Installing..."
fi
- ~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} --ca-file /root/cert/ca.cer \
- --cert-file /root/cert/${CF_Domain}.cer --key-file /root/cert/${CF_Domain}.key \
- --fullchain-file /root/cert/fullchain.cer
+
+ # Install the certificate
+ mkdir -p ${certPath}/${CF_Domain}
+ if [ $? -ne 0 ]; then
+ LOGE "Failed to create directory: ${certPath}/${CF_Domain}"
+ exit 1
+ fi
+
+ ~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} \
+ --fullchain-file ${certPath}/${CF_Domain}/fullchain.pem \
+ --key-file ${certPath}/${CF_Domain}/privkey.pem
+
if [ $? -ne 0 ]; then
LOGE "Certificate installation failed, script exiting..."
exit 1
else
- LOGI "Certificate installed Successfully,Turning on automatic updates..."
+ LOGI "Certificate installed successfully, Turning on automatic updates..."
fi
+
+ # Enable auto-update
~/.acme.sh/acme.sh --upgrade --auto-upgrade
if [ $? -ne 0 ]; then
- LOGE "Auto update setup Failed, script exiting..."
- ls -lah cert
- chmod 755 $certPath
+ LOGE "Auto update setup failed, script exiting..."
exit 1
else
- LOGI "The certificate is installed and auto-renewal is turned on, Specific information is as follows"
- ls -lah cert
- chmod 755 $certPath
+ LOGI "The certificate is installed and auto-renewal is turned on. Specific information is as follows:"
+ ls -lah ${certPath}/${CF_Domain}
+ chmod 755 ${certPath}/${CF_Domain}
+ fi
+
+ # Prompt user to set panel paths after successful certificate installation
+ read -p "Would you like to set this certificate for the panel? (y/n): " setPanel
+ if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
+ local webCertFile="${certPath}/${CF_Domain}/fullchain.pem"
+ local webKeyFile="${certPath}/${CF_Domain}/privkey.pem"
+
+ if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then
+ /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
+ LOGI "Panel paths set for domain: $CF_Domain"
+ LOGI " - Certificate File: $webCertFile"
+ LOGI " - Private Key File: $webKeyFile"
+ echo -e "${green}Access URL: https://${CF_Domain}:${existing_port}${existing_webBasePath}${plain}"
+ restart
+ else
+ LOGE "Error: Certificate or private key file not found for domain: $CF_Domain."
+ fi
+ else
+ LOGI "Skipping panel path setting."
fi
else
show_menu
@@ -1138,34 +1239,41 @@ ssl_cert_issue_CF() {
run_speedtest() {
# Check if Speedtest is already installed
if ! command -v speedtest &>/dev/null; then
- # If not installed, install it
- local pkg_manager=""
- local speedtest_install_script=""
-
- if command -v dnf &>/dev/null; then
- pkg_manager="dnf"
- speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh"
- elif command -v yum &>/dev/null; then
- pkg_manager="yum"
- speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh"
- elif command -v apt-get &>/dev/null; then
- pkg_manager="apt-get"
- speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh"
- elif command -v apt &>/dev/null; then
- pkg_manager="apt"
- speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh"
- fi
-
- if [[ -z $pkg_manager ]]; then
- echo "Error: Package manager not found. You may need to install Speedtest manually."
- return 1
+ # If not installed, determine installation method
+ if command -v snap &>/dev/null; then
+ # Use snap to install Speedtest
+ echo "Installing Speedtest using snap..."
+ snap install speedtest
else
- curl -s $speedtest_install_script | bash
- $pkg_manager install -y speedtest
+ # Fallback to using package managers
+ local pkg_manager=""
+ local speedtest_install_script=""
+
+ if command -v dnf &>/dev/null; then
+ pkg_manager="dnf"
+ speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh"
+ elif command -v yum &>/dev/null; then
+ pkg_manager="yum"
+ speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh"
+ elif command -v apt-get &>/dev/null; then
+ pkg_manager="apt-get"
+ speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh"
+ elif command -v apt &>/dev/null; then
+ pkg_manager="apt"
+ speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh"
+ fi
+
+ if [[ -z $pkg_manager ]]; then
+ echo "Error: Package manager not found. You may need to install Speedtest manually."
+ return 1
+ else
+ echo "Installing Speedtest using $pkg_manager..."
+ curl -s $speedtest_install_script | bash
+ $pkg_manager install -y speedtest
+ fi
fi
fi
- # Run Speedtest
speedtest
}
@@ -1186,7 +1294,7 @@ create_iplimit_jails() {
enabled=true
backend=auto
filter=3x-ipl
-action = %(known/action)s[name=%(__name__)s, protocol="%(protocol)s", chain="%(chain)s"]
+action=3x-ipl
logpath=${iplimit_log_path}
maxretry=2
findtime=32
@@ -1222,8 +1330,6 @@ actionunban = -D f2b- -s -j
echo "\$(date +"%%Y/%%m/%%d %%H:%%M:%%S") UNBAN [Email] = [IP] = unbanned." >> ${iplimit_banned_log_path}
[Init]
-# Use default settings from iptables-common.conf
-# This will automatically handle both IPv4 and IPv6
name = default
protocol = tcp
chain = INPUT
@@ -1283,7 +1389,7 @@ iplimit_main() {
3)
confirm "Proceed with Unbanning everyone from IP Limit jail?" "y"
if [[ $? == 0 ]]; then
- fail2ban-client reload --restart --unban 3x-ipl
+ fail2ban-client set 3x-ipl unban --all
truncate -s 0 "${iplimit_banned_log_path}"
echo -e "${green}All users Unbanned successfully.${plain}"
iplimit_main
@@ -1294,20 +1400,28 @@ iplimit_main() {
;;
4)
show_banlog
+ iplimit_main
;;
5)
tail -f /var/log/fail2ban.log
+ iplimit_main
;;
6)
service fail2ban status
+ iplimit_main
;;
7)
systemctl restart fail2ban
+ iplimit_main
;;
8)
remove_iplimit
+ iplimit_main
+ ;;
+ *)
+ echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
+ iplimit_main
;;
- *) echo "Invalid choice" ;;
esac
}
@@ -1388,7 +1502,7 @@ install_iplimit() {
remove_iplimit() {
echo -e "${green}\t1.${plain} Only remove IP Limit configurations"
echo -e "${green}\t2.${plain} Uninstall Fail2ban and IP Limit"
- echo -e "${green}\t0.${plain} Abort"
+ echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " num
case "$num" in
1)
@@ -1428,8 +1542,7 @@ remove_iplimit() {
before_show_menu
;;
0)
- echo -e "${yellow}Cancelled.${plain}\n"
- iplimit_main
+ show_menu
;;
*)
echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
@@ -1451,14 +1564,14 @@ SSH_port_forwarding() {
if [[ -n "$existing_cert" && -n "$existing_key" ]]; then
echo -e "${green}Panel is secure with SSL.${plain}"
- return 0
+ before_show_menu
fi
- if [[ -z "$existing_cert" && -z "$existing_key" && -z "$existing_listenIP" ]]; then
- echo -e "\n${red}Warning: No Cert and Key found! The panel is not secure.${plain}"
- echo "Please obtain a certificate or set up SSH port forwarding."
+ if [[ -z "$existing_cert" && -z "$existing_key" && (-z "$existing_listenIP" || "$existing_listenIP" == "0.0.0.0") ]]; then
+ echo -e "\n${red}Warning: No Cert and Key found! The panel is not secure.${plain}"
+ echo "Please obtain a certificate or set up SSH port forwarding."
fi
- if [[ -n "$existing_listenIP" && (-z "$existing_cert" && -z "$existing_key") ]]; then
+ if [[ -n "$existing_listenIP" && "$existing_listenIP" != "0.0.0.0" && (-z "$existing_cert" && -z "$existing_key") ]]; then
echo -e "\n${green}Current SSH Port Forwarding Configuration:${plain}"
echo -e "Standard SSH command:"
echo -e "${yellow}ssh -L 2222:${existing_listenIP}:${existing_port} root@${server_ip}${plain}"
@@ -1467,53 +1580,51 @@ SSH_port_forwarding() {
echo -e "\nAfter connecting, access the panel at:"
echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}"
fi
-
+
echo -e "\nChoose an option:"
echo -e "${green}1.${plain} Set listen IP"
echo -e "${green}2.${plain} Clear listen IP"
- echo -e "${green}0.${plain} Abort"
+ echo -e "${green}0.${plain} Back to Main Menu"
read -p "Choose an option: " num
case "$num" in
- 1)
- if [[ -z "$existing_listenIP" ]]; then
- echo -e "\nNo listenIP configured. Choose an option:"
- echo -e "1. Use default IP (127.0.0.1)"
- echo -e "2. Set a custom IP"
- read -p "Select an option (1 or 2): " listen_choice
+ 1)
+ if [[ -z "$existing_listenIP" || "$existing_listenIP" == "0.0.0.0" ]]; then
+ echo -e "\nNo listenIP configured. Choose an option:"
+ echo -e "1. Use default IP (127.0.0.1)"
+ echo -e "2. Set a custom IP"
+ read -p "Select an option (1 or 2): " listen_choice
- config_listenIP="127.0.0.1"
- [[ "$listen_choice" == "2" ]] && read -p "Enter custom IP to listen on: " config_listenIP
+ config_listenIP="127.0.0.1"
+ [[ "$listen_choice" == "2" ]] && read -p "Enter custom IP to listen on: " config_listenIP
- /usr/local/x-ui/x-ui setting -listenIP "${config_listenIP}" >/dev/null 2>&1
- echo -e "${green}listen IP has been set to ${config_listenIP}.${plain}"
- restart
- else
- config_listenIP="${existing_listenIP}"
- echo -e "${green}Current listen IP is already set to ${config_listenIP}.${plain}"
- fi
-
- if [[ -n "${config_listenIP}" ]]; then
- echo -e "\n${green}SSH Port Forwarding Configuration:${plain}"
- echo -e "Standard SSH command:"
- echo -e "${yellow}ssh -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}"
- echo -e "\nIf using SSH key:"
- echo -e "${yellow}ssh -i -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}"
- echo -e "\nAfter connecting, access the panel at:"
- echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}"
- fi
- ;;
- 2)
- /usr/local/x-ui/x-ui setting -listenIP ' ' >/dev/null 2>&1
- echo -e "${green}Listen IP has been cleared.${plain}"
+ /usr/local/x-ui/x-ui setting -listenIP "${config_listenIP}" >/dev/null 2>&1
+ echo -e "${green}listen IP has been set to ${config_listenIP}.${plain}"
+ echo -e "\n${green}SSH Port Forwarding Configuration:${plain}"
+ echo -e "Standard SSH command:"
+ echo -e "${yellow}ssh -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}"
+ echo -e "\nIf using SSH key:"
+ echo -e "${yellow}ssh -i -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}"
+ echo -e "\nAfter connecting, access the panel at:"
+ echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}"
restart
- ;;
- 0)
- echo "Operation aborted."
- ;;
- *)
- echo "Invalid option. Exiting."
- ;;
+ else
+ config_listenIP="${existing_listenIP}"
+ echo -e "${green}Current listen IP is already set to ${config_listenIP}.${plain}"
+ fi
+ ;;
+ 2)
+ /usr/local/x-ui/x-ui setting -listenIP 0.0.0.0 >/dev/null 2>&1
+ echo -e "${green}Listen IP has been cleared.${plain}"
+ restart
+ ;;
+ 0)
+ show_menu
+ ;;
+ *)
+ echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
+ SSH_port_forwarding
+ ;;
esac
}
diff --git a/xray/api.go b/xray/api.go
index d0de76e8..727ab526 100644
--- a/xray/api.go
+++ b/xray/api.go
@@ -129,7 +129,7 @@ func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]in
CipherType: ssCipherType,
})
} else {
- account = serial.ToTypedMessage(&shadowsocks_2022.User{
+ account = serial.ToTypedMessage(&shadowsocks_2022.ServerConfig{
Key: user["password"].(string),
Email: user["email"].(string),
})
diff --git a/xray/log_writer.go b/xray/log_writer.go
index c8d966b5..cc00d541 100644
--- a/xray/log_writer.go
+++ b/xray/log_writer.go
@@ -16,11 +16,24 @@ type LogWriter struct {
}
func (lw *LogWriter) Write(m []byte) (n int, err error) {
- regex := regexp.MustCompile(`^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[([^\]]+)\] (.+)$`)
+ crashRegex := regexp.MustCompile(`(?i)(panic|exception|stack trace|fatal error)`)
+
// Convert the data to a string
message := strings.TrimSpace(string(m))
+
+ // Check if the message contains a crash
+ if crashRegex.MatchString(message) {
+ logger.Debug("Core crash detected:\n", message)
+ lw.lastLine = message
+ err1 := writeCrachReport(m)
+ if err1 != nil {
+ logger.Error("Unable to write crash report:", err1)
+ }
+ return len(m), nil
+ }
+
+ regex := regexp.MustCompile(`^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[([^\]]+)\] (.+)$`)
messages := strings.Split(message, "\n")
- lw.lastLine = messages[len(messages)-1]
for _, msg := range messages {
matches := regex.FindStringSubmatch(msg)
@@ -42,9 +55,10 @@ func (lw *LogWriter) Write(m []byte) (n int, err error) {
default:
logger.Debug("XRAY: " + msg)
}
+ lw.lastLine = ""
} else if msg != "" {
logger.Debug("XRAY: " + msg)
- return len(m), nil
+ lw.lastLine = msg
}
}
diff --git a/xray/process.go b/xray/process.go
index db8509eb..b4947864 100644
--- a/xray/process.go
+++ b/xray/process.go
@@ -241,3 +241,8 @@ func (p *process) Stop() error {
}
return p.cmd.Process.Signal(syscall.SIGTERM)
}
+
+func writeCrachReport(m []byte) error {
+ crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log"
+ return os.WriteFile(crashReportPath, m, os.ModePerm)
+}