Compare commits

..

1 Commits

Author SHA1 Message Date
MHSanaei
440d08dbfb v1.7.1 2023-07-18 19:11:03 +03:30
35 changed files with 345 additions and 699 deletions

View File

@@ -17,9 +17,9 @@ jobs:
uses: actions/checkout@v3.5.3 uses: actions/checkout@v3.5.3
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v4.1.0 uses: actions/setup-go@v4.0.1
with: with:
go-version: '1.20' go-version: 'stable'
- name: Install dependencies for arm64 - name: Install dependencies for arm64
if: matrix.platform == 'arm64' if: matrix.platform == 'arm64'
@@ -47,18 +47,18 @@ jobs:
# Download dependencies # Download dependencies
if [ "${{ matrix.platform }}" == "amd64" ]; then if [ "${{ matrix.platform }}" == "amd64" ]; then
wget https://github.com/XTLS/Xray-core/releases/download/v1.8.1/Xray-linux-64.zip wget https://github.com/mhsanaei/Xray-core/releases/latest/download/Xray-linux-64.zip
unzip Xray-linux-64.zip unzip Xray-linux-64.zip
rm -f Xray-linux-64.zip rm -f Xray-linux-64.zip
else else
wget https://github.com/XTLS/Xray-core/releases/download/v1.8.1/Xray-linux-arm64-v8a.zip wget https://github.com/mhsanaei/Xray-core/releases/latest/download/Xray-linux-arm64-v8a.zip
unzip Xray-linux-arm64-v8a.zip unzip Xray-linux-arm64-v8a.zip
rm -f Xray-linux-arm64-v8a.zip rm -f Xray-linux-arm64-v8a.zip
fi fi
rm -f geoip.dat geosite.dat iran.dat rm -f geoip.dat geosite.dat iran.dat
wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
wget https://github.com/MasterKia/iran-hosted-domains/releases/latest/download/iran.dat wget https://github.com/bootmortis/iran-hosted-domains/releases/latest/download/iran.dat
mv xray xray-linux-${{ matrix.platform }} mv xray xray-linux-${{ matrix.platform }}
cd ../.. cd ../..
@@ -66,7 +66,7 @@ jobs:
run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui
- name: Upload - name: Upload
uses: svenstaro/upload-release-action@2.7.0 uses: svenstaro/upload-release-action@2.6.1
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }} tag: ${{ github.ref }}

View File

@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# Start fail2ban # Start fail2ban
fail2ban-client -x start fail2ban-client -x -f start
# Run x-ui # Run x-ui
exec /app/x-ui exec /app/x-ui

View File

@@ -18,11 +18,11 @@ esac
mkdir -p build/bin mkdir -p build/bin
cd build/bin cd build/bin
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.1/Xray-linux-${ARCH}.zip" wget "https://github.com/mhsanaei/xray-core/releases/latest/download/Xray-linux-${ARCH}.zip"
unzip "Xray-linux-${ARCH}.zip" unzip "Xray-linux-${ARCH}.zip"
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat iran.dat rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat iran.dat
mv xray "xray-linux-${FNAME}" mv xray "xray-linux-${FNAME}"
wget "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" wget "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
wget "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" wget "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
wget "https://github.com/MasterKia/iran-hosted-domains/releases/latest/download/iran.dat" wget "https://github.com/bootmortis/iran-hosted-domains/releases/latest/download/iran.dat"

View File

@@ -36,9 +36,7 @@ COPY --from=builder /app/x-ui.sh /usr/bin/x-ui
# Configure fail2ban # Configure fail2ban
RUN rm -f /etc/fail2ban/jail.d/alpine-ssh.conf \ RUN rm -f /etc/fail2ban/jail.d/alpine-ssh.conf \
&& cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local \ && cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local \
&& sed -i "s/^\[ssh\]$/&\nenabled = false/" /etc/fail2ban/jail.local \ && sed -i "s/^\[ssh\]$/&\nenabled = false/" /etc/fail2ban/jail.local
&& sed -i "s/^\[sshd\]$/&\nenabled = false/" /etc/fail2ban/jail.local \
&& sed -i "s/#allowipv6 = auto/allowipv6 = auto/g" /etc/fail2ban/fail2ban.conf
RUN chmod +x \ RUN chmod +x \
/app/DockerEntrypoint.sh \ /app/DockerEntrypoint.sh \

View File

@@ -23,10 +23,10 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
# Install custom version # Install custom version
To install your desired version you can add the version to the end of install command. Example for ver `v1.7.1`: To install your desired version you can add the version to the end of install command. Example for ver `v1.6.1`:
``` ```
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.7.1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.6.1
``` ```
# SSL # SSL
@@ -191,27 +191,6 @@ If you want to use routing to WARP follow steps as below:
</details> </details>
# IP Limit
<details>
<summary>Click for IP Limit details</summary>
**Note: IP Limit won't work correctly when using IP Tunnel**
- For versions up to `v1.6.1`:
- IP limit is built-in into the panel.
- For versions `v1.7.0` and newer:
- To make IP Limit work properly, you need to install fail2ban and its required files by following these steps:
1. Use the `x-ui` command inside the shell.
2. Select `16. IP Limit Management`.
3. Choose the appropriate options based on your needs.
</details>
# Telegram Bot # Telegram Bot
<details> <details>
@@ -321,7 +300,6 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
- Debian 10+ - Debian 10+
- CentOS 8+ - CentOS 8+
- Fedora 36+ - Fedora 36+
- Arch Linux
# Pictures # Pictures

View File

@@ -1 +1 @@
1.7.6 1.7.1

31
go.mod
View File

