Compare commits

...

48 Commits

Author SHA1 Message Date
MHSanaei
195effd177 v2.4.11 2024-12-27 21:49:45 +01:00
MHSanaei
747ad3b9c8 bug fix - outbound xhttp link 2024-12-27 21:30:51 +01:00
mhsanaei
cf879f9527 bug fix - vmess tls 2024-12-27 17:59:59 +01:00
mhsanaei
04c658f1a0 Client: Comment
now you can add Comment and write anything you want to remember
2024-12-27 13:48:07 +01:00
mhsanaei
2ab1a174db moment v2.30.1 2024-12-25 20:27:48 +01:00
mhsanaei
dfca2af997 axios v1.7.9 2024-12-25 19:09:54 +01:00
Baton34
0a7d15b48c RU: translation fix (#2620) 2024-12-22 14:10:06 +01:00
mhsanaei
518bc72f90 media - telebot 2024-12-21 14:00:21 +01:00
mhsanaei
3c65209ce9 Stargazers over Time - variant=adaptive 2024-12-21 13:52:05 +01:00
LoST
174535b05d unnecessary sudo removed (#2619)
All the commands do not work exactly, but since we already work in the beginning on behalf of root, then sudo is not necessary at the beginning. Is that right? 

P.S. when selected in the menu, it says that "command not found".
2024-12-20 23:48:10 +01:00
Tara Rostami
fff54fe7f3 fix bug (#2618) 2024-12-20 19:06:19 +01:00
LoST
0859d230b0 Firewall management: improved (#2614)
* fix permissions

* Update install func + add/edit func open/close ports + status firewall

* hotfix

* subport
2024-12-20 18:43:47 +01:00
KiselevAlexander
02998c5467 Added ip limit data and controls to client info modal (#2617) 2024-12-20 18:34:30 +01:00
Tara Rostami
3f38c42852 fail2ban: better ipv6 validation (#2615) 2024-12-20 18:33:27 +01:00
mhsanaei
49295661fd fail2ban - unban fix
sorry for my mistake
2024-12-19 23:24:10 +01:00
mhsanaei
e4301f8d93 fail2ban - allports 2024-12-19 22:49:25 +01:00
mhsanaei
c6586f8df2 fix typo 2024-12-19 14:53:09 +01:00
mhsanaei
8e81008cdc v2.4.10 2024-12-19 10:54:17 +01:00
mhsanaei
e33ad809d6 Xray Core v24.12.18 2024-12-19 10:48:43 +01:00
mhsanaei
d804043a18 fail2ban - bantime 30min 2024-12-18 13:23:32 +01:00
mhsanaei
0fb0df7056 fail2ban - ipv4 & 6 2024-12-18 12:31:05 +01:00
mhsanaei
73e90e0eaa TLS, REALITY : fingerprint set default to chrome 2024-12-17 23:25:54 +01:00
mhsanaei
44ef1ac9a6 remove insecure cipher suites list 2024-12-17 23:18:16 +01:00
mhsanaei
aeac7f2c8b UTLS: unsafe 2024-12-17 23:17:12 +01:00
mhsanaei
39ef172b87 fail2ban - ban and unban an IP Address 2024-12-17 17:59:04 +01:00
mhsanaei
0df85cc3d9 XHTTP: server & client
Remove scMinPostsIntervalMs, xmux, noGRPCHeader from the server side and add them to the client side.

Before you could have them on sub json but I decided to remove them.
2024-12-17 10:39:37 +01:00
MHSanaei
f0f4f082ae improve iplimit 2024-12-16 14:26:47 +01:00
MHSanaei
b29bd993d4 fix session
twice  set-cookie bug fixed
2024-12-16 14:24:59 +01:00
MHSanaei
127eaf69b6 fail2ban - unban all without restart 2024-12-16 13:28:53 +01:00
mhsanaei
36b0289bc6 XHTTP: Add "scMaxBufferedPosts" 2024-12-16 11:20:38 +01:00
MHSanaei
0abd0be725 v2.4.9 2024-12-16 10:13:40 +01:00
MHSanaei
918a2b1533 XHTTP: Add "hMaxRequestTimes, hKeepAlivePeriod" 2024-12-16 10:13:01 +01:00
MHSanaei
88a17cd227 Xray core v24.12.15 2024-12-16 10:00:15 +01:00
mhsanaei
b60387accb XHTTP: Add "keepAlivePeriod" 2024-12-11 17:05:47 +01:00
mhsanaei
049177024b Xray core buggy version removed
accept >= v24.11.30 or v1.8.24
2024-12-05 20:17:47 +01:00
mhsanaei
9c63638af1 xhttp - default settings 2024-12-05 20:15:19 +01:00
mhsanaei
67dfe664a6 GO v1.23.4 + update dependencies 2024-12-05 20:14:56 +01:00
mhsanaei
4efcdb3e01 Transport: Remove HTTP
Migrated to XHTTP "stream-one" mode.
2024-12-04 13:49:43 +01:00
Sanaei
ddc2cfacb9 Delete .github/dependabot.yml 2024-12-03 23:15:02 +01:00
mhsanaei
337729529a Xray Core v24.11.21 2024-12-03 23:09:38 +01:00
mhsanaei
4c4cc362b3 fix crash report
Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
2024-12-03 23:07:24 +01:00
mhsanaei
4e0aca16c2 [warp] report error in change license
Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
2024-12-03 23:01:32 +01:00
lexnake3
749a426a71 show IP on warning log when user pass is not correct (#2607) 2024-12-03 22:41:14 +01:00
mhsanaei
b859327b8a splithttp to xhttp 2024-12-03 22:24:34 +01:00
mhsanaei
3e8fc59213 WebSocket: Add heartbeatPeriod 2024-12-03 22:07:58 +01:00
mhsanaei
462e02140d XHTTP: Add "stream-one" 2024-12-03 21:57:44 +01:00
mhsanaei
6b41df2d89 update dependencies 2024-12-03 21:33:01 +01:00
Tara Rostami
eb5ed5c0dd readme update (#2604) 2024-11-21 20:48:30 +03:30
57 changed files with 744 additions and 615 deletions

View File

@@ -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"

View File

@@ -83,7 +83,7 @@ jobs:
cd x-ui/bin
# Download dependencies
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.11.21/"
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.12.18/"
if [ "${{ matrix.platform }}" == "amd64" ]; then
wget ${Xray_URL}Xray-linux-64.zip
unzip Xray-linux-64.zip

View File

@@ -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.11.21/Xray-linux-${ARCH}.zip"
wget "https://github.com/XTLS/Xray-core/releases/download/v24.12.18/Xray-linux-${ARCH}.zip"
unzip "Xray-linux-${ARCH}.zip"
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
mv xray "xray-linux-${FNAME}"

View File

@@ -1,6 +1,11 @@
[English](/README.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
<p align="center"><a href="#"><img src="./media/3X-UI.png" alt="Image"></a></p>
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
</picture>
</p>
**Un Panel Web Avanzado • Construido sobre Xray Core**
@@ -539,13 +544,34 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Vista previa
![1](./media/1.png)
![2](./media/2.png)
![3](./media/3.png)
![4](./media/4.png)
![5](./media/5.png)
![6](./media/6.png)
![7](./media/7.png)
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/01-overview-dark.png">
<img alt="3x-ui" src="./media/01-overview-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/02-inbounds-dark.png">
<img alt="3x-ui" src="./media/02-inbounds-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/03-add-inbound-dark.png">
<img alt="3x-ui" src="./media/03-add-inbound-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/04-add-client-dark.png">
<img alt="3x-ui" src="./media/04-add-client-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/05-settings-dark.png">
<img alt="3x-ui" src="./media/05-settings-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/06-configs-dark.png">
<img alt="3x-ui" src="./media/06-configs-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/07-bot-dark.png">
<img alt="3x-ui" src="./media/07-bot-light.png">
</picture>
## Un agradecimiento especial a
@@ -558,4 +584,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Estrellas a lo largo del tiempo
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg)](https://starchart.cc/MHSanaei/3x-ui)
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)

View File

@@ -1,6 +1,11 @@
[English](/README.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
<p align="center"><a href="#"><img src="./media/3X-UI.png" alt="Image"></a></p>
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
</picture>
</p>
**An Advanced Web Panel • Built on Xray Core**
@@ -548,13 +553,34 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Preview
![1](./media/1.png)
![2](./media/2.png)
![3](./media/3.png)
![4](./media/4.png)
![5](./media/5.png)
![6](./media/6.png)
![7](./media/7.png)
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/01-overview-dark.png">
<img alt="3x-ui" src="./media/01-overview-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/02-inbounds-dark.png">
<img alt="3x-ui" src="./media/02-inbounds-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/03-add-inbound-dark.png">
<img alt="3x-ui" src="./media/03-add-inbound-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/04-add-client-dark.png">
<img alt="3x-ui" src="./media/04-add-client-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/05-settings-dark.png">
<img alt="3x-ui" src="./media/05-settings-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/06-configs-dark.png">
<img alt="3x-ui" src="./media/06-configs-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/07-bot-dark.png">
<img alt="3x-ui" src="./media/07-bot-light.png">
</picture>
## A Special Thanks to
@@ -567,4 +593,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Stargazers over Time
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg)](https://starchart.cc/MHSanaei/3x-ui)
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)

View File

@@ -1,6 +1,11 @@
[English](/README.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
<p align="center"><a href="#"><img src="./media/3X-UI.png" alt="Image"></a></p>
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
</picture>
</p>
**Продвинутая веб-панель • Построена на основе Xray Core**
@@ -546,13 +551,34 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Предварительный Просмотр
![1](./media/1.png)
![2](./media/2.png)
![3](./media/3.png)
![4](./media/4.png)
![5](./media/5.png)
![6](./media/6.png)
![7](./media/7.png)
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/01-overview-dark.png">
<img alt="3x-ui" src="./media/01-overview-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/02-inbounds-dark.png">
<img alt="3x-ui" src="./media/02-inbounds-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/03-add-inbound-dark.png">
<img alt="3x-ui" src="./media/03-add-inbound-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/04-add-client-dark.png">
<img alt="3x-ui" src="./media/04-add-client-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/05-settings-dark.png">
<img alt="3x-ui" src="./media/05-settings-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/06-configs-dark.png">
<img alt="3x-ui" src="./media/06-configs-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/07-bot-dark.png">
<img alt="3x-ui" src="./media/07-bot-light.png">
</picture>
## Особая благодарность
@@ -565,4 +591,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Число звёзд со временем
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg)](https://starchart.cc/MHSanaei/3x-ui)
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)

View File

@@ -1,6 +1,11 @@
[English](/README.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
<p align="center"><a href="#"><img src="./media/3X-UI.png" alt="Image"></a></p>
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
</picture>
</p>
**一个更好的面板 • 基于Xray Core构建**
@@ -539,13 +544,34 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## 预览
![1](./media/1.png)
![2](./media/2.png)
![3](./media/3.png)
![4](./media/4.png)
![5](./media/5.png)
![6](./media/6.png)
![7](./media/7.png)
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/01-overview-dark.png">
<img alt="3x-ui" src="./media/01-overview-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/02-inbounds-dark.png">
<img alt="3x-ui" src="./media/02-inbounds-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/03-add-inbound-dark.png">
<img alt="3x-ui" src="./media/03-add-inbound-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/04-add-client-dark.png">
<img alt="3x-ui" src="./media/04-add-client-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/05-settings-dark.png">
<img alt="3x-ui" src="./media/05-settings-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/06-configs-dark.png">
<img alt="3x-ui" src="./media/06-configs-light.png">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/07-bot-dark.png">
<img alt="3x-ui" src="./media/07-bot-light.png">
</picture>
## 特别感谢
@@ -558,4 +584,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Star趋势
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg)](https://starchart.cc/MHSanaei/3x-ui)
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)

View File

@@ -1 +1 @@
2.4.8
2.4.11

View File

@@ -98,5 +98,6 @@ type Client struct {
Enable bool `json:"enable" form:"enable"`
TgID int64 `json:"tgId" form:"tgId"`
SubID string `json:"subId" form:"subId"`
Comment string `json:"comment" form:"comment"`
Reset int `json:"reset" form:"reset"`
}

42
go.mod
View File

@@ -1,37 +1,37 @@
module x-ui
go 1.23.3
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/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.10
github.com/valyala/fasthttp v1.57.0
github.com/xtls/xray-core v1.8.25-0.20241121054707-513f18bf531e
github.com/shirou/gopsutil/v4 v4.24.11
github.com/valyala/fasthttp v1.58.0
github.com/xtls/xray-core v1.8.25-0.20241218133935-cab2fdefd321
go.uber.org/atomic v1.11.0
golang.org/x/text v0.20.0
google.golang.org/grpc v1.68.0
gorm.io/driver/sqlite v1.5.6
golang.org/x/text v0.21.0
google.golang.org/grpc v1.69.2
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.4 // 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/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
@@ -40,7 +40,7 @@ require (
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-20241101162523-b92577c0c142 // 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
@@ -58,11 +58,11 @@ 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.21.0 // 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
@@ -84,18 +84,18 @@ require (
go.uber.org/mock v0.5.0 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/arch v0.12.0 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/net v0.33.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.27.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-20241118233622-e639e219e697 // indirect
google.golang.org/protobuf v1.35.2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/protobuf v1.36.0 // 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

98
go.sum
View File

@@ -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.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k=
github.com/bytedance/sonic v1.12.4/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,8 +24,8 @@ 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/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=
@@ -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=
@@ -53,8 +55,8 @@ github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL
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=
@@ -66,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-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs=
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/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=
@@ -113,8 +117,8 @@ 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.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
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=
@@ -131,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=
@@ -149,8 +153,8 @@ github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55
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.10 h1:7VOzPtfw/5YDU+jLEoBwXwxJbQetULywoSV4RYY7HkM=
github.com/shirou/gopsutil/v4 v4.24.10/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8=
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=
@@ -160,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=
@@ -174,8 +178,8 @@ 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=
@@ -185,12 +189,22 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zd
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.20241121054707-513f18bf531e h1:J5sTv0Sw+BonaI+rBh4Jkw9BfBqDjfAts81/HbIaqNg=
github.com/xtls/xray-core v1.8.25-0.20241121054707-513f18bf531e/go.mod h1:wByClH1yrH8I611sREjG62gxbP5hFtdAWYJfydQF/zI=
github.com/xtls/xray-core v1.8.25-0.20241218133935-cab2fdefd321 h1:vk+n1RmfhFCj5xSi4I6C3USpcUQ48H3lt/QrtARVz1M=
github.com/xtls/xray-core v1.8.25-0.20241218133935-cab2fdefd321/go.mod h1:DCaUwrBk1RIC7hWg/wGoAynE69g3ptua1sEr8i0BWxA=
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=
@@ -199,40 +213,40 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
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.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
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-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/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.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
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.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
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-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 h1:Z7FRVJPSMaHQxD0uXU8WdgFh8PseLM8Q8NzhnpMrBhQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
google.golang.org/protobuf v1.36.0/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=
@@ -242,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=

View File

@@ -2,6 +2,7 @@
red='\033[0;31m'
green='\033[0;32m'
blue='\033[0;34m'
yellow='\033[0;33m'
plain='\033[0m'
@@ -260,24 +261,24 @@ install_x-ui() {
systemctl start x-ui
echo -e "${green}x-ui ${tag_version}${plain} installation finished, it is running now..."
echo -e ""
echo -e "x-ui control menu usages: "
echo -e "----------------------------------------------"
echo -e "SUBCOMMANDS:"
echo -e "x-ui - Admin Management Script"
echo -e "x-ui start - Start"
echo -e "x-ui stop - Stop"
echo -e "x-ui restart - Restart"
echo -e "x-ui status - Current Status"
echo -e "x-ui settings - Current Settings"
echo -e "x-ui enable - Enable Autostart on OS Startup"
echo -e "x-ui disable - Disable Autostart on OS Startup"
echo -e "x-ui log - Check logs"
echo -e "x-ui banlog - Check Fail2ban ban logs"
echo -e "x-ui update - Update"
echo -e "x-ui legacy - legacy version"
echo -e "x-ui install - Install"
echo -e "x-ui uninstall - Uninstall"
echo -e "----------------------------------------------"
echo -e "┌───────────────────────────────────────────────────────┐
${blue}x-ui control menu usages (subcommands):${plain}
│ │
${blue}x-ui${plain} - Admin Management Script
${blue}x-ui start${plain} - Start │
${blue}x-ui stop${plain} - Stop │
${blue}x-ui restart${plain} - Restart │
${blue}x-ui status${plain} - Current Status
${blue}x-ui settings${plain} - Current Settings
${blue}x-ui enable${plain} - Enable Autostart on OS Startup
${blue}x-ui disable${plain} - Disable Autostart on OS Startup
${blue}x-ui log${plain} - Check logs │
${blue}x-ui banlog${plain} - Check Fail2ban ban logs
${blue}x-ui update${plain} - Update │
${blue}x-ui legacy${plain} - legacy version
${blue}x-ui install${plain} - Install │
${blue}x-ui uninstall${plain} - Uninstall │
└───────────────────────────────────────────────────────┘"
}
echo -e "${green}Running...${plain}"

BIN
media/01-overview-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
media/01-overview-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
media/02-inbounds-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
media/02-inbounds-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
media/05-settings-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
media/05-settings-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
media/06-configs-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
media/06-configs-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
media/07-bot-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
media/07-bot-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 226 KiB

BIN
media/3x-ui-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -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,16 +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"] = splithttp["mode"].(string)
obj["mode"] = xhttp["mode"].(string)
}
security, _ := stream["security"].(string)
obj["tls"] = security
@@ -361,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)
@@ -381,16 +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"] = splithttp["mode"].(string)
params["mode"] = xhttp["mode"].(string)
}
security, _ := stream["security"].(string)
if security == "tls" {
@@ -559,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)
@@ -579,16 +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"] = splithttp["mode"].(string)
params["mode"] = xhttp["mode"].(string)
}
security, _ := stream["security"].(string)
if security == "tls" {
@@ -757,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)
@@ -777,16 +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"] = splithttp["mode"].(string)
params["mode"] = xhttp["mode"].(string)
}
security, _ := stream["security"].(string)

File diff suppressed because one or more lines are too long

View File

@@ -34,10 +34,6 @@ const TLS_VERSION_OPTION = {
};
const TLS_CIPHER_OPTION = {
RSA_AES_128_CBC: "TLS_RSA_WITH_AES_128_CBC_SHA",
RSA_AES_256_CBC: "TLS_RSA_WITH_AES_256_CBC_SHA",
RSA_AES_128_GCM: "TLS_RSA_WITH_AES_128_GCM_SHA256",
RSA_AES_256_GCM: "TLS_RSA_WITH_AES_256_GCM_SHA384",
AES_128_GCM: "TLS_AES_128_GCM_SHA256",
AES_256_GCM: "TLS_AES_256_GCM_SHA384",
CHACHA20_POLY1305: "TLS_CHACHA20_POLY1305_SHA256",
@@ -64,6 +60,7 @@ const UTLS_FINGERPRINT = {
UTLS_QQ: "qq",
UTLS_RANDOM: "random",
UTLS_RANDOMIZED: "randomized",
UTLS_UNSAFE: "unsafe",
};
const ALPN_OPTION = {
@@ -117,6 +114,7 @@ const MODE_OPTION = {
AUTO: "auto",
PACKET_UP: "packet-up",
STREAM_UP: "stream-up",
STREAM_ONE: "stream-one",
};
Object.freeze(Protocols);
@@ -378,13 +376,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) {
@@ -401,6 +401,7 @@ class WsStreamSettings extends XrayCommonClass {
json.path,
json.host,
XrayCommonClass.toHeaders(json.headers),
json.heartbeatPeriod,
);
}
@@ -410,46 +411,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 = "",
@@ -520,37 +486,26 @@ 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",
noSSEHeader = false,
xPaddingBytes = "100-1000",
xmux = {
maxConcurrency: "16-32",
maxConnections: 0,
cMaxReuseTimes: "64-128",
cMaxLifetimeMs: 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) {
@@ -562,18 +517,15 @@ 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
);
}
@@ -582,19 +534,11 @@ 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,
xPaddingBytes: this.xPaddingBytes,
xmux: {
maxConcurrency: this.xmux.maxConcurrency,
maxConnections: this.xmux.maxConnections,
cMaxReuseTimes: this.xmux.cMaxReuseTimes,
cMaxLifetimeMs: this.xmux.cMaxLifetimeMs
},
mode: this.mode,
noGRPCHeader: this.noGRPCHeader
};
}
}
@@ -745,7 +689,10 @@ TlsStreamSettings.Cert = class extends XrayCommonClass {
};
TlsStreamSettings.Settings = class extends XrayCommonClass {
constructor(allowInsecure = false, fingerprint = '') {
constructor(
allowInsecure = false,
fingerprint = UTLS_FINGERPRINT.UTLS_CHROME,
) {
super();
this.allowInsecure = allowInsecure;
this.fingerprint = fingerprint;
@@ -834,7 +781,7 @@ class RealityStreamSettings extends XrayCommonClass {
RealityStreamSettings.Settings = class extends XrayCommonClass {
constructor(
publicKey = '',
fingerprint = UTLS_FINGERPRINT.UTLS_RANDOM,
fingerprint = UTLS_FINGERPRINT.UTLS_CHROME,
serverName = '',
spiderX = '/'
) {
@@ -953,10 +900,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();
@@ -968,10 +914,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;
}
@@ -1018,10 +963,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),
);
}
@@ -1037,10 +981,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,
};
}
@@ -1169,16 +1112,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
@@ -1217,12 +1156,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;
}
@@ -1232,12 +1169,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;
}
@@ -1261,7 +1196,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
@@ -1274,7 +1209,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() {
@@ -1326,10 +1261,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;
@@ -1340,14 +1271,14 @@ 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');
obj.mode = splithttp.mode;
} 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') {
if (tls === 'tls') {
if (!ObjectUtil.isEmpty(this.stream.tls.sni)) {
obj.sni = this.stream.tls.sni;
}
@@ -1395,11 +1326,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);
@@ -1413,11 +1339,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'));
params.set("mode", splithttp.mode);
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;
}
@@ -1499,11 +1425,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);
@@ -1517,11 +1438,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'));
params.set("mode", splithttp.mode);
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;
}
@@ -1582,11 +1503,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);
@@ -1600,11 +1516,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'));
params.set("mode", splithttp.mode);
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;
}
@@ -1862,6 +1778,7 @@ Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
enable = true,
tgId = '',
subId = RandomUtil.randomLowerAndNum(16),
comment = '',
reset = 0
) {
super();
@@ -1874,6 +1791,7 @@ Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
this.enable = enable;
this.tgId = tgId;
this.subId = subId;
this.comment = comment;
this.reset = reset;
}
@@ -1888,6 +1806,7 @@ Inbound.VmessSettings.VMESS = class extends XrayCommonClass {
json.enable,
json.tgId,
json.subId,
json.comment,
json.reset,
);
}
@@ -1968,6 +1887,7 @@ Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
enable = true,
tgId = '',
subId = RandomUtil.randomLowerAndNum(16),
comment = '',
reset = 0
) {
super();
@@ -1980,6 +1900,7 @@ Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
this.enable = enable;
this.tgId = tgId;
this.subId = subId;
this.comment = comment;
this.reset = reset;
}
@@ -1994,6 +1915,7 @@ Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
json.enable,
json.tgId,
json.subId,
json.comment,
json.reset,
);
}
@@ -2104,6 +2026,7 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
enable = true,
tgId = '',
subId = RandomUtil.randomLowerAndNum(16),
comment = '',
reset = 0
) {
super();
@@ -2115,6 +2038,7 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
this.enable = enable;
this.tgId = tgId;
this.subId = subId;
this.comment = comment;
this.reset = reset;
}
@@ -2128,6 +2052,7 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
enable: this.enable,
tgId: this.tgId,
subId: this.subId,
comment: this.comment,
reset: this.reset,
};
}
@@ -2142,6 +2067,7 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
json.enable,
json.tgId,
json.subId,
json.comment,
json.reset,
);
}
@@ -2261,6 +2187,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
enable = true,
tgId = '',
subId = RandomUtil.randomLowerAndNum(16),
comment = '',
reset = 0
) {
super();
@@ -2273,6 +2200,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
this.enable = enable;
this.tgId = tgId;
this.subId = subId;
this.comment = comment;
this.reset = reset;
}
@@ -2287,6 +2215,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
enable: this.enable,
tgId: this.tgId,
subId: this.subId,
comment: this.comment,
reset: this.reset,
};
}
@@ -2302,6 +2231,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
json.enable,
json.tgId,
json.subId,
json.comment,
json.reset,
);
}

