diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 790c3a1a..feed7051 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,7 +77,7 @@ jobs: cd x-ui/bin # Download dependencies - Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v1.8.8/" + Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v1.8.9/" if [ "${{ matrix.platform }}" == "amd64" ]; then wget ${Xray_URL}Xray-linux-64.zip unzip Xray-linux-64.zip diff --git a/.gitignore b/.gitignore index 158f4ee1..781a633d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .cache .sync* *.tar.gz +*.log access.log error.log tmp diff --git a/DockerInit.sh b/DockerInit.sh index e9cccf49..aa1c856d 100755 --- a/DockerInit.sh +++ b/DockerInit.sh @@ -27,7 +27,7 @@ case $1 in esac mkdir -p build/bin cd build/bin -wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.8/Xray-linux-${ARCH}.zip" +wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.9/Xray-linux-${ARCH}.zip" unzip "Xray-linux-${ARCH}.zip" rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat mv xray "xray-linux-${FNAME}" diff --git a/README.md b/README.md index 14d569db..3ef677d0 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,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.2.1`: +To install your desired version, add the version to the end of the installation command. e.g., ver `v2.2.5`: ``` -bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.2.1 +bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.2.5 ``` ## SSL Certificate @@ -311,9 +311,9 @@ If you want to use routing to WARP before v2.1.0 follow steps as below: ```sh "log": { - "access": "./access.log", - "dnsLog": false, - "loglevel": "warning" + "access": "./access.log", + "dnsLog": false, + "loglevel": "warning" }, ``` diff --git a/config/version b/config/version index fae692e4..ecf00d90 100644 --- a/config/version +++ b/config/version @@ -1 +1 @@ -2.2.1 \ No newline at end of file +2.2.5 \ No newline at end of file diff --git a/database/model/model.go b/database/model/model.go index 32ab255f..df41237d 100644 --- a/database/model/model.go +++ b/database/model/model.go @@ -2,6 +2,7 @@ package model import ( "fmt" + "x-ui/util/json_util" "x-ui/xray" ) diff --git a/go.mod b/go.mod index f6566e55..4a680303 100644 --- a/go.mod +++ b/go.mod @@ -12,35 +12,35 @@ require ( github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/pelletier/go-toml/v2 v2.1.1 github.com/robfig/cron/v3 v3.0.1 - github.com/shirou/gopsutil/v3 v3.24.1 + github.com/shirou/gopsutil/v3 v3.24.2 github.com/valyala/fasthttp v1.52.0 - github.com/xtls/xray-core v1.8.8 + github.com/xtls/xray-core v1.8.9 go.uber.org/atomic v1.11.0 golang.org/x/text v0.14.0 - google.golang.org/grpc v1.62.0 + google.golang.org/grpc v1.62.1 gorm.io/driver/sqlite v1.5.5 gorm.io/gorm v1.25.7 ) require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/bytedance/sonic v1.10.2 // indirect + github.com/bytedance/sonic v1.11.2 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect - github.com/fasthttp/router v1.4.22 // indirect + github.com/fasthttp/router v1.5.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.17.0 // indirect + github.com/go-playground/validator/v10 v10.19.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/pprof v0.0.0-20240225044709-fd706174c886 // indirect + github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // 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 @@ -51,22 +51,22 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-sqlite3 v1.14.19 // 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.15.0 // indirect + github.com/onsi/ginkgo/v2 v2.16.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.41.0 // indirect github.com/refraction-networking/utls v1.6.3 // 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.3.2 // indirect + github.com/sagernet/sing v0.3.6 // indirect github.com/sagernet/sing-shadowsocks v0.2.6 // indirect - github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect + github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 // indirect github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect @@ -79,21 +79,21 @@ require ( 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-20231112171332-de1173cf2b19 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // 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.6.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/mod v0.15.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/mod v0.16.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.18.0 // indirect + golang.org/x/tools v0.19.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-20240221002015-b0ce06bbee7c // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b // indirect lukechampine.com/blake3 v1.2.1 // indirect diff --git a/go.sum b/go.sum index 5a92f611..505b5b1b 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= -github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A= +github.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= @@ -41,8 +41,8 @@ github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fp github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0= github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/fasthttp/router v1.4.22 h1:qwWcYBbndVDwts4dKaz+A2ehsnbKilmiP6pUhXBfYKo= -github.com/fasthttp/router v1.4.22/go.mod h1:KeMvHLqhlB9vyDWD5TSvTccl9qeWrjSSiTJrJALHKV0= +github.com/fasthttp/router v1.5.0 h1:3Qbbo27HAPzwbpRzgiV5V9+2faPkPt3eNuRaDV6LYDA= +github.com/fasthttp/router v1.5.0/go.mod h1:FddcKNXFZg1imHcy+uKB0oo/o6yE9zD3wNguqlhWDak= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= @@ -61,8 +61,8 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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= @@ -76,8 +76,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74= -github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= +github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= @@ -93,8 +93,8 @@ github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= @@ -111,8 +111,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-20240225044709-fd706174c886 h1:JSJUTZTQT1Gzb2ROdAKOY3HwzBYcclS2GgumhMfHqjw= -github.com/google/pprof v0.0.0-20240225044709-fd706174c886/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= 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= @@ -155,8 +155,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +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-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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= @@ -165,8 +165,8 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI= -github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= @@ -183,8 +183,8 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM= github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM= +github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= @@ -221,17 +221,17 @@ github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6po 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/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sagernet/sing v0.3.2 h1:CwWcxUBPkMvwgfe2/zUgY5oHG9qOL8Aob/evIFYK9jo= -github.com/sagernet/sing v0.3.2/go.mod h1:qHySJ7u8po9DABtMYEkNBcOumx7ZZJf/fbv2sfTkNHE= +github.com/sagernet/sing v0.3.6 h1:dsEdYLKBQlrxUfw1a92x0VdPvR1/BOxQ+HIMyaoEJsQ= +github.com/sagernet/sing v0.3.6/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= 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/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= +github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 h1:KanIMPX0QdEdB4R3CiimCAbxFrhB3j7h0/OvpYGVQa8= +github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511/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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shirou/gopsutil/v3 v3.24.1 h1:R3t6ondCEvmARp3wxODhXMTLC/klMa87h2PHUw5m7QI= -github.com/shirou/gopsutil/v3 v3.24.1/go.mod h1:UU7a2MSBQa+kW1uuDq8DeEBS8kmrnQwsv2b5O513rwU= +github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y= +github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -270,9 +270,9 @@ 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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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= @@ -301,10 +301,10 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19 h1:capMfFYRgH9BCLd6A3Er/cH3A9Nz3CU2KwxwOQZIePI= github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE= -github.com/xtls/xray-core v1.8.8 h1:6ApBa5pNkPZ+I7jyJDZod3v5sadizS/BZr0pW7zcs8o= -github.com/xtls/xray-core v1.8.8/go.mod h1:Zp33A8cxnhP5Kt6nguQrMgNH4A/tgq7LE8cBedeNje8= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/xtls/xray-core v1.8.9 h1:wefcON0behu4DoQvCKJYZKsJlSvNhyq2I7vC2fxLFcY= +github.com/xtls/xray-core v1.8.9/go.mod h1:XDE4f422qJKAU3hNDSNZyWrOHvn9kF8UHVdyOzU38rc= +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= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= @@ -321,16 +321,16 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= 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.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.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= @@ -340,8 +340,8 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -371,9 +371,9 @@ 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.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -390,8 +390,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= @@ -409,19 +409,18 @@ 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-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 h1:em/y72n4XlYRtayY/cVj6pnVzHa//BDA1BdoO+z9mdE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= 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= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/logger/logger.go b/logger/logger.go index ca047cbc..35c5c0ac 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -8,12 +8,14 @@ import ( "github.com/op/go-logging" ) -var logger *logging.Logger -var logBuffer []struct { - time string - level logging.Level - log string -} +var ( + logger *logging.Logger + logBuffer []struct { + time string + level logging.Level + log string + } +) func init() { InitLogger(logging.INFO) diff --git a/main.go b/main.go index fdf54089..d8177458 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "os/signal" "syscall" _ "unsafe" + "x-ui/config" "x-ui/database" "x-ui/logger" @@ -342,7 +343,7 @@ func main() { updateTgbotEnableSts(enabletgbot) } default: - fmt.Println("except 'run' or 'setting' subcommands") + fmt.Println("Invalid subcommands") fmt.Println() runCmd.Usage() fmt.Println() diff --git a/sub/default.json b/sub/default.json index ba13f6fb..d98a03ef 100644 --- a/sub/default.json +++ b/sub/default.json @@ -1,4 +1,5 @@ { + "remarks": "", "dns": { "tag": "dns_out", "queryStrategy": "UseIP", @@ -78,28 +79,9 @@ { "type": "field", "network": "tcp,udp", - "balancerTag": "all" - } - ], - "balancers": [ - { - "tag": "all", - "selector": [ - "proxy" - ], - "strategy": { - "type": "leastPing" - } + "outboundTag": "proxy" } ] }, - "observatory": { - "probeInterval": "5m", - "probeURL": "https://api.github.com/_private/browser/stats", - "subjectSelector": [ - "proxy" - ], - "EnableConcurrency": true - }, "stats": {} } \ No newline at end of file diff --git a/sub/sub.go b/sub/sub.go index 2a4a37f4..26dbcd2c 100644 --- a/sub/sub.go +++ b/sub/sub.go @@ -7,6 +7,7 @@ import ( "net" "net/http" "strconv" + "x-ui/config" "x-ui/logger" "x-ui/util/common" @@ -99,7 +100,7 @@ func (s *Server) initRouter() (*gin.Engine, error) { } func (s *Server) Start() (err error) { - //This is an anonymous function, no function name + // This is an anonymous function, no function name defer func() { if err != nil { s.Stop() @@ -144,21 +145,19 @@ func (s *Server) Start() (err error) { if certFile != "" || keyFile != "" { cert, err := tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - listener.Close() - return err + if err == nil { + c := &tls.Config{ + Certificates: []tls.Certificate{cert}, + } + listener = network.NewAutoHttpsListener(listener) + listener = tls.NewListener(listener, c) + logger.Info("sub server run https on", listener.Addr()) + } else { + logger.Error("error in loading certificates: ", err) + logger.Info("sub server run http on", listener.Addr()) } - c := &tls.Config{ - Certificates: []tls.Certificate{cert}, - } - listener = network.NewAutoHttpsListener(listener) - listener = tls.NewListener(listener, c) - } - - if certFile != "" || keyFile != "" { - logger.Info("Sub server run https on", listener.Addr()) } else { - logger.Info("Sub server run http on", listener.Addr()) + logger.Info("sub server run http on", listener.Addr()) } s.listener = listener diff --git a/sub/subController.go b/sub/subController.go index b5c5cbac..dc66c892 100644 --- a/sub/subController.go +++ b/sub/subController.go @@ -25,16 +25,17 @@ func NewSUBController( showInfo bool, rModel string, update string, - jsonFragment string) *SUBController { - + jsonFragment string, +) *SUBController { + sub := NewSubService(showInfo, rModel) a := &SUBController{ subPath: subPath, subJsonPath: jsonPath, subEncrypt: encrypt, updateInterval: update, - subService: NewSubService(showInfo, rModel), - subJsonService: NewSubJsonService(jsonFragment), + subService: sub, + subJsonService: NewSubJsonService(jsonFragment, sub), } a.initRouter(g) return a diff --git a/sub/subJsonService.go b/sub/subJsonService.go index 8bc98dea..d50e9644 100644 --- a/sub/subJsonService.go +++ b/sub/subJsonService.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "strings" + "x-ui/database/model" "x-ui/logger" "x-ui/util/json_util" @@ -17,15 +18,34 @@ import ( var defaultJson string type SubJsonService struct { - fragmanet string + configJson map[string]interface{} + defaultOutbounds []json_util.RawMessage + fragment string inboundService service.InboundService - SubService + SubService *SubService } -func NewSubJsonService(fragment string) *SubJsonService { +func NewSubJsonService(fragment string, subService *SubService) *SubJsonService { + var configJson map[string]interface{} + var defaultOutbounds []json_util.RawMessage + json.Unmarshal([]byte(defaultJson), &configJson) + if outboundSlices, ok := configJson["outbounds"].([]interface{}); ok { + for _, defaultOutbound := range outboundSlices { + jsonBytes, _ := json.Marshal(defaultOutbound) + defaultOutbounds = append(defaultOutbounds, jsonBytes) + } + } + + if fragment != "" { + defaultOutbounds = append(defaultOutbounds, json_util.RawMessage(fragment)) + } + return &SubJsonService{ - fragmanet: fragment, + configJson: configJson, + defaultOutbounds: defaultOutbounds, + fragment: fragment, + SubService: subService, } } @@ -38,19 +58,8 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err var header string var traffic xray.ClientTraffic var clientTraffics []xray.ClientTraffic - var configJson map[string]interface{} - var defaultOutbounds []json_util.RawMessage + var configArray []json_util.RawMessage - json.Unmarshal([]byte(defaultJson), &configJson) - if outboundSlices, ok := configJson["outbounds"].([]interface{}); ok { - for _, defaultOutbound := range outboundSlices { - jsonBytes, _ := json.Marshal(defaultOutbound) - defaultOutbounds = append(defaultOutbounds, jsonBytes) - } - } - - outbounds := []json_util.RawMessage{} - startIndex := 0 // Prepare Inbounds for _, inbound := range inbounds { clients, err := s.inboundService.GetClients(inbound) @@ -61,7 +70,7 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err continue } if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' { - listen, port, streamSettings, err := s.getFallbackMaster(inbound.Listen, inbound.StreamSettings) + listen, port, streamSettings, err := s.SubService.getFallbackMaster(inbound.Listen, inbound.StreamSettings) if err == nil { inbound.Listen = listen inbound.Port = port @@ -69,22 +78,16 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err } } - var subClients []model.Client for _, client := range clients { if client.Enable && client.SubID == subId { - subClients = append(subClients, client) clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email)) + newConfigs := s.getConfig(inbound, client, host) + configArray = append(configArray, newConfigs...) } } - - outbound := s.getOutbound(inbound, subClients, host, startIndex) - if outbound != nil { - outbounds = append(outbounds, outbound...) - startIndex += len(outbound) - } } - if len(outbounds) == 0 { + if len(configArray) == 0 { return "", "", nil } @@ -111,21 +114,15 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err } } - if s.fragmanet != "" { - outbounds = append(outbounds, json_util.RawMessage(s.fragmanet)) - } - // Combile outbounds - outbounds = append(outbounds, defaultOutbounds...) - configJson["outbounds"] = outbounds - finalJson, _ := json.MarshalIndent(configJson, "", " ") + finalJson, _ := json.MarshalIndent(configArray, "", " ") header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000) return string(finalJson), header, nil } -func (s *SubJsonService) getOutbound(inbound *model.Inbound, clients []model.Client, host string, startIndex int) []json_util.RawMessage { - var newOutbounds []json_util.RawMessage +func (s *SubJsonService) getConfig(inbound *model.Inbound, client model.Client, host string) []json_util.RawMessage { + var newJsonArray []json_util.RawMessage stream := s.streamData(inbound.StreamSettings) externalProxies, ok := stream["externalProxy"].([]interface{}) @@ -135,13 +132,13 @@ func (s *SubJsonService) getOutbound(inbound *model.Inbound, clients []model.Cli "forceTls": "same", "dest": host, "port": float64(inbound.Port), + "remark": "", }, } } delete(stream, "externalProxy") - config_index := startIndex for _, ep := range externalProxies { extPrxy := ep.(map[string]interface{}) inbound.Listen = extPrxy["dest"].(string) @@ -160,21 +157,28 @@ func (s *SubJsonService) getOutbound(inbound *model.Inbound, clients []model.Cli } } streamSettings, _ := json.MarshalIndent(newStream, "", " ") - inbound.StreamSettings = string(streamSettings) - for _, client := range clients { - inbound.Tag = fmt.Sprintf("proxy_%d", config_index) - switch inbound.Protocol { - case "vmess", "vless": - newOutbounds = append(newOutbounds, s.genVnext(inbound, client)) - case "trojan", "shadowsocks": - newOutbounds = append(newOutbounds, s.genServer(inbound, client)) - } - config_index += 1 + var newOutbounds []json_util.RawMessage + + switch inbound.Protocol { + case "vmess", "vless": + newOutbounds = append(newOutbounds, s.genVnext(inbound, streamSettings, client)) + case "trojan", "shadowsocks": + newOutbounds = append(newOutbounds, s.genServer(inbound, streamSettings, client)) } + + newOutbounds = append(newOutbounds, s.defaultOutbounds...) + newConfigJson := make(map[string]interface{}) + for key, value := range s.configJson { + newConfigJson[key] = value + } + newConfigJson["outbounds"] = newOutbounds + newConfigJson["remarks"] = s.SubService.genRemark(inbound, client.Email, extPrxy["remark"].(string)) + newConfig, _ := json.MarshalIndent(newConfigJson, "", " ") + newJsonArray = append(newJsonArray, newConfig) } - return newOutbounds + return newJsonArray } func (s *SubJsonService) streamData(stream string) map[string]interface{} { @@ -188,7 +192,7 @@ func (s *SubJsonService) streamData(stream string) map[string]interface{} { } delete(streamSettings, "sockopt") - if s.fragmanet != "" { + if s.fragment != "" { streamSettings["sockopt"] = json_util.RawMessage(`{"dialerProxy": "fragment", "tcpKeepAliveIdle": 100, "tcpNoDelay": true}`) } @@ -214,7 +218,7 @@ func (s *SubJsonService) removeAcceptProxy(setting interface{}) map[string]inter func (s *SubJsonService) tlsData(tData map[string]interface{}) map[string]interface{} { tlsData := make(map[string]interface{}, 1) - tlsClientSettings := tData["settings"].(map[string]interface{}) + tlsClientSettings, _ := tData["settings"].(map[string]interface{}) tlsData["serverName"] = tData["serverName"] tlsData["alpn"] = tData["alpn"] @@ -229,7 +233,7 @@ func (s *SubJsonService) tlsData(tData map[string]interface{}) map[string]interf func (s *SubJsonService) realityData(rData map[string]interface{}) map[string]interface{} { rltyData := make(map[string]interface{}, 1) - rltyClientSettings := rData["settings"].(map[string]interface{}) + rltyClientSettings, _ := rData["settings"].(map[string]interface{}) rltyData["show"] = false rltyData["publicKey"] = rltyClientSettings["publicKey"] @@ -253,7 +257,7 @@ func (s *SubJsonService) realityData(rData map[string]interface{}) map[string]in return rltyData } -func (s *SubJsonService) genVnext(inbound *model.Inbound, client model.Client) json_util.RawMessage { +func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_util.RawMessage, client model.Client) json_util.RawMessage { outbound := Outbound{} usersData := make([]UserVnext, 1) @@ -272,8 +276,8 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, client model.Client) j } outbound.Protocol = string(inbound.Protocol) - outbound.Tag = inbound.Tag - outbound.StreamSettings = json_util.RawMessage(inbound.StreamSettings) + outbound.Tag = "proxy" + outbound.StreamSettings = streamSettings outbound.Settings = OutboundSettings{ Vnext: vnextData, } @@ -282,7 +286,7 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, client model.Client) j return result } -func (s *SubJsonService) genServer(inbound *model.Inbound, client model.Client) json_util.RawMessage { +func (s *SubJsonService) genServer(inbound *model.Inbound, streamSettings json_util.RawMessage, client model.Client) json_util.RawMessage { outbound := Outbound{} serverData := make([]ServerSetting, 1) @@ -308,8 +312,8 @@ func (s *SubJsonService) genServer(inbound *model.Inbound, client model.Client) } outbound.Protocol = string(inbound.Protocol) - outbound.Tag = inbound.Tag - outbound.StreamSettings = json_util.RawMessage(inbound.StreamSettings) + outbound.Tag = "proxy" + outbound.StreamSettings = streamSettings outbound.Settings = OutboundSettings{ Servers: serverData, } diff --git a/sub/subService.go b/sub/subService.go index 06d1ed0a..0ed1d454 100644 --- a/sub/subService.go +++ b/sub/subService.go @@ -6,10 +6,12 @@ import ( "net/url" "strings" "time" + "x-ui/database" "x-ui/database/model" "x-ui/logger" "x-ui/util/common" + "x-ui/util/random" "x-ui/web/service" "x-ui/xray" @@ -212,9 +214,14 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string { case "grpc": grpc, _ := stream["grpcSettings"].(map[string]interface{}) obj["path"] = grpc["serviceName"].(string) + obj["authority"] = grpc["authority"].(string) if grpc["multiMode"].(bool) { obj["type"] = "multi" } + case "httpupgrade": + httpupgrade, _ := stream["httpupgradeSettings"].(map[string]interface{}) + obj["path"] = httpupgrade["path"].(string) + obj["host"] = httpupgrade["host"].(string) } security, _ := stream["security"].(string) @@ -346,9 +353,14 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string { case "grpc": grpc, _ := stream["grpcSettings"].(map[string]interface{}) params["serviceName"] = grpc["serviceName"].(string) + params["authority"] = grpc["authority"].(string) if grpc["multiMode"].(bool) { params["mode"] = "multi" } + case "httpupgrade": + httpupgrade, _ := stream["httpupgradeSettings"].(map[string]interface{}) + params["path"] = httpupgrade["path"].(string) + params["host"] = httpupgrade["host"].(string) } security, _ := stream["security"].(string) @@ -391,25 +403,21 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string { if realitySetting != nil { if sniValue, ok := searchKey(realitySetting, "serverNames"); ok { sNames, _ := sniValue.([]interface{}) - params["sni"], _ = sNames[0].(string) + params["sni"] = sNames[random.Num(len(sNames))].(string) } if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok { params["pbk"], _ = pbkValue.(string) } if sidValue, ok := searchKey(realitySetting, "shortIds"); ok { shortIds, _ := sidValue.([]interface{}) - params["sid"], _ = shortIds[0].(string) + params["sid"] = shortIds[random.Num(len(shortIds))].(string) } if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok { if fp, ok := fpValue.(string); ok && len(fp) > 0 { params["fp"] = fp } } - if spxValue, ok := searchKey(realitySettings, "spiderX"); ok { - if spx, ok := spxValue.(string); ok && len(spx) > 0 { - params["spx"] = spx - } - } + params["spx"] = "/" + random.Seq(15) } if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { @@ -562,9 +570,14 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string case "grpc": grpc, _ := stream["grpcSettings"].(map[string]interface{}) params["serviceName"] = grpc["serviceName"].(string) + params["authority"] = grpc["authority"].(string) if grpc["multiMode"].(bool) { params["mode"] = "multi" } + case "httpupgrade": + httpupgrade, _ := stream["httpupgradeSettings"].(map[string]interface{}) + params["path"] = httpupgrade["path"].(string) + params["host"] = httpupgrade["host"].(string) } security, _ := stream["security"].(string) @@ -603,25 +616,21 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string if realitySetting != nil { if sniValue, ok := searchKey(realitySetting, "serverNames"); ok { sNames, _ := sniValue.([]interface{}) - params["sni"], _ = sNames[0].(string) + params["sni"] = sNames[random.Num(len(sNames))].(string) } if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok { params["pbk"], _ = pbkValue.(string) } if sidValue, ok := searchKey(realitySetting, "shortIds"); ok { shortIds, _ := sidValue.([]interface{}) - params["sid"], _ = shortIds[0].(string) + params["sid"] = shortIds[random.Num(len(shortIds))].(string) } if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok { if fp, ok := fpValue.(string); ok && len(fp) > 0 { params["fp"] = fp } } - if spxValue, ok := searchKey(realitySettings, "spiderX"); ok { - if spx, ok := spxValue.(string); ok && len(spx) > 0 { - params["spx"] = spx - } - } + params["spx"] = "/" + random.Seq(15) } if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { @@ -779,9 +788,14 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st case "grpc": grpc, _ := stream["grpcSettings"].(map[string]interface{}) params["serviceName"] = grpc["serviceName"].(string) + params["authority"] = grpc["authority"].(string) if grpc["multiMode"].(bool) { params["mode"] = "multi" } + case "httpupgrade": + httpupgrade, _ := stream["httpupgradeSettings"].(map[string]interface{}) + params["path"] = httpupgrade["path"].(string) + params["host"] = httpupgrade["host"].(string) } security, _ := stream["security"].(string) diff --git a/util/common/err.go b/util/common/err.go index f6078c33..494e5c82 100644 --- a/util/common/err.go +++ b/util/common/err.go @@ -3,6 +3,7 @@ package common import ( "errors" "fmt" + "x-ui/logger" ) diff --git a/util/random/random.go b/util/random/random.go index 1dd47ec9..67ee0691 100644 --- a/util/random/random.go +++ b/util/random/random.go @@ -4,12 +4,14 @@ import ( "math/rand" ) -var numSeq [10]rune -var lowerSeq [26]rune -var upperSeq [26]rune -var numLowerSeq [36]rune -var numUpperSeq [36]rune -var allSeq [62]rune +var ( + numSeq [10]rune + lowerSeq [26]rune + upperSeq [26]rune + numLowerSeq [36]rune + numUpperSeq [36]rune + allSeq [62]rune +) func init() { for i := 0; i < 10; i++ { diff --git a/web/assets/css/custom.css b/web/assets/css/custom.css index 4ab6c5a8..506a0439 100644 --- a/web/assets/css/custom.css +++ b/web/assets/css/custom.css @@ -80,6 +80,11 @@ html[data-theme='ultra-dark'] { .dark .waves-header { background-color: #0a2227; } + .dark .ant-calendar-year-panel-year:hover, + .dark .ant-calendar-month-panel-month:hover, + .dark .ant-calendar-decade-panel-decade:hover { + background-color: var(--dark-color-surface-600); + } } html, @@ -175,7 +180,7 @@ style attribute { position: relative; clear: both; } -.ant-table-body { +.ant-table-wrapper > div > div > div > div > div > div { overflow-x: auto !important; } .ant-card-hoverable { @@ -791,6 +796,15 @@ style attribute { border-color: var(--dark-color-surface-500); } +@media (max-width: 768px) { + .dark .ant-popover-inner { + background-color: var(--dark-color-surface-200); + } + .dark > .ant-popover-content > .ant-popover-arrow { + border-color: var(--dark-color-surface-200); + } +} + .ant-dropdown-menu-dark .ant-dropdown-menu-item:hover, .dark .ant-select-dropdown-menu-item-selected, .dark .ant-calendar-time-picker-select-option-selected { @@ -1257,3 +1271,8 @@ b, strong { .ant-empty-small .ant-empty-image { height: 20px; } + +.ant-menu-theme-switch:hover { + background-color: transparent !important; + cursor: default !important; +} diff --git a/web/assets/js/axios-init.js b/web/assets/js/axios-init.js index b864b714..f0b0f4be 100644 --- a/web/assets/js/axios-init.js +++ b/web/assets/js/axios-init.js @@ -14,3 +14,17 @@ axios.interceptors.request.use( }, (error) => Promise.reject(error), ); + +axios.interceptors.response.use( + (response) => response, + (error) => { + if (error.response) { + const statusCode = error.response.status; + // Check the status code + if (statusCode === 401) { // Unauthorized + return window.location.reload(); + } + } + return Promise.reject(error); + } +); diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js index 05248b77..60465599 100644 --- a/web/assets/js/model/outbound.js +++ b/web/assets/js/model/outbound.js @@ -51,7 +51,14 @@ const OutboundDomainStrategies = [ "AsIs", "UseIP", "UseIPv4", - "UseIPv6" + "UseIPv6", + "UseIPv6v4", + "UseIPv4v6", + "ForceIP", + "ForceIPv6v4", + "ForceIPv6", + "ForceIPv4v6", + "ForceIPv4" ]; const WireguardDomainStrategy = [ @@ -268,6 +275,28 @@ class GrpcStreamSettings extends CommonClass { } } +class HttpUpgradeStreamSettings extends CommonClass { + constructor(path='/', host='') { + super(); + this.path = path; + this.host = host; + } + + static fromJson(json={}) { + return new HttpUpgradeStreamSettings( + json.path, + json.Host, + ); + } + + toJson() { + return { + path: this.path, + host: this.host, + }; + } +} + class TlsStreamSettings extends CommonClass { constructor(serverName='', alpn=[], @@ -327,6 +356,34 @@ class RealityStreamSettings extends CommonClass { }; } }; +class SockoptStreamSettings extends CommonClass { + constructor(dialerProxy = "", tcpFastOpen = false, tcpKeepAliveInterval = 0, tcpNoDelay = false) { + super(); + this.dialerProxy = dialerProxy; + this.tcpFastOpen = tcpFastOpen; + this.tcpKeepAliveInterval = tcpKeepAliveInterval; + this.tcpNoDelay = tcpNoDelay; + } + + static fromJson(json = {}) { + if (Object.keys(json).length === 0) return undefined; + return new SockoptStreamSettings( + json.dialerProxy, + json.tcpFastOpen, + json.tcpKeepAliveInterval, + json.tcpNoDelay, + ); + } + + toJson() { + return { + dialerProxy: this.dialerProxy, + tcpFastOpen: this.tcpFastOpen, + tcpKeepAliveInterval: this.tcpKeepAliveInterval, + tcpNoDelay: this.tcpNoDelay, + }; + } +} class StreamSettings extends CommonClass { constructor(network='tcp', @@ -339,6 +396,8 @@ class StreamSettings extends CommonClass { httpSettings=new HttpStreamSettings(), quicSettings=new QuicStreamSettings(), grpcSettings=new GrpcStreamSettings(), + httpupgradeSettings=new HttpUpgradeStreamSettings(), + sockopt = undefined, ) { super(); this.network = network; @@ -351,6 +410,8 @@ class StreamSettings extends CommonClass { this.http = httpSettings; this.quic = quicSettings; this.grpc = grpcSettings; + this.httpupgrade = httpupgradeSettings; + this.sockopt = sockopt; } get isTls() { @@ -361,6 +422,14 @@ class StreamSettings extends CommonClass { return this.security === "reality"; } + get sockoptSwitch() { + return this.sockopt != undefined; + } + + set sockoptSwitch(value) { + this.sockopt = value ? new SockoptStreamSettings() : undefined; + } + static fromJson(json={}) { return new StreamSettings( json.network, @@ -373,6 +442,8 @@ class StreamSettings extends CommonClass { HttpStreamSettings.fromJson(json.httpSettings), QuicStreamSettings.fromJson(json.quicSettings), GrpcStreamSettings.fromJson(json.grpcSettings), + HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings), + SockoptStreamSettings.fromJson(json.sockopt), ); } @@ -389,6 +460,37 @@ class StreamSettings extends CommonClass { httpSettings: network === 'http' ? this.http.toJson() : undefined, quicSettings: network === 'quic' ? this.quic.toJson() : undefined, grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined, + httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined, + sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined, + }; + } +} + +class Mux extends CommonClass { + constructor(enabled = false, concurrency = 8, xudpConcurrency = 16, xudpProxyUDP443 = "reject") { + super(); + this.enabled = enabled; + this.concurrency = concurrency; + this.xudpConcurrency = xudpConcurrency; + this.xudpProxyUDP443 = xudpProxyUDP443; + } + + static fromJson(json = {}) { + if (Object.keys(json).length === 0) return undefined; + return new Mux( + json.enabled, + json.concurrency, + json.xudpConcurrency, + json.xudpProxyUDP443, + ); + } + + toJson() { + return { + enabled: this.enabled, + concurrency: this.concurrency, + xudpConcurrency: this.xudpConcurrency, + xudpProxyUDP443: this.xudpProxyUDP443, }; } } @@ -399,12 +501,14 @@ class Outbound extends CommonClass { protocol=Protocols.VMess, settings=null, streamSettings = new StreamSettings(), + mux = new Mux(), ) { super(); this.tag = tag; this._protocol = protocol; this.settings = settings == null ? Outbound.Settings.getSettings(protocol) : settings; this.stream = streamSettings; + this.mux = mux; } get protocol() { @@ -419,7 +523,7 @@ class Outbound extends CommonClass { canEnableTls() { if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(this.protocol)) return false; - return ["tcp", "ws", "http", "quic", "grpc"].includes(this.stream.network); + return ["tcp", "ws", "http", "quic", "grpc", "httpupgrade"].includes(this.stream.network); } //this is used for xtls-rprx-vision @@ -469,6 +573,7 @@ class Outbound extends CommonClass { json.protocol, Outbound.Settings.fromJson(json.protocol, json.settings), StreamSettings.fromJson(json.streamSettings), + Mux.fromJson(json.mux), ) } @@ -478,6 +583,7 @@ class Outbound extends CommonClass { protocol: this.protocol, settings: this.settings instanceof CommonClass ? this.settings.toJson() : this.settings, streamSettings: this.canEnableStream() ? this.stream.toJson() : undefined, + mux: this.mux?.enabled ? this.mux : undefined, }; } @@ -523,6 +629,8 @@ class Outbound extends CommonClass { json.type ? json.type : 'none'); } else if (network === 'grpc') { stream.grpc = new GrpcStreamSettings(json.path, json.type == 'multi'); + } else if (network === 'httpupgrade') { + stream.httpupgrade = new HttpUpgradeStreamSettings(json.path,json.host); } if(json.tls && json.tls == 'tls'){ @@ -533,7 +641,6 @@ class Outbound extends CommonClass { json.allowInsecure); } - return new Outbound(json.ps, Protocols.VMess, new Outbound.VmessSettings(json.add, json.port, json.id), stream); } @@ -564,6 +671,8 @@ class Outbound extends CommonClass { headerType ?? 'none'); } else if (type === 'grpc') { stream.grpc = new GrpcStreamSettings(url.searchParams.get('serviceName') ?? '', url.searchParams.get('mode') == 'multi'); + } else if (type === 'httpupgrade') { + stream.httpupgrade = new HttpUpgradeStreamSettings(path,host); } if(security == 'tls'){ @@ -580,7 +689,7 @@ class Outbound extends CommonClass { let sni=url.searchParams.get('sni') ?? ''; let sid=url.searchParams.get('sid') ?? ''; let spx=url.searchParams.get('spx') ?? ''; - stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx); + stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx); } let data = link.split('?'); diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index 791e8533..9d863798 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -446,16 +446,19 @@ class QuicStreamSettings extends XrayCommonClass { class GrpcStreamSettings extends XrayCommonClass { constructor( serviceName="", + authority="", multiMode=false, ) { super(); this.serviceName = serviceName; + this.authority = authority; this.multiMode = multiMode; } static fromJson(json={}) { return new GrpcStreamSettings( json.serviceName, + json.authority, json.multiMode ); } @@ -463,11 +466,36 @@ class GrpcStreamSettings extends XrayCommonClass { toJson() { return { serviceName: this.serviceName, + authority: this.authority, multiMode: this.multiMode, } } } +class HttpUpgradeStreamSettings extends XrayCommonClass { + constructor(acceptProxyProtocol=false, path='/', host='') { + super(); + this.acceptProxyProtocol = acceptProxyProtocol; + this.path = path; + this.host = host; + } + + static fromJson(json={}) { + return new HttpUpgradeStreamSettings( + json.acceptProxyProtocol, + json.path, + json.host, + ); + } + + toJson() { + return { + acceptProxyProtocol: this.acceptProxyProtocol, + path: this.path, + host: this.host, + }; + } +} class TlsStreamSettings extends XrayCommonClass { constructor(serverName='', @@ -833,6 +861,7 @@ class StreamSettings extends XrayCommonClass { httpSettings=new HttpStreamSettings(), quicSettings=new QuicStreamSettings(), grpcSettings=new GrpcStreamSettings(), + httpupgradeSettings=new HttpUpgradeStreamSettings(), sockopt = undefined, ) { super(); @@ -848,6 +877,7 @@ class StreamSettings extends XrayCommonClass { this.http = httpSettings; this.quic = quicSettings; this.grpc = grpcSettings; + this.httpupgrade = httpupgradeSettings; this.sockopt = sockopt; } @@ -910,6 +940,7 @@ class StreamSettings extends XrayCommonClass { HttpStreamSettings.fromJson(json.httpSettings), QuicStreamSettings.fromJson(json.quicSettings), GrpcStreamSettings.fromJson(json.grpcSettings), + HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings), SockoptStreamSettings.fromJson(json.sockopt), ); } @@ -929,6 +960,7 @@ class StreamSettings extends XrayCommonClass { httpSettings: network === 'http' ? this.http.toJson() : undefined, quicSettings: network === 'quic' ? this.quic.toJson() : undefined, grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined, + httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined, sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined, }; } @@ -1045,6 +1077,10 @@ class Inbound extends XrayCommonClass { return this.network === "http"; } + get isHttpupgrade() { + return this.network === "httpupgrade"; + } + // Shadowsocks get method() { switch (this.protocol) { @@ -1075,6 +1111,8 @@ class Inbound extends XrayCommonClass { return this.stream.ws.getHeader("Host"); } else if (this.isH2) { return this.stream.http.host[0]; + } else if (this.isHttpupgrade) { + return this.stream.httpupgrade.host; } return null; } @@ -1086,6 +1124,8 @@ class Inbound extends XrayCommonClass { return this.stream.ws.path; } else if (this.isH2) { return this.stream.http.path; + } else if (this.isHttpupgrade) { + return this.stream.httpupgrade.path; } return null; } @@ -1121,7 +1161,7 @@ class Inbound extends XrayCommonClass { canEnableTls() { if(![Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol)) return false; - return ["tcp", "ws", "http", "quic", "grpc"].includes(this.network); + return ["tcp", "ws", "http", "quic", "grpc", "httpupgrade"].includes(this.network); } //this is used for xtls-rprx-vision @@ -1204,9 +1244,14 @@ class Inbound extends XrayCommonClass { obj.path = this.stream.quic.key; } else if (network === 'grpc') { obj.path = this.stream.grpc.serviceName; + obj.authority = this.stream.grpc.authority; if (this.stream.grpc.multiMode){ obj.type = 'multi' } + } else if (network === 'httpupgrade') { + let httpupgrade = this.stream.httpupgrade; + obj.path = httpupgrade.path; + obj.host = httpupgrade.host; } if (security === 'tls') { @@ -1275,10 +1320,16 @@ class Inbound extends XrayCommonClass { case "grpc": const grpc = this.stream.grpc; params.set("serviceName", grpc.serviceName); + params.set("authority", grpc.authority); if(grpc.multiMode){ params.set("mode", "multi"); } break; + case "httpupgrade": + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host); + break; } if (security === 'tls') { @@ -1389,10 +1440,16 @@ class Inbound extends XrayCommonClass { case "grpc": const grpc = this.stream.grpc; params.set("serviceName", grpc.serviceName); + params.set("authority", grpc.authority); if(grpc.multiMode){ params.set("mode", "multi"); } break; + case "httpupgrade": + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host); + break; } if (security === 'tls') { @@ -1470,10 +1527,16 @@ class Inbound extends XrayCommonClass { case "grpc": const grpc = this.stream.grpc; params.set("serviceName", grpc.serviceName); + params.set("authority", grpc.authority); if(grpc.multiMode){ params.set("mode", "multi"); } break; + case "httpupgrade": + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host); + break; } if (security === 'tls') { diff --git a/web/assets/js/util/utils.js b/web/assets/js/util/utils.js index 61b322bd..f2f05f01 100644 --- a/web/assets/js/util/utils.js +++ b/web/assets/js/util/utils.js @@ -131,11 +131,11 @@ class RandomUtil { static randomUUID() { const template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; return template.replace(/[xy]/g, function (c) { - const randomValues = new Uint8Array(1); - crypto.getRandomValues(randomValues); - let randomValue = randomValues[0] % 16; - let calculatedValue = (c === 'x') ? randomValue : (randomValue & 0x3 | 0x8); - return calculatedValue.toString(16); + const randomValues = new Uint8Array(1); + crypto.getRandomValues(randomValues); + let randomValue = randomValues[0] % 16; + let calculatedValue = (c === 'x') ? randomValue : (randomValue & 0x3 | 0x8); + return calculatedValue.toString(16); }); } diff --git a/web/controller/api.go b/web/controller/api.go index 73c36787..6281097b 100644 --- a/web/controller/api.go +++ b/web/controller/api.go @@ -22,91 +22,37 @@ func (a *APIController) initRouter(g *gin.RouterGroup) { g = g.Group("/panel/api/inbounds") g.Use(a.checkLogin) - g.GET("/list", a.getAllInbounds) - g.GET("/get/:id", a.getSingleInbound) - g.GET("/getClientTraffics/:email", a.getClientTraffics) - g.POST("/add", a.addInbound) - g.POST("/del/:id", a.delInbound) - g.POST("/update/:id", a.updateInbound) - g.POST("/clientIps/:email", a.getClientIps) - g.POST("/clearClientIps/:email", a.clearClientIps) - g.POST("/addClient", a.addInboundClient) - g.POST("/:id/delClient/:clientId", a.delInboundClient) - g.POST("/updateClient/:clientId", a.updateInboundClient) - g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic) - g.POST("/resetAllTraffics", a.resetAllTraffics) - g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics) - g.POST("/delDepletedClients/:id", a.delDepletedClients) - g.GET("/createbackup", a.createBackup) - g.POST("/onlines", a.onlines) - a.inboundController = NewInboundController(g) -} -func (a *APIController) getAllInbounds(c *gin.Context) { - a.inboundController.getInbounds(c) -} + inboundRoutes := []struct { + Method string + Path string + Handler gin.HandlerFunc + }{ + {"GET", "/createbackup", a.createBackup}, + {"GET", "/list", a.inboundController.getInbounds}, + {"GET", "/get/:id", a.inboundController.getInbound}, + {"GET", "/getClientTraffics/:email", a.inboundController.getClientTraffics}, + {"POST", "/add", a.inboundController.addInbound}, + {"POST", "/del/:id", a.inboundController.delInbound}, + {"POST", "/update/:id", a.inboundController.updateInbound}, + {"POST", "/clientIps/:email", a.inboundController.getClientIps}, + {"POST", "/clearClientIps/:email", a.inboundController.clearClientIps}, + {"POST", "/addClient", a.inboundController.addInboundClient}, + {"POST", "/:id/delClient/:clientId", a.inboundController.delInboundClient}, + {"POST", "/updateClient/:clientId", a.inboundController.updateInboundClient}, + {"POST", "/:id/resetClientTraffic/:email", a.inboundController.resetClientTraffic}, + {"POST", "/resetAllTraffics", a.inboundController.resetAllTraffics}, + {"POST", "/resetAllClientTraffics/:id", a.inboundController.resetAllClientTraffics}, + {"POST", "/delDepletedClients/:id", a.inboundController.delDepletedClients}, + {"POST", "/onlines", a.inboundController.onlines}, + } -func (a *APIController) getSingleInbound(c *gin.Context) { - a.inboundController.getInbound(c) -} - -func (a *APIController) getClientTraffics(c *gin.Context) { - a.inboundController.getClientTraffics(c) -} - -func (a *APIController) addInbound(c *gin.Context) { - a.inboundController.addInbound(c) -} - -func (a *APIController) delInbound(c *gin.Context) { - a.inboundController.delInbound(c) -} - -func (a *APIController) updateInbound(c *gin.Context) { - a.inboundController.updateInbound(c) -} - -func (a *APIController) getClientIps(c *gin.Context) { - a.inboundController.getClientIps(c) -} - -func (a *APIController) clearClientIps(c *gin.Context) { - a.inboundController.clearClientIps(c) -} - -func (a *APIController) addInboundClient(c *gin.Context) { - a.inboundController.addInboundClient(c) -} - -func (a *APIController) delInboundClient(c *gin.Context) { - a.inboundController.delInboundClient(c) -} - -func (a *APIController) updateInboundClient(c *gin.Context) { - a.inboundController.updateInboundClient(c) -} - -func (a *APIController) resetClientTraffic(c *gin.Context) { - a.inboundController.resetClientTraffic(c) -} - -func (a *APIController) resetAllTraffics(c *gin.Context) { - a.inboundController.resetAllTraffics(c) -} - -func (a *APIController) resetAllClientTraffics(c *gin.Context) { - a.inboundController.resetAllClientTraffics(c) -} - -func (a *APIController) delDepletedClients(c *gin.Context) { - a.inboundController.delDepletedClients(c) + for _, route := range inboundRoutes { + g.Handle(route.Method, route.Path, route.Handler) + } } func (a *APIController) createBackup(c *gin.Context) { a.Tgbot.SendBackupToAdmins() } - -func (a *APIController) onlines(c *gin.Context) { - a.inboundController.onlines(c) -} diff --git a/web/controller/base.go b/web/controller/base.go index 674a195d..492fc2dc 100644 --- a/web/controller/base.go +++ b/web/controller/base.go @@ -2,6 +2,7 @@ package controller import ( "net/http" + "x-ui/logger" "x-ui/web/locale" "x-ui/web/session" @@ -9,13 +10,12 @@ import ( "github.com/gin-gonic/gin" ) -type BaseController struct { -} +type BaseController struct{} func (a *BaseController) checkLogin(c *gin.Context) { if !session.IsLogin(c) { if isAjax(c) { - pureJsonMsg(c, false, I18nWeb(c, "pages.login.loginAgain")) + pureJsonMsg(c, http.StatusUnauthorized, false, I18nWeb(c, "pages.login.loginAgain")) } else { c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path")) } diff --git a/web/controller/inbound.go b/web/controller/inbound.go index d613453f..511afd64 100644 --- a/web/controller/inbound.go +++ b/web/controller/inbound.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "strconv" + "x-ui/database/model" "x-ui/web/service" "x-ui/web/session" @@ -174,7 +175,7 @@ func (a *InboundController) addInboundClient(c *gin.Context) { return } jsonMsg(c, "Client(s) added", nil) - if err == nil && needRestart { + if needRestart { a.xrayService.SetToNeedRestart() } } @@ -195,7 +196,7 @@ func (a *InboundController) delInboundClient(c *gin.Context) { return } jsonMsg(c, "Client deleted", nil) - if err == nil && needRestart { + if needRestart { a.xrayService.SetToNeedRestart() } } @@ -218,7 +219,7 @@ func (a *InboundController) updateInboundClient(c *gin.Context) { return } jsonMsg(c, "Client updated", nil) - if err == nil && needRestart { + if needRestart { a.xrayService.SetToNeedRestart() } } @@ -239,7 +240,7 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) { return } jsonMsg(c, "traffic reseted", nil) - if err == nil && needRestart { + if needRestart { a.xrayService.SetToNeedRestart() } } diff --git a/web/controller/index.go b/web/controller/index.go index 9be88273..bc3c4204 100644 --- a/web/controller/index.go +++ b/web/controller/index.go @@ -3,6 +3,7 @@ package controller import ( "net/http" "time" + "x-ui/logger" "x-ui/web/service" "x-ui/web/session" @@ -49,15 +50,15 @@ func (a *IndexController) login(c *gin.Context) { var form LoginForm err := c.ShouldBind(&form) if err != nil { - pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.invalidFormData")) + pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.invalidFormData")) return } if form.Username == "" { - pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.emptyUsername")) + pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.emptyUsername")) return } if form.Password == "" { - pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.emptyPassword")) + pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.emptyPassword")) return } @@ -66,7 +67,7 @@ func (a *IndexController) login(c *gin.Context) { if user == nil { logger.Warningf("wrong username or password: \"%s\" \"%s\"", form.Username, form.Password) a.tgbot.UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0) - pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword")) + pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword")) return } else { logger.Infof("%s login success, Ip Address: %s\n", form.Username, getRemoteIp(c)) diff --git a/web/controller/server.go b/web/controller/server.go index 10baacb9..0eeca71c 100644 --- a/web/controller/server.go +++ b/web/controller/server.go @@ -5,6 +5,7 @@ import ( "net/http" "regexp" "time" + "x-ui/web/global" "x-ui/web/service" diff --git a/web/controller/setting.go b/web/controller/setting.go index 64cae71b..d04969dc 100644 --- a/web/controller/setting.go +++ b/web/controller/setting.go @@ -3,6 +3,7 @@ package controller import ( "errors" "time" + "x-ui/web/entity" "x-ui/web/service" "x-ui/web/session" diff --git a/web/controller/util.go b/web/controller/util.go index da77189b..a32c9270 100644 --- a/web/controller/util.go +++ b/web/controller/util.go @@ -4,6 +4,7 @@ import ( "net" "net/http" "strings" + "x-ui/config" "x-ui/logger" "x-ui/web/entity" @@ -48,18 +49,11 @@ func jsonMsgObj(c *gin.Context, msg string, obj interface{}, err error) { c.JSON(http.StatusOK, m) } -func pureJsonMsg(c *gin.Context, success bool, msg string) { - if success { - c.JSON(http.StatusOK, entity.Msg{ - Success: true, - Msg: msg, - }) - } else { - c.JSON(http.StatusOK, entity.Msg{ - Success: false, - Msg: msg, - }) - } +func pureJsonMsg(c *gin.Context, statusCode int, success bool, msg string) { + c.JSON(statusCode, entity.Msg{ + Success: success, + Msg: msg, + }) } func html(c *gin.Context, name string, title string, data gin.H) { diff --git a/web/entity/entity.go b/web/entity/entity.go index 06850128..0a9c3a56 100644 --- a/web/entity/entity.go +++ b/web/entity/entity.go @@ -5,6 +5,7 @@ import ( "net" "strings" "time" + "x-ui/util/common" ) diff --git a/web/global/global.go b/web/global/global.go index 7d0b4e1f..e92c375b 100644 --- a/web/global/global.go +++ b/web/global/global.go @@ -7,8 +7,10 @@ import ( "github.com/robfig/cron/v3" ) -var webServer WebServer -var subServer SubServer +var ( + webServer WebServer + subServer SubServer +) type WebServer interface { GetCron() *cron.Cron diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html index 3fcfdfc1..0e2b3a63 100644 --- a/web/html/common/qrcode_modal.html +++ b/web/html/common/qrcode_modal.html @@ -1,9 +1,10 @@ {{define "qrcodeModal"}} + :dialog-style="{ top: '20px' }" + :closable="true" + :class="themeSwitcher.currentTheme" + :footer="null" + width="300px"> {{ i18n "pages.inbounds.clickOnQRcode" }} diff --git a/web/html/login.html b/web/html/login.html index 7655c66f..dfb01cea 100644 --- a/web/html/login.html +++ b/web/html/login.html @@ -374,6 +374,12 @@ transform: translateZ(-100px); } } + .ant-menu-item .anticon { + margin-right: 4px; + } + .ant-menu-inline .ant-menu-item { + padding: 0 16px !important; + } @@ -410,19 +416,19 @@ - - - @@ -455,17 +461,7 @@ - -   - - - - - Ultra - - + diff --git a/web/html/xui/common_sider.html b/web/html/xui/common_sider.html index 78b833b9..bc8f4608 100644 --- a/web/html/xui/common_sider.html +++ b/web/html/xui/common_sider.html @@ -24,18 +24,7 @@ {{define "commonSider"}} - - - - - - - Ultra - - - + {{template "menuItems" .}} @@ -49,18 +38,7 @@
- - - - - - - Ultra - - - + {{template "menuItems" .}} diff --git a/web/html/xui/component/setting.html b/web/html/xui/component/setting.html index 82c0ae75..8adc000c 100644 --- a/web/html/xui/component/setting.html +++ b/web/html/xui/component/setting.html @@ -16,7 +16,7 @@ + + + + + + + + + + + + + diff --git a/web/html/xui/form/stream/stream_grpc.html b/web/html/xui/form/stream/stream_grpc.html index fcefdff9..e74a3c3f 100644 --- a/web/html/xui/form/stream/stream_grpc.html +++ b/web/html/xui/form/stream/stream_grpc.html @@ -3,6 +3,9 @@ + + + diff --git a/web/html/xui/form/stream/stream_httpupgrade.html b/web/html/xui/form/stream/stream_httpupgrade.html new file mode 100644 index 00000000..15c02aeb --- /dev/null +++ b/web/html/xui/form/stream/stream_httpupgrade.html @@ -0,0 +1,13 @@ +{{define "form/streamHTTPUpgrade"}} + + + + + + + + + + + +{{end}} diff --git a/web/html/xui/form/stream/stream_kcp.html b/web/html/xui/form/stream/stream_kcp.html index 5cdee701..97ca4071 100644 --- a/web/html/xui/form/stream/stream_kcp.html +++ b/web/html/xui/form/stream/stream_kcp.html @@ -23,25 +23,25 @@ - + - + - + - + - + - + {{end}} diff --git a/web/html/xui/form/stream/stream_settings.html b/web/html/xui/form/stream/stream_settings.html index af81651d..0d1eaa23 100644 --- a/web/html/xui/form/stream/stream_settings.html +++ b/web/html/xui/form/stream/stream_settings.html @@ -2,14 +2,15 @@ - TCP mKCP - WS + WebSocket H2 QUIC gRPC + HTTPUpgrade @@ -43,6 +44,12 @@ + + + +