@@ -7,16 +7,17 @@ require (
github.com/Workiva/go-datastructures v1.1.0 github.com/Workiva/go-datastructures v1.1.0
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/goccy/go-json v0.10.2 github.com/goccy/go-json v0.10.2
github.com/mymmrac/telego v0.26.0 github.com/mymmrac/telego v0.25.1
github.com/nicksnyder/go-i18n/v2 v2.2.1 github.com/nicksnyder/go-i18n/v2 v2.2.1
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pelletier/go-toml/v2 v2.0.9 github.com/pelletier/go-toml/v2 v2.0.9
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/shirou/gopsutil/v3 v3.23.7 github.com/shirou/gopsutil/v3 v3.23.6
github.com/xtls/xray-core v1.8.3 github.com/xtls/xray-core v1.8.3
github.com/yaa110/go-persian-calendar v1.1.5
go.uber.org/atomic v1.11.0 go.uber.org/atomic v1.11.0
golang.org/x/text v0.12.0 golang.org/x/text v0.11.0
google.golang.org/grpc v1.57.0 google.golang.org/grpc v1.56.2
gorm.io/driver/sqlite v1.5.2 gorm.io/driver/sqlite v1.5.2
gorm.io/gorm v1.25.2 gorm.io/gorm v1.25.2
) )
@@ -24,11 +25,10 @@ require (
require ( require (
github.com/BurntSushi/toml v1.3.2 // indirect github.com/BurntSushi/toml v1.3.2 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/bytedance/sonic v1.10.0-rc3 // indirect github.com/bytedance/sonic v1.9.2 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/fasthttp/router v1.4.20 // indirect github.com/fasthttp/router v1.4.19 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect github.com/francoispqt/gojay v1.2.13 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gaukas/godicttls v0.0.4 // indirect github.com/gaukas/godicttls v0.0.4 // indirect
@@ -36,7 +36,7 @@ require (
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.15.0 // indirect github.com/go-playground/validator/v10 v10.14.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
@@ -51,7 +51,6 @@ require (
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
@@ -64,7 +63,7 @@ require (
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/quic-go/quic-go v0.35.1 // indirect github.com/quic-go/quic-go v0.35.1 // indirect
github.com/refraction-networking/utls v1.3.3 // indirect github.com/refraction-networking/utls v1.3.2 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/sagernet/sing v0.2.7 // indirect github.com/sagernet/sing v0.2.7 // indirect
@@ -73,7 +72,7 @@ require (
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.11 // indirect
@@ -83,14 +82,14 @@ require (
github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983 // indirect github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/arch v0.4.0 // indirect golang.org/x/arch v0.4.0 // indirect
golang.org/x/crypto v0.12.0 // indirect golang.org/x/crypto v0.11.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/mod v0.11.0 // indirect golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.14.0 // indirect golang.org/x/net v0.12.0 // indirect
golang.org/x/sys v0.11.0 // indirect golang.org/x/sys v0.10.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.10.0 // indirect golang.org/x/tools v0.10.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect

68
go.sum
View File

@@ -22,18 +22,13 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= 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.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.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM=
github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0= github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.10.0-rc3/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-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 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=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -41,8 +36,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 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= 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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fasthttp/router v1.4.20 h1:yPeNxz5WxZGojzolKqiP15DTXnxZce9Drv577GBrDgU= github.com/fasthttp/router v1.4.19 h1:RLE539IU/S4kfb4MP56zgP0TIBU9kEg0ID9GpWO0vqk=
github.com/fasthttp/router v1.4.20/go.mod h1:um867yNQKtERxBm+C+yzgWxjspTiQoA8z86Ec3fK/tc= github.com/fasthttp/router v1.4.19/go.mod h1:+Fh3YOd8x1+he6ZS+d2iUDBH9MGGZ1xQFUor0DE9rKE=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= 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 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
@@ -67,8 +62,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjAR7VgKoNB6ryXfw= github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= 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/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
@@ -128,14 +123,12 @@ github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQs
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
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/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.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= 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.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
@@ -156,8 +149,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mymmrac/telego v0.26.0 h1:m4B3SW9dxL4uHpyjBnmhQeiFO7GWCxFjsUKUvFx3mf0= github.com/mymmrac/telego v0.25.1 h1:tMNmrRm0YGyLS56CBi0NDHwO1ZI6V7QMgX4KWSWuT1U=
github.com/mymmrac/telego v0.26.0/go.mod h1:kizipjY3MhxmkcGvyz8jiw/26vEKAhR2V7YTE69iqvw= github.com/mymmrac/telego v0.25.1/go.mod h1:nBO4SUqRV8j60JOS7trIr6bHPofwYCGJxYeqtQWgu2c=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA= github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA=
@@ -190,8 +183,8 @@ github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8G
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62poo= github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62poo=
github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g= github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
github.com/refraction-networking/utls v1.3.3 h1:f/TBLX7KBciRyFH3bwupp+CE4fzoYKCirhdRcC490sw= github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8=
github.com/refraction-networking/utls v1.3.3/go.mod h1:DlecWW1LMlMJu+9qpzzQqdHDT/C2LAe03EdpLUz/RL8= github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= 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/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 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
@@ -210,8 +203,8 @@ github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJ
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U= 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-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08=
github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= 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/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
@@ -255,9 +248,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
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.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
@@ -278,6 +270,8 @@ github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983 h1:AMyzgjkh54WocjQSlC
github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y= github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y=
github.com/xtls/xray-core v1.8.3 h1:lxaVklPjLKqUU4ua4qH8SBaRcAaNHlH+LmXOx0U/Ejg= github.com/xtls/xray-core v1.8.3 h1:lxaVklPjLKqUU4ua4qH8SBaRcAaNHlH+LmXOx0U/Ejg=
github.com/xtls/xray-core v1.8.3/go.mod h1:i7t4JFnq828P2+XK0XjGQ8W9x78iu+EJ7jI4l3sonIw= github.com/xtls/xray-core v1.8.3/go.mod h1:i7t4JFnq828P2+XK0XjGQ8W9x78iu+EJ7jI4l3sonIw=
github.com/yaa110/go-persian-calendar v1.1.5 h1:EUipRRhzE6bR2NZaSyZ5BEOP46LGbUjzQgdC+Ivrbe4=
github.com/yaa110/go-persian-calendar v1.1.5/go.mod h1:qtnmHCS9u1EiwzzSCSttGoxD5NfV9ZMzymxFCBYmqfg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -286,7 +280,6 @@ github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= 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 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
@@ -298,8 +291,8 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
@@ -325,8 +318,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -360,9 +353,9 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -370,8 +363,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
@@ -403,20 +396,20 @@ 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-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-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 v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 h1:wukfNtZmZUurLN/atp2hiIeTKn7QJWIQdHzqmsOnAOk= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 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.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.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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -438,7 +431,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

View File

@@ -53,28 +53,21 @@ elif [[ "${release}" == "debian" ]]; then
if [[ ${os_version} -lt 10 ]]; then if [[ ${os_version} -lt 10 ]]; then
echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1 echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "arch" ]]; then
echo "OS is ArchLinux"
else else
echo -e "${red}Failed to check the OS version, please contact the author!${plain}" && exit 1 echo -e "${red}Failed to check the OS version, please contact the author!${plain}" && exit 1
fi fi
install_base() { install_base() {
case "${release}" in case "${release}" in
centos|fedora) centos | fedora)
yum install -y -q wget curl tar yum install -y -q wget curl tar
;; ;;
arch) *)
pacman -Syu --noconfirm wget curl tar apt install -y -q wget curl tar
;; ;;
*)
apt install -y -q wget curl tar
;;
esac esac
} }
# This function will be called when user installed x-ui out of sercurity # This function will be called when user installed x-ui out of sercurity
config_after_install() { config_after_install() {
echo -e "${yellow}Install/update finished! For security it's recommended to modify panel settings ${plain}" echo -e "${yellow}Install/update finished! For security it's recommended to modify panel settings ${plain}"
@@ -111,6 +104,7 @@ config_after_install() {
} }
install_x-ui() { install_x-ui() {
systemctl stop x-ui
cd /usr/local/ cd /usr/local/
if [ $# == 0 ]; then if [ $# == 0 ]; then
@@ -137,7 +131,6 @@ install_x-ui() {
fi fi
if [[ -e /usr/local/x-ui/ ]]; then if [[ -e /usr/local/x-ui/ ]]; then
systemctl stop x-ui
rm /usr/local/x-ui/ -rf rm /usr/local/x-ui/ -rf
fi fi

View File

@@ -1,118 +1,98 @@
package logger package logger
import ( import (
"fmt"
"os" "os"
"time" "sync"
"github.com/op/go-logging" "github.com/op/go-logging"
) )
var logger *logging.Logger var (
var logBuffer []struct { logger *logging.Logger
time string mu sync.Mutex
level logging.Level )
log string
}
func init() { func init() {
InitLogger(logging.INFO) InitLogger(logging.INFO)
} }
func InitLogger(level logging.Level) { func InitLogger(level logging.Level) {
mu.Lock()
defer mu.Unlock()
if logger != nil {
return
}
format := logging.MustStringFormatter(
`%{time:2006/01/02 15:04:05} %{level} - %{message}`,
)
newLogger := logging.MustGetLogger("x-ui") newLogger := logging.MustGetLogger("x-ui")
var err error backend := logging.NewLogBackend(os.Stderr, "", 0)
var backend logging.Backend
var format logging.Formatter
ppid := os.Getppid()
if ppid == 1 {
backend, err = logging.NewSyslogBackend("")
format = logging.MustStringFormatter(
`%{level} - %{message}`,
)
}
if err != nil || ppid != 1 {
backend = logging.NewLogBackend(os.Stderr, "", 0)
format = logging.MustStringFormatter(
`%{time:2006/01/02 15:04:05} %{level} - %{message}`,
)
}
backendFormatter := logging.NewBackendFormatter(backend, format) backendFormatter := logging.NewBackendFormatter(backend, format)
backendLeveled := logging.AddModuleLevel(backendFormatter) backendLeveled := logging.AddModuleLevel(backendFormatter)
backendLeveled.SetLevel(level, "x-ui") backendLeveled.SetLevel(level, "")
newLogger.SetBackend(backendLeveled) newLogger.SetBackend(logging.MultiLogger(backendLeveled))
logger = newLogger logger = newLogger
} }
func Debug(args ...interface{}) { func Debug(args ...interface{}) {
logger.Debug(args...) if logger != nil {
addToBuffer("DEBUG", fmt.Sprint(args...)) logger.Debug(args...)
}
} }
func Debugf(format string, args ...interface{}) { func Debugf(format string, args ...interface{}) {
logger.Debugf(format, args...) if logger != nil {
addToBuffer("DEBUG", fmt.Sprintf(format, args...)) logger.Debugf(format, args...)
}
} }
func Info(args ...interface{}) { func Info(args ...interface{}) {
logger.Info(args...) if logger != nil {
addToBuffer("INFO", fmt.Sprint(args...)) logger.Info(args...)
}
} }
func Infof(format string, args ...interface{}) { func Infof(format string, args ...interface{}) {
logger.Infof(format, args...) if logger != nil {
addToBuffer("INFO", fmt.Sprintf(format, args...)) logger.Infof(format, args...)
}
} }
func Warning(args ...interface{}) { func Warning(args ...interface{}) {
logger.Warning(args...) if logger != nil {
addToBuffer("WARNING", fmt.Sprint(args...)) logger.Warning(args...)
}
} }
func Warningf(format string, args ...interface{}) { func Warningf(format string, args ...interface{}) {
logger.Warningf(format, args...) if logger != nil {
addToBuffer("WARNING", fmt.Sprintf(format, args...)) logger.Warningf(format, args...)
}
} }
func Error(args ...interface{}) { func Error(args ...interface{}) {
logger.Error(args...) if logger != nil {
addToBuffer("ERROR", fmt.Sprint(args...)) logger.Error(args...)
}
} }
func Errorf(format string, args ...interface{}) { func Errorf(format string, args ...interface{}) {
logger.Errorf(format, args...) if logger != nil {
addToBuffer("ERROR", fmt.Sprintf(format, args...)) logger.Errorf(format, args...)
}
func addToBuffer(level string, newLog string) {
t := time.Now()
if len(logBuffer) >= 10240 {
logBuffer = logBuffer[1:]
} }
logLevel, _ := logging.LogLevel(level)
logBuffer = append(logBuffer, struct {
time string
level logging.Level
log string
}{
time: t.Format("2006/01/02 15:04:05"),
level: logLevel,
log: newLog,
})
} }
func GetLogs(c int, level string) []string { func Notice(args ...interface{}) {
var output []string if logger != nil {
logLevel, _ := logging.LogLevel(level) logger.Notice(args...)
}
for i := len(logBuffer) - 1; i >= 0 && len(output) <= c; i-- { }
if logBuffer[i].level <= logLevel {
output = append(output, fmt.Sprintf("%s %s - %s", logBuffer[i].time, logBuffer[i].level, logBuffer[i].log)) func Noticef(format string, args ...interface{}) {
} if logger != nil {
logger.Noticef(format, args...)
} }
return output
} }

View File

@@ -14,6 +14,7 @@ import (
"x-ui/xray" "x-ui/xray"
"github.com/goccy/go-json" "github.com/goccy/go-json"
ptime "github.com/yaa110/go-persian-calendar"
) )
type SubService struct { type SubService struct {
@@ -144,15 +145,8 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string, expiryTi
remainedTraffic := s.getRemainedTraffic(email) remainedTraffic := s.getRemainedTraffic(email)
expiryTimeString := getExpiryTime(expiryTime) expiryTimeString := getExpiryTime(expiryTime)
remark := ""
isTerminated := strings.Contains(expiryTimeString, "Terminated") || strings.Contains(remainedTraffic, "Terminated")
if isTerminated {
remark = fmt.Sprintf("%s: %s⛔", email, "Terminated")
} else {
remark = fmt.Sprintf("%s: %s - %s", email, remainedTraffic, expiryTimeString)
}
remark := fmt.Sprintf("%s: %s- %s", email, remainedTraffic, expiryTimeString)
obj := map[string]interface{}{ obj := map[string]interface{}{
"v": "2", "v": "2",
"ps": remark, "ps": remark,
@@ -464,14 +458,8 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string, expiryTi
remainedTraffic := s.getRemainedTraffic(email) remainedTraffic := s.getRemainedTraffic(email)
expiryTimeString := getExpiryTime(expiryTime) expiryTimeString := getExpiryTime(expiryTime)
remark := ""
isTerminated := strings.Contains(expiryTimeString, "Terminated") || strings.Contains(remainedTraffic, "Terminated")
if isTerminated { remark := fmt.Sprintf("%s: %s- %s", email, remainedTraffic, expiryTimeString)
remark = fmt.Sprintf("%s: %s⛔", email, "Terminated")
} else {
remark = fmt.Sprintf("%s: %s - %s", email, remainedTraffic, expiryTimeString)
}
if len(domains) > 0 { if len(domains) > 0 {
links := "" links := ""
@@ -682,14 +670,8 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string, expiryT
remainedTraffic := s.getRemainedTraffic(email) remainedTraffic := s.getRemainedTraffic(email)
expiryTimeString := getExpiryTime(expiryTime) expiryTimeString := getExpiryTime(expiryTime)
remark := ""
isTerminated := strings.Contains(expiryTimeString, "Terminated") || strings.Contains(remainedTraffic, "Terminated")
if isTerminated { remark := fmt.Sprintf("%s: %s- %s", email, remainedTraffic, expiryTimeString)
remark = fmt.Sprintf("%s: %s⛔", email, "Terminated")
} else {
remark = fmt.Sprintf("%s: %s - %s", email, remainedTraffic, expiryTimeString)
}
if len(domains) > 0 { if len(domains) > 0 {
links := "" links := ""
@@ -774,10 +756,7 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string, ex
} }
} }
encPart := fmt.Sprintf("%s:%s", method, clients[clientIndex].Password) encPart := fmt.Sprintf("%s:%s:%s", method, inboundPassword, clients[clientIndex].Password)
if method[0] == '2' {
encPart = fmt.Sprintf("%s:%s:%s", method, inboundPassword, clients[clientIndex].Password)
}
link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), address, inbound.Port) link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), address, inbound.Port)
url, _ := url.Parse(link) url, _ := url.Parse(link)
q := url.Query() q := url.Query()
@@ -791,15 +770,8 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string, ex
remainedTraffic := s.getRemainedTraffic(email) remainedTraffic := s.getRemainedTraffic(email)
expiryTimeString := getExpiryTime(expiryTime) expiryTimeString := getExpiryTime(expiryTime)
remark := ""
isTerminated := strings.Contains(expiryTimeString, "Terminated") || strings.Contains(remainedTraffic, "Terminated")
if isTerminated {
remark = fmt.Sprintf("%s: %s⛔", clients[clientIndex].Email, "Terminated")
} else {
remark = fmt.Sprintf("%s: %s - %s", clients[clientIndex].Email, remainedTraffic, expiryTimeString)
}
remark := fmt.Sprintf("%s: %s- %s", clients[clientIndex].Email, remainedTraffic, expiryTimeString)
url.Fragment = remark url.Fragment = remark
return url.String() return url.String()
} }
@@ -851,18 +823,15 @@ func getExpiryTime(expiryTime int64) string {
expiryString := "" expiryString := ""
timeDifference := expiryTime/1000 - now timeDifference := expiryTime/1000 - now
isTerminated := timeDifference/3600 <= 0
if expiryTime == 0 { if expiryTime == 0 {
expiryString = "♾ ⏳" expiryString = "♾ ⏳"
} else if timeDifference > 172800 { } else if timeDifference > 172800 {
expiryString = fmt.Sprintf("%d %s⏳", timeDifference/86400, "Days") expiryString = fmt.Sprintf("%s ⏳", ptime.Unix((expiryTime/1000), 0).Format("yy-MM-dd hh:mm"))
} else if expiryTime < 0 { } else if expiryTime < 0 {
expiryString = fmt.Sprintf("%d %s⏳", expiryTime/-86400000, "Days") expiryString = fmt.Sprintf("%d ⏳", expiryTime/-86400000)
} else if isTerminated {
expiryString = fmt.Sprintf("%s⛔", "Terminated")
} else { } else {
expiryString = fmt.Sprintf("%d %s⏳", timeDifference/3600, "Hours") expiryString = fmt.Sprintf("%s %d ⏳", "ساعت", timeDifference/3600)
} }
return expiryString return expiryString
@@ -875,12 +844,8 @@ func (s *SubService) getRemainedTraffic(email string) string {
} }
remainedTraffic := "" remainedTraffic := ""
isTerminated := traffic.Total-(traffic.Up+traffic.Down) < 0
if traffic.Total == 0 { if traffic.Total == 0 {
remainedTraffic = "♾ 📊" remainedTraffic = "♾ 📊"
} else if isTerminated {
remainedTraffic = fmt.Sprintf("%s⛔", "Terminated")
} else { } else {
remainedTraffic = fmt.Sprintf("%s%s", common.FormatTraffic(traffic.Total-(traffic.Up+traffic.Down)), "📊") remainedTraffic = fmt.Sprintf("%s%s", common.FormatTraffic(traffic.Total-(traffic.Up+traffic.Down)), "📊")
} }

View File

@@ -16,10 +16,9 @@ const VmessMethods = {
}; };
const SSMethods = { const SSMethods = {
CHACHA20_POLY1305: 'chacha20-poly1305',
AES_256_GCM: 'aes-256-gcm', AES_256_GCM: 'aes-256-gcm',
AES_128_GCM: 'aes-128-gcm', AES_128_GCM: 'aes-128-gcm',
CHACHA20_POLY1305: 'chacha20-poly1305',
XCHACHA20_POLY1305: 'xchacha20-poly1305',
BLAKE3_AES_128_GCM: '2022-blake3-aes-128-gcm', BLAKE3_AES_128_GCM: '2022-blake3-aes-128-gcm',
BLAKE3_AES_256_GCM: '2022-blake3-aes-256-gcm', BLAKE3_AES_256_GCM: '2022-blake3-aes-256-gcm',
BLAKE3_CHACHA20_POLY1305: '2022-blake3-chacha20-poly1305', BLAKE3_CHACHA20_POLY1305: '2022-blake3-chacha20-poly1305',
@@ -387,10 +386,12 @@ class HttpStreamSettings extends XrayCommonClass {
constructor( constructor(
path='/', path='/',
host=[''], host=[''],
sockopt={acceptProxyProtocol: false}
) { ) {
super(); super();
this.path = path; this.path = path;
this.host = host.length === 0 ? [''] : host; this.host = host.length === 0 ? [''] : host;
this.sockopt = sockopt;
} }
addHost(host) { addHost(host) {
@@ -402,7 +403,7 @@ class HttpStreamSettings extends XrayCommonClass {
} }
static fromJson(json={}) { static fromJson(json={}) {
return new HttpStreamSettings(json.path, json.host); return new HttpStreamSettings(json.path, json.host, json.sockopt);
} }
toJson() { toJson() {
@@ -415,6 +416,7 @@ class HttpStreamSettings extends XrayCommonClass {
return { return {
path: this.path, path: this.path,
host: host, host: host,
sockopt: this.sockopt,
} }
} }
} }
@@ -422,7 +424,7 @@ class HttpStreamSettings extends XrayCommonClass {
class QuicStreamSettings extends XrayCommonClass { class QuicStreamSettings extends XrayCommonClass {
constructor(security=VmessMethods.NONE, constructor(security=VmessMethods.NONE,
key=RandomUtil.randomSeq(10), type='none') { key='', type='none') {
super(); super();
this.security = security; this.security = security;
this.key = key; this.key = key;
@@ -452,16 +454,19 @@ class GrpcStreamSettings extends XrayCommonClass {
constructor( constructor(
serviceName="", serviceName="",
multiMode=false, multiMode=false,
sockopt={acceptProxyProtocol: false}
) { ) {
super(); super();
this.serviceName = serviceName; this.serviceName = serviceName;
this.multiMode = multiMode; this.multiMode = multiMode;
this.sockopt = sockopt;
} }
static fromJson(json={}) { static fromJson(json={}) {
return new GrpcStreamSettings( return new GrpcStreamSettings(
json.serviceName, json.serviceName,
json.multiMode json.multiMode,
json.sockopt
); );
} }
@@ -469,6 +474,7 @@ class GrpcStreamSettings extends XrayCommonClass {
return { return {
serviceName: this.serviceName, serviceName: this.serviceName,
multiMode: this.multiMode, multiMode: this.multiMode,
sockopt: this.sockopt
} }
} }
} }
@@ -800,27 +806,6 @@ RealityStreamSettings.Settings = class extends XrayCommonClass {
} }
}; };
class SockoptStreamSettings extends XrayCommonClass {
constructor(
acceptProxyProtocol = false,
) {
super();
this.acceptProxyProtocol = acceptProxyProtocol;
}
static fromJson(json = {}) {
return new SockoptStreamSettings(
json.acceptProxyProtocol,
);
}
toJson() {
return {
acceptProxyProtocol: this.acceptProxyProtocol,
};
}
}
class StreamSettings extends XrayCommonClass { class StreamSettings extends XrayCommonClass {
constructor(network='tcp', constructor(network='tcp',
security='none', security='none',
@@ -833,7 +818,6 @@ class StreamSettings extends XrayCommonClass {
httpSettings=new HttpStreamSettings(), httpSettings=new HttpStreamSettings(),
quicSettings=new QuicStreamSettings(), quicSettings=new QuicStreamSettings(),
grpcSettings=new GrpcStreamSettings(), grpcSettings=new GrpcStreamSettings(),
sockopt = new SockoptStreamSettings(),
) { ) {
super(); super();
this.network = network; this.network = network;
@@ -847,7 +831,6 @@ class StreamSettings extends XrayCommonClass {
this.http = httpSettings; this.http = httpSettings;
this.quic = quicSettings; this.quic = quicSettings;
this.grpc = grpcSettings; this.grpc = grpcSettings;
this.sockopt = sockopt;
} }
get isTls() { get isTls() {
@@ -887,16 +870,6 @@ class StreamSettings extends XrayCommonClass {
} }
} }
get isSockopt() {
return ['http', 'grpc'].indexOf(this.network) !== -1;
}
set isSockopt(isSockopt) {
if (isSockopt) {
return ['http', 'grpc'].indexOf(this.network) !== -1;
}
}
static fromJson(json={}) { static fromJson(json={}) {
return new StreamSettings( return new StreamSettings(
@@ -911,7 +884,6 @@ class StreamSettings extends XrayCommonClass {
HttpStreamSettings.fromJson(json.httpSettings), HttpStreamSettings.fromJson(json.httpSettings),
QuicStreamSettings.fromJson(json.quicSettings), QuicStreamSettings.fromJson(json.quicSettings),
GrpcStreamSettings.fromJson(json.grpcSettings), GrpcStreamSettings.fromJson(json.grpcSettings),
SockoptStreamSettings.fromJson(json.sockopt),
); );
} }
@@ -929,7 +901,6 @@ class StreamSettings extends XrayCommonClass {
httpSettings: network === 'http' ? this.http.toJson() : undefined, httpSettings: network === 'http' ? this.http.toJson() : undefined,
quicSettings: network === 'quic' ? this.quic.toJson() : undefined, quicSettings: network === 'quic' ? this.quic.toJson() : undefined,
grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined, grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined,
sockopt: this.isSockopt ? this.sockopt.toJson() : undefined,
}; };
} }
} }
@@ -1069,10 +1040,7 @@ class Inbound extends XrayCommonClass {
} }
} }
get isSSMultiUser() { get isSSMultiUser() {
return this.method != SSMethods.BLAKE3_CHACHA20_POLY1305; return [SSMethods.BLAKE3_AES_128_GCM,SSMethods.BLAKE3_AES_256_GCM].includes(this.method);
}
get isSS2022(){
return this.method.substring(0,4) === "2022";
} }
get serverName() { get serverName() {
@@ -1502,11 +1470,9 @@ class Inbound extends XrayCommonClass {
break; break;
} }
let password = new Array(); let clientPassword = this.isSSMultiUser ? ':' + settings.shadowsockses[clientIndex].password : '';
if (this.isSS2022) password.push(settings.password);
if (this.isSSMultiUser) password.push(settings.shadowsockses[clientIndex].password);
let link = `ss://${safeBase64(settings.method + ':' + password.join(':'))}@${address}:${this.port}`; let link = `ss://${safeBase64(settings.method + ':' + settings.password + clientPassword)}@${address}:${this.port}`;
const url = new URL(link); const url = new URL(link);
for (const [key, value] of params) { for (const [key, value] of params) {
url.searchParams.set(key, value) url.searchParams.set(key, value)
@@ -2131,9 +2097,8 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
}; };
Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass { Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
constructor(method='', password=RandomUtil.randomShadowsocksPassword(), email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16)) { constructor(password=RandomUtil.randomShadowsocksPassword(), email=RandomUtil.randomLowerAndNum(8),limitIp=0, totalGB=0, expiryTime=0, enable=true, tgId='', subId=RandomUtil.randomLowerAndNum(16)) {
super(); super();
this.method = method;
this.password = password; this.password = password;
this.email = email; this.email = email;
this.limitIp = limitIp; this.limitIp = limitIp;
@@ -2146,7 +2111,6 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
toJson() { toJson() {
return { return {
method: this.method,
password: this.password, password: this.password,
email: this.email, email: this.email,
limitIp: this.limitIp, limitIp: this.limitIp,
@@ -2160,7 +2124,6 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
static fromJson(json = {}) { static fromJson(json = {}) {
return new Inbound.ShadowsocksSettings.Shadowsocks( return new Inbound.ShadowsocksSettings.Shadowsocks(
json.method,
json.password, json.password,
json.email, json.email,
json.limitIp, json.limitIp,

View File

@@ -118,9 +118,12 @@ func (a *ServerController) restartXrayService(c *gin.Context) {
func (a *ServerController) getLogs(c *gin.Context) { func (a *ServerController) getLogs(c *gin.Context) {
count := c.Param("count") count := c.Param("count")
level := c.PostForm("level") logLevel := c.PostForm("logLevel")
syslog := c.PostForm("syslog") logs, err := a.serverService.GetLogs(count, logLevel)
logs := a.serverService.GetLogs(count, level, syslog) if err != nil {
jsonMsg(c, "getLogs", err)
return
}
jsonObj(c, logs, nil) jsonObj(c, logs, nil)
} }

View File

@@ -200,12 +200,21 @@
this.inbound = dbInbound.toInbound(); this.inbound = dbInbound.toInbound();
this.delayedStart = false; this.delayedStart = false;
}, },
getClients(protocol, clientSettings) {
switch (protocol) {
case Protocols.VMESS: return clientSettings.vmesses;
case Protocols.VLESS: return clientSettings.vlesses;
case Protocols.TROJAN: return clientSettings.trojans;
case Protocols.SHADOWSOCKS: return clientSettings.shadowsockses;
default: return null;
}
},
newClient(protocol) { newClient(protocol) {
switch (protocol) { switch (protocol) {
case Protocols.VMESS: return new Inbound.VmessSettings.Vmess(); case Protocols.VMESS: return new Inbound.VmessSettings.Vmess();
case Protocols.VLESS: return new Inbound.VLESSSettings.VLESS(); case Protocols.VLESS: return new Inbound.VLESSSettings.VLESS();
case Protocols.TROJAN: return new Inbound.TrojanSettings.Trojan(); case Protocols.TROJAN: return new Inbound.TrojanSettings.Trojan();
case Protocols.SHADOWSOCKS: return new Inbound.ShadowsocksSettings.Shadowsocks(clientsBulkModal.inbound.settings.shadowsockses[0].method); case Protocols.SHADOWSOCKS: return new Inbound.ShadowsocksSettings.Shadowsocks();
default: return null; default: return null;
} }
}, },

View File

@@ -70,7 +70,7 @@
case Protocols.VMESS: return clients.push(new Inbound.VmessSettings.Vmess()); case Protocols.VMESS: return clients.push(new Inbound.VmessSettings.Vmess());
case Protocols.VLESS: return clients.push(new Inbound.VLESSSettings.VLESS()); case Protocols.VLESS: return clients.push(new Inbound.VLESSSettings.VLESS());
case Protocols.TROJAN: return clients.push(new Inbound.TrojanSettings.Trojan()); case Protocols.TROJAN: return clients.push(new Inbound.TrojanSettings.Trojan());
case Protocols.SHADOWSOCKS: return clients.push(new Inbound.ShadowsocksSettings.Shadowsocks(clients[0].method)); case Protocols.SHADOWSOCKS: return clients.push(new Inbound.ShadowsocksSettings.Shadowsocks());
default: return null; default: return null;
} }
}, },

View File

@@ -1,19 +1,10 @@
{{define "form/http"}} {{define "form/http"}}
<a-form layout="inline"> <a-form layout="inline">
<a-form-item> <a-form-item label='{{ i18n "username"}}'>
<a-row> <a-input v-model.trim="inbound.settings.accounts[0].user"></a-input>
<a-button type="primary" size="small" @click="inbound.settings.addAccount(new Inbound.SocksSettings.SocksAccount())">+</a-button> </a-form-item>
</a-row> <a-form-item label='{{ i18n "password" }}'>
<a-input-group v-for="(account, index) in inbound.settings.accounts"> <a-input v-model.trim="inbound.settings.accounts[0].pass"></a-input>
<a-input style="width: 45%" v-model.trim="account.user"
addon-before='{{ i18n "username" }}'></a-input>
<a-input style="width: 55%" v-model.trim="account.pass"
addon-before='{{ i18n "password" }}'>
<template slot="addonAfter">
<a-button type="primary" size="small" @click="inbound.settings.delAccount(index)">-</a-button>
</template>
</a-input>
</a-input-group>
</a-form-item> </a-form-item>
</a-form> </a-form>
{{end}} {{end}}

View File

@@ -115,7 +115,7 @@
<a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option> <a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item v-if="inbound.isSS2022" label='{{ i18n "password" }}'> <a-form-item label='{{ i18n "password" }}'>
<a-icon @click="inbound.settings.password = RandomUtil.randomShadowsocksPassword()" type="sync"> </a-icon> <a-icon @click="inbound.settings.password = RandomUtil.randomShadowsocksPassword()" type="sync"> </a-icon>
<a-input v-model.trim="inbound.settings.password" style="width: 250px;"></a-input> <a-input v-model.trim="inbound.settings.password" style="width: 250px;"></a-input>
</a-form-item> </a-form-item>

View File

@@ -6,20 +6,11 @@
</a-form-item> </a-form-item>
<br> <br>
<template v-if="inbound.settings.auth === 'password'"> <template v-if="inbound.settings.auth === 'password'">
<a-form-item> <a-form-item label='{{ i18n "username" }}'>
<a-row> <a-input v-model.trim="inbound.settings.accounts[0].user"></a-input>
<a-button type="primary" size="small" @click="inbound.settings.addAccount(new Inbound.SocksSettings.SocksAccount())">+</a-button> </a-form-item>
</a-row> <a-form-item label='{{ i18n "password" }}'>
<a-input-group v-for="(account, index) in inbound.settings.accounts"> <a-input v-model.trim="inbound.settings.accounts[0].pass"></a-input>
<a-input style="width: 45%" v-model.trim="account.user"
addon-before='{{ i18n "username" }}'></a-input>
<a-input style="width: 55%" v-model.trim="account.pass"
addon-before='{{ i18n "password" }}'>
<template slot="addonAfter">
<a-button type="primary" size="small" @click="inbound.settings.delAccount(index)">-</a-button>
</template>
</a-input>
</a-input-group>
</a-form-item> </a-form-item>
</template> </template>
<br> <br>

View File

@@ -1,7 +1,7 @@
{{define "form/streamGRPC"}} {{define "form/streamGRPC"}}
<a-form layout="inline"> <a-form layout="inline">
<a-form-item label="AcceptProxyProtocol"> <a-form-item label="AcceptProxyProtocol">
<a-switch v-model="inbound.stream.sockopt.acceptProxyProtocol"></a-switch> <a-switch v-model="inbound.stream.grpc.sockopt.acceptProxyProtocol"></a-switch>
</a-form-item> </a-form-item>
<br> <br>
<a-form-item label="ServiceName"> <a-form-item label="ServiceName">

View File

@@ -1,7 +1,7 @@
{{define "form/streamHTTP"}} {{define "form/streamHTTP"}}
<a-form layout="inline"> <a-form layout="inline">
<a-form-item label="AcceptProxyProtocol"> <a-form-item label="AcceptProxyProtocol">
<a-switch v-model="inbound.stream.sockopt.acceptProxyProtocol"></a-switch> <a-switch v-model="inbound.stream.http.sockopt.acceptProxyProtocol"></a-switch>
</a-form-item> </a-form-item>
<br> <br>
<a-form-item label='{{ i18n "path" }}'> <a-form-item label='{{ i18n "path" }}'>

View File

@@ -12,8 +12,7 @@
</a-form-item> </a-form-item>
<br> <br>
<a-form-item label='{{ i18n "password" }}'> <a-form-item label='{{ i18n "password" }}'>
<a-icon @click="inbound.stream.kcp.seed = RandomUtil.randomSeq(10)" type="sync"> </a-icon> <a-input v-model="inbound.stream.kcp.seed"></a-input>
<a-input v-model="inbound.stream.kcp.seed" style="width: 150px;" ></a-input>
</a-form-item> </a-form-item>
<br> <br>
<a-form-item label="MTU"> <a-form-item label="MTU">

View File

@@ -8,8 +8,7 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "password" }}'> <a-form-item label='{{ i18n "password" }}'>
<a-icon @click="inbound.stream.quic.key = RandomUtil.randomSeq(10)" type="sync"> </a-icon> <a-input v-model.trim="inbound.stream.quic.key"></a-input>
<a-input v-model.trim="inbound.stream.quic.key" style="width: 150px;"></a-input>
</a-form-item> </a-form-item>
<a-form-item label='{{ i18n "camouflage" }}'> <a-form-item label='{{ i18n "camouflage" }}'>
<a-select v-model="inbound.stream.quic.type" style="width: 280px;" :dropdown-class-name="themeSwitcher.darkCardClass"> <a-select v-model="inbound.stream.quic.type" style="width: 280px;" :dropdown-class-name="themeSwitcher.darkCardClass">

View File

@@ -58,19 +58,8 @@
reality: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br /> reality: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br />
reality Destination: <a-tag :color="inbound.stream.reality.dest ? 'green' : 'orange'">[[ inbound.stream.reality.dest ]]</a-tag> reality Destination: <a-tag :color="inbound.stream.reality.dest ? 'green' : 'orange'">[[ inbound.stream.reality.dest ]]</a-tag>
</td> </td>
<td v-else>tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag></td> <td v-else>tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag>
</tr> </td>
</table>
<table v-if="dbInbound.isSS" style="margin-bottom: 10px; width: 100%;">
<tr>
<td>{{ i18n "encryption" }}</td>
<td><a-tag color="green">[[ inbound.settings.method ]]</a-tag></td>
</tr><tr v-if="inbound.isSS2022">
<td>{{ i18n "password" }}</td>
<td><a-tag color="blue">[[ inbound.settings.password ]]</a-tag></td>
</tr><tr>
<td>{{ i18n "pages.inbounds.network" }}</td>
<td><a-tag color="green">[[ inbound.settings.network ]]</a-tag></td>
</tr> </tr>
</table> </table>
<template v-if="infoModal.clientSettings"> <template v-if="infoModal.clientSettings">
@@ -178,7 +167,19 @@
</template> </template>
</template> </template>
<template v-else> <template v-else>
<template v-if="dbInbound.isSS && !inbound.isSSMultiUser"> <a-divider></a-divider>
<table v-if="inbound.protocol == Protocols.SHADOWSOCKS" style="margin-bottom: 10px; width: 100%;">
<tr>
<th>{{ i18n "encryption" }}</th>
<th>{{ i18n "password" }}</th>
<th>{{ i18n "pages.inbounds.network" }}</th>
</tr><tr>
<td><a-tag color="green">[[ inbound.settings.method ]]</a-tag></td>
<td><a-tag color="blue">[[ inbound.settings.password ]]</a-tag></td>
<td><a-tag color="green">[[ inbound.settings.network ]]</a-tag></td>
</tr>
</table>
<template v-if="inbound.protocol == Protocols.SHADOWSOCKS && !inbound.isSSMultiUser">
<a-divider>URL</a-divider> <a-divider>URL</a-divider>
<a-row v-for="(link,index) in infoModal.links"> <a-row v-for="(link,index) in infoModal.links">
<a-col :span="22"><a-tag color="cyan">[[ link.remark ]]</a-tag><br />[[ link.link ]]</a-col> <a-col :span="22"><a-tag color="cyan">[[ link.remark ]]</a-tag><br />[[ link.link ]]</a-col>
@@ -204,19 +205,17 @@
<td><a-tag color="blue">[[ inbound.settings.followRedirect ]]</a-tag></td> <td><a-tag color="blue">[[ inbound.settings.followRedirect ]]</a-tag></td>
</tr> </tr>
</table> </table>
<table v-if="dbInbound.isSocks" style="margin-bottom: 10px; width: 100%;"> </table>
<table v-if="inbound.protocol == Protocols.SOCKS" style="margin-bottom: 10px; width: 100%;">
<tr> <tr>
<th>{{ i18n "password" }} Auth</th> <th>{{ i18n "password" }} Auth</th>
<th>{{ i18n "pages.inbounds.enable" }} udp</th> <th>{{ i18n "pages.inbounds.enable" }} udp</th>
<th>IP</th> <th>IP</th>
</tr> </tr><tr>
<tr>
<td><a-tag color="green">[[ inbound.settings.auth ]]</a-tag></td> <td><a-tag color="green">[[ inbound.settings.auth ]]</a-tag></td>
<td><a-tag color="blue">[[ inbound.settings.udp]]</a-tag></td> <td><a-tag color="blue">[[ inbound.settings.udp]]</a-tag></td>
<td><a-tag color="green">[[ inbound.settings.ip ]]</a-tag></td> <td><a-tag color="green">[[ inbound.settings.ip ]]</a-tag></td>
</tr> </tr><tr v-if="inbound.settings.auth == 'password'">
<template v-if="inbound.settings.auth == 'password'">
<tr>
<td> </td> <td> </td>
<td>{{ i18n "username" }}</td> <td>{{ i18n "username" }}</td>
<td>{{ i18n "password" }}</td> <td>{{ i18n "password" }}</td>
@@ -225,9 +224,9 @@
<td><a-tag color="blue">[[ account.user ]]</a-tag></td> <td><a-tag color="blue">[[ account.user ]]</a-tag></td>
<td><a-tag color="green">[[ account.pass ]]</a-tag></td> <td><a-tag color="green">[[ account.pass ]]</a-tag></td>
</tr> </tr>
</template> </table>
</table> </table>
<table v-if="dbInbound.isHTTP" style="margin-bottom: 10px; width: 100%;"> <table v-if="inbound.protocol == Protocols.HTTP" style="margin-bottom: 10px; width: 100%;">
<tr> <tr>
<th> </th> <th> </th>
<th>{{ i18n "username" }}</th> <th>{{ i18n "username" }}</th>
@@ -238,6 +237,7 @@
<td><a-tag color="green">[[ account.pass ]]</a-tag></td> <td><a-tag color="green">[[ account.pass ]]</a-tag></td>
</tr> </tr>
</table> </table>
</table>
</template> </template>
</a-modal> </a-modal>
<script> <script>

View File

@@ -110,15 +110,6 @@
if (this.inModal.inbound.settings.shadowsockses.length ==0){ if (this.inModal.inbound.settings.shadowsockses.length ==0){
this.inModal.inbound.settings.shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()]; this.inModal.inbound.settings.shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()];
} }
if (["aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305"].includes(this.inModal.inbound.settings.method)) {
this.inModal.inbound.settings.shadowsockses.forEach(client => {
client.method = this.inModal.inbound.settings.method;
})
} else {
this.inModal.inbound.settings.shadowsockses.forEach(client => {
client.method = "";
})
}
} else { } else {
if (this.inModal.inbound.settings.shadowsockses.length > 0){ if (this.inModal.inbound.settings.shadowsockses.length > 0){
this.inModal.inbound.settings.shadowsockses = []; this.inModal.inbound.settings.shadowsockses = [];

View File

@@ -11,9 +11,6 @@
.ant-col-sm-24 { .ant-col-sm-24 {
margin-top: 10px; margin-top: 10px;
} }
tr.hideExpandIcon .ant-table-row-expand-icon {
display: none;
}
</style> </style>
<body> <body>
@@ -121,12 +118,8 @@
</a-radio-group> </a-radio-group>
<a-table :columns="columns" :row-key="dbInbound => dbInbound.id" <a-table :columns="columns" :row-key="dbInbound => dbInbound.id"
:data-source="searchedInbounds" :data-source="searchedInbounds"
:loading="spinning" :scroll="{ x: 1200 }" :loading="spinning" :scroll="{ x: 1300 }"
:pagination="false" :pagination="false"
:expand-icon-as-cell="false"
:expand-row-by-click="false"
:expand-icon-column-index="0"
:row-class-name="dbInbound => (dbInbound.isTrojan || dbInbound.isVLess || dbInbound.isVMess || (dbInbound.isSS && dbInbound.toInbound().isSSMultiUser) ? '' : 'hideExpandIcon')"
style="margin-top: 20px" style="margin-top: 20px"
@change="() => getDBInbounds()"> @change="() => getDBInbounds()">
<template slot="action" slot-scope="text, dbInbound"> <template slot="action" slot-scope="text, dbInbound">
@@ -142,7 +135,7 @@
<a-icon type="qrcode"></a-icon> <a-icon type="qrcode"></a-icon>
{{ i18n "qrCode" }} {{ i18n "qrCode" }}
</a-menu-item> </a-menu-item>
<template v-if="dbInbound.isTrojan || dbInbound.isVLess || dbInbound.isVMess || (dbInbound.isSS && dbInbound.toInbound().isSSMultiUser)"> <template v-if="dbInbound.isTrojan || dbInbound.isVLess || dbInbound.isVMess || dbInbound.toInbound().isSSMultiUser">
<a-menu-item key="addClient"> <a-menu-item key="addClient">
<a-icon type="user-add"></a-icon> <a-icon type="user-add"></a-icon>
{{ i18n "pages.client.add"}} {{ i18n "pages.client.add"}}
@@ -262,7 +255,6 @@
:columns="innerColumns" :columns="innerColumns"
:data-source="getInboundClients(record)" :data-source="getInboundClients(record)"
:pagination="false" :pagination="false"
style="margin-left: 20px;"
> >
{{template "client_table"}} {{template "client_table"}}
</a-table> </a-table>
@@ -272,7 +264,6 @@
:columns="innerTrojanColumns" :columns="innerTrojanColumns"
:data-source="getInboundClients(record)" :data-source="getInboundClients(record)"
:pagination="false" :pagination="false"
style="margin-left: 20px;"
> >
{{template "client_table"}} {{template "client_table"}}
</a-table> </a-table>
@@ -288,20 +279,20 @@
{{template "component/themeSwitcher" .}} {{template "component/themeSwitcher" .}}
<script> <script>
const columns = [{ const columns = [{
title: "ID",
align: 'right',
dataIndex: "id",
width: 30,
}, {
title: '{{ i18n "pages.inbounds.operate" }}', title: '{{ i18n "pages.inbounds.operate" }}',
align: 'center', align: 'center',
width: 40, width: 60,
scopedSlots: { customRender: 'action' }, scopedSlots: { customRender: 'action' },
}, { }, {
title: '{{ i18n "pages.inbounds.enable" }}', title: '{{ i18n "pages.inbounds.enable" }}',
align: 'center', align: 'center',
width: 40, width: 40,
scopedSlots: { customRender: 'enable' }, scopedSlots: { customRender: 'enable' },
}, {
title: "ID",
align: 'center',
dataIndex: "id",
width: 40,
}, { }, {
title: '{{ i18n "pages.inbounds.remark" }}', title: '{{ i18n "pages.inbounds.remark" }}',
align: 'center', align: 'center',
@@ -349,7 +340,7 @@
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } }, { title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 50, scopedSlots: { customRender: 'traffic' } }, { title: '{{ i18n "pages.inbounds.traffic" }}', width: 50, scopedSlots: { customRender: 'traffic' } },
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 50, scopedSlots: { customRender: 'expiryTime' } }, { title: '{{ i18n "pages.inbounds.expireDate" }}', width: 50, scopedSlots: { customRender: 'expiryTime' } },
{ title: '{{ i18n "password" }}', width: 170, dataIndex: "password" }, { title: 'Password', width: 170, dataIndex: "password" },
]; ];
const app = new Vue({ const app = new Vue({

View File

@@ -86,7 +86,7 @@
<a-col :sm="24" :md="12"> <a-col :sm="24" :md="12">
<a-card hoverable :class="themeSwitcher.darkCardClass"> <a-card hoverable :class="themeSwitcher.darkCardClass">
{{ i18n "menu.link" }}: {{ i18n "menu.link" }}:
<a-tag color="blue" style="cursor: pointer;" @click="openLogs()">{{ i18n "pages.index.logs" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="openLogs(logModal.rows, logModal.logLevel)">{{ i18n "pages.index.logs" }}</a-tag>
<a-tag color="blue" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag>
<a-tag color="blue" style="cursor: pointer;" @click="openBackup">{{ i18n "pages.index.backup" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="openBackup">{{ i18n "pages.index.backup" }}</a-tag>
</a-card> </a-card>
@@ -108,30 +108,21 @@
</a-col> </a-col>
<a-col :sm="24" :md="12"> <a-col :sm="24" :md="12">
<a-card hoverable :class="themeSwitcher.darkCardClass"> <a-card hoverable :class="themeSwitcher.darkCardClass">
{{ i18n "pages.index.operationHours" }}: <a-row>
Xray: <a-col :span="12">
<a-tag color="green">[[ formatSecond(status.appStats.uptime) ]]</a-tag> {{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]]
OS: <a-tooltip>
<a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag> <template slot="title">
</a-card> {{ i18n "pages.index.systemLoadDesc" }}
</a-col> </template>
<a-col :sm="24" :md="12"> <a-icon type="question-circle" theme="filled"></a-icon>
<a-card hoverable :class="themeSwitcher.darkCardClass"> </a-tooltip>
{{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]] </a-col>
<a-tooltip> <a-col :span="12">
<template slot="title"> {{ i18n "pages.index.operationHours" }}:
{{ i18n "pages.index.systemLoadDesc" }} <a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag>
</template> </a-col>
<a-icon type="question-circle" theme="filled"></a-icon> </a-row>
</a-tooltip>
</a-card>
</a-col>
<a-col :sm="24" :md="12">
<a-card hoverable :class="themeSwitcher.darkCardClass">
{{ i18n "usage"}}:
Memory [[ sizeFormat(status.appStats.mem) ]] -
Threads [[ status.appStats.threads ]]
</a-tooltip>
</a-card> </a-card>
</a-col> </a-col>
<a-col :sm="24" :md="12"> <a-col :sm="24" :md="12">
@@ -262,7 +253,7 @@
<a-form-item label="Count"> <a-form-item label="Count">
<a-select v-model="logModal.rows" <a-select v-model="logModal.rows"
style="width: 80px" style="width: 80px"
@change="openLogs()" @change="openLogs(logModal.rows, logModal.logLevel)"
:dropdown-class-name="themeSwitcher.darkCardClass"> :dropdown-class-name="themeSwitcher.darkCardClass">
<a-select-option value="10">10</a-select-option> <a-select-option value="10">10</a-select-option>
<a-select-option value="20">20</a-select-option> <a-select-option value="20">20</a-select-option>
@@ -271,9 +262,9 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label="Log Level"> <a-form-item label="Log Level">
<a-select v-model="logModal.level" <a-select v-model="logModal.logLevel"
style="width: 120px" style="width: 120px"
@change="openLogs()" @change="openLogs(logModal.rows, logModal.logLevel)"
:dropdown-class-name="themeSwitcher.darkCardClass"> :dropdown-class-name="themeSwitcher.darkCardClass">
<a-select-option value="debug">Debug</a-select-option> <a-select-option value="debug">Debug</a-select-option>
<a-select-option value="info">Info</a-select-option> <a-select-option value="info">Info</a-select-option>
@@ -282,11 +273,8 @@
<a-select-option value="err">Error</a-select-option> <a-select-option value="err">Error</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label="SysLog">
<a-checkbox v-model="logModal.syslog" @change="openLogs()"></a-checkbox>
</a-form-item>
<a-form-item> <a-form-item>
<button class="ant-btn ant-btn-primary" @click="openLogs()"><a-icon type="sync"></a-icon> Reload</button> <button class="ant-btn ant-btn-primary" @click="openLogs(logModal.rows, logModal.logLevel)"><a-icon type="sync"></a-icon> Reload</button>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" style="margin-bottom: 10px;" <a-button type="primary" style="margin-bottom: 10px;"
@@ -370,8 +358,6 @@
this.tcpCount = 0; this.tcpCount = 0;
this.udpCount = 0; this.udpCount = 0;
this.uptime = 0; this.uptime = 0;
this.appUptime = 0;
this.appStats = {threads: 0, mem: 0, uptime: 0};
this.xray = { state: State.Stop, errorMsg: "", version: "", color: "" }; this.xray = { state: State.Stop, errorMsg: "", version: "", color: "" };
if (data == null) { if (data == null) {
@@ -390,8 +376,6 @@
this.tcpCount = data.tcpCount; this.tcpCount = data.tcpCount;
this.udpCount = data.udpCount; this.udpCount = data.udpCount;
this.uptime = data.uptime; this.uptime = data.uptime;
this.appUptime = data.appUptime;
this.appStats = data.appStats;
this.xray = data.xray; this.xray = data.xray;
switch (this.xray.state) { switch (this.xray.state) {
case State.Running: case State.Running:
@@ -425,11 +409,11 @@
visible: false, visible: false,
logs: '', logs: '',
rows: 20, rows: 20,
level: 'info', logLevel: 'info',
syslog: false, show(logs, rows) {
show(logs) {
this.visible = true; this.visible = true;
this.logs = logs? logs.join("\n"): "No Record..."; this.rows = rows;
this.logs = logs.join("\n");
}, },
hide() { hide() {
this.visible = false; this.visible = false;
@@ -530,14 +514,14 @@
return; return;
} }
}, },
async openLogs(){ async openLogs(rows, logLevel) {
this.loading(true); this.loading(true);
const msg = await HttpUtil.post('server/logs/'+logModal.rows,{level: logModal.level, syslog: logModal.syslog}); const msg = await HttpUtil.post('server/logs/' + rows, { logLevel: `${logLevel}` });
this.loading(false); this.loading(false);
if (!msg.success) { if (!msg.success) {
return; return;
} }
logModal.show(msg.obj); logModal.show(msg.obj, rows);
}, },
async openConfig() { async openConfig() {
this.loading(true); this.loading(true);

View File

@@ -15,11 +15,12 @@ import (
"x-ui/xray" "x-ui/xray"
) )
type CheckClientIpJob struct{} type CheckClientIpJob struct {}
var job *CheckClientIpJob var job *CheckClientIpJob
var disAllowedIps []string var disAllowedIps []string
var ipFiles = []string{ var ipFiles = []string{
xray.GetBlockedIPsPath(),
xray.GetIPLimitLogPath(), xray.GetIPLimitLogPath(),
xray.GetIPLimitBannedLogPath(), xray.GetIPLimitBannedLogPath(),
xray.GetAccessPersistentLogPath(), xray.GetAccessPersistentLogPath(),
@@ -31,6 +32,7 @@ func NewCheckClientIpJob() *CheckClientIpJob {
} }
func (j *CheckClientIpJob) Run() { func (j *CheckClientIpJob) Run() {
logger.Debug("Check Client IP Job...")
// create files required for iplimit if not exists // create files required for iplimit if not exists
for i := 0; i < len(ipFiles); i++ { for i := 0; i < len(ipFiles); i++ {
@@ -43,6 +45,11 @@ func (j *CheckClientIpJob) Run() {
if j.hasLimitIp() { if j.hasLimitIp() {
j.processLogFile() j.processLogFile()
} }
// write to blocked ips
blockedIps := []byte(strings.Join(disAllowedIps, ","))
err := os.WriteFile(xray.GetBlockedIPsPath(), blockedIps, 0644)
j.checkError(err)
} }
func (j *CheckClientIpJob) hasLimitIp() bool { func (j *CheckClientIpJob) hasLimitIp() bool {
@@ -129,8 +136,8 @@ func (j *CheckClientIpJob) processLogFile() {
} }
// added delay before cleaning logs to reduce chance of logging IP that already has been banned // added 3 seconds delay before cleaning logs to reduce chance of logging IP that already has been banned
time.Sleep(time.Second * 2) time.Sleep(time.Second * 3)
if shouldCleanLog { if shouldCleanLog {
// copy access log to persistent file // copy access log to persistent file

View File

@@ -316,17 +316,21 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
needRestart := false needRestart := false
s.xrayApi.Init(p.GetAPIPort()) s.xrayApi.Init(p.GetAPIPort())
if s.xrayApi.DelInbound(tag) == nil { err1 := s.xrayApi.DelInbound(tag)
if err1 != nil {
logger.Debug("Unable to delete old inbound by api:", err1)
needRestart = true
} else {
logger.Debug("Old inbound deleted by api:", tag) logger.Debug("Old inbound deleted by api:", tag)
}
if inbound.Enable { if inbound.Enable {
inboundJson, err2 := json.MarshalIndent(oldInbound.GenXrayInboundConfig(), "", " ") inboundJson, err2 := json.MarshalIndent(oldInbound.GenXrayInboundConfig(), "", " ")
if err2 != nil { if err2 != nil {
logger.Debug("Unable to marshal updated inbound config:", err2) logger.Debug("Unable to marshal updated inbound config:", err2)
needRestart = true }
} else {
err2 = s.xrayApi.AddInbound(inboundJson) err2 = s.xrayApi.AddInbound(inboundJson)
if err2 == nil { if err1 == nil {
logger.Debug("Updated inbound added by api:", oldInbound.Tag) logger.Debug("Updated inbound added by api:", oldInbound.Tag)
} else { } else {
logger.Debug("Unable to update inbound by api:", err2) logger.Debug("Unable to update inbound by api:", err2)
@@ -457,21 +461,15 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) (bool, error) {
if len(client.Email) > 0 { if len(client.Email) > 0 {
s.AddClientStat(tx, data.Id, &client) s.AddClientStat(tx, data.Id, &client)
if client.Enable { if client.Enable {
cipher := ""
if oldInbound.Protocol == "shadowsocks" {
cipher = oldSettings["method"].(string)
}
err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{ err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{
"email": client.Email, "email": client.Email,
"id": client.ID, "id": client.ID,
"flow": client.Flow, "flow": client.Flow,
"password": client.Password, "password": client.Password,
"cipher": cipher,
}) })
if err1 == nil { if err1 == nil {
logger.Debug("Client added by api:", client.Email) logger.Debug("Client added by api:", client.Email)
} else { } else {
logger.Debug("Error in adding client by api:", err1)
needRestart = true needRestart = true
} }
} }
@@ -538,18 +536,15 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool,
return false, err return false, err
} }
needRestart := false needRestart := false
s.xrayApi.Init(p.GetAPIPort())
if len(email) > 0 { if len(email) > 0 {
s.xrayApi.Init(p.GetAPIPort()) err = s.xrayApi.RemoveUser(oldInbound.Tag, email)
err1 := s.xrayApi.RemoveUser(oldInbound.Tag, email) if err == nil {
if err1 == nil {
logger.Debug("Client deleted by api:", email) logger.Debug("Client deleted by api:", email)
needRestart = false needRestart = false
} else {
logger.Debug("Unable to del client by api:", err1)
needRestart = true
} }
s.xrayApi.Close()
} }
s.xrayApi.Close()
return needRestart, db.Save(oldInbound).Error return needRestart, db.Save(oldInbound).Error
} }
@@ -655,35 +650,26 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
} }
} }
needRestart := false needRestart := false
s.xrayApi.Init(p.GetAPIPort())
if len(oldEmail) > 0 { if len(oldEmail) > 0 {
s.xrayApi.Init(p.GetAPIPort()) s.xrayApi.RemoveUser(oldInbound.Tag, oldEmail)
if s.xrayApi.RemoveUser(oldInbound.Tag, oldEmail) == nil {
logger.Debug("Old client deleted by api:", clients[0].Email)
}
if clients[0].Enable { if clients[0].Enable {
cipher := ""
if oldInbound.Protocol == "shadowsocks" {
cipher = oldSettings["method"].(string)
}
err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{ err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{
"email": clients[0].Email, "email": clients[0].Email,
"id": clients[0].ID, "id": clients[0].ID,
"flow": clients[0].Flow, "flow": clients[0].Flow,
"password": clients[0].Password, "password": clients[0].Password,
"cipher": cipher,
}) })
if err1 == nil { if err1 == nil {
logger.Debug("Client edited by api:", clients[0].Email) logger.Debug("Client edited by api:", clients[0].Email)
} else { needRestart = false
logger.Debug("Error in adding client by api:", err1)
needRestart = true
} }
} else {
logger.Debug("Client disabled by api:", clients[0].Email)
needRestart = false
} }
s.xrayApi.Close()
} else {
logger.Debug("Client old email not found")
needRestart = true
} }
s.xrayApi.Close()
return needRestart, tx.Save(oldInbound).Error return needRestart, tx.Save(oldInbound).Error
} }
@@ -737,11 +723,6 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e
return err return err
} }
// Avoid empty slice error
if len(dbClientTraffics) == 0 {
return nil
}
dbClientTraffics, err = s.adjustTraffics(tx, dbClientTraffics) dbClientTraffics, err = s.adjustTraffics(tx, dbClientTraffics)
if err != nil { if err != nil {
return err return err
@@ -833,11 +814,10 @@ func (s *InboundService) DisableInvalidInbounds() (bool, int64, error) {
} }
s.xrayApi.Init(p.GetAPIPort()) s.xrayApi.Init(p.GetAPIPort())
for _, tag := range tags { for _, tag := range tags {
err1 := s.xrayApi.DelInbound(tag) err = s.xrayApi.DelInbound(tag)
if err == nil { if err == nil {
logger.Debug("Inbound disabled by api:", tag) logger.Debug("Inbound disabled by api:", tag)
} else { } else {
logger.Debug("Error in disabling inbound by api:", err1)
needRestart = true needRestart = true
} }
} }
@@ -873,11 +853,10 @@ func (s *InboundService) DisableInvalidClients() (bool, int64, error) {
} }
s.xrayApi.Init(p.GetAPIPort()) s.xrayApi.Init(p.GetAPIPort())
for _, result := range results { for _, result := range results {
err1 := s.xrayApi.RemoveUser(result.Tag, result.Email) err = s.xrayApi.RemoveUser(result.Tag, result.Email)
if err1 == nil { if err == nil {
logger.Debug("Client disabled by api:", result.Email) logger.Debug("Client disabled by api:", result.Email)
} else { } else {
logger.Debug("Error in disabling client by api:", err1)
needRestart = true needRestart = true
} }
} }
@@ -1275,26 +1254,15 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (bool, e
for _, client := range clients { for _, client := range clients {
if client.Email == clientEmail { if client.Email == clientEmail {
s.xrayApi.Init(p.GetAPIPort()) s.xrayApi.Init(p.GetAPIPort())
cipher := ""
if string(inbound.Protocol) == "shadowsocks" {
var oldSettings map[string]interface{}
err = json.Unmarshal([]byte(inbound.Settings), &oldSettings)
if err != nil {
return false, err
}
cipher = oldSettings["method"].(string)
}
err1 := s.xrayApi.AddUser(string(inbound.Protocol), inbound.Tag, map[string]interface{}{ err1 := s.xrayApi.AddUser(string(inbound.Protocol), inbound.Tag, map[string]interface{}{
"email": client.Email, "email": client.Email,
"id": client.ID, "id": client.ID,
"flow": client.Flow, "flow": client.Flow,
"password": client.Password, "password": client.Password,
"cipher": cipher,
}) })
if err1 == nil { if err1 == nil {
logger.Debug("Client enabled due to reset traffic:", clientEmail) logger.Debug("Client enabled due to reset traffic:", clientEmail)
} else { } else {
logger.Debug("Error in enabling client by api:", err1)
needRestart = true needRestart = true
} }
s.xrayApi.Close() s.xrayApi.Close()

View File

@@ -12,7 +12,6 @@ import (
"os" "os"
"os/exec" "os/exec"
"runtime" "runtime"
"strconv"
"strings" "strings"
"time" "time"
@@ -77,11 +76,6 @@ type Status struct {
IPv4 string `json:"ipv4"` IPv4 string `json:"ipv4"`
IPv6 string `json:"ipv6"` IPv6 string `json:"ipv6"`
} `json:"publicIP"` } `json:"publicIP"`
AppStats struct {
Threads uint32 `json:"threads"`
Mem uint64 `json:"mem"`
Uptime uint64 `json:"uptime"`
} `json:"appStats"`
} }
type Release struct { type Release struct {
@@ -225,22 +219,12 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status {
status.Xray.ErrorMsg = s.xrayService.GetXrayResult() status.Xray.ErrorMsg = s.xrayService.GetXrayResult()
} }
status.Xray.Version = s.xrayService.GetXrayVersion() status.Xray.Version = s.xrayService.GetXrayVersion()
var rtm runtime.MemStats
runtime.ReadMemStats(&rtm)
status.AppStats.Mem = rtm.Sys
status.AppStats.Threads = uint32(runtime.NumGoroutine())
if p.IsRunning() {
status.AppStats.Uptime = p.GetUptime()
} else {
status.AppStats.Uptime = 0
}
return status return status
} }
func (s *ServerService) GetXrayVersions() ([]string, error) { func (s *ServerService) GetXrayVersions() ([]string, error) {
url := "https://api.github.com/repos/XTLS/Xray-core/releases" url := "https://api.github.com/repos/MHSanaei/Xray-core/releases"
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -259,11 +243,9 @@ func (s *ServerService) GetXrayVersions() ([]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var versions []string versions := make([]string, 0, len(releases))
for _, release := range releases { for _, release := range releases {
if release.TagName >= "v1.7.5" { versions = append(versions, release.TagName)
versions = append(versions, release.TagName)
}
} }
return versions, nil return versions, nil
} }
@@ -307,7 +289,7 @@ func (s *ServerService) downloadXRay(version string) (string, error) {
} }
fileName := fmt.Sprintf("Xray-%s-%s.zip", osName, arch) fileName := fmt.Sprintf("Xray-%s-%s.zip", osName, arch)
url := fmt.Sprintf("https://github.com/XTLS/Xray-core/releases/download/%s/%s", version, fileName) url := fmt.Sprintf("https://github.com/MHSanaei/Xray-core/releases/download/%s/%s", version, fileName)
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return "", err return "", err
@@ -376,72 +358,48 @@ func (s *ServerService) UpdateXray(version string) error {
return err return err
} }
downloadFile := func(fileName string, url string) error { err = copyZipFile("xray", xray.GetBinaryPath())
os.Remove(fileName) if err != nil {
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_TRUNC, fs.ModePerm)
if err != nil {
return err
}
defer file.Close()
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("download file failed: %s", resp.Status)
}
_, err = io.Copy(file, resp.Body)
return err return err
} }
err = copyZipFile("geosite.dat", xray.GetGeositePath())
copyFiles := map[string]string{ if err != nil {
"xray": xray.GetBinaryPath(), return err
"geosite.dat": xray.GetGeositePath(),
"geoip.dat": xray.GetGeoipPath(),
} }
err = copyZipFile("geoip.dat", xray.GetGeoipPath())
downloadFiles := map[string]string{ if err != nil {
xray.GetIranPath(): "https://github.com/MasterKia/iran-hosted-domains/releases/latest/download/iran.dat", return err
} }
err = copyZipFile("iran.dat", xray.GetIranPath())
for fileName, filePath := range copyFiles { if err != nil {
err := copyZipFile(fileName, filePath) return err
if err != nil {
return err
}
}
for fileName, filePath := range downloadFiles {
err := downloadFile(fileName, filePath)
if err != nil {
return err
}
} }
return nil return nil
} }
func (s *ServerService) GetLogs(count string, level string, syslog string) []string { func (s *ServerService) GetLogs(count string, logLevel string) ([]string, error) {
c, _ := strconv.Atoi(count) var cmdArgs []string
var lines []string if runtime.GOOS == "linux" {
cmdArgs = []string{"journalctl", "-u", "x-ui", "--no-pager", "-n", count}
if syslog == "true" { if logLevel != "" {
cmdArgs := []string{"journalctl", "-u", "x-ui", "--no-pager", "-n", count, "-p", level} cmdArgs = append(cmdArgs, "-p", logLevel)
// Run the command
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return []string{"Failed to run journalctl command!"}
} }
lines = strings.Split(out.String(), "\n")
} else { } else {
lines = logger.GetLogs(c, level) return []string{"Unsupported operating system"}, nil
} }
return lines cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return nil, err
}
lines := strings.Split(out.String(), "\n")
return lines, nil
} }
func (s *ServerService) GetConfigJson() (interface{}, error) { func (s *ServerService) GetConfigJson() (interface{}, error) {
@@ -459,7 +417,6 @@ func (s *ServerService) GetConfigJson() (interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return jsonData, nil return jsonData, nil
} }

View File

@@ -827,7 +827,7 @@ func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ...
t.SendMsgToTgbot(chatId, output, inlineKeyboard) t.SendMsgToTgbot(chatId, output, inlineKeyboard)
requestUser := telego.KeyboardButtonRequestUser{ requestUser := telego.KeyboardButtonRequestUser{
RequestID: int32(traffic.Id), RequestID: int32(traffic.Id),
UserIsBot: new(bool), UserIsBot: false,
} }
keyboard := tu.Keyboard( keyboard := tu.Keyboard(
tu.KeyboardRow( tu.KeyboardRow(

View File

@@ -116,7 +116,7 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
} }
} }
for key := range c { for key := range c {
if key != "email" && key != "id" && key != "password" && key != "flow" && key != "method" { if key != "email" && key != "id" && key != "password" && key != "flow" {
delete(c, key) delete(c, key)
} }
if c["flow"] == "xtls-rprx-vision-udp443" { if c["flow"] == "xtls-rprx-vision-udp443" {

View File

@@ -250,8 +250,8 @@ func (s *Server) startTask() {
// Check the inbound traffic every 30 seconds that the traffic exceeds and expires // Check the inbound traffic every 30 seconds that the traffic exceeds and expires
s.cron.AddJob("@every 30s", job.NewCheckInboundJob()) s.cron.AddJob("@every 30s", job.NewCheckInboundJob())
// check client ips from log file every 10 sec // check client ips from log file every 20 sec
s.cron.AddJob("@every 10s", job.NewCheckClientIpJob()) s.cron.AddJob("@every 20s", job.NewCheckClientIpJob())
// check client ips from log file every 3 day // check client ips from log file every 3 day
s.cron.AddJob("@every 3d", job.NewClearLogsJob()) s.cron.AddJob("@every 3d", job.NewClearLogsJob())

136
x-ui.sh
View File

@@ -54,8 +54,6 @@ elif [[ "${release}" == "debian" ]]; then
if [[ ${os_version} -lt 10 ]]; then if [[ ${os_version} -lt 10 ]]; then
echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1 echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
fi fi
elif [[ "${release}" == "arch" ]]; then
echo "OS is ArchLinux"
fi fi
@@ -510,7 +508,7 @@ update_geo() {
rm -f geoip.dat geosite.dat iran.dat rm -f geoip.dat geosite.dat iran.dat
wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
wget -N https://github.com/MasterKia/iran-hosted-domains/releases/latest/download/iran.dat wget -N https://github.com/bootmortis/iran-hosted-domains/releases/latest/download/iran.dat
systemctl start x-ui systemctl start x-ui
echo -e "${green}Geosite.dat + Geoip.dat + Iran.dat have been updated successfully in bin folder '${binfolder}'!${plain}" echo -e "${green}Geosite.dat + Geoip.dat + Iran.dat have been updated successfully in bin folder '${binfolder}'!${plain}"
before_show_menu before_show_menu
@@ -648,83 +646,6 @@ ssl_cert_issue() {
fi fi
} }
ssl_cert_issue_CF() {
echo -E ""
LOGD "******Instructions for use******"
LOGI "This Acme script requires the following data:"
LOGI "1.Cloudflare Registered e-mail"
LOGI "2.Cloudflare Global API Key"
LOGI "3.The domain name that has been resolved dns to the current server by Cloudflare"
LOGI "4.The script applies for a certificate. The default installation path is /root/cert "
confirm "Confirmed?[y/n]" "y"
if [ $? -eq 0 ]; then
# check for acme.sh first
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
echo "acme.sh could not be found. we will install it"
install_acme
if [ $? -ne 0 ]; then
LOGE "install acme failed, please check logs"
exit 1
fi
fi
CF_Domain=""
CF_GlobalKey=""
CF_AccountEmail=""
certPath=/root/cert
if [ ! -d "$certPath" ]; then
mkdir $certPath
else
rm -rf $certPath
mkdir $certPath
fi
LOGD "Please set a domain name:"
read -p "Input your domain here:" CF_Domain
LOGD "Your domain name is set to:${CF_Domain}"
LOGD "Please set the API key:"
read -p "Input your key here:" CF_GlobalKey
LOGD "Your API key is:${CF_GlobalKey}"
LOGD "Please set up registered email:"
read -p "Input your email here:" CF_AccountEmail
LOGD "Your registered email address is:${CF_AccountEmail}"
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
if [ $? -ne 0 ]; then
LOGE "Default CA, Lets'Encrypt fail, script exiting..."
exit 1
fi
export CF_Key="${CF_GlobalKey}"
export CF_Email=${CF_AccountEmail}
~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log
if [ $? -ne 0 ]; then
LOGE "Certificate issuance failed, script exiting..."
exit 1
else
LOGI "Certificate issued Successfully, Installing..."
fi
~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} --ca-file /root/cert/ca.cer \
--cert-file /root/cert/${CF_Domain}.cer --key-file /root/cert/${CF_Domain}.key \
--fullchain-file /root/cert/fullchain.cer
if [ $? -ne 0 ]; then
LOGE "Certificate installation failed, script exiting..."
exit 1
else
LOGI "Certificate installed Successfully,Turning on automatic updates..."
fi
~/.acme.sh/acme.sh --upgrade --auto-upgrade
if [ $? -ne 0 ]; then
LOGE "Auto update setup Failed, script exiting..."
ls -lah cert
chmod 755 $certPath
exit 1
else
LOGI "The certificate is installed and auto-renewal is turned on, Specific information is as follows"
ls -lah cert
chmod 755 $certPath
fi
else
show_menu
fi
}
warp_cloudflare() { warp_cloudflare() {
echo -e "${green}\t1.${plain} Install WARP socks5 proxy" echo -e "${green}\t1.${plain} Install WARP socks5 proxy"
echo -e "${green}\t2.${plain} Account Type (free, plus, team)" echo -e "${green}\t2.${plain} Account Type (free, plus, team)"
@@ -792,8 +713,8 @@ enabled=true
filter=3x-ipl filter=3x-ipl
action=3x-ipl action=3x-ipl
logpath=${iplimit_log_path} logpath=${iplimit_log_path}
maxretry=4 maxretry=3
findtime=60 findtime=100
bantime=${bantime}m bantime=${bantime}m
EOF EOF
@@ -851,8 +772,7 @@ iplimit_main() {
echo -e "${green}\t2.${plain} Change Ban Duration" echo -e "${green}\t2.${plain} Change Ban Duration"
echo -e "${green}\t3.${plain} Unban Everyone" echo -e "${green}\t3.${plain} Unban Everyone"
echo -e "${green}\t4.${plain} Check Logs" echo -e "${green}\t4.${plain} Check Logs"
echo -e "${green}\t5.${plain} fail2ban status" echo -e "${green}\t5.${plain} Uninstall IP Limit"
echo -e "${green}\t6.${plain} Uninstall IP Limit"
echo -e "${green}\t0.${plain} Back to Main Menu" echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " choice read -p "Choose an option: " choice
case "$choice" in case "$choice" in
@@ -868,7 +788,7 @@ iplimit_main() {
2) 2)
read -rp "Please enter new Ban Duration in Minutes [default 5]: " NUM read -rp "Please enter new Ban Duration in Minutes [default 5]: " NUM
if [[ $NUM =~ ^[0-9]+$ ]]; then if [[ $NUM =~ ^[0-9]+$ ]]; then
create_iplimit_jails ${NUM} create_iplimit_jail ${NUM}
systemctl restart fail2ban systemctl restart fail2ban
else else
echo -e "${red}${NUM} is not a number! Please, try again.${plain}" echo -e "${red}${NUM} is not a number! Please, try again.${plain}"
@@ -896,10 +816,6 @@ iplimit_main() {
iplimit_main iplimit_main
fi ;; fi ;;
5) 5)
service fail2ban status
;;
6)
remove_iplimit ;; remove_iplimit ;;
*) echo "Invalid choice" ;; *) echo "Invalid choice" ;;
esac esac
@@ -970,19 +886,23 @@ remove_iplimit(){
echo -e "${green}IP Limit removed successfully!${plain}\n" echo -e "${green}IP Limit removed successfully!${plain}\n"
before_show_menu ;; before_show_menu ;;
2) 2)
rm -rf /etc/fail2ban rm -f /etc/fail2ban/filter.d/3x-ipl.conf
rm -f /etc/fail2ban/action.d/3x-ipl.conf
rm -f /etc/fail2ban/jail.d/3x-ipl.conf
systemctl stop fail2ban systemctl stop fail2ban
systemctl disable fail2ban
case "${release}" in case "${release}" in
ubuntu|debian) ubuntu|debian)
apt-get purge fail2ban -y;; apt remove fail2ban -y ;;
centos) centos)
yum remove fail2ban -y;; yum -y remove fail2ban ;;
fedora) fedora)
dnf remove fail2ban -y;; dnf -y remove fail2ban ;;
*) *)
echo -e "${red}Unsupported operating system. Please uninstall Fail2ban manually.${plain}\n" echo -e "${red}Unsupported operating system. Please uninstall Fail2ban manually.${plain}\n"
exit 1 ;; exit 1 ;;
esac esac
rm -rf /etc/fail2ban
echo -e "${green}Fail2ban and IP Limit removed successfully!${plain}\n" echo -e "${green}Fail2ban and IP Limit removed successfully!${plain}\n"
before_show_menu ;; before_show_menu ;;
0) 0)
@@ -1035,17 +955,16 @@ show_menu() {
${green}14.${plain} Disable x-ui On System Startup ${green}14.${plain} Disable x-ui On System Startup
———————————————— ————————————————
${green}15.${plain} SSL Certificate Management ${green}15.${plain} SSL Certificate Management
${green}16.${plain} Cloudflare SSL Certificate ${green}16.${plain} IP Limit Management
${green}17.${plain} IP Limit Management ${green}17.${plain} WARP Management
${green}18.${plain} WARP Management
———————————————— ————————————————
${green}19.${plain} Enable BBR ${green}18.${plain} Enable BBR
${green}20.${plain} Update Geo Files ${green}19.${plain} Update Geo Files
${green}21.${plain} Active Firewall and open ports ${green}20.${plain} Active Firewall and open ports
${green}22.${plain} Speedtest by Ookla ${green}21.${plain} Speedtest by Ookla
" "
show_status show_status
echo && read -p "Please enter your selection [0-22]: " num echo && read -p "Please enter your selection [0-21]: " num
case "${num}" in case "${num}" in
0) 0)
@@ -1097,28 +1016,25 @@ show_menu() {
ssl_cert_issue_main ssl_cert_issue_main
;; ;;
16) 16)
ssl_cert_issue_CF
;;
17)
iplimit_main iplimit_main
;; ;;
18) 17)
warp_cloudflare warp_cloudflare
;; ;;
19) 18)
enable_bbr enable_bbr
;; ;;
20) 19)
update_geo update_geo
;; ;;
21) 20)
open_ports open_ports
;; ;;
22) 21)
run_speedtest run_speedtest
;; ;;
*) *)
LOGE "Please enter the correct number [0-22]" LOGE "Please enter the correct number [0-21]"
;; ;;
esac esac
} }

