mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-19 07:15:48 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47efac270d | ||
|
|
368eb89cd9 | ||
|
|
83e360ea1b | ||
|
|
6cdeb7ebeb | ||
|
|
035a1a7b5e | ||
|
|
857f0cb64c | ||
|
|
849a1249ac | ||
|
|
d608961af8 | ||
|
|
343e7a9f15 | ||
|
|
6ad558bd36 | ||
|
|
d6bf64f760 | ||
|
|
f8d20c8303 | ||
|
|
08403bc8f9 | ||
|
|
cdb90da138 | ||
|
|
c3d498f9ee | ||
|
|
0621eb0670 | ||
|
|
577c534e4c | ||
|
|
17dae4a563 | ||
|
|
9f1f841666 | ||
|
|
6b66c250b5 | ||
|
|
0829116fc1 | ||
|
|
aae0011a4f | ||
|
|
f4c565b208 | ||
|
|
2520994b13 | ||
|
|
d3fd56fc97 | ||
|
|
d4df614a9f | ||
|
|
640eb538a4 | ||
|
|
08153d45d1 | ||
|
|
843bb5f3ce | ||
|
|
7995310aa7 | ||
|
|
c277fd29fd | ||
|
|
6249528a58 | ||
|
|
83c26ad81d | ||
|
|
9b5379c0e7 | ||
|
|
8041950c29 | ||
|
|
541170c3c2 | ||
|
|
47ec105d1f | ||
|
|
525327c4ac | ||
|
|
0267a1b32a | ||
|
|
83df4ae7cf | ||
|
|
24465aeb43 | ||
|
|
ee2bbffc8f | ||
|
|
294a3f46a0 | ||
|
|
44a1104bff | ||
|
|
fbc4ba1ba0 | ||
|
|
b829ebca2b | ||
|
|
288c0b982a | ||
|
|
8919099594 | ||
|
|
3ee7761ab0 | ||
|
|
346a82b203 | ||
|
|
45e2d66f4b | ||
|
|
36ce3e0130 | ||
|
|
a04f2306bc | ||
|
|
fdc3b15efe | ||
|
|
2fb5168918 | ||
|
|
1fcf3d68f1 | ||
|
|
de654fdbc4 | ||
|
|
e32c723d68 | ||
|
|
41089df567 | ||
|
|
a703f70302 | ||
|
|
3c922d8673 | ||
|
|
78c3912002 | ||
|
|
0b8f5f7f67 | ||
|
|
ca3d45ddb4 | ||
|
|
fff74d7ea7 | ||
|
|
b3393e402b | ||
|
|
30d7376463 | ||
|
|
07f507dc1f | ||
|
|
49aafa5657 |
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -50,6 +50,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64,linux/arm64/v8, linux/arm/v7
|
platforms: linux/amd64,linux/arm64/v8, linux/arm/v7, linux/386
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|||||||
39
.github/workflows/release.yml
vendored
39
.github/workflows/release.yml
vendored
@@ -10,7 +10,11 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
platform: [amd64, arm64, arm]
|
platform:
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
|
- armv7
|
||||||
|
- 386
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -19,15 +23,17 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.0.0
|
uses: actions/setup-go@v5.0.0
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
|
|
||||||
- name: Install dependencies for arm64 and arm
|
- name: Install dependencies
|
||||||
if: matrix.platform == 'arm64' || matrix.platform == 'arm'
|
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt install gcc-aarch64-linux-gnu
|
if [ "${{ matrix.platform }}" == "arm64" ]; then
|
||||||
if [ "${{ matrix.platform }}" == "arm" ]; then
|
sudo apt install gcc-aarch64-linux-gnu
|
||||||
|
elif [ "${{ matrix.platform }}" == "armv7" ]; then
|
||||||
sudo apt install gcc-arm-linux-gnueabihf
|
sudo apt install gcc-arm-linux-gnueabihf
|
||||||
|
elif [ "${{ matrix.platform }}" == "386" ]; then
|
||||||
|
sudo apt install gcc-i686-linux-gnu
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Build x-ui
|
- name: Build x-ui
|
||||||
@@ -36,9 +42,15 @@ jobs:
|
|||||||
export GOOS=linux
|
export GOOS=linux
|
||||||
export GOARCH=${{ matrix.platform }}
|
export GOARCH=${{ matrix.platform }}
|
||||||
if [ "${{ matrix.platform }}" == "arm64" ]; then
|
if [ "${{ matrix.platform }}" == "arm64" ]; then
|
||||||
|
export GOARCH=arm64
|
||||||
export CC=aarch64-linux-gnu-gcc
|
export CC=aarch64-linux-gnu-gcc
|
||||||
elif [ "${{ matrix.platform }}" == "arm" ]; then
|
elif [ "${{ matrix.platform }}" == "armv7" ]; then
|
||||||
|
export GOARCH=arm
|
||||||
|
export GOARM=7
|
||||||
export CC=arm-linux-gnueabihf-gcc
|
export CC=arm-linux-gnueabihf-gcc
|
||||||
|
elif [ "${{ matrix.platform }}" == "386" ]; then
|
||||||
|
export GOARCH=386
|
||||||
|
export CC=i686-linux-gnu-gcc
|
||||||
fi
|
fi
|
||||||
go build -o xui-release -v main.go
|
go build -o xui-release -v main.go
|
||||||
|
|
||||||
@@ -60,12 +72,16 @@ jobs:
|
|||||||
wget ${Xray_URL}Xray-linux-arm64-v8a.zip
|
wget ${Xray_URL}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
|
||||||
else
|
elif [ "${{ matrix.platform }}" == "armv7" ]; then
|
||||||
wget ${Xray_URL}Xray-linux-arm32-v7a.zip
|
wget ${Xray_URL}Xray-linux-arm32-v7a.zip
|
||||||
unzip Xray-linux-arm32-v7a.zip
|
unzip Xray-linux-arm32-v7a.zip
|
||||||
rm -f Xray-linux-arm32-v7a.zip
|
rm -f Xray-linux-arm32-v7a.zip
|
||||||
|
elif [ "${{ matrix.platform }}" == "386" ]; then
|
||||||
|
wget ${Xray_URL}Xray-linux-32.zip
|
||||||
|
unzip Xray-linux-32.zip
|
||||||
|
rm -f Xray-linux-32.zip
|
||||||
fi
|
fi
|
||||||
rm -f geoip.dat geosite.dat geoip_IR.dat geosite_IR.dat
|
rm -f geoip.dat geosite.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 -O geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
|
wget -O geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
|
||||||
@@ -76,12 +92,11 @@ jobs:
|
|||||||
- name: Package
|
- name: Package
|
||||||
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 files to GH release
|
||||||
uses: svenstaro/upload-release-action@2.7.0
|
uses: MHSanaei/upload-release-action@2.8.0
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
file: x-ui-linux-${{ matrix.platform }}.tar.gz
|
file: x-ui-linux-${{ matrix.platform }}.tar.gz
|
||||||
asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
|
asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
|
||||||
prerelease: true
|
prerelease: true
|
||||||
overwrite: true
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ case $1 in
|
|||||||
ARCH="64"
|
ARCH="64"
|
||||||
FNAME="amd64"
|
FNAME="amd64"
|
||||||
;;
|
;;
|
||||||
|
i386)
|
||||||
|
ARCH="32"
|
||||||
|
FNAME="i386"
|
||||||
|
;;
|
||||||
armv8 | arm64 | aarch64)
|
armv8 | arm64 | aarch64)
|
||||||
ARCH="arm64-v8a"
|
ARCH="arm64-v8a"
|
||||||
FNAME="arm64"
|
FNAME="arm64"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.21-alpine AS builder
|
FROM golang:1.22-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
RUN apk --no-cache --update add build-base gcc wget unzip
|
RUN apk --no-cache --update add build-base gcc wget unzip
|
||||||
|
|||||||
66
README.md
66
README.md
@@ -43,10 +43,10 @@ bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.s
|
|||||||
|
|
||||||
## Install Custom Version
|
## Install Custom Version
|
||||||
|
|
||||||
**Step 1:** To install your desired version, add the version to the end of the installation command. e.g., ver `1.6.4`:
|
**Step 1:** To install your desired version, add the version to the end of the installation command. e.g., ver `1.7.1`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh) 1.6.4
|
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh) 1.7.1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Manual Install & Upgrade
|
## Manual Install & Upgrade
|
||||||
@@ -56,15 +56,32 @@ bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.s
|
|||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
**Step 1:** First download the latest compressed package from https://github.com/alireza0/x-ui/releases, generally choose Architecture `amd64`
|
1. To download the latest version of the compressed package directly to your server, run the following command:
|
||||||
|
|
||||||
**Step 2:** Then upload the compressed package to the server's `/root/` directory and login to the server with user `root`
|
|
||||||
|
|
||||||
> If your server CPU architecture is not `amd64` replace it with the appropriate architecture
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ARCH=$(uname -m)
|
ARCH=$(uname -m)
|
||||||
[[ "${ARCH}" == "s390x" ]] && XUI_ARCH="s390x" || [[ "${ARCH}" == "aarch64" || "${ARCH}" == "arm64" ]] && XUI_ARCH="arm64" || XUI_ARCH="amd64"
|
case "${ARCH}" in
|
||||||
|
x86_64 | x64 | amd64) XUI_ARCH="amd64" ;;
|
||||||
|
i*86 | x86) XUI_ARCH="386" ;;
|
||||||
|
armv8* | armv8 | arm64 | aarch64) XUI_ARCH="arm64" ;;
|
||||||
|
armv7* | armv7) XUI_ARCH="armv7" ;;
|
||||||
|
*) XUI_ARCH="amd64" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
wget https://github.com/alireza0/x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Once the compressed package is downloaded, execute the following commands to install or upgrade x-ui:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
case "${ARCH}" in
|
||||||
|
x86_64 | x64 | amd64) XUI_ARCH="amd64" ;;
|
||||||
|
i*86 | x86) XUI_ARCH="386" ;;
|
||||||
|
armv8* | armv8 | arm64 | aarch64) XUI_ARCH="arm64" ;;
|
||||||
|
armv7* | armv7) XUI_ARCH="armv7" ;;
|
||||||
|
*) XUI_ARCH="amd64" ;;
|
||||||
|
esac
|
||||||
cd /root/
|
cd /root/
|
||||||
rm x-ui/ /usr/local/x-ui/ /usr/bin/x-ui -rf
|
rm x-ui/ /usr/local/x-ui/ /usr/bin/x-ui -rf
|
||||||
tar zxvf x-ui-linux-${XUI_ARCH}.tar.gz
|
tar zxvf x-ui-linux-${XUI_ARCH}.tar.gz
|
||||||
@@ -92,7 +109,20 @@ systemctl restart x-ui
|
|||||||
curl -fsSL https://get.docker.com | sh
|
curl -fsSL https://get.docker.com | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
**Step 2:** Install X-UI
|
**Step 2:** Clone the Project Repository:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/alireza0/x-ui.git
|
||||||
|
cd x-ui
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3:** Start the Service
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
OR
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
mkdir x-ui && cd x-ui
|
mkdir x-ui && cd x-ui
|
||||||
@@ -105,6 +135,24 @@ docker run -itd \
|
|||||||
alireza7/x-ui:latest
|
alireza7/x-ui:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
update to latest version
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd x-ui
|
||||||
|
docker compose down
|
||||||
|
docker compose pull x-ui
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
remove x-ui from docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker stop x-ui
|
||||||
|
docker rm x-ui
|
||||||
|
cd --
|
||||||
|
rm -r x-ui
|
||||||
|
```
|
||||||
|
|
||||||
> Build your own image
|
> Build your own image
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.7.0
|
1.7.2
|
||||||
79
go.mod
79
go.mod
@@ -1,91 +1,92 @@
|
|||||||
module x-ui
|
module x-ui
|
||||||
|
|
||||||
go 1.21.4
|
go 1.22.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-contrib/sessions v0.0.4
|
github.com/Calidity/gin-sessions v1.3.1
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
||||||
github.com/goccy/go-json v0.10.2
|
github.com/goccy/go-json v0.10.2
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.3.0
|
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||||
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.1.1
|
github.com/pelletier/go-toml/v2 v2.1.1
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/shirou/gopsutil/v3 v3.23.12
|
github.com/shirou/gopsutil/v3 v3.24.1
|
||||||
github.com/xtls/xray-core v1.8.7
|
github.com/xtls/xray-core v1.8.7
|
||||||
go.uber.org/atomic v1.11.0
|
go.uber.org/atomic v1.11.0
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.14.0
|
||||||
google.golang.org/grpc v1.60.1
|
google.golang.org/grpc v1.61.1
|
||||||
gorm.io/driver/sqlite v1.5.4
|
gorm.io/driver/sqlite v1.5.5
|
||||||
gorm.io/gorm v1.25.5
|
gorm.io/gorm v1.25.7
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.11.0 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||||
github.com/cloudflare/circl v1.3.7 // indirect
|
github.com/cloudflare/circl v1.3.7 // 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/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.3 // indirect
|
||||||
github.com/gin-contrib/gzip v0.0.6
|
github.com/gin-contrib/gzip v0.0.6
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.3.0 // 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.14.0 // indirect
|
github.com/go-playground/validator/v10 v10.18.0 // 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/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 // indirect
|
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
|
||||||
github.com/gorilla/context v1.1.1 // indirect
|
github.com/gorilla/context v1.1.2 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/gorilla/sessions v1.2.1 // indirect
|
github.com/gorilla/sessions v1.2.2 // indirect
|
||||||
github.com/gorilla/websocket v1.5.1 // indirect
|
github.com/gorilla/websocket v1.5.1 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.17.4 // indirect
|
github.com/klauspost/compress v1.17.6 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
|
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.17 // indirect
|
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.13.2 // indirect
|
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
|
||||||
github.com/pires/go-proxyproto v0.7.0 // indirect
|
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
github.com/power-devops/perfstat v0.0.0-20240219145905-2259734c190a // indirect
|
||||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
github.com/quic-go/quic-go v0.41.0 // indirect
|
||||||
github.com/quic-go/quic-go v0.40.1 // indirect
|
github.com/refraction-networking/utls v1.6.2 // indirect
|
||||||
github.com/refraction-networking/utls v1.6.0 // 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/sagernet/sing v0.3.0 // indirect
|
github.com/sagernet/sing v0.3.0 // indirect
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.6 // indirect
|
github.com/sagernet/sing-shadowsocks v0.2.6 // 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.13 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.7.0 // 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.12 // indirect
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
||||||
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 // indirect
|
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 // indirect
|
||||||
github.com/vishvananda/netns v0.0.4 // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19 // indirect
|
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.uber.org/mock v0.4.0 // indirect
|
go.uber.org/mock v0.4.0 // indirect
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.7.0 // indirect
|
||||||
golang.org/x/crypto v0.17.0 // indirect
|
golang.org/x/crypto v0.19.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
|
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect
|
||||||
golang.org/x/mod v0.14.0 // indirect
|
golang.org/x/mod v0.15.0 // indirect
|
||||||
golang.org/x/net v0.19.0 // indirect
|
golang.org/x/net v0.21.0 // indirect
|
||||||
golang.org/x/sys v0.16.0 // indirect
|
golang.org/x/sys v0.17.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
golang.org/x/tools v0.16.1 // indirect
|
golang.org/x/tools v0.18.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||||
google.golang.org/protobuf v1.32.0 // indirect
|
google.golang.org/protobuf v1.32.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b // indirect
|
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b // indirect
|
||||||
|
|||||||
194
go.sum
194
go.sum
@@ -10,22 +10,25 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
|
|||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/Calidity/gin-sessions v1.3.1 h1:nF3dCBWa7TZ4j26iYLwGRmzZy9YODhWoOS3fmi+snyE=
|
||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/Calidity/gin-sessions v1.3.1/go.mod h1:I0+QE6qkO50TeN/n6If6novvxHk4Isvr23U8EdvPdns=
|
||||||
|
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||||
|
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/antonlindstrom/pgstore v0.0.0-20200229204646-b08ebf1105e0/go.mod h1:2Ti6VUHVxpC0VSmTZzEvpzysnaGAfGBOoMIz5ykPyyw=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
|
|
||||||
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/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
|
||||||
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
|
||||||
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.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.11.0 h1:FwNNv6Vu4z2Onf1++LNzxB/QhitD8wuTdpZzMTGITWo=
|
||||||
|
github.com/bytedance/sonic v1.11.0/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/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.1/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/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||||
@@ -42,43 +45,37 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
|
|||||||
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=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
|
||||||
github.com/gin-contrib/sessions v0.0.4 h1:gq4fNa1Zmp564iHP5G6EBuktilEos8VKhe2sza1KMgo=
|
|
||||||
github.com/gin-contrib/sessions v0.0.4/go.mod h1:pQ3sIyviBBGcxgyR8mkeJuXbeV3h3NYmhJADQTq5+Vo=
|
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
|
||||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
|
||||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
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.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
|
||||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||||
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.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
|
||||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U=
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 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/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
|
||||||
@@ -95,11 +92,9 @@ github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
|||||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
@@ -112,21 +107,21 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
|||||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 h1:dHLYa5D8/Ta0aLR2XcPsrkpAgGeFs6thhMcQK0oQ0n8=
|
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
|
||||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
|
||||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||||
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
||||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
||||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
|
||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
|
||||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
@@ -137,17 +132,16 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
|||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
||||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||||
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.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.6/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.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
@@ -157,42 +151,39 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
|
||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
|
||||||
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=
|
||||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik=
|
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0=
|
||||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
|
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||||
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
|
|
||||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
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/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.3.0 h1:2NPsCsNFCVd7i+Su0xYsBrIhS3bE2XMv5gNTft2O+PQ=
|
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.3.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
||||||
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
|
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
|
||||||
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
|
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
|
||||||
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
|
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||||
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||||
@@ -205,23 +196,19 @@ github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwy
|
|||||||
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
|
github.com/power-devops/perfstat v0.0.0-20240219145905-2259734c190a h1:XCUtNgBnZfUBhdfCX2QK+fslr9vevSsUg3W3peZwlak=
|
||||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20240219145905-2259734c190a/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
|
||||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
|
||||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
github.com/refraction-networking/utls v1.6.2 h1:iTeeGY0o6nMNcGyirxkD5bFIsVctP5InGZ3E0HrzS7k=
|
||||||
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
|
github.com/refraction-networking/utls v1.6.2/go.mod h1:yil9+7qSl+gBwJqztoQseO6Pr3h62pQoY1lXiNR/FPs=
|
||||||
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
|
||||||
github.com/refraction-networking/utls v1.6.0 h1:X5vQMqVx7dY7ehxxqkFER/W6DSjy8TMqSItXm8hRDYQ=
|
|
||||||
github.com/refraction-networking/utls v1.6.0/go.mod h1:kHJ6R9DFFA0WsRgBM35iiDku4O7AqPR6y79iuzW7b10=
|
|
||||||
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=
|
||||||
@@ -237,8 +224,8 @@ github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bc
|
|||||||
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.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
|
github.com/shirou/gopsutil/v3 v3.24.1 h1:R3t6ondCEvmARp3wxODhXMTLC/klMa87h2PHUw5m7QI=
|
||||||
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
|
github.com/shirou/gopsutil/v3 v3.24.1/go.mod h1:UU7a2MSBQa+kW1uuDq8DeEBS8kmrnQwsv2b5O513rwU=
|
||||||
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=
|
||||||
@@ -272,28 +259,26 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
|
|||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
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/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
|
||||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
||||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||||
|
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
|
||||||
|
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
|
||||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
|
||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||||
@@ -307,8 +292,9 @@ github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19 h1:capMfFYRgH9BCLd6A3
|
|||||||
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||||
github.com/xtls/xray-core v1.8.7 h1:lb8O1l3/eAg3YAXA6tLm5M6N7BsX8wxW9sJLjU3dHkA=
|
github.com/xtls/xray-core v1.8.7 h1:lb8O1l3/eAg3YAXA6tLm5M6N7BsX8wxW9sJLjU3dHkA=
|
||||||
github.com/xtls/xray-core v1.8.7/go.mod h1:9rFpflfQbgFeH1VKJw7yUmEy7myOyDCgNXXl0bmmyOo=
|
github.com/xtls/xray-core v1.8.7/go.mod h1:9rFpflfQbgFeH1VKJw7yUmEy7myOyDCgNXXl0bmmyOo=
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
|
||||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
go.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=
|
||||||
@@ -318,24 +304,23 @@ go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1
|
|||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||||
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.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
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-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
|
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE=
|
||||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -344,10 +329,9 @@ golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73r
|
|||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
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.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
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=
|
||||||
@@ -364,9 +348,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -374,17 +356,17 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.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.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
@@ -398,8 +380,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
|
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
@@ -417,14 +399,14 @@ 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-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk=
|
||||||
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.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
|
google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
|
||||||
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
|
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
||||||
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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
@@ -438,7 +420,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|||||||
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=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
@@ -446,18 +427,21 @@ gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0=
|
gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=
|
||||||
gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4=
|
gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE=
|
||||||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
|
||||||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||||
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b h1:yqkg3pTifuKukuWanp8spDsL4irJkHF5WI0J47hU87o=
|
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b h1:yqkg3pTifuKukuWanp8spDsL4irJkHF5WI0J47hU87o=
|
||||||
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||||
|
gvisor.dev/gvisor v0.0.0-20240216214558-53d2b511e78e h1:BAmOamSGzOqvWRcyoAZvud9SuInvUn2qYIK495rjF+4=
|
||||||
|
gvisor.dev/gvisor v0.0.0-20240216214558-53d2b511e78e/go.mod h1:YcCCAniKhCIGGvWxOobcre6euvNQON7nZCtMcVYO9rA=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
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=
|
||||||
|
|||||||
52
install.sh
52
install.sh
@@ -26,8 +26,9 @@ echo "The OS release is: $release"
|
|||||||
arch() {
|
arch() {
|
||||||
case "$(uname -m)" in
|
case "$(uname -m)" in
|
||||||
x86_64 | x64 | amd64) echo 'amd64' ;;
|
x86_64 | x64 | amd64) echo 'amd64' ;;
|
||||||
|
i*86 | x86) echo '386' ;;
|
||||||
armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
|
armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
|
||||||
armv7* | armv7 | arm | arm32 ) echo 'arm' ;;
|
armv7* | armv7 | arm) echo 'armv7' ;;
|
||||||
*) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
|
*) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -40,7 +41,7 @@ if [[ "${release}" == "centos" ]]; then
|
|||||||
if [[ ${os_version} -lt 8 ]]; then
|
if [[ ${os_version} -lt 8 ]]; then
|
||||||
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
|
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
elif [[ "${release}" == "ubuntu" ]]; then
|
elif [[ "${release}" == "ubuntu" ]]; then
|
||||||
if [[ ${os_version} -lt 20 ]]; then
|
if [[ ${os_version} -lt 20 ]]; then
|
||||||
echo -e "${red}please use Ubuntu 20 or higher version! ${plain}\n" && exit 1
|
echo -e "${red}please use Ubuntu 20 or higher version! ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
@@ -58,13 +59,18 @@ 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_dependencies() {
|
||||||
install_base() {
|
case "${release}" in
|
||||||
if [[ "${release}" == "centos" ]] || [[ "${release}" == "fedora" ]] ; then
|
centos)
|
||||||
yum install wget curl tar -y
|
yum -y update && yum install -y -q wget curl tar tzdata
|
||||||
else
|
;;
|
||||||
apt install wget curl tar -y
|
fedora)
|
||||||
fi
|
dnf -y update && dnf install -y -q wget curl tar tzdata
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
apt-get update && apt install -y -q wget curl tar tzdata
|
||||||
|
;;
|
||||||
|
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
|
||||||
@@ -103,6 +109,21 @@ config_after_install() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_x-ui() {
|
install_x-ui() {
|
||||||
|
# checks if the installation backup dir exist. if existed then ask user if they want to restore it else continue installation.
|
||||||
|
if [[ -e /usr/local/x-ui-backup/ ]]; then
|
||||||
|
read -p "Failed installation detected. Do you want to restore previously installed version? [y/n]? ": restore_confirm
|
||||||
|
if [[ "${restore_confirm}" == "y" || "${restore_confirm}" == "Y" ]]; then
|
||||||
|
systemctl stop x-ui
|
||||||
|
mv /usr/local/x-ui-backup/x-ui.db /etc/x-ui/ -f
|
||||||
|
mv /usr/local/x-ui-backup/ /usr/local/x-ui/ -f
|
||||||
|
systemctl start x-ui
|
||||||
|
echo -e "${green}previous installed x-ui restored successfully${plain}, it is up and running now..."
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo -e "Continuing installing x-ui ..."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
cd /usr/local/
|
cd /usr/local/
|
||||||
|
|
||||||
if [ $# == 0 ]; then
|
if [ $# == 0 ]; then
|
||||||
@@ -130,18 +151,27 @@ install_x-ui() {
|
|||||||
|
|
||||||
if [[ -e /usr/local/x-ui/ ]]; then
|
if [[ -e /usr/local/x-ui/ ]]; then
|
||||||
systemctl stop x-ui
|
systemctl stop x-ui
|
||||||
rm /usr/local/x-ui/ -rf
|
mv /usr/local/x-ui/ /usr/local/x-ui-backup/ -f
|
||||||
|
cp /etc/x-ui/x-ui.db /usr/local/x-ui-backup/ -f
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tar zxvf x-ui-linux-$(arch).tar.gz
|
tar zxvf x-ui-linux-$(arch).tar.gz
|
||||||
rm x-ui-linux-$(arch).tar.gz -f
|
rm x-ui-linux-$(arch).tar.gz -f
|
||||||
cd x-ui
|
cd x-ui
|
||||||
|
chmod +x x-ui
|
||||||
|
|
||||||
|
# Check the system's architecture and rename the file accordingly
|
||||||
|
if [[ $(arch) == "armv7" ]]; then
|
||||||
|
mv bin/xray-linux-$(arch) bin/xray-linux-arm
|
||||||
|
chmod +x bin/xray-linux-arm
|
||||||
|
fi
|
||||||
chmod +x x-ui bin/xray-linux-$(arch)
|
chmod +x x-ui bin/xray-linux-$(arch)
|
||||||
cp -f x-ui.service /etc/systemd/system/
|
cp -f x-ui.service /etc/systemd/system/
|
||||||
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/alireza0/x-ui/main/x-ui.sh
|
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/alireza0/x-ui/main/x-ui.sh
|
||||||
chmod +x /usr/local/x-ui/x-ui.sh
|
chmod +x /usr/local/x-ui/x-ui.sh
|
||||||
chmod +x /usr/bin/x-ui
|
chmod +x /usr/bin/x-ui
|
||||||
config_after_install
|
config_after_install
|
||||||
|
rm /usr/local/x-ui-backup/ -rf
|
||||||
#echo -e "If it is a new installation, the default web port is ${green}54321${plain}, The username and password are ${green}admin${plain} by default"
|
#echo -e "If it is a new installation, the default web port is ${green}54321${plain}, The username and password are ${green}admin${plain} by default"
|
||||||
#echo -e "Please make sure that this port is not occupied by other procedures,${yellow} And make sure that port 54321 has been released${plain}"
|
#echo -e "Please make sure that this port is not occupied by other procedures,${yellow} And make sure that port 54321 has been released${plain}"
|
||||||
# echo -e "If you want to modify the 54321 to other ports and enter the x-ui command to modify it, you must also ensure that the port you modify is also released"
|
# echo -e "If you want to modify the 54321 to other ports and enter the x-ui command to modify it, you must also ensure that the port you modify is also released"
|
||||||
@@ -172,5 +202,5 @@ install_x-ui() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
echo -e "${green}Running...${plain}"
|
echo -e "${green}Running...${plain}"
|
||||||
install_base
|
install_dependencies
|
||||||
install_x-ui $1
|
install_x-ui $1
|
||||||
|
|||||||
105
sub/default.json
Normal file
105
sub/default.json
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"dns": {
|
||||||
|
"tag": "dns_out",
|
||||||
|
"queryStrategy": "UseIP",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"address": "8.8.8.8",
|
||||||
|
"skipFallback": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"port": 10808,
|
||||||
|
"protocol": "socks",
|
||||||
|
"settings": {
|
||||||
|
"auth": "noauth",
|
||||||
|
"udp": true,
|
||||||
|
"userLevel": 8
|
||||||
|
},
|
||||||
|
"sniffing": {
|
||||||
|
"destOverride": [
|
||||||
|
"http",
|
||||||
|
"tls",
|
||||||
|
"fakedns"
|
||||||
|
],
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"tag": "socks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"port": 10809,
|
||||||
|
"protocol": "http",
|
||||||
|
"settings": {
|
||||||
|
"userLevel": 8
|
||||||
|
},
|
||||||
|
"tag": "http"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"log": {
|
||||||
|
"loglevel": "warning"
|
||||||
|
},
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"tag": "direct",
|
||||||
|
"protocol": "freedom",
|
||||||
|
"settings": {
|
||||||
|
"domainStrategy": "UseIP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "block",
|
||||||
|
"protocol": "blackhole",
|
||||||
|
"settings": {
|
||||||
|
"response": {
|
||||||
|
"type": "http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policy": {
|
||||||
|
"levels": {
|
||||||
|
"8": {
|
||||||
|
"connIdle": 300,
|
||||||
|
"downlinkOnly": 1,
|
||||||
|
"handshake": 4,
|
||||||
|
"uplinkOnly": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"statsOutboundUplink": true,
|
||||||
|
"statsOutboundDownlink": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"routing": {
|
||||||
|
"domainStrategy": "AsIs",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"network": "tcp,udp",
|
||||||
|
"balancerTag": "all"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"balancers": [
|
||||||
|
{
|
||||||
|
"tag": "all",
|
||||||
|
"selector": [
|
||||||
|
"proxy"
|
||||||
|
],
|
||||||
|
"strategy": {
|
||||||
|
"type": "leastPing"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"observatory": {
|
||||||
|
"probeInterval": "5m",
|
||||||
|
"probeURL": "https://api.github.com/_private/browser/stats",
|
||||||
|
"subjectSelector": [
|
||||||
|
"proxy"
|
||||||
|
],
|
||||||
|
"EnableConcurrency": true
|
||||||
|
},
|
||||||
|
"stats": {}
|
||||||
|
}
|
||||||
44
sub/sub.go
44
sub/sub.go
@@ -47,11 +47,6 @@ func (s *Server) initRouter() (*gin.Engine, error) {
|
|||||||
|
|
||||||
engine := gin.Default()
|
engine := gin.Default()
|
||||||
|
|
||||||
subPath, err := s.settingService.GetSubPath()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
subDomain, err := s.settingService.GetSubDomain()
|
subDomain, err := s.settingService.GetSubDomain()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -61,9 +56,44 @@ func (s *Server) initRouter() (*gin.Engine, error) {
|
|||||||
engine.Use(middleware.DomainValidatorMiddleware(subDomain))
|
engine.Use(middleware.DomainValidatorMiddleware(subDomain))
|
||||||
}
|
}
|
||||||
|
|
||||||
g := engine.Group(subPath)
|
LinksPath, err := s.settingService.GetSubPath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
s.sub = NewSUBController(g)
|
JsonPath, err := s.settingService.GetSubJsonPath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
Encrypt, err := s.settingService.GetSubEncrypt()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowInfo, err := s.settingService.GetSubShowInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
RemarkModel, err := s.settingService.GetRemarkModel()
|
||||||
|
if err != nil {
|
||||||
|
RemarkModel = "-ieo"
|
||||||
|
}
|
||||||
|
|
||||||
|
SubUpdates, err := s.settingService.GetSubUpdates()
|
||||||
|
if err != nil {
|
||||||
|
SubUpdates = "10"
|
||||||
|
}
|
||||||
|
|
||||||
|
SubJsonFragment, err := s.settingService.GetSubJsonFragment()
|
||||||
|
if err != nil {
|
||||||
|
SubJsonFragment = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
g := engine.Group("/")
|
||||||
|
|
||||||
|
s.sub = NewSUBController(g, LinksPath, JsonPath, Encrypt, ShowInfo, RemarkModel, SubUpdates, SubJsonFragment)
|
||||||
|
|
||||||
return engine, nil
|
return engine, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,34 +3,57 @@ package sub
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"strings"
|
"strings"
|
||||||
"x-ui/web/service"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SUBController struct {
|
type SUBController struct {
|
||||||
subService SubService
|
subPath string
|
||||||
settingService service.SettingService
|
subJsonPath string
|
||||||
|
subEncrypt bool
|
||||||
|
updateInterval string
|
||||||
|
|
||||||
|
subService *SubService
|
||||||
|
subJsonService *SubJsonService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSUBController(g *gin.RouterGroup) *SUBController {
|
func NewSUBController(
|
||||||
a := &SUBController{}
|
g *gin.RouterGroup,
|
||||||
|
subPath string,
|
||||||
|
jsonPath string,
|
||||||
|
encrypt bool,
|
||||||
|
showInfo bool,
|
||||||
|
rModel string,
|
||||||
|
update string,
|
||||||
|
jsonFragment string) *SUBController {
|
||||||
|
|
||||||
|
a := &SUBController{
|
||||||
|
subPath: subPath,
|
||||||
|
subJsonPath: jsonPath,
|
||||||
|
subEncrypt: encrypt,
|
||||||
|
updateInterval: update,
|
||||||
|
|
||||||
|
subService: NewSubService(showInfo, rModel),
|
||||||
|
subJsonService: NewSubJsonService(jsonFragment),
|
||||||
|
}
|
||||||
a.initRouter(g)
|
a.initRouter(g)
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SUBController) initRouter(g *gin.RouterGroup) {
|
func (a *SUBController) initRouter(g *gin.RouterGroup) {
|
||||||
g = g.Group("/")
|
gLink := g.Group(a.subPath)
|
||||||
|
gJson := g.Group(a.subJsonPath)
|
||||||
|
|
||||||
g.GET("/:subid", a.subs)
|
gLink.GET(":subid", a.subs)
|
||||||
|
|
||||||
|
gJson.GET(":subid", a.subJsons)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SUBController) subs(c *gin.Context) {
|
func (a *SUBController) subs(c *gin.Context) {
|
||||||
subEncrypt, _ := a.settingService.GetSubEncrypt()
|
println(c.Request.Header["User-Agent"][0])
|
||||||
subShowInfo, _ := a.settingService.GetSubShowInfo()
|
|
||||||
subId := c.Param("subid")
|
subId := c.Param("subid")
|
||||||
host := strings.Split(c.Request.Host, ":")[0]
|
host := strings.Split(c.Request.Host, ":")[0]
|
||||||
subs, headers, err := a.subService.GetSubs(subId, host, subShowInfo)
|
subs, header, err := a.subService.GetSubs(subId, host)
|
||||||
if err != nil || len(subs) == 0 {
|
if err != nil || len(subs) == 0 {
|
||||||
c.String(400, "Error!")
|
c.String(400, "Error!")
|
||||||
} else {
|
} else {
|
||||||
@@ -40,14 +63,32 @@ func (a *SUBController) subs(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add headers
|
// Add headers
|
||||||
c.Writer.Header().Set("Subscription-Userinfo", headers[0])
|
c.Writer.Header().Set("Subscription-Userinfo", header)
|
||||||
c.Writer.Header().Set("Profile-Update-Interval", headers[1])
|
c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval)
|
||||||
c.Writer.Header().Set("Profile-Title", headers[2])
|
c.Writer.Header().Set("Profile-Title", subId)
|
||||||
|
|
||||||
if subEncrypt {
|
if a.subEncrypt {
|
||||||
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
|
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
|
||||||
} else {
|
} else {
|
||||||
c.String(200, result)
|
c.String(200, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *SUBController) subJsons(c *gin.Context) {
|
||||||
|
println(c.Request.Header["User-Agent"][0])
|
||||||
|
subId := c.Param("subid")
|
||||||
|
host := strings.Split(c.Request.Host, ":")[0]
|
||||||
|
jsonSub, header, err := a.subJsonService.GetJson(subId, host)
|
||||||
|
if err != nil || len(jsonSub) == 0 {
|
||||||
|
c.String(400, "Error!")
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Add headers
|
||||||
|
c.Writer.Header().Set("Subscription-Userinfo", header)
|
||||||
|
c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval)
|
||||||
|
c.Writer.Header().Set("Profile-Title", subId)
|
||||||
|
|
||||||
|
c.String(200, jsonSub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
359
sub/subJsonService.go
Normal file
359
sub/subJsonService.go
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"x-ui/database/model"
|
||||||
|
"x-ui/logger"
|
||||||
|
"x-ui/util/json_util"
|
||||||
|
"x-ui/util/random"
|
||||||
|
"x-ui/web/service"
|
||||||
|
"x-ui/xray"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed default.json
|
||||||
|
var defaultJson string
|
||||||
|
|
||||||
|
type SubJsonService struct {
|
||||||
|
fragmanet string
|
||||||
|
|
||||||
|
inboundService service.InboundService
|
||||||
|
SubService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSubJsonService(fragment string) *SubJsonService {
|
||||||
|
return &SubJsonService{
|
||||||
|
fragmanet: fragment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubJsonService) GetJson(subId string, host string) (string, string, error) {
|
||||||
|
inbounds, err := s.SubService.getInboundsBySubId(subId)
|
||||||
|
if err != nil || len(inbounds) == 0 {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var header string
|
||||||
|
var traffic xray.ClientTraffic
|
||||||
|
var clientTraffics []xray.ClientTraffic
|
||||||
|
var configJson map[string]interface{}
|
||||||
|
var defaultOutbounds []json_util.RawMessage
|
||||||
|
|
||||||
|
json.Unmarshal([]byte(defaultJson), &configJson)
|
||||||
|
if outboundSlices, ok := configJson["outbounds"].([]interface{}); ok {
|
||||||
|
for _, defaultOutbound := range outboundSlices {
|
||||||
|
jsonBytes, _ := json.Marshal(defaultOutbound)
|
||||||
|
defaultOutbounds = append(defaultOutbounds, jsonBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outbounds := []json_util.RawMessage{}
|
||||||
|
startIndex := 0
|
||||||
|
// Prepare Inbounds
|
||||||
|
for _, inbound := range inbounds {
|
||||||
|
clients, err := s.inboundService.GetClients(inbound)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("SubJsonService - GetClients: Unable to get clients from inbound")
|
||||||
|
}
|
||||||
|
if clients == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' {
|
||||||
|
listen, port, streamSettings, err := s.getFallbackMaster(inbound.Listen, inbound.StreamSettings)
|
||||||
|
if err == nil {
|
||||||
|
inbound.Listen = listen
|
||||||
|
inbound.Port = port
|
||||||
|
inbound.StreamSettings = streamSettings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var subClients []model.Client
|
||||||
|
for _, client := range clients {
|
||||||
|
if client.Enable && client.SubID == subId {
|
||||||
|
subClients = append(subClients, client)
|
||||||
|
clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound := s.getOutbound(inbound, subClients, host, startIndex)
|
||||||
|
if outbound != nil {
|
||||||
|
outbounds = append(outbounds, outbound...)
|
||||||
|
startIndex += len(outbound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(outbounds) == 0 {
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare statistics
|
||||||
|
for index, clientTraffic := range clientTraffics {
|
||||||
|
if index == 0 {
|
||||||
|
traffic.Up = clientTraffic.Up
|
||||||
|
traffic.Down = clientTraffic.Down
|
||||||
|
traffic.Total = clientTraffic.Total
|
||||||
|
if clientTraffic.ExpiryTime > 0 {
|
||||||
|
traffic.ExpiryTime = clientTraffic.ExpiryTime
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
traffic.Up += clientTraffic.Up
|
||||||
|
traffic.Down += clientTraffic.Down
|
||||||
|
if traffic.Total == 0 || clientTraffic.Total == 0 {
|
||||||
|
traffic.Total = 0
|
||||||
|
} else {
|
||||||
|
traffic.Total += clientTraffic.Total
|
||||||
|
}
|
||||||
|
if clientTraffic.ExpiryTime != traffic.ExpiryTime {
|
||||||
|
traffic.ExpiryTime = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.fragmanet != "" {
|
||||||
|
outbounds = append(outbounds, json_util.RawMessage(s.fragmanet))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combile outbounds
|
||||||
|
outbounds = append(outbounds, defaultOutbounds...)
|
||||||
|
var outboundStrings []json_util.RawMessage
|
||||||
|
for _, outbound := range outbounds {
|
||||||
|
outboundStrings = append(outboundStrings, outbound)
|
||||||
|
}
|
||||||
|
configJson["outbounds"] = outboundStrings
|
||||||
|
finalJson, _ := json.MarshalIndent(configJson, "", " ")
|
||||||
|
|
||||||
|
header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
|
||||||
|
return string(finalJson), header, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubJsonService) getOutbound(inbound *model.Inbound, clients []model.Client, host string, startIndex int) []json_util.RawMessage {
|
||||||
|
var newOutbounds []json_util.RawMessage
|
||||||
|
stream := s.streamData(inbound.StreamSettings)
|
||||||
|
|
||||||
|
externalProxies, ok := stream["externalProxy"].([]interface{})
|
||||||
|
if !ok || len(externalProxies) == 0 {
|
||||||
|
externalProxies = []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"forceTls": "same",
|
||||||
|
"dest": host,
|
||||||
|
"port": float64(inbound.Port),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(stream, "externalProxy")
|
||||||
|
|
||||||
|
config_index := startIndex
|
||||||
|
for _, ep := range externalProxies {
|
||||||
|
extPrxy := ep.(map[string]interface{})
|
||||||
|
inbound.Listen = extPrxy["dest"].(string)
|
||||||
|
inbound.Port = int(extPrxy["port"].(float64))
|
||||||
|
newStream := stream
|
||||||
|
switch extPrxy["forceTls"].(string) {
|
||||||
|
case "tls":
|
||||||
|
if newStream["security"] != "tls" {
|
||||||
|
newStream["security"] = "tls"
|
||||||
|
newStream["tslSettings"] = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
case "none":
|
||||||
|
if newStream["security"] != "none" {
|
||||||
|
newStream["security"] = "none"
|
||||||
|
delete(newStream, "tslSettings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
streamSettings, _ := json.MarshalIndent(newStream, "", " ")
|
||||||
|
inbound.StreamSettings = string(streamSettings)
|
||||||
|
|
||||||
|
for _, client := range clients {
|
||||||
|
inbound.Tag = fmt.Sprintf("proxy_%d", config_index)
|
||||||
|
switch inbound.Protocol {
|
||||||
|
case "vmess", "vless":
|
||||||
|
newOutbounds = append(newOutbounds, s.genVnext(inbound, client))
|
||||||
|
case "trojan", "shadowsocks":
|
||||||
|
newOutbounds = append(newOutbounds, s.genServer(inbound, client))
|
||||||
|
}
|
||||||
|
config_index += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newOutbounds
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubJsonService) streamData(stream string) map[string]interface{} {
|
||||||
|
var streamSettings map[string]interface{}
|
||||||
|
json.Unmarshal([]byte(stream), &streamSettings)
|
||||||
|
security, _ := streamSettings["security"].(string)
|
||||||
|
if security == "tls" {
|
||||||
|
streamSettings["tlsSettings"] = s.tlsData(streamSettings["tlsSettings"].(map[string]interface{}))
|
||||||
|
} else if security == "reality" {
|
||||||
|
streamSettings["realitySettings"] = s.realityData(streamSettings["realitySettings"].(map[string]interface{}))
|
||||||
|
}
|
||||||
|
delete(streamSettings, "sockopt")
|
||||||
|
|
||||||
|
if s.fragmanet != "" {
|
||||||
|
streamSettings["sockopt"] = json_util.RawMessage(`{"dialerProxy": "fragment", "tcpKeepAliveIdle": 100, "TcpNoDelay": true}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove proxy protocol
|
||||||
|
network, _ := streamSettings["network"].(string)
|
||||||
|
switch network {
|
||||||
|
case "tcp":
|
||||||
|
streamSettings["tcpSettings"] = s.removeAcceptProxy(streamSettings["tcpSettings"])
|
||||||
|
case "ws":
|
||||||
|
streamSettings["wsSettings"] = s.removeAcceptProxy(streamSettings["wsSettings"])
|
||||||
|
}
|
||||||
|
|
||||||
|
return streamSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubJsonService) removeAcceptProxy(setting interface{}) map[string]interface{} {
|
||||||
|
netSettings, ok := setting.(map[string]interface{})
|
||||||
|
if ok {
|
||||||
|
delete(netSettings, "acceptProxyProtocol")
|
||||||
|
}
|
||||||
|
return netSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubJsonService) tlsData(tData map[string]interface{}) map[string]interface{} {
|
||||||
|
tlsData := make(map[string]interface{}, 1)
|
||||||
|
tlsClientSettings := tData["settings"].(map[string]interface{})
|
||||||
|
|
||||||
|
tlsData["serverName"] = tData["serverName"]
|
||||||
|
tlsData["alpn"] = tData["alpn"]
|
||||||
|
if allowInsecure, ok := tlsClientSettings["allowInsecure"].(string); ok {
|
||||||
|
tlsData["allowInsecure"] = allowInsecure
|
||||||
|
}
|
||||||
|
if fingerprint, ok := tlsClientSettings["fingerprint"].(string); ok {
|
||||||
|
tlsData["fingerprint"] = fingerprint
|
||||||
|
}
|
||||||
|
return tlsData
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubJsonService) realityData(rData map[string]interface{}) map[string]interface{} {
|
||||||
|
rltyData := make(map[string]interface{}, 1)
|
||||||
|
rltyClientSettings := rData["settings"].(map[string]interface{})
|
||||||
|
|
||||||
|
rltyData["show"] = false
|
||||||
|
rltyData["publicKey"] = rltyClientSettings["publicKey"]
|
||||||
|
rltyData["fingerprint"] = rltyClientSettings["fingerprint"]
|
||||||
|
|
||||||
|
// Set random data
|
||||||
|
rltyData["spiderX"] = "/" + random.Seq(15)
|
||||||
|
shortIds, ok := rData["shortIds"].([]interface{})
|
||||||
|
if ok && len(shortIds) > 0 {
|
||||||
|
rltyData["shortId"] = shortIds[random.Num(len(shortIds))].(string)
|
||||||
|
} else {
|
||||||
|
rltyData["shortId"] = ""
|
||||||
|
}
|
||||||
|
serverNames, ok := rData["serverNames"].([]interface{})
|
||||||
|
if ok && len(serverNames) > 0 {
|
||||||
|
rltyData["serverName"] = serverNames[random.Num(len(serverNames))].(string)
|
||||||
|
} else {
|
||||||
|
rltyData["serverName"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return rltyData
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubJsonService) genVnext(inbound *model.Inbound, client model.Client) json_util.RawMessage {
|
||||||
|
outbound := Outbound{}
|
||||||
|
usersData := make([]UserVnext, 1)
|
||||||
|
|
||||||
|
usersData[0].ID = client.ID
|
||||||
|
usersData[0].Level = 8
|
||||||
|
if inbound.Protocol == model.VLESS {
|
||||||
|
usersData[0].Flow = client.Flow
|
||||||
|
usersData[0].Encryption = "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
vnextData := make([]VnextSetting, 1)
|
||||||
|
vnextData[0] = VnextSetting{
|
||||||
|
Address: inbound.Listen,
|
||||||
|
Port: inbound.Port,
|
||||||
|
Users: usersData,
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound.Protocol = string(inbound.Protocol)
|
||||||
|
outbound.Tag = inbound.Tag
|
||||||
|
outbound.StreamSettings = json_util.RawMessage(inbound.StreamSettings)
|
||||||
|
outbound.Settings = OutboundSettings{
|
||||||
|
Vnext: vnextData,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, _ := json.MarshalIndent(outbound, "", " ")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubJsonService) genServer(inbound *model.Inbound, client model.Client) json_util.RawMessage {
|
||||||
|
outbound := Outbound{}
|
||||||
|
|
||||||
|
serverData := make([]ServerSetting, 1)
|
||||||
|
serverData[0] = ServerSetting{
|
||||||
|
Address: inbound.Listen,
|
||||||
|
Port: inbound.Port,
|
||||||
|
Level: 8,
|
||||||
|
Password: client.Password,
|
||||||
|
}
|
||||||
|
|
||||||
|
if inbound.Protocol == model.Shadowsocks {
|
||||||
|
var inboundSettings map[string]interface{}
|
||||||
|
json.Unmarshal([]byte(inbound.Settings), &inboundSettings)
|
||||||
|
method, _ := inboundSettings["method"].(string)
|
||||||
|
serverData[0].Method = method
|
||||||
|
|
||||||
|
// server password in multi-user 2022 protocols
|
||||||
|
if strings.HasPrefix(method, "2022") {
|
||||||
|
if serverPassword, ok := inboundSettings["password"].(string); ok {
|
||||||
|
serverData[0].Password = fmt.Sprintf("%s:%s", serverPassword, client.Password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound.Protocol = string(inbound.Protocol)
|
||||||
|
outbound.Tag = inbound.Tag
|
||||||
|
outbound.StreamSettings = json_util.RawMessage(inbound.StreamSettings)
|
||||||
|
outbound.Settings = OutboundSettings{
|
||||||
|
Servers: serverData,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, _ := json.MarshalIndent(outbound, "", " ")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
type Outbound struct {
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
StreamSettings json_util.RawMessage `json:"streamSettings"`
|
||||||
|
Mux map[string]interface{} `json:"mux,omitempty"`
|
||||||
|
ProxySettings map[string]interface{} `json:"proxySettings,omitempty"`
|
||||||
|
Settings OutboundSettings `json:"settings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutboundSettings struct {
|
||||||
|
Vnext []VnextSetting `json:"vnext,omitempty"`
|
||||||
|
Servers []ServerSetting `json:"servers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VnextSetting struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Users []UserVnext `json:"users"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserVnext struct {
|
||||||
|
Encryption string `json:"encryption,omitempty"`
|
||||||
|
Flow string `json:"flow,omitempty"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Level int `json:"level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerSetting struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
Level int `json:"level"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Flow string `json:"flow,omitempty"`
|
||||||
|
Method string `json:"method,omitempty"`
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"x-ui/database/model"
|
"x-ui/database/model"
|
||||||
"x-ui/logger"
|
"x-ui/logger"
|
||||||
"x-ui/util/common"
|
"x-ui/util/common"
|
||||||
|
"x-ui/util/random"
|
||||||
"x-ui/web/service"
|
"x-ui/web/service"
|
||||||
"x-ui/xray"
|
"x-ui/xray"
|
||||||
|
|
||||||
@@ -17,50 +18,46 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SubService struct {
|
type SubService struct {
|
||||||
address string
|
address string
|
||||||
showInfo bool
|
showInfo bool
|
||||||
remarkModel string
|
remarkModel string
|
||||||
|
|
||||||
inboundService service.InboundService
|
inboundService service.InboundService
|
||||||
settingService service.SettingService
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubService) GetSubs(subId string, host string, showInfo bool) ([]string, []string, error) {
|
func NewSubService(showInfo bool, remarkModel string) *SubService {
|
||||||
|
return &SubService{
|
||||||
|
showInfo: showInfo,
|
||||||
|
remarkModel: remarkModel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubService) GetSubs(subId string, host string) ([]string, string, error) {
|
||||||
s.address = host
|
s.address = host
|
||||||
s.showInfo = showInfo
|
|
||||||
var result []string
|
var result []string
|
||||||
var headers []string
|
var header string
|
||||||
var traffic xray.ClientTraffic
|
var traffic xray.ClientTraffic
|
||||||
var clientTraffics []xray.ClientTraffic
|
var clientTraffics []xray.ClientTraffic
|
||||||
inbounds, err := s.getInboundsBySubId(subId)
|
inbounds, err := s.getInboundsBySubId(subId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, "", err
|
||||||
}
|
|
||||||
s.remarkModel, err = s.settingService.GetRemarkModel()
|
|
||||||
if err != nil {
|
|
||||||
s.remarkModel = "-ieo"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare Inbounds
|
||||||
for _, inbound := range inbounds {
|
for _, inbound := range inbounds {
|
||||||
clients, err := s.inboundService.GetClients(inbound)
|
clients, err := s.inboundService.GetClients(inbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("SubService - GetSub: Unable to get clients from inbound")
|
logger.Error("SubService - GetClients: Unable to get clients from inbound")
|
||||||
}
|
}
|
||||||
if clients == nil {
|
if clients == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' {
|
if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' {
|
||||||
fallbackMaster, err := s.getFallbackMaster(inbound.Listen)
|
listen, port, streamSettings, err := s.getFallbackMaster(inbound.Listen, inbound.StreamSettings)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
inbound.Listen = fallbackMaster.Listen
|
inbound.Listen = listen
|
||||||
inbound.Port = fallbackMaster.Port
|
inbound.Port = port
|
||||||
var stream map[string]interface{}
|
inbound.StreamSettings = streamSettings
|
||||||
json.Unmarshal([]byte(inbound.StreamSettings), &stream)
|
|
||||||
var masterStream map[string]interface{}
|
|
||||||
json.Unmarshal([]byte(fallbackMaster.StreamSettings), &masterStream)
|
|
||||||
stream["security"] = masterStream["security"]
|
|
||||||
stream["tlsSettings"] = masterStream["tlsSettings"]
|
|
||||||
stream["externalProxy"] = masterStream["externalProxy"]
|
|
||||||
modifiedStream, _ := json.MarshalIndent(stream, "", " ")
|
|
||||||
inbound.StreamSettings = string(modifiedStream)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, client := range clients {
|
for _, client := range clients {
|
||||||
@@ -71,6 +68,8 @@ func (s *SubService) GetSubs(subId string, host string, showInfo bool) ([]string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare statistics
|
||||||
for index, clientTraffic := range clientTraffics {
|
for index, clientTraffic := range clientTraffics {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
traffic.Up = clientTraffic.Up
|
traffic.Up = clientTraffic.Up
|
||||||
@@ -92,11 +91,8 @@ func (s *SubService) GetSubs(subId string, host string, showInfo bool) ([]string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headers = append(headers, fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000))
|
header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
|
||||||
updateInterval, _ := s.settingService.GetSubUpdates()
|
return result, header, nil
|
||||||
headers = append(headers, fmt.Sprintf("%d", updateInterval))
|
|
||||||
headers = append(headers, subId)
|
|
||||||
return result, headers, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) {
|
func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) {
|
||||||
@@ -125,7 +121,7 @@ func (s *SubService) getClientTraffics(traffics []xray.ClientTraffic, email stri
|
|||||||
return xray.ClientTraffic{}
|
return xray.ClientTraffic{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubService) getFallbackMaster(dest string) (*model.Inbound, error) {
|
func (s *SubService) getFallbackMaster(dest string, streamSettings string) (string, int, string, error) {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
var inbound *model.Inbound
|
var inbound *model.Inbound
|
||||||
err := db.Model(model.Inbound{}).
|
err := db.Model(model.Inbound{}).
|
||||||
@@ -133,9 +129,19 @@ func (s *SubService) getFallbackMaster(dest string) (*model.Inbound, error) {
|
|||||||
Where("EXISTS (SELECT * FROM json_each(settings, '$.fallbacks') WHERE json_extract(value, '$.dest') = ?)", dest).
|
Where("EXISTS (SELECT * FROM json_each(settings, '$.fallbacks') WHERE json_extract(value, '$.dest') = ?)", dest).
|
||||||
Find(&inbound).Error
|
Find(&inbound).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", 0, "", err
|
||||||
}
|
}
|
||||||
return inbound, nil
|
|
||||||
|
var stream map[string]interface{}
|
||||||
|
json.Unmarshal([]byte(streamSettings), &stream)
|
||||||
|
var masterStream map[string]interface{}
|
||||||
|
json.Unmarshal([]byte(inbound.StreamSettings), &masterStream)
|
||||||
|
stream["security"] = masterStream["security"]
|
||||||
|
stream["tlsSettings"] = masterStream["tlsSettings"]
|
||||||
|
stream["externalProxy"] = masterStream["externalProxy"]
|
||||||
|
modifiedStream, _ := json.MarshalIndent(stream, "", " ")
|
||||||
|
|
||||||
|
return inbound.Listen, inbound.Port, string(modifiedStream), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubService) getLink(inbound *model.Inbound, email string) string {
|
func (s *SubService) getLink(inbound *model.Inbound, email string) string {
|
||||||
@@ -382,25 +388,21 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
|
|||||||
if realitySetting != nil {
|
if realitySetting != nil {
|
||||||
if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
|
if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
|
||||||
sNames, _ := sniValue.([]interface{})
|
sNames, _ := sniValue.([]interface{})
|
||||||
params["sni"], _ = sNames[0].(string)
|
params["sni"] = sNames[random.Num(len(sNames))].(string)
|
||||||
}
|
}
|
||||||
if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
|
if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
|
||||||
params["pbk"], _ = pbkValue.(string)
|
params["pbk"], _ = pbkValue.(string)
|
||||||
}
|
}
|
||||||
if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
|
if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
|
||||||
shortIds, _ := sidValue.([]interface{})
|
shortIds, _ := sidValue.([]interface{})
|
||||||
params["sid"], _ = shortIds[0].(string)
|
params["sid"] = shortIds[random.Num(len(shortIds))].(string)
|
||||||
}
|
}
|
||||||
if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
|
if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
|
||||||
if fp, ok := fpValue.(string); ok && len(fp) > 0 {
|
if fp, ok := fpValue.(string); ok && len(fp) > 0 {
|
||||||
params["fp"] = fp
|
params["fp"] = fp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if spxValue, ok := searchKey(realitySettings, "spiderX"); ok {
|
params["spx"] = "/" + random.Seq(15)
|
||||||
if spx, ok := spxValue.(string); ok && len(spx) > 0 {
|
|
||||||
params["spx"] = spx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
|
if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
|
||||||
@@ -563,25 +565,21 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
|
|||||||
if realitySetting != nil {
|
if realitySetting != nil {
|
||||||
if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
|
if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
|
||||||
sNames, _ := sniValue.([]interface{})
|
sNames, _ := sniValue.([]interface{})
|
||||||
params["sni"], _ = sNames[0].(string)
|
params["sni"] = sNames[random.Num(len(sNames))].(string)
|
||||||
}
|
}
|
||||||
if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
|
if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
|
||||||
params["pbk"], _ = pbkValue.(string)
|
params["pbk"], _ = pbkValue.(string)
|
||||||
}
|
}
|
||||||
if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
|
if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
|
||||||
shortIds, _ := sidValue.([]interface{})
|
shortIds, _ := sidValue.([]interface{})
|
||||||
params["sid"], _ = shortIds[0].(string)
|
params["sid"] = shortIds[random.Num(len(shortIds))].(string)
|
||||||
}
|
}
|
||||||
if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
|
if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
|
||||||
if fp, ok := fpValue.(string); ok && len(fp) > 0 {
|
if fp, ok := fpValue.(string); ok && len(fp) > 0 {
|
||||||
params["fp"] = fp
|
params["fp"] = fp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if spxValue, ok := searchKey(realitySettings, "spiderX"); ok {
|
params["spx"] = "/" + random.Seq(15)
|
||||||
if spx, ok := spxValue.(string); ok && len(spx) > 0 {
|
|
||||||
params["spx"] = spx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,3 +41,7 @@ func Seq(n int) string {
|
|||||||
}
|
}
|
||||||
return string(runes)
|
return string(runes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Num(n int) int {
|
||||||
|
return rand.Intn(n)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1038,6 +1038,12 @@ li.ant-select-dropdown-menu-item:empty:after {
|
|||||||
color: rgba(255, 255, 255, 0.25);
|
color: rgba(255, 255, 255, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark .ant-message-notice-content {
|
||||||
|
background-color: #222d42;
|
||||||
|
border: 1px solid #2c3950;
|
||||||
|
color: rgba(255, 255, 255, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
.ant-input-number-handler-wrap {
|
.ant-input-number-handler-wrap {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
@@ -1049,3 +1055,29 @@ li.ant-select-dropdown-menu-item:empty:after {
|
|||||||
.ant-input-number {
|
.ant-input-number {
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-modal-body,
|
||||||
|
.ant-collapse-content>.ant-collapse-content-box {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .ant-dropdown-menu-item:hover,
|
||||||
|
.dark .ant-dropdown-menu-submenu-title:hover,
|
||||||
|
.dark .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled),
|
||||||
|
.dark .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled) {
|
||||||
|
background-color: #313f5a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-dropdown,
|
||||||
|
.ant-popover-inner {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-popover-inner-content {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input-group-addon:not(:first-child):not(:last-child), .ant-input-group-wrap:not(:first-child):not(:last-child), .ant-input-group>.ant-input:not(:first-child):not(:last-child) {
|
||||||
|
border-radius: 0rem 1rem 1rem 0rem;
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB |
@@ -418,7 +418,7 @@ class Outbound extends CommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canEnableTls() {
|
canEnableTls() {
|
||||||
if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan].includes(this.protocol)) return false;
|
if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(this.protocol)) return false;
|
||||||
return ["tcp", "ws", "http", "quic", "grpc"].includes(this.stream.network);
|
return ["tcp", "ws", "http", "quic", "grpc"].includes(this.stream.network);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -860,13 +860,13 @@ Outbound.SocksSettings = class extends CommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
servers = json.servers;
|
let servers = json.servers;
|
||||||
if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}];
|
if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}];
|
||||||
return new Outbound.SocksSettings(
|
return new Outbound.SocksSettings(
|
||||||
servers[0].address,
|
servers[0].address,
|
||||||
servers[0].port,
|
servers[0].port,
|
||||||
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
|
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
|
||||||
ObjectUtil.isArrEmpty(servers[0].pass) ? '' : servers[0].users[0].pass,
|
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].pass,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -890,13 +890,13 @@ Outbound.HttpSettings = class extends CommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
servers = json.servers;
|
let servers = json.servers;
|
||||||
if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}];
|
if(ObjectUtil.isArrEmpty(servers)) servers=[{users: [{}]}];
|
||||||
return new Outbound.HttpSettings(
|
return new Outbound.HttpSettings(
|
||||||
servers[0].address,
|
servers[0].address,
|
||||||
servers[0].port,
|
servers[0].port,
|
||||||
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
|
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
|
||||||
ObjectUtil.isArrEmpty(servers[0].pass) ? '' : servers[0].users[0].pass,
|
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].pass,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,7 +912,7 @@ Outbound.HttpSettings = class extends CommonClass {
|
|||||||
};
|
};
|
||||||
Outbound.WireguardSettings = class extends CommonClass {
|
Outbound.WireguardSettings = class extends CommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
mtu=1420, secretKey=Wireguard.generateKeypair().privateKey,
|
mtu=1420, secretKey='',
|
||||||
address='', workers=2, domainStrategy='', reserved='',
|
address='', workers=2, domainStrategy='', reserved='',
|
||||||
peers=[new Outbound.WireguardSettings.Peer()], kernelMode=false) {
|
peers=[new Outbound.WireguardSettings.Peer()], kernelMode=false) {
|
||||||
super();
|
super();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class AllSetting {
|
|||||||
this.subListen = "";
|
this.subListen = "";
|
||||||
this.subPort = "2096";
|
this.subPort = "2096";
|
||||||
this.subPath = "/sub/";
|
this.subPath = "/sub/";
|
||||||
|
this.subJsonPath = "/json/";
|
||||||
this.subDomain = "";
|
this.subDomain = "";
|
||||||
this.subCertFile = "";
|
this.subCertFile = "";
|
||||||
this.subKeyFile = "";
|
this.subKeyFile = "";
|
||||||
@@ -31,6 +32,8 @@ class AllSetting {
|
|||||||
this.subEncrypt = true;
|
this.subEncrypt = true;
|
||||||
this.subShowInfo = false;
|
this.subShowInfo = false;
|
||||||
this.subURI = '';
|
this.subURI = '';
|
||||||
|
this.subJsonURI = '';
|
||||||
|
this.subJsonFragment = '';
|
||||||
|
|
||||||
this.timeLocation = "Asia/Tehran";
|
this.timeLocation = "Asia/Tehran";
|
||||||
|
|
||||||
|
|||||||
@@ -984,10 +984,6 @@ class Inbound extends XrayCommonClass {
|
|||||||
return [Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol);
|
return [Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
canSniffing() {
|
|
||||||
return [Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.port = RandomUtil.randomIntRange(10000, 60000);
|
this.port = RandomUtil.randomIntRange(10000, 60000);
|
||||||
this.listen = '';
|
this.listen = '';
|
||||||
@@ -1347,6 +1343,28 @@ class Inbound extends XrayCommonClass {
|
|||||||
return url.toString();
|
return url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWireguardLink(address, port, remark, peerId) {
|
||||||
|
let txt = `[Interface]\n`
|
||||||
|
txt += `PrivateKey = ${this.settings.peers[peerId].privateKey}\n`
|
||||||
|
txt += `Address = ${this.settings.peers[peerId].allowedIPs[0]}\n`
|
||||||
|
txt += `DNS = 1.1.1.1, 9.9.9.9\n`
|
||||||
|
if (this.settings.mtu) {
|
||||||
|
txt += `MTU = ${this.settings.mtu}\n`
|
||||||
|
}
|
||||||
|
txt += `\n# ${remark}\n`
|
||||||
|
txt += `[Peer]\n`
|
||||||
|
txt += `PublicKey = ${this.settings.pubKey}\n`
|
||||||
|
txt += `AllowedIPs = 0.0.0.0/0, ::/0\n`
|
||||||
|
txt += `Endpoint = ${address}:${port}`
|
||||||
|
if (this.settings.peers[peerId].psk) {
|
||||||
|
txt += `\nPresharedKey = ${this.settings.peers[peerId].psk}`
|
||||||
|
}
|
||||||
|
if (this.settings.peers[peerId].keepAlive) {
|
||||||
|
txt += `\nPersistentKeepalive = ${this.settings.peers[peerId].keepAlive}\n`
|
||||||
|
}
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
|
||||||
genLink(address='', port=this.port, forceTls='same', remark='', client) {
|
genLink(address='', port=this.port, forceTls='same', remark='', client) {
|
||||||
switch (this.protocol) {
|
switch (this.protocol) {
|
||||||
case Protocols.VMESS:
|
case Protocols.VMESS:
|
||||||
@@ -1370,7 +1388,7 @@ class Inbound extends XrayCommonClass {
|
|||||||
const orderChars = remarkModel.slice(1);
|
const orderChars = remarkModel.slice(1);
|
||||||
let orders = {
|
let orders = {
|
||||||
'i': remark,
|
'i': remark,
|
||||||
'e': client ? client.email : '',
|
'e': email,
|
||||||
'o': '',
|
'o': '',
|
||||||
};
|
};
|
||||||
if(ObjectUtil.isArrEmpty(this.stream.externalProxy)){
|
if(ObjectUtil.isArrEmpty(this.stream.externalProxy)){
|
||||||
@@ -1393,6 +1411,7 @@ class Inbound extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
genInboundLinks(remark = '', remarkModel = '-ieo') {
|
genInboundLinks(remark = '', remarkModel = '-ieo') {
|
||||||
|
let addr = !ObjectUtil.isEmpty(this.listen) && this.listen !== "0.0.0.0" ? this.listen : location.hostname;
|
||||||
if(this.clients){
|
if(this.clients){
|
||||||
let links = [];
|
let links = [];
|
||||||
this.clients.forEach((client) => {
|
this.clients.forEach((client) => {
|
||||||
@@ -1402,7 +1421,14 @@ class Inbound extends XrayCommonClass {
|
|||||||
});
|
});
|
||||||
return links.join('\r\n');
|
return links.join('\r\n');
|
||||||
} else {
|
} else {
|
||||||
if(this.protocol == Protocols.SHADOWSOCKS && !this.isSSMultiUser) return this.genSSLink(this.listen, this.port, 'same', remark);
|
if(this.protocol == Protocols.SHADOWSOCKS && !this.isSSMultiUser) return this.genSSLink(addr, this.port, 'same', remark);
|
||||||
|
if(this.protocol == Protocols.WIREGUARD) {
|
||||||
|
let links = [];
|
||||||
|
this.settings.peers.forEach((p,index) => {
|
||||||
|
links.push(this.getWireguardLink(addr,this.port,remark + remarkModel.charAt(0) + (index+1),index));
|
||||||
|
});
|
||||||
|
return links.join('\r\n');
|
||||||
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2070,7 +2096,7 @@ Inbound.WireguardSettings = class extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addPeer() {
|
addPeer() {
|
||||||
this.peers.push(new Inbound.WireguardSettings.Peer());
|
this.peers.push(new Inbound.WireguardSettings.Peer(null,null,'',['10.0.0.' + (this.peers.length+2)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
delPeer(index) {
|
delPeer(index) {
|
||||||
@@ -2098,16 +2124,24 @@ Inbound.WireguardSettings = class extends XrayCommonClass {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Inbound.WireguardSettings.Peer = class extends XrayCommonClass {
|
Inbound.WireguardSettings.Peer = class extends XrayCommonClass {
|
||||||
constructor(publicKey='', psk='', allowedIPs=['0.0.0.0/0','::/0'], keepAlive=0) {
|
constructor(privateKey, publicKey, psk='', allowedIPs=['10.0.0.2/32'], keepAlive=0) {
|
||||||
super();
|
super();
|
||||||
|
this.privateKey = privateKey
|
||||||
this.publicKey = publicKey;
|
this.publicKey = publicKey;
|
||||||
|
if (!this.publicKey){
|
||||||
|
[this.publicKey, this.privateKey] = Object.values(Wireguard.generateKeypair())
|
||||||
|
}
|
||||||
this.psk = psk;
|
this.psk = psk;
|
||||||
|
allowedIPs.forEach((a,index) => {
|
||||||
|
if (a.length>0 && !a.includes('/')) allowedIPs[index] += '/32';
|
||||||
|
})
|
||||||
this.allowedIPs = allowedIPs;
|
this.allowedIPs = allowedIPs;
|
||||||
this.keepAlive = keepAlive;
|
this.keepAlive = keepAlive;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json={}){
|
static fromJson(json={}){
|
||||||
return new Inbound.WireguardSettings.Peer(
|
return new Inbound.WireguardSettings.Peer(
|
||||||
|
json.privateKey,
|
||||||
json.publicKey,
|
json.publicKey,
|
||||||
json.preSharedKey,
|
json.preSharedKey,
|
||||||
json.allowedIPs,
|
json.allowedIPs,
|
||||||
@@ -2116,7 +2150,11 @@ Inbound.WireguardSettings.Peer = class extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toJson() {
|
toJson() {
|
||||||
|
this.allowedIPs.forEach((a,index) => {
|
||||||
|
if (a.length>0 && !a.includes('/')) this.allowedIPs[index] += '/32';
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
|
privateKey: this.privateKey,
|
||||||
publicKey: this.publicKey,
|
publicKey: this.publicKey,
|
||||||
preSharedKey: this.psk.length>0 ? this.psk : undefined,
|
preSharedKey: this.psk.length>0 ? this.psk : undefined,
|
||||||
allowedIPs: this.allowedIPs,
|
allowedIPs: this.allowedIPs,
|
||||||
|
|||||||
@@ -136,9 +136,9 @@ class RandomUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static randomShortId() {
|
static randomShortId() {
|
||||||
let shortIds = ['','','',''];
|
let shortIds = new Array(24).fill('');
|
||||||
for (var ii = 0; ii < 4; ii++) {
|
for (var ii = 0; ii < 24; ii++) {
|
||||||
for (var jj = 0; jj < this.randomInt(8); jj++){
|
for (var jj = 0; jj < this.randomInt(16); jj++){
|
||||||
let randomNum = this.randomInt(256);
|
let randomNum = this.randomInt(256);
|
||||||
shortIds[ii] += ('0' + randomNum.toString(16)).slice(-2)
|
shortIds[ii] += ('0' + randomNum.toString(16)).slice(-2)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ func (a *XraySettingController) warp(c *gin.Context) {
|
|||||||
resp, err = a.XraySettingService.RegWarp(skey, pkey)
|
resp, err = a.XraySettingService.RegWarp(skey, pkey)
|
||||||
case "license":
|
case "license":
|
||||||
license := c.PostForm("license")
|
license := c.PostForm("license")
|
||||||
println(license)
|
|
||||||
resp, err = a.XraySettingService.SetWarpLicence(license)
|
resp, err = a.XraySettingService.SetWarpLicence(license)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ type AllSetting struct {
|
|||||||
SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"`
|
SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"`
|
||||||
SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"`
|
SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"`
|
||||||
SubURI string `json:"subURI" form:"subURI"`
|
SubURI string `json:"subURI" form:"subURI"`
|
||||||
|
SubJsonPath string `json:"subJsonPath" form:"subJsonPath"`
|
||||||
|
SubJsonURI string `json:"subJsonURI" form:"subJsonURI"`
|
||||||
|
SubJsonFragment string `json:"subJsonFragment" form:"subJsonFragment"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AllSetting) CheckValid() error {
|
func (s *AllSetting) CheckValid() error {
|
||||||
@@ -103,6 +106,13 @@ func (s *AllSetting) CheckValid() error {
|
|||||||
s.SubPath += "/"
|
s.SubPath += "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(s.SubJsonPath, "/") {
|
||||||
|
s.SubJsonPath = "/" + s.SubJsonPath
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(s.SubJsonPath, "/") {
|
||||||
|
s.SubJsonPath += "/"
|
||||||
|
}
|
||||||
|
|
||||||
_, err := time.LoadLocation(s.TimeLocation)
|
_, err := time.LoadLocation(s.TimeLocation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.NewError("time location not exist:", s.TimeLocation)
|
return common.NewError("time location not exist:", s.TimeLocation)
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
<link rel="stylesheet" href="{{ .base_path }}assets/ant-design-vue@1.7.8/antd.min.css">
|
<link rel="stylesheet" href="{{ .base_path }}assets/ant-design-vue@1.7.8/antd.min.css">
|
||||||
<link rel="stylesheet" href="{{ .base_path }}assets/element-ui@2.15.0/theme-chalk/display.css">
|
<link rel="stylesheet" href="{{ .base_path }}assets/element-ui@2.15.0/theme-chalk/display.css">
|
||||||
<link rel="stylesheet" href="{{ .base_path }}assets/css/custom.css?{{ .cur_ver }}">
|
<link rel="stylesheet" href="{{ .base_path }}assets/css/custom.css?{{ .cur_ver }}">
|
||||||
<link rel=”icon” type=”image/x-icon” href="{{ .base_path }}assets/favicon.ico">
|
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="{{ .base_path }}assets/favicon.ico">
|
|
||||||
<style>
|
<style>
|
||||||
[v-cloak] {
|
[v-cloak] {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -30,4 +28,5 @@
|
|||||||
</style>
|
</style>
|
||||||
<title>{{ .host }}-{{ i18n .title}}</title>
|
<title>{{ .host }}-{{ i18n .title}}</title>
|
||||||
</head>
|
</head>
|
||||||
|
<div id="message"></div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -5,13 +5,23 @@
|
|||||||
width="300px" :class="themeSwitcher.currentTheme">
|
width="300px" :class="themeSwitcher.currentTheme">
|
||||||
<a-tag color="green" style="margin-bottom: 10px;display: block;text-align: center;" >{{ i18n "pages.inbounds.clickOnQRcode" }}</a-tag>
|
<a-tag color="green" style="margin-bottom: 10px;display: block;text-align: center;" >{{ i18n "pages.inbounds.clickOnQRcode" }}</a-tag>
|
||||||
<template v-if="app.subSettings.enable && qrModal.subId">
|
<template v-if="app.subSettings.enable && qrModal.subId">
|
||||||
<a-divider>Subscription</a-divider>
|
<a-divider>{{ i18n "pages.settings.subSettings"}}</a-divider>
|
||||||
<canvas @click="copyToClipboard('qrCode-sub',genSubLink(qrModal.client.subId))" id="qrCode-sub" style="width: 100%; height: 100%;"></canvas>
|
<canvas @click="copyToClipboard('qrCode-sub',genSubLink(qrModal.client.subId))"
|
||||||
|
id="qrCode-sub"
|
||||||
|
style="width: 100%; height: 100%; display: flex; border-radius: 1rem;">
|
||||||
|
</canvas>
|
||||||
|
<a-divider>{{ i18n "pages.settings.subSettings"}} Json</a-divider>
|
||||||
|
<canvas @click="copyToClipboard('qrCode-subJson',genSubJsonLink(qrModal.client.subId))"
|
||||||
|
id="qrCode-subJson"
|
||||||
|
style="width: 100%; height: 100%; display: flex; border-radius: 1rem;">
|
||||||
|
</canvas>
|
||||||
</template>
|
</template>
|
||||||
<a-divider>{{ i18n "pages.inbounds.client" }}</a-divider>
|
<a-divider>{{ i18n "pages.inbounds.client" }}</a-divider>
|
||||||
<template v-for="(row, index) in qrModal.qrcodes">
|
<template v-for="(row, index) in qrModal.qrcodes">
|
||||||
<a-tag color="blue" style="margin: 10px 0; display: block; text-align: center;">[[ row.remark ]]</a-tag>
|
<a-tag color="blue" style="margin: 10px 0; display: block; text-align: center;">[[ row.remark ]]</a-tag>
|
||||||
<canvas @click="copyToClipboard('qrCode-'+index, row.link)" :id="'qrCode-'+index" style="width: 100%; height: 100%;"></canvas>
|
<canvas @click="copyToClipboard('qrCode-'+index, row.link)"
|
||||||
|
:id="'qrCode-'+index"
|
||||||
|
style="width: 100%; height: 100%; display: flex; border-radius: 1rem;"></canvas>
|
||||||
</template>
|
</template>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
@@ -32,12 +42,21 @@
|
|||||||
this.client = client;
|
this.client = client;
|
||||||
this.subId = '';
|
this.subId = '';
|
||||||
this.qrcodes = [];
|
this.qrcodes = [];
|
||||||
this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, client).forEach(l => {
|
if (this.inbound.protocol == Protocols.WIREGUARD){
|
||||||
this.qrcodes.push({
|
this.inbound.genInboundLinks(dbInbound.remark).split('\r\n').forEach((l,index) =>{
|
||||||
remark: l.remark,
|
this.qrcodes.push({
|
||||||
link: l.link
|
remark: "Peer " + (index+1),
|
||||||
|
link: l
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
} else {
|
||||||
|
this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, client).forEach(l => {
|
||||||
|
this.qrcodes.push({
|
||||||
|
remark: l.remark,
|
||||||
|
link: l.link
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
},
|
},
|
||||||
close: function () {
|
close: function () {
|
||||||
@@ -70,12 +89,16 @@
|
|||||||
},
|
},
|
||||||
genSubLink(subID) {
|
genSubLink(subID) {
|
||||||
return app.subSettings.subURI+subID+'?name='+subID;
|
return app.subSettings.subURI+subID+'?name='+subID;
|
||||||
|
},
|
||||||
|
genSubJsonLink(subID) {
|
||||||
|
return app.subSettings.subJsonURI+subID;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
if (qrModal.client && qrModal.client.subId) {
|
if (qrModal.client && qrModal.client.subId) {
|
||||||
qrModal.subId = qrModal.client.subId;
|
qrModal.subId = qrModal.client.subId;
|
||||||
this.setQrCode("qrCode-sub", this.genSubLink(qrModal.subId));
|
this.setQrCode("qrCode-sub", this.genSubLink(qrModal.subId));
|
||||||
|
this.setQrCode("qrCode-subJson", this.genSubJsonLink(qrModal.subId));
|
||||||
}
|
}
|
||||||
qrModal.qrcodes.forEach((element, index) => {
|
qrModal.qrcodes.forEach((element, index) => {
|
||||||
this.setQrCode("qrCode-" + index, element.link);
|
this.setQrCode("qrCode-" + index, element.link);
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
{{define "textModal"}}
|
{{define "textModal"}}
|
||||||
<a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title"
|
<a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title"
|
||||||
:closable="true" ok-text='{{ i18n "copy" }}' cancel-text='{{ i18n "close" }}'
|
:closable="true"
|
||||||
:ok-button-props="{attrs:{id:'txt-modal-ok-btn'}}" :class="themeSwitcher.currentTheme">
|
:class="themeSwitcher.currentTheme">
|
||||||
<a-button v-if="!ObjectUtil.isEmpty(txtModal.fileName)" type="primary" style="margin-bottom: 10px;"
|
<template slot="footer">
|
||||||
:href="'data:application/text;charset=utf-8,' + encodeURIComponent(txtModal.content)"
|
<a-button v-if="!ObjectUtil.isEmpty(txtModal.fileName)" icon="download"
|
||||||
:download="txtModal.fileName">
|
:href="'data:application/text;charset=utf-8,' + encodeURIComponent(txtModal.content)"
|
||||||
{{ i18n "download" }} [[ txtModal.fileName ]]
|
:download="txtModal.fileName">[[ txtModal.fileName ]]
|
||||||
</a-button>
|
</a-button>
|
||||||
|
<a-button type="primary" id="copy-btn">{{ i18n "copy" }}</a-button>
|
||||||
|
</template>
|
||||||
<a-input type="textarea" v-model="txtModal.content"
|
<a-input type="textarea" v-model="txtModal.content"
|
||||||
:autosize="{ minRows: 10, maxRows: 20}"></a-input>
|
:autosize="{ minRows: 10, maxRows: 20}"></a-input>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -27,7 +29,7 @@
|
|||||||
this.visible = true;
|
this.visible = true;
|
||||||
textModalApp.$nextTick(() => {
|
textModalApp.$nextTick(() => {
|
||||||
if (this.clipboard === null) {
|
if (this.clipboard === null) {
|
||||||
this.clipboard = new ClipboardJS('#txt-modal-ok-btn', {
|
this.clipboard = new ClipboardJS('#copy-btn', {
|
||||||
text: () => this.content,
|
text: () => this.content,
|
||||||
});
|
});
|
||||||
this.clipboard.on('success', () => {
|
this.clipboard.on('success', () => {
|
||||||
|
|||||||
@@ -97,7 +97,8 @@
|
|||||||
<a-col :xs="22" :sm="20" :md="14" :lg="10" :xl="8" :xxl="6" id="login" style="margin: 3rem 0;">
|
<a-col :xs="22" :sm="20" :md="14" :lg="10" :xl="8" :xxl="6" id="login" style="margin: 3rem 0;">
|
||||||
<a-row type="flex" justify="center">
|
<a-row type="flex" justify="center">
|
||||||
<a-col>
|
<a-col>
|
||||||
<h1 class="title">{{ i18n "pages.login.title" }}</h1>
|
<h1 class="title" style="margin-bottom: 5px; font-size: 24px;">X-UI</h1>
|
||||||
|
<h2 class="title" style="text-align: center;">{{ i18n "pages.login.title" }}</h2>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
<a-row type="flex" justify="center">
|
<a-row type="flex" justify="center">
|
||||||
@@ -117,8 +118,8 @@
|
|||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-row justify="center" class="centered">
|
<a-row justify="center" class="centered">
|
||||||
<a-button type="primary" :loading="loading" @click="login" :icon="loading ? 'poweroff' : undefined"
|
<a-button type="primary" :loading="loading" @click="login" :icon="loading ? 'poweroff' : undefined"
|
||||||
:style="loading ? { width: '50px' } : { display: 'inline-block', width: '100%' }">
|
:style="{ fontWeight: 'bold', width: loading ? '50px' : '100%', display: 'inline-block' }">
|
||||||
[[ loading ? '' : '{{ i18n "login" }}' ]]
|
[[ loading ? '' : '{{ i18n "login" }}' ]]
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|||||||
@@ -61,13 +61,13 @@
|
|||||||
<template slot="label">
|
<template slot="label">
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
|
<span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
|
||||||
</template>
|
</template>
|
||||||
{{ i18n "pages.inbounds.totalFlow" }} (GB)
|
{{ i18n "pages.inbounds.totalFlow" }}
|
||||||
<a-icon type="question-circle"></a-icon>
|
<a-icon type="question-circle"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<a-input-number v-model="clientsBulkModal.totalGB" :min="0"></a-input-number>
|
<a-input-number v-model="clientsBulkModal.totalGB" :min="0"></a-input-number> GB
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.client.delayedStart" }}'>
|
<a-form-item label='{{ i18n "pages.client.delayedStart" }}'>
|
||||||
<a-switch v-model="clientsBulkModal.delayedStart" @click="clientsBulkModal.expiryTime=0"></a-switch>
|
<a-switch v-model="clientsBulkModal.delayedStart" @click="clientsBulkModal.expiryTime=0"></a-switch>
|
||||||
@@ -155,7 +155,7 @@
|
|||||||
}
|
}
|
||||||
ObjectUtil.execute(clientsBulkModal.confirm, clients, clientsBulkModal.dbInbound.id);
|
ObjectUtil.execute(clientsBulkModal.confirm, clients, clientsBulkModal.dbInbound.id);
|
||||||
},
|
},
|
||||||
show({ title='', okText='{{ i18n "sure" }}', dbInbound=null, confirm=(inbound, dbInbound)=>{} }) {
|
show({ title='', okText='{{ i18n "confirm" }}', dbInbound=null, confirm=(inbound, dbInbound)=>{} }) {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.okText = okText;
|
this.okText = okText;
|
||||||
@@ -189,7 +189,7 @@
|
|||||||
clientsBulkModal.visible = false;
|
clientsBulkModal.visible = false;
|
||||||
clientsBulkModal.loading(false);
|
clientsBulkModal.loading(false);
|
||||||
},
|
},
|
||||||
loading(loading) {
|
loading(loading=true) {
|
||||||
clientsBulkModal.confirmLoading = loading;
|
clientsBulkModal.confirmLoading = loading;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
ObjectUtil.execute(clientModal.confirm, clientModalApp.client, clientModal.dbInbound.id);
|
ObjectUtil.execute(clientModal.confirm, clientModalApp.client, clientModal.dbInbound.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
show({ title='', okText='{{ i18n "sure" }}', index=null, dbInbound=null, confirm=()=>{}, isEdit=false }) {
|
show({ title='', okText='{{ i18n "confirm" }}', index=null, dbInbound=null, confirm=()=>{}, isEdit=false }) {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.okText = okText;
|
this.okText = okText;
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
clientModal.visible = false;
|
clientModal.visible = false;
|
||||||
clientModal.loading(false);
|
clientModal.loading(false);
|
||||||
},
|
},
|
||||||
loading(loading) {
|
loading(loading=true) {
|
||||||
clientModal.confirmLoading = loading;
|
clientModal.confirmLoading = loading;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
{{define "menuItems"}}
|
{{define "menuItems"}}
|
||||||
<a-menu-item key="{{ .base_path }}xui/">
|
<a-menu-item key="{{ .base_path }}xui/">
|
||||||
<a-icon type="dashboard"></a-icon>
|
<a-icon type="dashboard"></a-icon>
|
||||||
<span>{{ i18n "menu.dashboard"}}</span>
|
<span><strong>{{ i18n "menu.dashboard"}}</strong></span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="{{ .base_path }}xui/inbounds">
|
<a-menu-item key="{{ .base_path }}xui/inbounds">
|
||||||
<a-icon type="user"></a-icon>
|
<a-icon type="user"></a-icon>
|
||||||
<span>{{ i18n "menu.inbounds"}}</span>
|
<span><strong>{{ i18n "menu.inbounds"}}</strong></span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="{{ .base_path }}xui/settings">
|
<a-menu-item key="{{ .base_path }}xui/settings">
|
||||||
<a-icon type="setting"></a-icon>
|
<a-icon type="setting"></a-icon>
|
||||||
<span>{{ i18n "menu.settings"}}</span>
|
<span><strong>{{ i18n "menu.settings"}}</strong></span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="{{ .base_path }}xui/xray">
|
<a-menu-item key="{{ .base_path }}xui/xray">
|
||||||
<a-icon type="tool"></a-icon>
|
<a-icon type="tool"></a-icon>
|
||||||
<span>{{ i18n "menu.xray"}}</span>
|
<span><strong>{{ i18n "menu.xray"}}</strong></span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="{{ .base_path }}logout">
|
<a-menu-item key="{{ .base_path }}logout">
|
||||||
<a-icon type="logout"></a-icon>
|
<a-icon type="logout"></a-icon>
|
||||||
<span>{{ i18n "menu.logout"}}</span>
|
<span><strong>{{ i18n "menu.logout"}}</strong></span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
toggleTheme() {
|
toggleTheme() {
|
||||||
this.isDarkTheme = !this.isDarkTheme;
|
this.isDarkTheme = !this.isDarkTheme;
|
||||||
localStorage.setItem('dark-mode', this.isDarkTheme);
|
localStorage.setItem('dark-mode', this.isDarkTheme);
|
||||||
|
document.getElementById('message').className = themeSwitcher.currentTheme;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -29,6 +30,10 @@
|
|||||||
props: [],
|
props: [],
|
||||||
template: `{{template "component/themeSwitchTemplate"}}`,
|
template: `{{template "component/themeSwitchTemplate"}}`,
|
||||||
data: () => ({ themeSwitcher }),
|
data: () => ({ themeSwitcher }),
|
||||||
|
mounted() {
|
||||||
|
this.$message.config({getContainer: () => document.getElementById('message')});
|
||||||
|
document.getElementById('message').className = themeSwitcher.currentTheme;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{{end}}
|
{{end}}
|
||||||
86
web/html/xui/dns_modal.html
Normal file
86
web/html/xui/dns_modal.html
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
{{define "dnsModal"}}
|
||||||
|
<a-modal id="dns-modal" v-model="dnsModal.visible" :title="dnsModal.title" @ok="dnsModal.ok"
|
||||||
|
:closable="true" :mask-closable="false"
|
||||||
|
:ok-text="dnsModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme">
|
||||||
|
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.outbound.address" }}'>
|
||||||
|
<a-input v-model.trim="dnsModal.dnsServer.address"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.dns.domains" }}'>
|
||||||
|
<a-button size="small" type="primary" @click="dnsModal.dnsServer.domains.push('')">+</a-button>
|
||||||
|
<template v-for="(domain, index) in dnsModal.dnsServer.domains">
|
||||||
|
<a-input v-model.trim="dnsModal.dnsServer.domains[index]">
|
||||||
|
<a-button size="small" slot="addonAfter" @click="dnsModal.dnsServer.domains.splice(index,1)">-</a-button>
|
||||||
|
</a-input>
|
||||||
|
</template>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.dns.strategy" }}' v-if="isAdvanced">
|
||||||
|
<a-select
|
||||||
|
v-model="dnsModal.dnsServer.queryStrategy"
|
||||||
|
style="width: 100%"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']">
|
||||||
|
[[ l ]]
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
<script>
|
||||||
|
const dnsModal = {
|
||||||
|
title: '',
|
||||||
|
visible: false,
|
||||||
|
okText: '{{ i18n "confirm" }}',
|
||||||
|
isEdit: false,
|
||||||
|
confirm: null,
|
||||||
|
dnsServer: {
|
||||||
|
address: "localhost",
|
||||||
|
domains: [],
|
||||||
|
queryStrategy: 'UseIP',
|
||||||
|
},
|
||||||
|
ok() {
|
||||||
|
domains = dnsModal.dnsServer.domains.filter(d => d.length>0);
|
||||||
|
dnsModal.dnsServer.domains = domains;
|
||||||
|
newDnsServer = domains.length > 0 ? dnsModal.dnsServer : dnsModal.dnsServer.address;
|
||||||
|
ObjectUtil.execute(dnsModal.confirm, newDnsServer);
|
||||||
|
},
|
||||||
|
show({ title='', okText='{{ i18n "confirm" }}', dnsServer, confirm=(dnsServer)=>{}, isEdit=false }) {
|
||||||
|
this.title = title;
|
||||||
|
this.okText = okText;
|
||||||
|
this.confirm = confirm;
|
||||||
|
this.visible = true;
|
||||||
|
if(isEdit) {
|
||||||
|
if (typeof dnsServer == 'object'){
|
||||||
|
this.dnsServer = dnsServer;
|
||||||
|
} else {
|
||||||
|
this.dnsServer.address = dnsServer?? '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dnsServer = {
|
||||||
|
address: "localhost",
|
||||||
|
domains: [],
|
||||||
|
queryStrategy: 'UseIP',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.isEdit = isEdit;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
dnsModal.visible = false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
delimiters: ['[[', ']]'],
|
||||||
|
el: '#dns-modal',
|
||||||
|
data: {
|
||||||
|
dnsModal: dnsModal,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isAdvanced: {
|
||||||
|
get: function () { return dnsModal.dnsServer.domains.length>0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
57
web/html/xui/fakedns_modal.html
Normal file
57
web/html/xui/fakedns_modal.html
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{{define "fakednsModal"}}
|
||||||
|
<a-modal id="fakedns-modal" v-model="fakednsModal.visible" :title="fakednsModal.title" @ok="fakednsModal.ok"
|
||||||
|
:closable="true" :mask-closable="false"
|
||||||
|
:ok-text="fakednsModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme">
|
||||||
|
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.fakedns.ipPool" }}'>
|
||||||
|
<a-input v-model.trim="fakednsModal.fakeDns.ipPool"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.fakedns.poolSize" }}'>
|
||||||
|
<a-input type="number" min="1" v-model.trim="fakednsModal.fakeDns.poolSize"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
<script>
|
||||||
|
const fakednsModal = {
|
||||||
|
title: '',
|
||||||
|
visible: false,
|
||||||
|
okText: '{{ i18n "confirm" }}',
|
||||||
|
isEdit: false,
|
||||||
|
confirm: null,
|
||||||
|
fakeDns: {
|
||||||
|
ipPool: "198.18.0.0/16",
|
||||||
|
poolSize: 65535,
|
||||||
|
},
|
||||||
|
ok() {
|
||||||
|
ObjectUtil.execute(fakednsModal.confirm, fakednsModal.fakeDns);
|
||||||
|
},
|
||||||
|
show({ title='', okText='{{ i18n "confirm" }}', fakeDns, confirm=(fakeDns)=>{}, isEdit=false }) {
|
||||||
|
this.title = title;
|
||||||
|
this.okText = okText;
|
||||||
|
this.confirm = confirm;
|
||||||
|
this.visible = true;
|
||||||
|
if(isEdit) {
|
||||||
|
this.fakeDns = fakeDns;
|
||||||
|
} else {
|
||||||
|
this.fakeDns = {
|
||||||
|
ipPool: "198.18.0.0/16",
|
||||||
|
poolSize: 65535,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.isEdit = isEdit;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
fakednsModal.visible = false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
delimiters: ['[[', ']]'],
|
||||||
|
el: '#fakedns-modal',
|
||||||
|
data: {
|
||||||
|
fakednsModal: fakednsModal,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
@@ -73,13 +73,13 @@
|
|||||||
<template slot="label">
|
<template slot="label">
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
|
<span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
|
||||||
</template>
|
</template>
|
||||||
{{ i18n "pages.inbounds.totalFlow" }} (GB)
|
{{ i18n "pages.inbounds.totalFlow" }}
|
||||||
<a-icon type="question-circle"></a-icon>
|
<a-icon type="question-circle"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<a-input-number v-model="client._totalGB" :min="0"></a-input-number>
|
<a-input-number v-model="client._totalGB" :min="0"></a-input-number> GB
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="isEdit && clientStats" label='{{ i18n "usage" }}'>
|
<a-form-item v-if="isEdit && clientStats" label='{{ i18n "usage" }}'>
|
||||||
<a-tag :color="clientUsageColor(clientStats, app.trafficDiff)">
|
<a-tag :color="clientUsageColor(clientStats, app.trafficDiff)">
|
||||||
|
|||||||
@@ -35,13 +35,13 @@
|
|||||||
<template slot="label">
|
<template slot="label">
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
|
<span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
|
||||||
</template>
|
</template>
|
||||||
{{ i18n "pages.inbounds.totalFlow" }} (GB)
|
{{ i18n "pages.inbounds.totalFlow" }}
|
||||||
<a-icon type="question-circle"></a-icon>
|
<a-icon type="question-circle"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<a-input-number v-model="dbInbound.totalGB" :min="0"></a-input-number>
|
<a-input-number v-model="dbInbound.totalGB" :min="0"></a-input-number> GB
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- sniffing -->
|
<!-- sniffing -->
|
||||||
<template v-if="inbound.canSniffing()">
|
<template>
|
||||||
{{template "form/sniffing"}}
|
{{template "form/sniffing"}}
|
||||||
</template>
|
</template>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -193,17 +193,23 @@
|
|||||||
<a-input v-model.trim="outbound.settings.pass"></a-input>
|
<a-input v-model.trim="outbound.settings.pass"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
<!-- trojan/shadowsocks -->
|
||||||
|
<template v-if="[Protocols.Trojan, Protocols.Shadowsocks].includes(outbound.protocol)">
|
||||||
|
<a-form-item label='{{ i18n "password" }}'>
|
||||||
|
<a-input v-model.trim="outbound.settings.password"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
<!-- shadowsocks -->
|
<!-- shadowsocks -->
|
||||||
<template v-if="outbound.protocol === Protocols.Shadowsocks">
|
<template v-if="outbound.protocol === Protocols.Shadowsocks">
|
||||||
<a-form-item label='{{ i18n "encryption" }}'>
|
<a-form-item label='{{ i18n "encryption" }}'>
|
||||||
<a-select v-model="outbound.settings.method" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select v-model="outbound.settings.method" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select-option v-for="(method,method_name) in SSMethods" :value="method">[[ method_name ]]</a-select-option>
|
<a-select-option v-for="(method, method_name) in SSMethods" :value="method">[[ method_name ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='UDP over TCP'>
|
<a-form-item label='UDP over TCP'>
|
||||||
<a-switch v-model="outbound.settings.uot"></a-switch>
|
<a-switch v-model="outbound.settings.uot"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- stream settings -->
|
<!-- stream settings -->
|
||||||
@@ -365,7 +371,7 @@
|
|||||||
|
|
||||||
<!-- reality settings -->
|
<!-- reality settings -->
|
||||||
<template v-if="outbound.stream.isReality">
|
<template v-if="outbound.stream.isReality">
|
||||||
<a-form-item label='{{ i18n "domainName" }}'>
|
<a-form-item label="SNI">
|
||||||
<a-input v-model.trim="outbound.stream.reality.serverName"></a-input>
|
<a-input v-model.trim="outbound.stream.reality.serverName"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="uTLS">
|
<a-form-item label="uTLS">
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<span>{{ i18n "reset" }}</span>
|
<span>{{ i18n "reset" }}</span>
|
||||||
</template>
|
</template>
|
||||||
{{ i18n "password" }}
|
{{ i18n "password" }}
|
||||||
<a-icon @click="client.password = RandomUtil.randomShadowsocksPassword()" type="sync"></a-icon>
|
<a-icon @click="inbound.settings.password = RandomUtil.randomShadowsocksPassword()" type="sync"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<a-input v-model.trim="inbound.settings.password"></a-input>
|
<a-input v-model.trim="inbound.settings.password"></a-input>
|
||||||
|
|||||||
@@ -32,10 +32,34 @@
|
|||||||
<a-icon v-if="inbound.settings.peers.length>1" type="delete" @click="() => inbound.settings.delPeer(index)"
|
<a-icon v-if="inbound.settings.peers.length>1" type="delete" @click="() => inbound.settings.delPeer(index)"
|
||||||
style="color: rgb(255, 77, 79);cursor: pointer;"/>
|
style="color: rgb(255, 77, 79);cursor: pointer;"/>
|
||||||
</a-divider>
|
</a-divider>
|
||||||
<a-form-item label='{{ i18n "pages.xray.wireguard.publicKey" }}'>
|
<a-form-item>
|
||||||
|
<template slot="label">
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
<span>{{ i18n "reset" }}</span>
|
||||||
|
</template>
|
||||||
|
{{ i18n "pages.xray.wireguard.secretKey" }}
|
||||||
|
<a-icon @click="[peer.publicKey, peer.privateKey] = Object.values(Wireguard.generateKeypair())"type="sync"> </a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-input v-model.trim="peer.privateKey"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<template slot="label">
|
||||||
|
{{ i18n "pages.xray.wireguard.publicKey" }}
|
||||||
|
</template>
|
||||||
<a-input v-model.trim="peer.publicKey"></a-input>
|
<a-input v-model.trim="peer.publicKey"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.xray.wireguard.psk" }}'>
|
<a-form-item>
|
||||||
|
<template slot="label">
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
<span>{{ i18n "reset" }}</span>
|
||||||
|
</template>
|
||||||
|
{{ i18n "pages.xray.wireguard.psk" }}
|
||||||
|
<a-icon @click="peer.psk = Wireguard.keyToBase64(Wireguard.generatePresharedKey())"type="sync"> </a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
<a-input v-model.trim="peer.psk"></a-input>
|
<a-input v-model.trim="peer.psk"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{{define "form/sniffing"}}
|
{{define "form/sniffing"}}
|
||||||
<a-divider style="margin:0;"></a-divider>
|
<a-divider style="margin:0;"></a-divider>
|
||||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
Sniffing
|
Sniffing
|
||||||
|
|||||||
@@ -4,57 +4,60 @@
|
|||||||
<a-form-item label="PROXY Protocol" v-if="inbound.canEnableTls()">
|
<a-form-item label="PROXY Protocol" v-if="inbound.canEnableTls()">
|
||||||
<a-switch v-model="inbound.stream.tcp.acceptProxyProtocol"></a-switch>
|
<a-switch v-model="inbound.stream.tcp.acceptProxyProtocol"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="HTTP {{ i18n "camouflage" }}">
|
<a-form-item label='HTTP {{ i18n "camouflage" }}'>
|
||||||
<a-switch
|
<a-switch :checked="inbound.stream.tcp.type === 'http'"
|
||||||
:checked="inbound.stream.tcp.type === 'http'"
|
|
||||||
@change="checked => inbound.stream.tcp.type = checked ? 'http' : 'none'">
|
@change="checked => inbound.stream.tcp.type = checked ? 'http' : 'none'">
|
||||||
</a-switch>
|
</a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|
||||||
<a-form v-if="inbound.stream.tcp.type === 'http'" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
<a-form v-if="inbound.stream.tcp.type === 'http'" :colon="false" :label-col="{ md: {span:8} }"
|
||||||
|
:wrapper-col="{ md: {span:14} }">
|
||||||
<!-- tcp request -->
|
<!-- tcp request -->
|
||||||
<a-divider style="margin:0;">{{ i18n "pages.inbounds.stream.general.requestHeader" }}</a-divider>
|
<a-divider style="margin:0;">{{ i18n "pages.inbounds.stream.general.request" }}</a-divider>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestVersion" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.version" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.tcp.request.version"></a-input>
|
<a-input v-model.trim="inbound.stream.tcp.request.version"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestMethod" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.method" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.tcp.request.method"></a-input>
|
<a-input v-model.trim="inbound.stream.tcp.request.method"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<template slot="label">{{ i18n "pages.inbounds.stream.tcp.requestPath" }}
|
<template slot="label">{{ i18n "pages.inbounds.stream.tcp.path" }}
|
||||||
<a-button size="small" @click="inbound.stream.tcp.request.addPath('/')">+</a-button>
|
<a-button size="small" @click="inbound.stream.tcp.request.addPath('/')">+</a-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-for="(path, index) in inbound.stream.tcp.request.path">
|
<template v-for="(path, index) in inbound.stream.tcp.request.path">
|
||||||
<a-input v-model.trim="inbound.stream.tcp.request.path[index]">
|
<a-input v-model.trim="inbound.stream.tcp.request.path[index]">
|
||||||
<a-button size="small" slot="addonAfter"
|
<a-button size="small" slot="addonAfter" @click="inbound.stream.tcp.request.removePath(index)"
|
||||||
@click="inbound.stream.tcp.request.removePath(index)"
|
v-if="inbound.stream.tcp.request.path.length>1">-</a-button>
|
||||||
v-if="inbound.stream.tcp.request.path.length>1">-</a-button>
|
|
||||||
</a-input>
|
</a-input>
|
||||||
</template>
|
</template>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.general.requestHeader" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
|
||||||
<a-button size="small" @click="inbound.stream.tcp.request.addHeader('', '')">+</a-button>
|
<a-button size="small" @click="inbound.stream.tcp.request.addHeader('', '')">+</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :wrapper-col="{span:24}">
|
<a-form-item :wrapper-col="{span:24}">
|
||||||
<a-input-group compact v-for="(header, index) in inbound.stream.tcp.request.headers">
|
<a-input-group compact v-for="(header, index) in inbound.stream.tcp.request.headers">
|
||||||
<a-input style="width: 50%" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
|
<a-input style="width: 50%" v-model.trim="header.name"
|
||||||
|
placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
|
||||||
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
|
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
<a-input style="width: 50%" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
|
<a-input style="width: 50%" v-model.trim="header.value"
|
||||||
<a-button slot="addonAfter" size="small" @click="inbound.stream.tcp.request.removeHeader(index)">-</a-button>
|
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
|
||||||
|
<a-button slot="addonAfter" size="small"
|
||||||
|
@click="inbound.stream.tcp.request.removeHeader(index)">-</a-button>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-input-group>
|
</a-input-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<!-- tcp response -->
|
<!-- tcp response -->
|
||||||
<a-divider style="margin:0;">{{ i18n "pages.inbounds.stream.tcp.responseHeader" }}</a-divider>
|
<a-divider style="margin:0;">{{ i18n "pages.inbounds.stream.general.response" }}</a-divider>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseVersion" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.version" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.tcp.response.version"></a-input>
|
<a-input v-model.trim="inbound.stream.tcp.response.version"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseStatus" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.status" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.tcp.response.status"></a-input>
|
<a-input v-model.trim="inbound.stream.tcp.response.status"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseStatusDescription" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.statusDescription" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.tcp.response.reason"></a-input>
|
<a-input v-model.trim="inbound.stream.tcp.response.reason"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseHeader" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseHeader" }}'>
|
||||||
@@ -63,11 +66,12 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :wrapper-col="{span:24}">
|
<a-form-item :wrapper-col="{span:24}">
|
||||||
<a-input-group compact v-for="(header, index) in inbound.stream.tcp.response.headers">
|
<a-input-group compact v-for="(header, index) in inbound.stream.tcp.response.headers">
|
||||||
<a-input style="width: 50%" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
|
<a-input style="width: 50%" v-model.trim="header.name"
|
||||||
|
placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
|
||||||
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
|
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
<a-input style="width: 50%" v-model.trim="header.value"
|
<a-input style="width: 50%" v-model.trim="header.value"
|
||||||
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
|
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
|
||||||
<template slot="addonAfter">
|
<template slot="addonAfter">
|
||||||
<a-button size="small" @click="inbound.stream.tcp.response.removeHeader(index)">-</a-button>
|
<a-button size="small" @click="inbound.stream.tcp.response.removeHeader(index)">-</a-button>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<a-form-item label='{{ i18n "path" }}'>
|
<a-form-item label='{{ i18n "path" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.ws.path"></a-input>
|
<a-input v-model.trim="inbound.stream.ws.path"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.general.requestHeader" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
|
||||||
<a-button size="small" @click="inbound.stream.ws.addHeader()">+</a-button>
|
<a-button size="small" @click="inbound.stream.ws.addHeader()">+</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :wrapper-col="{span:24}">
|
<a-form-item :wrapper-col="{span:24}">
|
||||||
|
|||||||
@@ -23,10 +23,10 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Min/Max Version">
|
<a-form-item label="Min/Max Version">
|
||||||
<a-input-group compact>
|
<a-input-group compact>
|
||||||
<a-select v-model="inbound.stream.tls.minVersion" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select v-model="inbound.stream.tls.minVersion" style="width:100px;" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
<a-select v-model="inbound.stream.tls.maxVersion" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select v-model="inbound.stream.tls.maxVersion" style="width:100px;" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-input-group>
|
</a-input-group>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@
|
|||||||
<template v-if="app.subSettings.enable && infoModal.clientSettings.subId">
|
<template v-if="app.subSettings.enable && infoModal.clientSettings.subId">
|
||||||
<a-divider>Subscription URL</a-divider>
|
<a-divider>Subscription URL</a-divider>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :sx="24" :md="22"><a :href="[[ infoModal.subLink ]]" target="_blank">[[ infoModal.subLink ]]</a></a-col>
|
<a-col :sx="24" :md="22">SUB: <a :href="[[ infoModal.subLink ]]" target="_blank">[[ infoModal.subLink ]]</a></a-col>
|
||||||
<a-col :sx="24" :md="2" style="text-align: right;">
|
<a-col :sx="24" :md="2" style="text-align: right;">
|
||||||
<a-tooltip title='{{ i18n "copy" }}'>
|
<a-tooltip title='{{ i18n "copy" }}'>
|
||||||
<button class="ant-btn ant-btn-primary" id="copy-sub-link" @click="copyToClipboard('copy-sub-link', infoModal.subLink)">
|
<button class="ant-btn ant-btn-primary" id="copy-sub-link" @click="copyToClipboard('copy-sub-link', infoModal.subLink)">
|
||||||
@@ -171,6 +171,16 @@
|
|||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
<a-row>
|
||||||
|
<a-col :sx="24" :md="22">JSON: <a :href="[[ infoModal.subJsonLink ]]" target="_blank">[[ infoModal.subJsonLink ]]</a></a-col>
|
||||||
|
<a-col :sx="24" :md="2" style="text-align: right;">
|
||||||
|
<a-tooltip title='{{ i18n "copy" }}'>
|
||||||
|
<button class="ant-btn ant-btn-primary" id="copy-subJson-link" @click="copyToClipboard('copy-subJson-link', infoModal.subJsonLink)">
|
||||||
|
<a-icon type="snippets"></a-icon>
|
||||||
|
</button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="app.tgBotEnable && infoModal.clientSettings.tgId">
|
<template v-if="app.tgBotEnable && infoModal.clientSettings.tgId">
|
||||||
<a-divider>Telegram ID</a-divider>
|
<a-divider>Telegram ID</a-divider>
|
||||||
@@ -279,24 +289,50 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<template v-for="(peer, index) in inbound.settings.peers">
|
<template v-for="(peer, index) in inbound.settings.peers">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><a-tag>Peer [[ index + 1 ]]</a-tag></td>
|
<td colspan="2"><a-divider>Peer [[ index + 1 ]]</a-divider></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="client-table-odd-row">
|
<tr class="client-table-odd-row">
|
||||||
|
<td>{{ i18n "pages.xray.wireguard.secretKey" }}</td>
|
||||||
|
<td>[[ peer.privateKey ]]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td>{{ i18n "pages.xray.wireguard.publicKey" }}</td>
|
<td>{{ i18n "pages.xray.wireguard.publicKey" }}</td>
|
||||||
<td>[[ peer.publicKey ]]</td>
|
<td>[[ peer.publicKey ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr class="client-table-odd-row">
|
||||||
<td>{{ i18n "pages.xray.wireguard.psk" }}</td>
|
<td>{{ i18n "pages.xray.wireguard.psk" }}</td>
|
||||||
<td>[[ peer.psk ]]</td>
|
<td>[[ peer.psk ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="client-table-odd-row">
|
<tr>
|
||||||
<td>{{ i18n "pages.xray.wireguard.allowedIPs" }}</td>
|
<td>{{ i18n "pages.xray.wireguard.allowedIPs" }}</td>
|
||||||
<td>[[ peer.allowedIPs.join(",") ]]</td>
|
<td>[[ peer.allowedIPs.join(",") ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr class="client-table-odd-row">
|
||||||
<td>Keep Alive</td>
|
<td>Keep Alive</td>
|
||||||
<td>[[ peer.keepAlive ]]</td>
|
<td>[[ peer.keepAlive ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="22" style="overflow-wrap: anywhere;">
|
||||||
|
<a-tag color="blue">Config</a-tag>
|
||||||
|
<div
|
||||||
|
v-html="infoModal.links[index].replaceAll(`\n`,`<br />`)"
|
||||||
|
style="border-radius: 1rem; padding: 0.5rem;"
|
||||||
|
class="client-table-odd-row"></div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="2" style="text-align: right;">
|
||||||
|
<a-tooltip title='{{ i18n "copy" }}'>
|
||||||
|
<button class="ant-btn ant-btn-primary"
|
||||||
|
:id="'copy-url-link-'+index"
|
||||||
|
@click="copyToClipboard('copy-url-link-'+index, infoModal.links[index])">
|
||||||
|
<a-icon type="snippets"></a-icon>
|
||||||
|
</button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@@ -315,6 +351,7 @@
|
|||||||
index: null,
|
index: null,
|
||||||
isExpired: false,
|
isExpired: false,
|
||||||
subLink: '',
|
subLink: '',
|
||||||
|
subJsonLink: '',
|
||||||
tgLink: '',
|
tgLink: '',
|
||||||
show(dbInbound, index) {
|
show(dbInbound, index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
@@ -323,10 +360,15 @@
|
|||||||
this.clientSettings = this.inbound.clients ? this.inbound.clients[index] : null;
|
this.clientSettings = this.inbound.clients ? this.inbound.clients[index] : null;
|
||||||
this.isExpired = this.inbound.clients ? this.inbound.isExpiry(index): this.dbInbound.isExpiry;
|
this.isExpired = this.inbound.clients ? this.inbound.isExpiry(index): this.dbInbound.isExpiry;
|
||||||
this.clientStats = this.inbound.clients ? this.dbInbound.clientStats.find(row => row.email === this.clientSettings.email) : [];
|
this.clientStats = this.inbound.clients ? this.dbInbound.clientStats.find(row => row.email === this.clientSettings.email) : [];
|
||||||
this.links = this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, this.clientSettings);
|
if (this.inbound.protocol == Protocols.WIREGUARD){
|
||||||
|
this.links = this.inbound.genInboundLinks(dbInbound.remark).split('\r\n')
|
||||||
|
} else {
|
||||||
|
this.links = this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, this.clientSettings);
|
||||||
|
}
|
||||||
if (this.clientSettings) {
|
if (this.clientSettings) {
|
||||||
if (this.clientSettings.subId) {
|
if (this.clientSettings.subId) {
|
||||||
this.subLink = this.genSubLink(this.clientSettings.subId);
|
this.subLink = this.genSubLink(this.clientSettings.subId);
|
||||||
|
this.subJsonLink = this.genSubJsonLink(this.clientSettings.subId);
|
||||||
}
|
}
|
||||||
if (this.clientSettings.tgId) {
|
if (this.clientSettings.tgId) {
|
||||||
this.tgLink = "https://t.me/" + this.clientSettings.tgId;
|
this.tgLink = "https://t.me/" + this.clientSettings.tgId;
|
||||||
@@ -339,6 +381,9 @@
|
|||||||
},
|
},
|
||||||
genSubLink(subID) {
|
genSubLink(subID) {
|
||||||
return app.subSettings.subURI+subID+'?name='+subID;
|
return app.subSettings.subURI+subID+'?name='+subID;
|
||||||
|
},
|
||||||
|
genSubJsonLink(subID) {
|
||||||
|
return app.subSettings.subJsonURI+subID+'?name='+subID;;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
title: '',
|
title: '',
|
||||||
visible: false,
|
visible: false,
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
okText: '{{ i18n "sure" }}',
|
okText: '{{ i18n "confirm" }}',
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
confirm: null,
|
confirm: null,
|
||||||
inbound: new Inbound(),
|
inbound: new Inbound(),
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
ok() {
|
ok() {
|
||||||
ObjectUtil.execute(inModal.confirm, inModal.inbound, inModal.dbInbound);
|
ObjectUtil.execute(inModal.confirm, inModal.inbound, inModal.dbInbound);
|
||||||
},
|
},
|
||||||
show({ title='', okText='{{ i18n "sure" }}', inbound=null, dbInbound=null, confirm=(inbound, dbInbound)=>{}, isEdit=false }) {
|
show({ title='', okText='{{ i18n "confirm" }}', inbound=null, dbInbound=null, confirm=(inbound, dbInbound)=>{}, isEdit=false }) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.okText = okText;
|
this.okText = okText;
|
||||||
if (inbound) {
|
if (inbound) {
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
inModal.visible = false;
|
inModal.visible = false;
|
||||||
inModal.loading(false);
|
inModal.loading(false);
|
||||||
},
|
},
|
||||||
loading(loading) {
|
loading(loading=true) {
|
||||||
inModal.confirmLoading = loading;
|
inModal.confirmLoading = loading;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,15 +68,15 @@
|
|||||||
<a-card hoverable>
|
<a-card hoverable>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :xs="24" :sm="24" :lg="12">
|
<a-col :xs="24" :sm="24" :lg="12">
|
||||||
{{ i18n "pages.inbounds.totalDownUp" }}:
|
<strong>{{ i18n "pages.inbounds.totalDownUp" }}:</strong>
|
||||||
<a-tag color="blue">[[ sizeFormat(total.up) ]] / [[ sizeFormat(total.down) ]]</a-tag>
|
<a-tag color="blue">[[ sizeFormat(total.up) ]] / [[ sizeFormat(total.down) ]]</a-tag>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :xs="24" :sm="24" :lg="12">
|
<a-col :xs="24" :sm="24" :lg="12">
|
||||||
{{ i18n "pages.inbounds.totalUsage" }}:
|
<strong>{{ i18n "pages.inbounds.totalUsage" }}:</strong>
|
||||||
<a-tag color="blue">[[ sizeFormat(total.up + total.down) ]]</a-tag>
|
<a-tag color="blue">[[ sizeFormat(total.up + total.down) ]]</a-tag>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :xs="24" :sm="24" :lg="12">
|
<a-col :xs="24" :sm="24" :lg="12">
|
||||||
{{ i18n "pages.inbounds.inboundCount" }}:
|
<strong>{{ i18n "pages.inbounds.inboundCount" }}:</strong>
|
||||||
<a-tag color="blue">[[ dbInbounds.length ]]</a-tag>
|
<a-tag color="blue">[[ dbInbounds.length ]]</a-tag>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :xs="24" :sm="24" :lg="12">
|
<a-col :xs="24" :sm="24" :lg="12">
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<a-back-top :target="() => document.getElementById('content-layout')" visibility-height="200">
|
<a-back-top :target="() => document.getElementById('content-layout')" visibility-height="200">
|
||||||
</a-back-top>
|
</a-back-top>
|
||||||
{{ i18n "clients" }}:
|
<strong>{{ i18n "clients" }}:</strong>
|
||||||
<a-tag color="blue">[[ total.clients ]]</a-tag>
|
<a-tag color="blue">[[ total.clients ]]</a-tag>
|
||||||
<a-popover title='{{ i18n "disabled" }}' :overlay-class-name="themeSwitcher.currentTheme">
|
<a-popover title='{{ i18n "disabled" }}' :overlay-class-name="themeSwitcher.currentTheme">
|
||||||
<template slot="content">
|
<template slot="content">
|
||||||
@@ -137,6 +137,10 @@
|
|||||||
<a-icon type="export"></a-icon>
|
<a-icon type="export"></a-icon>
|
||||||
{{ i18n "pages.inbounds.export" }}
|
{{ i18n "pages.inbounds.export" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
<a-menu-item key="subs" v-if="subSettings.enable">
|
||||||
|
<a-icon type="export"></a-icon>
|
||||||
|
{{ i18n "pages.inbounds.export" }} - {{ i18n "pages.settings.subSettings" }}
|
||||||
|
</a-menu-item>
|
||||||
<a-menu-item key="resetInbounds">
|
<a-menu-item key="resetInbounds">
|
||||||
<a-icon type="reload"></a-icon>
|
<a-icon type="reload"></a-icon>
|
||||||
{{ i18n "pages.inbounds.resetAllTraffic" }}
|
{{ i18n "pages.inbounds.resetAllTraffic" }}
|
||||||
@@ -145,7 +149,7 @@
|
|||||||
<a-icon type="file-done"></a-icon>
|
<a-icon type="file-done"></a-icon>
|
||||||
{{ i18n "pages.inbounds.resetAllClientTraffics" }}
|
{{ i18n "pages.inbounds.resetAllClientTraffics" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="delDepletedClients">
|
<a-menu-item key="delDepletedClients" style="color: #FF4D4F;">
|
||||||
<a-icon type="rest"></a-icon>
|
<a-icon type="rest"></a-icon>
|
||||||
{{ i18n "pages.inbounds.delDepletedClients" }}
|
{{ i18n "pages.inbounds.delDepletedClients" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -199,7 +203,7 @@
|
|||||||
<a-icon type="edit"></a-icon>
|
<a-icon type="edit"></a-icon>
|
||||||
{{ i18n "edit" }}
|
{{ i18n "edit" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="qrcode" v-if="dbInbound.isSS && !dbInbound.toInbound().isSSMultiUser">
|
<a-menu-item key="qrcode" v-if="(dbInbound.isSS && !dbInbound.toInbound().isSSMultiUser) || dbInbound.isWireguard">
|
||||||
<a-icon type="qrcode"></a-icon>
|
<a-icon type="qrcode"></a-icon>
|
||||||
{{ i18n "qrCode" }}
|
{{ i18n "qrCode" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -220,7 +224,11 @@
|
|||||||
<a-icon type="export"></a-icon>
|
<a-icon type="export"></a-icon>
|
||||||
{{ i18n "pages.inbounds.export"}}
|
{{ i18n "pages.inbounds.export"}}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="delDepletedClients">
|
<a-menu-item key="subs" v-if="subSettings.enable">
|
||||||
|
<a-icon type="export"></a-icon>
|
||||||
|
{{ i18n "pages.inbounds.export"}} - {{ i18n "pages.settings.subSettings" }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item key="delDepletedClients" style="color: #FF4D4F;">
|
||||||
<a-icon type="rest"></a-icon>
|
<a-icon type="rest"></a-icon>
|
||||||
{{ i18n "pages.inbounds.delDepletedClients" }}
|
{{ i18n "pages.inbounds.delDepletedClients" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -236,7 +244,7 @@
|
|||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="clipboard">
|
<a-menu-item key="clipboard">
|
||||||
<a-icon type="copy"></a-icon>
|
<a-icon type="copy"></a-icon>
|
||||||
{{ i18n "pages.inbounds.copyToClipboard" }}
|
{{ i18n "pages.inbounds.exportInbound" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="clone">
|
<a-menu-item key="clone">
|
||||||
<a-icon type="block"></a-icon> {{ i18n "pages.inbounds.clone"}}
|
<a-icon type="block"></a-icon> {{ i18n "pages.inbounds.clone"}}
|
||||||
@@ -247,7 +255,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item v-if="isMobile">
|
<a-menu-item v-if="isMobile">
|
||||||
<a-switch size="small" v-model="dbInbound.enable" @change="switchEnable(dbInbound.id)"></a-switch>
|
<a-switch size="small" v-model="dbInbound.enable" @change="switchEnable(dbInbound.id,dbInbound.enable)"></a-switch>
|
||||||
{{ i18n "pages.inbounds.enable" }}
|
{{ i18n "pages.inbounds.enable" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
@@ -314,7 +322,7 @@
|
|||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
<template slot="enable" slot-scope="text, dbInbound">
|
<template slot="enable" slot-scope="text, dbInbound">
|
||||||
<a-switch v-model="dbInbound.enable" @change="switchEnable(dbInbound.id)"></a-switch>
|
<a-switch v-model="dbInbound.enable" @change="switchEnable(dbInbound.id,dbInbound.enable)"></a-switch>
|
||||||
</template>
|
</template>
|
||||||
<template slot="expiryTime" slot-scope="text, dbInbound">
|
<template slot="expiryTime" slot-scope="text, dbInbound">
|
||||||
<a-popover v-if="dbInbound.expiryTime > 0" :overlay-class-name="themeSwitcher.currentTheme">
|
<a-popover v-if="dbInbound.expiryTime > 0" :overlay-class-name="themeSwitcher.currentTheme">
|
||||||
@@ -556,7 +564,8 @@
|
|||||||
refreshInterval: Number(localStorage.getItem("refreshInterval")) || 5000,
|
refreshInterval: Number(localStorage.getItem("refreshInterval")) || 5000,
|
||||||
subSettings: {
|
subSettings: {
|
||||||
enable : false,
|
enable : false,
|
||||||
subURI : ''
|
subURI : '',
|
||||||
|
subJsonURI : '',
|
||||||
},
|
},
|
||||||
remarkModel: '-ieo',
|
remarkModel: '-ieo',
|
||||||
tgBotEnable: false,
|
tgBotEnable: false,
|
||||||
@@ -601,7 +610,8 @@
|
|||||||
this.tgBotEnable = tgBotEnable;
|
this.tgBotEnable = tgBotEnable;
|
||||||
this.subSettings = {
|
this.subSettings = {
|
||||||
enable : subEnable,
|
enable : subEnable,
|
||||||
subURI: subURI
|
subURI: subURI,
|
||||||
|
subJsonURI: subJsonURI
|
||||||
};
|
};
|
||||||
this.pageSize = pageSize;
|
this.pageSize = pageSize;
|
||||||
this.remarkModel = remarkModel;
|
this.remarkModel = remarkModel;
|
||||||
@@ -638,8 +648,12 @@
|
|||||||
clientCount = clients.length;
|
clientCount = clients.length;
|
||||||
if (dbInbound.enable) {
|
if (dbInbound.enable) {
|
||||||
clients.forEach(client => {
|
clients.forEach(client => {
|
||||||
client.enable ? active.push(client.email) : deactive.push(client.email);
|
if (client.enable) {
|
||||||
if(this.isClientOnline(client.email)) online.push(client.email);
|
active.push(client.email);
|
||||||
|
if(this.isClientOnline(client.email)) online.push(client.email);
|
||||||
|
} else {
|
||||||
|
deactive.push(client.email);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
clientStats.forEach(client => {
|
clientStats.forEach(client => {
|
||||||
if (!client.enable) {
|
if (!client.enable) {
|
||||||
@@ -727,6 +741,9 @@
|
|||||||
case "export":
|
case "export":
|
||||||
this.exportAllLinks();
|
this.exportAllLinks();
|
||||||
break;
|
break;
|
||||||
|
case "subs":
|
||||||
|
this.exportAllSubs();
|
||||||
|
break;
|
||||||
case "resetInbounds":
|
case "resetInbounds":
|
||||||
this.resetAllTraffic();
|
this.resetAllTraffic();
|
||||||
break;
|
break;
|
||||||
@@ -758,6 +775,9 @@
|
|||||||
case "export":
|
case "export":
|
||||||
this.inboundLinks(dbInbound.id);
|
this.inboundLinks(dbInbound.id);
|
||||||
break;
|
break;
|
||||||
|
case "subs":
|
||||||
|
this.exportSubs(dbInbound.id);
|
||||||
|
break;
|
||||||
case "clipboard":
|
case "clipboard":
|
||||||
this.copyToClipboard(dbInbound.id);
|
this.copyToClipboard(dbInbound.id);
|
||||||
break;
|
break;
|
||||||
@@ -836,8 +856,8 @@
|
|||||||
port: RandomUtil.randomIntRange(10000, 60000),
|
port: RandomUtil.randomIntRange(10000, 60000),
|
||||||
protocol: baseInbound.protocol,
|
protocol: baseInbound.protocol,
|
||||||
settings: Inbound.Settings.getSettings(baseInbound.protocol).toString(),
|
settings: Inbound.Settings.getSettings(baseInbound.protocol).toString(),
|
||||||
streamSettings: baseInbound.stream.toString(),
|
streamSettings: baseInbound.stream.toString(),
|
||||||
sniffing: baseInbound.canSniffing() ? baseInbound.sniffing.toString() : '{}',
|
sniffing: baseInbound.sniffing.toString(),
|
||||||
};
|
};
|
||||||
await this.submit('/xui/inbound/add', data, inModal);
|
await this.submit('/xui/inbound/add', data, inModal);
|
||||||
},
|
},
|
||||||
@@ -856,7 +876,7 @@
|
|||||||
settings: inbound.settings.toString(),
|
settings: inbound.settings.toString(),
|
||||||
};
|
};
|
||||||
if (inbound.canEnableStream()) data.streamSettings = inbound.stream.toString();
|
if (inbound.canEnableStream()) data.streamSettings = inbound.stream.toString();
|
||||||
if (inbound.canSniffing()) data.sniffing = inbound.sniffing.toString();
|
data.sniffing = inbound.sniffing.toString();
|
||||||
|
|
||||||
await this.submit('/xui/inbound/add', data, inModal);
|
await this.submit('/xui/inbound/add', data, inModal);
|
||||||
},
|
},
|
||||||
@@ -875,7 +895,7 @@
|
|||||||
settings: inbound.settings.toString(),
|
settings: inbound.settings.toString(),
|
||||||
};
|
};
|
||||||
if (inbound.canEnableStream()) data.streamSettings = inbound.stream.toString();
|
if (inbound.canEnableStream()) data.streamSettings = inbound.stream.toString();
|
||||||
if (inbound.canSniffing()) data.sniffing = inbound.sniffing.toString();
|
data.sniffing = inbound.sniffing.toString();
|
||||||
|
|
||||||
await this.submit(`/xui/inbound/update/${dbInbound.id}`, data, inModal);
|
await this.submit(`/xui/inbound/update/${dbInbound.id}`, data, inModal);
|
||||||
},
|
},
|
||||||
@@ -1030,9 +1050,9 @@
|
|||||||
newDbInbound = this.checkFallback(dbInbound);
|
newDbInbound = this.checkFallback(dbInbound);
|
||||||
infoModal.show(newDbInbound, index);
|
infoModal.show(newDbInbound, index);
|
||||||
},
|
},
|
||||||
switchEnable(dbInboundId) {
|
switchEnable(dbInboundId,state) {
|
||||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
dbInbound.enable = !dbInbound.enable;
|
dbInbound.enable = state;
|
||||||
this.submit(`/xui/inbound/update/${dbInboundId}`, dbInbound);
|
this.submit(`/xui/inbound/update/${dbInboundId}`, dbInbound);
|
||||||
},
|
},
|
||||||
async switchEnableClient(dbInboundId, client) {
|
async switchEnableClient(dbInboundId, client) {
|
||||||
@@ -1182,6 +1202,22 @@
|
|||||||
newDbInbound = this.checkFallback(dbInbound);
|
newDbInbound = this.checkFallback(dbInbound);
|
||||||
txtModal.show('{{ i18n "pages.inbounds.export"}}', newDbInbound.genInboundLinks(this.remarkModel), newDbInbound.remark);
|
txtModal.show('{{ i18n "pages.inbounds.export"}}', newDbInbound.genInboundLinks(this.remarkModel), newDbInbound.remark);
|
||||||
},
|
},
|
||||||
|
exportSubs(dbInboundId) {
|
||||||
|
const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
|
const clients = this.getInboundClients(dbInbound);
|
||||||
|
let subLinks = []
|
||||||
|
if (clients != null){
|
||||||
|
clients.forEach(c => {
|
||||||
|
if (c.subId && c.subId.length>0){
|
||||||
|
subLinks.push(this.subSettings.subURI + c.subId + "?name=" + c.subId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
txtModal.show(
|
||||||
|
'{{ i18n "pages.inbounds.export"}} - {{ i18n "pages.settings.subSettings" }}',
|
||||||
|
[...new Set(subLinks)].join('\n'),
|
||||||
|
dbInbound.remark + "-Subs");
|
||||||
|
},
|
||||||
importInbound() {
|
importInbound() {
|
||||||
promptModal.open({
|
promptModal.open({
|
||||||
title: '{{ i18n "pages.inbounds.importInbound" }}',
|
title: '{{ i18n "pages.inbounds.importInbound" }}',
|
||||||
@@ -1194,7 +1230,24 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
exportAllLinks() {
|
exportAllSubs() {
|
||||||
|
let subLinks = []
|
||||||
|
for (const dbInbound of this.dbInbounds) {
|
||||||
|
const clients = this.getInboundClients(dbInbound);
|
||||||
|
if (clients != null){
|
||||||
|
clients.forEach(c => {
|
||||||
|
if (c.subId && c.subId.length>0){
|
||||||
|
subLinks.push(this.subSettings.subURI + c.subId + "?name=" + c.subId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
txtModal.show(
|
||||||
|
'{{ i18n "pages.inbounds.export"}} - {{ i18n "pages.settings.subSettings" }}',
|
||||||
|
[...new Set(subLinks)].join('\r\n'),
|
||||||
|
'All-Inbounds-Subs');
|
||||||
|
},
|
||||||
|
exportAllLinks() {
|
||||||
let copyText = [];
|
let copyText = [];
|
||||||
for (const dbInbound of this.dbInbounds) {
|
for (const dbInbound of this.dbInbounds) {
|
||||||
copyText.push(dbInbound.genInboundLinks(this.remarkModel));
|
copyText.push(dbInbound.genInboundLinks(this.remarkModel));
|
||||||
|
|||||||
@@ -44,14 +44,14 @@
|
|||||||
<a-progress type="dashboard" status="normal"
|
<a-progress type="dashboard" status="normal"
|
||||||
:stroke-color="status.cpu.color"
|
:stroke-color="status.cpu.color"
|
||||||
:percent="status.cpu.percent"></a-progress>
|
:percent="status.cpu.percent"></a-progress>
|
||||||
<div>CPU: [[ cpuCoreFormat(status.cpuCount) ]]</div>
|
<div><strong>CPU:</strong> [[ cpuCoreFormat(status.cpuCount) ]]</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12" style="text-align: center">
|
<a-col :span="12" style="text-align: center">
|
||||||
<a-progress type="dashboard" status="normal"
|
<a-progress type="dashboard" status="normal"
|
||||||
:stroke-color="status.mem.color"
|
:stroke-color="status.mem.color"
|
||||||
:percent="status.mem.percent"></a-progress>
|
:percent="status.mem.percent"></a-progress>
|
||||||
<div>
|
<div>
|
||||||
{{ i18n "pages.index.memory"}}: [[ sizeFormat(status.mem.current) ]] / [[ sizeFormat(status.mem.total) ]]
|
<strong>{{ i18n "pages.index.memory"}}:</strong> [[ sizeFormat(status.mem.current) ]] / [[ sizeFormat(status.mem.total) ]]
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
:stroke-color="status.swap.color"
|
:stroke-color="status.swap.color"
|
||||||
:percent="status.swap.percent"></a-progress>
|
:percent="status.swap.percent"></a-progress>
|
||||||
<div>
|
<div>
|
||||||
Swap: [[ sizeFormat(status.swap.current) ]] / [[ sizeFormat(status.swap.total) ]]
|
<strong>Swap:</strong> [[ sizeFormat(status.swap.current) ]] / [[ sizeFormat(status.swap.total) ]]
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12" style="text-align: center">
|
<a-col :span="12" style="text-align: center">
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
:stroke-color="status.disk.color"
|
:stroke-color="status.disk.color"
|
||||||
:percent="status.disk.percent"></a-progress>
|
:percent="status.disk.percent"></a-progress>
|
||||||
<div>
|
<div>
|
||||||
{{ i18n "pages.index.hard"}}: [[ sizeFormat(status.disk.current) ]] / [[ sizeFormat(status.disk.total) ]]
|
<strong>{{ i18n "pages.index.hard"}}:</strong> [[ sizeFormat(status.disk.current) ]] / [[ sizeFormat(status.disk.total) ]]
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
@@ -84,32 +84,36 @@
|
|||||||
<a-row>
|
<a-row>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable>
|
||||||
X-UI <a href="https://github.com/alireza0/x-ui/releases" target="_blank"><a-tag color="blue">{{ .cur_ver }}</a-tag></a>
|
<strong>{{ i18n "pages.inbounds.stream.tcp.version" }}:</strong>
|
||||||
Xray
|
<a href="https://github.com/alireza0/x-ui/releases" target="_blank">
|
||||||
|
<a-tag color="purple" style="cursor: pointer;">X-UI {{ .cur_ver }}</a-tag>
|
||||||
|
</a>
|
||||||
<a-tooltip title='{{ i18n "pages.index.xraySwitch" }}'>
|
<a-tooltip title='{{ i18n "pages.index.xraySwitch" }}'>
|
||||||
<a-tag color="blue" style="cursor: pointer;" @click="openSelectV2rayVersion">[[ status.xray.version ]]</a-tag>
|
<a-tag color="purple" style="cursor: pointer;" @click="openSelectV2rayVersion">Xray [[ status.xray.version ]]</a-tag>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable>
|
||||||
{{ i18n "pages.index.operationHours" }}:
|
<strong>{{ i18n "pages.index.operationHours" }}:</strong>
|
||||||
Xray
|
<a-tooltip>
|
||||||
<a-tag color="blue">[[ formatSecond(status.appStats.uptime) ]]</a-tag>
|
<template slot="title">
|
||||||
OS
|
{{ i18n "pages.index.xrayoperationHoursDesc" }}
|
||||||
|
</template>
|
||||||
|
<a-tag color="blue" style="margin-right: 3px;">Xray [[ formatSecond(status.appStats.uptime) ]]</a-tag>
|
||||||
|
</a-tooltip>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.operationHoursDesc" }}
|
{{ i18n "pages.index.operationHoursDesc" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<a-tag color="blue">OS [[ formatSecond(status.uptime) ]]</a-tag>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tag color="blue">[[ formatSecond(status.uptime) ]]</a-tag>
|
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable>
|
||||||
{{ i18n "pages.index.xrayStatus" }}:
|
<strong>{{ i18n "pages.index.xrayStatus" }}:</strong>
|
||||||
<a-tag :color="status.xray.color">[[ status.xray.state ]]</a-tag>
|
<a-tag :color="status.xray.color" style="margin-right: 3px;"><strong>[[ status.xray.state ]]</strong></a-tag>
|
||||||
<a-popover v-if="status.xray.state === State.Error"
|
<a-popover v-if="status.xray.state === State.Error"
|
||||||
:overlay-class-name="themeSwitcher.currentTheme">
|
:overlay-class-name="themeSwitcher.currentTheme">
|
||||||
<span slot="title" style="font-size: 12pt">An error occurred while running Xray
|
<span slot="title" style="font-size: 12pt">An error occurred while running Xray
|
||||||
@@ -118,51 +122,62 @@
|
|||||||
<template slot="content">
|
<template slot="content">
|
||||||
<p style="max-width: 400px" v-for="line in status.xray.errorMsg.split('\n')">[[ line ]]</p>
|
<p style="max-width: 400px" v-for="line in status.xray.errorMsg.split('\n')">[[ line ]]</p>
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<a-icon type="exclamation-circle"></a-icon>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
<a-tag color="purple" style="cursor: pointer;" @click="stopXrayService">{{ i18n "pages.index.stopXray" }}</a-tag>
|
<a-tag color="purple" style="cursor: pointer; margin-right: 3px;" @click="stopXrayService">{{ i18n "pages.index.stopXray" }}</a-tag>
|
||||||
<a-tag color="purple" style="cursor: pointer;" @click="restartXrayService">{{ i18n "pages.index.restartXray" }}</a-tag>
|
<a-tag color="purple" style="cursor: pointer; margin-right: 3px;" @click="restartXrayService">{{ i18n "pages.index.restartXray" }}</a-tag>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable>
|
||||||
{{ i18n "menu.link" }}:
|
<strong>{{ i18n "menu.link" }}:</strong>
|
||||||
<a-tag color="purple" style="cursor: pointer;" @click="openLogs()">{{ i18n "pages.index.logs" }}</a-tag>
|
<a-tag color="purple" style="cursor: pointer; margin-right: 3px;" @click="openLogs()">{{ i18n "pages.index.logs" }}</a-tag>
|
||||||
<a-tag color="purple" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag>
|
<a-tag color="purple" style="cursor: pointer; margin-right: 3px;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag>
|
||||||
<a-tag color="purple" style="cursor: pointer;" @click="openBackup">{{ i18n "pages.index.backup" }}</a-tag>
|
<a-tag color="purple" style="cursor: pointer;" @click="openBackup">{{ i18n "pages.index.backup" }}</a-tag>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable>
|
||||||
{{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]]
|
<strong>{{ i18n "pages.index.systemLoad" }}:</strong>
|
||||||
</a-card>
|
|
||||||
</a-col>
|
|
||||||
<a-col :sm="24" :md="12">
|
|
||||||
<a-card hoverable>
|
|
||||||
{{ i18n "usage"}}:
|
|
||||||
RAM: [[ sizeFormat(status.appStats.mem) ]] -
|
|
||||||
Threads: [[ status.appStats.threads ]]
|
|
||||||
</a-tooltip>
|
|
||||||
</a-card>
|
|
||||||
</a-col>
|
|
||||||
<a-col :sm="24" :md="12">
|
|
||||||
<a-card hoverable>
|
|
||||||
Host: [[ status.hostInfo.hostname ]] -
|
|
||||||
<template v-if="status.hostInfo.ipv4">IPv4:
|
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
[[ status.hostInfo.ipv4 ]]
|
{{ i18n "pages.index.systemLoadDesc" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<a-tag color="blue">[[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]]</a-tag>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :sm="24" :md="12">
|
||||||
|
<a-card hoverable>
|
||||||
|
<strong>{{ i18n "usage" }}:</strong>
|
||||||
|
<a-tag color="blue" style="margin-right: 3px;">RAM [[ sizeFormat(status.appStats.mem) ]]</a-tag>
|
||||||
|
<a-tag color="blue">Threads [[ status.appStats.threads ]]</a-tag>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :sm="24" :md="12">
|
||||||
|
<a-card hoverable>
|
||||||
|
<strong>{{ i18n "pages.index.serverInfo" }}:</strong>
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
{{ i18n "pages.index.hostname" }}
|
||||||
|
</template>
|
||||||
|
<a-tag color="blue" style="margin-right: 3px;">[[ status.hostInfo.hostname ]]</a-tag>
|
||||||
|
</a-tooltip>
|
||||||
|
<template v-if="status.hostInfo.ipv4">
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
[[ status.hostInfo.ipv4 ]]
|
||||||
|
</template>
|
||||||
|
<a-tag color="blue" style="margin-right: 3px;">IPv4</a-tag>
|
||||||
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="status.hostInfo.ipv6">IPv6:
|
<template v-if="status.hostInfo.ipv6">
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
[[ status.hostInfo.ipv6 ]]
|
[[ status.hostInfo.ipv6 ]]
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<a-tag color="blue" style="margin-right: 3px;">IPv6</a-tag>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
@@ -170,21 +185,21 @@
|
|||||||
<a-card hoverable>
|
<a-card hoverable>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
TCP: [[ status.tcpCount ]]
|
<a-icon type="swap"></a-icon>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.connectionTcpCountDesc" }}
|
{{ i18n "pages.index.connectionTcpCountDesc" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<strong>TCP:</Strong> <a-tag>[[ status.tcpCount ]]</a-tag>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
UDP: [[ status.udpCount ]]
|
<a-icon type="swap"></a-icon>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.connectionUdpCountDesc" }}
|
{{ i18n "pages.index.connectionUdpCountDesc" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<strong>UDP:</strong> <a-tag>[[ status.udpCount ]]</a-tag>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
@@ -195,22 +210,20 @@
|
|||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<a-icon type="arrow-up"></a-icon>
|
<a-icon type="arrow-up"></a-icon>
|
||||||
[[ sizeFormat(status.netIO.up) ]]/s
|
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.upSpeed" }}
|
{{ i18n "pages.index.upSpeed" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<strong>Up:</strong> [[ sizeFormat(status.netIO.up) ]]/s
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<a-icon type="arrow-down"></a-icon>
|
<a-icon type="arrow-down"></a-icon>
|
||||||
[[ sizeFormat(status.netIO.down) ]]/s
|
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.downSpeed" }}
|
{{ i18n "pages.index.downSpeed" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<strong>Down:</strong> [[ sizeFormat(status.netIO.down) ]]/s
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
@@ -221,22 +234,20 @@
|
|||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<a-icon type="cloud-upload"></a-icon>
|
<a-icon type="cloud-upload"></a-icon>
|
||||||
[[ sizeFormat(status.netTraffic.sent) ]]
|
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.totalSent" }}
|
{{ i18n "pages.index.totalSent" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<strong>Out:</strong> [[ sizeFormat(status.netTraffic.sent) ]]
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<a-icon type="cloud-download"></a-icon>
|
<a-icon type="cloud-download"></a-icon>
|
||||||
[[ sizeFormat(status.netTraffic.recv) ]]
|
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.totalReceive" }}
|
{{ i18n "pages.index.totalReceive" }}
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle"></a-icon>
|
<strong>In:</strong> [[ sizeFormat(status.netTraffic.recv) ]]
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
@@ -263,52 +274,53 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
<a-modal id="log-modal" v-model="logModal.visible" title="Logs"
|
<a-modal id="log-modal" v-model="logModal.visible"
|
||||||
:closable="true" @ok="() => logModal.visible = false" @cancel="() => logModal.visible = false"
|
:closable="true" @cancel="() => logModal.visible = false"
|
||||||
:class="themeSwitcher.currentTheme"
|
:class="themeSwitcher.currentTheme"
|
||||||
width="800px"
|
width="800px" footer="">
|
||||||
footer="">
|
<template slot="title">
|
||||||
|
{{ i18n "pages.index.logs" }}
|
||||||
|
<a-icon :spin="logModal.loading"
|
||||||
|
type="sync"
|
||||||
|
style="vertical-align: middle; margin-left: 10px;"
|
||||||
|
:disabled="logModal.loading"
|
||||||
|
@click="openLogs()">
|
||||||
|
</a-icon>
|
||||||
|
</template>
|
||||||
<a-form layout="inline">
|
<a-form layout="inline">
|
||||||
<a-form-item label="Count">
|
<a-form-item>
|
||||||
<a-select v-model="logModal.rows"
|
<a-input-group compact>
|
||||||
style="width: 80px"
|
<a-select v-model="logModal.rows" style="width:70px;"
|
||||||
@change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
|
@change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<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>
|
||||||
<a-select-option value="50">50</a-select-option>
|
<a-select-option value="50">50</a-select-option>
|
||||||
<a-select-option value="100">100</a-select-option>
|
<a-select-option value="100">100</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
<a-select v-model="logModal.level" style="width:100px;"
|
||||||
<a-form-item label="Log Level">
|
@change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select v-model="logModal.level"
|
<a-select-option value="debug">Debug</a-select-option>
|
||||||
style="width: 120px"
|
<a-select-option value="info">Info</a-select-option>
|
||||||
@change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select-option value="warning">Warning</a-select-option>
|
||||||
<a-select-option value="debug">Debug</a-select-option>
|
<a-select-option value="err">Error</a-select-option>
|
||||||
<a-select-option value="info">Info</a-select-option>
|
</a-select>
|
||||||
<a-select-option value="warning">Warning</a-select-option>
|
</a-input-group>
|
||||||
<a-select-option value="err">Error</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</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>
|
<a-form-item>
|
||||||
<a-button class="ant-btn ant-btn-primary" :loading="logModal.loading" @click="openLogs()"><a-icon :spin="logModal.loading" type="sync"></a-icon> Reload</a-button>
|
<a-checkbox v-model="logModal.syslog" @change="openLogs()">SysLog</a-checkbox>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item style="float: right;">
|
||||||
<a-button type="primary" style="margin-bottom: 10px;"
|
<a-button type="primary" icon="download"
|
||||||
:href="'data:application/text;charset=utf-8,' + encodeURIComponent(logModal.logs)" download="x-ui.log">
|
:href="'data:application/text;charset=utf-8,' + encodeURIComponent(logModal.logs)" download="x-ui.log">
|
||||||
{{ i18n "download" }} x-ui.log
|
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
<div class="ant-input" style="height: auto; max-height: 500px; overflow: auto;" v-html="logModal.logs"></div>
|
<div class="ant-input" style="height: auto; max-height: 500px; overflow: auto;" v-html="logModal.formattedLogs"></div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
<a-modal id="backup-modal" v-model="backupModal.visible" :title="backupModal.title"
|
<a-modal id="backup-modal" v-model="backupModal.visible" :title="backupModal.title"
|
||||||
:closable="true"
|
:closable="true" footer=""
|
||||||
:class="themeSwitcher.currentTheme"
|
:class="themeSwitcher.currentTheme">
|
||||||
@ok="() => backupModal.hide()" @cancel="() => backupModal.hide()">
|
|
||||||
<a-alert type="warning" style="margin-bottom: 10px; width: fit-content"
|
<a-alert type="warning" style="margin-bottom: 10px; width: fit-content"
|
||||||
:message="backupModal.description"
|
:message="backupModal.description"
|
||||||
show-icon
|
show-icon
|
||||||
@@ -330,9 +342,9 @@
|
|||||||
{{template "textModal"}}
|
{{template "textModal"}}
|
||||||
<script>
|
<script>
|
||||||
const State = {
|
const State = {
|
||||||
Running: "running",
|
Running: "Running",
|
||||||
Stop: "stop",
|
Stop: "Stop",
|
||||||
Error: "error",
|
Error: "Error",
|
||||||
}
|
}
|
||||||
Object.freeze(State);
|
Object.freeze(State);
|
||||||
|
|
||||||
@@ -400,7 +412,7 @@
|
|||||||
this.xray = data.xray;
|
this.xray = data.xray;
|
||||||
switch (this.xray.state) {
|
switch (this.xray.state) {
|
||||||
case State.Running:
|
case State.Running:
|
||||||
this.xray.color = "blue";
|
this.xray.color = 'blue';
|
||||||
break;
|
break;
|
||||||
case State.Stop:
|
case State.Stop:
|
||||||
this.xray.color = "orange";
|
this.xray.color = "orange";
|
||||||
@@ -435,7 +447,8 @@
|
|||||||
loading: false,
|
loading: false,
|
||||||
show(logs) {
|
show(logs) {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.logs = logs? this.formatLogs(logs) : "No Record...";
|
this.logs = logs;
|
||||||
|
this.formattedLogs = this.logs?.length > 0 ? this.formatLogs(this.logs) : "No Record...";
|
||||||
},
|
},
|
||||||
formatLogs(logs) {
|
formatLogs(logs) {
|
||||||
let formattedLogs = '';
|
let formattedLogs = '';
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-tabs-bar {
|
.ant-tabs-bar {
|
||||||
|
font-weight: bold;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +51,16 @@
|
|||||||
show-icon closable
|
show-icon closable
|
||||||
>
|
>
|
||||||
</a-alert>
|
</a-alert>
|
||||||
|
<a-alert type="error" v-if="confAlerts.length>0" style="margin-bottom: 10px"
|
||||||
|
message='{{ i18n "secAlertTitle" }}'
|
||||||
|
color="red"
|
||||||
|
show-icon closable
|
||||||
|
>
|
||||||
|
<template slot="description">
|
||||||
|
{{ i18n "secAlertConf" }}
|
||||||
|
<li v-for="a in confAlerts">- [[ a ]]</li>
|
||||||
|
</template>
|
||||||
|
</a-alert>
|
||||||
</transition>
|
</transition>
|
||||||
<a-space direction="vertical">
|
<a-space direction="vertical">
|
||||||
<a-card hoverable style="margin-bottom: .5rem;">
|
<a-card hoverable style="margin-bottom: .5rem;">
|
||||||
@@ -200,6 +211,17 @@
|
|||||||
<setting-list-item type="number" title='{{ i18n "pages.settings.subUpdates"}}' desc='{{ i18n "pages.settings.subUpdatesDesc"}}' v-model="allSetting.subUpdates"></setting-list-item>
|
<setting-list-item type="number" title='{{ i18n "pages.settings.subUpdates"}}' desc='{{ i18n "pages.settings.subUpdatesDesc"}}' v-model="allSetting.subUpdates"></setting-list-item>
|
||||||
</a-list>
|
</a-list>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="5" tab='{{ i18n "pages.settings.subSettings" }} Json' v-if="allSetting.subEnable">
|
||||||
|
<a-list item-layout="horizontal">
|
||||||
|
<setting-list-item type="text" title='{{ i18n "pages.settings.subPath"}}' desc='{{ i18n "pages.settings.subPathDesc"}}' v-model="allSetting.subJsonPath"></setting-list-item>
|
||||||
|
<setting-list-item type="text" title='{{ i18n "pages.settings.subURI"}}' desc='{{ i18n "pages.settings.subURIDesc"}}' v-model="allSetting.subJsonURI" placeholder="(http|https)://domain[:port]/path/"></setting-list-item>
|
||||||
|
<setting-list-item type="switch" title='{{ i18n "pages.settings.fragment"}}' desc='{{ i18n "pages.settings.fragmentDesc"}}' v-model="fragment"></setting-list-item>
|
||||||
|
<template v-if="fragment">
|
||||||
|
<setting-list-item type="text" title='length' v-model="fragmentLength" placeholder="100-200"></setting-list-item>
|
||||||
|
<setting-list-item type="text" title='Interval' v-model="fragmentInterval" placeholder="10-20"></setting-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</a-space>
|
</a-space>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
@@ -229,6 +251,24 @@
|
|||||||
remarkModels: {i:'Inbound',e:'Email',o:'Other'},
|
remarkModels: {i:'Inbound',e:'Email',o:'Other'},
|
||||||
remarkSeparators: [' ','-','_','@',':','~','|',',','.','/'],
|
remarkSeparators: [' ','-','_','@',':','~','|',',','.','/'],
|
||||||
remarkSample: '',
|
remarkSample: '',
|
||||||
|
defaultFragment: {
|
||||||
|
tag: "fragment",
|
||||||
|
protocol: "freedom",
|
||||||
|
settings: {
|
||||||
|
domainStrategy: "AsIs",
|
||||||
|
fragment: {
|
||||||
|
packets: "tlshello",
|
||||||
|
length: "100-200",
|
||||||
|
interval: "10-20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
streamSettings: {
|
||||||
|
sockopt: {
|
||||||
|
tcpKeepAliveIdle: 100,
|
||||||
|
TcpNoDelay: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
get remarkModel() {
|
get remarkModel() {
|
||||||
rm = this.allSetting.remarkModel;
|
rm = this.allSetting.remarkModel;
|
||||||
return rm.length>1 ? rm.substring(1).split('') : [];
|
return rm.length>1 ? rm.substring(1).split('') : [];
|
||||||
@@ -289,7 +329,7 @@
|
|||||||
title: '{{ i18n "pages.settings.restartPanel" }}',
|
title: '{{ i18n "pages.settings.restartPanel" }}',
|
||||||
content: '{{ i18n "pages.settings.restartPanelDesc" }}',
|
content: '{{ i18n "pages.settings.restartPanelDesc" }}',
|
||||||
class: themeSwitcher.currentTheme,
|
class: themeSwitcher.currentTheme,
|
||||||
okText: '{{ i18n "sure" }}',
|
okText: '{{ i18n "confirm" }}',
|
||||||
cancelText: '{{ i18n "cancel" }}',
|
cancelText: '{{ i18n "cancel" }}',
|
||||||
onOk: () => resolve(),
|
onOk: () => resolve(),
|
||||||
});
|
});
|
||||||
@@ -309,6 +349,50 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
fragment: {
|
||||||
|
get: function() { return this.allSetting?.subJsonFragment != ""; },
|
||||||
|
set: function (v) {
|
||||||
|
this.allSetting.subJsonFragment = v ? JSON.stringify(this.defaultFragment) : "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fragmentLength: {
|
||||||
|
get: function() { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.length : ""; },
|
||||||
|
set: function(v) {
|
||||||
|
if (v != ""){
|
||||||
|
newFragment = JSON.parse(this.allSetting.subJsonFragment);
|
||||||
|
newFragment.settings.fragment.length = v;
|
||||||
|
this.allSetting.subJsonFragment = JSON.stringify(newFragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fragmentInterval: {
|
||||||
|
get: function() { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.interval : ""; },
|
||||||
|
set: function(v) {
|
||||||
|
if (v != ""){
|
||||||
|
newFragment = JSON.parse(this.allSetting.subJsonFragment);
|
||||||
|
newFragment.settings.fragment.interval = v;
|
||||||
|
this.allSetting.subJsonFragment = JSON.stringify(newFragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confAlerts: {
|
||||||
|
get: function() {
|
||||||
|
if (!this.allSetting) return [];
|
||||||
|
var alerts = []
|
||||||
|
if (this.allSetting.port == 54321) alerts.push('{{ i18n "pages.settings.panelPort"}}');
|
||||||
|
panelPath = window.location.pathname.split('/').length<4
|
||||||
|
if (panelPath && this.allSetting.webBasePath == '/') alerts.push('{{ i18n "pages.settings.panelConfig"}} {{ i18n "pages.settings.panelUrlPath"}}');
|
||||||
|
if (this.allSetting.subEnable) {
|
||||||
|
subPath = this.allSetting.subURI.length >0 ? new URL(this.allSetting.subURI).pathname : this.allSetting.subPath;
|
||||||
|
if (subPath == '/sub/') alerts.push('{{ i18n "pages.settings.subSettings"}} {{ i18n "pages.settings.subPath"}}');
|
||||||
|
subJsonPath = this.allSetting.subJsonURI.length >0 ? new URL(this.allSetting.subJsonURI).pathname : this.allSetting.subJsonPath;
|
||||||
|
if (subJsonPath == '/json/') alerts.push('JSON {{ i18n "pages.settings.subPath"}}');
|
||||||
|
}
|
||||||
|
return alerts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
if (window.location.protocol !== "https:") {
|
if (window.location.protocol !== "https:") {
|
||||||
this.showAlert = true;
|
this.showAlert = true;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<td>[[ warpModal.warpData.access_token ]]</td>
|
<td>[[ warpModal.warpData.access_token ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Devide ID</td>
|
<td>Device ID</td>
|
||||||
<td>[[ warpModal.warpData.device_id ]]</td>
|
<td>[[ warpModal.warpData.device_id ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="client-table-odd-row">
|
<tr class="client-table-odd-row">
|
||||||
@@ -24,19 +24,19 @@
|
|||||||
<td>[[ warpModal.warpData.private_key ]]</td>
|
<td>[[ warpModal.warpData.private_key ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<a-divider style="margin: 0;">{{ i18n "pages.settings.toasts.modifySettings" }}</a-divider>
|
<a-divider style="margin: 0;">{{ i18n "pages.xray.outbound.settings" }}</a-divider>
|
||||||
<a-collapse style="margin: 10px 0;">
|
<a-collapse style="margin: 10px 0;">
|
||||||
<a-collapse-panel header='WARP/WARP+ License Key'>
|
<a-collapse-panel header='WARP/WARP+ License Key'>
|
||||||
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||||
<a-form-item label="License Key">
|
<a-form-item label="Key">
|
||||||
<a-input v-model="warpPlus"></a-input>
|
<a-input v-model="warpPlus"></a-input>
|
||||||
<a-button @click="updateLicense(warpPlus)" :disabled="warpPlus.length<26" :loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.update" }}</a-button>
|
<a-button @click="updateLicense(warpPlus)" :disabled="warpPlus.length<26" :loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.update" }}</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
</a-collapse>
|
</a-collapse>
|
||||||
<a-divider style="margin: 0;">{{ i18n "pages.settings.toasts.getSettings" }}</a-divider>
|
<a-divider style="margin: 0;">{{ i18n "pages.xray.outbound.accountInfo" }}</a-divider>
|
||||||
<a-button icon="sync" @click="getConfig" style="margin-bottom: 10px;" :loading="warpModal.confirmLoading">{{ i18n "info" }}</a-button>
|
<a-button icon="sync" @click="getConfig" style="margin-top: 5px; margin-bottom: 10px;" :loading="warpModal.confirmLoading" type="primary">{{ i18n "info" }}</a-button>
|
||||||
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig)">
|
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig)">
|
||||||
<table style="width: 100%">
|
<table style="width: 100%">
|
||||||
<tr class="client-table-odd-row">
|
<tr class="client-table-odd-row">
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<td>[[ warpModal.warpConfig.model ]]</td>
|
<td>[[ warpModal.warpConfig.model ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="client-table-odd-row">
|
<tr class="client-table-odd-row">
|
||||||
<td>Device Active</td>
|
<td>Device Enabled</td>
|
||||||
<td>[[ warpModal.warpConfig.enabled ]]</td>
|
<td>[[ warpModal.warpConfig.enabled ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account)">
|
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account)">
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
<td>[[ warpModal.warpConfig.account.role ]]</td>
|
<td>[[ warpModal.warpConfig.account.role ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Premium Data</td>
|
<td>WARP+ Data</td>
|
||||||
<td>[[ sizeFormat(warpModal.warpConfig.account.premium_data) ]]</td>
|
<td>[[ sizeFormat(warpModal.warpConfig.account.premium_data) ]]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="client-table-odd-row">
|
<tr class="client-table-odd-row">
|
||||||
@@ -74,16 +74,15 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
</table>
|
</table>
|
||||||
<a-divider style="margin: 10px 0;">WARP {{ i18n "pages.xray.rules.outbound" }}</a-divider>
|
<a-divider style="margin: 10px 0;">{{ i18n "pages.xray.outbound.outboundStatus" }}</a-divider>
|
||||||
<a-form :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
<a-form :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||||
<a-form-item label="{{ i18n "status" }}">
|
|
||||||
<template v-if="warpOutboundIndex>=0">
|
<template v-if="warpOutboundIndex>=0">
|
||||||
<a-tag color="green">{{ i18n "enabled" }}</a-tag>
|
<a-tag color="green" style="line-height: 31px;">{{ i18n "enabled" }}</a-tag>
|
||||||
<a-button @click="resetOutbound" :loading="warpModal.confirmLoading">{{ i18n "reset" }}</a-button>
|
<a-button @click="resetOutbound" :loading="warpModal.confirmLoading" type="danger">{{ i18n "reset" }}</a-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a-tag color="orange">{{ i18n "disabled" }}</a-tag>
|
<a-tag color="orange" style="line-height: 31px;">{{ i18n "disabled" }}</a-tag>
|
||||||
<a-button @click="addOutbound" :loading="warpModal.confirmLoading">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
|
<a-button @click="addOutbound" :loading="warpModal.confirmLoading" type="primary">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
|
||||||
</template>
|
</template>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
@@ -108,7 +107,7 @@
|
|||||||
this.visible = false;
|
this.visible = false;
|
||||||
this.loading(false);
|
this.loading(false);
|
||||||
},
|
},
|
||||||
loading(loading) {
|
loading(loading=true) {
|
||||||
this.confirmLoading = loading;
|
this.confirmLoading = loading;
|
||||||
},
|
},
|
||||||
async getData(){
|
async getData(){
|
||||||
@@ -140,6 +139,7 @@
|
|||||||
mtu: 1420,
|
mtu: 1420,
|
||||||
secretKey: warpModal.warpData.private_key,
|
secretKey: warpModal.warpData.private_key,
|
||||||
address: Object.values(config.interface.addresses),
|
address: Object.values(config.interface.addresses),
|
||||||
|
domainStrategy: 'ForceIP',
|
||||||
peers: [{
|
peers: [{
|
||||||
publicKey: peer.public_key,
|
publicKey: peer.public_key,
|
||||||
endpoint: peer.endpoint.host,
|
endpoint: peer.endpoint.host,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-tabs-bar {
|
.ant-tabs-bar {
|
||||||
|
font-weight: bold;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,13 +141,54 @@
|
|||||||
description='{{ i18n "pages.xray.RoutingStrategyDesc" }}'/>
|
description='{{ i18n "pages.xray.RoutingStrategyDesc" }}'/>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="24" :xl="12">
|
<a-col :lg="24" :xl="12">
|
||||||
<template>
|
<a-select
|
||||||
<a-select
|
v-model="routingStrategy"
|
||||||
v-model="routingStrategy"
|
style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select-option v-for="s in routingDomainStrategies" :value="s">[[ s ]]</a-select-option>
|
||||||
<a-select-option v-for="s in routingDomainStrategies" :value="s">[[ s ]]</a-select-option>
|
</a-select>
|
||||||
</a-select>
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-list-item>
|
||||||
|
</a-collapse-panel>
|
||||||
|
<a-collapse-panel header='{{ i18n "pages.xray.logConfigs" }}'>
|
||||||
|
<a-row :xs="24" :sm="24" :lg="12">
|
||||||
|
<a-alert type="warning" style="text-align: center;">
|
||||||
|
<template slot="message">
|
||||||
|
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
|
||||||
|
{{ i18n "pages.xray.logConfigsDesc" }}
|
||||||
</template>
|
</template>
|
||||||
|
</a-alert>
|
||||||
|
</a-row>
|
||||||
|
<a-list-item>
|
||||||
|
<a-row style="padding: 20px">
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-list-item-meta title='Level'/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<template>
|
||||||
|
<a-select
|
||||||
|
v-model="logLevel"
|
||||||
|
style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option v-for="level in ['none', 'debug', 'info', 'warning', 'error']" :value="level">[[ level ]]</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-list-item>
|
||||||
|
<a-row style="padding: 20px">
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-list-item-meta title='Access Logs' />
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-input v-model="logAccess"></a-input>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row style="padding: 20px">
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-list-item-meta title='Error Logs' />
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-input v-model="logError"></a-input>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-list-item>
|
</a-list-item>
|
||||||
@@ -223,6 +265,7 @@
|
|||||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.OpenAIWARP"}}' desc='{{ i18n "pages.xray.OpenAIWARPDesc"}}' v-model="OpenAIWARPSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.xray.OpenAIWARP"}}' desc='{{ i18n "pages.xray.OpenAIWARPDesc"}}' v-model="OpenAIWARPSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.NetflixWARP"}}' desc='{{ i18n "pages.xray.NetflixWARPDesc"}}' v-model="NetflixWARPSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.xray.NetflixWARP"}}' desc='{{ i18n "pages.xray.NetflixWARPDesc"}}' v-model="NetflixWARPSettings"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.SpotifyWARP"}}' desc='{{ i18n "pages.xray.SpotifyWARPDesc"}}' v-model="SpotifyWARPSettings"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.xray.SpotifyWARP"}}' desc='{{ i18n "pages.xray.SpotifyWARPDesc"}}' v-model="SpotifyWARPSettings"></setting-list-item>
|
||||||
|
<setting-list-item type="switch" title='{{ i18n "pages.xray.MetaWARP"}}' desc='{{ i18n "pages.xray.MetaWARPDesc"}}' v-model="MetaWARPSettings"></setting-list-item>
|
||||||
</template>
|
</template>
|
||||||
<a-button v-else style="margin: 10px 0;" @click="showWarp">WARP {{ i18n "pages.xray.rules.outbound" }}</a-button>
|
<a-button v-else style="margin: 10px 0;" @click="showWarp">WARP {{ i18n "pages.xray.rules.outbound" }}</a-button>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
@@ -294,6 +337,14 @@
|
|||||||
[[ rule.outboundTag ]]
|
[[ rule.outboundTag ]]
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
|
<template slot="balancer" slot-scope="text, rule, index">
|
||||||
|
<a-popover :overlay-class-name="themeSwitcher.currentTheme">
|
||||||
|
<template slot="content">
|
||||||
|
<p v-if="rule.balancerTag">Balancer Tag: [[ rule.balancerTag ]]</p>
|
||||||
|
</template>
|
||||||
|
[[ rule.balancerTag ]]
|
||||||
|
</a-popover>
|
||||||
|
</template>
|
||||||
<template slot="info" slot-scope="text, rule, index">
|
<template slot="info" slot-scope="text, rule, index">
|
||||||
<a-popover placement="bottomRight"
|
<a-popover placement="bottomRight"
|
||||||
v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0"
|
v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0"
|
||||||
@@ -332,6 +383,10 @@
|
|||||||
<td>Port</td>
|
<td>Port</td>
|
||||||
<td><a-tag color="green" v-for="r in rule.port.split(',')">[[ r ]]</a-tag></td>
|
<td><a-tag color="green" v-for="r in rule.port.split(',')">[[ r ]]</a-tag></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr v-if="rule.balancerTag">
|
||||||
|
<td>Balancer Tag</td>
|
||||||
|
<td><a-tag color="blue">[[ rule.balancerTag ]]</a-tag></td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</template>
|
</template>
|
||||||
<a-button shape="round" size="small" style="font-size: 14px; padding: 0 10px;">
|
<a-button shape="round" size="small" style="font-size: 14px; padding: 0 10px;">
|
||||||
@@ -356,6 +411,10 @@
|
|||||||
<a-dropdown :trigger="['click']">
|
<a-dropdown :trigger="['click']">
|
||||||
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
|
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
|
||||||
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
|
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
|
||||||
|
<a-menu-item v-if="index>0" @click="setFirstOutbound(index)">
|
||||||
|
<a-icon type="vertical-align-top"></a-icon>
|
||||||
|
{{ i18n "pages.xray.rules.first"}}
|
||||||
|
</a-menu-item>
|
||||||
<a-menu-item @click="editOutbound(index)">
|
<a-menu-item @click="editOutbound(index)">
|
||||||
<a-icon type="edit"></a-icon>
|
<a-icon type="edit"></a-icon>
|
||||||
{{ i18n "edit" }}
|
{{ i18n "edit" }}
|
||||||
@@ -409,6 +468,124 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="tpl-5" tab='{{ i18n "pages.xray.Balancers"}}' style="padding-top: 20px;" force-render="true">
|
||||||
|
<a-button type="primary" icon="plus" @click="addBalancer()" style="margin-bottom: 10px;">{{ i18n "pages.xray.balancer.addBalancer"}}</a-button>
|
||||||
|
<a-table :columns="balancerColumns" bordered v-if="balancersData.length>0"
|
||||||
|
:row-key="r => r.key"
|
||||||
|
:data-source="balancersData"
|
||||||
|
:scroll="isMobile ? {} : { x: 200 }"
|
||||||
|
:pagination="false"
|
||||||
|
:indent-size="0"
|
||||||
|
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||||
|
<template slot="action" slot-scope="text, balancer, index">
|
||||||
|
[[ index+1 ]]
|
||||||
|
<a-dropdown :trigger="['click']">
|
||||||
|
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
|
||||||
|
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
|
||||||
|
<a-menu-item @click="editBalancer(index)">
|
||||||
|
<a-icon type="edit"></a-icon>
|
||||||
|
{{ i18n "edit" }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item @click="deleteBalancer(index)">
|
||||||
|
<span style="color: #FF4D4F">
|
||||||
|
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
|
||||||
|
</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
<template slot="strategy" slot-scope="text, balancer, index">
|
||||||
|
<a-tag style="margin:0;" v-if="balancer.strategy=='random'" color="purple">Random</a-tag>
|
||||||
|
<a-tag style="margin:0;" v-if="balancer.strategy=='roundRobin'" color="green">Round Robin</a-tag>
|
||||||
|
</template>
|
||||||
|
<template slot="selector" slot-scope="text, balancer, index">
|
||||||
|
<a-tag class="info-large-tag" style="margin:1;" v-for="sel in balancer.selector">[[ sel ]]</a-tag>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="tpl-6" tab='DNS' style="padding-top: 20px;" force-render="true">
|
||||||
|
<setting-list-item type="switch" title='{{ i18n "pages.xray.dns.enable" }}' desc='{{ i18n "pages.xray.dns.enableDesc" }}' v-model="enableDNS"></setting-list-item>
|
||||||
|
<template v-if="enableDNS">
|
||||||
|
<a-list-item>
|
||||||
|
<a-row style="padding: 20px">
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-list-item-meta title='{{ i18n "pages.xray.dns.strategy" }}' description='{{ i18n "pages.xray.dns.strategyDesc" }}' />
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="24" :xl="12">
|
||||||
|
<a-select
|
||||||
|
v-model="dnsStrategy"
|
||||||
|
style="width: 100%"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']">
|
||||||
|
[[ l ]]
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-list-item>
|
||||||
|
<a-divider>DNS</a-divider>
|
||||||
|
<a-button type="primary" icon="plus" @click="addDNSServer()" style="margin-bottom: 10px;">{{ i18n "pages.xray.dns.add" }}</a-button>
|
||||||
|
<a-table :columns="dnsColumns" bordered v-if="dnsServers.length>0"
|
||||||
|
:row-key="r => r.key"
|
||||||
|
:data-source="dnsServers"
|
||||||
|
:scroll="isMobile ? {} : { x: 200 }"
|
||||||
|
:pagination="false"
|
||||||
|
:indent-size="0"
|
||||||
|
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||||
|
<template slot="action" slot-scope="text,dns,index">
|
||||||
|
[[ index+1 ]]
|
||||||
|
<a-dropdown :trigger="['click']">
|
||||||
|
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
|
||||||
|
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
|
||||||
|
<a-menu-item @click="editDNSServer(index)">
|
||||||
|
<a-icon type="edit"></a-icon>
|
||||||
|
{{ i18n "edit" }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item @click="deleteDNSServer(index)">
|
||||||
|
<span style="color: #FF4D4F">
|
||||||
|
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
|
||||||
|
</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
<template slot="address" slot-scope="dns,index">
|
||||||
|
<span v-if="typeof dns == 'object'">[[ dns.address ]]</span>
|
||||||
|
<span v-else>[[ dns ]]</span>
|
||||||
|
</template>
|
||||||
|
<template slot="domain" slot-scope="dns,index">
|
||||||
|
<span v-if="typeof dns == 'object'">[[ dns.domains.join(",") ]]</span>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<a-divider>Fake DNS</a-divider>
|
||||||
|
<a-button type="primary" icon="plus" @click="addFakedns()" style="margin-bottom: 10px;">{{ i18n "pages.xray.fakedns.add" }}</a-button>
|
||||||
|
<a-table :columns="fakednsColumns" bordered v-if="fakeDns && fakeDns.length>0"
|
||||||
|
:row-key="r => r.key"
|
||||||
|
:data-source="fakeDns"
|
||||||
|
:scroll="isMobile ? {} : { x: 200 }"
|
||||||
|
:pagination="false"
|
||||||
|
:indent-size="0"
|
||||||
|
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||||
|
<template slot="action" slot-scope="text,fakedns,index">
|
||||||
|
[[ index+1 ]]
|
||||||
|
<a-dropdown :trigger="['click']">
|
||||||
|
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
|
||||||
|
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
|
||||||
|
<a-menu-item @click="editFakedns(index)">
|
||||||
|
<a-icon type="edit"></a-icon>
|
||||||
|
{{ i18n "edit" }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item @click="deleteFakedns(index)">
|
||||||
|
<span style="color: #FF4D4F">
|
||||||
|
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
|
||||||
|
</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</template>
|
||||||
|
</a-tab-pane>
|
||||||
<a-tab-pane key="tpl-advanced" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;" force-render="true">
|
<a-tab-pane key="tpl-advanced" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;" force-render="true">
|
||||||
<a-list-item-meta title='{{ i18n "pages.xray.Template"}}' description='{{ i18n "pages.xray.TemplateDesc"}}'></a-list-item-meta>
|
<a-list-item-meta title='{{ i18n "pages.xray.Template"}}' description='{{ i18n "pages.xray.TemplateDesc"}}'></a-list-item-meta>
|
||||||
<a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" style="margin: 10px 0;" :size="isMobile ? 'small' : ''">
|
<a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" style="margin: 10px 0;" :size="isMobile ? 'small' : ''">
|
||||||
@@ -431,6 +608,9 @@
|
|||||||
{{template "ruleModal"}}
|
{{template "ruleModal"}}
|
||||||
{{template "outModal"}}
|
{{template "outModal"}}
|
||||||
{{template "reverseModal"}}
|
{{template "reverseModal"}}
|
||||||
|
{{template "balancerModal"}}
|
||||||
|
{{template "dnsModal"}}
|
||||||
|
{{template "fakednsModal"}}
|
||||||
{{template "warpModal"}}
|
{{template "warpModal"}}
|
||||||
<script>
|
<script>
|
||||||
const rulesColumns = [
|
const rulesColumns = [
|
||||||
@@ -450,6 +630,7 @@
|
|||||||
{ title: 'Inbound Tag', dataIndex: 'inboundTag', align: 'center', width: 20, ellipsis: true },
|
{ title: 'Inbound Tag', dataIndex: 'inboundTag', align: 'center', width: 20, ellipsis: true },
|
||||||
{ title: 'Client Email', dataIndex: 'user', align: 'center', width: 20, ellipsis: true }]},
|
{ title: 'Client Email', dataIndex: 'user', align: 'center', width: 20, ellipsis: true }]},
|
||||||
{ title: '{{ i18n "pages.xray.rules.outbound"}}', dataIndex: 'outboundTag', align: 'center', width: 20 },
|
{ title: '{{ i18n "pages.xray.rules.outbound"}}', dataIndex: 'outboundTag', align: 'center', width: 20 },
|
||||||
|
{ title: '{{ i18n "pages.xray.rules.balancer"}}', dataIndex: 'balancerTag', align: 'center', width: 15 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const rulesMobileColumns = [
|
const rulesMobileColumns = [
|
||||||
@@ -473,6 +654,25 @@
|
|||||||
{ title: '{{ i18n "pages.xray.outbound.domain"}}', dataIndex: 'domain', align: 'center', width: 50 },
|
{ title: '{{ i18n "pages.xray.outbound.domain"}}', dataIndex: 'domain', align: 'center', width: 50 },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const balancerColumns = [
|
||||||
|
{ title: "#", align: 'center', width: 20, scopedSlots: { customRender: 'action' } },
|
||||||
|
{ title: '{{ i18n "pages.xray.balancer.tag"}}', dataIndex: 'tag', align: 'center', width: 50 },
|
||||||
|
{ title: '{{ i18n "pages.xray.balancer.balancerStrategy"}}', align: 'center', width: 50, scopedSlots: { customRender: 'strategy' }},
|
||||||
|
{ title: '{{ i18n "pages.xray.balancer.balancerSelectors"}}', align: 'center', width: 100, scopedSlots: { customRender: 'selector' }},
|
||||||
|
];
|
||||||
|
|
||||||
|
const dnsColumns = [
|
||||||
|
{ title: "#", align: 'center', width: 20, scopedSlots: { customRender: 'action' } },
|
||||||
|
{ title: '{{ i18n "pages.xray.outbound.address"}}', align: 'center', width: 50, scopedSlots: { customRender: 'address' } },
|
||||||
|
{ title: '{{ i18n "pages.xray.dns.domains"}}', align: 'center', width: 50, scopedSlots: { customRender: 'domain' } },
|
||||||
|
];
|
||||||
|
|
||||||
|
const fakednsColumns = [
|
||||||
|
{ title: "#", align: 'center', width: 20, scopedSlots: { customRender: 'action' } },
|
||||||
|
{ title: '{{ i18n "pages.xray.fakedns.ipPool"}}', dataIndex: 'ipPool', align: 'center', width: 50 },
|
||||||
|
{ title: '{{ i18n "pages.xray.fakedns.poolSize"}}', dataIndex: 'poolSize', align: 'center', width: 50 },
|
||||||
|
];
|
||||||
|
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
delimiters: ['[[', ']]'],
|
delimiters: ['[[', ']]'],
|
||||||
el: '#app',
|
el: '#app',
|
||||||
@@ -542,6 +742,7 @@
|
|||||||
google: ["geosite:google"],
|
google: ["geosite:google"],
|
||||||
spotify: ["geosite:spotify"],
|
spotify: ["geosite:spotify"],
|
||||||
netflix: ["geosite:netflix"],
|
netflix: ["geosite:netflix"],
|
||||||
|
meta: ["geosite:meta"],
|
||||||
cn: [
|
cn: [
|
||||||
"geosite:cn",
|
"geosite:cn",
|
||||||
"regexp:.*\\.cn$"
|
"regexp:.*\\.cn$"
|
||||||
@@ -553,17 +754,17 @@
|
|||||||
ir: [
|
ir: [
|
||||||
"regexp:.*\\.ir$",
|
"regexp:.*\\.ir$",
|
||||||
"regexp:.*\\.xn--mgba3a4f16a$", // .ایران
|
"regexp:.*\\.xn--mgba3a4f16a$", // .ایران
|
||||||
"ext:geosite_IR.dat:ir" // have rules to bypass all .ir domains.
|
"ext:geosite_IR.dat:ir"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
familyProtectDNS: {
|
familyProtectDNS: {
|
||||||
"servers": [
|
"servers": [
|
||||||
"1.1.1.3",
|
"1.1.1.3", // https://developers.cloudflare.com/1.1.1.1/setup/
|
||||||
"1.0.0.3",
|
"1.0.0.3",
|
||||||
"94.140.14.15",
|
"2606:4700:4700::1113",
|
||||||
"94.140.15.16"
|
"2606:4700:4700::1003"
|
||||||
],
|
],
|
||||||
"queryStrategy": "UseIPv4"
|
"queryStrategy": "UseIP"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -764,6 +965,11 @@
|
|||||||
outbounds.splice(index,1);
|
outbounds.splice(index,1);
|
||||||
this.outboundSettings = JSON.stringify(outbounds);
|
this.outboundSettings = JSON.stringify(outbounds);
|
||||||
},
|
},
|
||||||
|
setFirstOutbound(index){
|
||||||
|
outbounds = this.templateSettings.outbounds;
|
||||||
|
outbounds.splice(0, 0, outbounds.splice(index, 1)[0]);
|
||||||
|
this.outboundSettings = JSON.stringify(outbounds);
|
||||||
|
},
|
||||||
addReverse(){
|
addReverse(){
|
||||||
reverseModal.show({
|
reverseModal.show({
|
||||||
title: '{{ i18n "pages.xray.outbound.addReverse"}}',
|
title: '{{ i18n "pages.xray.outbound.addReverse"}}',
|
||||||
@@ -849,6 +1055,155 @@
|
|||||||
|
|
||||||
this.templateSettings = newTemplateSettings;
|
this.templateSettings = newTemplateSettings;
|
||||||
},
|
},
|
||||||
|
addBalancer() {
|
||||||
|
balancerModal.show({
|
||||||
|
title: '{{ i18n "pages.xray.balancer.addBalancer"}}',
|
||||||
|
okText: '{{ i18n "pages.xray.balancer.addBalancer"}}',
|
||||||
|
balancerTags: this.balancersData.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag),
|
||||||
|
balancer: {
|
||||||
|
tag: '',
|
||||||
|
strategy: 'random',
|
||||||
|
selector: []
|
||||||
|
},
|
||||||
|
confirm: (balancer) => {
|
||||||
|
balancerModal.loading();
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
if (newTemplateSettings.routing.balancers == undefined) {
|
||||||
|
newTemplateSettings.routing.balancers = [];
|
||||||
|
}
|
||||||
|
let tmpBalancer = {
|
||||||
|
'tag': balancer.tag,
|
||||||
|
'selector': balancer.selector
|
||||||
|
};
|
||||||
|
if (balancer.strategy == 'roundRobin') {
|
||||||
|
tmpBalancer.strategy = {
|
||||||
|
'type': balancer.strategy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
newTemplateSettings.routing.balancers.push(tmpBalancer);
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
balancerModal.close();
|
||||||
|
},
|
||||||
|
isEdit: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
editBalancer(index) {
|
||||||
|
const oldTag = this.balancersData[index].tag;
|
||||||
|
balancerModal.show({
|
||||||
|
title: '{{ i18n "pages.xray.balancer.editBalancer"}}',
|
||||||
|
okText: '{{ i18n "sure" }}',
|
||||||
|
balancerTags: this.balancersData.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag),
|
||||||
|
balancer: this.balancersData[index],
|
||||||
|
confirm: (balancer) => {
|
||||||
|
balancerModal.loading();
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
|
||||||
|
let tmpBalancer = {
|
||||||
|
'tag': balancer.tag,
|
||||||
|
'selector': balancer.selector
|
||||||
|
};
|
||||||
|
if (balancer.strategy == 'roundRobin') {
|
||||||
|
tmpBalancer.strategy = {
|
||||||
|
'type': balancer.strategy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
newTemplateSettings.routing.balancers[index] = tmpBalancer;
|
||||||
|
// change edited tag if used in rule section
|
||||||
|
if (oldTag != balancer.tag) {
|
||||||
|
newTemplateSettings.routing.rules.forEach((rule) => {
|
||||||
|
if (rule.balancerTag && rule.balancerTag == oldTag) {
|
||||||
|
rule.balancerTag = balancer.tag;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
balancerModal.close();
|
||||||
|
},
|
||||||
|
isEdit: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteBalancer(index) {
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
|
||||||
|
//remove from balancers
|
||||||
|
const oldTag = this.balancersData[index].tag;
|
||||||
|
this.balancersData.splice(index, 1);
|
||||||
|
|
||||||
|
// remove from settings
|
||||||
|
let realIndex = newTemplateSettings.routing.balancers.findIndex((b) => b.tag == oldTag);
|
||||||
|
newTemplateSettings.routing.balancers.splice(realIndex, 1);
|
||||||
|
|
||||||
|
// remove related routing rules
|
||||||
|
let rules = [];
|
||||||
|
newTemplateSettings.routing.rules.forEach((r) => {
|
||||||
|
if (!r.balancerTag || r.balancerTag != oldTag) {
|
||||||
|
rules.push(r);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
newTemplateSettings.routing.rules = rules;
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
},
|
||||||
|
addDNSServer(){
|
||||||
|
dnsModal.show({
|
||||||
|
title: '{{ i18n "pages.xray.dns.add" }}',
|
||||||
|
confirm: (dnsServer) => {
|
||||||
|
dnsServers = this.dnsServers;
|
||||||
|
dnsServers.push(dnsServer);
|
||||||
|
this.dnsServers = dnsServers;
|
||||||
|
dnsModal.close();
|
||||||
|
},
|
||||||
|
isEdit: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
editDNSServer(index){
|
||||||
|
dnsModal.show({
|
||||||
|
title: '{{ i18n "pages.xray.dns.edit" }} #' + (index+1),
|
||||||
|
dnsServer: this.dnsServers[index],
|
||||||
|
confirm: (dnsServer) => {
|
||||||
|
dnsServers = this.dnsServers;
|
||||||
|
dnsServers[index] = dnsServer;
|
||||||
|
this.dnsServers = dnsServers;
|
||||||
|
dnsModal.close();
|
||||||
|
},
|
||||||
|
isEdit: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteDNSServer(index){
|
||||||
|
newDnsServers = this.dnsServers;
|
||||||
|
newDnsServers.splice(index,1);
|
||||||
|
this.dnsServers = newDnsServers;
|
||||||
|
},
|
||||||
|
addFakedns() {
|
||||||
|
fakednsModal.show({
|
||||||
|
title: '{{ i18n "pages.xray.fakedns.add" }}',
|
||||||
|
confirm: (item) => {
|
||||||
|
fakeDns = this.fakeDns?? [];
|
||||||
|
fakeDns.push(item);
|
||||||
|
this.fakeDns = fakeDns;
|
||||||
|
fakednsModal.close();
|
||||||
|
},
|
||||||
|
isEdit: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
editFakedns(index){
|
||||||
|
fakednsModal.show({
|
||||||
|
title: '{{ i18n "pages.xray.fakedns.edit" }} #' + (index+1),
|
||||||
|
fakeDns: this.fakeDns[index],
|
||||||
|
confirm: (item) => {
|
||||||
|
fakeDns = this.fakeDns;
|
||||||
|
fakeDns[index] = item;
|
||||||
|
this.fakeDns = fakeDns;
|
||||||
|
fakednsModal.close();
|
||||||
|
},
|
||||||
|
isEdit: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteFakedns(index){
|
||||||
|
fakeDns = this.fakeDns;
|
||||||
|
fakeDns.splice(index,1);
|
||||||
|
this.fakeDns = fakeDns;
|
||||||
|
},
|
||||||
addRule(){
|
addRule(){
|
||||||
ruleModal.show({
|
ruleModal.show({
|
||||||
title: '{{ i18n "pages.xray.rules.add"}}',
|
title: '{{ i18n "pages.xray.rules.add"}}',
|
||||||
@@ -910,6 +1265,38 @@
|
|||||||
get: function () { return this.xraySetting ? JSON.parse(this.xraySetting) : null; },
|
get: function () { return this.xraySetting ? JSON.parse(this.xraySetting) : null; },
|
||||||
set: function (newValue) { this.xraySetting = JSON.stringify(newValue, null, 2); },
|
set: function (newValue) { this.xraySetting = JSON.stringify(newValue, null, 2); },
|
||||||
},
|
},
|
||||||
|
logSettings: {
|
||||||
|
get: function () { return this.templateSettings ? this.templateSettings.log : {}; },
|
||||||
|
set: function (newValue) {
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
newTemplateSettings.log = newValue;
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
logLevel: {
|
||||||
|
get: function () { return this.logSettings?.loglevel?? 'none'; },
|
||||||
|
set: function (newValue) {
|
||||||
|
newLogSettings = this.logSettings;
|
||||||
|
newLogSettings.loglevel = newValue;
|
||||||
|
this.logSettings = newLogSettings;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
logAccess: {
|
||||||
|
get: function () { return this.logSettings?.access?? ''; },
|
||||||
|
set: function (newValue) {
|
||||||
|
newLogSettings = this.logSettings;
|
||||||
|
newValue == "" ? delete newLogSettings.access : newLogSettings.access = newValue;
|
||||||
|
this.logSettings = newLogSettings;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
logError: {
|
||||||
|
get: function () { return this.logSettings?.error?? ''; },
|
||||||
|
set: function (newValue) {
|
||||||
|
newLogSettings = this.logSettings;
|
||||||
|
newValue == "" ? delete newLogSettings.error : newLogSettings.error = newValue;
|
||||||
|
this.logSettings = newLogSettings;
|
||||||
|
},
|
||||||
|
},
|
||||||
inboundSettings: {
|
inboundSettings: {
|
||||||
get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.inbounds, null, 2) : null; },
|
get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.inbounds, null, 2) : null; },
|
||||||
set: function (newValue) {
|
set: function (newValue) {
|
||||||
@@ -984,6 +1371,27 @@
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
balancersData: {
|
||||||
|
get: function () {
|
||||||
|
data = []
|
||||||
|
if (this.templateSettings != null && this.templateSettings.routing != null && this.templateSettings.routing.balancers != null) {
|
||||||
|
this.templateSettings.routing.balancers.forEach((o, index) => {
|
||||||
|
let strategy = "random"
|
||||||
|
if (o.strategy && o.strategy.type == "roundRobin") {
|
||||||
|
strategy = o.strategy.type
|
||||||
|
}
|
||||||
|
|
||||||
|
data.push({
|
||||||
|
'key': index,
|
||||||
|
'tag': o.tag ? o.tag : "",
|
||||||
|
'strategy': strategy,
|
||||||
|
'selector': o.selector ? o.selector : []
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
},
|
||||||
freedomStrategy: {
|
freedomStrategy: {
|
||||||
get: function () {
|
get: function () {
|
||||||
if (!this.templateSettings) return "AsIs";
|
if (!this.templateSettings) return "AsIs";
|
||||||
@@ -1114,14 +1522,14 @@
|
|||||||
familyProtectSettings: {
|
familyProtectSettings: {
|
||||||
get: function () {
|
get: function () {
|
||||||
if (!this.templateSettings || !this.templateSettings.dns || !this.templateSettings.dns.servers) return false;
|
if (!this.templateSettings || !this.templateSettings.dns || !this.templateSettings.dns.servers) return false;
|
||||||
return doAllItemsExist(this.templateSettings.dns.servers, this.settingsData.familyProtectDNS.servers);
|
return doAllItemsExist(this.settingsData.familyProtectDNS.servers, this.templateSettings.dns.servers);
|
||||||
},
|
},
|
||||||
set: function (newValue) {
|
set: function (newValue) {
|
||||||
newTemplateSettings = this.templateSettings;
|
newTemplateSettings = this.templateSettings;
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
newTemplateSettings.dns = this.settingsData.familyProtectDNS;
|
newTemplateSettings.dns = this.settingsData.familyProtectDNS;
|
||||||
} else {
|
} else {
|
||||||
delete newTemplateSettings.dns;
|
newTemplateSettings.dns.servers = newTemplateSettings.dns?.servers?.filter(data => !this.settingsData.familyProtectDNS.servers.includes(data))
|
||||||
}
|
}
|
||||||
this.templateSettings = newTemplateSettings;
|
this.templateSettings = newTemplateSettings;
|
||||||
},
|
},
|
||||||
@@ -1335,6 +1743,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MetaWARPSettings: {
|
||||||
|
get: function () {
|
||||||
|
return doAllItemsExist(this.settingsData.domains.meta, this.warpDomains);
|
||||||
|
},
|
||||||
|
set: function (newValue) {
|
||||||
|
if (newValue) {
|
||||||
|
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.meta];
|
||||||
|
} else {
|
||||||
|
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.meta.includes(data));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
SpotifyWARPSettings: {
|
SpotifyWARPSettings: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return doAllItemsExist(this.settingsData.domains.spotify, this.warpDomains);
|
return doAllItemsExist(this.settingsData.domains.spotify, this.warpDomains);
|
||||||
@@ -1347,6 +1767,42 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
enableDNS: {
|
||||||
|
get: function () {
|
||||||
|
return this.templateSettings ? this.templateSettings.dns != null : false;
|
||||||
|
},
|
||||||
|
set: function (newValue) {
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
newTemplateSettings.dns = newValue ? { servers: [], queryStrategy: "UseIP" } : null;
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dnsStrategy: {
|
||||||
|
get: function () {
|
||||||
|
return this.enableDNS ? this.templateSettings.dns.queryStrategy : null;
|
||||||
|
},
|
||||||
|
set: function (newValue) {
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
newTemplateSettings.dns.queryStrategy = newValue;
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dnsServers: {
|
||||||
|
get: function () { return this.enableDNS ? this.templateSettings.dns.servers : []; },
|
||||||
|
set: function (newValue) {
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
newTemplateSettings.dns.servers = newValue;
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fakeDns: {
|
||||||
|
get: function () { return this.templateSettings && this.templateSettings.fakedns ? this.templateSettings.fakedns : []; },
|
||||||
|
set: function (newValue) {
|
||||||
|
newTemplateSettings = this.templateSettings;
|
||||||
|
newTemplateSettings.fakedns = newValue.length >0 ? newValue : null;
|
||||||
|
this.templateSettings = newTemplateSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
111
web/html/xui/xray_balancer_modal.html
Normal file
111
web/html/xui/xray_balancer_modal.html
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
{{define "balancerModal"}}
|
||||||
|
<a-modal
|
||||||
|
id="balancer-modal"
|
||||||
|
v-model="balancerModal.visible"
|
||||||
|
:title="balancerModal.title"
|
||||||
|
@ok="balancerModal.ok"
|
||||||
|
:confirm-loading="balancerModal.confirmLoading"
|
||||||
|
:ok-button-props="{ props: { disabled: !balancerModal.isValid } }"
|
||||||
|
:closable="true"
|
||||||
|
:mask-closable="false"
|
||||||
|
:ok-text="balancerModal.okText"
|
||||||
|
cancel-text='{{ i18n "close" }}'
|
||||||
|
:class="themeSwitcher.currentTheme">
|
||||||
|
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.balancer.tag" }}' has-feedback
|
||||||
|
:validate-status="balancerModal.duplicateTag? 'warning' : 'success'">
|
||||||
|
<a-input v-model.trim="balancerModal.balancer.tag" @change="balancerModal.check()"
|
||||||
|
placeholder='{{ i18n "pages.xray.balancer.tagDesc" }}'></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.balancer.balancerStrategy" }}'>
|
||||||
|
<a-select v-model="balancerModal.balancer.strategy" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value="random">Random</a-select-option>
|
||||||
|
<a-select-option value="roundRobin">Round Robin</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='{{ i18n "pages.xray.balancer.balancerSelectors" }}' has-feedback :validate-status="balancerModal.emptySelector? 'warning' : 'success'">
|
||||||
|
<a-select v-model="balancerModal.balancer.selector" mode="tags" @change="balancerModal.checkSelector()"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option v-for="tag in balancerModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</table>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
<script>
|
||||||
|
const balancerModal = {
|
||||||
|
title: '',
|
||||||
|
visible: false,
|
||||||
|
confirmLoading: false,
|
||||||
|
okText: '{{ i18n "sure" }}',
|
||||||
|
isEdit: false,
|
||||||
|
confirm: null,
|
||||||
|
duplicateTag: false,
|
||||||
|
emptySelector: false,
|
||||||
|
balancer: {
|
||||||
|
tag: '',
|
||||||
|
strategy: 'random',
|
||||||
|
selector: []
|
||||||
|
},
|
||||||
|
outboundTags: [],
|
||||||
|
balancerTags:[],
|
||||||
|
ok() {
|
||||||
|
if (balancerModal.balancer.selector.length == 0) {
|
||||||
|
balancerModal.emptySelector = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
balancerModal.emptySelector = false;
|
||||||
|
ObjectUtil.execute(balancerModal.confirm, balancerModal.balancer);
|
||||||
|
},
|
||||||
|
show({ title = '', okText = '{{ i18n "sure" }}', balancerTags = [], balancer, confirm = (balancer) => { }, isEdit = false }) {
|
||||||
|
this.title = title;
|
||||||
|
this.okText = okText;
|
||||||
|
this.confirm = confirm;
|
||||||
|
this.visible = true;
|
||||||
|
if (isEdit) {
|
||||||
|
balancerModal.balancer = balancer;
|
||||||
|
} else {
|
||||||
|
balancerModal.balancer = {
|
||||||
|
tag: '',
|
||||||
|
strategy: 'random',
|
||||||
|
selector: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.balancerTags = balancerTags.filter((tag) => tag != balancer.tag);
|
||||||
|
this.outboundTags = app.templateSettings.outbounds.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag);
|
||||||
|
this.isEdit = isEdit;
|
||||||
|
this.check()
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
balancerModal.visible = false;
|
||||||
|
balancerModal.loading(false);
|
||||||
|
},
|
||||||
|
loading(loading=true) {
|
||||||
|
balancerModal.confirmLoading = loading;
|
||||||
|
},
|
||||||
|
check() {
|
||||||
|
if (balancerModal.balancer.tag == '' || balancerModal.balancerTags.includes(balancerModal.balancer.tag)) {
|
||||||
|
this.duplicateTag = true;
|
||||||
|
this.isValid = false;
|
||||||
|
} else {
|
||||||
|
this.duplicateTag = false;
|
||||||
|
this.isValid = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkSelector() {
|
||||||
|
balancerModal.emptySelector = balancerModal.balancer.selector.length == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
delimiters: ['[[', ']]'],
|
||||||
|
el: '#balancer-modal',
|
||||||
|
data: {
|
||||||
|
balancerModal: balancerModal
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
title: '',
|
title: '',
|
||||||
visible: false,
|
visible: false,
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
okText: '{{ i18n "sure" }}',
|
okText: '{{ i18n "confirm" }}',
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
confirm: null,
|
confirm: null,
|
||||||
outbound: new Outbound(),
|
outbound: new Outbound(),
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
ok() {
|
ok() {
|
||||||
ObjectUtil.execute(outModal.confirm, outModal.outbound.toJson());
|
ObjectUtil.execute(outModal.confirm, outModal.outbound.toJson());
|
||||||
},
|
},
|
||||||
show({ title='', okText='{{ i18n "sure" }}', outbound, confirm=(outbound)=>{}, isEdit=false, tags=[] }) {
|
show({ title='', okText='{{ i18n "confirm" }}', outbound, confirm=(outbound)=>{}, isEdit=false, tags=[] }) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.okText = okText;
|
this.okText = okText;
|
||||||
this.confirm = confirm;
|
this.confirm = confirm;
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
outModal.visible = false;
|
outModal.visible = false;
|
||||||
outModal.loading(false);
|
outModal.loading(false);
|
||||||
},
|
},
|
||||||
loading(loading) {
|
loading(loading=true) {
|
||||||
outModal.confirmLoading = loading;
|
outModal.confirmLoading = loading;
|
||||||
},
|
},
|
||||||
check(){
|
check(){
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
:options="reverseModal.inboundTags"></a-checkbox-group>
|
:options="reverseModal.inboundTags"></a-checkbox-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
</table>
|
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
<script>
|
<script>
|
||||||
@@ -46,7 +45,7 @@
|
|||||||
title: '',
|
title: '',
|
||||||
visible: false,
|
visible: false,
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
okText: '{{ i18n "sure" }}',
|
okText: '{{ i18n "confirm" }}',
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
confirm: null,
|
confirm: null,
|
||||||
reverse: {
|
reverse: {
|
||||||
@@ -74,7 +73,7 @@
|
|||||||
}
|
}
|
||||||
ObjectUtil.execute(reverseModal.confirm, reverseModal.reverse, reverseModal.rules);
|
ObjectUtil.execute(reverseModal.confirm, reverseModal.reverse, reverseModal.rules);
|
||||||
},
|
},
|
||||||
show({ title='', okText='{{ i18n "sure" }}', reverse, rules, confirm=(reverse, rules)=>{}, isEdit=false }) {
|
show({ title='', okText='{{ i18n "confirm" }}', reverse, rules, confirm=(reverse, rules)=>{}, isEdit=false }) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.okText = okText;
|
this.okText = okText;
|
||||||
this.confirm = confirm;
|
this.confirm = confirm;
|
||||||
@@ -120,7 +119,7 @@
|
|||||||
reverseModal.visible = false;
|
reverseModal.visible = false;
|
||||||
reverseModal.loading(false);
|
reverseModal.loading(false);
|
||||||
},
|
},
|
||||||
loading(loading) {
|
loading(loading=true) {
|
||||||
reverseModal.confirmLoading = loading;
|
reverseModal.confirmLoading = loading;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -131,8 +130,6 @@
|
|||||||
data: {
|
data: {
|
||||||
reverseModal: reverseModal,
|
reverseModal: reverseModal,
|
||||||
reverseTypes: { bridge: '{{ i18n "pages.xray.outbound.bridge" }}', portal:'{{ i18n "pages.xray.outbound.portal" }}'},
|
reverseTypes: { bridge: '{{ i18n "pages.xray.outbound.bridge" }}', portal:'{{ i18n "pages.xray.outbound.portal" }}'},
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,19 @@
|
|||||||
<a-select-option v-for="tag in ruleModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
|
<a-select-option v-for="tag in ruleModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<template slot="label">
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
<span>{{ i18n "pages.xray.balancer.balancerDesc" }}</span>
|
||||||
|
</template>
|
||||||
|
Balancer Tag <a-icon type="question-circle"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-select v-model="ruleModal.rule.balancerTag" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option v-for="tag in ruleModal.balancerTags" :value="tag">[[ tag ]]</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
</table>
|
</table>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
@@ -116,7 +129,7 @@
|
|||||||
title: '',
|
title: '',
|
||||||
visible: false,
|
visible: false,
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
okText: '{{ i18n "sure" }}',
|
okText: '{{ i18n "confirm" }}',
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
confirm: null,
|
confirm: null,
|
||||||
rule: {
|
rule: {
|
||||||
@@ -133,6 +146,7 @@
|
|||||||
protocol: [],
|
protocol: [],
|
||||||
attrs: [],
|
attrs: [],
|
||||||
outboundTag: "",
|
outboundTag: "",
|
||||||
|
balancerTag: "",
|
||||||
},
|
},
|
||||||
inboundTags: [],
|
inboundTags: [],
|
||||||
outboundTags: [],
|
outboundTags: [],
|
||||||
@@ -142,7 +156,7 @@
|
|||||||
newRule = ruleModal.getResult();
|
newRule = ruleModal.getResult();
|
||||||
ObjectUtil.execute(ruleModal.confirm, newRule);
|
ObjectUtil.execute(ruleModal.confirm, newRule);
|
||||||
},
|
},
|
||||||
show({ title='', okText='{{ i18n "sure" }}', rule, confirm=(rule)=>{}, isEdit=false }) {
|
show({ title='', okText='{{ i18n "confirm" }}', rule, confirm=(rule)=>{}, isEdit=false }) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.okText = okText;
|
this.okText = okText;
|
||||||
this.confirm = confirm;
|
this.confirm = confirm;
|
||||||
@@ -160,6 +174,7 @@
|
|||||||
this.rule.protocol = rule.protocol;
|
this.rule.protocol = rule.protocol;
|
||||||
this.rule.attrs = rule.attrs ? Object.entries(rule.attrs) : [];
|
this.rule.attrs = rule.attrs ? Object.entries(rule.attrs) : [];
|
||||||
this.rule.outboundTag = rule.outboundTag;
|
this.rule.outboundTag = rule.outboundTag;
|
||||||
|
this.rule.balancerTag = rule.balancerTag ? rule.balancerTag : "";
|
||||||
} else {
|
} else {
|
||||||
this.rule = {
|
this.rule = {
|
||||||
domainMatcher: "",
|
domainMatcher: "",
|
||||||
@@ -174,6 +189,7 @@
|
|||||||
protocol: [],
|
protocol: [],
|
||||||
attrs: [],
|
attrs: [],
|
||||||
outboundTag: "",
|
outboundTag: "",
|
||||||
|
balancerTag: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.isEdit = isEdit;
|
this.isEdit = isEdit;
|
||||||
@@ -186,12 +202,15 @@
|
|||||||
}
|
}
|
||||||
if(app.templateSettings.reverse.portals) this.outboundTags.push(...app.templateSettings.reverse.portals.map(b => b.tag));
|
if(app.templateSettings.reverse.portals) this.outboundTags.push(...app.templateSettings.reverse.portals.map(b => b.tag));
|
||||||
}
|
}
|
||||||
|
if (app.templateSettings.routing && app.templateSettings.routing.balancers) {
|
||||||
|
this.balancerTags = app.templateSettings.routing.balancers.filter((o) => !ObjectUtil.isEmpty(o.tag)).map(obj => obj.tag)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
ruleModal.visible = false;
|
ruleModal.visible = false;
|
||||||
ruleModal.loading(false);
|
ruleModal.loading(false);
|
||||||
},
|
},
|
||||||
loading(loading) {
|
loading(loading=true) {
|
||||||
ruleModal.confirmLoading = loading;
|
ruleModal.confirmLoading = loading;
|
||||||
},
|
},
|
||||||
getResult() {
|
getResult() {
|
||||||
@@ -211,6 +230,7 @@
|
|||||||
rule.protocol = value.protocol;
|
rule.protocol = value.protocol;
|
||||||
rule.attrs = Object.fromEntries(value.attrs);
|
rule.attrs = Object.fromEntries(value.attrs);
|
||||||
rule.outboundTag = value.outboundTag;
|
rule.outboundTag = value.outboundTag;
|
||||||
|
rule.balancerTag = value.balancerTag;
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(rule)) {
|
for (const [key, value] of Object.entries(rule)) {
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -474,6 +474,10 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(newClients) == 0 {
|
||||||
|
return false, common.NewError("no client remained in Inbound")
|
||||||
|
}
|
||||||
|
|
||||||
settings["clients"] = newClients
|
settings["clients"] = newClients
|
||||||
newSettings, err := json.MarshalIndent(settings, "", " ")
|
newSettings, err := json.MarshalIndent(settings, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ import (
|
|||||||
type ProcessState string
|
type ProcessState string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Running ProcessState = "running"
|
Running ProcessState = "Running"
|
||||||
Stop ProcessState = "stop"
|
Stop ProcessState = "Stop"
|
||||||
Error ProcessState = "error"
|
Error ProcessState = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ var defaultValueMap = map[string]string{
|
|||||||
"subEncrypt": "true",
|
"subEncrypt": "true",
|
||||||
"subShowInfo": "false",
|
"subShowInfo": "false",
|
||||||
"subURI": "",
|
"subURI": "",
|
||||||
|
"subJsonPath": "/json/",
|
||||||
|
"subJsonURI": "",
|
||||||
|
"subJsonFragment": "",
|
||||||
"warp": "",
|
"warp": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,17 +356,11 @@ func (s *SettingService) GetSubPort() (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SettingService) GetSubPath() (string, error) {
|
func (s *SettingService) GetSubPath() (string, error) {
|
||||||
subPath, err := s.getString("subPath")
|
return s.getString("subPath")
|
||||||
if err != nil {
|
}
|
||||||
return "", err
|
|
||||||
}
|
func (s *SettingService) GetSubJsonPath() (string, error) {
|
||||||
if !strings.HasPrefix(subPath, "/") {
|
return s.getString("subJsonPath")
|
||||||
subPath = "/" + subPath
|
|
||||||
}
|
|
||||||
if !strings.HasSuffix(subPath, "/") {
|
|
||||||
subPath += "/"
|
|
||||||
}
|
|
||||||
return subPath, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SettingService) GetSubDomain() (string, error) {
|
func (s *SettingService) GetSubDomain() (string, error) {
|
||||||
@@ -378,8 +375,8 @@ func (s *SettingService) GetSubKeyFile() (string, error) {
|
|||||||
return s.getString("subKeyFile")
|
return s.getString("subKeyFile")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SettingService) GetSubUpdates() (int, error) {
|
func (s *SettingService) GetSubUpdates() (string, error) {
|
||||||
return s.getInt("subUpdates")
|
return s.getString("subUpdates")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SettingService) GetSubEncrypt() (bool, error) {
|
func (s *SettingService) GetSubEncrypt() (bool, error) {
|
||||||
@@ -398,6 +395,14 @@ func (s *SettingService) GetSubURI() (string, error) {
|
|||||||
return s.getString("subURI")
|
return s.getString("subURI")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SettingService) GetSubJsonURI() (string, error) {
|
||||||
|
return s.getString("subJsonURI")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SettingService) GetSubJsonFragment() (string, error) {
|
||||||
|
return s.getString("subJsonFragment")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SettingService) GetWarp() (string, error) {
|
func (s *SettingService) GetWarp() (string, error) {
|
||||||
return s.getString("warp")
|
return s.getString("warp")
|
||||||
}
|
}
|
||||||
@@ -446,6 +451,7 @@ func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) {
|
|||||||
"tgBotEnable": func() (interface{}, error) { return s.GetTgbotenabled() },
|
"tgBotEnable": func() (interface{}, error) { return s.GetTgbotenabled() },
|
||||||
"subEnable": func() (interface{}, error) { return s.GetSubEnable() },
|
"subEnable": func() (interface{}, error) { return s.GetSubEnable() },
|
||||||
"subURI": func() (interface{}, error) { return s.GetSubURI() },
|
"subURI": func() (interface{}, error) { return s.GetSubURI() },
|
||||||
|
"subJsonURI": func() (interface{}, error) { return s.GetSubJsonURI() },
|
||||||
"remarkModel": func() (interface{}, error) { return s.GetRemarkModel() },
|
"remarkModel": func() (interface{}, error) { return s.GetRemarkModel() },
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,10 +465,11 @@ func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) {
|
|||||||
result[key] = value
|
result[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
if result["subEnable"].(bool) && result["subURI"].(string) == "" {
|
if result["subEnable"].(bool) && (result["subURI"].(string) == "" || result["subJsonURI"].(string) == "") {
|
||||||
subURI := ""
|
subURI := ""
|
||||||
subPort, _ := s.GetSubPort()
|
subPort, _ := s.GetSubPort()
|
||||||
subPath, _ := s.GetSubPath()
|
subPath, _ := s.GetSubPath()
|
||||||
|
subJsonPath, _ := s.GetSubJsonPath()
|
||||||
subDomain, _ := s.GetSubDomain()
|
subDomain, _ := s.GetSubDomain()
|
||||||
subKeyFile, _ := s.GetSubKeyFile()
|
subKeyFile, _ := s.GetSubKeyFile()
|
||||||
subCertFile, _ := s.GetSubCertFile()
|
subCertFile, _ := s.GetSubCertFile()
|
||||||
@@ -483,12 +490,12 @@ func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) {
|
|||||||
} else {
|
} else {
|
||||||
subURI += fmt.Sprintf("%s:%d", subDomain, subPort)
|
subURI += fmt.Sprintf("%s:%d", subDomain, subPort)
|
||||||
}
|
}
|
||||||
if subPath[0] == byte('/') {
|
if result["subURI"].(string) == "" {
|
||||||
subURI += subPath
|
result["subURI"] = subURI + subPath
|
||||||
} else {
|
}
|
||||||
subURI += "/" + subPath
|
if result["subJsonURI"].(string) == "" {
|
||||||
|
result["subJsonURI"] = subURI + subJsonPath
|
||||||
}
|
}
|
||||||
result["subURI"] = subURI
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ func (s *XraySettingService) RegWarp(secretKey string, publicKey string) (string
|
|||||||
hostName, _ := os.Hostname()
|
hostName, _ := os.Hostname()
|
||||||
data := fmt.Sprintf(`{"key":"%s","tos":"%s","type": "PC","model": "x-ui", "name": "%s"}`, publicKey, tos, hostName)
|
data := fmt.Sprintf(`{"key":"%s","tos":"%s","type": "PC","model": "x-ui", "name": "%s"}`, publicKey, tos, hostName)
|
||||||
|
|
||||||
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg")
|
url := "https://api.cloudflareclient.com/v0a2158/reg"
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(data)))
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(data)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"x-ui/database/model"
|
"x-ui/database/model"
|
||||||
|
|
||||||
"github.com/gin-contrib/sessions"
|
sessions "github.com/Calidity/gin-sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -43,24 +43,25 @@
|
|||||||
"domainName" = "Domain Name"
|
"domainName" = "Domain Name"
|
||||||
"monitor" = "Listen IP"
|
"monitor" = "Listen IP"
|
||||||
"certificate" = "Certificate"
|
"certificate" = "Certificate"
|
||||||
"fail" = " Fail"
|
"fail" = " Failed"
|
||||||
"success" = " Successful"
|
"success" = " Successful"
|
||||||
"getVersion" = "Get Version"
|
"getVersion" = "Get Version"
|
||||||
"install" = "Install"
|
"install" = "Install"
|
||||||
"clients" = "Clients"
|
"clients" = "Clients"
|
||||||
"usage" = "Usage"
|
"usage" = "Usage"
|
||||||
"remained" = "Remained"
|
"remained" = "Remaining"
|
||||||
"secAlertTitle" = "Security Alert"
|
"secAlertTitle" = "Security Alert"
|
||||||
"secAlertSsl" = "THIS CONNECTION IS NOT SECURE. PLEASE AVOID ENTERING SENSITIVE INFORMATION UNTIL TLS IS ACTIVATED FOR DATA PROTECTION."
|
"secAlertSsl" = "This connection is not secure. Please avoid entering sensitive information until TLS is activated for data protection."
|
||||||
|
"secAlertConf" = "Certain configurations have been identified as susceptible to attacks, prompting immediate action to reinforce security protocols and safeguard against potential security breaches."
|
||||||
"security" = "Security"
|
"security" = "Security"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
"dashboard" = "OVERVIEW"
|
"dashboard" = "Overview"
|
||||||
"inbounds" = "INBOUNDS"
|
"inbounds" = "Inbounds"
|
||||||
"settings" = "PANEL SETTINGS"
|
"settings" = "Panel Settings"
|
||||||
"xray" = "XRAY CONFIGS"
|
"xray" = "Xray Configs"
|
||||||
"logout" = "LOG OUT"
|
"logout" = "Log Out"
|
||||||
"link" = "Management"
|
"link" = "Manage"
|
||||||
|
|
||||||
[pages.login]
|
[pages.login]
|
||||||
"title" = "Welcome"
|
"title" = "Welcome"
|
||||||
@@ -77,30 +78,34 @@
|
|||||||
"title" = "Overview"
|
"title" = "Overview"
|
||||||
"memory" = "RAM"
|
"memory" = "RAM"
|
||||||
"hard" = "Disk"
|
"hard" = "Disk"
|
||||||
"xrayStatus" = "Status"
|
"serverInfo" = "Server"
|
||||||
|
"hostname" = "Hostname"
|
||||||
|
"xrayStatus" = "Xray"
|
||||||
"stopXray" = "Stop"
|
"stopXray" = "Stop"
|
||||||
"restartXray" = "Restart"
|
"restartXray" = "Restart"
|
||||||
"xraySwitch" = "Change Xray Version"
|
"xraySwitch" = "Change Xray Version"
|
||||||
"xraySwitchClick" = "Choose the version you want to switch."
|
"xraySwitchClick" = "Choose the version you want to switch."
|
||||||
"xraySwitchClickDesk" = "Choose carefully, as older versions may not be compatible with the current configurations."
|
"xraySwitchClickDesk" = "Choose carefully, as older versions may not be compatible with the current configurations."
|
||||||
"operationHours" = "Uptime"
|
"operationHours" = "Uptime"
|
||||||
"operationHoursDesc" = "Time since startup"
|
"operationHoursDesc" = "Uptime since OS startup"
|
||||||
|
"xrayoperationHoursDesc" = "Uptime since Xray last restart"
|
||||||
"systemLoad" = "System Load"
|
"systemLoad" = "System Load"
|
||||||
"connectionTcpCountDesc" = "Total TCP connections across all networks"
|
"systemLoadDesc" = "Average load for the past 1, 5, and 15 minutes"
|
||||||
"connectionUdpCountDesc" = "Total UDP connections across all networks"
|
"connectionTcpCountDesc" = "Total TCP connections"
|
||||||
"upSpeed" = "Overall upload speed across all networks"
|
"connectionUdpCountDesc" = "Total UDP connections"
|
||||||
"downSpeed" = "Overall download speed across all networks"
|
"upSpeed" = "Overall upload speed"
|
||||||
"totalSent" = "Total traffic sent across all networks since OS startup"
|
"downSpeed" = "Overall download speed"
|
||||||
"totalReceive" = "Total traffic received across all networks since OS startup"
|
"totalSent" = "Total data sent since OS startup"
|
||||||
|
"totalReceive" = "Total data received since OS startup"
|
||||||
"xraySwitchVersionDialog" = "Change Xray Version"
|
"xraySwitchVersionDialog" = "Change Xray Version"
|
||||||
"xraySwitchVersionDialogDesc" = "Are you sure you want to change the Xray version to"
|
"xraySwitchVersionDialogDesc" = "Are you sure you want to change the Xray version to"
|
||||||
"dontRefresh" = "Installation is in progress, please do not refresh this page."
|
"dontRefresh" = "Installation is in progress, please do not refresh this page."
|
||||||
"logs" = "Logs"
|
"logs" = "Logs"
|
||||||
"config" = "Config"
|
"config" = "Config"
|
||||||
"backup" = "Backup & Restore"
|
"backup" = "Backup & Restore"
|
||||||
"backupTitle" = "Backup & Restore Database"
|
"backupTitle" = "Database Backup & Restore"
|
||||||
"backupDescription" = "It is recommended to make a backup before importing a new database."
|
"backupDescription" = "It is recommended to make a backup before restoring a database."
|
||||||
"exportDatabase" = "Backup"
|
"exportDatabase" = "Get Backup"
|
||||||
"importDatabase" = "Restore"
|
"importDatabase" = "Restore"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
@@ -116,13 +121,13 @@
|
|||||||
"traffic" = "Traffic"
|
"traffic" = "Traffic"
|
||||||
"details" = "Details"
|
"details" = "Details"
|
||||||
"transportConfig" = "Transport Config"
|
"transportConfig" = "Transport Config"
|
||||||
"expireDate" = "Expiry Date"
|
"expireDate" = "Expiration"
|
||||||
"resetTraffic" = "Reset Traffic"
|
"resetTraffic" = "Reset Traffic"
|
||||||
"addInbound" = "Add Inbound"
|
"addInbound" = "Add Inbound"
|
||||||
"generalActions" = "General Actions"
|
"generalActions" = "General Actions"
|
||||||
"create" = "Create"
|
"create" = "Create"
|
||||||
"update" = "Update"
|
"update" = "Update"
|
||||||
"modifyInbound" = "Modify Inbound"
|
"modifyInbound" = "Edit Inbound"
|
||||||
"deleteInbound" = "Delete Inbound"
|
"deleteInbound" = "Delete Inbound"
|
||||||
"deleteInboundContent" = "Are you sure you want to delete inbound?"
|
"deleteInboundContent" = "Are you sure you want to delete inbound?"
|
||||||
"deleteClient" = "Delete Client"
|
"deleteClient" = "Delete Client"
|
||||||
@@ -134,8 +139,8 @@
|
|||||||
"destinationPort" = "Destination Port"
|
"destinationPort" = "Destination Port"
|
||||||
"targetAddress" = "Target Address"
|
"targetAddress" = "Target Address"
|
||||||
"monitorDesc" = "Leave blank to listen on all IPs"
|
"monitorDesc" = "Leave blank to listen on all IPs"
|
||||||
"meansNoLimit" = "Means no limit"
|
"meansNoLimit" = "Zero means unlimited. (Unit: GB)"
|
||||||
"totalFlow" = "Total Flow"
|
"totalFlow" = "Total Traffic"
|
||||||
"leaveBlankToNeverExpire" = "Leave blank to never expire"
|
"leaveBlankToNeverExpire" = "Leave blank to never expire"
|
||||||
"noRecommendKeepDefault" = "It is recommended to keep the default"
|
"noRecommendKeepDefault" = "It is recommended to keep the default"
|
||||||
"certificatePath" = "File Path"
|
"certificatePath" = "File Path"
|
||||||
@@ -149,7 +154,7 @@
|
|||||||
"export" = "Export All URLs"
|
"export" = "Export All URLs"
|
||||||
"clone" = "Clone"
|
"clone" = "Clone"
|
||||||
"cloneInbound" = "Clone"
|
"cloneInbound" = "Clone"
|
||||||
"cloneInboundContent" = "All settings for this inbound, except Port, Listening IP, and Clients, will be applied to the clone."
|
"cloneInboundContent" = "All settings for this inbound, except Port, Listen IP, and Clients, will be applied to the clone."
|
||||||
"cloneInboundOk" = "Clone"
|
"cloneInboundOk" = "Clone"
|
||||||
"resetAllTraffic" = "Reset All Inbounds Traffic"
|
"resetAllTraffic" = "Reset All Inbounds Traffic"
|
||||||
"resetAllTrafficTitle" = "Reset All Inbounds Traffic"
|
"resetAllTrafficTitle" = "Reset All Inbounds Traffic"
|
||||||
@@ -166,12 +171,12 @@
|
|||||||
"email" = "Email"
|
"email" = "Email"
|
||||||
"emailDesc" = "Please provide a unique email address"
|
"emailDesc" = "Please provide a unique email address"
|
||||||
"setDefaultCert" = "Set Cert from Panel"
|
"setDefaultCert" = "Set Cert from Panel"
|
||||||
"telegramDesc" = "Please provide Telegram or Chat ID(s) without using the '@'. (get it here @userinfobot) or (use '/id' command in the bot)"
|
"telegramDesc" = "Please provide Chat ID(s) without using the '@' symbol. (Get it here @userinfobot) or (Use '/id' command in the bot)"
|
||||||
"subscriptionDesc" = "To find your subscription URL, navigate to the 'Details'. Additionally, you can use the same name for several clients."
|
"subscriptionDesc" = "To find your subscription URL, navigate to the 'More Information'. Additionally, you can use the same name for several clients."
|
||||||
"info" = "Info"
|
"info" = "Info"
|
||||||
"same" = "Same"
|
"same" = "Same"
|
||||||
"inboundData" = "Inbound's Data"
|
"inboundData" = "Inbound's Data"
|
||||||
"copyToClipboard" = "Copy to Clipboard"
|
"exportInbound" = "Export Inbound"
|
||||||
"import" = "Import"
|
"import" = "Import"
|
||||||
"importInbound" = "Import an Inbound"
|
"importInbound" = "Import an Inbound"
|
||||||
|
|
||||||
@@ -187,27 +192,28 @@
|
|||||||
"last" = "Last"
|
"last" = "Last"
|
||||||
"prefix" = "Prefix"
|
"prefix" = "Prefix"
|
||||||
"postfix" = "Postfix"
|
"postfix" = "Postfix"
|
||||||
"delayedStart" = "Start after First Use"
|
"delayedStart" = "Start on Initial Use"
|
||||||
"expireDays" = "Duration"
|
"expireDays" = "Duration"
|
||||||
"days" = "Day(s)"
|
"days" = "Day(s)"
|
||||||
"renew" = "Auto Renew"
|
"renew" = "Auto Renew"
|
||||||
"renewDesc" = "Auto-renewal after expiration. (0 = disable)(unit: day)"
|
"renewDesc" = "Auto-renewal after expiration. (0 = disable)(Unit: day)"
|
||||||
|
|
||||||
[pages.inbounds.toasts]
|
[pages.inbounds.toasts]
|
||||||
"obtain" = "Obtain"
|
"obtain" = "Obtain"
|
||||||
|
|
||||||
[pages.inbounds.stream.general]
|
[pages.inbounds.stream.general]
|
||||||
"requestHeader" = "Request Header"
|
"request" = "Request"
|
||||||
|
"response" = "Response"
|
||||||
"name" = "Name"
|
"name" = "Name"
|
||||||
"value" = "Value"
|
"value" = "Value"
|
||||||
|
|
||||||
[pages.inbounds.stream.tcp]
|
[pages.inbounds.stream.tcp]
|
||||||
"requestVersion" = "Request Version"
|
"version" = "Version"
|
||||||
"requestMethod" = "Request Method"
|
"method" = "Method"
|
||||||
"requestPath" = "Request Path"
|
"path" = "Path"
|
||||||
"responseVersion" = "Response Version"
|
"status" = "Status"
|
||||||
"responseStatus" = "Response Status"
|
"statusDescription" = "Status Description"
|
||||||
"responseStatusDescription" = "Response Status Description"
|
"requestHeader" = "Request Header"
|
||||||
"responseHeader" = "Response Header"
|
"responseHeader" = "Response Header"
|
||||||
|
|
||||||
[pages.inbounds.stream.quic]
|
[pages.inbounds.stream.quic]
|
||||||
@@ -220,23 +226,23 @@
|
|||||||
"restartPanel" = "Restart Panel"
|
"restartPanel" = "Restart Panel"
|
||||||
"restartPanelDesc" = "Are you sure you want to restart the panel? If you are unable to access the panel after restarting, please check the logs in the terminal script"
|
"restartPanelDesc" = "Are you sure you want to restart the panel? If you are unable to access the panel after restarting, please check the logs in the terminal script"
|
||||||
"resetDefaultConfig" = "Reset to Default"
|
"resetDefaultConfig" = "Reset to Default"
|
||||||
"panelConfig" = "Configuration"
|
"panelConfig" = "General"
|
||||||
"userSettings" = "Authentication"
|
"userSettings" = "Authentication"
|
||||||
"TGBotSettings" = "Telegram Bot"
|
"TGBotSettings" = "Telegram Bot"
|
||||||
"panelListeningIP" = "Listen IP"
|
"panelListeningIP" = "Listen IP"
|
||||||
"panelListeningIPDesc" = "The IP address for the web panel. (leave blank to listen on all IPs)"
|
"panelListeningIPDesc" = "The IP address for the web panel. (Leave blank to listen on all IPs)"
|
||||||
"panelListeningDomain" = "Listen Domain"
|
"panelListeningDomain" = "Listen Domain"
|
||||||
"panelListeningDomainDesc" = "The domain name for the web panel. (leave blank to listen on all domains and IPs)"
|
"panelListeningDomainDesc" = "The domain name for the web panel. (Leave blank to listen on all domains and IPs)"
|
||||||
"panelPort" = "Listen Port"
|
"panelPort" = "Listen Port"
|
||||||
"panelPortDesc" = "The port number for the web panel. (must be an unused port)"
|
"panelPortDesc" = "The port number for the web panel. (Must be an unused port)"
|
||||||
"publicKeyPath" = "Public Key Path"
|
"publicKeyPath" = "Public Key Path"
|
||||||
"publicKeyPathDesc" = "The public key file path for the web panel. (begins with ‘/‘)"
|
"publicKeyPathDesc" = "The public key file path for the web panel. (Begins with ‘/‘)"
|
||||||
"privateKeyPath" = "Private Key Path"
|
"privateKeyPath" = "Private Key Path"
|
||||||
"privateKeyPathDesc" = "The private key file path for the web panel. (begins with ‘/‘)"
|
"privateKeyPathDesc" = "The private key file path for the web panel. (Begins with ‘/‘)"
|
||||||
"panelUrlPath" = "URI Path"
|
"panelUrlPath" = "URI Path"
|
||||||
"panelUrlPathDesc" = "The URI path for the web panel. (begins with ‘/‘ and concludes with ‘/‘)"
|
"panelUrlPathDesc" = "The URI path for the web panel. (Begins with ‘/‘ and concludes with ‘/‘)"
|
||||||
"pageSize" = "Pagination Size"
|
"pageSize" = "Pagination Size"
|
||||||
"pageSizeDesc" = "Define page size for the inbounds table. (0 = disable)"
|
"pageSizeDesc" = "The page size for the inbounds table. (0 = disable)"
|
||||||
"remarkModel" = "Remark Model & Separation Character"
|
"remarkModel" = "Remark Model & Separation Character"
|
||||||
"sampleRemark" = "Sample Remark"
|
"sampleRemark" = "Sample Remark"
|
||||||
"oldUsername" = "Current Username"
|
"oldUsername" = "Current Username"
|
||||||
@@ -246,53 +252,55 @@
|
|||||||
"telegramBotEnable" = "Enable Telegram Bot"
|
"telegramBotEnable" = "Enable Telegram Bot"
|
||||||
"telegramBotEnableDesc" = "Enables the Telegram bot."
|
"telegramBotEnableDesc" = "Enables the Telegram bot."
|
||||||
"telegramToken" = "Telegram Token"
|
"telegramToken" = "Telegram Token"
|
||||||
"telegramTokenDesc" = "The Telegram bot token obtained from '@BotFather'."
|
"telegramTokenDesc" = "The Telegram token. (Get it here @BotFather)"
|
||||||
"telegramChatId" = "Admin Chat ID"
|
"telegramChatId" = "Admin Chat ID"
|
||||||
"telegramChatIdDesc" = "The Telegram Admin Chat ID(s). (comma-separated)(use @userinfobot) or (use '/id' command in the bot)"
|
"telegramChatIdDesc" = "The Telegram Admin Chat ID(s). (Comma-separated)(Get it here @userinfobot) or (Use '/id' command in the bot)"
|
||||||
"telegramNotifyTime" = "Notification Time"
|
"telegramNotifyTime" = "Notification Time"
|
||||||
"telegramNotifyTimeDesc" = "The Telegram bot notification time set for periodic reports. (use the crontab time format)"
|
"telegramNotifyTimeDesc" = "The Telegram bot notification time set for periodic reports. (Use the crontab time format)"
|
||||||
"tgNotifyBackup" = "Database Backup"
|
"tgNotifyBackup" = "Database Backup"
|
||||||
"tgNotifyBackupDesc" = "Send a database backup file with a report."
|
"tgNotifyBackupDesc" = "Get a database backup file with a report."
|
||||||
"tgNotifyLogin" = "Login Notification"
|
"tgNotifyLogin" = "Login Notification"
|
||||||
"tgNotifyLoginDesc" = "Get notified about the username, IP address, and time whenever someone attempts to log into your web panel."
|
"tgNotifyLoginDesc" = "Get notified about the username, IP, and time whenever someone attempts to log into your web panel."
|
||||||
"sessionMaxAge" = "Session Duration"
|
"sessionMaxAge" = "Session Duration"
|
||||||
"sessionMaxAgeDesc" = "The duration for which you can stay logged in. (unit: minute)"
|
"sessionMaxAgeDesc" = "The duration for which you can stay logged in. (Unit: minute)"
|
||||||
"expireTimeDiff" = "Client Expiration Threshold Notification"
|
"expireTimeDiff" = "Expiration Time Notification"
|
||||||
"expireTimeDiffDesc" = "Get notified about client expiration when reaching this threshold. (unit: day)"
|
"expireTimeDiffDesc" = "Get notified when the remaining time reaches the set threshold. (Unit: day)"
|
||||||
"trafficDiff" = "Traffic Exhaustion Threshold Notification"
|
"trafficDiff" = "Traffic Limit Notification"
|
||||||
"trafficDiffDesc" = "Get notified about traffic exhaustion when reaching this threshold. (unit: GB)"
|
"trafficDiffDesc" = "Get notified when remaining traffic reaches the set threshold. (Unit: GB)"
|
||||||
"tgNotifyCpu" = "CPU Load Threshold Notification"
|
"tgNotifyCpu" = "CPU Load Notification"
|
||||||
"tgNotifyCpuDesc" = "Get notified if CPU usage exceeds this threshold. (unit: %)"
|
"tgNotifyCpuDesc" = "Get notified if CPU load exceeds the set threshold. (Unit: %)"
|
||||||
"timeZone" = "Time Zone"
|
"timeZone" = "Time Zone"
|
||||||
"timeZoneDesc" = "Scheduled tasks run based on this time zone."
|
"timeZoneDesc" = "Scheduled tasks will run based on this time zone."
|
||||||
"subSettings" = "Subscription"
|
"subSettings" = "Subscription"
|
||||||
"subEnable" = "Enable Subscription Service"
|
"subEnable" = "Enable Subscription Service"
|
||||||
"subEnableDesc" = "Enables the subscription service."
|
"subEnableDesc" = "Enables the subscription service."
|
||||||
"subListen" = "Listen IP"
|
"subListen" = "Listen IP"
|
||||||
"subListenDesc" = "The IP address for the subscription service. (leave blank to listen on all IPs)"
|
"subListenDesc" = "The IP address for the subscription service. (Leave blank to listen on all IPs)"
|
||||||
"subPort" = "Listen Port"
|
"subPort" = "Listen Port"
|
||||||
"subPortDesc" = "The port number for the subscription service. (must be an unused port)"
|
"subPortDesc" = "The port number for the subscription service. (Must be an unused port)"
|
||||||
"subCertPath" = "Public Key Path"
|
"subCertPath" = "Public Key Path"
|
||||||
"subCertPathDesc" = "The public key file path for the subscription service. (begins with ‘/‘)"
|
"subCertPathDesc" = "The public key file path for the subscription service. (Begins with ‘/‘)"
|
||||||
"subKeyPath" = "Private Key Path"
|
"subKeyPath" = "Private Key Path"
|
||||||
"subKeyPathDesc" = "The private key file path for the subscription service. (begins with ‘/‘)"
|
"subKeyPathDesc" = "The private key file path for the subscription service. (Begins with ‘/‘)"
|
||||||
"subPath" = "URI Path"
|
"subPath" = "URI Path"
|
||||||
"subPathDesc" = "The URI path for the subscription service. (begins with ‘/‘ and concludes with ‘/‘)"
|
"subPathDesc" = "The URI path for the subscription service. (Begins with ‘/‘ and concludes with ‘/‘)"
|
||||||
"subDomain" = "Listen Domain"
|
"subDomain" = "Listen Domain"
|
||||||
"subDomainDesc" = "The domain name for the subscription service. (leave blank to listen on all domains and IPs)"
|
"subDomainDesc" = "The domain name for the subscription service. (Leave blank to listen on all domains and IPs)"
|
||||||
"subUpdates" = "Update Intervals"
|
"subUpdates" = "Update Intervals"
|
||||||
"subUpdatesDesc" = "The update intervals of the subscription URL in the client apps. (unit: hour)"
|
"subUpdatesDesc" = "The update intervals of the subscription URL in the client apps. (Unit: hour)"
|
||||||
"subEncrypt" = "Encode"
|
"subEncrypt" = "Encode"
|
||||||
"subEncryptDesc" = "The returned content of subscription service will be Base64 encoded."
|
"subEncryptDesc" = "The returned content of subscription service will be Base64 encoded."
|
||||||
"subShowInfo" = "Show Usage Info"
|
"subShowInfo" = "Show Usage Info"
|
||||||
"subShowInfoDesc" = "The remaining traffic and date will be displayed in the client apps."
|
"subShowInfoDesc" = "The remaining traffic and date will be displayed in the client apps."
|
||||||
"subURI" = "Reverse Proxy URI"
|
"subURI" = "Reverse Proxy URI"
|
||||||
"subURIDesc" = "The URI path of the subscription URL for use behind proxies."
|
"subURIDesc" = "The subscription service will use the URI that has been set up behind reverse proxies."
|
||||||
|
"fragment" = "Fragmentation"
|
||||||
|
"fragmentDesc" = "Enable fragmentation for TLS hello packet"
|
||||||
|
|
||||||
[pages.settings.toasts]
|
[pages.settings.toasts]
|
||||||
"modifySettings" = "Modify Settings"
|
"modifySettings" = "Modify Settings"
|
||||||
"getSettings" = "Get Settings"
|
"getSettings" = "Get Settings"
|
||||||
"modifyUser" = "Modify User"
|
"modifyUser" = "Modify Admin"
|
||||||
"originalUserPassIncorrect" = "The current username or password is incorrect"
|
"originalUserPassIncorrect" = "The current username or password is incorrect"
|
||||||
"userPassMustBeNotEmpty" = "The new username or password is required"
|
"userPassMustBeNotEmpty" = "The new username or password is required"
|
||||||
|
|
||||||
@@ -300,10 +308,12 @@
|
|||||||
"title" = "Xray Configs"
|
"title" = "Xray Configs"
|
||||||
"save" = "Save"
|
"save" = "Save"
|
||||||
"restart" = "Restart Xray"
|
"restart" = "Restart Xray"
|
||||||
"basicTemplate" = "Basic"
|
"basicTemplate" = "Basics"
|
||||||
"advancedTemplate" = "Advanced"
|
"advancedTemplate" = "Advanced"
|
||||||
"generalConfigs" = "General Strategy"
|
"generalConfigs" = "General Strategy"
|
||||||
"generalConfigsDesc" = "These options will determine general strategy adjustments."
|
"generalConfigsDesc" = "These options will determine general strategy adjustments."
|
||||||
|
"logConfigs" = "Log"
|
||||||
|
"logConfigsDesc" = "Logs may affect your server's efficiency. It is recommended to enable it wisely only in case of your needs"
|
||||||
"blockConfigs" = "Protection Shield"
|
"blockConfigs" = "Protection Shield"
|
||||||
"blockConfigsDesc" = "These options will block traffic based on specific requested protocols and websites."
|
"blockConfigsDesc" = "These options will block traffic based on specific requested protocols and websites."
|
||||||
"blockCountryConfigs" = "Block Country"
|
"blockCountryConfigs" = "Block Country"
|
||||||
@@ -311,11 +321,11 @@
|
|||||||
"directCountryConfigs" = "Direct Country"
|
"directCountryConfigs" = "Direct Country"
|
||||||
"directCountryConfigsDesc" = "These options will directly forward traffic based on the specific requested country."
|
"directCountryConfigsDesc" = "These options will directly forward traffic based on the specific requested country."
|
||||||
"ipv4Configs" = "IPv4 Routing"
|
"ipv4Configs" = "IPv4 Routing"
|
||||||
"ipv4ConfigsDesc" = "These options will route requests to destination only via IPv4."
|
"ipv4ConfigsDesc" = "These options will route traffic based on specific requested destination via system's IPv4."
|
||||||
"warpConfigs" = "WARP Routing"
|
"warpConfigs" = "WARP Config"
|
||||||
"warpConfigsDesc" = "WARP will route traffic to websites through Cloudflare servers."
|
"warpConfigsDesc" = "These options will route traffic based on specific requested destination via WARP."
|
||||||
"Template" = "Advanced Xray Configuration Template"
|
"Template" = "Advanced Xray Configuration Template"
|
||||||
"TemplateDesc" = "The final Xray configuration file will be generated based on this template."
|
"TemplateDesc" = "The final Xray config file will be generated based on this template."
|
||||||
"FreedomStrategy" = "Freedom Protocol Strategy"
|
"FreedomStrategy" = "Freedom Protocol Strategy"
|
||||||
"FreedomStrategyDesc" = "Set the output strategy for the network in the Freedom Protocol."
|
"FreedomStrategyDesc" = "Set the output strategy for the network in the Freedom Protocol."
|
||||||
"RoutingStrategy" = "Overall Routing Strategy"
|
"RoutingStrategy" = "Overall Routing Strategy"
|
||||||
@@ -359,9 +369,11 @@
|
|||||||
"GoogleWARP" = "Google"
|
"GoogleWARP" = "Google"
|
||||||
"GoogleWARPDesc" = "Routes traffic to Google via WARP."
|
"GoogleWARPDesc" = "Routes traffic to Google via WARP."
|
||||||
"OpenAIWARP" = "ChatGPT"
|
"OpenAIWARP" = "ChatGPT"
|
||||||
"OpenAIWARPDesc" = "Routes traffic to OpenAI (ChatGPT) via WARP."
|
"OpenAIWARPDesc" = "Routes traffic to ChatGPT via WARP."
|
||||||
"NetflixWARP" = "Netflix"
|
"NetflixWARP" = "Netflix"
|
||||||
"NetflixWARPDesc" = "Routes traffic to Netflix via WARP."
|
"NetflixWARPDesc" = "Routes traffic to Netflix via WARP."
|
||||||
|
"MetaWARP" = "Meta"
|
||||||
|
"MetaWARPDesc" = "Routes traffic to Meta (Instagram, Facebook, WhatsApp, Threads,...) via WARP."
|
||||||
"SpotifyWARP" = "Spotify"
|
"SpotifyWARP" = "Spotify"
|
||||||
"SpotifyWARPDesc" = "Routes traffic to Spotify via WARP."
|
"SpotifyWARPDesc" = "Routes traffic to Spotify via WARP."
|
||||||
"completeTemplate" = "All"
|
"completeTemplate" = "All"
|
||||||
@@ -369,6 +381,7 @@
|
|||||||
"Outbounds" = "Outbounds"
|
"Outbounds" = "Outbounds"
|
||||||
"Routings" = "Routing Rules"
|
"Routings" = "Routing Rules"
|
||||||
"RoutingsDesc" = "The priority of each rule is important!"
|
"RoutingsDesc" = "The priority of each rule is important!"
|
||||||
|
"Balancers" = "Balancers"
|
||||||
|
|
||||||
[pages.xray.rules]
|
[pages.xray.rules]
|
||||||
"first" = "First"
|
"first" = "First"
|
||||||
@@ -383,6 +396,7 @@
|
|||||||
"add" = "Add Rule"
|
"add" = "Add Rule"
|
||||||
"edit" = "Edit Rule"
|
"edit" = "Edit Rule"
|
||||||
"useComma" = "Comma-separated items"
|
"useComma" = "Comma-separated items"
|
||||||
|
"balancer" = "Balancer"
|
||||||
|
|
||||||
[pages.xray.outbound]
|
[pages.xray.outbound]
|
||||||
"addOutbound" = "Add Outbound"
|
"addOutbound" = "Add Outbound"
|
||||||
@@ -398,6 +412,18 @@
|
|||||||
"bridge" = "Bridge"
|
"bridge" = "Bridge"
|
||||||
"portal" = "Portal"
|
"portal" = "Portal"
|
||||||
"intercon" = "Interconnection"
|
"intercon" = "Interconnection"
|
||||||
|
"settings" = "Settings"
|
||||||
|
"accountInfo" = "Account Information"
|
||||||
|
"outboundStatus" = "Outbound Status"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "Add Balancer"
|
||||||
|
"editBalancer" = "Edit Balancer"
|
||||||
|
"balancerStrategy" = "Strategy"
|
||||||
|
"balancerSelectors" = "Selectors"
|
||||||
|
"tag" = "Tag"
|
||||||
|
"tagDesc" = "Unique Tag"
|
||||||
|
"balancerDesc" = "It is not possible to use balancerTag and outboundTag at the same time. If used at the same time, only outboundTag will work."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Secret Key"
|
"secretKey" = "Secret Key"
|
||||||
@@ -407,6 +433,21 @@
|
|||||||
"psk" = "PreShared Key"
|
"psk" = "PreShared Key"
|
||||||
"domainStrategy" = "Domain Strategy"
|
"domainStrategy" = "Domain Strategy"
|
||||||
|
|
||||||
|
[pages.xray.dns]
|
||||||
|
"enable" = "Enable DNS"
|
||||||
|
"enableDesc" = "Enable built-in DNS server"
|
||||||
|
"strategy" = "Query Strategy"
|
||||||
|
"strategyDesc" = "Overall strategy to resolve domain names"
|
||||||
|
"add" = "Add Server"
|
||||||
|
"edit" = "Edit Server"
|
||||||
|
"domains" = "Domains"
|
||||||
|
|
||||||
|
[pages.xray.fakedns]
|
||||||
|
"add" = "Add Fake DNS"
|
||||||
|
"edit" = "Edit Fake DNS"
|
||||||
|
"ipPool" = "IP Pool Subnet"
|
||||||
|
"poolSize" = "Pool Size"
|
||||||
|
|
||||||
[tgbot]
|
[tgbot]
|
||||||
"noResult" = "❗ No result!"
|
"noResult" = "❗ No result!"
|
||||||
"wentWrong" = "❌ Something went wrong!"
|
"wentWrong" = "❌ Something went wrong!"
|
||||||
@@ -427,11 +468,11 @@
|
|||||||
"status" = "✅ Bot is OK!"
|
"status" = "✅ Bot is OK!"
|
||||||
"usage" = "❗️ Please provide a text to search!"
|
"usage" = "❗️ Please provide a text to search!"
|
||||||
"getID" = "🆔 Your ID: <code>{{ .ID }}</code>"
|
"getID" = "🆔 Your ID: <code>{{ .ID }}</code>"
|
||||||
"helpAdminCommands" = "Search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nSearch for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>"
|
"helpAdminCommands" = "Search for a client email:\r\n<code>/Usage [Email]</code>\r\n\r\nSearch for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>"
|
||||||
"helpClientCommands" = "To search for statistics, simply use the following command:\r\n\r\n<code>/usage [UUID|Password]</code>\r\n\r\nUse UUID for VMess/VLESS and password for Trojan/Shadowsocks."
|
"helpClientCommands" = "To search for statistics, simply use the following command:\r\n\r\n<code>/Usage [UUID|Password]</code>\r\n\r\nUse UUID for VMess/VLESS and Password for Trojan/Shadowsocks."
|
||||||
|
|
||||||
[tgbot.messages]
|
[tgbot.messages]
|
||||||
"cpuThreshold" = "🔴 CPU load {{ .Percent }}% = CPU load {{ .Percent }}% is more than the threshold of {{ .Threshold }}%"
|
"cpuThreshold" = "🔴 CPU load {{ .Percent }}% Exceeds the threshold of {{ .Threshold }}%"
|
||||||
"loginSuccess" = "✅ Logged in to the web panel successfully.\r\n"
|
"loginSuccess" = "✅ Logged in to the web panel successfully.\r\n"
|
||||||
"loginFailed" = "❗Log in to the web panel failed.\r\n"
|
"loginFailed" = "❗Log in to the web panel failed.\r\n"
|
||||||
"report" = "🕰 Scheduled reports: {{ .RunTime }}\r\n"
|
"report" = "🕰 Scheduled reports: {{ .RunTime }}\r\n"
|
||||||
@@ -447,12 +488,12 @@
|
|||||||
"tcpCount" = "🔹 TCP: {{ .Count }}\r\n"
|
"tcpCount" = "🔹 TCP: {{ .Count }}\r\n"
|
||||||
"udpCount" = "🔸 UDP: {{ .Count }}\r\n"
|
"udpCount" = "🔸 UDP: {{ .Count }}\r\n"
|
||||||
"traffic" = "🚦 Traffic: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
|
"traffic" = "🚦 Traffic: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
|
||||||
"xrayStatus" = "ℹ️ Xray status: {{ .State }}\r\n"
|
"xrayStatus" = "ℹ️ Status: {{ .State }}\r\n"
|
||||||
"username" = "👤 Username: {{ .Username }}\r\n"
|
"username" = "👤 Username: {{ .Username }}\r\n"
|
||||||
"time" = "⏰ Time: {{ .Time }}\r\n"
|
"time" = "⏰ Time: {{ .Time }}\r\n"
|
||||||
"inbound" = "📍 Inbound: {{ .Remark }}\r\n"
|
"inbound" = "📍 Inbound: {{ .Remark }}\r\n"
|
||||||
"port" = "🔌 Port: {{ .Port }}\r\n"
|
"port" = "🔌 Port: {{ .Port }}\r\n"
|
||||||
"expire" = "📅 Expire date: {{ .DateTime }}\r\n \r\n"
|
"expire" = "📅 Expiry date: {{ .DateTime }}\r\n \r\n"
|
||||||
"expireIn" = "📅 Expire in: {{ .Time }}\r\n \r\n"
|
"expireIn" = "📅 Expire in: {{ .Time }}\r\n \r\n"
|
||||||
"active" = "💡 Active: {{ .Enable }}\r\n"
|
"active" = "💡 Active: {{ .Enable }}\r\n"
|
||||||
"online" = "🌐 Connection status: {{ .Status }}\r\n"
|
"online" = "🌐 Connection status: {{ .Status }}\r\n"
|
||||||
@@ -461,7 +502,7 @@
|
|||||||
"download" = "🔽 Download↓: {{ .Download }}\r\n"
|
"download" = "🔽 Download↓: {{ .Download }}\r\n"
|
||||||
"total" = "🔄 Total: {{ .UpDown }} / {{ .Total }}\r\n"
|
"total" = "🔄 Total: {{ .UpDown }} / {{ .Total }}\r\n"
|
||||||
"exhaustedMsg" = "🚨 Exhausted {{ .Type }}:\r\n"
|
"exhaustedMsg" = "🚨 Exhausted {{ .Type }}:\r\n"
|
||||||
"exhaustedCount" = "🚨 Exhausted {{ .Type }} count:\r\n"
|
"exhaustedCount" = "🚨 Exhausted {{ .Type }} Count:\r\n"
|
||||||
"onlinesCount" = "🌐 Online clients: {{ .Count }}\r\n"
|
"onlinesCount" = "🌐 Online clients: {{ .Count }}\r\n"
|
||||||
"disabled" = "🛑 Disabled: {{ .Disabled }}\r\n"
|
"disabled" = "🛑 Disabled: {{ .Disabled }}\r\n"
|
||||||
"depleteSoon" = "🔜 Deplete soon: {{ .Deplete }}\r\n \r\n"
|
"depleteSoon" = "🔜 Deplete soon: {{ .Deplete }}\r\n \r\n"
|
||||||
@@ -470,8 +511,8 @@
|
|||||||
"no" = "❌ No"
|
"no" = "❌ No"
|
||||||
|
|
||||||
[tgbot.buttons]
|
[tgbot.buttons]
|
||||||
"dbBackup" = "Get DB Backup"
|
"dbBackup" = "Get Backup"
|
||||||
"serverUsage" = "Server Usage"
|
"serverUsage" = "System Usage"
|
||||||
"getInbounds" = "Get Inbounds"
|
"getInbounds" = "Get Inbounds"
|
||||||
"depleteSoon" = "Deplete Soon"
|
"depleteSoon" = "Deplete Soon"
|
||||||
"clientUsage" = "Get Usage"
|
"clientUsage" = "Get Usage"
|
||||||
@@ -480,5 +521,5 @@
|
|||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
"getInboundsFailed" = "❌ Failed to get inbounds"
|
"getInboundsFailed" = "❌ Failed to get inbounds"
|
||||||
"askToAddUser" = "Your configuration is not found!\r\nYou should configure your Telegram username and ask your Admin to add it to your configuration(s)."
|
"askToAddUser" = "Your configuration is not found!\r\nPlease set a Telegram username, and then ask the service admin to add it to the configuration(s)."
|
||||||
"askToAddUserName" = "Your configuration is not found!\r\nPlease ask your Admin to use your Telegram username in your configuration(s).\r\n\r\nYour username: <b>@{{ .TgUserName }}</b>"
|
"askToAddUserName" = "Your configuration is not found!\r\nPlease ask the service admin to add your Telegram username to the configuration(s).\r\n\r\nYour Username: <b>@{{ .TgUserName }}</b>"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"indefinite" = "نامحدود"
|
"indefinite" = "نامحدود"
|
||||||
"unlimited" = "نامحدود"
|
"unlimited" = "نامحدود"
|
||||||
"none" = "هیچ"
|
"none" = "هیچ"
|
||||||
"qrCode" = "QRکد"
|
"qrCode" = "QR کد"
|
||||||
"info" = "اطلاعات بیشتر"
|
"info" = "اطلاعات بیشتر"
|
||||||
"edit" = "ویرایش"
|
"edit" = "ویرایش"
|
||||||
"delete" = "حذف"
|
"delete" = "حذف"
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
"offline" = "آفلاین"
|
"offline" = "آفلاین"
|
||||||
"online" = "آنلاین"
|
"online" = "آنلاین"
|
||||||
"domainName" = "آدرس دامنه"
|
"domainName" = "آدرس دامنه"
|
||||||
"monitor" = "آیپی اتصال"
|
"monitor" = "آدرس آیپی"
|
||||||
"certificate" = "گواهی"
|
"certificate" = "گواهی"
|
||||||
"fail" = "ناموفق"
|
"fail" = "ناموفق"
|
||||||
"success" = " موفق"
|
"success" = " موفق"
|
||||||
@@ -51,7 +51,8 @@
|
|||||||
"usage" = "استفاده"
|
"usage" = "استفاده"
|
||||||
"remained" = "باقیمانده"
|
"remained" = "باقیمانده"
|
||||||
"secAlertTitle" = "هشدارامنیتی"
|
"secAlertTitle" = "هشدارامنیتی"
|
||||||
"secAlertSsl" = "ایناتصالامن نیست. لطفا تازمانیکه تیالاس برای محافظت از دادهها فعال نشدهاست، از وارد کردن اطلاعات حساس خودداریکنید"
|
"secAlertSsl" = "ایناتصالامن نیست. لطفا تازمانیکه تیالاس برای محافظت از دادهها فعال نشدهاست، از وارد کردن اطلاعات حساس خودداری کنید"
|
||||||
|
"secAlertConf" = "پیکربندیهای خاصی مستعد حملات سایبری شناسایی شدهاند، اقدام فوری برای تقویت پروتکلهای امنیتی و محافظت در برابر نقضهای امنیتی لازم است"
|
||||||
"security" = "امنیت"
|
"security" = "امنیت"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
@@ -64,7 +65,7 @@
|
|||||||
|
|
||||||
[pages.login]
|
[pages.login]
|
||||||
"title" = "خوشآمدید"
|
"title" = "خوشآمدید"
|
||||||
"loginAgain" = "مدت زمان استفاده بهاتمامرسیده، لطفا دوباره وارد شوید"
|
"loginAgain" = "مدت زمان استفاده بهاتمام رسیده، لطفا دوباره وارد شوید"
|
||||||
|
|
||||||
[pages.login.toasts]
|
[pages.login.toasts]
|
||||||
"invalidFormData" = "اطلاعات بهدرستی وارد نشدهاست"
|
"invalidFormData" = "اطلاعات بهدرستی وارد نشدهاست"
|
||||||
@@ -77,44 +78,48 @@
|
|||||||
"title" = "نمای کلی"
|
"title" = "نمای کلی"
|
||||||
"memory" = "RAM"
|
"memory" = "RAM"
|
||||||
"hard" = "Disk"
|
"hard" = "Disk"
|
||||||
"xrayStatus" = "وضعیتایکسری"
|
"serverInfo" = "سرور"
|
||||||
|
"hostname" = "نام میزبان"
|
||||||
|
"xrayStatus" = "ایکسری"
|
||||||
"stopXray" = "توقف"
|
"stopXray" = "توقف"
|
||||||
"restartXray" = "شروعمجدد"
|
"restartXray" = "ریستارت"
|
||||||
"xraySwitch" = "تغییرنسخه"
|
"xraySwitch" = "تغییر نسخه ایکسری"
|
||||||
"xraySwitchClick" = "نسخه مورد نظر را انتخاب کنید"
|
"xraySwitchClick" = "نسخه مورد نظر را انتخاب کنید"
|
||||||
"xraySwitchClickDesk" = "لطفا بادقت انتخاب کنید. درصورت انتخاب نسخه قدیمیتر، امکان ناهماهنگی با پیکربندی فعلی وجود دارد"
|
"xraySwitchClickDesk" = "لطفا بادقت انتخاب کنید. درصورت انتخاب نسخه قدیمیتر، امکان ناهماهنگی با پیکربندیهای فعلی وجود دارد"
|
||||||
"operationHours" = "مدتکارکرد"
|
"operationHours" = "مدتکارکرد"
|
||||||
"operationHoursDesc" = "مدت فعالیت سیستمعامل پساز شروع بهکار"
|
"operationHoursDesc" = "مدت کارکرد سیستمعامل پساز شروع بهکار"
|
||||||
|
"xrayoperationHoursDesc" = "مدت کارکرد ایکسری پساز آخرین ریستارت"
|
||||||
"systemLoad" = "بارسیستم"
|
"systemLoad" = "بارسیستم"
|
||||||
"connectionTcpCountDesc" = "در تمامشبکهها TCP مجموعاتصالات"
|
"systemLoadDesc" = "میانگین بار در 1، 5 و 15 دقیقه گذشته"
|
||||||
"connectionUdpCountDesc" = "در تمامشبکهها UDP مجموعاتصالات"
|
"connectionTcpCountDesc" = "TCP کل اتصالات"
|
||||||
"upSpeed" = "سرعت کلی آپلود در تمامشبکهها"
|
"connectionUdpCountDesc" = "UDP کل اتصالات"
|
||||||
"downSpeed" = "سرعت کلی دانلود در تمامشبکهها"
|
"upSpeed" = "سرعت کلی آپلود"
|
||||||
"totalSent" = "مجموع ترافیک ارسالشده پساز شروعبهکار سیستمعامل"
|
"downSpeed" = "سرعت کلی دانلود"
|
||||||
"totalReceive" = "مجموع ترافیک دریافتشده پساز شروعبهکار سیستمعامل"
|
"totalSent" = "کل ترافیک ارسالی پساز شروع بهکار سیستمعامل"
|
||||||
|
"totalReceive" = "کل ترافیک دریافتی پساز شروع بهکار سیستمعامل"
|
||||||
"xraySwitchVersionDialog" = "تغییرنسخهایکسری"
|
"xraySwitchVersionDialog" = "تغییرنسخهایکسری"
|
||||||
"xraySwitchVersionDialogDesc" = "آیا از تغییر نسخه مطمئن هستید؟"
|
"xraySwitchVersionDialogDesc" = "آیا از تغییر نسخه مطمئن هستید؟"
|
||||||
"dontRefresh" = "در حال نصب، لطفا صفحه را رفرش نکنید"
|
"dontRefresh" = "در حال نصب، لطفا صفحه را رفرش نکنید"
|
||||||
"logs" = "گزارشها"
|
"logs" = "گزارشها"
|
||||||
"config" = "پیکربندی"
|
"config" = "کانفیگ"
|
||||||
"backup" = "پشتیبانگیری"
|
"backup" = "پشتیبانگیری و بازیابی"
|
||||||
"backupTitle" = "پشتیبانگیری دیتابیس"
|
"backupTitle" = "پشتیبانگیری و بازیابی دیتابیس"
|
||||||
"backupDescription" = "توصیهمیشود قبلاز واردکردن یک دیتابیس جدید، نسخه پشتیبان تهیه کنید"
|
"backupDescription" = "توصیهمیشود قبلاز بازیابی دیتابیس، یک نسخه پشتیبان تهیه کنید"
|
||||||
"exportDatabase" = "پشتیبانگیری"
|
"exportDatabase" = "پشتیبانگیری"
|
||||||
"importDatabase" = "بازگرداندن"
|
"importDatabase" = "بازیابی"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
"title" = "کاربران"
|
"title" = "کاربران"
|
||||||
"totalDownUp" = "دریافت/ارسال کل"
|
"totalDownUp" = "دریافت/ارسال کل"
|
||||||
"totalUsage" = "مصرف کل"
|
"totalUsage" = "مصرف کل"
|
||||||
"inboundCount" = "کل ورودیها"
|
"inboundCount" = "کل ورودیها"
|
||||||
"operate" = "عملیات"
|
"operate" = "منو"
|
||||||
"enable" = "فعال"
|
"enable" = "فعال"
|
||||||
"remark" = "نام"
|
"remark" = "نام"
|
||||||
"protocol" = "پروتکل"
|
"protocol" = "پروتکل"
|
||||||
"port" = "پورت"
|
"port" = "پورت"
|
||||||
"traffic" = "ترافیک"
|
"traffic" = "ترافیک"
|
||||||
"details" = "توضیحات"
|
"details" = "جزئیات"
|
||||||
"transportConfig" = "نحوه اتصال"
|
"transportConfig" = "نحوه اتصال"
|
||||||
"expireDate" = "تاریخ انقضا"
|
"expireDate" = "تاریخ انقضا"
|
||||||
"resetTraffic" = "ریست ترافیک"
|
"resetTraffic" = "ریست ترافیک"
|
||||||
@@ -133,8 +138,8 @@
|
|||||||
"network" = "شبکه"
|
"network" = "شبکه"
|
||||||
"destinationPort" = "پورت مقصد"
|
"destinationPort" = "پورت مقصد"
|
||||||
"targetAddress" = "آدرس مقصد"
|
"targetAddress" = "آدرس مقصد"
|
||||||
"monitorDesc" = "بهطور پیشفرض خالیبگذارید"
|
"monitorDesc" = "برای گوشدادن بهتمام آیپیها خالیبگذارید"
|
||||||
"meansNoLimit" = "یعنیبدونمحدودیت"
|
"meansNoLimit" = "صفر یعنی نامحدود. واحد: گیگابایت"
|
||||||
"totalFlow" = "ترافیک کل"
|
"totalFlow" = "ترافیک کل"
|
||||||
"leaveBlankToNeverExpire" = "برای منقضینشدن خالیبگذارید"
|
"leaveBlankToNeverExpire" = "برای منقضینشدن خالیبگذارید"
|
||||||
"noRecommendKeepDefault" = "توصیهمیشود بهطور پیشفرض حفظشود"
|
"noRecommendKeepDefault" = "توصیهمیشود بهطور پیشفرض حفظشود"
|
||||||
@@ -144,7 +149,7 @@
|
|||||||
"publicKeyContent" = "محتوای کلید عمومی"
|
"publicKeyContent" = "محتوای کلید عمومی"
|
||||||
"keyPath" = "مسیر کلید خصوصی"
|
"keyPath" = "مسیر کلید خصوصی"
|
||||||
"keyContent" = "محتوای کلید خصوصی"
|
"keyContent" = "محتوای کلید خصوصی"
|
||||||
"clickOnQRcode" = "برای کپی بر روی کدتصویری کلیک کنید"
|
"clickOnQRcode" = "برای کپی لینک بر روی کدتصویری کلیک کنید"
|
||||||
"client" = "کاربر"
|
"client" = "کاربر"
|
||||||
"export" = "استخراج لینکها"
|
"export" = "استخراج لینکها"
|
||||||
"clone" = "شبیهسازی"
|
"clone" = "شبیهسازی"
|
||||||
@@ -165,12 +170,12 @@
|
|||||||
"email" = "ایمیل"
|
"email" = "ایمیل"
|
||||||
"emailDesc" = "باید یک ایمیل یکتا باشد"
|
"emailDesc" = "باید یک ایمیل یکتا باشد"
|
||||||
"setDefaultCert" = "استفاده از گواهی پنل"
|
"setDefaultCert" = "استفاده از گواهی پنل"
|
||||||
"telegramDesc" = " استفاده کنید'/id'یااز دستور @userinfobot آنرا اینجا دریافت کنید .از آیدی(های) چت تلگرام بدون '@' استفاده کنید"
|
"telegramDesc" = "دریافت کنید '/id'یا دستور @userinfobot آیدی(های) چت مدیر را بدون '@' واردکنید. از"
|
||||||
"subscriptionDesc" = "شما میتوانید لینک سابسکربپشن خودرا در 'جزئیات' پیدا کنید، همچنین میتوانید از همین نام برای چندین کاربر استفادهکنید"
|
"subscriptionDesc" = "لینک سابسکربپشن خودرا در 'اطلاعات بیشتر' پیدا کنید، همچنین میتوانید از همین نام برای چندین کاربر استفادهکنید"
|
||||||
"info" = "اطلاعات"
|
"info" = "اطلاعات"
|
||||||
"same" = "همسان"
|
"same" = "همسان"
|
||||||
"inboundData" = "دادههای ورودی"
|
"inboundData" = "دادههای ورودی"
|
||||||
"copyToClipboard" = "کپی در حافظه"
|
"exportInbound" = "استخراج ورودی"
|
||||||
"import" = "افزودن"
|
"import" = "افزودن"
|
||||||
"importInbound" = "افزودن یک ورودی"
|
"importInbound" = "افزودن یک ورودی"
|
||||||
|
|
||||||
@@ -196,17 +201,18 @@
|
|||||||
"obtain" = "فراهمسازی"
|
"obtain" = "فراهمسازی"
|
||||||
|
|
||||||
[pages.inbounds.stream.general]
|
[pages.inbounds.stream.general]
|
||||||
"requestHeader" = "درخواست سربرگ"
|
"request" = "درخواست"
|
||||||
|
"response" = "پاسخ"
|
||||||
"name" = "نام"
|
"name" = "نام"
|
||||||
"value" = "مقدار"
|
"value" = "مقدار"
|
||||||
|
|
||||||
[pages.inbounds.stream.tcp]
|
[pages.inbounds.stream.tcp]
|
||||||
"requestVersion" = "نسخه درخواست"
|
"version" = "نسخه"
|
||||||
"requestMethod" = "متد درخواست"
|
"method" = "متد"
|
||||||
"requestPath" = "مسیر درخواست"
|
"path" = "مسیر"
|
||||||
"responseVersion" = "نسخه پاسخ"
|
"status" = "وضعیت"
|
||||||
"responseStatus" = "وضعیت پاسخ"
|
"statusDescription" = "توضیحات وضعیت"
|
||||||
"responseStatusDescription" = "توضیحات وضعیت پاسخ"
|
"requestHeader" = "سربرگ درخواست"
|
||||||
"responseHeader" = "سربرگ پاسخ"
|
"responseHeader" = "سربرگ پاسخ"
|
||||||
|
|
||||||
[pages.inbounds.stream.quic]
|
[pages.inbounds.stream.quic]
|
||||||
@@ -217,23 +223,23 @@
|
|||||||
"save" = "ذخیره"
|
"save" = "ذخیره"
|
||||||
"infoDesc" = "برای اعمال تغییرات در این بخش باید پس از ذخیره کردن، پنل را ریستارت کنید"
|
"infoDesc" = "برای اعمال تغییرات در این بخش باید پس از ذخیره کردن، پنل را ریستارت کنید"
|
||||||
"restartPanel" = "ریستارت پنل"
|
"restartPanel" = "ریستارت پنل"
|
||||||
"restartPanelDesc" = "آیا مطمئن به ریستارت پنل هستید؟ اگر پساز ریستارت نمیتوانید به پنل دسترسی پیدا کنید، لطفاً گزارشهای موجود در اسکریپت پنل را بررسی کنید"
|
"restartPanelDesc" = "آیا مطمئن به ریستارت پنل هستید؟ اگر پساز ریستارت نتوانستید به پنل دسترسی پیدا کنید، گزارشهای موجود در اسکریپت پنل را بررسی کنید"
|
||||||
"resetDefaultConfig" = "برگشت به پیشفرض"
|
"resetDefaultConfig" = "برگشت به پیشفرض"
|
||||||
"panelConfig" = "پیکربندی"
|
"panelConfig" = "عمومی"
|
||||||
"userSettings" = "احرازهویت"
|
"userSettings" = "احرازهویت"
|
||||||
"TGBotSettings" = "ربات تلگرام"
|
"TGBotSettings" = "ربات تلگرام"
|
||||||
"panelListeningIP" = "آدرس آیپی"
|
"panelListeningIP" = "آدرس آیپی"
|
||||||
"panelListeningIPDesc" = "آدرس آیپی برای وب پنل. برای گوشدادن بهتمام آیپیها خالیبگذارید"
|
"panelListeningIPDesc" = "آدرس آیپی برای وب پنل. برای گوشدادن بهتمام آیپیها خالیبگذارید"
|
||||||
"panelListeningDomain" = "نام دامنه"
|
"panelListeningDomain" = "نام دامنه"
|
||||||
"panelListeningDomainDesc" = "آدرس دامنه برای وب پنل. برای گوش دادن بهتمام دامنهها و آیپیها خالیبگذارید"
|
"panelListeningDomainDesc" = "آدرس دامنه برای وب پنل. برای گوشدادن بهتمام دامنهها و آیپیها خالیبگذارید"
|
||||||
"panelPort" = "پورت"
|
"panelPort" = "شماره پورت"
|
||||||
"panelPortDesc" = "شماره پورت برای وب پنل. باید پورت استفاده نشدهباشد"
|
"panelPortDesc" = "شماره پورت برای وب پنل. باید پورت استفاده نشدهباشد"
|
||||||
"publicKeyPath" = "مسیر کلید عمومی"
|
"publicKeyPath" = "مسیر کلید عمومی"
|
||||||
"publicKeyPathDesc" = "مسیر فایل کلیدعمومی برای وب پنل. با '/' شروعمیشود"
|
"publicKeyPathDesc" = "مسیر فایل کلیدعمومی برای وب پنل. با '/' شروعمیشود"
|
||||||
"privateKeyPath" = "مسیر کلید خصوصی"
|
"privateKeyPath" = "مسیر کلید خصوصی"
|
||||||
"privateKeyPathDesc" = "مسیر فایل کلیدخصوصی برای وب پنل. با '/' شروعمیشود"
|
"privateKeyPathDesc" = "مسیر فایل کلیدخصوصی برای وب پنل. با '/' شروعمیشود"
|
||||||
"panelUrlPath" = "URI مسیر"
|
"panelUrlPath" = "URI مسیر"
|
||||||
"panelUrlPathDesc" = "برای وب پنل. با '/' شروع و با '/' خاتمه مییابد URI مسیر"
|
"panelUrlPathDesc" = "مسیر لینک وب پنل. با '/' شروع و با '/' خاتمه مییابد"
|
||||||
"pageSize" = "اندازه صفحه بندی جدول"
|
"pageSize" = "اندازه صفحه بندی جدول"
|
||||||
"pageSizeDesc" = "اندازه صفحه برای جدول ورودیها. 0 = غیرفعال"
|
"pageSizeDesc" = "اندازه صفحه برای جدول ورودیها. 0 = غیرفعال"
|
||||||
"remarkModel" = "نامکانفیگ و جداکننده"
|
"remarkModel" = "نامکانفیگ و جداکننده"
|
||||||
@@ -245,48 +251,50 @@
|
|||||||
"telegramBotEnable" = "فعالسازی ربات تلگرام"
|
"telegramBotEnable" = "فعالسازی ربات تلگرام"
|
||||||
"telegramBotEnableDesc" = "ربات تلگرام را فعال میکند"
|
"telegramBotEnableDesc" = "ربات تلگرام را فعال میکند"
|
||||||
"telegramToken" = "توکن تلگرام"
|
"telegramToken" = "توکن تلگرام"
|
||||||
"telegramTokenDesc" = "دریافت کنید @botfather توکن را میتوانید از"
|
"telegramTokenDesc" = "دریافت کنید @botfather توکن تلگرام، از"
|
||||||
"telegramChatId" = "آیدی چت مدیر"
|
"telegramChatId" = "آیدی چت مدیر"
|
||||||
"telegramChatIdDesc" = "استفادهکنید'/id'یا دستور @userinfobot آیدی(های) چت تلگرام مدیر، برای دریافت شناسههای چت خود از"
|
"telegramChatIdDesc" = "دریافت کنید '/id'یا دستور @userinfobot آیدی(های) چت مدیر، از"
|
||||||
"telegramNotifyTime" = "زمان نوتیفیکیشن"
|
"telegramNotifyTime" = "زمان اطلاعرسانی"
|
||||||
"telegramNotifyTimeDesc" = "زماناطلاعرسانی ربات تلگرام برای گزارش های دورهای. از فرمت زمانبندی لینوکس استفادهکنید"
|
"telegramNotifyTimeDesc" = "زماناطلاعرسانی ربات تلگرام برای ارسال گزارشهای دورهای. از فرمت زمانی کرونتاب استفادهکنید"
|
||||||
"tgNotifyBackup" = "پشتیبانگیری از دیتابیس"
|
"tgNotifyBackup" = "پشتیبانگیری دیتابیس"
|
||||||
"tgNotifyBackupDesc" = "فایل پشتیباندیتابیس را بههمراه گزارش ارسال میکند"
|
"tgNotifyBackupDesc" = "فایل پشتیبان دیتابیس را بههمراه گزارش دریافت میکنید"
|
||||||
"tgNotifyLogin" = "اعلان ورود"
|
"tgNotifyLogin" = "اطلاعرسانی ورود"
|
||||||
"tgNotifyLoginDesc" = "نامکاربری، آدرس آیپی، و زمان ورود، فردی که سعی میکند وارد پنل شود را نمایش میدهد"
|
"tgNotifyLoginDesc" = "هر زمان کسی سعی به ورود به وب پنل شما را داشت. درباره نامکاربری، آیپی و زمان، مطلع میشوید"
|
||||||
"sessionMaxAge" = "بیشینه زمان جلسه وب"
|
"sessionMaxAge" = "مدت جلسه"
|
||||||
"sessionMaxAgeDesc" = "بیشینه زمانی که میتوانید لاگین بمانید. واحد: دقیقه"
|
"sessionMaxAgeDesc" = "بیشینه مدت زمانیکه میتوانید لاگین بمانید. واحد: دقیقه"
|
||||||
"expireTimeDiff" = "آستانه زمان باقی مانده"
|
"expireTimeDiff" = "اطلاعرسانی زمانانقضا"
|
||||||
"expireTimeDiffDesc" = "فاصله زمانی هشدار تا رسیدن به زمان انقضا. واحد: روز"
|
"expireTimeDiffDesc" = "وقتی زمان باقیمانده بهآستانه تعیینشده رسید، مطلع میشوید. واحد: روز"
|
||||||
"trafficDiff" = "آستانه ترافیک باقی مانده"
|
"trafficDiff" = "اطلاعرسانی ترافیک باقیمانده"
|
||||||
"trafficDiffDesc" = "فاصله زمانی هشدار تا رسیدن به اتمام ترافیک. واحد: گیگابایت"
|
"trafficDiffDesc" = "وقتی ترافیک باقیمانده بهآستانه تعیینشده رسید، مطلع میشوید. واحد: گیگابایت"
|
||||||
"tgNotifyCpu" = "آستانه هشدار بار پردازنده"
|
"tgNotifyCpu" = "اطلاعرسانی بار پردازنده"
|
||||||
"tgNotifyCpuDesc" = "اگر بار روی پردازنده ازاین آستانه فراتر رفت، برای شما پیام ارسال میشود. واحد: درصد"
|
"tgNotifyCpuDesc" = "اگر بار پردازنده از آستانه تعیینشده فراتر رفت، مطلع میشوید. واحد: درصد"
|
||||||
"timeZone" = "منطقه زمانی"
|
"timeZone" = "منطقه زمانی"
|
||||||
"timeZoneDesc" = "وظایف برنامه ریزی شده بر اساس این منطقهزمانی اجرا میشود"
|
"timeZoneDesc" = "وظایف برنامه ریزی شده بر اساس این منطقهزمانی اجرا میشود"
|
||||||
"subSettings" = "سابسکریپشن"
|
"subSettings" = "سابسکریپشن"
|
||||||
"subEnable" = "فعالسازی سرویس سابسکریپشن"
|
"subEnable" = "فعالسازی سرویس سابسکریپشن"
|
||||||
"subEnableDesc" = " سرویس سابسکریپشن را فعالمیکند"
|
"subEnableDesc" = " سرویس سابسکریپشن را فعال میکند"
|
||||||
"subListen" = "آدرس آیپی"
|
"subListen" = "آدرس آیپی"
|
||||||
"subListenDesc" = "آدرس آیپی برای سرویس سابسکریپشن. برای گوش دادن بهتمام آیپیها خالیبگذارید"
|
"subListenDesc" = "آدرس آیپی برای سابسکریپشن. برای گوشدادن بهتمام آیپیها خالیبگذارید"
|
||||||
"subPort" = "پورت"
|
"subPort" = "شماره پورت"
|
||||||
"subPortDesc" = "شماره پورت برای سرویس سابسکریپشن. باید پورت استفاده نشدهباشد"
|
"subPortDesc" = "شماره پورت برای سابسکریپشن. باید پورت استفاده نشدهباشد"
|
||||||
"subCertPath" = "مسیر کلید عمومی"
|
"subCertPath" = "مسیر کلید عمومی"
|
||||||
"subCertPathDesc" = "مسیر فایل کلیدعمومی برای سرویس سابیکریپشن. با '/' شروعمیشود"
|
"subCertPathDesc" = "مسیر فایل کلیدعمومی برای سابیکریپشن. با '/' شروعمیشود"
|
||||||
"subKeyPath" = "مسیر کلید خصوصی"
|
"subKeyPath" = "مسیر کلید خصوصی"
|
||||||
"subKeyPathDesc" = "مسیر فایل کلیدخصوصی برای سرویس سابسکریپشن. با '/' شروعمیشود"
|
"subKeyPathDesc" = "مسیر فایل کلیدخصوصی برای سابسکریپشن. با '/' شروعمیشود"
|
||||||
"subPath" = "URI مسیر"
|
"subPath" = "URI مسیر"
|
||||||
"subPathDesc" = "برای سرویس سابسکریپشن. با '/' شروع و با '/' خاتمه مییابد URI مسیر"
|
"subPathDesc" = "مسیر لینک سابسکریپشن. با '/' شروع و با '/' خاتمه مییابد"
|
||||||
"subDomain" = "نام دامنه"
|
"subDomain" = "نام دامنه"
|
||||||
"subDomainDesc" = "آدرس دامنه برای سرویس سابسکریپشن. برای گوش دادن به تمام دامنهها و آیپیها خالیبگذارید"
|
"subDomainDesc" = "آدرس دامنه برای سابسکریپشن. برای گوشدادن بهتمام دامنهها و آیپیها خالیبگذارید"
|
||||||
"subUpdates" = "فاصله بروزرسانی سابسکریپشن"
|
"subUpdates" = "فاصله بروزرسانی"
|
||||||
"subUpdatesDesc" = "فاصله مابین بروزرسانی در برنامههای کاربری - واحد: ساعت"
|
"subUpdatesDesc" = "فاصله مابین بروزرسانی لینک سابسکریپشن در برنامههای کاربری. واحد: ساعت"
|
||||||
"subEncrypt" = "کدگذاری"
|
"subEncrypt" = "کدگذاری"
|
||||||
"subEncryptDesc" = "کدگذاری خواهدشد Base64 محتوای برگشتی سرویس سابسکریپشن برپایه"
|
"subEncryptDesc" = " محتوای برگشتی سابسکریپشن برپایه بیس64 کدگذاری خواهدشد"
|
||||||
"subShowInfo" = "نمایش اطلاعات مصرف"
|
"subShowInfo" = "نمایش اطلاعات مصرف"
|
||||||
"subShowInfoDesc" = "ترافیک و زمان باقیمانده را در برنامههای کاربری نمایش میدهد"
|
"subShowInfoDesc" = "ترافیک و زمان باقیمانده را در برنامههای کاربری نمایش میدهد"
|
||||||
"subURI" = "پروکسی معکوس URI مسیر"
|
"subURI" = "پراکسی معکوس URI"
|
||||||
"subURIDesc" = "سابسکریپشن را برای استفاده در پشت پراکسیها تغییر میدهد URI مسیر"
|
"subURIDesc" = "سابسکریپشن از لینکی که در پشت پراکسیهای معکوس تنظیم شده، استفاده خواهدکرد"
|
||||||
|
"fragment" = "تکهتکه شدن"
|
||||||
|
"fragmentDesc" = "فعال کردن تکه تکه شدن برای بسته نخست تیالاس"
|
||||||
|
|
||||||
[pages.settings.toasts]
|
[pages.settings.toasts]
|
||||||
"modifySettings" = "ویرایش تنظیمات"
|
"modifySettings" = "ویرایش تنظیمات"
|
||||||
@@ -303,6 +311,8 @@
|
|||||||
"advancedTemplate" = "پیشرفته"
|
"advancedTemplate" = "پیشرفته"
|
||||||
"generalConfigs" = "استراتژی کلی"
|
"generalConfigs" = "استراتژی کلی"
|
||||||
"generalConfigsDesc" = "این گزینهها استراتژی کلی ترافیک را تعیین میکنند"
|
"generalConfigsDesc" = "این گزینهها استراتژی کلی ترافیک را تعیین میکنند"
|
||||||
|
"logConfigs" = "گزارشها"
|
||||||
|
"logConfigsDesc" = "گزارشها ممکن است بر کارایی سرور شما تأثیر بگذارند. توصیه می شود فقط در صورت نیاز آن را آگاهانه فعال کنید"
|
||||||
"blockConfigs" = "سپر محافظ"
|
"blockConfigs" = "سپر محافظ"
|
||||||
"blockConfigsDesc" = "این گزینهها ترافیک را بر اساس پروتکلهای درخواستی خاص، و وب سایتها مسدود میکند"
|
"blockConfigsDesc" = "این گزینهها ترافیک را بر اساس پروتکلهای درخواستی خاص، و وب سایتها مسدود میکند"
|
||||||
"blockCountryConfigs" = "مسدودسازی کشور"
|
"blockCountryConfigs" = "مسدودسازی کشور"
|
||||||
@@ -310,9 +320,9 @@
|
|||||||
"directCountryConfigs" = "اتصال مستقیم کشور"
|
"directCountryConfigs" = "اتصال مستقیم کشور"
|
||||||
"directCountryConfigsDesc" = "این گزینهها ترافیک را بر اساس کشور درخواستی خاص بصورت مستقیم ارسال میکند"
|
"directCountryConfigsDesc" = "این گزینهها ترافیک را بر اساس کشور درخواستی خاص بصورت مستقیم ارسال میکند"
|
||||||
"ipv4Configs" = "IPv4 مسیریابی"
|
"ipv4Configs" = "IPv4 مسیریابی"
|
||||||
"ipv4ConfigsDesc" = "این گزینهها درخواستها را فقط از طریق آیپینسخه4 به مقصد هدایت میکند"
|
"ipv4ConfigsDesc" = "این گزینهها ترافیک را از طریق آیپی نسخه4 ماشین، به مقصد هدایت میکند"
|
||||||
"warpConfigs" = "تنظیمات برای وارپ"
|
"warpConfigs" = "WARP تنظمیات"
|
||||||
"warpConfigsDesc" = ".وارپ ترافیک را از طریق سرورهای کلادفلر به وب سایت ها هدایت می کند"
|
"warpConfigsDesc" = "این گزینهها ترافیک را از طریق وارپ کلادفلر به مقصد هدایت میکند"
|
||||||
"Template" = "پیکربندی پیشرفته الگو ایکسری"
|
"Template" = "پیکربندی پیشرفته الگو ایکسری"
|
||||||
"TemplateDesc" = "فایل پیکربندی نهایی ایکسری بر اساس این الگو ایجاد میشود"
|
"TemplateDesc" = "فایل پیکربندی نهایی ایکسری بر اساس این الگو ایجاد میشود"
|
||||||
"FreedomStrategy" = "Freedom استراتژی پروتکل"
|
"FreedomStrategy" = "Freedom استراتژی پروتکل"
|
||||||
@@ -325,7 +335,7 @@
|
|||||||
"PrivateIpDesc" = "اتصال به آیپیهای رنج خصوصی را مسدود میکند"
|
"PrivateIpDesc" = "اتصال به آیپیهای رنج خصوصی را مسدود میکند"
|
||||||
"Ads" = "مسدودسازی تبلیغات"
|
"Ads" = "مسدودسازی تبلیغات"
|
||||||
"AdsDesc" = "وبسایتهای تبلیغاتی را مسدود میکند"
|
"AdsDesc" = "وبسایتهای تبلیغاتی را مسدود میکند"
|
||||||
"Family" = "محافظت خانواده"
|
"Family" = "محافظ خانواده"
|
||||||
"FamilyDesc" = "محتوای مخصوص بزرگسالان، و وبسایتهای ناامن را مسدود میکند"
|
"FamilyDesc" = "محتوای مخصوص بزرگسالان، و وبسایتهای ناامن را مسدود میکند"
|
||||||
"IRIp" = "مسدودسازی اتصال به آیپیهای ایران"
|
"IRIp" = "مسدودسازی اتصال به آیپیهای ایران"
|
||||||
"IRIpDesc" = "اتصال به آیپیهای کشور ایران را مسدود میکند"
|
"IRIpDesc" = "اتصال به آیپیهای کشور ایران را مسدود میکند"
|
||||||
@@ -352,9 +362,9 @@
|
|||||||
"DirectRussiaDomain" = "ارتباط مستقیم دامنه های روسیه"
|
"DirectRussiaDomain" = "ارتباط مستقیم دامنه های روسیه"
|
||||||
"DirectRussiaDomainDesc" = "اتصال مستقیم به دامنههای کشور روسیه"
|
"DirectRussiaDomainDesc" = "اتصال مستقیم به دامنههای کشور روسیه"
|
||||||
"GoogleIPv4" = "گوگل"
|
"GoogleIPv4" = "گوگل"
|
||||||
"GoogleIPv4Desc" = "ترافیک را از طریق آیپینسخه4 به گوگل هدایت میکند"
|
"GoogleIPv4Desc" = "ترافیک را از طریق آیپی نسخه4، به گوگل هدایت میکند"
|
||||||
"NetflixIPv4" = "نتفلیکس"
|
"NetflixIPv4" = "نتفلیکس"
|
||||||
"NetflixIPv4Desc" = "ترافیک را از طریق آیپینسخه4 به نتفلیکس هدایت میکند"
|
"NetflixIPv4Desc" = "ترافیک را از طریق آیپی نسخه4، به نتفلیکس هدایت میکند"
|
||||||
"completeTemplate" = "کامل"
|
"completeTemplate" = "کامل"
|
||||||
"GoogleWARP" = "گوگل"
|
"GoogleWARP" = "گوگل"
|
||||||
"GoogleWARPDesc" = "ترافیک را از طریق وارپ به گوگل هدایت میکند"
|
"GoogleWARPDesc" = "ترافیک را از طریق وارپ به گوگل هدایت میکند"
|
||||||
@@ -362,12 +372,15 @@
|
|||||||
"OpenAIWARPDesc" = "ترافیک را از طریق وارپ به چت جیپیتی هدایت میکند"
|
"OpenAIWARPDesc" = "ترافیک را از طریق وارپ به چت جیپیتی هدایت میکند"
|
||||||
"NetflixWARP" = "نتفلیکس"
|
"NetflixWARP" = "نتفلیکس"
|
||||||
"NetflixWARPDesc" = "ترافیک را از طریق وارپ به نتفلیکس هدایت میکند"
|
"NetflixWARPDesc" = "ترافیک را از طریق وارپ به نتفلیکس هدایت میکند"
|
||||||
|
"MetaWARP" = "متا"
|
||||||
|
"MetaWARPDesc" = "ترافیک را از طریق وارپ به متا (اینستاگرام، فیس بوک، واتساپ، تردز و...) هدایت می کند."
|
||||||
"SpotifyWARP" = "اسپاتیفای"
|
"SpotifyWARP" = "اسپاتیفای"
|
||||||
"SpotifyWARPDesc" = " ترافیک را از طریق وارپ به اسپاتیفای هدایت میکند"
|
"SpotifyWARPDesc" = " ترافیک را از طریق وارپ به اسپاتیفای هدایت میکند"
|
||||||
"Inbounds" = "ورودیها"
|
"Inbounds" = "ورودیها"
|
||||||
"Outbounds" = "خروجیها"
|
"Outbounds" = "خروجیها"
|
||||||
"Routings" = "قوانین مسیریابی"
|
"Routings" = "قوانین مسیریابی"
|
||||||
"RoutingsDesc" = "اولویت هر قانون مهم است"
|
"RoutingsDesc" = "اولویت هر قانون مهم است"
|
||||||
|
"Balancers" = "بالانسرها"
|
||||||
|
|
||||||
[pages.xray.rules]
|
[pages.xray.rules]
|
||||||
"first" = "اولین"
|
"first" = "اولین"
|
||||||
@@ -382,6 +395,7 @@
|
|||||||
"add" = "افزودن قانون"
|
"add" = "افزودن قانون"
|
||||||
"edit" = "ویرایش قانون"
|
"edit" = "ویرایش قانون"
|
||||||
"useComma" = "موارد جداشده با کاما"
|
"useComma" = "موارد جداشده با کاما"
|
||||||
|
"balancer" = "بالانسر"
|
||||||
|
|
||||||
[pages.xray.outbound]
|
[pages.xray.outbound]
|
||||||
"addOutbound" = "افزودن خروجی"
|
"addOutbound" = "افزودن خروجی"
|
||||||
@@ -397,6 +411,18 @@
|
|||||||
"bridge" = "پل"
|
"bridge" = "پل"
|
||||||
"portal" = "پورتال"
|
"portal" = "پورتال"
|
||||||
"intercon" = "اتصال میانی"
|
"intercon" = "اتصال میانی"
|
||||||
|
"settings" = "تنظیمات"
|
||||||
|
"accountInfo" = "اطلاعات حساب"
|
||||||
|
"outboundStatus" = "وضعیت خروجی"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "افزودن بالانسر"
|
||||||
|
"editBalancer" = "ویرایش بالانسر"
|
||||||
|
"balancerStrategy" = "استراتژی"
|
||||||
|
"balancerSelectors" = "انتخابگرها"
|
||||||
|
"tag" = "برچسب"
|
||||||
|
"tagDesc" = "برچسب یگانه"
|
||||||
|
"balancerDesc" = "امکان استفاده همزمان برچسب خروجی و برچسب بالانسر باهم وجود ندارد. درصورت استفاده همزمان فقط برجسب خروجی عمل خواهد کرد."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "کلید شخصی"
|
"secretKey" = "کلید شخصی"
|
||||||
@@ -406,6 +432,21 @@
|
|||||||
"psk" = "کلید مشترک"
|
"psk" = "کلید مشترک"
|
||||||
"domainStrategy" = "استراتژی حل دامنه"
|
"domainStrategy" = "استراتژی حل دامنه"
|
||||||
|
|
||||||
|
[pages.xray.dns]
|
||||||
|
"enable" = "فعال کردن حل دامنه"
|
||||||
|
"enableDesc" = "سرور حل دامنه داخلی را فعال کنید"
|
||||||
|
"strategy" = "استراتژی پرسوجو"
|
||||||
|
"strategyDesc" = "استراتژی کلی برای حل نام دامنه"
|
||||||
|
"add" = "افزودن سرور"
|
||||||
|
"edit" = "ویرایش سرور"
|
||||||
|
"domains" = "دامنهها"
|
||||||
|
|
||||||
|
[pages.xray.fakedns]
|
||||||
|
"add" = "افزودن دیاناس جعلی"
|
||||||
|
"edit" = "ویرایش دیاناس جعلی"
|
||||||
|
"ipPool" = "زیرشبکه استخر آیپی"
|
||||||
|
"poolSize" = "اندازه استخر"
|
||||||
|
|
||||||
[tgbot]
|
[tgbot]
|
||||||
"noResult" = "❗نتیجهای یافت نشد"
|
"noResult" = "❗نتیجهای یافت نشد"
|
||||||
"wentWrong" = "❌ مشکلی رخ دادهاست"
|
"wentWrong" = "❌ مشکلی رخ دادهاست"
|
||||||
@@ -436,48 +477,48 @@
|
|||||||
"report" = "🕰 گزارشاتزمانبندیشده: {{ .RunTime }}\r\n"
|
"report" = "🕰 گزارشاتزمانبندیشده: {{ .RunTime }}\r\n"
|
||||||
"datetime" = "⏰ تاریخوزمان: {{ .DateTime }}\r\n"
|
"datetime" = "⏰ تاریخوزمان: {{ .DateTime }}\r\n"
|
||||||
"hostname" = "💻 ناممیزبان: {{ .Hostname }}\r\n"
|
"hostname" = "💻 ناممیزبان: {{ .Hostname }}\r\n"
|
||||||
"version" = "🚀 نسخهپنل: {{ .Version }}\r\n"
|
"version" = "🚀 X-UI: {{ .Version }}\r\n"
|
||||||
"ipv6" = "🌐 IPv6: {{ .IPv6 }}\r\n"
|
"ipv6" = "🌐 IPv6: {{ .IPv6 }}\r\n"
|
||||||
"ipv4" = "🌐 IPv4: {{ .IPv4 }}\r\n"
|
"ipv4" = "🌐 IPv4: {{ .IPv4 }}\r\n"
|
||||||
"ip" = "🌐 آدرسآیپی: {{ .IP }}\r\n"
|
"ip" = "🌐 IP: {{ .IP }}\r\n"
|
||||||
"serverUpTime" = "⏳ مدتکارکردسیستم: {{ .UpTime }} {{ .Unit }}\r\n"
|
"serverUpTime" = "⏳ مدتکارکرد: {{ .UpTime }} {{ .Unit }}\r\n"
|
||||||
"serverLoad" = "📈 بارسیستم: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n"
|
"serverLoad" = "📈 بارسیستم: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n"
|
||||||
"serverMemory" = "📋 RAM: {{ .Current }}/{{ .Total }}\r\n"
|
"serverMemory" = "📋 RAM: {{ .Current }}/{{ .Total }}\r\n"
|
||||||
"tcpCount" = "🔹 TCP: {{ .Count }}\r\n"
|
"tcpCount" = "🔹 TCP: {{ .Count }}\r\n"
|
||||||
"udpCount" = "🔸 UDP: {{ .Count }}\r\n"
|
"udpCount" = "🔸 UDP: {{ .Count }}\r\n"
|
||||||
"traffic" = "🚦 ترافیک: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
|
"traffic" = "🚦 ترافیک: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
|
||||||
"xrayStatus" = "ℹ️ وضعیتایکسری: {{ .State }}\r\n"
|
"xrayStatus" = "ℹ️ وضعیت: {{ .State }}\r\n"
|
||||||
"username" = "👤 نامکاربری: {{ .Username }}\r\n"
|
"username" = "👤 نامکاربری: {{ .Username }}\r\n"
|
||||||
"time" = "⏰ زمان: {{ .Time }}\r\n"
|
"time" = "⏰ زمان: {{ .Time }}\r\n"
|
||||||
"inbound" = "📍 نامورودی: {{ .Remark }}\r\n"
|
"inbound" = "📍 نامورودی: {{ .Remark }}\r\n"
|
||||||
"port" = "🔌 پورت: {{ .Port }}\r\n"
|
"port" = "🔌 پورت: {{ .Port }}\r\n"
|
||||||
"expire" = "📅 تاریخانقضا: {{ .DateTime }}\r\n \r\n"
|
"expire" = "📅 تاریخانقضا: {{ .DateTime }}\r\n \r\n"
|
||||||
"expireIn" = "📅 باقیماندهتاانقضا: {{ .Time }}\r\n \r\n"
|
"expireIn" = "📅 انقضا در: {{ .Time }}\r\n \r\n"
|
||||||
"active" = "💡 فعال: {{ .Enable }}\r\n"
|
"active" = "💡 فعال: {{ .Enable }}\r\n"
|
||||||
"online" = "🌐 وضعیت اتصال: {{ .Status }}\r\n"
|
"online" = "🌐 وضعیتاتصال: {{ .Status }}\r\n"
|
||||||
"email" = "📧 ایمیل: {{ .Email }}\r\n"
|
"email" = "📧 ایمیل: {{ .Email }}\r\n"
|
||||||
"upload" = "🔼 آپلود↑: {{ .Upload }}\r\n"
|
"upload" = "🔼 آپلود↑: {{ .Upload }}\r\n"
|
||||||
"download" = "🔽 دانلود↓: {{ .Download }}\r\n"
|
"download" = "🔽 دانلود↓: {{ .Download }}\r\n"
|
||||||
"total" = "🔄 کل: {{ .UpDown }} / {{ .Total }}\r\n"
|
"total" = "🔄 کل: {{ .UpDown }} / {{ .Total }}\r\n"
|
||||||
"exhaustedMsg" = "🚨 {{ .Type }} بهاتمامرسیدهاست:\r\n"
|
"exhaustedMsg" = "🚨 {{ .Type }} بهاتمامرسیدهاست:\r\n"
|
||||||
"exhaustedCount" = "🚨 تعداد {{ .Type }} بهاتمامرسیدهاست:\r\n"
|
"exhaustedCount" = "🚨 تعداد {{ .Type }} بهاتمام رسیدهاست:\r\n"
|
||||||
"onlinesCount" = "🌐 کاربرانآنلاین: {{ .Count }}\r\n"
|
"onlinesCount" = "🌐 کاربرانآنلاین: {{ .Count }}\r\n"
|
||||||
"disabled" = "🛑 غیرفعال: {{ .Disabled }}\r\n"
|
"disabled" = "🛑 غیرفعال: {{ .Disabled }}\r\n"
|
||||||
"depleteSoon" = "🔜 بهزودیبهپایانخواهدرسید: {{ .Deplete }}\r\n \r\n"
|
"depleteSoon" = "🔜 بهزودی بهپایان خواهدرسید: {{ .Deplete }}\r\n \r\n"
|
||||||
"backupTime" = "🗄 زمانپشتیبانگیری: {{ .Time }}\r\n"
|
"backupTime" = "🗄 زمانپشتیبانگیری: {{ .Time }}\r\n"
|
||||||
"yes" = "✅ بله"
|
"yes" = "✅ بله"
|
||||||
"no" = "❌ خیر"
|
"no" = "❌ خیر"
|
||||||
|
|
||||||
[tgbot.buttons]
|
[tgbot.buttons]
|
||||||
"dbBackup" = "دریافت پشتیبان دیتابیس"
|
"dbBackup" = "دریافت فایل پشتیبان"
|
||||||
"serverUsage" = "استفاده از سیستم"
|
"serverUsage" = "استفاده از سیستم"
|
||||||
"getInbounds" = "دریافت ورودیها"
|
"getInbounds" = "دریافت ورودیها"
|
||||||
"depleteSoon" = "بهزودی به پایان خواهد رسید"
|
"depleteSoon" = "بهزودی بهپایان خواهدرسید"
|
||||||
"clientUsage" = "دریافت آمار کاربر"
|
"clientUsage" = "دریافت آمار کاربر"
|
||||||
"onlines" = "کاربران آنلاین"
|
"onlines" = "کاربران آنلاین"
|
||||||
"commands" = "دستورات"
|
"commands" = "دستورات"
|
||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
"getInboundsFailed" = "❌ دریافت ورودیها باخطا مواجه شد"
|
"getInboundsFailed" = "❌ دریافت ورودیها باخطا مواجه شد"
|
||||||
"askToAddUser" = "پیکربندی شما پیدا نشد!\r\nشما باید نامکاربری تلگرام خود را پیکربندی کنید و از مدیر پنل خود بخواهید که آن را به پیکربندی شما اضافه کند"
|
"askToAddUser" = "پیکربندی شما پیدا نشد!\r\nشما باید نامکاربری تلگرام خود را تنظیم کنید و از مدیر سرویس خود بخواهید که آن را به پیکربندی(های) شما اضافه کند"
|
||||||
"askToAddUserName" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر پنل درخواست کنید اطلاعات تلگرام شما را در پیکربندی(های) مربوط بهشما تنظیمکند \r\n\r\nنامکاربری شما: @{{ .TgUserName }}"
|
"askToAddUserName" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر سرویس خود بخواهید اطلاعات تلگرام شما را به پیکربندی(های) شما اضافه کند \r\n\r\nنامکاربری شما: @{{ .TgUserName }}"
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
"remained" = "Осталось"
|
"remained" = "Осталось"
|
||||||
"secAlertTitle" = "Предупреждение системы безопасности"
|
"secAlertTitle" = "Предупреждение системы безопасности"
|
||||||
"secAlertSsl" = "Это соединение не защищено. Пожалуйста, воздержитесь от ввода конфиденциальной информации до тех пор, пока не будет активирован TLS для защиты данных"
|
"secAlertSsl" = "Это соединение не защищено. Пожалуйста, воздержитесь от ввода конфиденциальной информации до тех пор, пока не будет активирован TLS для защиты данных"
|
||||||
|
"secAlertConf" = "Некоторые конфигурации были определены как уязвимые для атак, что требует немедленных действий по усилению протоколов безопасности и защите от потенциальных нарушений безопасности."
|
||||||
"security" = "Безопасность"
|
"security" = "Безопасность"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
@@ -77,15 +78,19 @@
|
|||||||
"title" = "Статус системы"
|
"title" = "Статус системы"
|
||||||
"memory" = "ОЗУ"
|
"memory" = "ОЗУ"
|
||||||
"hard" = "Место на диске"
|
"hard" = "Место на диске"
|
||||||
"xrayStatus" = "Статус Xray"
|
"serverInfo" = "Сервер"
|
||||||
|
"hostname" = "Имя хоста"
|
||||||
|
"xrayStatus" = "Xray"
|
||||||
"stopXray" = "Остановка"
|
"stopXray" = "Остановка"
|
||||||
"restartXray" = "Перезапуск Xray"
|
"restartXray" = "Перезапуск"
|
||||||
"xraySwitch" = "Сменить версию"
|
"xraySwitch" = "Сменить версию"
|
||||||
"xraySwitchClick" = "Выберите желаемую версию"
|
"xraySwitchClick" = "Выберите желаемую версию"
|
||||||
"xraySwitchClickDesk" = "Выбирайте внимательно, так как старые версии могут быть несовместимы с текущими конфигурациями"
|
"xraySwitchClickDesk" = "Выбирайте внимательно, так как старые версии могут быть несовместимы с текущими конфигурациями"
|
||||||
"operationHours" = "Время работы"
|
"operationHours" = "Время работы"
|
||||||
"operationHoursDesc" = "Время работы системы: время с момента запуска."
|
"operationHoursDesc" = "Время безотказной работы с момента запуска ОС"
|
||||||
|
"xrayoperationHoursDesc" = "Время работы с момента последней перезагрузки Xray"
|
||||||
"systemLoad" = "Системная нагрузка"
|
"systemLoad" = "Системная нагрузка"
|
||||||
|
"systemLoadDesc" = "Средняя нагрузка за последние 1, 5 и 15 минут"
|
||||||
"connectionTcpCountDesc" = "Всего подключений TCP по всем сетевым картам."
|
"connectionTcpCountDesc" = "Всего подключений TCP по всем сетевым картам."
|
||||||
"connectionUdpCountDesc" = "Общее количество подключений UDP по всем сетевым картам."
|
"connectionUdpCountDesc" = "Общее количество подключений UDP по всем сетевым картам."
|
||||||
"upSpeed" = "Общая скорость отдачи"
|
"upSpeed" = "Общая скорость отдачи"
|
||||||
@@ -100,8 +105,8 @@
|
|||||||
"backup" = "Бекап и восстановление"
|
"backup" = "Бекап и восстановление"
|
||||||
"backupTitle" = "База данных бекапа и восстановления"
|
"backupTitle" = "База данных бекапа и восстановления"
|
||||||
"backupDescription" = "Не забудьте сделать резервную копию перед импортом новой базы данных"
|
"backupDescription" = "Не забудьте сделать резервную копию перед импортом новой базы данных"
|
||||||
"exportDatabase" = "Экспорт базы данных"
|
"exportDatabase" = "Резерв"
|
||||||
"importDatabase" = "Импорт базы данных"
|
"importDatabase" = "Восстановить"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
"title" = "Подключения"
|
"title" = "Подключения"
|
||||||
@@ -134,7 +139,7 @@
|
|||||||
"destinationPort" = "Порт назначения"
|
"destinationPort" = "Порт назначения"
|
||||||
"targetAddress" = "Целевой адрес"
|
"targetAddress" = "Целевой адрес"
|
||||||
"monitorDesc" = "Оставьте пустым по умолчанию"
|
"monitorDesc" = "Оставьте пустым по умолчанию"
|
||||||
"meansNoLimit" = "Значит без ограничений"
|
"meansNoLimit" = "Ноль означает неограниченно. (значение: ГБ)"
|
||||||
"totalFlow" = "Общий расход"
|
"totalFlow" = "Общий расход"
|
||||||
"leaveBlankToNeverExpire" = "Оставьте пустым, чтобы сделать бессрочно"
|
"leaveBlankToNeverExpire" = "Оставьте пустым, чтобы сделать бессрочно"
|
||||||
"noRecommendKeepDefault" = "Нет особых требований для сохранения настроек по умолчанию"
|
"noRecommendKeepDefault" = "Нет особых требований для сохранения настроек по умолчанию"
|
||||||
@@ -171,7 +176,7 @@
|
|||||||
"info" = "Информация"
|
"info" = "Информация"
|
||||||
"same" = "Тот же"
|
"same" = "Тот же"
|
||||||
"inboundData" = "Входящие данные"
|
"inboundData" = "Входящие данные"
|
||||||
"copyToClipboard" = "Копировать в буфер обмена"
|
"exportInbound" = "Экспорт входящих"
|
||||||
"import" = "Импортировать"
|
"import" = "Импортировать"
|
||||||
"importInbound" = "Импортировать входящее сообщение"
|
"importInbound" = "Импортировать входящее сообщение"
|
||||||
|
|
||||||
@@ -197,17 +202,18 @@
|
|||||||
"obtain" = "Получить"
|
"obtain" = "Получить"
|
||||||
|
|
||||||
[pages.inbounds.stream.general]
|
[pages.inbounds.stream.general]
|
||||||
"requestHeader" = "Заголовок запроса"
|
"request" = "Запрос"
|
||||||
|
"response" = "Ответ"
|
||||||
"name" = "Имя"
|
"name" = "Имя"
|
||||||
"value" = "Значение"
|
"value" = "Ценить"
|
||||||
|
|
||||||
[pages.inbounds.stream.tcp]
|
[pages.inbounds.stream.tcp]
|
||||||
"requestVersion" = "Версия запроса"
|
"version" = "Версия"
|
||||||
"requestMethod" = "Метод запроса"
|
"method" = "Метод"
|
||||||
"requestPath" = "Петь запроса"
|
"path" = "Путь"
|
||||||
"responseVersion" = "Версия ответа"
|
"status" = "Положение дел"
|
||||||
"responseStatus" = "Статус ответа"
|
"statusDescription" = "Описание статуса"
|
||||||
"responseStatusDescription" = "Описание статуса ответа"
|
"requestHeader" = "Заголовок запроса"
|
||||||
"responseHeader" = "Заголовок ответа"
|
"responseHeader" = "Заголовок ответа"
|
||||||
|
|
||||||
[pages.inbounds.stream.quic]
|
[pages.inbounds.stream.quic]
|
||||||
@@ -288,6 +294,8 @@
|
|||||||
"subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации"
|
"subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации"
|
||||||
"subURI" = "URI обратного прокси"
|
"subURI" = "URI обратного прокси"
|
||||||
"subURIDesc" = "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами"
|
"subURIDesc" = "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами"
|
||||||
|
"fragment" = "Фрагментация"
|
||||||
|
"fragmentDesc" = "Включить фрагментацию для пакета приветствия TLS"
|
||||||
|
|
||||||
[pages.settings.toasts]
|
[pages.settings.toasts]
|
||||||
"modifySettings" = "Изменение настроек"
|
"modifySettings" = "Изменение настроек"
|
||||||
@@ -304,6 +312,8 @@
|
|||||||
"advancedTemplate" = "Расширенные шаблоны"
|
"advancedTemplate" = "Расширенные шаблоны"
|
||||||
"generalConfigs" = "Основные настройки"
|
"generalConfigs" = "Основные настройки"
|
||||||
"generalConfigsDesc" = "Общие настройки"
|
"generalConfigsDesc" = "Общие настройки"
|
||||||
|
"logConfigs" = "Журнал"
|
||||||
|
"logConfigsDesc" = "Журналы могут повлиять на эффективность вашего сервера. Рекомендуется включать их с умом только в случае ваших нужд!"
|
||||||
"blockConfigs" = "Блокирующие конфигурации"
|
"blockConfigs" = "Блокирующие конфигурации"
|
||||||
"blockConfigsDesc" = "Эти параметры не позволят пользователям подключаться к определенным протоколам и веб-сайтам."
|
"blockConfigsDesc" = "Эти параметры не позволят пользователям подключаться к определенным протоколам и веб-сайтам."
|
||||||
"blockCountryConfigs" = "Конфигурация блокировки стран"
|
"blockCountryConfigs" = "Конфигурация блокировки стран"
|
||||||
@@ -362,6 +372,8 @@
|
|||||||
"OpenAIWARPDesc" = "Добавить маршрутизацию для OpenAI (ChatGPT) через WARP"
|
"OpenAIWARPDesc" = "Добавить маршрутизацию для OpenAI (ChatGPT) через WARP"
|
||||||
"NetflixWARP" = "Маршрутизация Netflix через WARP"
|
"NetflixWARP" = "Маршрутизация Netflix через WARP"
|
||||||
"NetflixWARPDesc" = "Добавить маршрутизацию для Netflix через WARP"
|
"NetflixWARPDesc" = "Добавить маршрутизацию для Netflix через WARP"
|
||||||
|
"MetaWARP" = "Мета"
|
||||||
|
"MetaWARPDesc" = "Направляет трафик в Meta (Instagram, Facebook, WhatsApp, Threads...) через WARP."
|
||||||
"SpotifyWARP" = "Маршрутизация Spotify через WARP"
|
"SpotifyWARP" = "Маршрутизация Spotify через WARP"
|
||||||
"SpotifyWARPDesc" = "Добавить маршрутизацию для Spotify через WARP"
|
"SpotifyWARPDesc" = "Добавить маршрутизацию для Spotify через WARP"
|
||||||
"completeTemplate" = "Все"
|
"completeTemplate" = "Все"
|
||||||
@@ -369,6 +381,7 @@
|
|||||||
"Outbounds" = "Исходящие"
|
"Outbounds" = "Исходящие"
|
||||||
"Routings" = "Правила маршрутизации"
|
"Routings" = "Правила маршрутизации"
|
||||||
"RoutingsDesc" = "Важен приоритет каждого правила!"
|
"RoutingsDesc" = "Важен приоритет каждого правила!"
|
||||||
|
"Balancers" = "Балансиры"
|
||||||
|
|
||||||
[pages.xray.rules]
|
[pages.xray.rules]
|
||||||
"first" = "Первый"
|
"first" = "Первый"
|
||||||
@@ -383,6 +396,7 @@
|
|||||||
"add" = "Добавить правило"
|
"add" = "Добавить правило"
|
||||||
"edit" = "Редактировать правило"
|
"edit" = "Редактировать правило"
|
||||||
"useComma" = "Элементы, разделенные запятыми"
|
"useComma" = "Элементы, разделенные запятыми"
|
||||||
|
"balancer" = "балансир"
|
||||||
|
|
||||||
[pages.xray.outbound]
|
[pages.xray.outbound]
|
||||||
"addOutbound" = "Добавить исходящий"
|
"addOutbound" = "Добавить исходящий"
|
||||||
@@ -398,6 +412,18 @@
|
|||||||
"bridge" = "Мост"
|
"bridge" = "Мост"
|
||||||
"portal" = "Портал"
|
"portal" = "Портал"
|
||||||
"intercon" = "Соединение"
|
"intercon" = "Соединение"
|
||||||
|
"settings" = "Настройки"
|
||||||
|
"accountInfo" = "Информация Об Учетной Записи"
|
||||||
|
"outboundStatus" = "Исходящий статус"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "Добавить балансир"
|
||||||
|
"editBalancer" = "Редактировать балансир"
|
||||||
|
"balancerStrategy" = "Стратегия"
|
||||||
|
"balancerSelectors" = "Селекторы"
|
||||||
|
"tag" = "Тег"
|
||||||
|
"tagDesc" = "уникальный тег"
|
||||||
|
"balancerDesc" = "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Секретный ключ"
|
"secretKey" = "Секретный ключ"
|
||||||
@@ -407,6 +433,21 @@
|
|||||||
"psk" = "Общий ключ"
|
"psk" = "Общий ключ"
|
||||||
"domainStrategy" = "Стратегия домена"
|
"domainStrategy" = "Стратегия домена"
|
||||||
|
|
||||||
|
[pages.xray.dns]
|
||||||
|
"enable" = "Включить DNS"
|
||||||
|
"enableDesc" = "Включить встроенный DNS-сервер"
|
||||||
|
"strategy" = "Стратегия запроса"
|
||||||
|
"strategyDesc" = "Общая стратегия разрешения доменных имен"
|
||||||
|
"add" = "Добавить сервер"
|
||||||
|
"edit" = "Редактировать сервер"
|
||||||
|
"domains" = "Домены"
|
||||||
|
|
||||||
|
[pages.xray.fakedns]
|
||||||
|
"add" = "Добавить поддельный DNS"
|
||||||
|
"edit" = "Редактировать поддельный DNS"
|
||||||
|
"ipPool" = "Подсеть пула IP"
|
||||||
|
"poolSize" = "Размер пула"
|
||||||
|
|
||||||
[tgbot]
|
[tgbot]
|
||||||
"noResult" = "❗ Нет результатов!"
|
"noResult" = "❗ Нет результатов!"
|
||||||
"wentWrong" = "❌ Что-то пошло не так!"
|
"wentWrong" = "❌ Что-то пошло не так!"
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
"remained" = "Còn lại"
|
"remained" = "Còn lại"
|
||||||
"secAlertTitle" = "Cảnh báo an ninh-Tiếng Việt by Ohoang7"
|
"secAlertTitle" = "Cảnh báo an ninh-Tiếng Việt by Ohoang7"
|
||||||
"secAlertSsl" = "Kết nối này không an toàn; Vui lòng không nhập thông tin nhạy cảm cho đến khi TLS được kích hoạt để bảo vệ dữ liệu của Bạn"
|
"secAlertSsl" = "Kết nối này không an toàn; Vui lòng không nhập thông tin nhạy cảm cho đến khi TLS được kích hoạt để bảo vệ dữ liệu của Bạn"
|
||||||
|
"secAlertConf" = "Một số cấu hình nhất định đã được xác định là dễ bị tấn công, thúc đẩy hành động ngay lập tức để củng cố các giao thức bảo mật và bảo vệ chống lại các vi phạm bảo mật tiềm ẩn."
|
||||||
"security" = "Bảo vệ"
|
"security" = "Bảo vệ"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
@@ -77,15 +78,19 @@
|
|||||||
"title" = "Trạng thái hệ thống"
|
"title" = "Trạng thái hệ thống"
|
||||||
"memory" = "Bộ nhớ"
|
"memory" = "Bộ nhớ"
|
||||||
"hard" = "Ổ cứng"
|
"hard" = "Ổ cứng"
|
||||||
"xrayStatus" = "Trạng thái của Xray"
|
"serverInfo" = "Máy chủ"
|
||||||
"stopXray" = "Dừng Xray"
|
"hostname" = "Tên máy chủ"
|
||||||
"restartXray" = "Khởi động lại Xray"
|
"xrayStatus" = "Xray"
|
||||||
|
"stopXray" = "Dừng"
|
||||||
|
"restartXray" = "Khởi động lại"
|
||||||
"xraySwitch" = "Chuyển đổi phiên bản"
|
"xraySwitch" = "Chuyển đổi phiên bản"
|
||||||
"xraySwitchClick" = "Chọn phiên bản mà bạn muốn chuyển đổi sang."
|
"xraySwitchClick" = "Chọn phiên bản mà bạn muốn chuyển đổi sang."
|
||||||
"xraySwitchClickDesk" = "Hãy lựa chọn thận trọng, vì các phiên bản cũ có thể không tương thích với các cấu hình hiện tại, của Bạn"
|
"xraySwitchClickDesk" = "Hãy lựa chọn thận trọng, vì các phiên bản cũ có thể không tương thích với các cấu hình hiện tại, của Bạn"
|
||||||
"operationHours" = "Thời gian hoạt động"
|
"operationHours" = "Thời gian hoạt động"
|
||||||
"operationHoursDesc" = "Thời gian hoạt động của hệ thống: thời gian kể từ khi khởi động."
|
"operationHoursDesc" = "Thời gian hoạt động kể từ khi khởi động hệ điều hành"
|
||||||
|
"xrayoperationHoursDesc" = "Thời gian hoạt động kể từ lần khởi động Xray cuối cùng"
|
||||||
"systemLoad" = "Tải hệ thống"
|
"systemLoad" = "Tải hệ thống"
|
||||||
|
"systemLoadDesc" = "Tải trung bình trong 1, 5 và 15 phút qua"
|
||||||
"connectionTcpCountDesc" = "Tổng số kết nối TCP trên tất cả các card mạng."
|
"connectionTcpCountDesc" = "Tổng số kết nối TCP trên tất cả các card mạng."
|
||||||
"connectionUdpCountDesc" = "Tổng số kết nối UDP trên tất cả các card mạng."
|
"connectionUdpCountDesc" = "Tổng số kết nối UDP trên tất cả các card mạng."
|
||||||
"upSpeed" = "Tổng tốc độ tải lên cho tất cả các thẻ mạng."
|
"upSpeed" = "Tổng tốc độ tải lên cho tất cả các thẻ mạng."
|
||||||
@@ -134,7 +139,7 @@
|
|||||||
"destinationPort" = "Cổng đích"
|
"destinationPort" = "Cổng đích"
|
||||||
"targetAddress" = "Địa chỉ mục tiêu"
|
"targetAddress" = "Địa chỉ mục tiêu"
|
||||||
"monitorDesc" = "Mặc định để trống"
|
"monitorDesc" = "Mặc định để trống"
|
||||||
"meansNoLimit" = "Nghĩa là không giới hạn"
|
"meansNoLimit" = "Số không có nghĩa là không giới hạn. (đơn vị: GB)"
|
||||||
"totalFlow" = "Tổng lưu lượng"
|
"totalFlow" = "Tổng lưu lượng"
|
||||||
"leaveBlankToNeverExpire" = "Để trống để không bao giờ hết hạn"
|
"leaveBlankToNeverExpire" = "Để trống để không bao giờ hết hạn"
|
||||||
"noRecommendKeepDefault" = "Không yêu cầu đặc biệt để giữ nguyên cài đặt mặc định"
|
"noRecommendKeepDefault" = "Không yêu cầu đặc biệt để giữ nguyên cài đặt mặc định"
|
||||||
@@ -171,7 +176,7 @@
|
|||||||
"info" = "Thông tin"
|
"info" = "Thông tin"
|
||||||
"same" = "Như nhau"
|
"same" = "Như nhau"
|
||||||
"inboundData" = "Dữ liệu gửi đến"
|
"inboundData" = "Dữ liệu gửi đến"
|
||||||
"copyToClipboard" = "Sao chép vào bảng nhớ tạm"
|
"exportInbound" = "Xuất nhập khẩu"
|
||||||
"import" = "Nhập"
|
"import" = "Nhập"
|
||||||
"importInbound" = "Nhập hàng gửi về"
|
"importInbound" = "Nhập hàng gửi về"
|
||||||
|
|
||||||
@@ -197,17 +202,18 @@
|
|||||||
"obtain" = "Nhận được"
|
"obtain" = "Nhận được"
|
||||||
|
|
||||||
[pages.inbounds.stream.general]
|
[pages.inbounds.stream.general]
|
||||||
"requestHeader" = "Tiêu đề yêu cầu"
|
"request" = "Lời yêu cầu"
|
||||||
|
"response" = "Phản ứng"
|
||||||
"name" = "Tên"
|
"name" = "Tên"
|
||||||
"value" = "Giá trị"
|
"value" = "Giá trị"
|
||||||
|
|
||||||
[pages.inbounds.stream.tcp]
|
[pages.inbounds.stream.tcp]
|
||||||
"requestVersion" = "Phiên bản yêu cầu"
|
"version" = "Phiên bản"
|
||||||
"requestMethod" = "Phương thức yêu cầu"
|
"method" = "Phương pháp"
|
||||||
"requestPath" = "Đường dẫn yêu cầu"
|
"path" = "Con đường"
|
||||||
"responseVersion" = "Phiên bản phản hồi"
|
"status" = "Trạng thái"
|
||||||
"responseStatus" = "Trạng thái phản hồi"
|
"statusDescription" = "Tình trạng Mô tả"
|
||||||
"responseStatusDescription" = "Mô tả trạng thái phản hồi"
|
"requestHeader" = "Tiêu đề yêu cầu"
|
||||||
"responseHeader" = "Tiêu đề phản hồi"
|
"responseHeader" = "Tiêu đề phản hồi"
|
||||||
|
|
||||||
[pages.inbounds.stream.quic]
|
[pages.inbounds.stream.quic]
|
||||||
@@ -288,6 +294,8 @@
|
|||||||
"subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình"
|
"subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình"
|
||||||
"subURI" = "URI proxy ngược"
|
"subURI" = "URI proxy ngược"
|
||||||
"subURIDesc" = "Thay đổi URI cơ sở của URL đăng ký để sử dụng ở phía sau proxy"
|
"subURIDesc" = "Thay đổi URI cơ sở của URL đăng ký để sử dụng ở phía sau proxy"
|
||||||
|
"fragment" = "Sự phân mảnh"
|
||||||
|
"fragmentDesc" = "Kích hoạt phân mảnh cho gói TLS hello"
|
||||||
|
|
||||||
[pages.settings.toasts]
|
[pages.settings.toasts]
|
||||||
"modifySettings" = "Sửa đổi cài đặt"
|
"modifySettings" = "Sửa đổi cài đặt"
|
||||||
@@ -304,6 +312,8 @@
|
|||||||
"advancedTemplate" = "Mẫu nâng cao"
|
"advancedTemplate" = "Mẫu nâng cao"
|
||||||
"generalConfigs" = "Cấu hình Chung"
|
"generalConfigs" = "Cấu hình Chung"
|
||||||
"generalConfigsDesc" = "Những tùy chọn này sẽ cung cấp điều chỉnh tổng quát."
|
"generalConfigsDesc" = "Những tùy chọn này sẽ cung cấp điều chỉnh tổng quát."
|
||||||
|
"logConfigs" = "Nhật ký"
|
||||||
|
"logConfigsDesc" = "Nhật ký có thể ảnh hưởng đến hiệu suất máy chủ của bạn. Bạn chỉ nên kích hoạt nó một cách khôn ngoan trong trường hợp bạn cần"
|
||||||
"blockConfigs" = "Cấu hình Chặn"
|
"blockConfigs" = "Cấu hình Chặn"
|
||||||
"blockConfigsDesc" = "Những tùy chọn này sẽ ngăn người dùng kết nối đến các giao thức và trang web cụ thể."
|
"blockConfigsDesc" = "Những tùy chọn này sẽ ngăn người dùng kết nối đến các giao thức và trang web cụ thể."
|
||||||
"blockCountryConfigs" = "Cấu hình Chặn Quốc gia"
|
"blockCountryConfigs" = "Cấu hình Chặn Quốc gia"
|
||||||
@@ -362,6 +372,8 @@
|
|||||||
"OpenAIWARPDesc" = "Thêm định tuyến cho OpenAI (ChatGPT) qua WARP."
|
"OpenAIWARPDesc" = "Thêm định tuyến cho OpenAI (ChatGPT) qua WARP."
|
||||||
"NetflixWARP" = "Định tuyến Netflix qua WARP."
|
"NetflixWARP" = "Định tuyến Netflix qua WARP."
|
||||||
"NetflixWARPDesc" = "Thêm định tuyến cho Netflix qua WARP."
|
"NetflixWARPDesc" = "Thêm định tuyến cho Netflix qua WARP."
|
||||||
|
"MetaWARP" = "Meta"
|
||||||
|
"MetaWARPDesc" = "Định tuyến lưu lượng truy cập tới Meta (Instagram, Facebook, WhatsApp, Threads,...) thông qua WARP."
|
||||||
"SpotifyWARP" = "Định tuyến Spotify qua WARP."
|
"SpotifyWARP" = "Định tuyến Spotify qua WARP."
|
||||||
"SpotifyWARPDesc" = "Thêm định tuyến cho Spotify qua WARP."
|
"SpotifyWARPDesc" = "Thêm định tuyến cho Spotify qua WARP."
|
||||||
"completeTemplate" = "Tất cả"
|
"completeTemplate" = "Tất cả"
|
||||||
@@ -369,6 +381,7 @@
|
|||||||
"Outbounds" = "Đầu ra"
|
"Outbounds" = "Đầu ra"
|
||||||
"Routings" = "Quy tắc định tuyến"
|
"Routings" = "Quy tắc định tuyến"
|
||||||
"RoutingsDesc" = "Mức độ ưu tiên của mỗi quy tắc là quan trọng!"
|
"RoutingsDesc" = "Mức độ ưu tiên của mỗi quy tắc là quan trọng!"
|
||||||
|
"Balancers" = "Cân bằng"
|
||||||
|
|
||||||
[pages.xray.rules]
|
[pages.xray.rules]
|
||||||
"first" = "Đầu tiên"
|
"first" = "Đầu tiên"
|
||||||
@@ -383,6 +396,7 @@
|
|||||||
"add" = "Thêm quy tắc"
|
"add" = "Thêm quy tắc"
|
||||||
"edit" = "Chỉnh sửa quy tắc"
|
"edit" = "Chỉnh sửa quy tắc"
|
||||||
"useComma" = "Các mục được phân tách bằng dấu phẩy"
|
"useComma" = "Các mục được phân tách bằng dấu phẩy"
|
||||||
|
"balancer" = "Cân bằng"
|
||||||
|
|
||||||
[pages.xray.outbound]
|
[pages.xray.outbound]
|
||||||
"addOutbound" = "Thêm Đầu vào"
|
"addOutbound" = "Thêm Đầu vào"
|
||||||
@@ -398,6 +412,18 @@
|
|||||||
"bridge" = "Liên kết"
|
"bridge" = "Liên kết"
|
||||||
"portal" = "Cổng thông tin"
|
"portal" = "Cổng thông tin"
|
||||||
"intercon" = "Kết nối"
|
"intercon" = "Kết nối"
|
||||||
|
"settings" = "cài đặt"
|
||||||
|
"accountInfo" = "Thông tin tài khoản"
|
||||||
|
"outboundStatus" = "Trạng thái đầu ra"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "Thêm cân bằng"
|
||||||
|
"editBalancer" = "Chỉnh sửa cân bằng"
|
||||||
|
"balancerStrategy" = "Chiến lược"
|
||||||
|
"balancerSelectors" = "Bộ chọn"
|
||||||
|
"tag" = "Thẻ"
|
||||||
|
"tagDesc" = "thẻ duy nhất"
|
||||||
|
"balancerDesc" = "Không thể sử dụng balancerTag và outboundTag cùng một lúc. Nếu sử dụng cùng lúc thì chỉ outboundTag mới hoạt động."
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Chìa khoá bí mật"
|
"secretKey" = "Chìa khoá bí mật"
|
||||||
@@ -407,6 +433,21 @@
|
|||||||
"psk" = "Khóa chia sẻ"
|
"psk" = "Khóa chia sẻ"
|
||||||
"domainStrategy" = "Chiến lược tên miền"
|
"domainStrategy" = "Chiến lược tên miền"
|
||||||
|
|
||||||
|
[pages.xray.dns]
|
||||||
|
"enable" = "Kích hoạt DNS"
|
||||||
|
"enableDesc" = "Kích hoạt máy chủ DNS tích hợp"
|
||||||
|
"strategy" = "Chiến lược truy vấn"
|
||||||
|
"strategyDesc" = "Chiến lược tổng thể để phân giải tên miền"
|
||||||
|
"add" = "Thêm máy chủ"
|
||||||
|
"edit" = "Chỉnh sửa máy chủ"
|
||||||
|
"domains" = "Tên miền"
|
||||||
|
|
||||||
|
[pages.xray.fakedns]
|
||||||
|
"add" = "Thêm DNS giả"
|
||||||
|
"edit" = "Chỉnh sửa DNS giả"
|
||||||
|
"ipPool" = "Mạng con nhóm IP"
|
||||||
|
"poolSize" = "Kích thước bể bơi"
|
||||||
|
|
||||||
[tgbot]
|
[tgbot]
|
||||||
"noResult" = "❗ Không có kết quả!"
|
"noResult" = "❗ Không có kết quả!"
|
||||||
"wentWrong" = "❌ Đã xảy ra lỗi!"
|
"wentWrong" = "❌ Đã xảy ra lỗi!"
|
||||||
@@ -454,7 +495,7 @@
|
|||||||
"port" = "🔌 Cổng: {{ .Port }}\r\n"
|
"port" = "🔌 Cổng: {{ .Port }}\r\n"
|
||||||
"expire" = "📅 Hạn sử dụng: {{ .DateTime }}\r\n \r\n"
|
"expire" = "📅 Hạn sử dụng: {{ .DateTime }}\r\n \r\n"
|
||||||
"expireIn" = "📅 Hết hạn vào: {{ .Time }}\r\n \r\n"
|
"expireIn" = "📅 Hết hạn vào: {{ .Time }}\r\n \r\n"
|
||||||
"active" = "💡 Có hiệu lực {{ .Enable }}\r\n"
|
"active" = "💡 Có hiệu lực {{ .Enable }}\r\n"
|
||||||
"online" = "🌐 Tình trạng kết nối: {{ .Status }}\r\n"
|
"online" = "🌐 Tình trạng kết nối: {{ .Status }}\r\n"
|
||||||
"email" = "📧 Email: {{ .Email }}\r\n"
|
"email" = "📧 Email: {{ .Email }}\r\n"
|
||||||
"upload" = "🔼 Tải lên↑: {{ .Upload }}\r\n"
|
"upload" = "🔼 Tải lên↑: {{ .Upload }}\r\n"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"remark" = "备注"
|
"remark" = "备注"
|
||||||
"enable" = "启用"
|
"enable" = "启用"
|
||||||
"protocol" = "协议"
|
"protocol" = "协议"
|
||||||
"search" = "搜尋"
|
"search" = "查找"
|
||||||
"filter" = "过滤器"
|
"filter" = "过滤器"
|
||||||
"loading" = "加载中..."
|
"loading" = "加载中..."
|
||||||
"second" = "秒"
|
"second" = "秒"
|
||||||
@@ -30,8 +30,8 @@
|
|||||||
"sure" = "确定"
|
"sure" = "确定"
|
||||||
"encryption" = "加密"
|
"encryption" = "加密"
|
||||||
"transmission" = "传输"
|
"transmission" = "传输"
|
||||||
"host" = "主持人"
|
"host" = "主机"
|
||||||
"path" = "小路"
|
"path" = "路径"
|
||||||
"camouflage" = "混淆"
|
"camouflage" = "混淆"
|
||||||
"status" = "状态"
|
"status" = "状态"
|
||||||
"enabled" = "开启"
|
"enabled" = "开启"
|
||||||
@@ -52,6 +52,7 @@
|
|||||||
"remained" = "仍然存在"
|
"remained" = "仍然存在"
|
||||||
"secAlertTitle" = "安全警报"
|
"secAlertTitle" = "安全警报"
|
||||||
"secAlertSsl" = "此连接不安全;在激活 TLS 进行数据保护之前,请勿输入敏感信息"
|
"secAlertSsl" = "此连接不安全;在激活 TLS 进行数据保护之前,请勿输入敏感信息"
|
||||||
|
"secAlertConf" = "某些配置已被确定为容易受到攻击,促使立即采取行动以加强安全协议并防范潜在的安全漏洞。"
|
||||||
"security" = "安全"
|
"security" = "安全"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
@@ -64,28 +65,32 @@
|
|||||||
|
|
||||||
[pages.login]
|
[pages.login]
|
||||||
"title" = "欢迎"
|
"title" = "欢迎"
|
||||||
"loginAgain" = "登录时效已过,请重新登录"
|
"loginAgain" = "会话过期,请重新登录"
|
||||||
|
|
||||||
[pages.login.toasts]
|
[pages.login.toasts]
|
||||||
"invalidFormData" = "数据格式错误"
|
"invalidFormData" = "数据格式错误"
|
||||||
"emptyUsername" = "请输入用户名"
|
"emptyUsername" = "请输入用户名"
|
||||||
"emptyPassword" = "请输入密码"
|
"emptyPassword" = "请输入密码"
|
||||||
"wrongUsernameOrPassword" = "用户名或密码错误"
|
"wrongUsernameOrPassword" = "用户名或密码错误"
|
||||||
"successLogin" = "登录"
|
"successLogin" = "登录成功"
|
||||||
|
|
||||||
[pages.index]
|
[pages.index]
|
||||||
"title" = "系统状态"
|
"title" = "系统状态"
|
||||||
"memory" = "内存"
|
"memory" = "内存"
|
||||||
"hard" = "硬盘"
|
"hard" = "硬盘"
|
||||||
"xrayStatus" = "Xray 状态"
|
"serverInfo" = "服务器"
|
||||||
|
"hostname" = "主机名"
|
||||||
|
"xrayStatus" = "Xray"
|
||||||
"stopXray" = "停止"
|
"stopXray" = "停止"
|
||||||
"restartXray" = "重启"
|
"restartXray" = "重启"
|
||||||
"xraySwitch" = "切换版本"
|
"xraySwitch" = "切换版本"
|
||||||
"xraySwitchClick" = "点击你想切换的版本"
|
"xraySwitchClick" = "点击你想切换的版本"
|
||||||
"xraySwitchClickDesk" = "请谨慎选择,旧版本可能配置不兼容"
|
"xraySwitchClickDesk" = "请谨慎选择,旧版本可能配置不兼容"
|
||||||
"operationHours" = "运行时间"
|
"operationHours" = "运行时间"
|
||||||
"operationHoursDesc" = "系统自启动以来的运行时间"
|
"operationHoursDesc" = "自操作系统启动以来的正常运行时间"
|
||||||
|
"xrayoperationHoursDesc" = "自 Xray 上次重启以来的正常运行时间"
|
||||||
"systemLoad" = "系统负载"
|
"systemLoad" = "系统负载"
|
||||||
|
"systemLoadDesc" = "过去 1 分钟、5 分钟和 15 分钟的平均负载"
|
||||||
"connectionTcpCountDesc" = "所有网卡的总 TCP 连接数。"
|
"connectionTcpCountDesc" = "所有网卡的总 TCP 连接数。"
|
||||||
"connectionUdpCountDesc" = "所有网卡的总 UDP 连接数。"
|
"connectionUdpCountDesc" = "所有网卡的总 UDP 连接数。"
|
||||||
"upSpeed" = "所有网卡的总上传速度"
|
"upSpeed" = "所有网卡的总上传速度"
|
||||||
@@ -94,7 +99,7 @@
|
|||||||
"totalReceive" = "系统启动以来所有网卡的总下载流量"
|
"totalReceive" = "系统启动以来所有网卡的总下载流量"
|
||||||
"xraySwitchVersionDialog" = "切换 Xray 版本"
|
"xraySwitchVersionDialog" = "切换 Xray 版本"
|
||||||
"xraySwitchVersionDialogDesc" = "是否切换 Xray 版本至"
|
"xraySwitchVersionDialogDesc" = "是否切换 Xray 版本至"
|
||||||
"dontRefresh" = "安装中,请不要刷新此页面"
|
"dontRefresh" = "安装中,请勿刷新此页面"
|
||||||
"logs" = "日志"
|
"logs" = "日志"
|
||||||
"config" = "配置"
|
"config" = "配置"
|
||||||
"backup" = "备份"
|
"backup" = "备份"
|
||||||
@@ -118,7 +123,7 @@
|
|||||||
"transportConfig" = "传输配置"
|
"transportConfig" = "传输配置"
|
||||||
"expireDate" = "到期时间"
|
"expireDate" = "到期时间"
|
||||||
"resetTraffic" = "重置流量"
|
"resetTraffic" = "重置流量"
|
||||||
"addInbound" = "添加入"
|
"addInbound" = "添加入站"
|
||||||
"generalActions" = "通用操作"
|
"generalActions" = "通用操作"
|
||||||
"create" = "添加"
|
"create" = "添加"
|
||||||
"update" = "修改"
|
"update" = "修改"
|
||||||
@@ -134,7 +139,7 @@
|
|||||||
"destinationPort" = "目标端口"
|
"destinationPort" = "目标端口"
|
||||||
"targetAddress" = "目标地址"
|
"targetAddress" = "目标地址"
|
||||||
"monitorDesc" = "默认留空即可"
|
"monitorDesc" = "默认留空即可"
|
||||||
"meansNoLimit" = "表示不限制"
|
"meansNoLimit" = "零意味着无限。(单位:GB)"
|
||||||
"totalFlow" = "总流量"
|
"totalFlow" = "总流量"
|
||||||
"leaveBlankToNeverExpire" = "留空则永不到期"
|
"leaveBlankToNeverExpire" = "留空则永不到期"
|
||||||
"noRecommendKeepDefault" = "没有特殊需求保持默认即可"
|
"noRecommendKeepDefault" = "没有特殊需求保持默认即可"
|
||||||
@@ -148,9 +153,9 @@
|
|||||||
"client" = "客户"
|
"client" = "客户"
|
||||||
"export" = "导出链接"
|
"export" = "导出链接"
|
||||||
"clone" = "克隆"
|
"clone" = "克隆"
|
||||||
"cloneInbound" = "创造"
|
"cloneInbound" = "创建"
|
||||||
"cloneInboundContent" = "此入站的所有项目除 Port、Listening IP、Clients 将应用于克隆"
|
"cloneInboundContent" = "此入站的所有项目除 Port、Listening IP、Clients 将应用于克隆"
|
||||||
"cloneInboundOk" = "创造"
|
"cloneInboundOk" = "创建"
|
||||||
"resetAllTraffic" = "重置所有入站流量"
|
"resetAllTraffic" = "重置所有入站流量"
|
||||||
"resetAllTrafficTitle" = "重置所有入站流量"
|
"resetAllTrafficTitle" = "重置所有入站流量"
|
||||||
"resetAllTrafficContent" = "您确定要重置所有入站流量吗?"
|
"resetAllTrafficContent" = "您确定要重置所有入站流量吗?"
|
||||||
@@ -164,16 +169,16 @@
|
|||||||
"delDepletedClientsTitle" = "删除耗尽的客户"
|
"delDepletedClientsTitle" = "删除耗尽的客户"
|
||||||
"delDepletedClientsContent" = "你确定要删除所有耗尽的客户端吗?"
|
"delDepletedClientsContent" = "你确定要删除所有耗尽的客户端吗?"
|
||||||
"email" = "电子邮件"
|
"email" = "电子邮件"
|
||||||
"emailDesc" = "电子邮件必须完全唯"
|
"emailDesc" = "电子邮件必须完全唯一"
|
||||||
"setDefaultCert" = "从面板设置证书"
|
"setDefaultCert" = "从面板设置证书"
|
||||||
"telegramDesc" = "使用 Telegram ID,不包含 @ 符号或聊天 ID(可以在 @userinfobot 处获取,或在机器人中使用'/id'命令)"
|
"telegramDesc" = "使用 Telegram ID,不包含 @ 符号或聊天 ID(可以在 @userinfobot 处获取,或在机器人中使用'/id'命令)"
|
||||||
"subscriptionDesc" = "您可以在详细信息上找到您的子链接,你可以为多个客户端使用相同的名称"
|
"subscriptionDesc" = "您可以在详细信息上找到您的子链接,你可以为多个客户端使用相同的名称"
|
||||||
"info" = "信息"
|
"info" = "信息"
|
||||||
"same" = "相同"
|
"same" = "相同"
|
||||||
"inboundData" = "入站数据"
|
"inboundData" = "入站数据"
|
||||||
"copyToClipboard" = "复制到剪贴板"
|
"exportInbound" = "导出入站数据"
|
||||||
"import"="导入"
|
"import"="导入"
|
||||||
"importInbound" = "导入入站"
|
"importInbound" = "导入入站数据"
|
||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "添加客户端"
|
"add" = "添加客户端"
|
||||||
@@ -183,7 +188,7 @@
|
|||||||
"clientCount" = "客户数量"
|
"clientCount" = "客户数量"
|
||||||
"bulk" = "批量创建"
|
"bulk" = "批量创建"
|
||||||
"method" = "方法"
|
"method" = "方法"
|
||||||
"first" = "第一"
|
"first" = "第一个"
|
||||||
"last" = "最后"
|
"last" = "最后"
|
||||||
"prefix" = "前缀"
|
"prefix" = "前缀"
|
||||||
"postfix" = "后缀"
|
"postfix" = "后缀"
|
||||||
@@ -197,17 +202,18 @@
|
|||||||
"obtain" = "获取"
|
"obtain" = "获取"
|
||||||
|
|
||||||
[pages.inbounds.stream.general]
|
[pages.inbounds.stream.general]
|
||||||
"requestHeader" = "请求头"
|
"request" = "请求"
|
||||||
|
"response" = "响应"
|
||||||
"name" = "名称"
|
"name" = "名称"
|
||||||
"value" = "值"
|
"value" = "值"
|
||||||
|
|
||||||
[pages.inbounds.stream.tcp]
|
[pages.inbounds.stream.tcp]
|
||||||
"requestVersion" = "请求版本"
|
"version" = "版本"
|
||||||
"requestMethod" = "请求方法"
|
"method" = "方法"
|
||||||
"requestPath" = "请求路径"
|
"path" = "路径"
|
||||||
"responseVersion" = "响应版本"
|
"status" = "状态"
|
||||||
"responseStatus" = "响应状态"
|
"statusDescription" = "状态描述"
|
||||||
"responseStatusDescription" = "响应状态说明"
|
"requestHeader" = "请求头"
|
||||||
"responseHeader" = "响应头"
|
"responseHeader" = "响应头"
|
||||||
|
|
||||||
[pages.inbounds.stream.quic]
|
[pages.inbounds.stream.quic]
|
||||||
@@ -218,15 +224,15 @@
|
|||||||
"save" = "保存配置"
|
"save" = "保存配置"
|
||||||
"infoDesc" = "此处的所有更改都需要保存并重启面板才能生效"
|
"infoDesc" = "此处的所有更改都需要保存并重启面板才能生效"
|
||||||
"restartPanel" = "重启面板"
|
"restartPanel" = "重启面板"
|
||||||
"restartPanelDesc" = "确定要重启面板吗?点击确定将于 3 秒后重启,若重启后无法访问面板,请前往服务器查看面板日志信息"
|
"restartPanelDesc" = "是否重启面板?点击确定将于 3 秒后重启,若重启后无法访问面板,请前往服务器查看面板日志信息"
|
||||||
"resetDefaultConfig" = "重置为默认配置"
|
"resetDefaultConfig" = "重置为默认配置"
|
||||||
"panelConfig" = "面板配置"
|
"panelConfig" = "面板配置"
|
||||||
"userSettings" = "用户设置"
|
"userSettings" = "用户设置"
|
||||||
"TGBotSettings" = "TG提醒相关设置"
|
"TGBotSettings" = "TG 提醒相关设置"
|
||||||
"panelListeningIP" = "面板监听 IP"
|
"panelListeningIP" = "面板监听 IP"
|
||||||
"panelListeningIPDesc" = "默认留空监听所有 IP"
|
"panelListeningIPDesc" = "默认留空监听所有 IP"
|
||||||
"panelListeningDomain" = "面板监听域名"
|
"panelListeningDomain" = "面板监听域名"
|
||||||
"panelListeningDomainDesc" = "默认情况下留空以监视所有域名和 IP 地址"
|
"panelListeningDomainDesc" = "默认留空以监视所有域名和 IP 地址"
|
||||||
"panelPort" = "面板监听端口"
|
"panelPort" = "面板监听端口"
|
||||||
"panelPortDesc" = "重启面板生效"
|
"panelPortDesc" = "重启面板生效"
|
||||||
"publicKeyPath" = "面板证书公钥文件路径"
|
"publicKeyPath" = "面板证书公钥文件路径"
|
||||||
@@ -250,13 +256,13 @@
|
|||||||
"telegramChatId" = "以逗号分隔的多个 chatID"
|
"telegramChatId" = "以逗号分隔的多个 chatID"
|
||||||
"telegramChatIdDesc" = "多个聊天 ID 用逗号分隔。使用 @userinfobot 或在机器人中使用'/id'命令获取您的聊天 ID。"
|
"telegramChatIdDesc" = "多个聊天 ID 用逗号分隔。使用 @userinfobot 或在机器人中使用'/id'命令获取您的聊天 ID。"
|
||||||
"telegramNotifyTime" = "电报机器人通知时间"
|
"telegramNotifyTime" = "电报机器人通知时间"
|
||||||
"telegramNotifyTimeDesc" = "采用Crontab定时格式"
|
"telegramNotifyTimeDesc" = "采用 Crontab 定时格式"
|
||||||
"tgNotifyBackup" = "数据库备份"
|
"tgNotifyBackup" = "数据库备份"
|
||||||
"tgNotifyBackupDesc" = "正在发送数据库备份文件和报告通知"
|
"tgNotifyBackupDesc" = "正在发送数据库备份文件和报告通知"
|
||||||
"tgNotifyLogin" = "登录通知"
|
"tgNotifyLogin" = "登录通知"
|
||||||
"tgNotifyLoginDesc" = "当有人试图登录您的面板时显示用户名、IP 地址和时间"
|
"tgNotifyLoginDesc" = "有登录面板请求时显示用户名、IP 地址和时间"
|
||||||
"sessionMaxAge" = "会话最大年龄"
|
"sessionMaxAge" = "会话最大时长"
|
||||||
"sessionMaxAgeDesc" = "您可以保持登录状态的时间(单位:分钟)"
|
"sessionMaxAgeDesc" = "您可以保持登录状态的最长时间(单位:分钟)"
|
||||||
"expireTimeDiff" = "耗尽时间阈值"
|
"expireTimeDiff" = "耗尽时间阈值"
|
||||||
"expireTimeDiffDesc" = "到期前检测耗尽(单位:天)"
|
"expireTimeDiffDesc" = "到期前检测耗尽(单位:天)"
|
||||||
"trafficDiff" = "耗尽流量阈值"
|
"trafficDiff" = "耗尽流量阈值"
|
||||||
@@ -288,6 +294,8 @@
|
|||||||
"subShowInfoDesc" = "在配置名称后显示剩余流量和日期"
|
"subShowInfoDesc" = "在配置名称后显示剩余流量和日期"
|
||||||
"subURI" = "反向代理 URI"
|
"subURI" = "反向代理 URI"
|
||||||
"subURIDesc" = "更改订阅 URL 的基本 URI 以在代理后面使用"
|
"subURIDesc" = "更改订阅 URL 的基本 URI 以在代理后面使用"
|
||||||
|
"fragment" = "碎片"
|
||||||
|
"fragmentDesc" = "启用 TLS hello 数据包分段"
|
||||||
|
|
||||||
[pages.settings.toasts]
|
[pages.settings.toasts]
|
||||||
"modifySettings" = "修改设置"
|
"modifySettings" = "修改设置"
|
||||||
@@ -303,12 +311,14 @@
|
|||||||
"basicTemplate" = "基本模板"
|
"basicTemplate" = "基本模板"
|
||||||
"advancedTemplate" = "高级模板部件"
|
"advancedTemplate" = "高级模板部件"
|
||||||
"generalConfigs" = "通用配置"
|
"generalConfigs" = "通用配置"
|
||||||
"generalConfigsDesc" = "这些选项将提供一般调整"
|
"generalConfigsDesc" = "这些选项提供通用设置调整"
|
||||||
|
"logConfigs"="日志"
|
||||||
|
"logConfigsDesc" = "日志可能会影响您服务器的效率。建议仅在您需要时明智地启用它"
|
||||||
"blockConfigs" = "阻塞配置"
|
"blockConfigs" = "阻塞配置"
|
||||||
"blockConfigsDesc" = "这些选项将阻止用户连接到特定协议和网站"
|
"blockConfigsDesc" = "这些选项将禁止用户连接到特定协议和网站"
|
||||||
"blockCountryConfigs" = "阻止国家配置"
|
"blockCountryConfigs" = "禁连国家配置"
|
||||||
"blockCountryConfigsDesc" = "这些选项将阻止用户连接到特定国家/地区的域。"
|
"blockCountryConfigsDesc" = "这些选项将禁止用户连接到特定国家/地区的域。"
|
||||||
"directCountryConfigs" = "直接国家配置"
|
"directCountryConfigs" = "直连国家配置"
|
||||||
"directCountryConfigsDesc" = "这些选项会将用户直接连接到特定国家/地区的域。"
|
"directCountryConfigsDesc" = "这些选项会将用户直接连接到特定国家/地区的域。"
|
||||||
"ipv4Configs" = "IPv4 配置"
|
"ipv4Configs" = "IPv4 配置"
|
||||||
"ipv4ConfigsDesc" = "此选项将仅通过 IPv4 路由到目标域"
|
"ipv4ConfigsDesc" = "此选项将仅通过 IPv4 路由到目标域"
|
||||||
@@ -320,8 +330,8 @@
|
|||||||
"FreedomStrategyDesc" = "在自由协议中设置网络输出策略"
|
"FreedomStrategyDesc" = "在自由协议中设置网络输出策略"
|
||||||
"RoutingStrategy" = "配置路由域策略"
|
"RoutingStrategy" = "配置路由域策略"
|
||||||
"RoutingStrategyDesc" = "设置DNS解析的整体路由策略"
|
"RoutingStrategyDesc" = "设置DNS解析的整体路由策略"
|
||||||
"Torrent" = "禁止使用 bittorrent"
|
"Torrent" = "禁止使用 bitTorrent"
|
||||||
"TorrentDesc" = "更改配置模板避免用户使用bittorrent"
|
"TorrentDesc" = "更改配置模板避免用户使用 bitTorrent"
|
||||||
"PrivateIp" = "禁止私人 IP 范围连接"
|
"PrivateIp" = "禁止私人 IP 范围连接"
|
||||||
"PrivateIpDesc" = "更改配置模板以避免连接私有 IP 范围"
|
"PrivateIpDesc" = "更改配置模板以避免连接私有 IP 范围"
|
||||||
"Ads" = "屏蔽广告"
|
"Ads" = "屏蔽广告"
|
||||||
@@ -362,6 +372,8 @@
|
|||||||
"OpenAIWARPDesc" = "将OpenAI(ChatGPT)路由添加到WARP"
|
"OpenAIWARPDesc" = "将OpenAI(ChatGPT)路由添加到WARP"
|
||||||
"NetflixWARP" = "将 Netflix 路由到 WARP"
|
"NetflixWARP" = "将 Netflix 路由到 WARP"
|
||||||
"NetflixWARPDesc" = "为Netflix添加路由到WARP"
|
"NetflixWARPDesc" = "为Netflix添加路由到WARP"
|
||||||
|
"MetaWARP"="元"
|
||||||
|
"MetaWARPDesc" = "通过 WARP 将流量路由到 Meta(Instagram、Facebook、WhatsApp、Threads...)"
|
||||||
"SpotifyWARP" = "将 Spotify 路由到 WARP"
|
"SpotifyWARP" = "将 Spotify 路由到 WARP"
|
||||||
"SpotifyWARPDesc" = "为Spotify添加路由到WARP"
|
"SpotifyWARPDesc" = "为Spotify添加路由到WARP"
|
||||||
"completeTemplate" = "全部"
|
"completeTemplate" = "全部"
|
||||||
@@ -369,6 +381,7 @@
|
|||||||
"Outbounds" = "出站"
|
"Outbounds" = "出站"
|
||||||
"Routings" = "路由规则"
|
"Routings" = "路由规则"
|
||||||
"RoutingsDesc" = "每条规则的优先级都很重要"
|
"RoutingsDesc" = "每条规则的优先级都很重要"
|
||||||
|
"Balancers" = "平衡器"
|
||||||
|
|
||||||
[pages.xray.rules]
|
[pages.xray.rules]
|
||||||
"first" = "第一个"
|
"first" = "第一个"
|
||||||
@@ -383,6 +396,7 @@
|
|||||||
"add" = "添加规则"
|
"add" = "添加规则"
|
||||||
"edit" = "编辑规则"
|
"edit" = "编辑规则"
|
||||||
"useComma" = "逗号分隔的项目"
|
"useComma" = "逗号分隔的项目"
|
||||||
|
"balancer" = "平衡器"
|
||||||
|
|
||||||
[pages.xray.outbound]
|
[pages.xray.outbound]
|
||||||
"addOutbound" = "添加出站"
|
"addOutbound" = "添加出站"
|
||||||
@@ -398,6 +412,18 @@
|
|||||||
"bridge" = "桥"
|
"bridge" = "桥"
|
||||||
"portal" = "门户"
|
"portal" = "门户"
|
||||||
"intercon" = "互连"
|
"intercon" = "互连"
|
||||||
|
"settings" = "设置"
|
||||||
|
"accountInfo" = "帐户信息"
|
||||||
|
"outboundStatus" = "出站状态"
|
||||||
|
|
||||||
|
[pages.xray.balancer]
|
||||||
|
"addBalancer" = "添加平衡器"
|
||||||
|
"editBalancer" = "编辑平衡器"
|
||||||
|
"balancerStrategy" = "战略"
|
||||||
|
"balancerSelectors" = "选择器"
|
||||||
|
"tag" = "标签"
|
||||||
|
"tagDesc" = "唯一标记"
|
||||||
|
"balancerDesc" = "不能同时使用balancerTag和outboundTag。 如果同时使用,则只有outboundTag起作用。"
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "密钥"
|
"secretKey" = "密钥"
|
||||||
@@ -407,6 +433,21 @@
|
|||||||
"psk" = "共享密钥"
|
"psk" = "共享密钥"
|
||||||
"domainStrategy" = "域策略"
|
"domainStrategy" = "域策略"
|
||||||
|
|
||||||
|
[pages.xray.dns]
|
||||||
|
"enable" = "启用 DNS"
|
||||||
|
"enableDesc" = "启用内置 DNS 服务器"
|
||||||
|
"strategy" = "查询策略"
|
||||||
|
"strategyDesc" = "解析域名的总体策略"
|
||||||
|
"add" = "添加服务器"
|
||||||
|
"edit" = "编辑服务器"
|
||||||
|
"domains" = "域"
|
||||||
|
|
||||||
|
[pages.xray.fakedns]
|
||||||
|
"add" = "添加假 DNS"
|
||||||
|
"edit" = "编辑假 DNS"
|
||||||
|
"ipPool" = "IP 池子网"
|
||||||
|
"poolSize" = "池大小"
|
||||||
|
|
||||||
[tgbot]
|
[tgbot]
|
||||||
"noResult" = "❗ 没有结果!"
|
"noResult" = "❗ 没有结果!"
|
||||||
"wentWrong" = "❌ 出了点问题!"
|
"wentWrong" = "❌ 出了点问题!"
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ import (
|
|||||||
"x-ui/web/network"
|
"x-ui/web/network"
|
||||||
"x-ui/web/service"
|
"x-ui/web/service"
|
||||||
|
|
||||||
|
sessions "github.com/Calidity/gin-sessions"
|
||||||
|
"github.com/Calidity/gin-sessions/cookie"
|
||||||
"github.com/gin-contrib/gzip"
|
"github.com/gin-contrib/gzip"
|
||||||
"github.com/gin-contrib/sessions"
|
|
||||||
"github.com/gin-contrib/sessions/cookie"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
20
x-ui.sh
20
x-ui.sh
@@ -133,8 +133,14 @@ custom_version() {
|
|||||||
eval $install_command
|
eval $install_command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Function to handle the deletion of the script file
|
||||||
|
delete_script() {
|
||||||
|
rm "$0" # Remove the script file itself
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
uninstall() {
|
uninstall() {
|
||||||
confirm "Are you sure you want to uninstall the panel? xray will also uninstalled!" "n"
|
confirm "Are you sure you want to uninstall the panel? xray will also uninstalled!" " n"
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $? != 0 ]]; then
|
||||||
if [[ $# == 0 ]]; then
|
if [[ $# == 0 ]]; then
|
||||||
show_menu
|
show_menu
|
||||||
@@ -148,14 +154,14 @@ uninstall() {
|
|||||||
systemctl reset-failed
|
systemctl reset-failed
|
||||||
rm /etc/x-ui/ -rf
|
rm /etc/x-ui/ -rf
|
||||||
rm /usr/local/x-ui/ -rf
|
rm /usr/local/x-ui/ -rf
|
||||||
|
echo -e "\nUninstalled Successfully."
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "Uninstalled Successfully,If you want to remove this script,then after exiting the script run ${green}rm /usr/bin/x-ui -f${plain} to delete it."
|
echo -e "If you need to install this panel again, you can use below command:"
|
||||||
|
echo -e "${green}bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh)${plain}"
|
||||||
echo ""
|
echo ""
|
||||||
|
# Trap the SIGTERM signal
|
||||||
if [[ $# == 0 ]]; then
|
trap delete_script SIGTERM
|
||||||
before_show_menu
|
delete_script
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_user() {
|
reset_user() {
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ type Config struct {
|
|||||||
API json_util.RawMessage `json:"api"`
|
API json_util.RawMessage `json:"api"`
|
||||||
Stats json_util.RawMessage `json:"stats"`
|
Stats json_util.RawMessage `json:"stats"`
|
||||||
Reverse json_util.RawMessage `json:"reverse"`
|
Reverse json_util.RawMessage `json:"reverse"`
|
||||||
FakeDNS json_util.RawMessage `json:"fakeDns"`
|
FakeDNS json_util.RawMessage `json:"fakedns"`
|
||||||
|
Observatory json_util.RawMessage `json:"observatory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Equals(other *Config) bool {
|
func (c *Config) Equals(other *Config) bool {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package xray
|
package xray
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"x-ui/logger"
|
"x-ui/logger"
|
||||||
)
|
)
|
||||||
@@ -14,37 +15,31 @@ type LogWriter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (lw *LogWriter) Write(m []byte) (n int, err error) {
|
func (lw *LogWriter) Write(m []byte) (n int, err error) {
|
||||||
|
regex := regexp.MustCompile(`^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[([^\]]+)\] (.+)$`)
|
||||||
|
|
||||||
// Convert the data to a string
|
// Convert the data to a string
|
||||||
message := strings.TrimSpace(string(m))
|
message := strings.TrimSpace(string(m))
|
||||||
|
|
||||||
messages := strings.Split(message, "\n")
|
messages := strings.Split(message, "\n")
|
||||||
lw.lastLine = messages[len(messages)-1]
|
lw.lastLine = messages[len(messages)-1]
|
||||||
|
|
||||||
for _, msg := range messages {
|
for _, msg := range messages {
|
||||||
messageBody := msg
|
matches := regex.FindStringSubmatch(msg)
|
||||||
|
|
||||||
// Remove timestamp
|
if len(matches) > 3 {
|
||||||
splittedMsg := strings.SplitN(msg, " ", 3)
|
level := matches[2]
|
||||||
if len(splittedMsg) > 2 {
|
msgBody := matches[3]
|
||||||
messageBody = strings.TrimSpace(strings.SplitN(msg, " ", 3)[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find level in []
|
|
||||||
startIndex := strings.Index(messageBody, "[")
|
|
||||||
endIndex := strings.Index(messageBody, "]")
|
|
||||||
if startIndex != -1 && endIndex != -1 {
|
|
||||||
level := strings.TrimSpace(messageBody[startIndex+1 : endIndex])
|
|
||||||
msgBody := "XRAY: " + strings.TrimSpace(messageBody[endIndex+1:])
|
|
||||||
|
|
||||||
// Map the level to the appropriate logger function
|
// Map the level to the appropriate logger function
|
||||||
switch level {
|
switch level {
|
||||||
case "Debug":
|
case "Debug":
|
||||||
logger.Debug(msgBody)
|
logger.Debug("XRAY: " + msgBody)
|
||||||
case "Info":
|
case "Info":
|
||||||
logger.Info(msgBody)
|
logger.Info("XRAY: " + msgBody)
|
||||||
case "Warning":
|
case "Warning":
|
||||||
logger.Warning(msgBody)
|
logger.Warning("XRAY: " + msgBody)
|
||||||
case "Error":
|
case "Error":
|
||||||
logger.Error(msgBody)
|
logger.Error("XRAY: " + msgBody)
|
||||||
default:
|
default:
|
||||||
logger.Debug("XRAY: " + msg)
|
logger.Debug("XRAY: " + msg)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user