mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-03-19 17:15:49 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d54e33051 | ||
|
|
01be9fec95 | ||
|
|
0306e75c2a | ||
|
|
255ff9cc20 | ||
|
|
2fbb1ca6c9 | ||
|
|
3b47028060 | ||
|
|
d9ab8b4ce4 | ||
|
|
e6389f3fb3 | ||
|
|
96fd7d0e7c | ||
|
|
cf02f02210 | ||
|
|
4dc8974af0 | ||
|
|
b527a528ea | ||
|
|
1a53af0434 | ||
|
|
be8d55dadb | ||
|
|
d54e7a9b14 | ||
|
|
45c3d730d4 | ||
|
|
aab01ff11a |
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: ''
|
|
||||||
labels: bug
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Version (please complete the following information):**
|
|
||||||
- 3X-UI Version : [e.g. 2.3.5]
|
|
||||||
- Xray Version : [e.g. 1.8.13]
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
||||||
77
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
77
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
name: Bug report
|
||||||
|
description: Create a report to help us improve
|
||||||
|
title: "Bug report"
|
||||||
|
labels: ["bug"]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thank you for reporting a bug! Please fill out the following information.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: A clear and concise description of what the bug is.
|
||||||
|
placeholder: My problem is...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: how-repeat-problem
|
||||||
|
attributes:
|
||||||
|
label: How to repeat the problem?
|
||||||
|
description: Sequence of actions that allow you to reproduce the bug
|
||||||
|
placeholder: |
|
||||||
|
1. Open `Inbounds` page
|
||||||
|
2. ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: expected-action
|
||||||
|
attributes:
|
||||||
|
label: Expected action
|
||||||
|
description: What's going to happen
|
||||||
|
placeholder: Must be...
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: received-action
|
||||||
|
attributes:
|
||||||
|
label: Received action
|
||||||
|
description: What's really happening
|
||||||
|
placeholder: It's actually happening...
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: xui-version
|
||||||
|
attributes:
|
||||||
|
label: 3x-ui Version
|
||||||
|
description: Which version of 3x-ui are you using?
|
||||||
|
placeholder: 2.X.X
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: xray-version
|
||||||
|
attributes:
|
||||||
|
label: Xray-core Version
|
||||||
|
description: Which version of Xray-core are you using?
|
||||||
|
placeholder: 2.X.X
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: Please check all the checkboxes
|
||||||
|
options:
|
||||||
|
- label: This bug report is written entirely in English.
|
||||||
|
required: true
|
||||||
|
- label: This bug report is new and no one has reported it before me.
|
||||||
|
required: true
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: ''
|
|
||||||
labels: enhancement
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
||||||
39
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
39
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: Feature request
|
||||||
|
description: Suggest an idea for this project
|
||||||
|
title: "Feature request"
|
||||||
|
labels: ["enhancement"]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: is-related-problem
|
||||||
|
attributes:
|
||||||
|
label: Is your feature request related to a problem?
|
||||||
|
description: A clear and concise description of what the problem is.
|
||||||
|
placeholder: I'm always frustrated when...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
attributes:
|
||||||
|
label: Describe the solution you'd like
|
||||||
|
description: A clear and concise description of what you want to happen.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
attributes:
|
||||||
|
label: Describe alternatives you've considered
|
||||||
|
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: Please check all the checkboxes
|
||||||
|
options:
|
||||||
|
- label: This feature report is written entirely in English.
|
||||||
|
required: true
|
||||||
10
.github/ISSUE_TEMPLATE/question-.md
vendored
10
.github/ISSUE_TEMPLATE/question-.md
vendored
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
name: 'Question '
|
|
||||||
about: Describe this issue template's purpose here.
|
|
||||||
title: ''
|
|
||||||
labels: question
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
22
.github/ISSUE_TEMPLATE/question.yaml
vendored
Normal file
22
.github/ISSUE_TEMPLATE/question.yaml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: Question
|
||||||
|
description: Describe this issue template's purpose here.
|
||||||
|
title: "Question"
|
||||||
|
labels: ["question"]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: question
|
||||||
|
attributes:
|
||||||
|
label: Question
|
||||||
|
placeholder: I have a question, ..., how can I solve it?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: checklist
|
||||||
|
attributes:
|
||||||
|
label: Checklist
|
||||||
|
description: Please check all the checkboxes
|
||||||
|
options:
|
||||||
|
- label: This question is written entirely in English.
|
||||||
|
required: true
|
||||||
20
.github/pull_request_template.yml
vendored
Normal file
20
.github/pull_request_template.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
## What is the pull request?
|
||||||
|
|
||||||
|
<!-- Briefly describe the changes introduced by this pull request -->
|
||||||
|
|
||||||
|
## Which part of the application is affected by the change?
|
||||||
|
|
||||||
|
- [ ] Frontend
|
||||||
|
- [ ] Backend
|
||||||
|
|
||||||
|
## Type of Changes
|
||||||
|
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] New feature
|
||||||
|
- [ ] Refactoring
|
||||||
|
- [ ] Other
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
<!-- Add screenshots to illustrate the changes -->
|
||||||
|
<!-- Remove this section if it is not applicable. -->
|
||||||
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@@ -1,13 +1,17 @@
|
|||||||
name: Release 3X-UI
|
name: Build and Release 3X-UI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
push:
|
push:
|
||||||
tags:
|
pull_request:
|
||||||
- "v*.*.*"
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
platform:
|
platform:
|
||||||
@@ -27,6 +31,7 @@ jobs:
|
|||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -45,7 +50,7 @@ jobs:
|
|||||||
sudo apt install gcc-s390x-linux-gnu
|
sudo apt install gcc-s390x-linux-gnu
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Build x-ui
|
- name: Build 3x-ui
|
||||||
run: |
|
run: |
|
||||||
export CGO_ENABLED=1
|
export CGO_ENABLED=1
|
||||||
export GOOS=linux
|
export GOOS=linux
|
||||||
@@ -83,7 +88,7 @@ jobs:
|
|||||||
cd x-ui/bin
|
cd x-ui/bin
|
||||||
|
|
||||||
# Download dependencies
|
# Download dependencies
|
||||||
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v25.3.31/"
|
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v25.4.30/"
|
||||||
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
|
||||||
@@ -134,6 +139,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload files to GH release
|
- name: Upload files to GH release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event_name == 'release' && github.event.action == 'published'
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ case $1 in
|
|||||||
esac
|
esac
|
||||||
mkdir -p build/bin
|
mkdir -p build/bin
|
||||||
cd build/bin
|
cd build/bin
|
||||||
wget -q "https://github.com/XTLS/Xray-core/releases/download/v25.3.31/Xray-linux-${ARCH}.zip"
|
wget -q "https://github.com/XTLS/Xray-core/releases/download/v25.4.30/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}"
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
|||||||
Para instalar la versión deseada, utiliza el siguiente comando de instalación. Por ejemplo, ver `v1.7.9`:
|
Para instalar la versión deseada, utiliza el siguiente comando de instalación. Por ejemplo, ver `v1.7.9`:
|
||||||
|
|
||||||
```
|
```
|
||||||
VERSION=v1.7.9 && <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||||
```
|
```
|
||||||
|
|
||||||
## Certificado SSL
|
## Certificado SSL
|
||||||
@@ -586,4 +586,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
|
|||||||
|
|
||||||
## Estrellas a lo largo del tiempo
|
## Estrellas a lo largo del tiempo
|
||||||
|
|
||||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
|||||||
Чтобы установить желаемую версию, используйте следующую команду установки. Например, ver `v1.7.9`:
|
Чтобы установить желаемую версию, используйте следующую команду установки. Например, ver `v1.7.9`:
|
||||||
|
|
||||||
```
|
```
|
||||||
VERSION=v1.7.9 && <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||||
```
|
```
|
||||||
|
|
||||||
## SSL Сертификат
|
## SSL Сертификат
|
||||||
@@ -593,4 +593,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
|
|||||||
|
|
||||||
## Число звёзд со временем
|
## Число звёзд со временем
|
||||||
|
|
||||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
|||||||
要安装您想要的版本,请使用以下安装命令。例如,ver `v1.7.9`:
|
要安装您想要的版本,请使用以下安装命令。例如,ver `v1.7.9`:
|
||||||
|
|
||||||
```
|
```
|
||||||
VERSION=v1.7.9 && <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||||
```
|
```
|
||||||
|
|
||||||
### SSL证书
|
### SSL证书
|
||||||
@@ -586,4 +586,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
|
|||||||
|
|
||||||
## Star趋势
|
## Star趋势
|
||||||
|
|
||||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.5.7
|
2.5.8
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
---
|
|
||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
3x-ui:
|
3x-ui:
|
||||||
image: ghcr.io/mhsanaei/3x-ui:latest
|
image: ghcr.io/mhsanaei/3x-ui:latest
|
||||||
|
|||||||
19
go.mod
19
go.mod
@@ -14,11 +14,11 @@ require (
|
|||||||
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.3
|
github.com/shirou/gopsutil/v4 v4.25.3
|
||||||
github.com/valyala/fasthttp v1.60.0
|
github.com/valyala/fasthttp v1.61.0
|
||||||
github.com/xtls/xray-core v1.250306.1-0.20250331123338-ab5d7cf3d2d6
|
github.com/xtls/xray-core v1.250306.1-0.20250430044058-87ab8e512882
|
||||||
go.uber.org/atomic v1.11.0
|
go.uber.org/atomic v1.11.0
|
||||||
golang.org/x/text v0.24.0
|
golang.org/x/text v0.24.0
|
||||||
google.golang.org/grpc v1.71.1
|
google.golang.org/grpc v1.72.0
|
||||||
gorm.io/driver/sqlite v1.5.7
|
gorm.io/driver/sqlite v1.5.7
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
)
|
)
|
||||||
@@ -32,7 +32,7 @@ require (
|
|||||||
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 // indirect
|
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 // indirect
|
||||||
github.com/ebitengine/purego v0.8.2 // indirect
|
github.com/ebitengine/purego v0.8.2 // indirect
|
||||||
github.com/fasthttp/router v1.5.4 // indirect
|
github.com/fasthttp/router v1.5.4 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
@@ -40,7 +40,7 @@ require (
|
|||||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
github.com/google/btree v1.1.3 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 // indirect
|
||||||
github.com/gorilla/context v1.1.2 // indirect
|
github.com/gorilla/context v1.1.2 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/gorilla/sessions v1.4.0 // indirect
|
github.com/gorilla/sessions v1.4.0 // indirect
|
||||||
@@ -61,8 +61,8 @@ require (
|
|||||||
github.com/pires/go-proxyproto v0.8.0 // indirect
|
github.com/pires/go-proxyproto v0.8.0 // 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.5.1 // indirect
|
github.com/quic-go/qpack v0.5.1 // indirect
|
||||||
github.com/quic-go/quic-go v0.50.1 // indirect
|
github.com/quic-go/quic-go v0.51.0 // indirect
|
||||||
github.com/refraction-networking/utls v1.6.7 // indirect
|
github.com/refraction-networking/utls v1.7.1 // indirect
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
github.com/sagernet/sing v0.6.6 // indirect
|
github.com/sagernet/sing v0.6.6 // indirect
|
||||||
@@ -81,11 +81,10 @@ require (
|
|||||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect
|
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||||
go.uber.org/mock v0.5.1 // indirect
|
go.uber.org/mock v0.5.2 // indirect
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||||
golang.org/x/arch v0.16.0 // indirect
|
golang.org/x/arch v0.16.0 // indirect
|
||||||
golang.org/x/crypto v0.37.0 // indirect
|
golang.org/x/crypto v0.37.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
|
||||||
golang.org/x/mod v0.24.0 // indirect
|
golang.org/x/mod v0.24.0 // indirect
|
||||||
golang.org/x/net v0.39.0 // indirect
|
golang.org/x/net v0.39.0 // indirect
|
||||||
golang.org/x/sync v0.13.0 // indirect
|
golang.org/x/sync v0.13.0 // indirect
|
||||||
@@ -97,6 +96,6 @@ require (
|
|||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a // indirect
|
||||||
google.golang.org/protobuf v1.36.6 // indirect
|
google.golang.org/protobuf v1.36.6 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20250403230555-2b1f43f26fbb // indirect
|
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5 // indirect
|
||||||
lukechampine.com/blake3 v1.4.0 // indirect
|
lukechampine.com/blake3 v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
42
go.sum
42
go.sum
@@ -24,8 +24,8 @@ github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z
|
|||||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
github.com/fasthttp/router v1.5.4 h1:oxdThbBwQgsDIYZ3wR1IavsNl6ZS9WdjKukeMikOnC8=
|
github.com/fasthttp/router v1.5.4 h1:oxdThbBwQgsDIYZ3wR1IavsNl6ZS9WdjKukeMikOnC8=
|
||||||
github.com/fasthttp/router v1.5.4/go.mod h1:3/hysWq6cky7dTfzaaEPZGdptwjwx0qzTgFCKEWRjgc=
|
github.com/fasthttp/router v1.5.4/go.mod h1:3/hysWq6cky7dTfzaaEPZGdptwjwx0qzTgFCKEWRjgc=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||||
github.com/gin-contrib/gzip v1.2.3 h1:dAhT722RuEG330ce2agAs75z7yB+NKvX/ZM1r8w0u2U=
|
github.com/gin-contrib/gzip v1.2.3 h1:dAhT722RuEG330ce2agAs75z7yB+NKvX/ZM1r8w0u2U=
|
||||||
@@ -66,8 +66,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
|
|||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4=
|
||||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
||||||
@@ -104,8 +104,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.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU=
|
github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/miekg/dns v1.1.64 h1:wuZgD9wwCE6XMT05UU/mlSko71eRSXEAm2EbjQXLKnQ=
|
github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc=
|
||||||
github.com/miekg/dns v1.1.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
|
github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
|
||||||
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=
|
||||||
@@ -135,10 +135,10 @@ github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4
|
|||||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||||
github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q=
|
github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
|
||||||
github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
|
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||||
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
|
github.com/refraction-networking/utls v1.7.1 h1:dxg+jla3uocgN8HtX+ccwDr68uCBBO3qLrkZUbqkcw0=
|
||||||
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
github.com/refraction-networking/utls v1.7.1/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
@@ -178,8 +178,8 @@ github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF
|
|||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||||
github.com/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.60.0 h1:kBRYS0lOhVJ6V+bYN8PqAHELKHtXqwq9zNMLKx1MBsw=
|
github.com/valyala/fasthttp v1.61.0 h1:VV08V0AfoRaFurP1EWKvQQdPTZHiUzaVoulX1aBDgzU=
|
||||||
github.com/valyala/fasthttp v1.60.0/go.mod h1:iY4kDgV3Gc6EqhRZ8icqcmlG6bqhcDXfuHgTO4FXCvc=
|
github.com/valyala/fasthttp v1.61.0/go.mod h1:wRIV/4cMwUPWnRcDno9hGnYZGh78QzODFfo1LTUhBog=
|
||||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
||||||
@@ -189,8 +189,8 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zd
|
|||||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
|
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
|
||||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
|
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
|
||||||
github.com/xtls/xray-core v1.250306.1-0.20250331123338-ab5d7cf3d2d6 h1:12QXC7rYztOQhq/3ooiHrEc5X98478076aUiIW8mzR8=
|
github.com/xtls/xray-core v1.250306.1-0.20250430044058-87ab8e512882 h1:O/aN4TCrJ+fmaDOBoQhtTRev2hVHIENy2EJ70jQcyEY=
|
||||||
github.com/xtls/xray-core v1.250306.1-0.20250331123338-ab5d7cf3d2d6/go.mod h1:O+FFC64bjnOukaGHPdZ+wqGHTrgPDN+qH0U+YWCzbEo=
|
github.com/xtls/xray-core v1.250306.1-0.20250430044058-87ab8e512882/go.mod h1:v7SYLVSg2wkuP8jo9/0qaJ5zrCQhmUig7bSnUOdMqu0=
|
||||||
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=
|
||||||
@@ -211,16 +211,14 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
|||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||||
go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||||
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||||
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||||
@@ -247,8 +245,8 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uI
|
|||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a h1:GIqLhp/cYUkuGuiT+vJk8vhOP86L4+SP5j8yXgeVpvI=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a h1:GIqLhp/cYUkuGuiT+vJk8vhOP86L4+SP5j8yXgeVpvI=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||||
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
|
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
|
||||||
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -264,8 +262,8 @@ gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I=
|
|||||||
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
gvisor.dev/gvisor v0.0.0-20250403230555-2b1f43f26fbb h1:rOQHoZqzW4aOUPdXb3HpJmJkEUYqASpXKy4W3sUQfYE=
|
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5 h1:sfK5nHuG7lRFZ2FdTT3RimOqWBg8IrVm+/Vko1FVOsk=
|
||||||
gvisor.dev/gvisor v0.0.0-20250403230555-2b1f43f26fbb/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
|
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
|
||||||
lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w=
|
lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w=
|
||||||
lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0=
|
lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0=
|
||||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func (a *SUBController) subs(c *gin.Context) {
|
|||||||
// Add headers
|
// Add headers
|
||||||
c.Writer.Header().Set("Subscription-Userinfo", header)
|
c.Writer.Header().Set("Subscription-Userinfo", header)
|
||||||
c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval)
|
c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval)
|
||||||
c.Writer.Header().Set("Profile-Title", a.subTitle)
|
c.Writer.Header().Set("Profile-Title", "base64:" + base64.StdEncoding.EncodeToString([]byte(a.subTitle)))
|
||||||
|
|
||||||
if a.subEncrypt {
|
if a.subEncrypt {
|
||||||
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
|
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
|
||||||
@@ -119,7 +119,7 @@ func (a *SUBController) subJsons(c *gin.Context) {
|
|||||||
// Add headers
|
// Add headers
|
||||||
c.Writer.Header().Set("Subscription-Userinfo", header)
|
c.Writer.Header().Set("Subscription-Userinfo", header)
|
||||||
c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval)
|
c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval)
|
||||||
c.Writer.Header().Set("Profile-Title", a.subTitle)
|
c.Writer.Header().Set("Profile-Title", "base64:" + base64.StdEncoding.EncodeToString([]byte(a.subTitle)))
|
||||||
|
|
||||||
c.String(200, jsonSub)
|
c.String(200, jsonSub)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ func getLinesNum(filename string) (int, error) {
|
|||||||
func GetTCPCount() (int, error) {
|
func GetTCPCount() (int, error) {
|
||||||
root := HostProc()
|
root := HostProc()
|
||||||
|
|
||||||
tcp4, err := getLinesNum(fmt.Sprintf("%v/net/tcp", root))
|
tcp4, err := safeGetLinesNum(fmt.Sprintf("%v/net/tcp", root))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
tcp6, err := getLinesNum(fmt.Sprintf("%v/net/tcp6", root))
|
tcp6, err := safeGetLinesNum(fmt.Sprintf("%v/net/tcp6", root))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -59,14 +59,23 @@ func GetTCPCount() (int, error) {
|
|||||||
func GetUDPCount() (int, error) {
|
func GetUDPCount() (int, error) {
|
||||||
root := HostProc()
|
root := HostProc()
|
||||||
|
|
||||||
udp4, err := getLinesNum(fmt.Sprintf("%v/net/udp", root))
|
udp4, err := safeGetLinesNum(fmt.Sprintf("%v/net/udp", root))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
udp6, err := getLinesNum(fmt.Sprintf("%v/net/udp6", root))
|
udp6, err := safeGetLinesNum(fmt.Sprintf("%v/net/udp6", root))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return udp4 + udp6, nil
|
return udp4 + udp6, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func safeGetLinesNum(path string) (int, error) {
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
return 0, nil
|
||||||
|
} else if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return getLinesNum(path)
|
||||||
|
}
|
||||||
|
|||||||
2
web/assets/css/custom.min.css
vendored
2
web/assets/css/custom.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -140,8 +140,10 @@ class RandomUtil {
|
|||||||
|
|
||||||
static randomShadowsocksPassword() {
|
static randomShadowsocksPassword() {
|
||||||
const array = new Uint8Array(32);
|
const array = new Uint8Array(32);
|
||||||
|
|
||||||
window.crypto.getRandomValues(array);
|
window.crypto.getRandomValues(array);
|
||||||
return Base64.encode(String.fromCharCode(...array));
|
|
||||||
|
return Base64.alternativeEncode(String.fromCharCode(...array));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,6 +530,12 @@ class Base64 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static alternativeEncode(content) {
|
||||||
|
return window.btoa(
|
||||||
|
content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
static decode(content = "") {
|
static decode(content = "") {
|
||||||
return new TextDecoder()
|
return new TextDecoder()
|
||||||
.decode(
|
.decode(
|
||||||
@@ -807,7 +815,7 @@ const MediaQueryMixin = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FileManager {
|
class FileManager {
|
||||||
static downloadTextFile(content, filename='file.txt', options = { type: "text/plain" }) {
|
static downloadTextFile(content, filename = 'file.txt', options = { type: "text/plain" }) {
|
||||||
let link = window.document.createElement('a');
|
let link = window.document.createElement('a');
|
||||||
|
|
||||||
link.download = filename;
|
link.download = filename;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
{{define "component/themeSwitchTemplateLogin"}}
|
{{define "component/themeSwitchTemplateLogin"}}
|
||||||
<template>
|
<template>
|
||||||
<a-space direction="vertical" :size="10" :style="{ width: '100%' }">
|
<a-space @mousedown="themeSwitcher.animationsOff()" id="change-theme" direction="vertical" :size="10" :style="{ width: '100%' }">
|
||||||
<a-space direction="horizontal" size="small">
|
<a-space direction="horizontal" size="small">
|
||||||
<a-switch size="small" :default-checked="themeSwitcher.isDarkTheme" @change="themeSwitcher.toggleTheme()"></a-switch>
|
<a-switch size="small" :default-checked="themeSwitcher.isDarkTheme" @change="themeSwitcher.toggleTheme()"></a-switch>
|
||||||
<span>{{ i18n "menu.dark" }}</span>
|
<span>{{ i18n "menu.dark" }}</span>
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
/* margin: 20px 0 50px 0;*/
|
/*margin: 20px 0 50px 0;*/
|
||||||
height: 110px;
|
height: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-btn,
|
.ant-form-item-children .ant-btn,
|
||||||
.ant-input {
|
.ant-input {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
@@ -42,7 +42,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 32px;
|
font-size: 2rem;
|
||||||
|
margin-block-end: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title b {
|
.title b {
|
||||||
@@ -57,7 +58,7 @@
|
|||||||
animation: charge 0.5s both;
|
animation: charge 0.5s both;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 2rem;
|
border-radius: 2rem;
|
||||||
padding: 3rem;
|
padding: 4rem 3rem;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@@ -439,12 +440,11 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
padding: 24px;
|
padding: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-section > .ant-btn {
|
.ant-space-item .ant-switch {
|
||||||
width: 36px;
|
margin: 2px 0 4px;
|
||||||
height: 36px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -467,25 +467,25 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-section">
|
|
||||||
<a-popover :overlay-class-name="themeSwitcher.currentTheme" title='{{ i18n "menu.settings" }}' placement="bottomRight" trigger="click">
|
|
||||||
<template slot="content">
|
|
||||||
<a-space direction="vertical" :size="10">
|
|
||||||
<a-theme-switch-login></a-theme-switch-login>
|
|
||||||
<span>{{ i18n "pages.settings.language" }}</span>
|
|
||||||
<a-select ref="selectLang" :style="{ width: '100%' }" v-model="lang" @change="LanguageManager.setLanguage(lang)" :dropdown-class-name="themeSwitcher.currentTheme">
|
|
||||||
<a-select-option :value="l.value" label="English" v-for="l in LanguageManager.supportedLanguages">
|
|
||||||
<span role="img" aria-label="l.name" v-text="l.icon"></span>
|
|
||||||
<span v-text="l.name"></span>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
<a-button shape="circle" icon="setting"></a-button>
|
|
||||||
</a-popover>
|
|
||||||
</div>
|
|
||||||
<a-row type="flex" justify="center" align="middle" :style="{ height: '100%', overflow: 'auto', overflowX: 'hidden' }">
|
<a-row type="flex" justify="center" align="middle" :style="{ height: '100%', overflow: 'auto', overflowX: 'hidden' }">
|
||||||
<a-col :xs="22" :sm="20" :md="14" :lg="10" :xl="8" :xxl="6" id="login" :style="{ margin: '3rem 0' }">
|
<a-col :xs="22" :sm="12" :md="10" :lg="8" :xl="6" :xxl="5" id="login" :style="{ margin: '3rem 0' }">
|
||||||
|
<div class="setting-section">
|
||||||
|
<a-popover :overlay-class-name="themeSwitcher.currentTheme" title='{{ i18n "menu.settings" }}' placement="bottomRight" trigger="click">
|
||||||
|
<template slot="content">
|
||||||
|
<a-space direction="vertical" :size="10">
|
||||||
|
<a-theme-switch-login></a-theme-switch-login>
|
||||||
|
<span>{{ i18n "pages.settings.language" }}</span>
|
||||||
|
<a-select ref="selectLang" :style="{ width: '100%' }" v-model="lang" @change="LanguageManager.setLanguage(lang)" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option :value="l.value" label="English" v-for="l in LanguageManager.supportedLanguages">
|
||||||
|
<span role="img" aria-label="l.name" v-text="l.icon"></span>
|
||||||
|
<span v-text="l.name"></span>
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
<a-button shape="circle" icon="setting"></a-button>
|
||||||
|
</a-popover>
|
||||||
|
</div>
|
||||||
<a-row type="flex" justify="center">
|
<a-row type="flex" justify="center">
|
||||||
<a-col :style="{ width: '100%' }">
|
<a-col :style="{ width: '100%' }">
|
||||||
<h2 class="title headline zoom">
|
<h2 class="title headline zoom">
|
||||||
@@ -503,25 +503,24 @@
|
|||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-input autocomplete="username" name="username" v-model.trim="user.username"
|
<a-input autocomplete="username" name="username" v-model.trim="user.username"
|
||||||
placeholder='{{ i18n "username" }}' @keydown.enter.native="login" autofocus>
|
placeholder='{{ i18n "username" }}' @keydown.enter.native="login" autofocus>
|
||||||
<a-icon slot="prefix" type="user" :style="{ fontSize: '16px' }"></a-icon>
|
<a-icon slot="prefix" type="user" :style="{ fontSize: '1rem' }"></a-icon>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-input-password autocomplete="password" name="password" icon="lock" v-model.trim="user.password"
|
<a-input-password autocomplete="password" name="password" v-model.trim="user.password"
|
||||||
placeholder='{{ i18n "password" }}' @keydown.enter.native="login">
|
placeholder='{{ i18n "password" }}' @keydown.enter.native="login">
|
||||||
<a-icon slot="prefix" type="lock" :style="{ fontSize: '16px' }"></a-icon>
|
<a-icon slot="prefix" type="lock" :style="{ fontSize: '1rem' }"></a-icon>
|
||||||
</a-input-password>
|
</a-input-password>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="secretEnable">
|
<a-form-item v-if="secretEnable">
|
||||||
<a-input-password autocomplete="secret" name="secret" icon="lock" v-model.trim="user.loginSecret"
|
<a-input-password autocomplete="secret" name="secret" v-model.trim="user.loginSecret"
|
||||||
placeholder='{{ i18n "secretToken" }}' @keydown.enter.native="login">
|
placeholder='{{ i18n "secretToken" }}' @keydown.enter.native="login">
|
||||||
<a-icon slot="prefix" type="key" :style="{ fontSize: '16px' }"></a-icon>
|
<a-icon slot="prefix" type="key" :style="{ fontSize: '1rem' }"></a-icon>
|
||||||
</a-input-password>
|
</a-input-password>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-row justify="center" class="centered">
|
<a-row justify="center" class="centered">
|
||||||
<div :style="{ height: '50px', marginTop: '16px' }" class="wave-btn-bg wave-btn-bg-cl"
|
<div :style="{ height: '50px', marginTop: '1rem', ...loading ? { width: '52px' } : { display: 'inline-block' } }" class="wave-btn-bg wave-btn-bg-cl">
|
||||||
:style="loading ? { width: '52px' } : { display: 'inline-block' }">
|
|
||||||
<a-button class="ant-btn-primary-login" type="primary" :loading="loading" @click="login"
|
<a-button class="ant-btn-primary-login" type="primary" :loading="loading" @click="login"
|
||||||
:icon="loading ? 'poweroff' : undefined">
|
:icon="loading ? 'poweroff' : undefined">
|
||||||
[[ loading ? '' : '{{ i18n "login" }}' ]]
|
[[ loading ? '' : '{{ i18n "login" }}' ]]
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
{{define "modals/qrcodeModal"}}
|
{{define "modals/qrcodeModal"}}
|
||||||
<a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title"
|
<a-modal id="qrcode-modal" v-model="qrModal.visible" :closable="true" :class="themeSwitcher.currentTheme"
|
||||||
:dialog-style="isMobile ? { top: '18px' } : {}"
|
width="fit-content" :dialog-style="isMobile ? { top: '18px' } : {}" :footer="null">
|
||||||
:closable="true"
|
<template #title>
|
||||||
:class="themeSwitcher.currentTheme"
|
<a-space direction="horizontal">
|
||||||
:footer="null" width="fit-content">
|
<span>[[ qrModal.title ]]</span>
|
||||||
|
<a-popover :overlay-class-name="themeSwitcher.currentTheme" trigger="click" placement="bottom">
|
||||||
|
<template slot="content">
|
||||||
|
<a-space direction="vertical">
|
||||||
|
<template v-for="(row, index) in qrModal.qrcodes">
|
||||||
|
<b>[[ row.remark ]]</b>
|
||||||
|
<a-space direction="horizontal">
|
||||||
|
<a-switch size="small" :checked="row.useIPv4" @click="toggleIPv4(index)"></a-switch>
|
||||||
|
<span>{{ i18n "useIPv4ForHost" }}</span>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
<a-icon type="setting"></a-icon>
|
||||||
|
</a-popover>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
<tr-qr-modal class="qr-modal">
|
<tr-qr-modal class="qr-modal">
|
||||||
<template v-if="app.subSettings.enable && qrModal.subId">
|
<template v-if="app.subSettings.enable && qrModal.subId">
|
||||||
<tr-qr-box class="qr-box">
|
<tr-qr-box class="qr-box">
|
||||||
@@ -34,6 +50,53 @@
|
|||||||
</tr-qr-modal>
|
</tr-qr-modal>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.ant-table:not(.ant-table-expanded-row .ant-table) {
|
||||||
|
outline: 1px solid #f0f0f0;
|
||||||
|
outline-offset: -1px;
|
||||||
|
border-radius: 1rem;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QR code transition effects */
|
||||||
|
.qr-cv {
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-transition-enter-active, .qr-transition-leave-active {
|
||||||
|
transition: opacity 0.3s, transform 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-transition-enter, .qr-transition-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-transition-enter-to, .qr-transition-leave {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-flash {
|
||||||
|
animation: qr-flash-animation 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes qr-flash-animation {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const qrModal = {
|
const qrModal = {
|
||||||
title: '',
|
title: '',
|
||||||
@@ -42,31 +105,37 @@
|
|||||||
qrcodes: [],
|
qrcodes: [],
|
||||||
visible: false,
|
visible: false,
|
||||||
subId: '',
|
subId: '',
|
||||||
show: function(title = '', dbInbound, client) {
|
show: function (title = '', dbInbound, client) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.dbInbound = dbInbound;
|
this.dbInbound = dbInbound;
|
||||||
this.inbound = dbInbound.toInbound();
|
this.inbound = dbInbound.toInbound();
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.subId = '';
|
this.subId = '';
|
||||||
this.qrcodes = [];
|
this.qrcodes = [];
|
||||||
|
// Reset the status fetched flag when showing the modal
|
||||||
|
if (qrModalApp) qrModalApp.statusFetched = false;
|
||||||
if (this.inbound.protocol == Protocols.WIREGUARD) {
|
if (this.inbound.protocol == Protocols.WIREGUARD) {
|
||||||
this.inbound.genInboundLinks(dbInbound.remark).split('\r\n').forEach((l, index) => {
|
this.inbound.genInboundLinks(dbInbound.remark).split('\r\n').forEach((l, index) => {
|
||||||
this.qrcodes.push({
|
this.qrcodes.push({
|
||||||
remark: "Peer " + (index + 1),
|
remark: "Peer " + (index + 1),
|
||||||
link: l
|
link: l,
|
||||||
|
useIPv4: false,
|
||||||
|
originalLink: l
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, client).forEach(l => {
|
this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, client).forEach(l => {
|
||||||
this.qrcodes.push({
|
this.qrcodes.push({
|
||||||
remark: l.remark,
|
remark: l.remark,
|
||||||
link: l.link
|
link: l.link,
|
||||||
|
useIPv4: false,
|
||||||
|
originalLink: l.link
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function () {
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -76,8 +145,72 @@
|
|||||||
mixins: [MediaQueryMixin],
|
mixins: [MediaQueryMixin],
|
||||||
data: {
|
data: {
|
||||||
qrModal: qrModal,
|
qrModal: qrModal,
|
||||||
|
serverStatus: null,
|
||||||
|
statusFetched: false,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async getStatus() {
|
||||||
|
try {
|
||||||
|
const msg = await HttpUtil.post('/server/status');
|
||||||
|
if (msg.success) {
|
||||||
|
this.serverStatus = msg.obj;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to get status:", e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleIPv4(index) {
|
||||||
|
const row = qrModal.qrcodes[index];
|
||||||
|
row.useIPv4 = !row.useIPv4;
|
||||||
|
this.updateLink(index);
|
||||||
|
},
|
||||||
|
updateLink(index) {
|
||||||
|
const row = qrModal.qrcodes[index];
|
||||||
|
if (!this.serverStatus || !this.serverStatus.publicIP) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.useIPv4 && this.serverStatus.publicIP.ipv4) {
|
||||||
|
// Replace the hostname or IP in the link with the IPv4 address
|
||||||
|
const originalLink = row.originalLink;
|
||||||
|
const url = new URL(originalLink);
|
||||||
|
const ipv4 = this.serverStatus.publicIP.ipv4;
|
||||||
|
|
||||||
|
if (qrModal.inbound.protocol == Protocols.WIREGUARD) {
|
||||||
|
// Special handling for WireGuard config
|
||||||
|
const endpointRegex = /Endpoint = ([^:]+):(\d+)/;
|
||||||
|
const match = originalLink.match(endpointRegex);
|
||||||
|
if (match) {
|
||||||
|
row.link = originalLink.replace(
|
||||||
|
`Endpoint = ${match[1]}:${match[2]}`,
|
||||||
|
`Endpoint = ${ipv4}:${match[2]}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For other protocols using URL format
|
||||||
|
url.hostname = ipv4;
|
||||||
|
row.link = url.toString();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Restore original link
|
||||||
|
row.link = row.originalLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update QR code with transition effect
|
||||||
|
const canvasElement = document.querySelector('#qrCode-' + index);
|
||||||
|
if (canvasElement) {
|
||||||
|
// Add flash animation class
|
||||||
|
canvasElement.classList.add('qr-flash');
|
||||||
|
|
||||||
|
// Remove the class after animation completes
|
||||||
|
setTimeout(() => {
|
||||||
|
canvasElement.classList.remove('qr-flash');
|
||||||
|
}, 600);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setQrCode("qrCode-" + index, row.link);
|
||||||
|
},
|
||||||
copy(content) {
|
copy(content) {
|
||||||
ClipboardManager
|
ClipboardManager
|
||||||
.copyText(content)
|
.copyText(content)
|
||||||
@@ -117,8 +250,14 @@
|
|||||||
updated() {
|
updated() {
|
||||||
if (this.qrModal.visible) {
|
if (this.qrModal.visible) {
|
||||||
fixOverflow();
|
fixOverflow();
|
||||||
|
if (!this.statusFetched) {
|
||||||
|
this.getStatus();
|
||||||
|
this.statusFetched = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.revertOverflow();
|
this.revertOverflow();
|
||||||
|
// Reset the flag when modal is closed so it will fetch again next time
|
||||||
|
this.statusFetched = false;
|
||||||
}
|
}
|
||||||
if (qrModal.client && qrModal.client.subId) {
|
if (qrModal.client && qrModal.client.subId) {
|
||||||
qrModal.subId = qrModal.client.subId;
|
qrModal.subId = qrModal.client.subId;
|
||||||
@@ -127,6 +266,10 @@
|
|||||||
}
|
}
|
||||||
qrModal.qrcodes.forEach((element, index) => {
|
qrModal.qrcodes.forEach((element, index) => {
|
||||||
this.setQrCode("qrCode-" + index, element.link);
|
this.setQrCode("qrCode-" + index, element.link);
|
||||||
|
// Update links based on current toggle state
|
||||||
|
if (element.useIPv4 && this.serverStatus && this.serverStatus.publicIP) {
|
||||||
|
this.updateLink(index);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -142,8 +285,7 @@
|
|||||||
|
|
||||||
function wrapContentsInMarquee(element) {
|
function wrapContentsInMarquee(element) {
|
||||||
element.classList.add("tr-marquee");
|
element.classList.add("tr-marquee");
|
||||||
element.children[0].style.animation = `move-ltr ${
|
element.children[0].style.animation = `move-ltr ${(element.children[0].clientWidth / element.clientWidth) * 5
|
||||||
(element.children[0].clientWidth / element.clientWidth) * 5
|
|
||||||
}s ease-in-out infinite`;
|
}s ease-in-out infinite`;
|
||||||
const marqueeText = element.children[0];
|
const marqueeText = element.children[0];
|
||||||
if (element.children.length < 2) {
|
if (element.children.length < 2) {
|
||||||
@@ -159,4 +301,4 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -319,19 +319,11 @@
|
|||||||
this.loading(false);
|
this.loading(false);
|
||||||
await this.updateAllSetting();
|
await this.updateAllSetting();
|
||||||
},
|
},
|
||||||
generateRandomString(length) {
|
|
||||||
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
|
||||||
let randomString = "";
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
randomString += chars[Math.floor(Math.random() * chars.length)];
|
|
||||||
}
|
|
||||||
return randomString;
|
|
||||||
},
|
|
||||||
async getNewSecret() {
|
async getNewSecret() {
|
||||||
if (!this.changeSecret) {
|
if (!this.changeSecret) {
|
||||||
this.changeSecret = true;
|
this.changeSecret = true;
|
||||||
this.user.loginSecret = '';
|
this.user.loginSecret = '';
|
||||||
const newSecret = this.generateRandomString(64);
|
const newSecret = RandomUtil.randomSeq(64);
|
||||||
await PromiseUtil.sleep(1000);
|
await PromiseUtil.sleep(1000);
|
||||||
this.user.loginSecret = newSecret;
|
this.user.loginSecret = newSecret;
|
||||||
this.changeSecret = false;
|
this.changeSecret = false;
|
||||||
|
|||||||
@@ -131,7 +131,7 @@
|
|||||||
{{template "modals/fakednsModal"}}
|
{{template "modals/fakednsModal"}}
|
||||||
{{template "modals/warpModal"}}
|
{{template "modals/warpModal"}}
|
||||||
<script>
|
<script>
|
||||||
const rulesColumns = [
|
const rulesColumns = [
|
||||||
{ title: "#", align: 'center', width: 15, scopedSlots: { customRender: 'action' } },
|
{ title: "#", align: 'center', width: 15, scopedSlots: { customRender: 'action' } },
|
||||||
{ title: '{{ i18n "pages.xray.rules.source"}}', children: [
|
{ title: '{{ i18n "pages.xray.rules.source"}}', children: [
|
||||||
{ title: 'IP', dataIndex: "source", align: 'center', width: 20, ellipsis: true },
|
{ title: 'IP', dataIndex: "source", align: 'center', width: 20, ellipsis: true },
|
||||||
@@ -383,47 +383,6 @@
|
|||||||
if(msg.obj.length > 1) Vue.prototype.$message.error(msg.obj);
|
if(msg.obj.length > 1) Vue.prototype.$message.error(msg.obj);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async fetchUserSecret() {
|
|
||||||
this.loading(true);
|
|
||||||
const userMessage = await HttpUtil.post("/panel/setting/getUserSecret", this.user);
|
|
||||||
if (userMessage.success) {
|
|
||||||
this.user = userMessage.obj;
|
|
||||||
}
|
|
||||||
this.loading(false);
|
|
||||||
},
|
|
||||||
async updateSecret() {
|
|
||||||
this.loading(true);
|
|
||||||
const msg = await HttpUtil.post("/panel/setting/updateUserSecret", this.user);
|
|
||||||
if (msg.success) {
|
|
||||||
this.user = msg.obj;
|
|
||||||
window.location.replace(basePath + "logout");
|
|
||||||
}
|
|
||||||
this.loading(false);
|
|
||||||
await this.updateXraySetting();
|
|
||||||
},
|
|
||||||
generateRandomString(length) {
|
|
||||||
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
|
||||||
let randomString = "";
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
randomString += chars[Math.floor(Math.random() * chars.length)];
|
|
||||||
}
|
|
||||||
return randomString;
|
|
||||||
},
|
|
||||||
async getNewSecret() {
|
|
||||||
this.loading(true);
|
|
||||||
await PromiseUtil.sleep(600);
|
|
||||||
const newSecret = this.generateRandomString(64);
|
|
||||||
this.user.loginSecret = newSecret;
|
|
||||||
document.getElementById("token").textContent = newSecret;
|
|
||||||
this.loading(false);
|
|
||||||
},
|
|
||||||
async toggleToken(value) {
|
|
||||||
if (value) {
|
|
||||||
await this.getNewSecret();
|
|
||||||
} else {
|
|
||||||
this.user.loginSecret = "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async resetXrayConfigToDefault() {
|
async resetXrayConfigToDefault() {
|
||||||
this.loading(true);
|
this.loading(true);
|
||||||
const msg = await HttpUtil.get("/panel/setting/getDefaultJsonConfig");
|
const msg = await HttpUtil.get("/panel/setting/getDefaultJsonConfig");
|
||||||
|
|||||||
@@ -1413,6 +1413,16 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
|
|||||||
t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
|
t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
|
||||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.successfulOperation"), tu.ReplyKeyboardRemove())
|
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.successfulOperation"), tu.ReplyKeyboardRemove())
|
||||||
}
|
}
|
||||||
|
case "add_client_submit_enable":
|
||||||
|
client_Enable = true
|
||||||
|
_, err := t.SubmitAddClient()
|
||||||
|
if err != nil {
|
||||||
|
errorMessage := fmt.Sprintf("%v", err)
|
||||||
|
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.error_add_client", "error=="+errorMessage), tu.ReplyKeyboardRemove())
|
||||||
|
} else {
|
||||||
|
t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
|
||||||
|
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.successfulOperation"), tu.ReplyKeyboardRemove())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2216,6 +2226,9 @@ func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) {
|
|||||||
),
|
),
|
||||||
tu.InlineKeyboardRow(
|
tu.InlineKeyboardRow(
|
||||||
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"),
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"),
|
||||||
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitEnable")).WithCallbackData("add_client_submit_enable"),
|
||||||
|
),
|
||||||
|
tu.InlineKeyboardRow(
|
||||||
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"),
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -2239,6 +2252,9 @@ func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) {
|
|||||||
),
|
),
|
||||||
tu.InlineKeyboardRow(
|
tu.InlineKeyboardRow(
|
||||||
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"),
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"),
|
||||||
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitEnable")).WithCallbackData("add_client_submit_enable"),
|
||||||
|
),
|
||||||
|
tu.InlineKeyboardRow(
|
||||||
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"),
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -2262,6 +2278,9 @@ func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) {
|
|||||||
),
|
),
|
||||||
tu.InlineKeyboardRow(
|
tu.InlineKeyboardRow(
|
||||||
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"),
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"),
|
||||||
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitEnable")).WithCallbackData("add_client_submit_enable"),
|
||||||
|
),
|
||||||
|
tu.InlineKeyboardRow(
|
||||||
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"),
|
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "اتنسخ بنجاح"
|
"copySuccess" = "اتنسخ بنجاح"
|
||||||
"sure" = "متأكد؟"
|
"sure" = "متأكد؟"
|
||||||
"encryption" = "تشفير"
|
"encryption" = "تشفير"
|
||||||
|
"useIPv4ForHost" = "استخدم IPv4 للمضيف"
|
||||||
"transmission" = "نقل"
|
"transmission" = "نقل"
|
||||||
"host" = "المستضيف"
|
"host" = "المستضيف"
|
||||||
"path" = "مسار"
|
"path" = "مسار"
|
||||||
@@ -641,13 +642,14 @@
|
|||||||
"getBanLogs" = "احصل على سجلات الحظر"
|
"getBanLogs" = "احصل على سجلات الحظر"
|
||||||
"allClients" = "كل العملاء"
|
"allClients" = "كل العملاء"
|
||||||
|
|
||||||
"addClient" = "أضف عميل"
|
"addClient" = "إضافة عميل"
|
||||||
"submitDisable" = "اعتمد على إنه معطل ✅"
|
"submitDisable" = "إرسال كمعطّل ☑️"
|
||||||
"use_default" = "🏷️ استخدم الافتراضي"
|
"submitEnable" = "إرسال كمفعّل ✅"
|
||||||
"change_id" = "⚙️🔑 تغيير الـ ID"
|
"use_default" = "🏷️ استخدام الإعدادات الافتراضية"
|
||||||
"change_password" = "⚙️🔑 تغيير الباسورد"
|
"change_id" = "⚙️🔑 المعرّف"
|
||||||
"change_email" = "⚙️📧 تغيير الإيميل"
|
"change_password" = "⚙️🔑 كلمة السر"
|
||||||
"change_comment" = "⚙️💬 تغيير التعليق"
|
"change_email" = "⚙️📧 البريد الإلكتروني"
|
||||||
|
"change_comment" = "⚙️💬 تعليق"
|
||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
"successfulOperation" = "✅ العملية نجحت!"
|
"successfulOperation" = "✅ العملية نجحت!"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "Copied Successful"
|
"copySuccess" = "Copied Successful"
|
||||||
"sure" = "Sure"
|
"sure" = "Sure"
|
||||||
"encryption" = "Encryption"
|
"encryption" = "Encryption"
|
||||||
|
"useIPv4ForHost" = "Use IPv4 for host"
|
||||||
"transmission" = "Transmission"
|
"transmission" = "Transmission"
|
||||||
"host" = "Host"
|
"host" = "Host"
|
||||||
"path" = "Path"
|
"path" = "Path"
|
||||||
@@ -642,7 +643,8 @@
|
|||||||
"allClients" = "All Clients"
|
"allClients" = "All Clients"
|
||||||
|
|
||||||
"addClient" = "Add Client"
|
"addClient" = "Add Client"
|
||||||
"submitDisable" = "Submit As Disable ✅"
|
"submitDisable" = "Submit As Disable ☑️"
|
||||||
|
"submitEnable" = "Submit As Enable ✅"
|
||||||
"use_default" = "🏷️ Use default"
|
"use_default" = "🏷️ Use default"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 Password"
|
"change_password" = "⚙️🔑 Password"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "Copiado exitosamente"
|
"copySuccess" = "Copiado exitosamente"
|
||||||
"sure" = "Seguro"
|
"sure" = "Seguro"
|
||||||
"encryption" = "Encriptación"
|
"encryption" = "Encriptación"
|
||||||
|
"useIPv4ForHost" = "Usar IPv4 para el host"
|
||||||
"transmission" = "Transmisión"
|
"transmission" = "Transmisión"
|
||||||
"host" = "Anfitrión"
|
"host" = "Anfitrión"
|
||||||
"path" = "Ruta"
|
"path" = "Ruta"
|
||||||
@@ -644,15 +645,17 @@
|
|||||||
"getBanLogs" = "Registros de prohibición"
|
"getBanLogs" = "Registros de prohibición"
|
||||||
"allClients" = "Todos los Clientes"
|
"allClients" = "Todos los Clientes"
|
||||||
|
|
||||||
"addClient" = "Añadir Cliente"
|
"addClient" = "Añadir cliente"
|
||||||
"submitDisable" = "Enviar como Deshabilitado ✅"
|
"submitDisable" = "Enviar como deshabilitado ☑️"
|
||||||
"use_default" = "🏷️ Usar predeterminado"
|
"submitEnable" = "Enviar como habilitado ✅"
|
||||||
|
"use_default" = "🏷️ Usar por defecto"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 Contraseña"
|
"change_password" = "⚙️🔑 Contraseña"
|
||||||
"change_email" = "⚙️📧 Correo electrónico"
|
"change_email" = "⚙️📧 Correo electrónico"
|
||||||
"change_comment" = "⚙️💬 Comentario"
|
"change_comment" = "⚙️💬 Comentario"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
"successfulOperation" = "✅ ¡Exitosa!"
|
"successfulOperation" = "✅ ¡Exitosa!"
|
||||||
"errorOperation" = "❗ Error en la Operación."
|
"errorOperation" = "❗ Error en la Operación."
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "باموفقیت کپیشد"
|
"copySuccess" = "باموفقیت کپیشد"
|
||||||
"sure" = "مطمئن"
|
"sure" = "مطمئن"
|
||||||
"encryption" = "رمزگذاری"
|
"encryption" = "رمزگذاری"
|
||||||
|
"useIPv4ForHost" = "از IPv4 برای میزبان استفاده کنید"
|
||||||
"transmission" = "راهاتصال"
|
"transmission" = "راهاتصال"
|
||||||
"host" = "آدرس"
|
"host" = "آدرس"
|
||||||
"path" = "مسیر"
|
"path" = "مسیر"
|
||||||
@@ -644,15 +645,15 @@
|
|||||||
"getBanLogs" = "گزارش های بلوک را دریافت کنید"
|
"getBanLogs" = "گزارش های بلوک را دریافت کنید"
|
||||||
"allClients" = "همه مشتریان"
|
"allClients" = "همه مشتریان"
|
||||||
|
|
||||||
"addClient" = "اضافه کردن مشتری"
|
"addClient" = "افزودن مشتری"
|
||||||
"submitDisable" = "ارسال به عنوان غیرفعال ✅"
|
"submitDisable" = "ارسال به عنوان غیرفعال ☑️"
|
||||||
|
"submitEnable" = "ارسال به عنوان فعال ✅"
|
||||||
"use_default" = "🏷️ استفاده از پیشفرض"
|
"use_default" = "🏷️ استفاده از پیشفرض"
|
||||||
"change_id" = "⚙️🔑 شناسه"
|
"change_id" = "⚙️🔑 شناسه"
|
||||||
"change_password" = "⚙️🔑 رمز عبور"
|
"change_password" = "⚙️🔑 گذرواژه"
|
||||||
"change_email" = "⚙️📧 ایمیل"
|
"change_email" = "⚙️📧 ایمیل"
|
||||||
"change_comment" = "⚙️💬 نظر"
|
"change_comment" = "⚙️💬 نظر"
|
||||||
|
|
||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
"successfulOperation" = "✅ انجام شد!"
|
"successfulOperation" = "✅ انجام شد!"
|
||||||
"errorOperation" = "❗ خطا در عملیات."
|
"errorOperation" = "❗ خطا در عملیات."
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "Berhasil Disalin"
|
"copySuccess" = "Berhasil Disalin"
|
||||||
"sure" = "Yakin"
|
"sure" = "Yakin"
|
||||||
"encryption" = "Enkripsi"
|
"encryption" = "Enkripsi"
|
||||||
|
"useIPv4ForHost" = "Gunakan IPv4 untuk host"
|
||||||
"transmission" = "Transmisi"
|
"transmission" = "Transmisi"
|
||||||
"host" = "Host"
|
"host" = "Host"
|
||||||
"path" = "Jalur"
|
"path" = "Jalur"
|
||||||
@@ -645,14 +646,16 @@
|
|||||||
"allClients" = "Semua Klien"
|
"allClients" = "Semua Klien"
|
||||||
|
|
||||||
"addClient" = "Tambah Klien"
|
"addClient" = "Tambah Klien"
|
||||||
"submitDisable" = "Kirim Sebagai Nonaktif ✅"
|
"submitDisable" = "Kirim Sebagai Nonaktif ☑️"
|
||||||
"use_default" = "🏷️ Gunakan default"
|
"submitEnable" = "Kirim Sebagai Aktif ✅"
|
||||||
|
"use_default" = "🏷️ Gunakan Default"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 Kata Sandi"
|
"change_password" = "⚙️🔑 Kata Sandi"
|
||||||
"change_email" = "⚙️📧 Email"
|
"change_email" = "⚙️📧 Email"
|
||||||
"change_comment" = "⚙️💬 Komentar"
|
"change_comment" = "⚙️💬 Komentar"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
"successfulOperation" = "✅ Operasi berhasil!"
|
"successfulOperation" = "✅ Operasi berhasil!"
|
||||||
"errorOperation" = "❗ Kesalahan dalam operasi."
|
"errorOperation" = "❗ Kesalahan dalam operasi."
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "コピー成功"
|
"copySuccess" = "コピー成功"
|
||||||
"sure" = "確定"
|
"sure" = "確定"
|
||||||
"encryption" = "暗号化"
|
"encryption" = "暗号化"
|
||||||
|
"useIPv4ForHost" = "ホストにIPv4を使用"
|
||||||
"transmission" = "伝送"
|
"transmission" = "伝送"
|
||||||
"host" = "ホスト"
|
"host" = "ホスト"
|
||||||
"path" = "パス"
|
"path" = "パス"
|
||||||
@@ -645,14 +646,14 @@
|
|||||||
"allClients" = "すべてのクライアント"
|
"allClients" = "すべてのクライアント"
|
||||||
|
|
||||||
"addClient" = "クライアントを追加"
|
"addClient" = "クライアントを追加"
|
||||||
"submitDisable" = "無効として送信 ✅"
|
"submitDisable" = "無効として送信 ☑️"
|
||||||
|
"submitEnable" = "有効として送信 ✅"
|
||||||
"use_default" = "🏷️ デフォルトを使用"
|
"use_default" = "🏷️ デフォルトを使用"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 パスワード"
|
"change_password" = "⚙️🔑 パスワード"
|
||||||
"change_email" = "⚙️📧 メール"
|
"change_email" = "⚙️📧 メールアドレス"
|
||||||
"change_comment" = "⚙️💬 コメント"
|
"change_comment" = "⚙️💬 コメント"
|
||||||
|
|
||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
"successfulOperation" = "✅ 成功!"
|
"successfulOperation" = "✅ 成功!"
|
||||||
"errorOperation" = "❗ 操作エラー。"
|
"errorOperation" = "❗ 操作エラー。"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "Copiado com Sucesso"
|
"copySuccess" = "Copiado com Sucesso"
|
||||||
"sure" = "Certo"
|
"sure" = "Certo"
|
||||||
"encryption" = "Criptografia"
|
"encryption" = "Criptografia"
|
||||||
|
"useIPv4ForHost" = "Usar IPv4 para o host"
|
||||||
"transmission" = "Transmissão"
|
"transmission" = "Transmissão"
|
||||||
"host" = "Servidor"
|
"host" = "Servidor"
|
||||||
"path" = "Caminho"
|
"path" = "Caminho"
|
||||||
@@ -645,7 +646,8 @@
|
|||||||
"allClients" = "Todos os clientes"
|
"allClients" = "Todos os clientes"
|
||||||
|
|
||||||
"addClient" = "Adicionar Cliente"
|
"addClient" = "Adicionar Cliente"
|
||||||
"submitDisable" = "Enviar como Desativado ✅"
|
"submitDisable" = "Enviar como Desativado ☑️"
|
||||||
|
"submitEnable" = "Enviar como Ativado ✅"
|
||||||
"use_default" = "🏷️ Usar padrão"
|
"use_default" = "🏷️ Usar padrão"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 Senha"
|
"change_password" = "⚙️🔑 Senha"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "Скопировано"
|
"copySuccess" = "Скопировано"
|
||||||
"sure" = "Да"
|
"sure" = "Да"
|
||||||
"encryption" = "Шифрование"
|
"encryption" = "Шифрование"
|
||||||
|
"useIPv4ForHost" = "Использовать IPv4 для хоста"
|
||||||
"transmission" = "Протокол"
|
"transmission" = "Протокол"
|
||||||
"host" = "Хост"
|
"host" = "Хост"
|
||||||
"path" = "Путь"
|
"path" = "Путь"
|
||||||
@@ -645,7 +646,8 @@
|
|||||||
"allClients" = "Все клиенты"
|
"allClients" = "Все клиенты"
|
||||||
|
|
||||||
"addClient" = "Добавить клиента"
|
"addClient" = "Добавить клиента"
|
||||||
"submitDisable" = "Отправить отключенным ✅"
|
"submitDisable" = "Отправить как отключённый ☑️"
|
||||||
|
"submitEnable" = "Отправить как включённый ✅"
|
||||||
"use_default" = "🏷️ Использовать по умолчанию"
|
"use_default" = "🏷️ Использовать по умолчанию"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 Пароль"
|
"change_password" = "⚙️🔑 Пароль"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "Başarıyla Kopyalandı"
|
"copySuccess" = "Başarıyla Kopyalandı"
|
||||||
"sure" = "Emin misiniz"
|
"sure" = "Emin misiniz"
|
||||||
"encryption" = "Şifreleme"
|
"encryption" = "Şifreleme"
|
||||||
|
"useIPv4ForHost" = "Ana bilgisayar için IPv4 kullan"
|
||||||
"transmission" = "İletim"
|
"transmission" = "İletim"
|
||||||
"host" = "Sunucu"
|
"host" = "Sunucu"
|
||||||
"path" = "Yol"
|
"path" = "Yol"
|
||||||
@@ -645,9 +646,10 @@
|
|||||||
"allClients" = "Tüm Müşteriler"
|
"allClients" = "Tüm Müşteriler"
|
||||||
|
|
||||||
"addClient" = "Müşteri Ekle"
|
"addClient" = "Müşteri Ekle"
|
||||||
"submitDisable" = "Devre Dışı Olarak Gönder ✅"
|
"submitDisable" = "Devre Dışı Olarak Gönder ☑️"
|
||||||
|
"submitEnable" = "Etkin Olarak Gönder ✅"
|
||||||
"use_default" = "🏷️ Varsayılanı Kullan"
|
"use_default" = "🏷️ Varsayılanı Kullan"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 Kimlik"
|
||||||
"change_password" = "⚙️🔑 Şifre"
|
"change_password" = "⚙️🔑 Şifre"
|
||||||
"change_email" = "⚙️📧 E-posta"
|
"change_email" = "⚙️📧 E-posta"
|
||||||
"change_comment" = "⚙️💬 Yorum"
|
"change_comment" = "⚙️💬 Yorum"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "Скопійовано успішно"
|
"copySuccess" = "Скопійовано успішно"
|
||||||
"sure" = "Звичайно"
|
"sure" = "Звичайно"
|
||||||
"encryption" = "Шифрування"
|
"encryption" = "Шифрування"
|
||||||
|
"useIPv4ForHost" = "Використовувати IPv4 для хоста"
|
||||||
"transmission" = "Протокол передачи"
|
"transmission" = "Протокол передачи"
|
||||||
"host" = "Хост"
|
"host" = "Хост"
|
||||||
"path" = "Шлях"
|
"path" = "Шлях"
|
||||||
@@ -645,8 +646,9 @@
|
|||||||
"allClients" = "Всі Клієнти"
|
"allClients" = "Всі Клієнти"
|
||||||
|
|
||||||
"addClient" = "Додати клієнта"
|
"addClient" = "Додати клієнта"
|
||||||
"submitDisable" = "Надіслати відключеним ✅"
|
"submitDisable" = "Надіслати як вимкнено ☑️"
|
||||||
"use_default" = "🏷️ Використовувати за замовчуванням"
|
"submitEnable" = "Надіслати як увімкнено ✅"
|
||||||
|
"use_default" = "🏷️ Використати типове"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 Пароль"
|
"change_password" = "⚙️🔑 Пароль"
|
||||||
"change_email" = "⚙️📧 Електронна пошта"
|
"change_email" = "⚙️📧 Електронна пошта"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "Đã sao chép thành công"
|
"copySuccess" = "Đã sao chép thành công"
|
||||||
"sure" = "Chắc chắn"
|
"sure" = "Chắc chắn"
|
||||||
"encryption" = "Mã hóa"
|
"encryption" = "Mã hóa"
|
||||||
|
"useIPv4ForHost" = "Sử dụng IPv4 cho máy chủ"
|
||||||
"transmission" = "Truyền tải"
|
"transmission" = "Truyền tải"
|
||||||
"host" = "Máy chủ"
|
"host" = "Máy chủ"
|
||||||
"path" = "Đường dẫn"
|
"path" = "Đường dẫn"
|
||||||
@@ -645,12 +646,13 @@
|
|||||||
"allClients" = "Tất cả Khách hàng"
|
"allClients" = "Tất cả Khách hàng"
|
||||||
|
|
||||||
"addClient" = "Thêm Khách Hàng"
|
"addClient" = "Thêm Khách Hàng"
|
||||||
"submitDisable" = "Gửi Dưới Dạng Tắt ✅"
|
"submitDisable" = "Gửi Dưới Dạng Vô Hiệu ☑️"
|
||||||
"use_default" = "🏷️ Sử dụng mặc định"
|
"submitEnable" = "Gửi Dưới Dạng Kích Hoạt ✅"
|
||||||
|
"use_default" = "🏷️ Sử Dụng Mặc Định"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 Mật khẩu"
|
"change_password" = "⚙️🔑 Mật Khẩu"
|
||||||
"change_email" = "⚙️📧 Email"
|
"change_email" = "⚙️📧 Email"
|
||||||
"change_comment" = "⚙️💬 Bình luận"
|
"change_comment" = "⚙️💬 Bình Luận"
|
||||||
|
|
||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "复制成功"
|
"copySuccess" = "复制成功"
|
||||||
"sure" = "确定"
|
"sure" = "确定"
|
||||||
"encryption" = "加密"
|
"encryption" = "加密"
|
||||||
|
"useIPv4ForHost" = "使用 IPv4 连接主机"
|
||||||
"transmission" = "传输"
|
"transmission" = "传输"
|
||||||
"host" = "主机"
|
"host" = "主机"
|
||||||
"path" = "路径"
|
"path" = "路径"
|
||||||
@@ -645,7 +646,8 @@
|
|||||||
"allClients" = "所有客户"
|
"allClients" = "所有客户"
|
||||||
|
|
||||||
"addClient" = "添加客户"
|
"addClient" = "添加客户"
|
||||||
"submitDisable" = "提交为禁用 ✅"
|
"submitDisable" = "提交为禁用 ☑️"
|
||||||
|
"submitEnable" = "提交为启用 ✅"
|
||||||
"use_default" = "🏷️ 使用默认"
|
"use_default" = "🏷️ 使用默认"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 密码"
|
"change_password" = "⚙️🔑 密码"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"copySuccess" = "複製成功"
|
"copySuccess" = "複製成功"
|
||||||
"sure" = "確定"
|
"sure" = "確定"
|
||||||
"encryption" = "加密"
|
"encryption" = "加密"
|
||||||
|
"useIPv4ForHost" = "使用 IPv4 連接主機"
|
||||||
"transmission" = "傳輸"
|
"transmission" = "傳輸"
|
||||||
"host" = "主機"
|
"host" = "主機"
|
||||||
"path" = "路徑"
|
"path" = "路徑"
|
||||||
@@ -645,8 +646,9 @@
|
|||||||
"allClients" = "所有客戶"
|
"allClients" = "所有客戶"
|
||||||
|
|
||||||
"addClient" = "新增客戶"
|
"addClient" = "新增客戶"
|
||||||
"submitDisable" = "提交為停用 ✅"
|
"submitDisable" = "以停用方式送出 ☑️"
|
||||||
"use_default" = "🏷️ 使用預設"
|
"submitEnable" = "以啟用方式送出 ✅"
|
||||||
|
"use_default" = "🏷️ 使用預設值"
|
||||||
"change_id" = "⚙️🔑 ID"
|
"change_id" = "⚙️🔑 ID"
|
||||||
"change_password" = "⚙️🔑 密碼"
|
"change_password" = "⚙️🔑 密碼"
|
||||||
"change_email" = "⚙️📧 電子郵件"
|
"change_email" = "⚙️📧 電子郵件"
|
||||||
|
|||||||
Reference in New Issue
Block a user