View File

@@ -15,7 +15,6 @@ import (
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/infra/conf" "github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/proxy/shadowsocks" "github.com/xtls/xray-core/proxy/shadowsocks"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/proxy/trojan" "github.com/xtls/xray-core/proxy/trojan"
"github.com/xtls/xray-core/proxy/vless" "github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vmess" "github.com/xtls/xray-core/proxy/vmess"
@@ -63,12 +62,10 @@ func (x *XrayAPI) AddInbound(inbound []byte) error {
err := json.Unmarshal(inbound, conf) err := json.Unmarshal(inbound, conf)
if err != nil { if err != nil {
logger.Debug("Failed to unmarshal inbound:", err) logger.Debug("Failed to unmarshal inbound:", err)
return err
} }
config, err := conf.Build() config, err := conf.Build()
if err != nil { if err != nil {
logger.Debug("Failed to build inbound Detur:", err) logger.Debug("Failed to build inbound Detur:", err)
return err
} }
inboundConfig := command.AddInboundRequest{Inbound: config} inboundConfig := command.AddInboundRequest{Inbound: config}
@@ -102,31 +99,9 @@ func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]in
Password: user["password"].(string), Password: user["password"].(string),
}) })
case "shadowsocks": case "shadowsocks":
var ssCipherType shadowsocks.CipherType account = serial.ToTypedMessage(&shadowsocks.Account{
switch user["cipher"].(string) { Password: user["password"].(string),
case "aes-128-gcm": })
ssCipherType = shadowsocks.CipherType_AES_128_GCM
case "aes-256-gcm":
ssCipherType = shadowsocks.CipherType_AES_256_GCM
case "chacha20-poly1305":
ssCipherType = shadowsocks.CipherType_CHACHA20_POLY1305
case "xchacha20-poly1305":
ssCipherType = shadowsocks.CipherType_XCHACHA20_POLY1305
default:
ssCipherType = shadowsocks.CipherType_NONE
}
if ssCipherType != shadowsocks.CipherType_NONE {
account = serial.ToTypedMessage(&shadowsocks.Account{
Password: user["password"].(string),
CipherType: ssCipherType,
})
} else {
account = serial.ToTypedMessage(&shadowsocks_2022.User{
Key: user["password"].(string),
Email: user["email"].(string),
})
}
default: default:
return nil return nil
} }