View File

@@ -39,6 +39,7 @@ const UTLS_FINGERPRINT = {
UTLS_QQ: "qq",
UTLS_RANDOM: "random",
UTLS_RANDOMIZED: "randomized",
UTLS_UNSAFE: "unsafe",
};
const ALPN_OPTION = {
@@ -81,6 +82,7 @@ const MODE_OPTION = {
AUTO: "auto",
PACKET_UP: "packet-up",
STREAM_UP: "stream-up",
STREAM_ONE: "stream-one",
};
Object.freeze(Protocols);
@@ -205,16 +207,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,
);
}
@@ -222,63 +231,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 = "",
@@ -326,23 +283,39 @@ class HttpUpgradeStreamSettings extends CommonClass {
}
}
class SplitHTTPStreamSettings extends CommonClass {
class xHTTPStreamSettings extends CommonClass {
constructor(
path = '/',
host = '',
mode = '',
noGRPCHeader = false,
scMinPostsIntervalMs = "30",
xmux = {
maxConcurrency: "16-32",
maxConnections: 0,
cMaxReuseTimes: "64-128",
cMaxLifetimeMs: 0,
hMaxRequestTimes: "800-900",
hKeepAlivePeriod: 0,
},
) {
super();
this.path = path;
this.host = host;
this.mode = mode;
this.noGRPCHeader = noGRPCHeader;
this.scMinPostsIntervalMs = scMinPostsIntervalMs;
this.xmux = xmux;
}
static fromJson(json = {}) {
return new SplitHTTPStreamSettings(
return new xHTTPStreamSettings(
json.path,
json.host,
json.mode,
json.noGRPCHeader,
json.scMinPostsIntervalMs,
json.xmux
);
}
@@ -351,6 +324,16 @@ class SplitHTTPStreamSettings extends CommonClass {
path: this.path,
host: this.host,
mode: this.mode,
noGRPCHeader: this.noGRPCHeader,
scMinPostsIntervalMs: this.scMinPostsIntervalMs,
xmux: {
maxConcurrency: this.xmux.maxConcurrency,
maxConnections: this.xmux.maxConnections,
cMaxReuseTimes: this.xmux.cMaxReuseTimes,
cMaxLifetimeMs: this.xmux.cMaxLifetimeMs,
hMaxRequestTimes: this.xmux.hMaxRequestTimes,
hKeepAlivePeriod: this.xmux.hKeepAlivePeriod,
},
};
}
}
@@ -469,11 +452,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();
@@ -484,10 +465,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;
}
@@ -516,11 +496,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),
);
}
@@ -535,10 +513,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,
};
}
@@ -576,7 +553,7 @@ class Mux extends CommonClass {
class Outbound extends CommonClass {
constructor(
tag = '',
protocol = Protocols.VMess,
protocol = Protocols.VLESS,
settings = null,
streamSettings = new StreamSettings(),
sendThrough,
@@ -603,7 +580,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
@@ -616,7 +593,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() {
@@ -714,17 +691,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, json.mode);
} else if (network === 'xhttp') {
stream.xhttp = new xHTTPStreamSettings(json.path, json.host, json.mode);
}
if (json.tls && json.tls == 'tls') {
@@ -749,6 +721,7 @@ class Outbound extends CommonClass {
let headerType = url.searchParams.get('headerType') ?? undefined;
let host = url.searchParams.get('host') ?? undefined;
let path = url.searchParams.get('path') ?? undefined;
let mode = url.searchParams.get('mode') ?? undefined;
if (type === 'tcp' || type === 'none') {
stream.tcp = new TcpStreamSettings(headerType ?? 'none', host, path);
@@ -758,8 +731,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') ?? '',
@@ -767,8 +738,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, mode);
} else if (type === 'xhttp') {
stream.xhttp = new xHTTPStreamSettings(path, host, mode);
}
if (security == 'tls') {

File diff suppressed because one or more lines are too long

View File

@@ -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"))
}

View File

@@ -68,6 +68,9 @@
</template>
<a-input-number style="width: 50%" v-model="client.tgId" min="0"></a-input-number>
</a-form-item>
<a-form-item v-if="client.email" label='Comment'>
<a-input v-model.trim="client.comment"></a-input>
</a-form-item>
<a-form-item v-if="app.ipLimitEnable">
<template slot="label">
<a-tooltip>

View File

@@ -270,10 +270,9 @@
<a-select-option value="tcp">TCP (RAW)</a-select-option>
<a-select-option value="kcp">mKCP</a-select-option>
<a-select-option value="ws">WebSocket</a-select-option>
<a-select-option value="http">HTTP</a-select-option>
<a-select-option value="grpc">gRPC</a-select-option>
<a-select-option value="httpupgrade">HTTPUpgrade</a-select-option>
<a-select-option value="splithttp">SplitHTTP (XHTTP)</a-select-option>
<a-select-option value="xhttp">XHTTP</a-select-option>
</a-select>
</a-form-item>
<template v-if="outbound.stream.network === 'tcp'">
@@ -337,15 +336,8 @@
<a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="outbound.stream.ws.path"></a-input>
</a-form-item>
</template>
<!-- http -->
<template v-if="outbound.stream.network === 'http'">
<a-form-item label='{{ i18n "host" }}'>
<a-input v-model.trim="outbound.stream.http.host"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="outbound.stream.http.path"></a-input>
<a-form-item label='Heartbeat Period'>
<a-input-number v-model.number="outbound.stream.ws.heartbeatPeriod" :min="0"></a-input-number>
</a-form-item>
</template>
@@ -372,19 +364,43 @@
</a-form-item>
</template>
<!-- splithttp -->
<template v-if="outbound.stream.network === 'splithttp'">
<!-- xhttp -->
<template v-if="outbound.stream.network === 'xhttp'">
<a-form-item label='{{ i18n "host" }}'>
<a-input v-model="outbound.stream.splithttp.host"></a-input>
<a-input v-model="outbound.stream.xhttp.host"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="outbound.stream.splithttp.path"></a-input>
<a-input v-model.trim="outbound.stream.xhttp.path"></a-input>
</a-form-item>
<a-form-item label='Mode'>
<a-select v-model="outbound.stream.splithttp.mode" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select v-model="outbound.stream.xhttp.mode" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="No gRPC Header" v-if="outbound.stream.xhttp.mode === 'stream-up' || outbound.stream.xhttp.mode === 'stream-one'">
<a-switch v-model="outbound.stream.xhttp.noGRPCHeader"></a-switch>
</a-form-item>
<a-form-item label="Min Upload Interval (Ms)" v-if="outbound.stream.xhttp.mode === 'packet-up'">
<a-input v-model.trim="outbound.stream.xhttp.scMinPostsIntervalMs"></a-input>
</a-form-item>
<a-form-item label="Max Concurrency" v-if="!outbound.stream.xhttp.xmux.maxConnections">
<a-input v-model="outbound.stream.xhttp.xmux.maxConcurrency"></a-input>
</a-form-item>
<a-form-item label="Max Connections" v-if="!outbound.stream.xhttp.xmux.maxConcurrency">
<a-input v-model="outbound.stream.xhttp.xmux.maxConnections"></a-input>
</a-form-item>
<a-form-item label="Max Reuse Times">
<a-input v-model="outbound.stream.xhttp.xmux.cMaxReuseTimes"></a-input>
</a-form-item>
<a-form-item label="Max Lifetime (ms)">
<a-input v-model="outbound.stream.xhttp.xmux.cMaxLifetimeMs"></a-input>
</a-form-item>
<a-form-item label="Max Request Times">
<a-input v-model="outbound.stream.xhttp.xmux.hMaxRequestTimes"></a-input>
</a-form-item>
<a-form-item label='Keep Alive Period'>
<a-input v-model.number="outbound.stream.xhttp.xmux.hKeepAlivePeriod"></a-input>
</a-form-item>
</template>
</template>

View File

@@ -1,17 +0,0 @@
{{define "form/streamHTTP"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="inbound.stream.http.path"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">{{ i18n "host" }}
<a-button icon="plus" size="small" @click="inbound.stream.http.addHost()"></a-button>
</template>
<template v-for="(host, index) in inbound.stream.http.host">
<a-input v-model.trim="inbound.stream.http.host[index]">
<a-button icon="minus" size="small" slot="addonAfter" @click="inbound.stream.http.removeHost(index)" v-if="inbound.stream.http.host.length>1"></a-button>
</a-input>
</template>
</a-form-item>
</a-form>
{{end}}

View File

@@ -7,10 +7,9 @@
<a-select-option value="tcp">TCP (RAW)</a-select-option>
<a-select-option value="kcp">mKCP</a-select-option>
<a-select-option value="ws">WebSocket</a-select-option>
<a-select-option value="http">HTTP</a-select-option>
<a-select-option value="grpc">gRPC</a-select-option>
<a-select-option value="httpupgrade">HTTPUpgrade</a-select-option>
<a-select-option value="splithttp">SplitHTTP (XHTTP)</a-select-option>
<a-select-option value="xhttp">XHTTP</a-select-option>
</a-select>
</a-form-item>
</a-form>
@@ -30,11 +29,6 @@
{{template "form/streamWS"}}
</template>
<!-- http -->
<template v-if="inbound.stream.network === 'http'">
{{template "form/streamHTTP"}}
</template>
<!-- grpc -->
<template v-if="inbound.stream.network === 'grpc'">
{{template "form/streamGRPC"}}
@@ -45,9 +39,9 @@
{{template "form/streamHTTPUpgrade"}}
</template>
<!-- splithttp -->
<template v-if="inbound.stream.network === 'splithttp'">
{{template "form/streamSplitHTTP"}}
<!-- xhttp -->
<template v-if="inbound.stream.network === 'xhttp'">
{{template "form/streamXHTTP"}}
</template>
<!-- sockopt -->

View File

@@ -1,62 +0,0 @@
{{define "form/streamSplitHTTP"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "host" }}'>
<a-input v-model.trim="inbound.stream.splithttp.host"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="inbound.stream.splithttp.path"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button icon="plus" size="small" @click="inbound.stream.splithttp.addHeader('host', '')"></a-button>
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.splithttp.headers">
<a-input style="width: 50%" v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="header.value"
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button slot="addonAfter" size="small"
@click="inbound.stream.splithttp.removeHeader(index)">-</a-button>
</a-input>
</a-input-group>
</a-form-item>
<a-form-item label='Mode'>
<a-select v-model="inbound.stream.splithttp.mode" style="width: 50%"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Max Concurrent Upload">
<a-input v-model.trim="inbound.stream.splithttp.scMaxConcurrentPosts"></a-input>
</a-form-item>
<a-form-item label="Max Upload Size (Byte)">
<a-input v-model.trim="inbound.stream.splithttp.scMaxEachPostBytes"></a-input>
</a-form-item>
<a-form-item label="Min Upload Interval (Ms)">
<a-input v-model.trim="inbound.stream.splithttp.scMinPostsIntervalMs"></a-input>
</a-form-item>
<a-form-item label="Padding Bytes">
<a-input v-model.trim="inbound.stream.splithttp.xPaddingBytes"></a-input>
</a-form-item>
<a-form-item label="No SSE Header">
<a-switch v-model="inbound.stream.splithttp.noSSEHeader"></a-switch>
</a-form-item>
<a-form-item label="Max Concurrency" v-if="!inbound.stream.splithttp.xmux.maxConnections">
<a-input v-model="inbound.stream.splithttp.xmux.maxConcurrency"></a-input>
</a-form-item>
<a-form-item label="Max Connections" v-if="!inbound.stream.splithttp.xmux.maxConcurrency">
<a-input v-model="inbound.stream.splithttp.xmux.maxConnections"></a-input>
</a-form-item>
<a-form-item label="Max Reuse Times">
<a-input v-model="inbound.stream.splithttp.xmux.cMaxReuseTimes"></a-input>
</a-form-item>
<a-form-item label="Max Lifetime (ms)">
<a-input v-model="inbound.stream.splithttp.xmux.cMaxLifetimeMs"></a-input>
</a-form-item>
<a-form-item label="No gRPC Header">
<a-switch v-model="inbound.stream.splithttp.noGRPCHeader"></a-switch>
</a-form-item>
</a-form>
{{end}}

View File

@@ -9,8 +9,11 @@
<a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="inbound.stream.ws.path"></a-input>
</a-form-item>
<a-form-item label='Heartbeat Period'>
<a-input-number v-model.number="inbound.stream.ws.heartbeatPeriod" :min="0"></a-input-number>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button icon="plus" size="small" @click="inbound.stream.ws.addHeader('host', '')"></a-button>
<a-button icon="plus" size="small" @click="inbound.stream.ws.addHeader('', '')"></a-button>
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.ws.headers">

View File

@@ -0,0 +1,43 @@
{{define "form/streamXHTTP"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "host" }}'>
<a-input v-model.trim="inbound.stream.xhttp.host"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "path" }}'>
<a-input v-model.trim="inbound.stream.xhttp.path"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
<a-button icon="plus" size="small" @click="inbound.stream.xhttp.addHeader('host', '')"></a-button>
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.xhttp.headers">
<a-input style="width: 50%" v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="header.value"
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button slot="addonAfter" size="small" @click="inbound.stream.xhttp.removeHeader(index)">-</a-button>
</a-input>
</a-input-group>
</a-form-item>
<a-form-item label='Mode'>
<a-select v-model="inbound.stream.xhttp.mode" style="width: 50%"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Max Buffered Upload" v-if="inbound.stream.xhttp.mode === 'packet-up'">
<a-input v-model.trim="inbound.stream.xhttp.scMaxBufferedPosts"></a-input>
</a-form-item>
<a-form-item label="Max Upload Size (Byte)" v-if="inbound.stream.xhttp.mode === 'packet-up'">
<a-input v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input>
</a-form-item>
<a-form-item label="Padding Bytes">
<a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input>
</a-form-item>
<a-form-item label="No SSE Header">
<a-switch v-model="inbound.stream.xhttp.noSSEHeader"></a-switch>
</a-form-item>
</a-form>
{{end}}

View File

@@ -34,7 +34,7 @@
<a-tag color="green">[[ inbound.network ]]</a-tag>
</td>
</tr>
<template v-if="inbound.isTcp || inbound.isWs || inbound.isH2 || inbound.isHttpupgrade || inbound.isSplithttp">
<template v-if="inbound.isTcp || inbound.isWs || inbound.isHttpupgrade || inbound.isXHTTP">
<tr>
<td>{{ i18n "host" }}</td>
<td v-if="inbound.host">
@@ -58,11 +58,11 @@
</td>
</tr>
</template>
<template v-if="inbound.isSplithttp">
<template v-if="inbound.isXHTTP">
<tr>
<td>Mode</td>
<td>
<a-tag>[[ inbound.stream.splithttp.mode ]]</a-tag>
<a-tag>[[ inbound.stream.xhttp.mode ]]</a-tag>
</td>
</tr>
</template>
@@ -185,6 +185,33 @@
<a-tag>↑ [[ sizeFormat(infoModal.clientStats.up) ]] / [[ sizeFormat(infoModal.clientStats.down) ]] ↓</a-tag>
</td>
</tr>
<tr v-if="infoModal.clientSettings.comment">
<td>Comment</td>
<td>
<a-tooltip :title="[[ infoModal.clientSettings.comment ]]">
<a-tag class="info-large-tag">[[ infoModal.clientSettings.comment ]]</a-tag>
</a-tooltip>
</td>
</tr>
<tr v-if="app.ipLimitEnable">
<td>{{ i18n "pages.inbounds.IPLimit" }}</td>
<td>
<a-tag>[[ infoModal.clientSettings.limitIp ]]</a-tag>
</td>
</tr>
<tr v-if="app.ipLimitEnable">
<td>{{ i18n "pages.inbounds.IPLimitlog" }}</td>
<td>
<a-tag>[[ infoModal.clientIps ]]</a-tag>
<a-icon type="sync" :spin="refreshing" @click="refreshIPs" style="margin: 0 5px;"></a-icon>
<a-tooltip :title="[[ dbInbound.address ]]">
<template slot="title">
<span>{{ i18n "pages.inbounds.IPLimitlogclear" }}</span>
</template>
<a-icon type="delete" @click="clearClientIps"></a-icon>
</a-tooltip>
</td>
</tr>
</table>
<table style="display: inline-table; margin-block: 10px; width: 100%; text-align: center;">
<tr>
@@ -417,6 +444,18 @@
</template>
</a-modal>
<script>
function refreshIPs(email) {
return HttpUtil.post(`/panel/inbound/clientIps/${email}`).then((msg) => {
if (msg.success) {
try {
return JSON.parse(msg.obj).join(', ');
} catch (e) {
return msg.obj;
}
}
});
}
const infoModal = {
visible: false,
inbound: new Inbound(),
@@ -431,6 +470,7 @@
isExpired: false,
subLink: '',
subJsonLink: '',
clientIps: '',
show(dbInbound, index) {
this.index = index;
this.inbound = dbInbound.toInbound();
@@ -438,6 +478,12 @@
this.clientSettings = this.inbound.clients ? this.inbound.clients[index] : null;
this.isExpired = this.inbound.clients ? this.inbound.isExpiry(index) : this.dbInbound.isExpiry;
this.clientStats = this.inbound.clients ? this.dbInbound.clientStats.find(row => row.email === this.clientSettings.email) : [];
if (app.ipLimitEnable && this.clientSettings.limitIp) {
refreshIPs(this.clientStats.email).then((ips) => {
this.clientIps = ips;
})
}
if (this.inbound.protocol == Protocols.WIREGUARD) {
this.links = this.inbound.genInboundLinks(dbInbound.remark).split('\r\n')
} else {
@@ -466,6 +512,7 @@
el: '#inbound-info-modal',
data: {
infoModal,
refreshing: false,
get dbInbound() {
return this.infoModal.dbInbound;
},
@@ -502,6 +549,26 @@
remained = this.infoModal.clientStats.total - this.infoModal.clientStats.up - this.infoModal.clientStats.down;
return remained > 0 ? sizeFormat(remained) : '-';
},
refreshIPs() {
this.refreshing = true;
refreshIPs(this.infoModal.clientStats.email)
.then((ips) => {
this.infoModal.clientIps = ips;
})
.finally(() => {
this.refreshing = false;
});
},
clearClientIps() {
HttpUtil.post(`/panel/inbound/clearClientIps/${this.infoModal.clientStats.email}`)
.then((msg) => {
if (!msg.success) {
return;
}
this.infoModal.clientIps = 'No IP Record';
})
.catch(() => {});
},
},
});
</script>

View File

@@ -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
}

View File

@@ -286,7 +286,7 @@ func (s *ServerService) GetXrayVersions() ([]string, error) {
}
if (major == 1 && minor == 8 && patch == 24) ||
(major == 24 && ((minor > 11) || (minor == 11 && patch >= 11))) ||
(major == 24 && ((minor > 11) || (minor == 11 && patch >= 30))) ||
(major > 24) {
versions = append(versions, release.TagName)
}

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -41,7 +41,7 @@
"offline" = "Офлайн"
"online" = "Онлайн"
"domainName" = "Домен"
"monitor" = "Порт IP"
"monitor" = "Слушать IP"
"certificate" = "Цифровой сертификат"
"fail" = "Неудачно"
"success" = "Успешно"

217
x-ui.sh
View File

@@ -2,6 +2,7 @@
red='\033[0;31m'
green='\033[0;32m'
blue='\033[0;34m'
yellow='\033[0;33m'
plain='\033[0m'
@@ -682,10 +683,12 @@ show_xray_status() {
}
firewall_menu() {
echo -e "${green}\t1.${plain} Install Firewall & open ports"
echo -e "${green}\t2.${plain} Allowed List"
echo -e "${green}\t3.${plain} Delete Ports from List"
echo -e "${green}\t4.${plain} Disable Firewall"
echo -e "${green}\t1.${plain} Install Firewall"
echo -e "${green}\t2.${plain} Port List"
echo -e "${green}\t3.${plain} Open Ports"
echo -e "${green}\t4.${plain} Delete Ports from List"
echo -e "${green}\t5.${plain} Disable Firewall"
echo -e "${green}\t6.${plain} Firewall Status"
echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " choice
case "$choice" in
@@ -693,19 +696,27 @@ firewall_menu() {
show_menu
;;
1)
open_ports
install_firewall
firewall_menu
;;
2)
sudo ufw status
ufw status numbered
firewall_menu
;;
3)
delete_ports
open_ports
firewall_menu
;;
4)
sudo ufw disable
delete_ports
firewall_menu
;;
5)
ufw disable
firewall_menu
;;
6)
ufw status verbose
firewall_menu
;;
*)
@@ -715,7 +726,7 @@ firewall_menu() {
esac
}
open_ports() {
install_firewall() {
if ! command -v ufw &>/dev/null; then
echo "ufw firewall is not installed. Installing now..."
apt-get update
@@ -733,13 +744,16 @@ open_ports() {
ufw allow ssh
ufw allow http
ufw allow https
ufw allow 2053/tcp
ufw allow 2053/tcp #webPort
ufw allow 2096/tcp #subport
# Enable the firewall
ufw --force enable
fi
}
# Prompt the user to enter a list of ports
open_ports() {
# Prompt the user to enter the ports they want to open
read -p "Enter the ports you want to open (e.g. 80,443,2053 or range 400-500): " ports
# Check if the input is valid
@@ -755,19 +769,28 @@ open_ports() {
# Split the range into start and end ports
start_port=$(echo $port | cut -d'-' -f1)
end_port=$(echo $port | cut -d'-' -f2)
# Open the port range
ufw allow $start_port:$end_port/tcp
ufw allow $start_port:$end_port/udp
else
# Open the single port
ufw allow "$port"
fi
done
# Confirm that the ports are open
echo "The following ports are now open:"
ufw status | grep "ALLOW" | grep -Eo "[0-9]+(/[a-z]+)?"
echo "Firewall status:"
ufw status verbose
# Confirm that the ports are opened
echo "Opened the specified ports:"
for port in "${PORT_LIST[@]}"; do
if [[ $port == *-* ]]; then
start_port=$(echo $port | cut -d'-' -f1)
end_port=$(echo $port | cut -d'-' -f2)
# Check if the port range has been successfully opened
(ufw status | grep -q "$start_port:$end_port") && echo "$start_port-$end_port"
else
# Check if the individual port has been successfully opened
(ufw status | grep -q "$port") && echo "$port"
fi
done
}
delete_ports() {
@@ -818,7 +841,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
@@ -826,6 +848,7 @@ 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
@@ -833,6 +856,7 @@ update_geo() {
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
@@ -840,6 +864,7 @@ update_geo() {
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
@@ -852,7 +877,6 @@ update_geo() {
;;
esac
systemctl start x-ui
before_show_menu
}
@@ -1277,8 +1301,8 @@ run_speedtest() {
}
create_iplimit_jails() {
# Use default bantime if not passed => 15 minutes
local bantime="${1:-15}"
# Use default bantime if not passed => 30 minutes
local bantime="${1:-30}"
# Uncomment 'allowipv6 = auto' in fail2ban.conf
sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf
@@ -1309,7 +1333,7 @@ EOF
cat << EOF > /etc/fail2ban/action.d/3x-ipl.conf
[INCLUDES]
before = iptables-common.conf
before = iptables-allports.conf
[Definition]
actionstart = <iptables> -N f2b-<name>
@@ -1352,15 +1376,22 @@ iplimit_remove_conflicts() {
done
}
ip_validation() {
ipv6_regex="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
ipv4_regex="^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)$"
}
iplimit_main() {
echo -e "\n${green}\t1.${plain} Install Fail2ban and configure IP Limit"
echo -e "${green}\t2.${plain} Change Ban Duration"
echo -e "${green}\t3.${plain} Unban Everyone"
echo -e "${green}\t4.${plain} Ban Logs"
echo -e "${green}\t5.${plain} Real-Time Logs"
echo -e "${green}\t6.${plain} Service Status"
echo -e "${green}\t7.${plain} Service Restart"
echo -e "${green}\t8.${plain} Uninstall Fail2ban and IP Limit"
echo -e "${green}\t5.${plain} Ban an IP Address"
echo -e "${green}\t6.${plain} Unban an IP Address"
echo -e "${green}\t7.${plain} Real-Time Logs"
echo -e "${green}\t8.${plain} Service Status"
echo -e "${green}\t9.${plain} Service Restart"
echo -e "${green}\t10.${plain} Uninstall Fail2ban and IP Limit"
echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " choice
case "$choice" in
@@ -1402,22 +1433,44 @@ iplimit_main() {
iplimit_main
;;
5)
tail -f /var/log/fail2ban.log
read -rp "Enter the IP address you want to ban: " ban_ip
ip_validation
if [[ $ban_ip =~ $ipv4_regex || $ban_ip =~ $ipv6_regex ]]; then
fail2ban-client set 3x-ipl banip "$ban_ip"
echo -e "${green}IP Address ${ban_ip} has been banned successfully.${plain}"
else
echo -e "${red}Invalid IP address format! Please try again.${plain}"
fi
iplimit_main
;;
6)
service fail2ban status
read -rp "Enter the IP address you want to unban: " unban_ip
ip_validation
if [[ $unban_ip =~ $ipv4_regex || $unban_ip =~ $ipv6_regex ]]; then
fail2ban-client set 3x-ipl unbanip "$unban_ip"
echo -e "${green}IP Address ${unban_ip} has been unbanned successfully.${plain}"
else
echo -e "${red}Invalid IP address format! Please try again.${plain}"
fi
iplimit_main
;;
7)
systemctl restart fail2ban
tail -f /var/log/fail2ban.log
iplimit_main
;;
8)
service fail2ban status
iplimit_main
;;
9)
systemctl restart fail2ban
iplimit_main
;;
10)
remove_iplimit
iplimit_main
;;
*)
*)
echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
iplimit_main
;;
@@ -1628,61 +1681,63 @@ SSH_port_forwarding() {
}
show_usage() {
echo "x-ui control menu usages: "
echo "------------------------------------------"
echo -e "SUBCOMMANDS:"
echo -e "x-ui - Admin Management Script"
echo -e "x-ui start - Start"
echo -e "x-ui stop - Stop"
echo -e "x-ui restart - Restart"
echo -e "x-ui status - Current Status"
echo -e "x-ui settings - Current Settings"
echo -e "x-ui enable - Enable Autostart on OS Startup"
echo -e "x-ui disable - Disable Autostart on OS Startup"
echo -e "x-ui log - Check logs"
echo -e "x-ui banlog - Check Fail2ban ban logs"
echo -e "x-ui update - Update"
echo -e "x-ui custom - custom version"
echo -e "x-ui install - Install"
echo -e "x-ui uninstall - Uninstall"
echo "------------------------------------------"
echo -e "┌───────────────────────────────────────────────────────┐
${blue}x-ui control menu usages (subcommands):${plain}
│ │
${blue}x-ui${plain} - Admin Management Script
${blue}x-ui start${plain} - Start │
${blue}x-ui stop${plain} - Stop │
${blue}x-ui restart${plain} - Restart │
${blue}x-ui status${plain} - Current Status
${blue}x-ui settings${plain} - Current Settings
${blue}x-ui enable${plain} - Enable Autostart on OS Startup
${blue}x-ui disable${plain} - Disable Autostart on OS Startup
${blue}x-ui log${plain} - Check logs │
${blue}x-ui banlog${plain} - Check Fail2ban ban logs
${blue}x-ui update${plain} - Update │
${blue}x-ui legacy${plain} - legacy version
${blue}x-ui install${plain} - Install │
${blue}x-ui uninstall${plain} - Uninstall │
└───────────────────────────────────────────────────────┘"
}
show_menu() {
echo -e "
${green}3X-UI Panel Management Script${plain}
${green}0.${plain} Exit Script
————————————————
${green}1.${plain} Install
${green}2.${plain} Update
${green}3.${plain} Update Menu
${green}4.${plain} Legacy Version
${green}5.${plain} Uninstall
————————————————
${green}6.${plain} Reset Username & Password & Secret Token
${green}7.${plain} Reset Web Base Path
${green}8.${plain} Reset Settings
${green}9.${plain} Change Port
${green}10.${plain} View Current Settings
————————————————
${green}11.${plain} Start
${green}12.${plain} Stop
${green}13.${plain} Restart
${green}14.${plain} Check Status
${green}15.${plain} Logs Management
————————————————
${green}16.${plain} Enable Autostart
${green}17.${plain} Disable Autostart
————————————————
${green}18.${plain} SSL Certificate Management
${green}19.${plain} Cloudflare SSL Certificate
${green}20.${plain} IP Limit Management
${green}21.${plain} Firewall Management
${green}22.${plain} SSH Port Forwarding Management
————————————————
${green}23.${plain} Enable BBR
${green}24.${plain} Update Geo Files
${green}25.${plain} Speedtest by Ookla
╔────────────────────────────────────────────────╗
${green}3X-UI Panel Management Script${plain}
${green}0.${plain} Exit Script │
│────────────────────────────────────────────────│
${green}1.${plain} Install │
${green}2.${plain} Update
${green}3.${plain} Update Menu │
${green}4.${plain} Legacy Version │
${green}5.${plain} Uninstall │
│────────────────────────────────────────────────│
${green}6.${plain} Reset Username & Password & Secret Token │
${green}7.${plain} Reset Web Base Path │
${green}8.${plain} Reset Settings │
${green}9.${plain} Change Port │
${green}10.${plain} View Current Settings │
│────────────────────────────────────────────────│
${green}11.${plain} Start │
${green}12.${plain} Stop │
${green}13.${plain} Restart │
${green}14.${plain} Check Status │
${green}15.${plain} Logs Management │
│────────────────────────────────────────────────│
${green}16.${plain} Enable Autostart
${green}17.${plain} Disable Autostart │
│────────────────────────────────────────────────│
${green}18.${plain} SSL Certificate Management │
${green}19.${plain} Cloudflare SSL Certificate │
${green}20.${plain} IP Limit Management
${green}21.${plain} Firewall Management │
${green}22.${plain} SSH Port Forwarding Management │
│────────────────────────────────────────────────│
${green}23.${plain} Enable BBR │
${green}24.${plain} Update Geo Files │
${green}25.${plain} Speedtest by Ookla │
╚────────────────────────────────────────────────╝
"
show_status
echo && read -p "Please enter your selection [0-25]: " num

View File

@@ -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
}
}

View File

@@ -226,7 +226,6 @@ func (p *process) Start() (err error) {
if err != nil {
logger.Error("Failure in running xray-core:", err)
p.exitErr = err
p.witeCrachReport(err)
}
}()
@@ -243,7 +242,7 @@ func (p *process) Stop() error {
return p.cmd.Process.Signal(syscall.SIGTERM)
}
func (p *process) witeCrachReport(err error) error {
func writeCrachReport(m []byte) error {
crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log"
return os.WriteFile(crashReportPath, []byte(err.Error()), os.ModePerm)
return os.WriteFile(crashReportPath, m, os.ModePerm)
}