Compare commits

...

17 Commits

Author SHA1 Message Date
mhsanaei
3d54e33051 v2.5.8 2025-04-30 11:24:06 +02:00
mhsanaei
01be9fec95 Xray Core v25.4.30 2025-04-30 10:56:55 +02:00
mhsanaei
0306e75c2a update dependencies 2025-04-30 10:51:49 +02:00
Павел
255ff9cc20 refactror: add check ipv6 path
fix issues #1669 #2882
2025-04-29 20:32:54 +07:00
Tara Rostami
2fbb1ca6c9 chore: minor fixes for login page 2025-04-27 11:22:43 +07:00
Shishkevich D.
3b47028060 chore: new templates for issues and pull requests (#2935)
* chore: new issue templates

* chore: fixing templates

* chore: add pull request template
also edited bug report

* chore: add checklist for question and feat request template

* chore: remove title prefix

* fix: template title

* fix: re-fixing the template title

* chore: remove checklist for pull request

* chore: remove emojies

* fix: elimination of minor defects
2025-04-23 09:04:36 +02:00
Shishkevich D.
d9ab8b4ce4 fix: qr modal header 2025-04-19 22:43:24 +07:00
Shishkevich D.
e6389f3fb3 chore: move qr params in a-popover 2025-04-19 22:36:17 +07:00
AKILA INDUNIL
96fd7d0e7c feat: add a toggle to use public IPv4 in QR/URI 2025-04-19 22:32:22 +07:00
Pk-web6936
cf02f02210 automatic Build and Release (#2919)
* Update release.yml

* Update release.yml

* Update release.yml
2025-04-18 22:32:38 +02:00
Pk-web6936
4dc8974af0 docs: Update README (#2921)
* Update README.es_ES.md

* Update README.ru_RU.md
2025-04-18 22:31:35 +02:00
006lp
b527a528ea docs: Update README.zh_CN.md (#2920) 2025-04-18 21:16:39 +02:00
Shishkevich D.
1a53af0434 chore: deleting unnecessary functions 2025-04-18 17:55:09 +07:00
nistootsin
be8d55dadb feat: add Submit As Enable in telegram bot 2025-04-16 15:16:55 +07:00
Shishkevich D.
d54e7a9b14 fix: encoding subscription title in base64 2025-04-15 19:29:54 +07:00
Shishkevich D.
45c3d730d4 fix: Error when generating shadowsocks keys in Blake3_AES_256_GCM 2025-04-15 18:33:26 +07:00
Columbiysky
aab01ff11a fix docker-compose.yml: the attribute version is obsolete (#2891) 2025-04-12 08:19:55 +02:00
39 changed files with 499 additions and 241 deletions

View File

@@ -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
View 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

View File

@@ -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.

View 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

View File

@@ -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
View 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
View 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. -->

View File

@@ -1,13 +1,17 @@
name: Release 3X-UI
name: Build and Release 3X-UI
on:
workflow_dispatch:
release:
types: [published]
push:
tags:
- "v*.*.*"
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
permissions:
contents: write
strategy:
matrix:
platform:
@@ -27,6 +31,7 @@ jobs:
uses: actions/setup-go@v5
with:
go-version-file: go.mod
check-latest: true
- name: Install dependencies
run: |
@@ -45,7 +50,7 @@ jobs:
sudo apt install gcc-s390x-linux-gnu
fi
- name: Build x-ui
- name: Build 3x-ui
run: |
export CGO_ENABLED=1
export GOOS=linux
@@ -83,7 +88,7 @@ jobs:
cd x-ui/bin
# 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
wget -q ${Xray_URL}Xray-linux-64.zip
unzip Xray-linux-64.zip
@@ -134,6 +139,7 @@ jobs:
- name: Upload files to GH release
uses: svenstaro/upload-release-action@v2
if: github.event_name == 'release' && github.event.action == 'published'
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}

View File

@@ -27,7 +27,7 @@ case $1 in
esac
mkdir -p 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"
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
mv xray "xray-linux-${FNAME}"

View File

@@ -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`:
```
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
@@ -586,4 +586,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Estrellas a lo largo del tiempo
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)

View File

@@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
Чтобы установить желаемую версию, используйте следующую команду установки. Например, 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 Сертификат
@@ -593,4 +593,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Число звёзд со временем
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)

View File

@@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
要安装您想要的版本请使用以下安装命令。例如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证书
@@ -586,4 +586,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## Star趋势
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)

View File

@@ -1 +1 @@
2.5.7
2.5.8

View File

@@ -1,6 +1,3 @@
---
version: "3"
services:
3x-ui:
image: ghcr.io/mhsanaei/3x-ui:latest

19
go.mod
View File

@@ -14,11 +14,11 @@ require (
github.com/pelletier/go-toml/v2 v2.2.4
github.com/robfig/cron/v3 v3.0.1
github.com/shirou/gopsutil/v4 v4.25.3
github.com/valyala/fasthttp v1.60.0
github.com/xtls/xray-core v1.250306.1-0.20250331123338-ab5d7cf3d2d6
github.com/valyala/fasthttp v1.61.0
github.com/xtls/xray-core v1.250306.1-0.20250430044058-87ab8e512882
go.uber.org/atomic v1.11.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/gorm v1.25.12
)
@@ -32,7 +32,7 @@ require (
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 // indirect
github.com/ebitengine/purego v0.8.2 // 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/go-ole/go-ole v1.3.0 // 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-task/slim-sprig/v3 v3.0.0 // 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/securecookie v1.1.2 // 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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.50.1 // indirect
github.com/refraction-networking/utls v1.6.7 // indirect
github.com/quic-go/quic-go v0.51.0 // indirect
github.com/refraction-networking/utls v1.7.1 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/rogpeppe/go-internal v1.14.1 // 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/yusufpapurcu/wmi v1.2.4 // 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
golang.org/x/arch v0.16.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/net v0.39.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/protobuf v1.36.6 // 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
)

42
go.sum
View File

@@ -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/fasthttp/router v1.5.4 h1:oxdThbBwQgsDIYZ3wR1IavsNl6ZS9WdjKukeMikOnC8=
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.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
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/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
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.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
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-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4=
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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU=
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.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc=
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-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
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/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/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q=
github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/refraction-networking/utls v1.7.1 h1:dxg+jla3uocgN8HtX+ccwDr68uCBBO3qLrkZUbqkcw0=
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/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
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.60.0/go.mod h1:iY4kDgV3Gc6EqhRZ8icqcmlG6bqhcDXfuHgTO4FXCvc=
github.com/valyala/fasthttp v1.61.0 h1:VV08V0AfoRaFurP1EWKvQQdPTZHiUzaVoulX1aBDgzU=
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/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
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/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/xray-core v1.250306.1-0.20250331123338-ab5d7cf3d2d6 h1:12QXC7rYztOQhq/3ooiHrEc5X98478076aUiIW8mzR8=
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 h1:O/aN4TCrJ+fmaDOBoQhtTRev2hVHIENy2EJ70jQcyEY=
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/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
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/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
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.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
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/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
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/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
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/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
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=
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/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
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/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
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/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
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-20250403230555-2b1f43f26fbb/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5 h1:sfK5nHuG7lRFZ2FdTT3RimOqWBg8IrVm+/Vko1FVOsk=
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/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

View File

@@ -85,7 +85,7 @@ func (a *SUBController) subs(c *gin.Context) {
// Add headers
c.Writer.Header().Set("Subscription-Userinfo", header)
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 {
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
@@ -119,7 +119,7 @@ func (a *SUBController) subJsons(c *gin.Context) {
// Add headers
c.Writer.Header().Set("Subscription-Userinfo", header)
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)
}

View File

@@ -44,11 +44,11 @@ func getLinesNum(filename string) (int, error) {
func GetTCPCount() (int, error) {
root := HostProc()
tcp4, err := getLinesNum(fmt.Sprintf("%v/net/tcp", root))
tcp4, err := safeGetLinesNum(fmt.Sprintf("%v/net/tcp", root))
if err != nil {
return 0, err
}
tcp6, err := getLinesNum(fmt.Sprintf("%v/net/tcp6", root))
tcp6, err := safeGetLinesNum(fmt.Sprintf("%v/net/tcp6", root))
if err != nil {
return 0, err
}
@@ -59,14 +59,23 @@ func GetTCPCount() (int, error) {
func GetUDPCount() (int, error) {
root := HostProc()
udp4, err := getLinesNum(fmt.Sprintf("%v/net/udp", root))
udp4, err := safeGetLinesNum(fmt.Sprintf("%v/net/udp", root))
if err != nil {
return 0, err
}
udp6, err := getLinesNum(fmt.Sprintf("%v/net/udp6", root))
udp6, err := safeGetLinesNum(fmt.Sprintf("%v/net/udp6", root))
if err != nil {
return 0, err
}
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)
}

File diff suppressed because one or more lines are too long

View File

@@ -140,8 +140,10 @@ class RandomUtil {
static randomShadowsocksPassword() {
const array = new Uint8Array(32);
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 = "") {
return new TextDecoder()
.decode(
@@ -807,7 +815,7 @@ const MediaQueryMixin = {
}
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');
link.download = filename;

View File

@@ -24,7 +24,7 @@
{{define "component/themeSwitchTemplateLogin"}}
<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-switch size="small" :default-checked="themeSwitcher.isDarkTheme" @change="themeSwitcher.toggleTheme()"></a-switch>
<span>{{ i18n "menu.dark" }}</span>

View File

@@ -9,11 +9,11 @@
h1 {
text-align: center;
/* margin: 20px 0 50px 0;*/
/*margin: 20px 0 50px 0;*/
height: 110px;
}
.ant-btn,
.ant-form-item-children .ant-btn,
.ant-input {
height: 50px;
border-radius: 30px;
@@ -42,7 +42,8 @@
}
.title {
font-size: 32px;
font-size: 2rem;
margin-block-end: 2rem;
}
.title b {
@@ -57,7 +58,7 @@
animation: charge 0.5s both;
background-color: #fff;
border-radius: 2rem;
padding: 3rem;
padding: 4rem 3rem;
transition: all 0.3s;
user-select: none;
-webkit-user-select: none;
@@ -439,12 +440,11 @@
position: absolute;
top: 0;
right: 0;
padding: 24px;
padding: 22px;
}
.setting-section > .ant-btn {
width: 36px;
height: 36px;
.ant-space-item .ant-switch {
margin: 2px 0 4px;
}
</style>
@@ -467,25 +467,25 @@
</g>
</svg>
</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>
&nbsp;&nbsp;<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-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>
&nbsp;&nbsp;<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-col :style="{ width: '100%' }">
<h2 class="title headline zoom">
@@ -503,25 +503,24 @@
<a-form-item>
<a-input autocomplete="username" name="username" v-model.trim="user.username"
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-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">
<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-form-item>
<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">
<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-form-item>
<a-form-item>
<a-row justify="center" class="centered">
<div :style="{ height: '50px', marginTop: '16px' }" class="wave-btn-bg wave-btn-bg-cl"
:style="loading ? { width: '52px' } : { display: 'inline-block' }">
<div :style="{ height: '50px', marginTop: '1rem', ...loading ? { width: '52px' } : { display: 'inline-block' } }" class="wave-btn-bg wave-btn-bg-cl">
<a-button class="ant-btn-primary-login" type="primary" :loading="loading" @click="login"
:icon="loading ? 'poweroff' : undefined">
[[ loading ? '' : '{{ i18n "login" }}' ]]

View File

@@ -1,9 +1,25 @@
{{define "modals/qrcodeModal"}}
<a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title"
:dialog-style="isMobile ? { top: '18px' } : {}"
:closable="true"
:class="themeSwitcher.currentTheme"
:footer="null" width="fit-content">
<a-modal id="qrcode-modal" v-model="qrModal.visible" :closable="true" :class="themeSwitcher.currentTheme"
width="fit-content" :dialog-style="isMobile ? { top: '18px' } : {}" :footer="null">
<template #title>
<a-space direction="horizontal">
<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">
<template v-if="app.subSettings.enable && qrModal.subId">
<tr-qr-box class="qr-box">
@@ -34,6 +50,53 @@
</tr-qr-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>
const qrModal = {
title: '',
@@ -42,31 +105,37 @@
qrcodes: [],
visible: false,
subId: '',
show: function(title = '', dbInbound, client) {
show: function (title = '', dbInbound, client) {
this.title = title;
this.dbInbound = dbInbound;
this.inbound = dbInbound.toInbound();
this.client = client;
this.subId = '';
this.qrcodes = [];
// Reset the status fetched flag when showing the modal
if (qrModalApp) qrModalApp.statusFetched = false;
if (this.inbound.protocol == Protocols.WIREGUARD) {
this.inbound.genInboundLinks(dbInbound.remark).split('\r\n').forEach((l, index) => {
this.qrcodes.push({
remark: "Peer " + (index + 1),
link: l
link: l,
useIPv4: false,
originalLink: l
});
});
} else {
this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, client).forEach(l => {
this.qrcodes.push({
remark: l.remark,
link: l.link
link: l.link,
useIPv4: false,
originalLink: l.link
});
});
}
this.visible = true;
},
close: function() {
close: function () {
this.visible = false;
},
};
@@ -76,8 +145,72 @@
mixins: [MediaQueryMixin],
data: {
qrModal: qrModal,
serverStatus: null,
statusFetched: false,
},
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) {
ClipboardManager
.copyText(content)
@@ -117,8 +250,14 @@
updated() {
if (this.qrModal.visible) {
fixOverflow();
if (!this.statusFetched) {
this.getStatus();
this.statusFetched = true;
}
} else {
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) {
qrModal.subId = qrModal.client.subId;
@@ -127,6 +266,10 @@
}
qrModal.qrcodes.forEach((element, index) => {
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) {
element.classList.add("tr-marquee");
element.children[0].style.animation = `move-ltr ${
(element.children[0].clientWidth / element.clientWidth) * 5
element.children[0].style.animation = `move-ltr ${(element.children[0].clientWidth / element.clientWidth) * 5
}s ease-in-out infinite`;
const marqueeText = element.children[0];
if (element.children.length < 2) {
@@ -159,4 +301,4 @@
});
}
</script>
{{end}}
{{end}}

View File

@@ -319,19 +319,11 @@
this.loading(false);
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() {
if (!this.changeSecret) {
this.changeSecret = true;
this.user.loginSecret = '';
const newSecret = this.generateRandomString(64);
const newSecret = RandomUtil.randomSeq(64);
await PromiseUtil.sleep(1000);
this.user.loginSecret = newSecret;
this.changeSecret = false;

View File

@@ -131,7 +131,7 @@
{{template "modals/fakednsModal"}}
{{template "modals/warpModal"}}
<script>
const rulesColumns = [
const rulesColumns = [
{ title: "#", align: 'center', width: 15, scopedSlots: { customRender: 'action' } },
{ title: '{{ i18n "pages.xray.rules.source"}}', children: [
{ 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);
}
},
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() {
this.loading(true);
const msg = await HttpUtil.get("/panel/setting/getDefaultJsonConfig");

View File

@@ -1413,6 +1413,16 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
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.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"),
),
)
@@ -2239,6 +2252,9 @@ func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) {
),
tu.InlineKeyboardRow(
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"),
),
)
@@ -2262,6 +2278,9 @@ func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) {
),
tu.InlineKeyboardRow(
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"),
),
)

View File

@@ -29,6 +29,7 @@
"copySuccess" = "اتنسخ بنجاح"
"sure" = "متأكد؟"
"encryption" = "تشفير"
"useIPv4ForHost" = "استخدم IPv4 للمضيف"
"transmission" = "نقل"
"host" = "المستضيف"
"path" = "مسار"
@@ -641,13 +642,14 @@
"getBanLogs" = "احصل على سجلات الحظر"
"allClients" = "كل العملاء"
"addClient" = "أضف عميل"
"submitDisable" = "اعتمد على إنه معطل "
"use_default" = "🏷️ استخدم الافتراضي"
"change_id" = "⚙️🔑 تغيير الـ ID"
"change_password" = "⚙️🔑 تغيير الباسورد"
"change_email" = "⚙️📧 تغيير الإيميل"
"change_comment" = "⚙️💬 تغيير التعليق"
"addClient" = "إضافة عميل"
"submitDisable" = "إرسال كمعطّل ☑️"
"submitEnable" = "إرسال كمفعّل ✅"
"use_default" = "🏷️ استخدام الإعدادات الافتراضية"
"change_id" = "⚙️🔑 المعرّف"
"change_password" = "⚙️🔑 كلمة السر"
"change_email" = "⚙️📧 البريد الإلكتروني"
"change_comment" = "⚙️💬 تعليق"
[tgbot.answers]
"successfulOperation" = "✅ العملية نجحت!"

View File

@@ -29,6 +29,7 @@
"copySuccess" = "Copied Successful"
"sure" = "Sure"
"encryption" = "Encryption"
"useIPv4ForHost" = "Use IPv4 for host"
"transmission" = "Transmission"
"host" = "Host"
"path" = "Path"
@@ -642,7 +643,8 @@
"allClients" = "All Clients"
"addClient" = "Add Client"
"submitDisable" = "Submit As Disable "
"submitDisable" = "Submit As Disable ☑️"
"submitEnable" = "Submit As Enable ✅"
"use_default" = "🏷️ Use default"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 Password"

View File

@@ -29,6 +29,7 @@
"copySuccess" = "Copiado exitosamente"
"sure" = "Seguro"
"encryption" = "Encriptación"
"useIPv4ForHost" = "Usar IPv4 para el host"
"transmission" = "Transmisión"
"host" = "Anfitrión"
"path" = "Ruta"
@@ -644,15 +645,17 @@
"getBanLogs" = "Registros de prohibición"
"allClients" = "Todos los Clientes"
"addClient" = "Añadir Cliente"
"submitDisable" = "Enviar como Deshabilitado "
"use_default" = "🏷️ Usar predeterminado"
"addClient" = "Añadir cliente"
"submitDisable" = "Enviar como deshabilitado ☑️"
"submitEnable" = "Enviar como habilitado"
"use_default" = "🏷️ Usar por defecto"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 Contraseña"
"change_email" = "⚙️📧 Correo electrónico"
"change_comment" = "⚙️💬 Comentario"
[tgbot.answers]
"successfulOperation" = "✅ ¡Exitosa!"
"errorOperation" = "❗ Error en la Operación."

View File

@@ -29,6 +29,7 @@
"copySuccess" = "باموفقیت کپی‌شد"
"sure" = "مطمئن"
"encryption" = "رمزگذاری"
"useIPv4ForHost" = "از IPv4 برای میزبان استفاده کنید"
"transmission" = "راه‌اتصال"
"host" = "آدرس"
"path" = "مسیر"
@@ -644,15 +645,15 @@
"getBanLogs" = "گزارش های بلوک را دریافت کنید"
"allClients" = "همه مشتریان"
"addClient" = "اضافه کردن مشتری"
"submitDisable" = "ارسال به عنوان غیرفعال "
"addClient" = "افزودن مشتری"
"submitDisable" = "ارسال به عنوان غیرفعال ☑️"
"submitEnable" = "ارسال به عنوان فعال ✅"
"use_default" = "🏷️ استفاده از پیش‌فرض"
"change_id" = "⚙️🔑 شناسه"
"change_password" = "⚙️🔑 رمز عبور"
"change_password" = "⚙️🔑 گذرواژه"
"change_email" = "⚙️📧 ایمیل"
"change_comment" = "⚙️💬 نظر"
[tgbot.answers]
"successfulOperation" = "✅ انجام شد!"
"errorOperation" = "❗ خطا در عملیات."

View File

@@ -29,6 +29,7 @@
"copySuccess" = "Berhasil Disalin"
"sure" = "Yakin"
"encryption" = "Enkripsi"
"useIPv4ForHost" = "Gunakan IPv4 untuk host"
"transmission" = "Transmisi"
"host" = "Host"
"path" = "Jalur"
@@ -645,14 +646,16 @@
"allClients" = "Semua Klien"
"addClient" = "Tambah Klien"
"submitDisable" = "Kirim Sebagai Nonaktif "
"use_default" = "🏷️ Gunakan default"
"submitDisable" = "Kirim Sebagai Nonaktif ☑️"
"submitEnable" = "Kirim Sebagai Aktif ✅"
"use_default" = "🏷️ Gunakan Default"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 Kata Sandi"
"change_email" = "⚙️📧 Email"
"change_comment" = "⚙️💬 Komentar"
[tgbot.answers]
"successfulOperation" = "✅ Operasi berhasil!"
"errorOperation" = "❗ Kesalahan dalam operasi."

View File

@@ -29,6 +29,7 @@
"copySuccess" = "コピー成功"
"sure" = "確定"
"encryption" = "暗号化"
"useIPv4ForHost" = "ホストにIPv4を使用"
"transmission" = "伝送"
"host" = "ホスト"
"path" = "パス"
@@ -645,14 +646,14 @@
"allClients" = "すべてのクライアント"
"addClient" = "クライアントを追加"
"submitDisable" = "無効として送信 "
"submitDisable" = "無効として送信 ☑️"
"submitEnable" = "有効として送信 ✅"
"use_default" = "🏷️ デフォルトを使用"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 パスワード"
"change_email" = "⚙️📧 メール"
"change_email" = "⚙️📧 メールアドレス"
"change_comment" = "⚙️💬 コメント"
[tgbot.answers]
"successfulOperation" = "✅ 成功!"
"errorOperation" = "❗ 操作エラー。"

View File

@@ -29,6 +29,7 @@
"copySuccess" = "Copiado com Sucesso"
"sure" = "Certo"
"encryption" = "Criptografia"
"useIPv4ForHost" = "Usar IPv4 para o host"
"transmission" = "Transmissão"
"host" = "Servidor"
"path" = "Caminho"
@@ -645,7 +646,8 @@
"allClients" = "Todos os clientes"
"addClient" = "Adicionar Cliente"
"submitDisable" = "Enviar como Desativado "
"submitDisable" = "Enviar como Desativado ☑️"
"submitEnable" = "Enviar como Ativado ✅"
"use_default" = "🏷️ Usar padrão"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 Senha"

View File

@@ -29,6 +29,7 @@
"copySuccess" = "Скопировано"
"sure" = "Да"
"encryption" = "Шифрование"
"useIPv4ForHost" = "Использовать IPv4 для хоста"
"transmission" = "Протокол"
"host" = "Хост"
"path" = "Путь"
@@ -645,7 +646,8 @@
"allClients" = "Все клиенты"
"addClient" = "Добавить клиента"
"submitDisable" = "Отправить отключенным ✅"
"submitDisable" = "Отправить как отключённый ☑️"
"submitEnable" = "Отправить как включённый ✅"
"use_default" = "🏷️ Использовать по умолчанию"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 Пароль"

View File

@@ -29,6 +29,7 @@
"copySuccess" = "Başarıyla Kopyalandı"
"sure" = "Emin misiniz"
"encryption" = "Şifreleme"
"useIPv4ForHost" = "Ana bilgisayar için IPv4 kullan"
"transmission" = "İletim"
"host" = "Sunucu"
"path" = "Yol"
@@ -645,9 +646,10 @@
"allClients" = "Tüm Müşteriler"
"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"
"change_id" = "⚙️🔑 ID"
"change_id" = "⚙️🔑 Kimlik"
"change_password" = "⚙️🔑 Şifre"
"change_email" = "⚙️📧 E-posta"
"change_comment" = "⚙️💬 Yorum"

View File

@@ -29,6 +29,7 @@
"copySuccess" = "Скопійовано успішно"
"sure" = "Звичайно"
"encryption" = "Шифрування"
"useIPv4ForHost" = "Використовувати IPv4 для хоста"
"transmission" = "Протокол передачи"
"host" = "Хост"
"path" = "Шлях"
@@ -645,8 +646,9 @@
"allClients" = "Всі Клієнти"
"addClient" = "Додати клієнта"
"submitDisable" = "Надіслати відключеним ✅"
"use_default" = "🏷️ Використовувати за замовчуванням"
"submitDisable" = "Надіслати як вимкнено ☑️"
"submitEnable" = "Надіслати як увімкнено ✅"
"use_default" = "🏷️ Використати типове"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 Пароль"
"change_email" = "⚙️📧 Електронна пошта"

View File

@@ -29,6 +29,7 @@
"copySuccess" = "Đã sao chép thành công"
"sure" = "Chắc chắn"
"encryption" = "Mã hóa"
"useIPv4ForHost" = "Sử dụng IPv4 cho máy chủ"
"transmission" = "Truyền tải"
"host" = "Máy chủ"
"path" = "Đường dẫn"
@@ -645,12 +646,13 @@
"allClients" = "Tất cả Khách hàng"
"addClient" = "Thêm Khách Hàng"
"submitDisable" = "Gửi Dưới Dạng Tắt ✅"
"use_default" = "🏷️ Sử dụng mặc định"
"submitDisable" = "Gửi Dưới Dạng Vô Hiệu ☑️"
"submitEnable" = "Gửi Dưới Dạng Kích Hoạt ✅"
"use_default" = "🏷️ Sử Dụng Mặc Định"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 Mật khẩu"
"change_password" = "⚙️🔑 Mật Khẩu"
"change_email" = "⚙️📧 Email"
"change_comment" = "⚙️💬 Bình luận"
"change_comment" = "⚙️💬 Bình Luận"
[tgbot.answers]

View File

@@ -29,6 +29,7 @@
"copySuccess" = "复制成功"
"sure" = "确定"
"encryption" = "加密"
"useIPv4ForHost" = "使用 IPv4 连接主机"
"transmission" = "传输"
"host" = "主机"
"path" = "路径"
@@ -645,7 +646,8 @@
"allClients" = "所有客户"
"addClient" = "添加客户"
"submitDisable" = "提交为禁用 "
"submitDisable" = "提交为禁用 ☑️"
"submitEnable" = "提交为启用 ✅"
"use_default" = "🏷️ 使用默认"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 密码"

View File

@@ -29,6 +29,7 @@
"copySuccess" = "複製成功"
"sure" = "確定"
"encryption" = "加密"
"useIPv4ForHost" = "使用 IPv4 連接主機"
"transmission" = "傳輸"
"host" = "主機"
"path" = "路徑"
@@ -645,8 +646,9 @@
"allClients" = "所有客戶"
"addClient" = "新增客戶"
"submitDisable" = "提交為停用 ✅"
"use_default" = "🏷️ 使用預設"
"submitDisable" = "以停用方式送出 ☑️"
"submitEnable" = "以啟用方式送出 ✅"
"use_default" = "🏷️ 使用預設值"
"change_id" = "⚙️🔑 ID"
"change_password" = "⚙️🔑 密碼"
"change_email" = "⚙️📧 電子郵件"