View File

@@ -13,8 +13,6 @@ import (
"strings" "strings"
"sync" "sync"
"syscall" "syscall"
"time"
"x-ui/config" "x-ui/config"
"x-ui/logger" "x-ui/logger"
"x-ui/util/common" "x-ui/util/common"
@@ -46,6 +44,10 @@ func GetIranPath() string {
return config.GetBinFolderPath() + "/iran.dat" return config.GetBinFolderPath() + "/iran.dat"
} }
func GetBlockedIPsPath() string {
return config.GetBinFolderPath() + "/BlockedIps"
}
func GetIPLimitLogPath() string { func GetIPLimitLogPath() string {
return config.GetLogFolder() + "/3xipl.log" return config.GetLogFolder() + "/3xipl.log"
} }
@@ -86,6 +88,7 @@ func stopProcess(p *Process) {
p.Stop() p.Stop()
} }
type Process struct { type Process struct {
*process *process
} }
@@ -102,18 +105,16 @@ type process struct {
version string version string
apiPort int apiPort int
config *Config config *Config
lines *queue.Queue lines *queue.Queue
exitErr error exitErr error
startTime time.Time
} }
func newProcess(config *Config) *process { func newProcess(config *Config) *process {
return &process{ return &process{
version: "Unknown", version: "Unknown",
config: config, config: config,
lines: queue.New(100), lines: queue.New(100),
startTime: time.Now(),
} }
} }
@@ -157,10 +158,6 @@ func (p *Process) GetConfig() *Config {
return p.config return p.config
} }
func (p *Process) GetUptime() uint64 {
return uint64(time.Since(p.startTime).Seconds())
}
func (p *process) refreshAPIPort() { func (p *process) refreshAPIPort() {
for _, inbound := range p.config.InboundConfigs { for _, inbound := range p.config.InboundConfigs {
if inbound.Tag == "api" { if inbound.Tag == "api" {
@@ -206,7 +203,7 @@ func (p *process) Start() (err error) {
return common.NewErrorf("Failed to write configuration file: %v", err) return common.NewErrorf("Failed to write configuration file: %v", err)
} }
cmd := exec.Command(GetBinaryPath(), "-c", configPath) cmd := exec.Command(GetBinaryPath(), "-c", configPath, "-restrictedIPsPath", GetBlockedIPsPath())
p.cmd = cmd p.cmd = cmd
stdReader, err := cmd.StdoutPipe() stdReader, err := cmd.StdoutPipe()