Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0630642849 | ||
|
|
8bd3827b41 | ||
|
|
24b367b82f | ||
|
|
011443bfc1 | ||
|
|
7417c52c8f | ||
|
|
4d4eef8d8a | ||
|
|
9de8b4acaf | ||
|
|
f21c293693 | ||
|
|
56159d9c52 | ||
|
|
6cbdf64013 | ||
|
|
bb9b9100a8 | ||
|
|
816adfc3ea | ||
|
|
0a95b0c7b2 | ||
|
|
d298f4ffbd | ||
|
|
315e8af025 | ||
|
|
de985263f5 | ||
|
|
dfe0bbd371 | ||
|
|
60cb328698 | ||
|
|
3d7f13225a | ||
|
|
76fdfb2ef2 | ||
|
|
8018023187 | ||
|
|
ea9d5dc2d5 |
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22'
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
cd x-ui/bin
|
||||
|
||||
# Download dependencies
|
||||
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v1.8.16/"
|
||||
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v1.8.21/"
|
||||
if [ "${{ matrix.platform }}" == "amd64" ]; then
|
||||
wget ${Xray_URL}Xray-linux-64.zip
|
||||
unzip Xray-linux-64.zip
|
||||
@@ -125,7 +125,13 @@ jobs:
|
||||
|
||||
- name: Package
|
||||
run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui
|
||||
|
||||
|
||||
- name: Upload files to Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: x-ui-linux-${{ matrix.platform }}
|
||||
path: ./x-ui-linux-${{ matrix.platform }}.tar.gz
|
||||
|
||||
- name: Upload files to GH release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
|
||||
@@ -27,7 +27,7 @@ case $1 in
|
||||
esac
|
||||
mkdir -p build/bin
|
||||
cd build/bin
|
||||
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.16/Xray-linux-${ARCH}.zip"
|
||||
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.21/Xray-linux-${ARCH}.zip"
|
||||
unzip "Xray-linux-${ARCH}.zip"
|
||||
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
|
||||
mv xray "xray-linux-${FNAME}"
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<p align="left"><a href="#"><img width="125" src="https://github.com/MHSanaei/3x-ui/assets/115543613/7aa895dd-048a-42e7-989b-afd41a74e2e1" alt="Image"></a></p>
|
||||
|
||||
- USDT (TRC20): `TXncxkvhkDWGts487Pjqq1qT9JmwRUz8CC`
|
||||
- MATIC (polygon): `0x41C9548675D044c6Bfb425786C765bc37427256A`
|
||||
- LTC (Litecoin): `ltc1q2ach7x6d2zq0n4l0t4zl7d7xe2s6fs7a3vspwv`
|
||||
|
||||
## Instalar y Actualizar
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<p align="left"><a href="#"><img width="125" src="https://github.com/MHSanaei/3x-ui/assets/115543613/7aa895dd-048a-42e7-989b-afd41a74e2e1" alt="Image"></a></p>
|
||||
|
||||
- USDT (TRC20): `TXncxkvhkDWGts487Pjqq1qT9JmwRUz8CC`
|
||||
- MATIC (polygon): `0x41C9548675D044c6Bfb425786C765bc37427256A`
|
||||
- LTC (Litecoin): `ltc1q2ach7x6d2zq0n4l0t4zl7d7xe2s6fs7a3vspwv`
|
||||
|
||||
## Install & Upgrade
|
||||
|
||||
@@ -26,10 +28,10 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
||||
|
||||
## Install Custom Version
|
||||
|
||||
To install your desired version, add the version to the end of the installation command. e.g., ver `v2.3.7`:
|
||||
To install your desired version, add the version to the end of the installation command. e.g., ver `v2.3.10`:
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.3.7
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.3.10
|
||||
```
|
||||
|
||||
## SSL Certificate
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<p align="left"><a href="#"><img width="125" src="https://github.com/MHSanaei/3x-ui/assets/115543613/7aa895dd-048a-42e7-989b-afd41a74e2e1" alt="Image"></a></p>
|
||||
|
||||
- USDT (TRC20): `TXncxkvhkDWGts487Pjqq1qT9JmwRUz8CC`
|
||||
- MATIC (polygon): `0x41C9548675D044c6Bfb425786C765bc37427256A`
|
||||
- LTC (Litecoin): `ltc1q2ach7x6d2zq0n4l0t4zl7d7xe2s6fs7a3vspwv`
|
||||
|
||||
## 安装 & 升级
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.3.8
|
||||
2.3.10
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
@@ -18,54 +19,51 @@ import (
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
var initializers = []func() error{
|
||||
initUser,
|
||||
initInbound,
|
||||
initOutbound,
|
||||
initSetting,
|
||||
initInboundClientIps,
|
||||
initClientTraffic,
|
||||
const (
|
||||
defaultUsername = "admin"
|
||||
defaultPassword = "admin"
|
||||
defaultSecret = ""
|
||||
)
|
||||
|
||||
func initModels() error {
|
||||
models := []interface{}{
|
||||
&model.User{},
|
||||
&model.Inbound{},
|
||||
&model.OutboundTraffics{},
|
||||
&model.Setting{},
|
||||
&model.InboundClientIps{},
|
||||
&xray.ClientTraffic{},
|
||||
}
|
||||
for _, model := range models {
|
||||
if err := db.AutoMigrate(model); err != nil {
|
||||
log.Printf("Error auto migrating model: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initUser() error {
|
||||
err := db.AutoMigrate(&model.User{})
|
||||
empty, err := isTableEmpty("users")
|
||||
if err != nil {
|
||||
log.Printf("Error checking if users table is empty: %v", err)
|
||||
return err
|
||||
}
|
||||
var count int64
|
||||
err = db.Model(&model.User{}).Count(&count).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
if empty {
|
||||
user := &model.User{
|
||||
Username: "admin",
|
||||
Password: "admin",
|
||||
LoginSecret: "",
|
||||
Username: defaultUsername,
|
||||
Password: defaultPassword,
|
||||
LoginSecret: defaultSecret,
|
||||
}
|
||||
return db.Create(user).Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initInbound() error {
|
||||
return db.AutoMigrate(&model.Inbound{})
|
||||
}
|
||||
|
||||
func initOutbound() error {
|
||||
return db.AutoMigrate(&model.OutboundTraffics{})
|
||||
}
|
||||
|
||||
func initSetting() error {
|
||||
return db.AutoMigrate(&model.Setting{})
|
||||
}
|
||||
|
||||
func initInboundClientIps() error {
|
||||
return db.AutoMigrate(&model.InboundClientIps{})
|
||||
}
|
||||
|
||||
func initClientTraffic() error {
|
||||
return db.AutoMigrate(&xray.ClientTraffic{})
|
||||
func isTableEmpty(tableName string) (bool, error) {
|
||||
var count int64
|
||||
err := db.Table(tableName).Count(&count).Error
|
||||
return count == 0, err
|
||||
}
|
||||
|
||||
func InitDB(dbPath string) error {
|
||||
@@ -91,15 +89,27 @@ func InitDB(dbPath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, initialize := range initializers {
|
||||
if err := initialize(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := initModels(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := initUser(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CloseDB() error {
|
||||
if db != nil {
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sqlDB.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDB() *gorm.DB {
|
||||
return db
|
||||
}
|
||||
|
||||
42
go.mod
42
go.mod
@@ -1,6 +1,6 @@
|
||||
module x-ui
|
||||
|
||||
go 1.22.4
|
||||
go 1.22.5
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/gzip v1.0.1
|
||||
@@ -14,12 +14,12 @@ require (
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/shirou/gopsutil/v4 v4.24.6
|
||||
github.com/valyala/fasthttp v1.55.0
|
||||
github.com/xtls/xray-core v1.8.16
|
||||
github.com/xtls/xray-core v1.8.21
|
||||
go.uber.org/atomic v1.11.0
|
||||
golang.org/x/text v0.16.0
|
||||
google.golang.org/grpc v1.65.0
|
||||
gorm.io/driver/sqlite v1.5.6
|
||||
gorm.io/gorm v1.25.10
|
||||
gorm.io/gorm v1.25.11
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -40,10 +40,10 @@ require (
|
||||
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
|
||||
github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da // indirect
|
||||
github.com/gorilla/context v1.1.2 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/gorilla/sessions v1.2.2 // indirect
|
||||
github.com/gorilla/sessions v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/grbit/go-json v0.11.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
@@ -52,25 +52,26 @@ require (
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.22 // 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.19.0 // indirect
|
||||
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/quic-go/quic-go v0.45.0 // indirect
|
||||
github.com/refraction-networking/utls v1.6.6 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/quic-go v0.45.1 // 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.11.0 // indirect
|
||||
github.com/sagernet/sing v0.4.1 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/sagernet/sing v0.4.2 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
||||
@@ -78,21 +79,22 @@ require (
|
||||
github.com/valyala/fastjson v1.6.4 // indirect
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/xtls/reality v0.0.0-20240429224917-ecc4401070cc // indirect
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.25.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
golang.org/x/net v0.27.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
golang.org/x/tools v0.23.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-20240604185151-ef581f913117 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect
|
||||
|
||||
80
go.sum
80
go.sum
@@ -97,8 +97,8 @@ 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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da h1:xRmpO92tb8y+Z85iUOMOicpCfaYcv7o3Cg3wKrIpg8g=
|
||||
github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
@@ -106,8 +106,8 @@ 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=
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
||||
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
||||
github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg=
|
||||
github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grbit/go-json v0.11.0 h1:bAbyMdYrYl/OjYsSqLH99N2DyQ291mHy726Mx+sYrnc=
|
||||
@@ -139,8 +139,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0=
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI=
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
@@ -179,31 +179,33 @@ github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE=
|
||||
github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
|
||||
github.com/refraction-networking/utls v1.6.6 h1:igFsYBUJPYM8Rno9xUuDoM5GQrVEqY4llzEXOkL43Ig=
|
||||
github.com/refraction-networking/utls v1.6.6/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/quic-go v0.45.1 h1:tPfeYCk+uZHjmDRwHHQmvHRYL2t44ROTujLeFVBmjCA=
|
||||
github.com/quic-go/quic-go v0.45.1/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
|
||||
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=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sagernet/sing v0.4.1 h1:zVlpE+7k7AFoC2pv6ReqLf0PIHjihL/jsBl5k05PQFk=
|
||||
github.com/sagernet/sing v0.4.1/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
|
||||
github.com/sagernet/sing v0.4.2 h1:jzGNJdZVRI0xlAfFugsIQUPvyB9SuWvbJK7zQCXc4QM=
|
||||
github.com/sagernet/sing v0.4.2/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||
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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil/v4 v4.24.6 h1:9qqCSYF2pgOU+t+NgJtp7Co5+5mHF/HyKBUckySQL64=
|
||||
github.com/shirou/gopsutil/v4 v4.24.6/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA=
|
||||
@@ -250,10 +252,10 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
||||
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/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
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.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
@@ -273,10 +275,10 @@ github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3/go.mo
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20240429224917-ecc4401070cc h1:0Nj8T1n7F7+v4vRVroaJIvY6R0vNABLfPH+lzPHRJvI=
|
||||
github.com/xtls/reality v0.0.0-20240429224917-ecc4401070cc/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||
github.com/xtls/xray-core v1.8.16 h1:PhbpdREAIvDS7xmxR6Sdpkx0h5ugmf6wIoWECWtJ0kE=
|
||||
github.com/xtls/xray-core v1.8.16/go.mod h1:tjzDQQJpFORuhf7fBsiswiexLVEeJpAfMsD0NE5xV7M=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||
github.com/xtls/xray-core v1.8.21 h1:cNdepud+R9PENKzXlSZsq0je4BWI6liXAuep6CD6xvk=
|
||||
github.com/xtls/xray-core v1.8.21/go.mod h1:0CwyMPNA5Cs+ukPXHbYQGgne/ug0PuXOSVqBu7zyXOc=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
@@ -297,13 +299,13 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
|
||||
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -337,8 +339,6 @@ golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -353,8 +353,8 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
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=
|
||||
@@ -371,8 +371,8 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
@@ -395,8 +395,8 @@ 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/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
|
||||
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 h1:ze1vwAdliUAr68RQ5NtufWaXaOg8WUO2OACzEV+TNdE=
|
||||
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||
|
||||
@@ -1023,10 +1023,9 @@ func (s *SubService) genRemark(inbound *model.Inbound, email string, extra strin
|
||||
remark = append(remark, fmt.Sprintf("%dM⏳", minutes))
|
||||
}
|
||||
case exp < 0:
|
||||
passedSeconds := now - exp
|
||||
days := passedSeconds / 86400
|
||||
hours := (passedSeconds % 86400) / 3600
|
||||
minutes := (passedSeconds % 3600) / 60
|
||||
days := exp / -86400
|
||||
hours := (exp % -86400) / 3600
|
||||
minutes := (exp % -3600) / 60
|
||||
if days > 0 {
|
||||
if hours > 0 {
|
||||
remark = append(remark, fmt.Sprintf("%dD,%dH⏳", days, hours))
|
||||
|
||||
@@ -577,6 +577,10 @@ class Outbound extends CommonClass {
|
||||
}
|
||||
|
||||
canEnableMux() {
|
||||
if (this.settings.flow && this.settings.flow != ''){
|
||||
this.mux.enabled = false;
|
||||
return false;
|
||||
}
|
||||
return [Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks, Protocols.HTTP, Protocols.Socks].includes(this.protocol);
|
||||
}
|
||||
|
||||
|
||||
@@ -523,7 +523,7 @@ class HTTPUpgradeStreamSettings extends XrayCommonClass {
|
||||
}
|
||||
|
||||
class SplitHTTPStreamSettings extends XrayCommonClass {
|
||||
constructor(path='/', host='', headers=[] , maxUploadSize= 1, maxConcurrentUploads= 10) {
|
||||
constructor(path='/', host='', headers=[] , maxUploadSize= 1000000, maxConcurrentUploads= 10) {
|
||||
super();
|
||||
this.path = path;
|
||||
this.host = host;
|
||||
@@ -570,7 +570,7 @@ class TlsStreamSettings extends XrayCommonClass {
|
||||
disableSystemRoot = false,
|
||||
enableSessionResumption = false,
|
||||
certificates=[new TlsStreamSettings.Cert()],
|
||||
alpn=[ALPN_OPTION.H2,ALPN_OPTION.HTTP1],
|
||||
alpn=[ALPN_OPTION.H3,ALPN_OPTION.H2,ALPN_OPTION.HTTP1],
|
||||
settings=new TlsStreamSettings.Settings()) {
|
||||
super();
|
||||
this.sni = serverName;
|
||||
@@ -712,7 +712,7 @@ TlsStreamSettings.Settings = class extends XrayCommonClass {
|
||||
class XtlsStreamSettings extends XrayCommonClass {
|
||||
constructor(serverName='',
|
||||
certificates=[new XtlsStreamSettings.Cert()],
|
||||
alpn=[ALPN_OPTION.H2,ALPN_OPTION.HTTP1],
|
||||
alpn=[ALPN_OPTION.H3,ALPN_OPTION.H2,ALPN_OPTION.HTTP1],
|
||||
settings=new XtlsStreamSettings.Settings()) {
|
||||
super();
|
||||
this.sni = serverName;
|
||||
@@ -892,7 +892,7 @@ class RealityStreamSettings extends XrayCommonClass {
|
||||
}
|
||||
|
||||
RealityStreamSettings.Settings = class extends XrayCommonClass {
|
||||
constructor(publicKey = '', fingerprint = UTLS_FINGERPRINT.UTLS_FIREFOX, serverName = '', spiderX= '/') {
|
||||
constructor(publicKey = '', fingerprint = UTLS_FINGERPRINT.UTLS_RANDOM, serverName = '', spiderX= '/') {
|
||||
super();
|
||||
this.publicKey = publicKey;
|
||||
this.fingerprint = fingerprint;
|
||||
@@ -2608,4 +2608,4 @@ Inbound.WireguardSettings.Peer = class extends XrayCommonClass {
|
||||
keepAlive: this.keepAlive?? undefined,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -128,7 +128,7 @@ Date.prototype.formatDateTime = function (split = ' ') {
|
||||
};
|
||||
|
||||
class DateUtil {
|
||||
// String string to date object
|
||||
// String to date object
|
||||
static parseDate(str) {
|
||||
return new Date(str.replace(/-/g, '/'));
|
||||
}
|
||||
@@ -143,4 +143,9 @@ class DateUtil {
|
||||
date.setMinTime();
|
||||
return date;
|
||||
}
|
||||
|
||||
static convertToJalalian(date) {
|
||||
return date && moment.isMoment(date) ? date.format('jYYYY/jMM/jDD HH:mm:ss') : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,73 +1,57 @@
|
||||
class Msg {
|
||||
constructor(success, msg, obj) {
|
||||
this.success = false;
|
||||
this.msg = "";
|
||||
this.obj = null;
|
||||
|
||||
if (success != null) {
|
||||
this.success = success;
|
||||
}
|
||||
if (msg != null) {
|
||||
this.msg = msg;
|
||||
}
|
||||
if (obj != null) {
|
||||
this.obj = obj;
|
||||
}
|
||||
constructor(success = false, msg = "", obj = null) {
|
||||
this.success = success;
|
||||
this.msg = msg;
|
||||
this.obj = obj;
|
||||
}
|
||||
}
|
||||
|
||||
class HttpUtil {
|
||||
static _handleMsg(msg) {
|
||||
if (!(msg instanceof Msg)) {
|
||||
if (!(msg instanceof Msg) || msg.msg === "") {
|
||||
return;
|
||||
}
|
||||
if (msg.msg === "") {
|
||||
return;
|
||||
}
|
||||
if (msg.success) {
|
||||
Vue.prototype.$message.success(msg.msg);
|
||||
} else {
|
||||
Vue.prototype.$message.error(msg.msg);
|
||||
}
|
||||
const messageType = msg.success ? 'success' : 'error';
|
||||
Vue.prototype.$message[messageType](msg.msg);
|
||||
}
|
||||
|
||||
static _respToMsg(resp) {
|
||||
const data = resp.data;
|
||||
const { data } = resp;
|
||||
if (data == null) {
|
||||
return new Msg(true);
|
||||
} else if (typeof data === 'object') {
|
||||
if (data.hasOwnProperty('success')) {
|
||||
return new Msg(data.success, data.msg, data.obj);
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
} else {
|
||||
return new Msg(false, 'unknown data:', data);
|
||||
}
|
||||
if (typeof data === 'object' && 'success' in data) {
|
||||
return new Msg(data.success, data.msg, data.obj);
|
||||
}
|
||||
return typeof data === 'object' ? data : new Msg(false, 'unknown data:', data);
|
||||
}
|
||||
|
||||
static async get(url, data, options) {
|
||||
let msg;
|
||||
static async get(url, params, options = {}) {
|
||||
try {
|
||||
const resp = await axios.get(url, data, options);
|
||||
msg = this._respToMsg(resp);
|
||||
} catch (e) {
|
||||
msg = new Msg(false, e.toString());
|
||||
const resp = await axios.get(url, { params, ...options });
|
||||
const msg = this._respToMsg(resp);
|
||||
this._handleMsg(msg);
|
||||
return msg;
|
||||
} catch (error) {
|
||||
console.error('GET request failed:', error);
|
||||
const errorMsg = new Msg(false, error.response?.data?.message || error.message);
|
||||
this._handleMsg(errorMsg);
|
||||
return errorMsg;
|
||||
}
|
||||
this._handleMsg(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
static async post(url, data, options) {
|
||||
let msg;
|
||||
static async post(url, data, options = {}) {
|
||||
try {
|
||||
const resp = await axios.post(url, data, options);
|
||||
msg = this._respToMsg(resp);
|
||||
} catch (e) {
|
||||
msg = new Msg(false, e.toString());
|
||||
const msg = this._respToMsg(resp);
|
||||
this._handleMsg(msg);
|
||||
return msg;
|
||||
} catch (error) {
|
||||
console.error('POST request failed:', error);
|
||||
const errorMsg = new Msg(false, error.response?.data?.message || error.message);
|
||||
this._handleMsg(errorMsg);
|
||||
return errorMsg;
|
||||
}
|
||||
this._handleMsg(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
static async postWithModal(url, data, modal) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"x-ui/logger"
|
||||
@@ -64,14 +65,17 @@ func (a *IndexController) login(c *gin.Context) {
|
||||
|
||||
user := a.userService.CheckUser(form.Username, form.Password, form.LoginSecret)
|
||||
timeStr := time.Now().Format("2006-01-02 15:04:05")
|
||||
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\"", form.Username, form.Password, form.LoginSecret)
|
||||
a.tgbot.UserLoginNotify(form.Username, form.Password, getRemoteIp(c), timeStr, 0)
|
||||
logger.Warningf("wrong username or password or secret: \"%s\" \"%s\" \"%s\"", safeUser, safePass, safeSecret)
|
||||
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", form.Username, getRemoteIp(c))
|
||||
a.tgbot.UserLoginNotify(form.Username, ``, 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()
|
||||
|
||||
@@ -12,6 +12,7 @@ type XraySettingController struct {
|
||||
InboundService service.InboundService
|
||||
OutboundService service.OutboundService
|
||||
XrayService service.XrayService
|
||||
WarpService service.WarpService
|
||||
}
|
||||
|
||||
func NewXraySettingController(g *gin.RouterGroup) *XraySettingController {
|
||||
@@ -72,16 +73,18 @@ func (a *XraySettingController) warp(c *gin.Context) {
|
||||
var err error
|
||||
switch action {
|
||||
case "data":
|
||||
resp, err = a.XraySettingService.GetWarp()
|
||||
resp, err = a.WarpService.GetWarpData()
|
||||
case "del":
|
||||
err = a.WarpService.DelWarpData()
|
||||
case "config":
|
||||
resp, err = a.XraySettingService.GetWarpConfig()
|
||||
resp, err = a.WarpService.GetWarpConfig()
|
||||
case "reg":
|
||||
skey := c.PostForm("privateKey")
|
||||
pkey := c.PostForm("publicKey")
|
||||
resp, err = a.XraySettingService.RegWarp(skey, pkey)
|
||||
resp, err = a.WarpService.RegWarp(skey, pkey)
|
||||
case "license":
|
||||
license := c.PostForm("license")
|
||||
resp, err = a.XraySettingService.SetWarpLicense(license)
|
||||
resp, err = a.WarpService.SetWarpLicense(license)
|
||||
}
|
||||
|
||||
jsonObj(c, resp, err)
|
||||
|
||||
@@ -108,15 +108,16 @@
|
||||
format="YYYY-MM-DD HH:mm:ss" :dropdown-class-name="themeSwitcher.currentTheme"
|
||||
v-model="clientsBulkModal.expiryTime"></a-date-picker>
|
||||
<persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
|
||||
value="clientsBulkModal.expiryTime" v-model="clientsBulkModal.expiryTime"></persian-datepicker>
|
||||
value="clientsBulkModal.expiryTime" v-model="clientsBulkModal.expiryTime">
|
||||
</persian-datepicker>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="clientsBulkModal.expiryTime != 0">
|
||||
<template slot="label">
|
||||
<span>{{ i18n "pages.client.renew" }}</span>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<span>{{ i18n "pages.client.renewDesc" }}</span>
|
||||
</template>
|
||||
{{ i18n "pages.client.renew" }}
|
||||
<a-icon type="question-circle"></a-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
@@ -54,12 +54,13 @@
|
||||
<a-icon type="question-circle"></a-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-date-picker style="width: 100%;" v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme"
|
||||
v-model="dbInbound._expiryTime"></a-date-picker>
|
||||
<persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
|
||||
value="dbInbound._expiryTime" v-model="dbInbound._expiryTime"></persian-datepicker>
|
||||
</a-form-item>
|
||||
<a-date-picker style="width: 100%;" v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }"
|
||||
format="YYYY-MM-DD HH:mm:ss" :dropdown-class-name="themeSwitcher.currentTheme"
|
||||
v-model="dbInbound._expiryTime"></a-date-picker>
|
||||
<persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
|
||||
value="dbInbound._expiryTime" v-model="dbInbound._expiryTime">
|
||||
</persian-datepicker>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- vmess settings -->
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="Max Upload Size (MB)">
|
||||
<a-form-item label="Max Upload Size (Byte)">
|
||||
<a-input-number v-model="inbound.stream.splithttp.maxUploadSize" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label="Max Concurrent Upload">
|
||||
|
||||
@@ -90,7 +90,14 @@
|
||||
<template slot="content">
|
||||
<span v-if="client.expiryTime < 0">{{ i18n "pages.client.delayedStart" }}
|
||||
</span>
|
||||
<span v-else>[[ DateUtil.formatMillis(client._expiryTime) ]]</span>
|
||||
<span v-else>
|
||||
<template v-if="app.datepicker === 'gregorian'">
|
||||
[[ DateUtil.formatMillis(client._expiryTime) ]]
|
||||
</template>
|
||||
<template v-else>
|
||||
[[ DateUtil.convertToJalalian(moment(client._expiryTime)) ]]
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
<table>
|
||||
<tr class="tr-table-box">
|
||||
@@ -108,7 +115,14 @@
|
||||
<template slot="content">
|
||||
<span v-if="client.expiryTime < 0">{{ i18n "pages.client.delayedStart" }}
|
||||
</span>
|
||||
<span v-else>[[ DateUtil.formatMillis(client._expiryTime) ]]</span>
|
||||
<span v-else>
|
||||
<template v-if="app.datepicker === 'gregorian'">
|
||||
[[ DateUtil.formatMillis(client._expiryTime) ]]
|
||||
</template>
|
||||
<template v-else>
|
||||
[[ DateUtil.convertToJalalian(moment(client._expiryTime)) ]]
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
<a-tag style="min-width: 50px; border: none;" :color="userExpiryColor(app.expireDiff, client, themeSwitcher.isDarkTheme)"> [[ remainedDays(client.expiryTime) ]] </a-tag>
|
||||
</a-popover>
|
||||
@@ -201,7 +215,14 @@
|
||||
<template slot="content">
|
||||
<span v-if="client.expiryTime < 0">{{ i18n "pages.client.delayedStart" }}
|
||||
</span>
|
||||
<span v-else>[[ DateUtil.formatMillis(client._expiryTime) ]]</span>
|
||||
<span v-else>
|
||||
<template v-if="app.datepicker === 'gregorian'">
|
||||
[[ DateUtil.formatMillis(client._expiryTime) ]]
|
||||
</template>
|
||||
<template v-else>
|
||||
[[ DateUtil.convertToJalalian(moment(client._expiryTime)) ]]
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
<a-progress :show-info="false" :status="isClientEnabled(record, client.email)? 'exception' : ''" :percent="expireProgress(client.expiryTime, client.reset)" />
|
||||
</a-popover>
|
||||
@@ -214,7 +235,14 @@
|
||||
<template slot="content">
|
||||
<span v-if="client.expiryTime < 0">{{ i18n "pages.client.delayedStart" }}
|
||||
</span>
|
||||
<span v-else>[[ DateUtil.formatMillis(client._expiryTime) ]]</span>
|
||||
<span v-else>
|
||||
<template v-if="app.datepicker === 'gregorian'">
|
||||
[[ DateUtil.formatMillis(client._expiryTime) ]]
|
||||
</template>
|
||||
<template v-else>
|
||||
[[ DateUtil.convertToJalalian(moment(client._expiryTime)) ]]
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
<a-tag style="min-width: 50px; border: none;" :color="userExpiryColor(app.expireDiff, client, themeSwitcher.isDarkTheme)"> [[ remainedDays(client.expiryTime) ]] </a-tag>
|
||||
</a-popover>
|
||||
|
||||
@@ -221,7 +221,14 @@
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="infoModal.clientSettings.expiryTime > 0">
|
||||
<a-tag :color="usageColor(new Date().getTime(), app.expireDiff, infoModal.clientSettings.expiryTime)"> [[ DateUtil.formatMillis(infoModal.clientSettings.expiryTime) ]] </a-tag>
|
||||
<a-tag :color="usageColor(new Date().getTime(), app.expireDiff, infoModal.clientSettings.expiryTime)">
|
||||
<template v-if="app.datepicker === 'gregorian'">
|
||||
[[ DateUtil.formatMillis(infoModal.clientSettings.expiryTime) ]]
|
||||
</template>
|
||||
<template v-else>
|
||||
[[ DateUtil.convertToJalalian(moment(infoModal.clientSettings.expiryTime)) ]]
|
||||
</template>
|
||||
</a-tag>
|
||||
</template>
|
||||
<a-tag v-else-if="infoModal.clientSettings.expiryTime < 0" color="green">[[ infoModal.clientSettings.expiryTime / -86400000 ]] {{ i18n "pages.client.days" }}
|
||||
</a-tag>
|
||||
|
||||
@@ -403,9 +403,12 @@
|
||||
</template>
|
||||
<template slot="expiryTime" slot-scope="text, dbInbound">
|
||||
<a-popover v-if="dbInbound.expiryTime > 0" :overlay-class-name="themeSwitcher.currentTheme">
|
||||
<template slot="content">
|
||||
<template slot="content" v-if="app.datepicker === 'gregorian'">
|
||||
[[ DateUtil.formatMillis(dbInbound.expiryTime) ]]
|
||||
</template>
|
||||
<template v-else slot="content">
|
||||
[[ DateUtil.convertToJalalian(moment(dbInbound.expiryTime)) ]]
|
||||
</template>
|
||||
<a-tag style="min-width: 50px;" :color="usageColor(new Date().getTime(), app.expireDiff, dbInbound._expiryTime)">
|
||||
[[ remainedDays(dbInbound._expiryTime) ]]
|
||||
</a-tag>
|
||||
@@ -498,8 +501,14 @@
|
||||
<tr>
|
||||
<td>{{ i18n "pages.inbounds.expireDate" }}</td>
|
||||
<td>
|
||||
<a-tag style="min-width: 50px; text-align: center;" v-if="dbInbound.expiryTime > 0" :color="dbInbound.isExpiry? 'red': 'blue'">
|
||||
[[ DateUtil.formatMillis(dbInbound.expiryTime) ]]
|
||||
<a-tag style="min-width: 50px; text-align: center;" v-if="dbInbound.expiryTime > 0"
|
||||
:color="dbInbound.isExpiry? 'red': 'blue'">
|
||||
<template v-if="app.datepicker === 'gregorian'">
|
||||
[[ DateUtil.formatMillis(dbInbound.expiryTime) ]]
|
||||
</template>
|
||||
<template v-else>
|
||||
[[ DateUtil.convertToJalalian(moment(dbInbound.expiryTime)) ]]
|
||||
</template>
|
||||
</a-tag>
|
||||
<a-tag v-else style="text-align: center;" color="purple" class="infinite-tag">
|
||||
<svg height="10px" width="14px" viewBox="0 0 640 512" fill="currentColor">
|
||||
|
||||
@@ -24,19 +24,22 @@
|
||||
<td>[[ warpModal.warpData.private_key ]]</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a-button @click="delConfig" :loading="warpModal.confirmLoading" type="danger">{{ i18n "delete" }}</a-button>
|
||||
<a-divider style="margin: 0;">{{ i18n "pages.xray.outbound.settings" }}</a-divider>
|
||||
<a-collapse style="margin: 10px 0;">
|
||||
<a-collapse-panel header='WARP/WARP+ License Key'>
|
||||
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||
<a-form-item label="Key">
|
||||
<a-input v-model="warpPlus"></a-input>
|
||||
<a-button @click="updateLicense(warpPlus)" :disabled="warpPlus.length<26" :loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.update" }}</a-button>
|
||||
<a-button @click="updateLicense(warpPlus)" :disabled="warpPlus.length<26"
|
||||
:loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.update" }}</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
<a-divider style="margin: 0;">{{ i18n "pages.xray.outbound.accountInfo" }}</a-divider>
|
||||
<a-button icon="sync" @click="getConfig" style="margin-top: 5px; margin-bottom: 10px;" :loading="warpModal.confirmLoading" type="primary">{{ i18n "info" }}</a-button>
|
||||
<a-button icon="sync" @click="getConfig" style="margin-top: 5px; margin-bottom: 10px;"
|
||||
:loading="warpModal.confirmLoading" type="primary">{{ i18n "info" }}</a-button>
|
||||
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig)">
|
||||
<table style="width: 100%">
|
||||
<tr class="client-table-odd-row">
|
||||
@@ -51,39 +54,39 @@
|
||||
<td>Device Enabled</td>
|
||||
<td>[[ warpModal.warpConfig.enabled ]]</td>
|
||||
</tr>
|
||||
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account)">
|
||||
<tr>
|
||||
<td>Account Type</td>
|
||||
<td>[[ warpModal.warpConfig.account.account_type ]]</td>
|
||||
</tr>
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Role</td>
|
||||
<td>[[ warpModal.warpConfig.account.role ]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WARP+ Data</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.premium_data) ]]</td>
|
||||
</tr>
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Quota</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.quota) ]]</td>
|
||||
</tr>
|
||||
<tr v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account.usage)">
|
||||
<td>Usage</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.usage) ]]</td>
|
||||
</tr>
|
||||
</template>
|
||||
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account)">
|
||||
<tr>
|
||||
<td>Account Type</td>
|
||||
<td>[[ warpModal.warpConfig.account.account_type ]]</td>
|
||||
</tr>
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Role</td>
|
||||
<td>[[ warpModal.warpConfig.account.role ]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WARP+ Data</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.premium_data) ]]</td>
|
||||
</tr>
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Quota</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.quota) ]]</td>
|
||||
</tr>
|
||||
<tr v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account.usage)">
|
||||
<td>Usage</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.usage) ]]</td>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
<a-divider style="margin: 10px 0;">{{ i18n "pages.xray.outbound.outboundStatus" }}</a-divider>
|
||||
<a-form :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||
<template v-if="warpOutboundIndex>=0">
|
||||
<a-tag color="green" style="line-height: 31px;">{{ i18n "enabled" }}</a-tag>
|
||||
<a-button @click="resetOutbound" :loading="warpModal.confirmLoading" type="danger">{{ i18n "reset" }}</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-tag color="orange" style="line-height: 31px;">{{ i18n "disabled" }}</a-tag>
|
||||
<a-button @click="addOutbound" :loading="warpModal.confirmLoading" type="primary">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
|
||||
</template>
|
||||
<template v-if="warpOutboundIndex>=0">
|
||||
<a-tag color="green" style="line-height: 31px;">{{ i18n "enabled" }}</a-tag>
|
||||
<a-button @click="resetOutbound" :loading="warpModal.confirmLoading" type="danger">{{ i18n "reset" }}</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-tag color="orange" style="line-height: 31px;">{{ i18n "disabled" }}</a-tag>
|
||||
<a-button @click="addOutbound" :loading="warpModal.confirmLoading" type="primary">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
|
||||
</template>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
@@ -101,21 +104,20 @@
|
||||
this.visible = true;
|
||||
this.warpConfig = null;
|
||||
this.getData();
|
||||
|
||||
},
|
||||
close() {
|
||||
this.visible = false;
|
||||
this.loading(false);
|
||||
},
|
||||
loading(loading=true) {
|
||||
loading(loading = true) {
|
||||
this.confirmLoading = loading;
|
||||
},
|
||||
async getData(){
|
||||
async getData() {
|
||||
this.loading(true);
|
||||
const msg = await HttpUtil.post('/panel/xray/warp/data');
|
||||
this.loading(false);
|
||||
if (msg.success) {
|
||||
this.warpData = msg.obj.length>0 ? JSON.parse(msg.obj): null;
|
||||
this.warpData = msg.obj.length > 0 ? JSON.parse(msg.obj) : null;
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -131,14 +133,15 @@
|
||||
collectConfig() {
|
||||
config = warpModal.warpConfig.config;
|
||||
peer = config.peers[0];
|
||||
if(config){
|
||||
if (config) {
|
||||
warpModal.warpOutbound = Outbound.fromJson({
|
||||
tag: 'warp',
|
||||
protocol: Protocols.Wireguard,
|
||||
settings: {
|
||||
mtu: 1420,
|
||||
secretKey: warpModal.warpData.private_key,
|
||||
address: Object.values(config.interface.addresses),
|
||||
address: this.getAddresses(config.interface.addresses),
|
||||
reserved: this.getResolved(config.client_id),
|
||||
domainStrategy: 'ForceIP',
|
||||
peers: [{
|
||||
publicKey: peer.public_key,
|
||||
@@ -149,10 +152,32 @@
|
||||
});
|
||||
}
|
||||
},
|
||||
async register(){
|
||||
getAddresses(addrs) {
|
||||
let addresses = [];
|
||||
if (addrs.v4) addresses.push(addrs.v4 + "/32");
|
||||
if (addrs.v6) addresses.push(addrs.v6 + "/128");
|
||||
return addresses;
|
||||
},
|
||||
getResolved(client_id) {
|
||||
let reserved = [];
|
||||
let decoded = atob(client_id);
|
||||
let hexString = '';
|
||||
for (let i = 0; i < decoded.length; i++) {
|
||||
let hex = decoded.charCodeAt(i).toString(16);
|
||||
hexString += (hex.length === 1 ? '0' : '') + hex;
|
||||
}
|
||||
|
||||
for (let i = 0; i < hexString.length; i += 2) {
|
||||
let hexByte = hexString.slice(i, i + 2);
|
||||
let decValue = parseInt(hexByte, 16);
|
||||
reserved.push(decValue);
|
||||
}
|
||||
return reserved;
|
||||
},
|
||||
async register() {
|
||||
warpModal.loading(true);
|
||||
keys = Wireguard.generateKeypair();
|
||||
const msg = await HttpUtil.post('/panel/xray/warp/reg',keys);
|
||||
const msg = await HttpUtil.post('/panel/xray/warp/reg', keys);
|
||||
if (msg.success) {
|
||||
resp = JSON.parse(msg.obj);
|
||||
warpModal.warpData = resp.data;
|
||||
@@ -161,9 +186,9 @@
|
||||
}
|
||||
warpModal.loading(false);
|
||||
},
|
||||
async updateLicense(l){
|
||||
async updateLicense(l) {
|
||||
warpModal.loading(true);
|
||||
const msg = await HttpUtil.post('/panel/xray/warp/license',{license: l});
|
||||
const msg = await HttpUtil.post('/panel/xray/warp/license', { license: l });
|
||||
if (msg.success) {
|
||||
warpModal.warpData = JSON.parse(msg.obj);
|
||||
warpModal.warpConfig = null;
|
||||
@@ -171,7 +196,7 @@
|
||||
}
|
||||
warpModal.loading(false);
|
||||
},
|
||||
async getConfig(){
|
||||
async getConfig() {
|
||||
warpModal.loading(true);
|
||||
const msg = await HttpUtil.post('/panel/xray/warp/config');
|
||||
warpModal.loading(false);
|
||||
@@ -180,20 +205,37 @@
|
||||
this.collectConfig();
|
||||
}
|
||||
},
|
||||
addOutbound(){
|
||||
async delConfig() {
|
||||
warpModal.loading(true);
|
||||
const msg = await HttpUtil.post('/panel/xray/warp/del');
|
||||
warpModal.loading(false);
|
||||
if (msg.success) {
|
||||
warpModal.warpData = null;
|
||||
warpModal.warpConfig = null;
|
||||
this.delOutbound();
|
||||
}
|
||||
},
|
||||
addOutbound() {
|
||||
app.templateSettings.outbounds.push(warpModal.warpOutbound.toJson());
|
||||
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
|
||||
warpModal.close();
|
||||
},
|
||||
resetOutbound(){
|
||||
resetOutbound() {
|
||||
app.templateSettings.outbounds[this.warpOutboundIndex] = warpModal.warpOutbound.toJson();
|
||||
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
|
||||
warpModal.close();
|
||||
},
|
||||
delOutbound() {
|
||||
if (this.warpOutboundIndex != -1) {
|
||||
app.templateSettings.outbounds.splice(this.warpOutboundIndex, 1);
|
||||
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
|
||||
}
|
||||
warpModal.close();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
warpOutboundIndex: {
|
||||
get: function() {
|
||||
get: function () {
|
||||
return app.templateSettings ? app.templateSettings.outbounds.findIndex((o) => o.tag == 'warp') : -1;
|
||||
}
|
||||
}
|
||||
@@ -201,4 +243,4 @@
|
||||
});
|
||||
|
||||
</script>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -1054,12 +1054,13 @@
|
||||
});
|
||||
},
|
||||
changeObsCode() {
|
||||
if (this.obsSettings == ''){
|
||||
return
|
||||
}
|
||||
if(this.cm != null) {
|
||||
this.cm.toTextArea();
|
||||
}
|
||||
if (this.obsSettings == ''){
|
||||
this.cm = null;
|
||||
return
|
||||
}
|
||||
textAreaObj = document.getElementById('obsSetting');
|
||||
textAreaObj.value = this[this.obsSettings];
|
||||
this.cm = CodeMirror.fromTextArea(textAreaObj, this.cmOptions);
|
||||
@@ -1267,7 +1268,8 @@
|
||||
balancer: {
|
||||
tag: '',
|
||||
strategy: 'random',
|
||||
selector: []
|
||||
selector: [],
|
||||
fallbackTag: ''
|
||||
},
|
||||
confirm: (balancer) => {
|
||||
balancerModal.loading();
|
||||
@@ -1277,27 +1279,18 @@
|
||||
}
|
||||
let tmpBalancer = {
|
||||
'tag': balancer.tag,
|
||||
'selector': balancer.selector
|
||||
'selector': balancer.selector,
|
||||
'fallbackTag': balancer.fallbackTag
|
||||
};
|
||||
if (balancer.strategy && balancer.strategy != 'random') {
|
||||
tmpBalancer.strategy = {
|
||||
'type': balancer.strategy
|
||||
};
|
||||
if (balancer.strategy == 'leastPing'){
|
||||
if (!newTemplateSettings.observatory)
|
||||
newTemplateSettings.observatory = this.defaultObservatory;
|
||||
if (!newTemplateSettings.observatory.subjectSelector.includes(balancer.tag))
|
||||
newTemplateSettings.observatory.subjectSelector.push(balancer.tag);
|
||||
}
|
||||
if (balancer.strategy == 'leastLoad'){
|
||||
if (!newTemplateSettings.burstObservatory)
|
||||
newTemplateSettings.burstObservatory = this.defaultBurstObservatory;
|
||||
if (!newTemplateSettings.burstObservatory.subjectSelector.includes(balancer.tag))
|
||||
newTemplateSettings.burstObservatory.subjectSelector.push(balancer.tag);
|
||||
}
|
||||
}
|
||||
newTemplateSettings.routing.balancers.push(tmpBalancer);
|
||||
this.templateSettings = newTemplateSettings;
|
||||
if (balancer.strategy == 'leastPing' || balancer.strategy == 'leastLoad')
|
||||
this.updateObservatorySelectors();
|
||||
balancerModal.close();
|
||||
this.changeObsCode();
|
||||
},
|
||||
@@ -1317,7 +1310,8 @@
|
||||
|
||||
let tmpBalancer = {
|
||||
'tag': balancer.tag,
|
||||
'selector': balancer.selector
|
||||
'selector': balancer.selector,
|
||||
'fallbackTag': balancer.fallbackTag
|
||||
};
|
||||
|
||||
// Remove old tag
|
||||
@@ -1332,18 +1326,6 @@
|
||||
tmpBalancer.strategy = {
|
||||
'type': balancer.strategy
|
||||
};
|
||||
if (balancer.strategy == 'leastPing'){
|
||||
if (!newTemplateSettings.observatory)
|
||||
newTemplateSettings.observatory = this.defaultObservatory;
|
||||
if (!newTemplateSettings.observatory.subjectSelector.includes(balancer.tag))
|
||||
newTemplateSettings.observatory.subjectSelector.push(balancer.tag);
|
||||
}
|
||||
if (balancer.strategy == 'leastLoad'){
|
||||
if (!newTemplateSettings.burstObservatory)
|
||||
newTemplateSettings.burstObservatory = this.defaultBurstObservatory;
|
||||
if (!newTemplateSettings.burstObservatory.subjectSelector.includes(balancer.tag))
|
||||
newTemplateSettings.burstObservatory.subjectSelector.push(balancer.tag);
|
||||
}
|
||||
}
|
||||
|
||||
newTemplateSettings.routing.balancers[index] = tmpBalancer;
|
||||
@@ -1356,14 +1338,49 @@
|
||||
});
|
||||
}
|
||||
this.templateSettings = newTemplateSettings;
|
||||
if (balancer.strategy == 'leastPing' || balancer.strategy == 'leastLoad')
|
||||
this.updateObservatorySelectors();
|
||||
balancerModal.close();
|
||||
this.changeObsCode();
|
||||
},
|
||||
isEdit: true
|
||||
});
|
||||
},
|
||||
updateObservatorySelectors(){
|
||||
newTemplateSettings = this.templateSettings;
|
||||
const leastPings = this.balancersData.filter((b) => b.strategy == 'leastPing');
|
||||
const leastLoads = this.balancersData.filter((b) => b.strategy == 'leastLoad');
|
||||
if (leastPings.length>0){
|
||||
if (!newTemplateSettings.observatory)
|
||||
newTemplateSettings.observatory = this.defaultObservatory;
|
||||
newTemplateSettings.observatory.subjectSelector = [];
|
||||
leastPings.forEach((b) => {
|
||||
b.selector.forEach((s) => {
|
||||
if (!newTemplateSettings.observatory.subjectSelector.includes(s))
|
||||
newTemplateSettings.observatory.subjectSelector.push(s);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
delete newTemplateSettings.observatory
|
||||
}
|
||||
if (leastLoads.length>0){
|
||||
if (!newTemplateSettings.burstObservatory)
|
||||
newTemplateSettings.burstObservatory = this.defaultBurstObservatory;
|
||||
newTemplateSettings.burstObservatory.subjectSelector = [];
|
||||
leastLoads.forEach((b) => {
|
||||
b.selector.forEach((s) => {
|
||||
if (!newTemplateSettings.burstObservatory.subjectSelector.includes(s))
|
||||
newTemplateSettings.burstObservatory.subjectSelector.push(s);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
delete newTemplateSettings.burstObservatory
|
||||
}
|
||||
this.templateSettings = newTemplateSettings;
|
||||
this.changeObsCode();
|
||||
},
|
||||
deleteBalancer(index) {
|
||||
let newTemplateSettings = { ...this.templateSettings };
|
||||
newTemplateSettings = this.templateSettings;
|
||||
|
||||
// Remove from balancers
|
||||
const removedBalancer = this.balancersData.splice(index, 1)[0];
|
||||
@@ -1371,27 +1388,14 @@
|
||||
// Remove from settings
|
||||
let realIndex = newTemplateSettings.routing.balancers.findIndex((b) => b.tag === removedBalancer.tag);
|
||||
newTemplateSettings.routing.balancers.splice(realIndex, 1);
|
||||
|
||||
// Remove tag from observatory
|
||||
if (newTemplateSettings.observatory){
|
||||
newTemplateSettings.observatory.subjectSelector = newTemplateSettings.observatory.subjectSelector.filter(s => s != removedBalancer.tag);
|
||||
}
|
||||
if (newTemplateSettings.burstObservatory){
|
||||
newTemplateSettings.burstObservatory.subjectSelector = newTemplateSettings.burstObservatory.subjectSelector.filter(s => s != removedBalancer.tag);
|
||||
}
|
||||
|
||||
// Remove related routing rules
|
||||
newTemplateSettings.routing.rules.forEach((rule) => {
|
||||
if (rule.balancerTag === removedBalancer.tag) {
|
||||
delete rule.balancerTag;
|
||||
}
|
||||
});
|
||||
|
||||
// Update balancers property to an empty array if there are no more balancers
|
||||
if (newTemplateSettings.routing.balancers.length === 0) {
|
||||
delete newTemplateSettings.routing.balancers;
|
||||
}
|
||||
this.templateSettings = newTemplateSettings;
|
||||
this.updateObservatorySelectors();
|
||||
this.obsSettings = '';
|
||||
this.changeObsCode()
|
||||
},
|
||||
addDNSServer(){
|
||||
@@ -1622,7 +1626,8 @@
|
||||
'key': index,
|
||||
'tag': o.tag ? o.tag : "",
|
||||
'strategy': o.strategy?.type ?? "random",
|
||||
'selector': o.selector ? o.selector : []
|
||||
'selector': o.selector ? o.selector : [],
|
||||
'fallbackTag': o.fallbackTag?? '',
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1649,22 +1654,8 @@
|
||||
this.templateSettings = newTemplateSettings;
|
||||
},
|
||||
},
|
||||
observatoryEnable: {
|
||||
get: function () { return this.templateSettings != null && this.templateSettings.observatory },
|
||||
set: function (v) {
|
||||
newTemplateSettings = this.templateSettings;
|
||||
newTemplateSettings.observatory = v ? this.defaultObservatory : undefined;
|
||||
this.templateSettings = newTemplateSettings;
|
||||
}
|
||||
},
|
||||
burstObservatoryEnable: {
|
||||
get: function () { return this.templateSettings != null && this.templateSettings.burstObservatory },
|
||||
set: function (v) {
|
||||
newTemplateSettings = this.templateSettings;
|
||||
newTemplateSettings.burstObservatory = v ? this.defaultBurstObservatory : undefined;
|
||||
this.templateSettings = newTemplateSettings;
|
||||
}
|
||||
},
|
||||
observatoryEnable: function () { return this.templateSettings != null && this.templateSettings.observatory != undefined },
|
||||
burstObservatoryEnable: function () { return this.templateSettings != null && this.templateSettings.burstObservatory != undefined },
|
||||
freedomStrategy: {
|
||||
get: function () {
|
||||
if (!this.templateSettings) return "AsIs";
|
||||
|
||||
@@ -25,13 +25,19 @@
|
||||
<a-select-option value="leastPing">Least Ping</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.xray.balancer.balancerSelectors" }}' has-feedback
|
||||
:validate-status="balancerModal.emptySelector? 'warning' : 'success'">
|
||||
<a-form-item label='{{ i18n "pages.xray.balancer.balancerSelectors" }}' has-feedback
|
||||
:validate-status="balancerModal.emptySelector? 'warning' : 'success'">
|
||||
<a-select v-model="balancerModal.balancer.selector" mode="tags" @change="balancerModal.checkSelector()"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="tag in balancerModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="Fallback">
|
||||
<a-select v-model="balancerModal.balancer.fallbackTag" clearable
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="tag in [ '', ...balancerModal.outboundTags]" :value="tag">[[ tag ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</table>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
@@ -48,7 +54,8 @@
|
||||
balancer: {
|
||||
tag: '',
|
||||
strategy: 'random',
|
||||
selector: []
|
||||
selector: [],
|
||||
fallbackTag: ''
|
||||
},
|
||||
outboundTags: [],
|
||||
balancerTags:[],
|
||||
@@ -71,7 +78,8 @@
|
||||
balancerModal.balancer = {
|
||||
tag: '',
|
||||
strategy: 'random',
|
||||
selector: []
|
||||
selector: [],
|
||||
fallbackTag: ''
|
||||
};
|
||||
}
|
||||
this.balancerTags = balancerTags.filter((tag) => tag != balancer.tag);
|
||||
|
||||
@@ -300,7 +300,7 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
||||
if limitIp < len(ips) {
|
||||
j.disAllowedIps = append(j.disAllowedIps, ips[limitIp:]...)
|
||||
for i := limitIp; i < len(ips); i++ {
|
||||
logger.Debugf("[LIMIT_IP] Email = %s || SRC = %s", clientEmail, ips[i])
|
||||
log.Printf("[LIMIT_IP] Email = %s || SRC = %s", clientEmail, ips[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package middleware
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -14,12 +15,17 @@ func DomainValidatorMiddleware(domain string) gin.HandlerFunc {
|
||||
host = c.GetHeader("X-Real-IP")
|
||||
}
|
||||
if host == "" {
|
||||
host, _, _ := net.SplitHostPort(c.Request.Host)
|
||||
if host != domain {
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
return
|
||||
host = c.Request.Host
|
||||
if colonIndex := strings.LastIndex(host, ":"); colonIndex != -1 {
|
||||
host, _, _ = net.SplitHostPort(host)
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
|
||||
if host != domain {
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
162
web/service/warp.go
Normal file
162
web/service/warp.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
"x-ui/logger"
|
||||
)
|
||||
|
||||
type WarpService struct {
|
||||
SettingService
|
||||
}
|
||||
|
||||
func (s *WarpService) GetWarpData() (string, error) {
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return warp, nil
|
||||
}
|
||||
|
||||
func (s *WarpService) DelWarpData() error {
|
||||
err := s.SettingService.SetWarp("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *WarpService) GetWarpConfig() (string, error) {
|
||||
var warpData map[string]string
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = json.Unmarshal([]byte(warp), &warpData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg/%s", warpData["device_id"])
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+warpData["access_token"])
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
func (s *WarpService) RegWarp(secretKey string, publicKey string) (string, error) {
|
||||
tos := time.Now().UTC().Format("2006-01-02T15:04:05.000Z")
|
||||
hostName, _ := os.Hostname()
|
||||
data := fmt.Sprintf(`{"key":"%s","tos":"%s","type": "PC","model": "x-ui", "name": "%s"}`, publicKey, tos, hostName)
|
||||
|
||||
url := "https://api.cloudflareclient.com/v0a2158/reg"
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(data)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req.Header.Add("CF-Client-Version", "a-7.21-0721")
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var rspData map[string]interface{}
|
||||
err = json.Unmarshal(buffer.Bytes(), &rspData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
deviceId := rspData["id"].(string)
|
||||
token := rspData["token"].(string)
|
||||
license, ok := rspData["account"].(map[string]interface{})["license"].(string)
|
||||
if !ok {
|
||||
logger.Debug("Error accessing license value.")
|
||||
return "", err
|
||||
}
|
||||
|
||||
warpData := fmt.Sprintf("{\n \"access_token\": \"%s\",\n \"device_id\": \"%s\",", token, deviceId)
|
||||
warpData += fmt.Sprintf("\n \"license_key\": \"%s\",\n \"private_key\": \"%s\"\n}", license, secretKey)
|
||||
|
||||
s.SettingService.SetWarp(warpData)
|
||||
|
||||
result := fmt.Sprintf("{\n \"data\": %s,\n \"config\": %s\n}", warpData, buffer.String())
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *WarpService) SetWarpLicense(license string) (string, error) {
|
||||
var warpData map[string]string
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = json.Unmarshal([]byte(warp), &warpData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg/%s/account", warpData["device_id"])
|
||||
data := fmt.Sprintf(`{"license": "%s"}`, license)
|
||||
|
||||
req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(data)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+warpData["access_token"])
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,13 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"x-ui/util/common"
|
||||
"x-ui/xray"
|
||||
@@ -32,142 +27,3 @@ func (s *XraySettingService) CheckXrayConfig(XrayTemplateConfig string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *XraySettingService) GetWarpData() (string, error) {
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return warp, nil
|
||||
}
|
||||
|
||||
func (s *XraySettingService) GetWarpConfig() (string, error) {
|
||||
var warpData map[string]string
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = json.Unmarshal([]byte(warp), &warpData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg/%s", warpData["device_id"])
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+warpData["access_token"])
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
func (s *XraySettingService) RegWarp(secretKey string, publicKey string) (string, error) {
|
||||
tos := time.Now().UTC().Format("2006-01-02T15:04:05.000Z")
|
||||
hostName, _ := os.Hostname()
|
||||
data := fmt.Sprintf(`{"key":"%s","tos":"%s","type": "PC","model": "x-ui", "name": "%s"}`, publicKey, tos, hostName)
|
||||
|
||||
url := "https://api.cloudflareclient.com/v0a2158/reg"
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(data)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req.Header.Add("CF-Client-Version", "a-7.21-0721")
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var rspData map[string]interface{}
|
||||
err = json.Unmarshal(buffer.Bytes(), &rspData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
deviceId := rspData["id"].(string)
|
||||
token := rspData["token"].(string)
|
||||
license, ok := rspData["account"].(map[string]interface{})["license"].(string)
|
||||
if !ok {
|
||||
fmt.Println("Error accessing license value.")
|
||||
return "", err
|
||||
}
|
||||
|
||||
warpData := fmt.Sprintf("{\n \"access_token\": \"%s\",\n \"device_id\": \"%s\",", token, deviceId)
|
||||
warpData += fmt.Sprintf("\n \"license_key\": \"%s\",\n \"private_key\": \"%s\"\n}", license, secretKey)
|
||||
|
||||
s.SettingService.SetWarp(warpData)
|
||||
|
||||
result := fmt.Sprintf("{\n \"data\": %s,\n \"config\": %s\n}", warpData, buffer.String())
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *XraySettingService) SetWarpLicense(license string) (string, error) {
|
||||
var warpData map[string]string
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = json.Unmarshal([]byte(warp), &warpData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg/%s/account", warpData["device_id"])
|
||||
data := fmt.Sprintf(`{"license": "%s"}`, license)
|
||||
|
||||
req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(data)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+warpData["access_token"])
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@ func init() {
|
||||
|
||||
func SetLoginUser(c *gin.Context, user *model.User) error {
|
||||
s := sessions.Default(c)
|
||||
s.Options(sessions.Options{
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
})
|
||||
s.Set(loginUser, user)
|
||||
return s.Save()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user