mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-02-28 21:23:01 +00:00
Compare commits
10 commits
356e7fd920
...
df8c567683
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df8c567683 | ||
|
|
06c49b92f8 | ||
|
|
e35213bc73 | ||
|
|
aa6a886977 | ||
|
|
9d603c5ad2 | ||
|
|
a973fa6d68 | ||
|
|
3af6497577 | ||
|
|
c59f54bb0e | ||
|
|
a6ca391ba1 | ||
|
|
511684d289 |
14 changed files with 727 additions and 226 deletions
127
.github/workflows/release.yml
vendored
127
.github/workflows/release.yml
vendored
|
|
@ -89,7 +89,7 @@ jobs:
|
||||||
cd x-ui/bin
|
cd x-ui/bin
|
||||||
|
|
||||||
# Download dependencies
|
# Download dependencies
|
||||||
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.1.18/"
|
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.1.31/"
|
||||||
if [ "${{ matrix.platform }}" == "amd64" ]; then
|
if [ "${{ matrix.platform }}" == "amd64" ]; then
|
||||||
wget -q ${Xray_URL}Xray-linux-64.zip
|
wget -q ${Xray_URL}Xray-linux-64.zip
|
||||||
unzip Xray-linux-64.zip
|
unzip Xray-linux-64.zip
|
||||||
|
|
@ -151,6 +151,96 @@ jobs:
|
||||||
overwrite: true
|
overwrite: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|
||||||
|
# =================================
|
||||||
|
# macOS Build (darwin)
|
||||||
|
# =================================
|
||||||
|
build-macos:
|
||||||
|
name: Build for macOS
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- arch: amd64
|
||||||
|
runner: macos-13
|
||||||
|
- arch: arm64
|
||||||
|
runner: macos-14
|
||||||
|
runs-on: ${{ matrix.runner }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
|
- name: Build 3X-UI for macOS (CGO)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
export CGO_ENABLED=1
|
||||||
|
export GOOS=darwin
|
||||||
|
export GOARCH=${{ matrix.arch }}
|
||||||
|
|
||||||
|
go version
|
||||||
|
go env GOOS GOARCH CGO_ENABLED
|
||||||
|
|
||||||
|
go build -ldflags "-w -s" -o xui-release -v main.go
|
||||||
|
file xui-release
|
||||||
|
|
||||||
|
mkdir -p x-ui/bin
|
||||||
|
cp xui-release x-ui/x-ui
|
||||||
|
cp x-ui.sh x-ui/
|
||||||
|
|
||||||
|
# Download dependencies
|
||||||
|
cd x-ui/bin
|
||||||
|
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.1.18/"
|
||||||
|
if [ "${{ matrix.arch }}" = "amd64" ]; then
|
||||||
|
curl -fsSL -o Xray-macos-64.zip "${Xray_URL}Xray-macos-64.zip"
|
||||||
|
unzip -q Xray-macos-64.zip
|
||||||
|
rm -f Xray-macos-64.zip
|
||||||
|
elif [ "${{ matrix.arch }}" = "arm64" ]; then
|
||||||
|
curl -fsSL -o Xray-macos-arm64-v8a.zip "${Xray_URL}Xray-macos-arm64-v8a.zip"
|
||||||
|
unzip -q Xray-macos-arm64-v8a.zip
|
||||||
|
rm -f Xray-macos-arm64-v8a.zip
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f geoip.dat geosite.dat
|
||||||
|
curl -fsSL -o geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
|
||||||
|
curl -fsSL -o geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
|
||||||
|
curl -fsSL -o geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
|
||||||
|
curl -fsSL -o geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
|
||||||
|
curl -fsSL -o geoip_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat
|
||||||
|
curl -fsSL -o geosite_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat
|
||||||
|
|
||||||
|
mv xray xray-macos-${{ matrix.arch }}
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
- name: Package
|
||||||
|
shell: bash
|
||||||
|
run: tar -zcvf x-ui-darwin-${{ matrix.arch }}.tar.gz x-ui
|
||||||
|
|
||||||
|
- name: Upload files to Artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: x-ui-darwin-${{ matrix.arch }}
|
||||||
|
path: ./x-ui-darwin-${{ matrix.arch }}.tar.gz
|
||||||
|
|
||||||
|
- name: Upload files to GH release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: |
|
||||||
|
(github.event_name == 'release' && github.event.action == 'published') ||
|
||||||
|
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tag: ${{ github.ref }}
|
||||||
|
file: x-ui-darwin-${{ matrix.arch }}.tar.gz
|
||||||
|
asset_name: x-ui-darwin-${{ matrix.arch }}.tar.gz
|
||||||
|
overwrite: true
|
||||||
|
prerelease: true
|
||||||
|
|
||||||
# =================================
|
# =================================
|
||||||
# Windows Build
|
# Windows Build
|
||||||
# =================================
|
# =================================
|
||||||
|
|
@ -173,21 +263,42 @@ jobs:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|
||||||
|
- name: Install MSYS2
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
msystem: MINGW64
|
||||||
|
update: true
|
||||||
|
install: >-
|
||||||
|
mingw-w64-x86_64-gcc
|
||||||
|
mingw-w64-x86_64-sqlite3
|
||||||
|
mingw-w64-x86_64-pkg-config
|
||||||
|
|
||||||
|
- name: Build 3X-UI for Windows (CGO)
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
export PATH="/c/hostedtoolcache/windows/go/$(ls /c/hostedtoolcache/windows/go | sort -V | tail -n1)/x64/bin:$PATH"
|
||||||
|
|
||||||
|
export CGO_ENABLED=1
|
||||||
|
export GOOS=windows
|
||||||
|
export GOARCH=amd64
|
||||||
|
export CC=x86_64-w64-mingw32-gcc
|
||||||
|
|
||||||
|
which go
|
||||||
|
go version
|
||||||
|
gcc --version
|
||||||
|
|
||||||
|
go build -ldflags "-w -s" -o xui-release.exe -v main.go
|
||||||
|
|
||||||
- name: Build 3X-UI for Windows
|
- name: Build 3X-UI for Windows
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$env:CGO_ENABLED="1"
|
|
||||||
$env:GOOS="windows"
|
|
||||||
$env:GOARCH="amd64"
|
|
||||||
go build -ldflags "-w -s" -o xui-release.exe -v main.go
|
|
||||||
|
|
||||||
mkdir x-ui
|
mkdir x-ui
|
||||||
Copy-Item xui-release.exe x-ui\
|
Copy-Item xui-release.exe x-ui\
|
||||||
mkdir x-ui\bin
|
mkdir x-ui\bin
|
||||||
cd x-ui\bin
|
cd x-ui\bin
|
||||||
|
|
||||||
# Download Xray for Windows
|
# Download Xray for Windows
|
||||||
$Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.1.18/"
|
$Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.1.31/"
|
||||||
Invoke-WebRequest -Uri "${Xray_URL}Xray-windows-64.zip" -OutFile "Xray-windows-64.zip"
|
Invoke-WebRequest -Uri "${Xray_URL}Xray-windows-64.zip" -OutFile "Xray-windows-64.zip"
|
||||||
Expand-Archive -Path "Xray-windows-64.zip" -DestinationPath .
|
Expand-Archive -Path "Xray-windows-64.zip" -DestinationPath .
|
||||||
Remove-Item "Xray-windows-64.zip"
|
Remove-Item "Xray-windows-64.zip"
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ case $1 in
|
||||||
esac
|
esac
|
||||||
mkdir -p build/bin
|
mkdir -p build/bin
|
||||||
cd build/bin
|
cd build/bin
|
||||||
curl -sfLRO "https://github.com/XTLS/Xray-core/releases/download/v26.1.18/Xray-linux-${ARCH}.zip"
|
curl -sfLRO "https://github.com/XTLS/Xray-core/releases/download/v26.1.31/Xray-linux-${ARCH}.zip"
|
||||||
unzip "Xray-linux-${ARCH}.zip"
|
unzip "Xray-linux-${ARCH}.zip"
|
||||||
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
|
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
|
||||||
mv xray "xray-linux-${FNAME}"
|
mv xray "xray-linux-${FNAME}"
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
2.8.8
|
2.8.9
|
||||||
24
go.mod
24
go.mod
|
|
@ -16,11 +16,11 @@ require (
|
||||||
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.2.4
|
github.com/pelletier/go-toml/v2 v2.2.4
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/shirou/gopsutil/v4 v4.25.12
|
github.com/shirou/gopsutil/v4 v4.26.1
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/valyala/fasthttp v1.69.0
|
github.com/valyala/fasthttp v1.69.0
|
||||||
github.com/xlzd/gotp v0.1.0
|
github.com/xlzd/gotp v0.1.0
|
||||||
github.com/xtls/xray-core v1.260118.0
|
github.com/xtls/xray-core v1.260131.0
|
||||||
go.uber.org/atomic v1.11.0
|
go.uber.org/atomic v1.11.0
|
||||||
golang.org/x/crypto v0.47.0
|
golang.org/x/crypto v0.47.0
|
||||||
golang.org/x/sys v0.40.0
|
golang.org/x/sys v0.40.0
|
||||||
|
|
@ -35,11 +35,10 @@ require (
|
||||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||||
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178 // indirect
|
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178 // indirect
|
||||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||||
github.com/bytedance/sonic v1.14.2 // indirect
|
github.com/bytedance/sonic v1.15.0 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.4.0 // indirect
|
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||||
github.com/cloudflare/circl v1.6.2 // indirect
|
github.com/cloudflare/circl v1.6.3 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 // indirect
|
|
||||||
github.com/ebitengine/purego v0.9.1 // indirect
|
github.com/ebitengine/purego v0.9.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
|
|
@ -64,24 +63,21 @@ require (
|
||||||
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
|
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.33 // indirect
|
github.com/mattn/go-sqlite3 v1.14.33 // indirect
|
||||||
github.com/miekg/dns v1.1.70 // indirect
|
github.com/miekg/dns v1.1.72 // 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/pires/go-proxyproto v0.8.1 // indirect
|
github.com/pires/go-proxyproto v0.9.2 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/quic-go/qpack v0.6.0 // indirect
|
github.com/quic-go/qpack v0.6.0 // indirect
|
||||||
github.com/quic-go/quic-go v0.59.0 // indirect
|
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||||
github.com/refraction-networking/utls v1.8.2 // indirect
|
github.com/refraction-networking/utls v1.8.2 // indirect
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
github.com/sagernet/sing v0.7.14 // indirect
|
github.com/sagernet/sing v0.7.18 // indirect
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.9 // indirect
|
github.com/sagernet/sing-shadowsocks v0.2.9 // indirect
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect
|
|
||||||
github.com/tklauser/go-sysconf v0.3.16 // indirect
|
github.com/tklauser/go-sysconf v0.3.16 // indirect
|
||||||
github.com/tklauser/numcpus v0.11.0 // indirect
|
github.com/tklauser/numcpus v0.11.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.3.1 // indirect
|
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fastjson v1.6.7 // indirect
|
github.com/valyala/fastjson v1.6.7 // indirect
|
||||||
github.com/vishvananda/netlink v1.3.1 // indirect
|
github.com/vishvananda/netlink v1.3.1 // indirect
|
||||||
|
|
@ -98,8 +94,8 @@ require (
|
||||||
golang.org/x/tools v0.41.0 // indirect
|
golang.org/x/tools v0.41.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-20250521234502-f333402bd9cb // indirect
|
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2 // indirect
|
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0 // indirect
|
||||||
lukechampine.com/blake3 v1.4.1 // indirect
|
lukechampine.com/blake3 v1.4.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
51
go.sum
51
go.sum
|
|
@ -10,20 +10,17 @@ github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178 h1:bSq8n+gX4oO/
|
||||||
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178/go.mod h1:N1WIjPphkqs4efXWuyDNQ6OjjIK04vM3h+bEgwV+eVU=
|
github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178/go.mod h1:N1WIjPphkqs4efXWuyDNQ6OjjIK04vM3h+bEgwV+eVU=
|
||||||
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
||||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||||
github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
|
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
|
||||||
github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980=
|
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
|
||||||
github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o=
|
github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=
|
||||||
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||||
github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ=
|
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||||
github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
|
||||||
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 h1:ucRHb6/lvW/+mTEIGbvhcYU3S8+uSNkuMjx/qZFfhtM=
|
|
||||||
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
|
||||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
|
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
|
||||||
|
|
@ -124,8 +121,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||||
github.com/mattn/go-isatty v0.0.20/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.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0=
|
github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0=
|
||||||
github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/miekg/dns v1.1.70 h1:DZ4u2AV35VJxdD9Fo9fIWm119BsQL5cZU1cQ9s0LkqA=
|
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||||
github.com/miekg/dns v1.1.70/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||||
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=
|
||||||
|
|
@ -141,8 +138,8 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v
|
||||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
github.com/pires/go-proxyproto v0.9.2 h1:H1UdHn695zUVVmB0lQ354lOWHOy6TZSpzBl3tgN0s1U=
|
||||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
github.com/pires/go-proxyproto v0.9.2/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||||
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-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
|
|
@ -153,20 +150,16 @@ github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SA
|
||||||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||||
github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo=
|
github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo=
|
||||||
github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/sagernet/sing v0.7.14 h1:5QQRDCUvYNOMyVp3LuK/hYEBAIv0VsbD3x/l9zH467s=
|
github.com/sagernet/sing v0.7.18 h1:iZHkaru1/MoHugx3G+9S3WG4owMewKO/KvieE2Pzk4E=
|
||||||
github.com/sagernet/sing v0.7.14/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.7.18/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.9 h1:Paep5zCszRKsEn8587O0MnhFWKJwDW1Y4zOYYlIxMkM=
|
github.com/sagernet/sing-shadowsocks v0.2.9 h1:Paep5zCszRKsEn8587O0MnhFWKJwDW1Y4zOYYlIxMkM=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.9/go.mod h1:TE/Z6401Pi8tgr0nBZcM/xawAI6u3F6TTbz4nH/qw+8=
|
github.com/sagernet/sing-shadowsocks v0.2.9/go.mod h1:TE/Z6401Pi8tgr0nBZcM/xawAI6u3F6TTbz4nH/qw+8=
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4=
|
github.com/shirou/gopsutil/v4 v4.26.1 h1:TOkEyriIXk2HX9d4isZJtbjXbEjf5qyKPAzbzY0JWSo=
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
github.com/shirou/gopsutil/v4 v4.26.1/go.mod h1:medLI9/UNAb0dOI9Q3/7yWSqKkj00u+1tgY8nvv41pc=
|
||||||
github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY=
|
|
||||||
github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|
@ -174,7 +167,6 @@ 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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
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.6.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.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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
|
@ -189,8 +181,6 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
|
||||||
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/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
||||||
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||||
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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI=
|
github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI=
|
||||||
|
|
@ -205,8 +195,8 @@ github.com/xlzd/gotp v0.1.0 h1:37blvlKCh38s+fkem+fFh7sMnceltoIEBYTVXyoa5Po=
|
||||||
github.com/xlzd/gotp v0.1.0/go.mod h1:ndLJ3JKzi3xLmUProq4LLxCuECL93dG9WASNLpHz8qg=
|
github.com/xlzd/gotp v0.1.0/go.mod h1:ndLJ3JKzi3xLmUProq4LLxCuECL93dG9WASNLpHz8qg=
|
||||||
github.com/xtls/reality v0.0.0-20251116175510-cd53f7d50237 h1:UXjrmniKlY+ZbIqpN91lejB3pszQQQRVu1vqH/p/aGM=
|
github.com/xtls/reality v0.0.0-20251116175510-cd53f7d50237 h1:UXjrmniKlY+ZbIqpN91lejB3pszQQQRVu1vqH/p/aGM=
|
||||||
github.com/xtls/reality v0.0.0-20251116175510-cd53f7d50237/go.mod h1:vbHCV/3VWUvy1oKvTxxWJRPEWSeR1sYgQHIh6u/JiZQ=
|
github.com/xtls/reality v0.0.0-20251116175510-cd53f7d50237/go.mod h1:vbHCV/3VWUvy1oKvTxxWJRPEWSeR1sYgQHIh6u/JiZQ=
|
||||||
github.com/xtls/xray-core v1.260118.0 h1:RJtgIbQ3ykFRcH1CKeoCgQ5WvhsMFu+lnvLF/fFHagE=
|
github.com/xtls/xray-core v1.260131.0 h1:gPBykLhUvRZ8sfubNerkwWqV3c15UtmSYQG2cgKqrV4=
|
||||||
github.com/xtls/xray-core v1.260118.0/go.mod h1:A5k7TXE2KfAjT8dAq6Ir4mMP1q0OTh+8VMmUdqWMQpg=
|
github.com/xtls/xray-core v1.260131.0/go.mod h1:cxzYFZrxu1B1NtPjHsqv4UzgDvRA71mV4rXYH4KtO7Q=
|
||||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
|
|
@ -263,8 +253,8 @@ golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+Z
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
|
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|
@ -275,14 +265,13 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
|
||||||
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=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 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.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
|
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
|
||||||
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
|
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
|
||||||
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
||||||
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||||
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2 h1:fr6L00yGG2RP5NMea6njWpdC+bm+cMdFClrSpaicp1c=
|
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0 h1:Lk6hARj5UPY47dBep70OD/TIMwikJ5fGUGX0Rm3Xigk=
|
||||||
gvisor.dev/gvisor v0.0.0-20260109181451-4be7c433dae2/go.mod h1:QkHjoMIBaYtpVufgwv3keYAbln78mBoCuShZrPrer1Q=
|
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0/go.mod h1:QkHjoMIBaYtpVufgwv3keYAbln78mBoCuShZrPrer1Q=
|
||||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||||
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
||||||
|
|
|
||||||
|
|
@ -318,15 +318,13 @@ TcpStreamSettings.TcpResponse = class extends XrayCommonClass {
|
||||||
|
|
||||||
class KcpStreamSettings extends XrayCommonClass {
|
class KcpStreamSettings extends XrayCommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
mtu = 1250,
|
mtu = 1350,
|
||||||
tti = 50,
|
tti = 20,
|
||||||
uplinkCapacity = 5,
|
uplinkCapacity = 5,
|
||||||
downlinkCapacity = 20,
|
downlinkCapacity = 20,
|
||||||
congestion = false,
|
congestion = false,
|
||||||
readBufferSize = 2,
|
readBufferSize = 1,
|
||||||
writeBufferSize = 2,
|
writeBufferSize = 1,
|
||||||
type = 'none',
|
|
||||||
seed = RandomUtil.randomSeq(10),
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.mtu = mtu;
|
this.mtu = mtu;
|
||||||
|
|
@ -336,8 +334,6 @@ class KcpStreamSettings extends XrayCommonClass {
|
||||||
this.congestion = congestion;
|
this.congestion = congestion;
|
||||||
this.readBuffer = readBufferSize;
|
this.readBuffer = readBufferSize;
|
||||||
this.writeBuffer = writeBufferSize;
|
this.writeBuffer = writeBufferSize;
|
||||||
this.type = type;
|
|
||||||
this.seed = seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
static fromJson(json = {}) {
|
||||||
|
|
@ -349,8 +345,6 @@ class KcpStreamSettings extends XrayCommonClass {
|
||||||
json.congestion,
|
json.congestion,
|
||||||
json.readBufferSize,
|
json.readBufferSize,
|
||||||
json.writeBufferSize,
|
json.writeBufferSize,
|
||||||
ObjectUtil.isEmpty(json.header) ? 'none' : json.header.type,
|
|
||||||
json.seed,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -363,10 +357,6 @@ class KcpStreamSettings extends XrayCommonClass {
|
||||||
congestion: this.congestion,
|
congestion: this.congestion,
|
||||||
readBufferSize: this.readBuffer,
|
readBufferSize: this.readBuffer,
|
||||||
writeBufferSize: this.writeBuffer,
|
writeBufferSize: this.writeBuffer,
|
||||||
header: {
|
|
||||||
type: this.type,
|
|
||||||
},
|
|
||||||
seed: this.seed,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -497,6 +487,19 @@ class xHTTPStreamSettings extends XrayCommonClass {
|
||||||
noSSEHeader = false,
|
noSSEHeader = false,
|
||||||
xPaddingBytes = "100-1000",
|
xPaddingBytes = "100-1000",
|
||||||
mode = MODE_OPTION.AUTO,
|
mode = MODE_OPTION.AUTO,
|
||||||
|
xPaddingObfsMode = false,
|
||||||
|
xPaddingKey = '',
|
||||||
|
xPaddingHeader = '',
|
||||||
|
xPaddingPlacement = '',
|
||||||
|
xPaddingMethod = '',
|
||||||
|
uplinkHTTPMethod = '',
|
||||||
|
sessionPlacement = '',
|
||||||
|
sessionKey = '',
|
||||||
|
seqPlacement = '',
|
||||||
|
seqKey = '',
|
||||||
|
uplinkDataPlacement = '',
|
||||||
|
uplinkDataKey = '',
|
||||||
|
uplinkChunkSize = 0,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
|
@ -508,6 +511,19 @@ class xHTTPStreamSettings extends XrayCommonClass {
|
||||||
this.noSSEHeader = noSSEHeader;
|
this.noSSEHeader = noSSEHeader;
|
||||||
this.xPaddingBytes = xPaddingBytes;
|
this.xPaddingBytes = xPaddingBytes;
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
this.xPaddingObfsMode = xPaddingObfsMode;
|
||||||
|
this.xPaddingKey = xPaddingKey;
|
||||||
|
this.xPaddingHeader = xPaddingHeader;
|
||||||
|
this.xPaddingPlacement = xPaddingPlacement;
|
||||||
|
this.xPaddingMethod = xPaddingMethod;
|
||||||
|
this.uplinkHTTPMethod = uplinkHTTPMethod;
|
||||||
|
this.sessionPlacement = sessionPlacement;
|
||||||
|
this.sessionKey = sessionKey;
|
||||||
|
this.seqPlacement = seqPlacement;
|
||||||
|
this.seqKey = seqKey;
|
||||||
|
this.uplinkDataPlacement = uplinkDataPlacement;
|
||||||
|
this.uplinkDataKey = uplinkDataKey;
|
||||||
|
this.uplinkChunkSize = uplinkChunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
addHeader(name, value) {
|
addHeader(name, value) {
|
||||||
|
|
@ -529,6 +545,19 @@ class xHTTPStreamSettings extends XrayCommonClass {
|
||||||
json.noSSEHeader,
|
json.noSSEHeader,
|
||||||
json.xPaddingBytes,
|
json.xPaddingBytes,
|
||||||
json.mode,
|
json.mode,
|
||||||
|
json.xPaddingObfsMode,
|
||||||
|
json.xPaddingKey,
|
||||||
|
json.xPaddingHeader,
|
||||||
|
json.xPaddingPlacement,
|
||||||
|
json.xPaddingMethod,
|
||||||
|
json.uplinkHTTPMethod,
|
||||||
|
json.sessionPlacement,
|
||||||
|
json.sessionKey,
|
||||||
|
json.seqPlacement,
|
||||||
|
json.seqKey,
|
||||||
|
json.uplinkDataPlacement,
|
||||||
|
json.uplinkDataKey,
|
||||||
|
json.uplinkChunkSize,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -543,6 +572,19 @@ class xHTTPStreamSettings extends XrayCommonClass {
|
||||||
noSSEHeader: this.noSSEHeader,
|
noSSEHeader: this.noSSEHeader,
|
||||||
xPaddingBytes: this.xPaddingBytes,
|
xPaddingBytes: this.xPaddingBytes,
|
||||||
mode: this.mode,
|
mode: this.mode,
|
||||||
|
xPaddingObfsMode: this.xPaddingObfsMode,
|
||||||
|
xPaddingKey: this.xPaddingKey,
|
||||||
|
xPaddingHeader: this.xPaddingHeader,
|
||||||
|
xPaddingPlacement: this.xPaddingPlacement,
|
||||||
|
xPaddingMethod: this.xPaddingMethod,
|
||||||
|
uplinkHTTPMethod: this.uplinkHTTPMethod,
|
||||||
|
sessionPlacement: this.sessionPlacement,
|
||||||
|
sessionKey: this.sessionKey,
|
||||||
|
seqPlacement: this.seqPlacement,
|
||||||
|
seqKey: this.seqKey,
|
||||||
|
uplinkDataPlacement: this.uplinkDataPlacement,
|
||||||
|
uplinkDataKey: this.uplinkDataKey,
|
||||||
|
uplinkChunkSize: this.uplinkChunkSize,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -554,7 +596,8 @@ class TlsStreamSettings extends XrayCommonClass {
|
||||||
maxVersion = TLS_VERSION_OPTION.TLS13,
|
maxVersion = TLS_VERSION_OPTION.TLS13,
|
||||||
cipherSuites = '',
|
cipherSuites = '',
|
||||||
rejectUnknownSni = false,
|
rejectUnknownSni = false,
|
||||||
verifyPeerCertByName = ['dns.google', 'cloudflare-dns.com'],
|
verifyPeerCertByNames = ['dns.google', 'cloudflare-dns.com'],
|
||||||
|
pinnedPeerCertSha256 = [],
|
||||||
disableSystemRoot = false,
|
disableSystemRoot = false,
|
||||||
enableSessionResumption = false,
|
enableSessionResumption = false,
|
||||||
certificates = [new TlsStreamSettings.Cert()],
|
certificates = [new TlsStreamSettings.Cert()],
|
||||||
|
|
@ -569,7 +612,8 @@ class TlsStreamSettings extends XrayCommonClass {
|
||||||
this.maxVersion = maxVersion;
|
this.maxVersion = maxVersion;
|
||||||
this.cipherSuites = cipherSuites;
|
this.cipherSuites = cipherSuites;
|
||||||
this.rejectUnknownSni = rejectUnknownSni;
|
this.rejectUnknownSni = rejectUnknownSni;
|
||||||
this.verifyPeerCertByName = Array.isArray(verifyPeerCertByName) ? verifyPeerCertByName.join(",") : verifyPeerCertByName;
|
this.verifyPeerCertByNames = Array.isArray(verifyPeerCertByNames) ? verifyPeerCertByNames.join(",") : verifyPeerCertByNames;
|
||||||
|
this.pinnedPeerCertSha256 = pinnedPeerCertSha256;
|
||||||
this.disableSystemRoot = disableSystemRoot;
|
this.disableSystemRoot = disableSystemRoot;
|
||||||
this.enableSessionResumption = enableSessionResumption;
|
this.enableSessionResumption = enableSessionResumption;
|
||||||
this.certs = certificates;
|
this.certs = certificates;
|
||||||
|
|
@ -603,7 +647,8 @@ class TlsStreamSettings extends XrayCommonClass {
|
||||||
json.maxVersion,
|
json.maxVersion,
|
||||||
json.cipherSuites,
|
json.cipherSuites,
|
||||||
json.rejectUnknownSni,
|
json.rejectUnknownSni,
|
||||||
json.verifyPeerCertByName,
|
json.verifyPeerCertByNames,
|
||||||
|
json.pinnedPeerCertSha256 || [],
|
||||||
json.disableSystemRoot,
|
json.disableSystemRoot,
|
||||||
json.enableSessionResumption,
|
json.enableSessionResumption,
|
||||||
certs,
|
certs,
|
||||||
|
|
@ -621,7 +666,8 @@ class TlsStreamSettings extends XrayCommonClass {
|
||||||
maxVersion: this.maxVersion,
|
maxVersion: this.maxVersion,
|
||||||
cipherSuites: this.cipherSuites,
|
cipherSuites: this.cipherSuites,
|
||||||
rejectUnknownSni: this.rejectUnknownSni,
|
rejectUnknownSni: this.rejectUnknownSni,
|
||||||
verifyPeerCertByName: this.verifyPeerCertByName.split(","),
|
verifyPeerCertByNames: this.verifyPeerCertByNames.split(","),
|
||||||
|
pinnedPeerCertSha256: this.pinnedPeerCertSha256.length > 0 ? this.pinnedPeerCertSha256 : undefined,
|
||||||
disableSystemRoot: this.disableSystemRoot,
|
disableSystemRoot: this.disableSystemRoot,
|
||||||
enableSessionResumption: this.enableSessionResumption,
|
enableSessionResumption: this.enableSessionResumption,
|
||||||
certificates: TlsStreamSettings.toJsonArray(this.certs),
|
certificates: TlsStreamSettings.toJsonArray(this.certs),
|
||||||
|
|
@ -929,6 +975,51 @@ class SockoptStreamSettings extends XrayCommonClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FinalMask extends XrayCommonClass {
|
||||||
|
constructor(type = 'salamander', settings = {}) {
|
||||||
|
super();
|
||||||
|
this.type = type;
|
||||||
|
this.settings = this._getDefaultSettings(type, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getDefaultSettings(type, settings = {}) {
|
||||||
|
switch (type) {
|
||||||
|
case 'salamander':
|
||||||
|
case 'mkcp-aes128gcm':
|
||||||
|
return { password: settings.password || '' };
|
||||||
|
case 'header-dns':
|
||||||
|
case 'xdns':
|
||||||
|
return { domain: settings.domain || '' };
|
||||||
|
case 'mkcp-original':
|
||||||
|
case 'header-dtls':
|
||||||
|
case 'header-srtp':
|
||||||
|
case 'header-utp':
|
||||||
|
case 'header-wechat':
|
||||||
|
case 'header-wireguard':
|
||||||
|
return {};
|
||||||
|
default:
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json = {}) {
|
||||||
|
return new FinalMask(
|
||||||
|
json.type || 'salamander',
|
||||||
|
json.settings || {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
toJson() {
|
||||||
|
const result = {
|
||||||
|
type: this.type
|
||||||
|
};
|
||||||
|
if (this.settings && Object.keys(this.settings).length > 0) {
|
||||||
|
result.settings = this.settings;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class StreamSettings extends XrayCommonClass {
|
class StreamSettings extends XrayCommonClass {
|
||||||
constructor(network = 'tcp',
|
constructor(network = 'tcp',
|
||||||
security = 'none',
|
security = 'none',
|
||||||
|
|
@ -941,6 +1032,7 @@ class StreamSettings extends XrayCommonClass {
|
||||||
grpcSettings = new GrpcStreamSettings(),
|
grpcSettings = new GrpcStreamSettings(),
|
||||||
httpupgradeSettings = new HTTPUpgradeStreamSettings(),
|
httpupgradeSettings = new HTTPUpgradeStreamSettings(),
|
||||||
xhttpSettings = new xHTTPStreamSettings(),
|
xhttpSettings = new xHTTPStreamSettings(),
|
||||||
|
finalmask = { udp: [] },
|
||||||
sockopt = undefined,
|
sockopt = undefined,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -955,9 +1047,23 @@ class StreamSettings extends XrayCommonClass {
|
||||||
this.grpc = grpcSettings;
|
this.grpc = grpcSettings;
|
||||||
this.httpupgrade = httpupgradeSettings;
|
this.httpupgrade = httpupgradeSettings;
|
||||||
this.xhttp = xhttpSettings;
|
this.xhttp = xhttpSettings;
|
||||||
|
this.finalmask = finalmask;
|
||||||
this.sockopt = sockopt;
|
this.sockopt = sockopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addUdpMask(type = 'salamander') {
|
||||||
|
if (!this.finalmask.udp) {
|
||||||
|
this.finalmask.udp = [];
|
||||||
|
}
|
||||||
|
this.finalmask.udp.push(new FinalMask(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
delUdpMask(index) {
|
||||||
|
if (this.finalmask.udp) {
|
||||||
|
this.finalmask.udp.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get isTls() {
|
get isTls() {
|
||||||
return this.security === "tls";
|
return this.security === "tls";
|
||||||
}
|
}
|
||||||
|
|
@ -992,6 +1098,14 @@ class StreamSettings extends XrayCommonClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
static fromJson(json = {}) {
|
||||||
|
let finalmask = { udp: [] };
|
||||||
|
if (json.finalmask) {
|
||||||
|
if (Array.isArray(json.finalmask)) {
|
||||||
|
finalmask.udp = json.finalmask.map(mask => FinalMask.fromJson(mask));
|
||||||
|
} else if (json.finalmask.udp) {
|
||||||
|
finalmask.udp = json.finalmask.udp.map(mask => FinalMask.fromJson(mask));
|
||||||
|
}
|
||||||
|
}
|
||||||
return new StreamSettings(
|
return new StreamSettings(
|
||||||
json.network,
|
json.network,
|
||||||
json.security,
|
json.security,
|
||||||
|
|
@ -1004,6 +1118,7 @@ class StreamSettings extends XrayCommonClass {
|
||||||
GrpcStreamSettings.fromJson(json.grpcSettings),
|
GrpcStreamSettings.fromJson(json.grpcSettings),
|
||||||
HTTPUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
|
HTTPUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
|
||||||
xHTTPStreamSettings.fromJson(json.xhttpSettings),
|
xHTTPStreamSettings.fromJson(json.xhttpSettings),
|
||||||
|
finalmask,
|
||||||
SockoptStreamSettings.fromJson(json.sockopt),
|
SockoptStreamSettings.fromJson(json.sockopt),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1022,6 +1137,9 @@ class StreamSettings extends XrayCommonClass {
|
||||||
grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined,
|
grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined,
|
||||||
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
|
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
|
||||||
xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
|
xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
|
||||||
|
finalmask: (this.finalmask.udp && this.finalmask.udp.length > 0) ? {
|
||||||
|
udp: this.finalmask.udp.map(mask => mask.toJson())
|
||||||
|
} : undefined,
|
||||||
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
|
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1947,7 +2065,9 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
|
||||||
json.selectedAuth = this.selectedAuth;
|
json.selectedAuth = this.selectedAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.testseed && this.testseed.length >= 4) {
|
// Only include testseed if at least one client has a flow set
|
||||||
|
const hasFlow = this.vlesses && this.vlesses.some(vless => vless.flow && vless.flow !== '');
|
||||||
|
if (hasFlow && this.testseed && this.testseed.length >= 4) {
|
||||||
json.testseed = this.testseed;
|
json.testseed = this.testseed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2509,7 +2629,7 @@ Inbound.HttpSettings.HttpAccount = class extends XrayCommonClass {
|
||||||
Inbound.WireguardSettings = class extends XrayCommonClass {
|
Inbound.WireguardSettings = class extends XrayCommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
protocol,
|
protocol,
|
||||||
mtu = 1250,
|
mtu = 1420,
|
||||||
secretKey = Wireguard.generateKeypair().privateKey,
|
secretKey = Wireguard.generateKeypair().privateKey,
|
||||||
peers = [new Inbound.WireguardSettings.Peer()],
|
peers = [new Inbound.WireguardSettings.Peer()],
|
||||||
noKernelTun = false
|
noKernelTun = false
|
||||||
|
|
|
||||||
|
|
@ -165,15 +165,13 @@ class TcpStreamSettings extends CommonClass {
|
||||||
|
|
||||||
class KcpStreamSettings extends CommonClass {
|
class KcpStreamSettings extends CommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
mtu = 1250,
|
mtu = 1350,
|
||||||
tti = 50,
|
tti = 20,
|
||||||
uplinkCapacity = 5,
|
uplinkCapacity = 5,
|
||||||
downlinkCapacity = 20,
|
downlinkCapacity = 20,
|
||||||
congestion = false,
|
congestion = false,
|
||||||
readBufferSize = 2,
|
readBufferSize = 1,
|
||||||
writeBufferSize = 2,
|
writeBufferSize = 1,
|
||||||
type = 'none',
|
|
||||||
seed = '',
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.mtu = mtu;
|
this.mtu = mtu;
|
||||||
|
|
@ -183,8 +181,6 @@ class KcpStreamSettings extends CommonClass {
|
||||||
this.congestion = congestion;
|
this.congestion = congestion;
|
||||||
this.readBuffer = readBufferSize;
|
this.readBuffer = readBufferSize;
|
||||||
this.writeBuffer = writeBufferSize;
|
this.writeBuffer = writeBufferSize;
|
||||||
this.type = type;
|
|
||||||
this.seed = seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
static fromJson(json = {}) {
|
||||||
|
|
@ -196,8 +192,6 @@ class KcpStreamSettings extends CommonClass {
|
||||||
json.congestion,
|
json.congestion,
|
||||||
json.readBufferSize,
|
json.readBufferSize,
|
||||||
json.writeBufferSize,
|
json.writeBufferSize,
|
||||||
ObjectUtil.isEmpty(json.header) ? 'none' : json.header.type,
|
|
||||||
json.seed,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,10 +204,6 @@ class KcpStreamSettings extends CommonClass {
|
||||||
congestion: this.congestion,
|
congestion: this.congestion,
|
||||||
readBufferSize: this.readBuffer,
|
readBufferSize: this.readBuffer,
|
||||||
writeBufferSize: this.writeBuffer,
|
writeBufferSize: this.writeBuffer,
|
||||||
header: {
|
|
||||||
type: this.type,
|
|
||||||
},
|
|
||||||
seed: this.seed,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -434,7 +424,8 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
up = '0',
|
up = '0',
|
||||||
down = '0',
|
down = '0',
|
||||||
udphopPort = '',
|
udphopPort = '',
|
||||||
udphopInterval = 30,
|
udphopIntervalMin = 30,
|
||||||
|
udphopIntervalMax = 30,
|
||||||
initStreamReceiveWindow = 8388608,
|
initStreamReceiveWindow = 8388608,
|
||||||
maxStreamReceiveWindow = 8388608,
|
maxStreamReceiveWindow = 8388608,
|
||||||
initConnectionReceiveWindow = 20971520,
|
initConnectionReceiveWindow = 20971520,
|
||||||
|
|
@ -450,7 +441,8 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
this.up = up;
|
this.up = up;
|
||||||
this.down = down;
|
this.down = down;
|
||||||
this.udphopPort = udphopPort;
|
this.udphopPort = udphopPort;
|
||||||
this.udphopInterval = udphopInterval;
|
this.udphopIntervalMin = udphopIntervalMin;
|
||||||
|
this.udphopIntervalMax = udphopIntervalMax;
|
||||||
this.initStreamReceiveWindow = initStreamReceiveWindow;
|
this.initStreamReceiveWindow = initStreamReceiveWindow;
|
||||||
this.maxStreamReceiveWindow = maxStreamReceiveWindow;
|
this.maxStreamReceiveWindow = maxStreamReceiveWindow;
|
||||||
this.initConnectionReceiveWindow = initConnectionReceiveWindow;
|
this.initConnectionReceiveWindow = initConnectionReceiveWindow;
|
||||||
|
|
@ -462,10 +454,18 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
static fromJson(json = {}) {
|
||||||
let udphopPort = '';
|
let udphopPort = '';
|
||||||
let udphopInterval = 30;
|
let udphopIntervalMin = 30;
|
||||||
|
let udphopIntervalMax = 30;
|
||||||
if (json.udphop) {
|
if (json.udphop) {
|
||||||
udphopPort = json.udphop.port || '';
|
udphopPort = json.udphop.port || '';
|
||||||
udphopInterval = json.udphop.interval || 30;
|
// Backward compatibility: if old 'interval' exists, use it for both min/max
|
||||||
|
if (json.udphop.interval !== undefined) {
|
||||||
|
udphopIntervalMin = json.udphop.interval;
|
||||||
|
udphopIntervalMax = json.udphop.interval;
|
||||||
|
} else {
|
||||||
|
udphopIntervalMin = json.udphop.intervalMin || 30;
|
||||||
|
udphopIntervalMax = json.udphop.intervalMax || 30;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new HysteriaStreamSettings(
|
return new HysteriaStreamSettings(
|
||||||
json.version,
|
json.version,
|
||||||
|
|
@ -474,7 +474,8 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
json.up,
|
json.up,
|
||||||
json.down,
|
json.down,
|
||||||
udphopPort,
|
udphopPort,
|
||||||
udphopInterval,
|
udphopIntervalMin,
|
||||||
|
udphopIntervalMax,
|
||||||
json.initStreamReceiveWindow,
|
json.initStreamReceiveWindow,
|
||||||
json.maxStreamReceiveWindow,
|
json.maxStreamReceiveWindow,
|
||||||
json.initConnectionReceiveWindow,
|
json.initConnectionReceiveWindow,
|
||||||
|
|
@ -503,7 +504,8 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
if (this.udphopPort) {
|
if (this.udphopPort) {
|
||||||
result.udphop = {
|
result.udphop = {
|
||||||
port: this.udphopPort,
|
port: this.udphopPort,
|
||||||
interval: this.udphopInterval
|
intervalMin: this.udphopIntervalMin,
|
||||||
|
intervalMax: this.udphopIntervalMax
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -558,27 +560,49 @@ class SockoptStreamSettings extends CommonClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UdpMask extends CommonClass {
|
class FinalMask extends CommonClass {
|
||||||
constructor(type = 'salamander', password = '') {
|
constructor(type = 'salamander', settings = {}) {
|
||||||
super();
|
super();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.password = password;
|
this.settings = this._getDefaultSettings(type, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getDefaultSettings(type, settings = {}) {
|
||||||
|
switch (type) {
|
||||||
|
case 'salamander':
|
||||||
|
case 'mkcp-aes128gcm':
|
||||||
|
return { password: settings.password || '' };
|
||||||
|
case 'header-dns':
|
||||||
|
case 'xdns':
|
||||||
|
return { domain: settings.domain || '' };
|
||||||
|
case 'mkcp-original':
|
||||||
|
case 'header-dtls':
|
||||||
|
case 'header-srtp':
|
||||||
|
case 'header-utp':
|
||||||
|
case 'header-wechat':
|
||||||
|
case 'header-wireguard':
|
||||||
|
return {}; // No settings needed
|
||||||
|
default:
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
static fromJson(json = {}) {
|
||||||
return new UdpMask(
|
return new FinalMask(
|
||||||
json.type,
|
json.type || 'salamander',
|
||||||
json.settings?.password || ''
|
json.settings || {}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJson() {
|
toJson() {
|
||||||
return {
|
const result = {
|
||||||
type: this.type,
|
type: this.type
|
||||||
settings: {
|
|
||||||
password: this.password
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
// Only include settings if they exist and are not empty
|
||||||
|
if (this.settings && Object.keys(this.settings).length > 0) {
|
||||||
|
result.settings = this.settings;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -595,7 +619,7 @@ class StreamSettings extends CommonClass {
|
||||||
httpupgradeSettings = new HttpUpgradeStreamSettings(),
|
httpupgradeSettings = new HttpUpgradeStreamSettings(),
|
||||||
xhttpSettings = new xHTTPStreamSettings(),
|
xhttpSettings = new xHTTPStreamSettings(),
|
||||||
hysteriaSettings = new HysteriaStreamSettings(),
|
hysteriaSettings = new HysteriaStreamSettings(),
|
||||||
udpmasks = [],
|
finalmask = { udp: [] },
|
||||||
sockopt = undefined,
|
sockopt = undefined,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -610,16 +634,21 @@ class StreamSettings extends CommonClass {
|
||||||
this.httpupgrade = httpupgradeSettings;
|
this.httpupgrade = httpupgradeSettings;
|
||||||
this.xhttp = xhttpSettings;
|
this.xhttp = xhttpSettings;
|
||||||
this.hysteria = hysteriaSettings;
|
this.hysteria = hysteriaSettings;
|
||||||
this.udpmasks = udpmasks;
|
this.finalmask = finalmask;
|
||||||
this.sockopt = sockopt;
|
this.sockopt = sockopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
addUdpMask() {
|
addUdpMask(type = 'salamander') {
|
||||||
this.udpmasks.push(new UdpMask());
|
if (!this.finalmask.udp) {
|
||||||
|
this.finalmask.udp = [];
|
||||||
|
}
|
||||||
|
this.finalmask.udp.push(new FinalMask(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
delUdpMask(index) {
|
delUdpMask(index) {
|
||||||
this.udpmasks.splice(index, 1);
|
if (this.finalmask.udp) {
|
||||||
|
this.finalmask.udp.splice(index, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get isTls() {
|
get isTls() {
|
||||||
|
|
@ -639,7 +668,16 @@ class StreamSettings extends CommonClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
static fromJson(json = {}) {
|
||||||
const udpmasks = json.udpmasks ? json.udpmasks.map(mask => UdpMask.fromJson(mask)) : [];
|
let finalmask = { udp: [] };
|
||||||
|
if (json.finalmask) {
|
||||||
|
if (Array.isArray(json.finalmask)) {
|
||||||
|
// Legacy format: direct array (backward compatibility)
|
||||||
|
finalmask.udp = json.finalmask.map(mask => FinalMask.fromJson(mask));
|
||||||
|
} else if (json.finalmask.udp) {
|
||||||
|
// New format: object with udp array
|
||||||
|
finalmask.udp = json.finalmask.udp.map(mask => FinalMask.fromJson(mask));
|
||||||
|
}
|
||||||
|
}
|
||||||
return new StreamSettings(
|
return new StreamSettings(
|
||||||
json.network,
|
json.network,
|
||||||
json.security,
|
json.security,
|
||||||
|
|
@ -652,7 +690,7 @@ class StreamSettings extends CommonClass {
|
||||||
HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
|
HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
|
||||||
xHTTPStreamSettings.fromJson(json.xhttpSettings),
|
xHTTPStreamSettings.fromJson(json.xhttpSettings),
|
||||||
HysteriaStreamSettings.fromJson(json.hysteriaSettings),
|
HysteriaStreamSettings.fromJson(json.hysteriaSettings),
|
||||||
udpmasks,
|
finalmask,
|
||||||
SockoptStreamSettings.fromJson(json.sockopt),
|
SockoptStreamSettings.fromJson(json.sockopt),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -671,7 +709,9 @@ class StreamSettings extends CommonClass {
|
||||||
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
|
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
|
||||||
xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
|
xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
|
||||||
hysteriaSettings: network === 'hysteria' ? this.hysteria.toJson() : undefined,
|
hysteriaSettings: network === 'hysteria' ? this.hysteria.toJson() : undefined,
|
||||||
udpmasks: this.udpmasks.length > 0 ? this.udpmasks.map(mask => mask.toJson()) : undefined,
|
finalmask: (this.finalmask.udp && this.finalmask.udp.length > 0) ? {
|
||||||
|
udp: this.finalmask.udp.map(mask => mask.toJson())
|
||||||
|
} : undefined,
|
||||||
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
|
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -996,7 +1036,15 @@ class Outbound extends CommonClass {
|
||||||
stream.hysteria.up = urlParams.get('up') ?? '0';
|
stream.hysteria.up = urlParams.get('up') ?? '0';
|
||||||
stream.hysteria.down = urlParams.get('down') ?? '0';
|
stream.hysteria.down = urlParams.get('down') ?? '0';
|
||||||
stream.hysteria.udphopPort = urlParams.get('udphopPort') ?? '';
|
stream.hysteria.udphopPort = urlParams.get('udphopPort') ?? '';
|
||||||
stream.hysteria.udphopInterval = parseInt(urlParams.get('udphopInterval') ?? '30');
|
// Support both old single interval and new min/max range
|
||||||
|
if (urlParams.has('udphopInterval')) {
|
||||||
|
const interval = parseInt(urlParams.get('udphopInterval'));
|
||||||
|
stream.hysteria.udphopIntervalMin = interval;
|
||||||
|
stream.hysteria.udphopIntervalMax = interval;
|
||||||
|
} else {
|
||||||
|
stream.hysteria.udphopIntervalMin = parseInt(urlParams.get('udphopIntervalMin') ?? '30');
|
||||||
|
stream.hysteria.udphopIntervalMax = parseInt(urlParams.get('udphopIntervalMax') ?? '30');
|
||||||
|
}
|
||||||
|
|
||||||
// Optional QUIC parameters
|
// Optional QUIC parameters
|
||||||
if (urlParams.has('initStreamReceiveWindow')) {
|
if (urlParams.has('initStreamReceiveWindow')) {
|
||||||
|
|
@ -1285,11 +1333,14 @@ Outbound.VLESSSettings = class extends CommonClass {
|
||||||
flow: this.flow,
|
flow: this.flow,
|
||||||
encryption: this.encryption,
|
encryption: this.encryption,
|
||||||
};
|
};
|
||||||
if (this.testpre > 0) {
|
// Only include Vision settings when flow is set
|
||||||
result.testpre = this.testpre;
|
if (this.flow && this.flow !== '') {
|
||||||
}
|
if (this.testpre > 0) {
|
||||||
if (this.testseed && this.testseed.length >= 4) {
|
result.testpre = this.testpre;
|
||||||
result.testseed = this.testseed;
|
}
|
||||||
|
if (this.testseed && this.testseed.length >= 4) {
|
||||||
|
result.testseed = this.testseed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -1422,7 +1473,7 @@ Outbound.HttpSettings = class extends CommonClass {
|
||||||
|
|
||||||
Outbound.WireguardSettings = class extends CommonClass {
|
Outbound.WireguardSettings = class extends CommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
mtu = 1250,
|
mtu = 1420,
|
||||||
secretKey = '',
|
secretKey = '',
|
||||||
address = [''],
|
address = [''],
|
||||||
workers = 2,
|
workers = 2,
|
||||||
|
|
|
||||||
|
|
@ -407,21 +407,6 @@
|
||||||
|
|
||||||
<!-- kcp -->
|
<!-- kcp -->
|
||||||
<template v-if="outbound.stream.network === 'kcp'">
|
<template v-if="outbound.stream.network === 'kcp'">
|
||||||
<a-form-item label='{{ i18n "camouflage" }}'>
|
|
||||||
<a-select v-model="outbound.stream.kcp.type"
|
|
||||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
|
||||||
<a-select-option value="none">None</a-select-option>
|
|
||||||
<a-select-option value="srtp">SRTP</a-select-option>
|
|
||||||
<a-select-option value="utp">uTP</a-select-option>
|
|
||||||
<a-select-option value="wechat-video">WeChat</a-select-option>
|
|
||||||
<a-select-option value="dtls">DTLS 1.2</a-select-option>
|
|
||||||
<a-select-option value="wireguard">WireGuard</a-select-option>
|
|
||||||
<a-select-option value="dns">DNS</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label='{{ i18n "password" }}'>
|
|
||||||
<a-input v-model="outbound.stream.kcp.seed"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label='MTU'>
|
<a-form-item label='MTU'>
|
||||||
<a-input-number v-model.number="outbound.stream.kcp.mtu"
|
<a-input-number v-model.number="outbound.stream.kcp.mtu"
|
||||||
min="0"></a-input-number>
|
min="0"></a-input-number>
|
||||||
|
|
@ -546,8 +531,9 @@
|
||||||
<a-input v-model.trim="outbound.stream.hysteria.auth"></a-input>
|
<a-input v-model.trim="outbound.stream.hysteria.auth"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Congestion'>
|
<a-form-item label='Congestion'>
|
||||||
<a-select v-model="outbound.stream.hysteria.congestion" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select v-model="outbound.stream.hysteria.congestion"
|
||||||
<a-select-option value="">BBR (Auto)</a-select-option>
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value>BBR (Auto)</a-select-option>
|
||||||
<a-select-option value="brutal">Brutal</a-select-option>
|
<a-select-option value="brutal">Brutal</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
@ -563,10 +549,16 @@
|
||||||
<a-input v-model.trim="outbound.stream.hysteria.udphopPort"
|
<a-input v-model.trim="outbound.stream.hysteria.udphopPort"
|
||||||
placeholder="e.g., 1145-1919 or 11,13,15-17"></a-input>
|
placeholder="e.g., 1145-1919 or 11,13,15-17"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='UDP Hop Interval (s)'
|
<a-form-item label='UDP Hop Interval Min (s)'
|
||||||
v-if="outbound.stream.hysteria.udphopPort">
|
v-if="outbound.stream.hysteria.udphopPort">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model.number="outbound.stream.hysteria.udphopInterval"
|
v-model.number="outbound.stream.hysteria.udphopIntervalMin"
|
||||||
|
:min="5"></a-input-number>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='UDP Hop Interval Max (s)'
|
||||||
|
v-if="outbound.stream.hysteria.udphopPort">
|
||||||
|
<a-input-number
|
||||||
|
v-model.number="outbound.stream.hysteria.udphopIntervalMax"
|
||||||
:min="5"></a-input-number>
|
:min="5"></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Init Stream Receive'>
|
<a-form-item label='Init Stream Receive'>
|
||||||
|
|
@ -602,25 +594,73 @@
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- udpmasks settings -->
|
<!-- finalmask settings -->
|
||||||
<template v-if="outbound.canEnableStream()">
|
<template v-if="outbound.canEnableStream()">
|
||||||
<a-form-item label="UDP Masks">
|
<a-form-item label="UDP Masks">
|
||||||
<a-button icon="plus" type="primary" size="small" @click="outbound.stream.addUdpMask()"></a-button>
|
<a-button icon="plus" type="primary" size="small"
|
||||||
|
@click="outbound.stream.addUdpMask(outbound.protocol === Protocols.Hysteria ? 'salamander' : (outbound.stream.network === 'kcp' ? 'mkcp-aes128gcm' : 'xdns'))"></a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<template v-if="outbound.stream.udpmasks.length > 0">
|
<template
|
||||||
<a-form v-for="(mask, index) in outbound.stream.udpmasks" :key="index" :colon="false"
|
v-if="outbound.stream.finalmask.udp && outbound.stream.finalmask.udp.length > 0">
|
||||||
|
<a-form v-for="(mask, index) in outbound.stream.finalmask.udp"
|
||||||
|
:key="index" :colon="false"
|
||||||
:label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
:label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||||
<a-divider :style="{ margin: '0' }"> UDP Mask [[ index + 1 ]]
|
<a-divider :style="{ margin: '0' }"> UDP Mask [[ index + 1 ]]
|
||||||
<a-icon type="delete" @click="() => outbound.stream.delUdpMask(index)"
|
<a-icon type="delete"
|
||||||
|
@click="() => outbound.stream.delUdpMask(index)"
|
||||||
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
|
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
|
||||||
</a-divider>
|
</a-divider>
|
||||||
<a-form-item label='Type'>
|
<a-form-item label='Type'>
|
||||||
<a-select v-model="mask.type" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select v-model="mask.type"
|
||||||
<a-select-option value="salamander">Salamander</a-select-option>
|
@change="(type) => mask.settings = mask._getDefaultSettings(type, {})"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<!-- Salamander for Hysteria2 only -->
|
||||||
|
<a-select-option v-if="outbound.protocol === Protocols.Hysteria"
|
||||||
|
value="salamander">
|
||||||
|
Salamander (Hysteria2)</a-select-option>
|
||||||
|
<!-- mKCP-specific masks -->
|
||||||
|
<a-select-option v-if="outbound.stream.network === 'kcp'"
|
||||||
|
value="mkcp-aes128gcm">
|
||||||
|
mKCP AES-128-GCM</a-select-option>
|
||||||
|
<a-select-option v-if="outbound.stream.network === 'kcp'"
|
||||||
|
value="header-dns">
|
||||||
|
Header DNS</a-select-option>
|
||||||
|
<a-select-option v-if="outbound.stream.network === 'kcp'"
|
||||||
|
value="header-dtls">
|
||||||
|
Header DTLS 1.2</a-select-option>
|
||||||
|
<a-select-option v-if="outbound.stream.network === 'kcp'"
|
||||||
|
value="header-srtp">
|
||||||
|
Header SRTP</a-select-option>
|
||||||
|
<a-select-option v-if="outbound.stream.network === 'kcp'"
|
||||||
|
value="header-utp">
|
||||||
|
Header uTP</a-select-option>
|
||||||
|
<a-select-option v-if="outbound.stream.network === 'kcp'"
|
||||||
|
value="header-wechat">
|
||||||
|
Header WeChat Video</a-select-option>
|
||||||
|
<a-select-option v-if="outbound.stream.network === 'kcp'"
|
||||||
|
value="header-wireguard">
|
||||||
|
Header WireGuard</a-select-option>
|
||||||
|
<a-select-option v-if="outbound.stream.network === 'kcp'"
|
||||||
|
value="mkcp-original">
|
||||||
|
mKCP Original</a-select-option>
|
||||||
|
<!-- xDNS for TCP/WS/HTTPUpgrade/XHTTP -->
|
||||||
|
<a-select-option
|
||||||
|
v-if="['tcp', 'ws', 'httpupgrade', 'xhttp'].includes(outbound.stream.network)"
|
||||||
|
value="xdns">
|
||||||
|
xDNS (Experimental)</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Password'>
|
<!-- Settings for password-based masks -->
|
||||||
<a-input v-model.trim="mask.password" placeholder="Obfuscation password"></a-input>
|
<a-form-item label='Password'
|
||||||
|
v-if="['salamander', 'mkcp-aes128gcm'].includes(mask.type)">
|
||||||
|
<a-input v-model.trim="mask.settings.password"
|
||||||
|
placeholder="Obfuscation password"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<!-- Settings for domain-based masks -->
|
||||||
|
<a-form-item label='Domain'
|
||||||
|
v-if="['header-dns', 'xdns'].includes(mask.type)">
|
||||||
|
<a-input v-model.trim="mask.settings.domain"
|
||||||
|
placeholder="e.g., www.example.com"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
70
web/html/form/stream/stream_finalmask.html
Normal file
70
web/html/form/stream/stream_finalmask.html
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
{{define "form/streamFinalMask"}}
|
||||||
|
<a-divider :style="{ margin: '5px 0 0' }"></a-divider>
|
||||||
|
<a-form :colon="false" :label-col="{ md: {span:8} }"
|
||||||
|
:wrapper-col="{ md: {span:14} }">
|
||||||
|
<a-form-item label="UDP Masks">
|
||||||
|
<a-button icon="plus" type="primary" size="small"
|
||||||
|
@click="inbound.stream.addUdpMask(inbound.stream.network === 'kcp' ? 'mkcp-aes128gcm' : 'xdns')"></a-button>
|
||||||
|
</a-form-item>
|
||||||
|
<template
|
||||||
|
v-if="inbound.stream.finalmask.udp && inbound.stream.finalmask.udp.length > 0">
|
||||||
|
<a-form v-for="(mask, index) in inbound.stream.finalmask.udp"
|
||||||
|
:key="index" :colon="false"
|
||||||
|
:label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||||
|
<a-divider :style="{ margin: '0' }"> UDP Mask [[ index + 1 ]]
|
||||||
|
<a-icon type="delete"
|
||||||
|
@click="() => inbound.stream.delUdpMask(index)"
|
||||||
|
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
|
||||||
|
</a-divider>
|
||||||
|
<a-form-item label='Type'>
|
||||||
|
<a-select v-model="mask.type"
|
||||||
|
@change="(type) => mask.settings = mask._getDefaultSettings(type, {})"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<!-- mKCP-specific masks -->
|
||||||
|
<a-select-option v-if="inbound.stream.network === 'kcp'"
|
||||||
|
value="mkcp-aes128gcm">
|
||||||
|
mKCP AES-128-GCM</a-select-option>
|
||||||
|
<a-select-option v-if="inbound.stream.network === 'kcp'"
|
||||||
|
value="header-dns">
|
||||||
|
Header DNS</a-select-option>
|
||||||
|
<a-select-option v-if="inbound.stream.network === 'kcp'"
|
||||||
|
value="header-dtls">
|
||||||
|
Header DTLS 1.2</a-select-option>
|
||||||
|
<a-select-option v-if="inbound.stream.network === 'kcp'"
|
||||||
|
value="header-srtp">
|
||||||
|
Header SRTP</a-select-option>
|
||||||
|
<a-select-option v-if="inbound.stream.network === 'kcp'"
|
||||||
|
value="header-utp">
|
||||||
|
Header uTP</a-select-option>
|
||||||
|
<a-select-option v-if="inbound.stream.network === 'kcp'"
|
||||||
|
value="header-wechat">
|
||||||
|
Header WeChat Video</a-select-option>
|
||||||
|
<a-select-option v-if="inbound.stream.network === 'kcp'"
|
||||||
|
value="header-wireguard">
|
||||||
|
Header WireGuard</a-select-option>
|
||||||
|
<a-select-option v-if="inbound.stream.network === 'kcp'"
|
||||||
|
value="mkcp-original">
|
||||||
|
mKCP Original</a-select-option>
|
||||||
|
<!-- xDNS for TCP/WS/HTTPUpgrade/XHTTP -->
|
||||||
|
<a-select-option
|
||||||
|
v-if="['tcp', 'ws', 'httpupgrade', 'xhttp'].includes(inbound.stream.network)"
|
||||||
|
value="xdns">
|
||||||
|
xDNS (Experimental)</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<!-- Settings for password-based masks -->
|
||||||
|
<a-form-item label='Password'
|
||||||
|
v-if="['mkcp-aes128gcm'].includes(mask.type)">
|
||||||
|
<a-input v-model.trim="mask.settings.password"
|
||||||
|
placeholder="Obfuscation password"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<!-- Settings for domain-based masks -->
|
||||||
|
<a-form-item label='Domain'
|
||||||
|
v-if="['header-dns', 'xdns'].includes(mask.type)">
|
||||||
|
<a-input v-model.trim="mask.settings.domain"
|
||||||
|
placeholder="e.g., www.example.com"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
|
</a-form>
|
||||||
|
{{end}}
|
||||||
|
|
@ -1,48 +1,32 @@
|
||||||
{{define "form/streamKCP"}}
|
{{define "form/streamKCP"}}
|
||||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
<a-form :colon="false" :label-col="{ md: {span:8} }"
|
||||||
<a-form-item label='{{ i18n "camouflage" }}'>
|
:wrapper-col="{ md: {span:14} }">
|
||||||
<a-select v-model="inbound.stream.kcp.type" :style="{ width: '50%' }" :dropdown-class-name="themeSwitcher.currentTheme">
|
|
||||||
<a-select-option value="none">None</a-select-option>
|
|
||||||
<a-select-option value="srtp">SRTP</a-select-option>
|
|
||||||
<a-select-option value="utp">uTP</a-select-option>
|
|
||||||
<a-select-option value="wechat-video">WeChat</a-select-option>
|
|
||||||
<a-select-option value="dtls">DTLS 1.2</a-select-option>
|
|
||||||
<a-select-option value="wireguard">WireGuard</a-select-option>
|
|
||||||
<a-select-option value="dns">DNS</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
|
||||||
<template slot="label">
|
|
||||||
<a-tooltip>
|
|
||||||
<template slot="title">
|
|
||||||
<span>{{ i18n "reset" }}</span>
|
|
||||||
</template>
|
|
||||||
{{ i18n "password" }}
|
|
||||||
<a-icon @click="inbound.stream.kcp.seed = RandomUtil.randomSeq(10)"type="sync"> </a-icon>
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
<a-input v-model.trim="inbound.stream.kcp.seed"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label='MTU'>
|
<a-form-item label='MTU'>
|
||||||
<a-input-number v-model.number="inbound.stream.kcp.mtu" :min="576" :max="1460"></a-input-number>
|
<a-input-number v-model.number="inbound.stream.kcp.mtu" :min="576"
|
||||||
|
:max="1460"></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='TTI (ms)'>
|
<a-form-item label='TTI (ms)'>
|
||||||
<a-input-number v-model.number="inbound.stream.kcp.tti" :min="10" :max="100"></a-input-number>
|
<a-input-number v-model.number="inbound.stream.kcp.tti" :min="10"
|
||||||
|
:max="100"></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Uplink (MB/s)'>
|
<a-form-item label='Uplink (MB/s)'>
|
||||||
<a-input-number v-model.number="inbound.stream.kcp.upCap" :min="0"></a-input-number>
|
<a-input-number v-model.number="inbound.stream.kcp.upCap"
|
||||||
</a-form-item>
|
:min="0"></a-input-number>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item label='Downlink (MB/s)'>
|
<a-form-item label='Downlink (MB/s)'>
|
||||||
<a-input-number v-model.number="inbound.stream.kcp.downCap" :min="0"></a-input-number>
|
<a-input-number v-model.number="inbound.stream.kcp.downCap"
|
||||||
|
:min="0"></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Congestion'>
|
<a-form-item label='Congestion'>
|
||||||
<a-switch v-model="inbound.stream.kcp.congestion"></a-switch>
|
<a-switch v-model="inbound.stream.kcp.congestion"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Read Buffer (MB)'>
|
<a-form-item label='Read Buffer (MB)'>
|
||||||
<a-input-number v-model.number="inbound.stream.kcp.readBuffer" :min="0"></a-input-number>
|
<a-input-number v-model.number="inbound.stream.kcp.readBuffer"
|
||||||
|
:min="0"></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Write Buffer (MB)'>
|
<a-form-item label='Write Buffer (MB)'>
|
||||||
<a-input-number v-model.number="inbound.stream.kcp.writeBuffer" :min="0"></a-input-number>
|
<a-input-number v-model.number="inbound.stream.kcp.writeBuffer"
|
||||||
|
:min="0"></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
{{define "form/streamSettings"}}
|
{{define "form/streamSettings"}}
|
||||||
<!-- select stream network -->
|
<!-- select stream network -->
|
||||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
<a-form :colon="false" :label-col="{ md: {span:8} }"
|
||||||
|
:wrapper-col="{ md: {span:14} }">
|
||||||
<a-form-item label='{{ i18n "transmission" }}'>
|
<a-form-item label='{{ i18n "transmission" }}'>
|
||||||
<a-select v-model="inbound.stream.network" :style="{ width: '75%' }" @change="streamNetworkChange"
|
<a-select v-model="inbound.stream.network" :style="{ width: '75%' }"
|
||||||
|
@change="streamNetworkChange"
|
||||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select-option value="tcp">TCP (RAW)</a-select-option>
|
<a-select-option value="tcp">TCP (RAW)</a-select-option>
|
||||||
<a-select-option value="kcp">mKCP</a-select-option>
|
<a-select-option value="kcp">mKCP</a-select-option>
|
||||||
|
|
@ -48,4 +50,10 @@
|
||||||
<template>
|
<template>
|
||||||
{{template "form/streamSockopt"}}
|
{{template "form/streamSockopt"}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- finalmask - only for TCP, WS, HTTPUpgrade, XHTTP, mKCP -->
|
||||||
|
<template
|
||||||
|
v-if="['tcp', 'ws', 'httpupgrade', 'xhttp', 'kcp'].includes(inbound.stream.network)">
|
||||||
|
{{template "form/streamFinalMask"}}
|
||||||
|
</template>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{{define "form/streamXHTTP"}}
|
{{define "form/streamXHTTP"}}
|
||||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
<a-form :colon="false" :label-col="{ md: {span:8} }"
|
||||||
|
:wrapper-col="{ md: {span:14} }">
|
||||||
<a-form-item label='{{ i18n "host" }}'>
|
<a-form-item label='{{ i18n "host" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.host"></a-input>
|
<a-input v-model.trim="inbound.stream.xhttp.host"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
@ -7,38 +8,138 @@
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.path"></a-input>
|
<a-input v-model.trim="inbound.stream.xhttp.path"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
|
||||||
<a-button icon="plus" size="small" @click="inbound.stream.xhttp.addHeader('', '')"></a-button>
|
<a-button icon="plus" size="small"
|
||||||
|
@click="inbound.stream.xhttp.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.xhttp.headers">
|
<a-input-group compact
|
||||||
|
v-for="(header, index) in inbound.stream.xhttp.headers">
|
||||||
<a-input :style="{ width: '50%' }" v-model.trim="header.name"
|
<a-input :style="{ width: '50%' }" v-model.trim="header.name"
|
||||||
placeholder='{{ i18n "pages.inbounds.stream.general.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" }}'>
|
||||||
<a-button icon="minus" slot="addonAfter" size="small" @click="inbound.stream.xhttp.removeHeader(index)"></a-button>
|
<a-button icon="minus" slot="addonAfter" size="small"
|
||||||
|
@click="inbound.stream.xhttp.removeHeader(index)"></a-button>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-input-group>
|
</a-input-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Mode'>
|
<a-form-item label='Mode'>
|
||||||
<a-select v-model="inbound.stream.xhttp.mode" :style="{ width: '50%' }"
|
<a-select v-model="inbound.stream.xhttp.mode" :style="{ width: '50%' }"
|
||||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key
|
||||||
|
]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Max Buffered Upload" v-if="inbound.stream.xhttp.mode === 'packet-up'">
|
<a-form-item label="Max Buffered Upload"
|
||||||
<a-input-number v-model.number="inbound.stream.xhttp.scMaxBufferedPosts"></a-input-number>
|
v-if="inbound.stream.xhttp.mode === 'packet-up'">
|
||||||
|
<a-input-number
|
||||||
|
v-model.number="inbound.stream.xhttp.scMaxBufferedPosts"></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Max Upload Size (Byte)" v-if="inbound.stream.xhttp.mode === 'packet-up'">
|
<a-form-item label="Max Upload Size (Byte)"
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input>
|
v-if="inbound.stream.xhttp.mode === 'packet-up'">
|
||||||
|
<a-input
|
||||||
|
v-model.trim="inbound.stream.xhttp.scMaxEachPostBytes"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Stream-Up Server" v-if="inbound.stream.xhttp.mode === 'stream-up'">
|
<a-form-item label="Stream-Up Server"
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.scStreamUpServerSecs"></a-input>
|
v-if="inbound.stream.xhttp.mode === 'stream-up'">
|
||||||
|
<a-input
|
||||||
|
v-model.trim="inbound.stream.xhttp.scStreamUpServerSecs"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Padding Bytes">
|
<a-form-item label="Padding Bytes">
|
||||||
<a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input>
|
<a-input v-model.trim="inbound.stream.xhttp.xPaddingBytes"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="Padding Obfs Mode">
|
||||||
|
<a-switch v-model="inbound.stream.xhttp.xPaddingObfsMode"></a-switch>
|
||||||
|
</a-form-item>
|
||||||
|
<template v-if="inbound.stream.xhttp.xPaddingObfsMode">
|
||||||
|
<a-form-item label="Padding Key">
|
||||||
|
<a-input v-model.trim="inbound.stream.xhttp.xPaddingKey"
|
||||||
|
placeholder="x_padding"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Padding Header">
|
||||||
|
<a-input v-model.trim="inbound.stream.xhttp.xPaddingHeader"
|
||||||
|
placeholder="X-Padding"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Padding Placement">
|
||||||
|
<a-select v-model="inbound.stream.xhttp.xPaddingPlacement"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value>Default (queryInHeader)</a-select-option>
|
||||||
|
<a-select-option
|
||||||
|
value="queryInHeader">queryInHeader</a-select-option>
|
||||||
|
<a-select-option value="header">header</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Padding Method">
|
||||||
|
<a-select v-model="inbound.stream.xhttp.xPaddingMethod"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value>Default (repeat-x)</a-select-option>
|
||||||
|
<a-select-option value="repeat-x">repeat-x</a-select-option>
|
||||||
|
<a-select-option value="tokenish">tokenish</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
|
<a-form-item label="Uplink HTTP Method">
|
||||||
|
<a-select v-model="inbound.stream.xhttp.uplinkHTTPMethod"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value>Default (POST)</a-select-option>
|
||||||
|
<a-select-option value="POST">POST</a-select-option>
|
||||||
|
<a-select-option value="PUT">PUT</a-select-option>
|
||||||
|
<a-select-option value="GET">GET (packet-up only)</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Session Placement">
|
||||||
|
<a-select v-model="inbound.stream.xhttp.sessionPlacement"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value>Default (path)</a-select-option>
|
||||||
|
<a-select-option value="path">path</a-select-option>
|
||||||
|
<a-select-option value="header">header</a-select-option>
|
||||||
|
<a-select-option value="cookie">cookie</a-select-option>
|
||||||
|
<a-select-option value="query">query</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Session Key"
|
||||||
|
v-if="inbound.stream.xhttp.sessionPlacement && inbound.stream.xhttp.sessionPlacement !== 'path'">
|
||||||
|
<a-input v-model.trim="inbound.stream.xhttp.sessionKey"
|
||||||
|
placeholder="x_session"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Sequence Placement">
|
||||||
|
<a-select v-model="inbound.stream.xhttp.seqPlacement"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value>Default (path)</a-select-option>
|
||||||
|
<a-select-option value="path">path</a-select-option>
|
||||||
|
<a-select-option value="header">header</a-select-option>
|
||||||
|
<a-select-option value="cookie">cookie</a-select-option>
|
||||||
|
<a-select-option value="query">query</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Sequence Key"
|
||||||
|
v-if="inbound.stream.xhttp.seqPlacement && inbound.stream.xhttp.seqPlacement !== 'path'">
|
||||||
|
<a-input v-model.trim="inbound.stream.xhttp.seqKey"
|
||||||
|
placeholder="x_seq"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Uplink Data Placement"
|
||||||
|
v-if="inbound.stream.xhttp.mode === 'packet-up'">
|
||||||
|
<a-select v-model="inbound.stream.xhttp.uplinkDataPlacement"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value>Default (body)</a-select-option>
|
||||||
|
<a-select-option value="body">body</a-select-option>
|
||||||
|
<a-select-option value="header">header</a-select-option>
|
||||||
|
<a-select-option value="query">query</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Uplink Data Key"
|
||||||
|
v-if="inbound.stream.xhttp.mode === 'packet-up' && inbound.stream.xhttp.uplinkDataPlacement && inbound.stream.xhttp.uplinkDataPlacement !== 'body'">
|
||||||
|
<a-input v-model.trim="inbound.stream.xhttp.uplinkDataKey"
|
||||||
|
placeholder="x_data"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Uplink Chunk Size"
|
||||||
|
v-if="inbound.stream.xhttp.mode === 'packet-up' && inbound.stream.xhttp.uplinkDataPlacement && inbound.stream.xhttp.uplinkDataPlacement !== 'body'">
|
||||||
|
<a-input-number v-model.number="inbound.stream.xhttp.uplinkChunkSize"
|
||||||
|
:min="0" placeholder="0 (unlimited)"></a-input-number>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item label="No SSE Header">
|
<a-form-item label="No SSE Header">
|
||||||
<a-switch v-model="inbound.stream.xhttp.noSSEHeader"></a-switch>
|
<a-switch v-model="inbound.stream.xhttp.noSSEHeader"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
{{define "form/tlsSettings"}}
|
{{define "form/tlsSettings"}}
|
||||||
<!-- tls enable -->
|
<!-- tls enable -->
|
||||||
<a-form v-if="inbound.canEnableTls()" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
<a-form v-if="inbound.canEnableTls()" :colon="false"
|
||||||
|
:label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||||
<a-divider :style="{ margin: '3px 0' }"></a-divider>
|
<a-divider :style="{ margin: '3px 0' }"></a-divider>
|
||||||
<a-form-item label='{{ i18n "security" }}'>
|
<a-form-item label='{{ i18n "security" }}'>
|
||||||
<a-radio-group v-model="inbound.stream.security" button-style="solid">
|
<a-radio-group v-model="inbound.stream.security" button-style="solid">
|
||||||
<a-radio-button value="none">{{ i18n "none" }}</a-radio-button>
|
<a-radio-button value="none">{{ i18n "none" }}</a-radio-button>
|
||||||
<a-radio-button v-if="inbound.canEnableReality()" value="reality">Reality</a-radio-button>
|
<a-radio-button v-if="inbound.canEnableReality()"
|
||||||
|
value="reality">Reality</a-radio-button>
|
||||||
<a-radio-button value="tls">TLS</a-radio-button>
|
<a-radio-button value="tls">TLS</a-radio-button>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
@ -16,33 +18,44 @@
|
||||||
<a-input v-model.trim="inbound.stream.tls.sni"></a-input>
|
<a-input v-model.trim="inbound.stream.tls.sni"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Cipher Suites">
|
<a-form-item label="Cipher Suites">
|
||||||
<a-select v-model="inbound.stream.tls.cipherSuites" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select v-model="inbound.stream.tls.cipherSuites"
|
||||||
<a-select-option value="">Auto</a-select-option>
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select-option v-for="key,value in TLS_CIPHER_OPTION" :value="key">[[ value ]]</a-select-option>
|
<a-select-option value>Auto</a-select-option>
|
||||||
|
<a-select-option v-for="key,value in TLS_CIPHER_OPTION" :value="key">[[
|
||||||
|
value ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</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" :style="{ width: '50%' }"
|
<a-select v-model="inbound.stream.tls.minVersion"
|
||||||
|
:style="{ width: '50%' }"
|
||||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
: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" :style="{ width: '50%' }"
|
<a-select v-model="inbound.stream.tls.maxVersion"
|
||||||
|
:style="{ width: '50%' }"
|
||||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
: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>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="uTLS">
|
<a-form-item label="uTLS">
|
||||||
<a-select v-model="inbound.stream.tls.settings.fingerprint" :style="{ width: '100%' }"
|
<a-select v-model="inbound.stream.tls.settings.fingerprint"
|
||||||
|
:style="{ width: '100%' }"
|
||||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select-option value=''>None</a-select-option>
|
<a-select-option value>None</a-select-option>
|
||||||
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key
|
||||||
|
]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="ALPN">
|
<a-form-item label="ALPN">
|
||||||
<a-select mode="multiple" :dropdown-class-name="themeSwitcher.currentTheme" v-model="inbound.stream.tls.alpn">
|
<a-select mode="multiple"
|
||||||
<a-select-option v-for="alpn in ALPN_OPTION" :value="alpn">[[ alpn ]]</a-select-option>
|
:dropdown-class-name="themeSwitcher.currentTheme"
|
||||||
|
v-model="inbound.stream.tls.alpn">
|
||||||
|
<a-select-option v-for="alpn in ALPN_OPTION" :value="alpn">[[ alpn
|
||||||
|
]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Allow Insecure">
|
<a-form-item label="Allow Insecure">
|
||||||
|
|
@ -57,21 +70,34 @@
|
||||||
<a-form-item label="Session Resumption">
|
<a-form-item label="Session Resumption">
|
||||||
<a-switch v-model="inbound.stream.tls.enableSessionResumption"></a-switch>
|
<a-switch v-model="inbound.stream.tls.enableSessionResumption"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="verifyPeerCertByName">
|
<a-form-item label="verifyPeerCertByNames">
|
||||||
<a-input v-model.trim="inbound.stream.tls.verifyPeerCertByName"></a-input>
|
<a-input v-model.trim="inbound.stream.tls.verifyPeerCertByNames"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="pinned Peer Cert Sha256">
|
||||||
|
<a-select mode="tags" v-model="inbound.stream.tls.pinnedPeerCertSha256"
|
||||||
|
:dropdown-class-name="themeSwitcher.currentTheme"
|
||||||
|
placeholder="Enter SHA256 fingerprints (base64)">
|
||||||
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-divider :style="{ margin: '3px 0' }"></a-divider>
|
<a-divider :style="{ margin: '3px 0' }"></a-divider>
|
||||||
<template v-for="cert,index in inbound.stream.tls.certs">
|
<template v-for="cert,index in inbound.stream.tls.certs">
|
||||||
<a-form-item label='{{ i18n "certificate" }}'>
|
<a-form-item label='{{ i18n "certificate" }}'>
|
||||||
<a-radio-group v-model="cert.useFile" button-style="solid" :style="{ display: 'inline-flex', whiteSpace: 'nowrap', maxWidth: '100%' }">
|
<a-radio-group v-model="cert.useFile" button-style="solid"
|
||||||
<a-radio-button :value="true" :style="{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }">{{ i18n "pages.inbounds.certificatePath" }}</a-radio-button>
|
:style="{ display: 'inline-flex', whiteSpace: 'nowrap', maxWidth: '100%' }">
|
||||||
<a-radio-button :value="false" :style="{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }">{{ i18n "pages.inbounds.certificateContent" }}</a-radio-button>
|
<a-radio-button :value="true"
|
||||||
|
:style="{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }">{{
|
||||||
|
i18n "pages.inbounds.certificatePath" }}</a-radio-button>
|
||||||
|
<a-radio-button :value="false"
|
||||||
|
:style="{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }">{{
|
||||||
|
i18n "pages.inbounds.certificateContent" }}</a-radio-button>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label=" ">
|
<a-form-item label=" ">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button icon="plus" v-if="index === 0" type="primary" size="small" @click="inbound.stream.tls.addCert()"></a-button>
|
<a-button icon="plus" v-if="index === 0" type="primary" size="small"
|
||||||
<a-button icon="minus" v-if="inbound.stream.tls.certs.length>1" type="primary" size="small"
|
@click="inbound.stream.tls.addCert()"></a-button>
|
||||||
|
<a-button icon="minus" v-if="inbound.stream.tls.certs.length>1"
|
||||||
|
type="primary" size="small"
|
||||||
@click="inbound.stream.tls.removeCert(index)"></a-button>
|
@click="inbound.stream.tls.removeCert(index)"></a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
@ -83,7 +109,8 @@
|
||||||
<a-input v-model.trim="cert.keyFile"></a-input>
|
<a-input v-model.trim="cert.keyFile"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label=" ">
|
<a-form-item label=" ">
|
||||||
<a-button type="primary" icon="import" @click="setDefaultCertData(index)">
|
<a-button type="primary" icon="import"
|
||||||
|
@click="setDefaultCertData(index)">
|
||||||
{{ i18n "pages.inbounds.setDefaultCert" }}</a-button>
|
{{ i18n "pages.inbounds.setDefaultCert" }}</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -99,8 +126,10 @@
|
||||||
<a-switch v-model="cert.oneTimeLoading"></a-switch>
|
<a-switch v-model="cert.oneTimeLoading"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='Usage Option'>
|
<a-form-item label='Usage Option'>
|
||||||
<a-select v-model="cert.usage" :style="{ width: '50%' }" :dropdown-class-name="themeSwitcher.currentTheme">
|
<a-select v-model="cert.usage" :style="{ width: '50%' }"
|
||||||
<a-select-option v-for="key in USAGE_OPTION" :value="key">[[ key ]]</a-select-option>
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option v-for="key in USAGE_OPTION" :value="key">[[ key
|
||||||
|
]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Build Chain" v-if="cert.usage === 'issue'">
|
<a-form-item label="Build Chain" v-if="cert.usage === 'issue'">
|
||||||
|
|
@ -108,20 +137,22 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
<a-form-item label='ECH key'>
|
<a-form-item label='ECH key'>
|
||||||
<a-input v-model="inbound.stream.tls.echServerKeys"></a-input>
|
<a-input v-model="inbound.stream.tls.echServerKeys"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='ECH config'>
|
<a-form-item label='ECH config'>
|
||||||
<a-input v-model="inbound.stream.tls.settings.echConfigList"></a-input>
|
<a-input v-model="inbound.stream.tls.settings.echConfigList"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='ECH force query'>
|
<a-form-item label='ECH force query'>
|
||||||
<a-select v-model="inbound.stream.tls.echForceQuery"
|
<a-select v-model="inbound.stream.tls.echForceQuery"
|
||||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
<a-select-option v-for="key in ['none', 'half', 'full']" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in ['none', 'half', 'full']" :value="key">[[
|
||||||
</a-select>
|
key ]]</a-select-option>
|
||||||
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label=" ">
|
<a-form-item label=" ">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="primary" icon="import" @click="getNewEchCert">Get New ECH Cert</a-button>
|
<a-button type="primary" icon="import" @click="getNewEchCert">Get New
|
||||||
|
ECH Cert</a-button>
|
||||||
<a-button danger @click="clearEchCert">Clear</a-button>
|
<a-button danger @click="clearEchCert">Clear</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
|
||||||
|
|
@ -567,7 +567,7 @@ func (s *ServerService) GetXrayVersions() ([]string, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if major > 26 || (major == 26 && minor > 1) || (major == 26 && minor == 1 && patch >= 18) {
|
if major > 26 || (major == 26 && minor > 1) || (major == 26 && minor == 1 && patch >= 31) {
|
||||||
versions = append(versions, release.TagName)
|
versions = append(versions, release.TagName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue