Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ef8a5a37e | ||
|
|
c49a9e877c | ||
|
|
b08d653e02 | ||
|
|
0928e408c0 | ||
|
|
032ed73c0d | ||
|
|
c5bbee354f | ||
|
|
fe7ce3f74b | ||
|
|
63acd585ba | ||
|
|
9a1cf70451 | ||
|
|
1777f257a8 | ||
|
|
b4997da51c | ||
|
|
4f9aff3043 | ||
|
|
e68317c6bd | ||
|
|
b7f476568b | ||
|
|
40c2f5206b | ||
|
|
b0a544a321 | ||
|
|
12828b6a15 | ||
|
|
8c6c9ace79 | ||
|
|
f881c5347c | ||
|
|
430338f045 | ||
|
|
74b14657cf | ||
|
|
07b35753d4 | ||
|
|
263df2abf5 | ||
|
|
738a771b87 | ||
|
|
025f559460 | ||
|
|
baaa814a51 | ||
|
|
d46e0e6925 | ||
|
|
3cd3cba8c6 | ||
|
|
366463bbb3 | ||
|
|
a0d6f85837 | ||
|
|
f25a7a571e | ||
|
|
87e173b567 | ||
|
|
6fbcd28799 | ||
|
|
b9ffe62d69 | ||
|
|
96786c9418 | ||
|
|
0423d8d919 | ||
|
|
688a68aba9 | ||
|
|
bc56e63737 | ||
|
|
a3e5628961 | ||
|
|
74ff17eeed | ||
|
|
b1dca4dc24 | ||
|
|
1a2b14b212 | ||
|
|
20b30958cb | ||
|
|
d224c207f8 | ||
|
|
f2d7b23e50 | ||
|
|
a28a855eff | ||
|
|
68da556bd2 | ||
|
|
b77001973a | ||
|
|
7d887024df | ||
|
|
8641ec8f13 | ||
|
|
6337efb786 | ||
|
|
4d9852f68d | ||
|
|
750fc54787 | ||
|
|
a2cd6a534f | ||
|
|
529eb3088a | ||
|
|
f0de1e5a62 | ||
|
|
14c5546661 | ||
|
|
e6a52dc2f6 | ||
|
|
28c9e7fe9c | ||
|
|
b37b12754f | ||
|
|
c7ca4c29d5 | ||
|
|
44b74224ab | ||
|
|
7a4523dec1 |
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the 3x-ui 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.
|
||||||
|
|
||||||
|
**Server (please complete the following information):**
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
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.
|
||||||
10
.github/ISSUE_TEMPLATE/question-.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: 'Question '
|
||||||
|
about: Describe this issue template's purpose here.
|
||||||
|
title: ''
|
||||||
|
labels: question
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
6
.github/workflows/release.yml
vendored
@@ -6,11 +6,11 @@ jobs:
|
|||||||
name: build x-ui amd64 version
|
name: build x-ui amd64 version
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3.3.0
|
- uses: actions/checkout@v3.4.0
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v3.5.0
|
uses: actions/setup-go@v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: '1.20.1'
|
go-version: 'stable'
|
||||||
- name: build linux amd64 version
|
- name: build linux amd64 version
|
||||||
run: |
|
run: |
|
||||||
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o xui-release -v main.go
|
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o xui-release -v main.go
|
||||||
|
|||||||
86
README.md
@@ -1,10 +1,11 @@
|
|||||||
# 3x-ui
|
# 3x-ui
|
||||||

|

|
||||||

|

|
||||||
[](https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui)
|

|
||||||
[](https://img.shields.io/github/downloads/mhsanaei/3x-ui/total)
|

|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
|
|
||||||
|
|
||||||
> **Disclaimer: This project is only for personal learning and communication, please do not use it for illegal purposes, please do not use it in a production environment**
|
> **Disclaimer: This project is only for personal learning and communication, please do not use it for illegal purposes, please do not use it in a production environment**
|
||||||
|
|
||||||
xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)**
|
xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)**
|
||||||
@@ -14,7 +15,11 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)**
|
|||||||
```
|
```
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||||
```
|
```
|
||||||
|
## Install custom version
|
||||||
|
To install your desired version you can add the version to the end of install command. Example for ver `v1.0.9`:
|
||||||
|
```
|
||||||
|
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.0.9
|
||||||
|
```
|
||||||
# SSL
|
# SSL
|
||||||
```
|
```
|
||||||
apt-get install certbot -y
|
apt-get install certbot -y
|
||||||
@@ -27,7 +32,7 @@ certbot renew --dry-run
|
|||||||
# Default settings
|
# Default settings
|
||||||
|
|
||||||
- Port: 2053
|
- Port: 2053
|
||||||
- username and password will be generated randomly you can see them after you install it (x-ui "7")
|
- username and password will be generated randomly if you skip to modify your own security(x-ui "7")
|
||||||
- database path: /etc/x-ui/x-ui.db
|
- database path: /etc/x-ui/x-ui.db
|
||||||
|
|
||||||
before you set ssl on settings
|
before you set ssl on settings
|
||||||
@@ -39,28 +44,73 @@ After you set ssl on settings
|
|||||||
# Enable Traffic For Users:
|
# Enable Traffic For Users:
|
||||||
|
|
||||||
**copy and paste to xray Configuration :** (you don't need to do this if you have a fresh install)
|
**copy and paste to xray Configuration :** (you don't need to do this if you have a fresh install)
|
||||||
- [for enable traffic](https://raw.githubusercontent.com/MHSanaei/3x-ui/main/media/for%20enable%20traffic.txt)
|
- [for enable traffic](https://raw.githubusercontent.com/mhsanaei/3x-ui/main/media/for%20enable%20traffic.txt)
|
||||||
- [for enable traffic+block all iran ip address](https://raw.githubusercontent.com/MHSanaei/3x-ui/main/media/for%20enable%20traffic%2Bblock%20all%20iran%20ip.txt)
|
- [for enable traffic+block all iran ip address](https://raw.githubusercontent.com/mhsanaei/3x-ui/main/media/for%20enable%20traffic%2Bblock%20all%20iran%20ip.txt)
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
- System Status Monitoring
|
||||||
|
- Search within all inbounds and clients
|
||||||
|
- Support Dark/Light theme UI
|
||||||
|
- Support multi-user multi-protocol, web page visualization operation
|
||||||
|
- Supported protocols: vmess, vless, trojan, shadowsocks, dokodemo-door, socks, http
|
||||||
|
- Support for configuring more transport configurations
|
||||||
|
- Traffic statistics, limit traffic, limit expiration time
|
||||||
|
- Customizable xray configuration templates
|
||||||
|
- Support https access panel (self-provided domain name + ssl certificate)
|
||||||
|
- Support one-click SSL certificate application and automatic renewal
|
||||||
|
- For more advanced configuration items, please refer to the panel
|
||||||
|
|
||||||
|
# Tg robot use
|
||||||
|
|
||||||
|
X-UI supports daily traffic notification, panel login reminder and other functions through the Tg robot. To use the Tg robot, you need to apply for the specific application tutorial. You can refer to the [blog](https://coderfan.net/how-to-use-telegram-bot-to-alarm-you-when-someone-login-into-your-vps.html)
|
||||||
|
Set the robot-related parameters in the panel background, including:
|
||||||
|
|
||||||
|
- Tg robot Token
|
||||||
|
- Tg robot ChatId
|
||||||
|
- Tg robot cycle runtime, in crontab syntax
|
||||||
|
- Tg robot Expiration threshold
|
||||||
|
- Tg robot Traffic threshold
|
||||||
|
- Tg robot Enable send backup in cycle runtime
|
||||||
|
- Tg robot Enable CPU usage alarm threshold
|
||||||
|
|
||||||
|
Reference syntax:
|
||||||
|
|
||||||
|
- @hourly // hourly notification
|
||||||
|
- @daily // Daily notification (00:00 in the morning)
|
||||||
|
- @every 8h // notify every 8 hours
|
||||||
|
|
||||||
|
# Telegram Bot Features
|
||||||
|
|
||||||
|
- Report periodic
|
||||||
|
- Login notification
|
||||||
|
- CPU threshold notification
|
||||||
|
- Threshold for Expiration time and Traffic to report in advance
|
||||||
|
- Support client report if client's telegram username is added to the end of `email` like 'test123@telegram_username'
|
||||||
|
- Support telegram traffic report searched with UID (VMESS/VLESS) or Password (TROJAN) - anonymously
|
||||||
|
- Menu based bot
|
||||||
|
- Search client by email ( only admin )
|
||||||
|
- Check all inbounds
|
||||||
|
- Check server status
|
||||||
|
- Check Exhausted users
|
||||||
|
- Receive backup by request and in periodic reports
|
||||||
|
|
||||||
|
# A Special Thanks To
|
||||||
|
- [alireza0](https://github.com/alireza0/)
|
||||||
|
- [HexaSoftwareTech](https://github.com/HexaSoftwareTech/)
|
||||||
|
|
||||||
# Suggestion System
|
# Suggestion System
|
||||||
- Ubuntu 20.04+
|
- Ubuntu 20.04+
|
||||||
- Debian 10+
|
- Debian 10+
|
||||||
- CentOS 8+
|
- CentOS 8+
|
||||||
|
- Fedora 36+
|
||||||
|
|
||||||
# Pictures
|
# Pictures
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
# A Special Thanks To
|
|
||||||
- [vaxilu](https://github.com/vaxilu/)
|
|
||||||
- [HexaSoftwareTech](https://github.com/HexaSoftwareTech/)
|
|
||||||
- [diditra](https://github.com/diditra/)
|
|
||||||
- [FranzKafkaYu](https://github.com/FranzKafkaYu)
|
|
||||||
- [alireza0](https://github.com/alireza0/)
|
|
||||||
|
|
||||||
|
|
||||||
## Stargazers over time
|
## Stargazers over time
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.0.8
|
1.0.9
|
||||||
|
|||||||
24
go.mod
@@ -10,15 +10,15 @@ require (
|
|||||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.2.1
|
github.com/nicksnyder/go-i18n/v2 v2.2.1
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6
|
github.com/pelletier/go-toml/v2 v2.0.7
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/shirou/gopsutil/v3 v3.23.1
|
github.com/shirou/gopsutil/v3 v3.23.2
|
||||||
github.com/xtls/xray-core v1.7.5
|
github.com/xtls/xray-core v1.8.0
|
||||||
go.uber.org/atomic v1.10.0
|
go.uber.org/atomic v1.10.0
|
||||||
golang.org/x/text v0.7.0
|
golang.org/x/text v0.8.0
|
||||||
google.golang.org/grpc v1.53.0
|
google.golang.org/grpc v1.54.0
|
||||||
gorm.io/driver/sqlite v1.4.4
|
gorm.io/driver/sqlite v1.4.4
|
||||||
gorm.io/gorm v1.24.5
|
gorm.io/gorm v1.24.6
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -31,7 +31,7 @@ require (
|
|||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
||||||
github.com/goccy/go-json v0.10.0 // indirect
|
github.com/goccy/go-json v0.10.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/gorilla/context v1.1.1 // indirect
|
github.com/gorilla/context v1.1.1 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||||
github.com/gorilla/sessions v1.2.1 // indirect
|
github.com/gorilla/sessions v1.2.1 // indirect
|
||||||
@@ -53,10 +53,10 @@ require (
|
|||||||
github.com/ugorji/go/codec v1.2.10 // indirect
|
github.com/ugorji/go/codec v1.2.10 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/arch v0.2.0 // indirect
|
golang.org/x/arch v0.2.0 // indirect
|
||||||
golang.org/x/crypto v0.6.0 // indirect
|
golang.org/x/crypto v0.7.0 // indirect
|
||||||
golang.org/x/net v0.7.0 // indirect
|
golang.org/x/net v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.5.0 // indirect
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 // indirect
|
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
google.golang.org/protobuf v1.29.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
83
go.sum
@@ -3,7 +3,7 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak
|
|||||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig=
|
github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig=
|
||||||
github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A=
|
github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A=
|
||||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
github.com/antonlindstrom/pgstore v0.0.0-20200229204646-b08ebf1105e0/go.mod h1:2Ti6VUHVxpC0VSmTZzEvpzysnaGAfGBOoMIz5ykPyyw=
|
github.com/antonlindstrom/pgstore v0.0.0-20200229204646-b08ebf1105e0/go.mod h1:2Ti6VUHVxpC0VSmTZzEvpzysnaGAfGBOoMIz5ykPyyw=
|
||||||
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
|
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||||
@@ -52,8 +52,8 @@ github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
|
|||||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
@@ -61,7 +61,7 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
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/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U=
|
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso=
|
||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||||
@@ -80,7 +80,7 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
|||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
|
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
|
||||||
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
@@ -100,6 +100,7 @@ github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S
|
|||||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
|
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
|
||||||
|
github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo=
|
||||||
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=
|
||||||
@@ -108,12 +109,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA=
|
github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
|
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
|
||||||
github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI=
|
github.com/onsi/ginkgo/v2 v2.9.0 h1:Tugw2BKlNHTMfG+CheOITkYvk4LAh6MFOvikhGVnhE8=
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||||
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=
|
github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=
|
||||||
github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
|
github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
|
||||||
@@ -124,21 +125,20 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om
|
|||||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
|
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
|
||||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
||||||
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
|
github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
|
||||||
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
|
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
|
||||||
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
|
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
|
||||||
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
|
github.com/refraction-networking/utls v1.2.3-0.20230308205431-4f1df6c200db h1:ULRv/GPW5KYDafE0FACN2no+HTCyQLUtfyOIeyp3GNc=
|
||||||
github.com/refraction-networking/utls v1.2.2-0.20230207151345-a75a4b484849 h1:vNEcNapWFwnYJTBcVkHJa8VrdL40PNDLDbSGVY+ZV7I=
|
|
||||||
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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
github.com/sagernet/sing v0.1.6 h1:Qy63OUfKpcqKjfd5rPmUlj0RGjHZSK/PJn0duyCCsRg=
|
github.com/sagernet/sing v0.1.7 h1:g4vjr3q8SUlBZSx97Emz5OBfSMBxxW5Q8C2PfdoSo08=
|
||||||
github.com/sagernet/sing-shadowsocks v0.1.1-0.20230202035033-e3123545f2f7 h1:Plup6oEiyLzY3HDqQ+QsUBzgBGdVmcsgf3t8h940z9U=
|
github.com/sagernet/sing-shadowsocks v0.1.1 h1:uFK2rlVeD/b1xhDwSMbUI2goWc6fOKxp+ZeKHZq6C9Q=
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
|
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
||||||
github.com/shirou/gopsutil/v3 v3.23.1 h1:a9KKO+kGLKEvcPIs4W62v0nu3sciVDOOOPUD0Hz7z/4=
|
github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU=
|
||||||
github.com/shirou/gopsutil/v3 v3.23.1/go.mod h1:NN6mnm5/0k8jw4cBfCnJtr5L7ErOTg18tMNpgFkn0hA=
|
github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
@@ -148,8 +148,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
|
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
|
||||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||||
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||||
@@ -163,14 +164,14 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
|
|||||||
github.com/ugorji/go/codec v1.2.10 h1:eimT6Lsr+2lzmSZxPhLFoOWFmQqwk0fllJJ5hEbTXtQ=
|
github.com/ugorji/go/codec v1.2.10 h1:eimT6Lsr+2lzmSZxPhLFoOWFmQqwk0fllJJ5hEbTXtQ=
|
||||||
github.com/ugorji/go/codec v1.2.10/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.10/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
||||||
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM=
|
github.com/xtls/reality v0.0.0-20230309125256-0d0713b108c8 h1:LLtLxEe3S0Ko+ckqt4t29RLskpNdOZfgjZCC2/Byr50=
|
||||||
github.com/xtls/xray-core v1.7.5 h1:Ukr3hXnOG2ciViQL7kfYRl9S3GVej2dkV7DzabmoLL4=
|
github.com/xtls/xray-core v1.8.0 h1:/OD0sDv6YIBqvE+cVfnqlKrtbMs0Fm9IP5BR5d8Eu4k=
|
||||||
github.com/xtls/xray-core v1.7.5/go.mod h1:Mx1QzIDvSk4eZ8hKa3AYsSPfyZJNQXWVXTJxJRJ98wI=
|
github.com/xtls/xray-core v1.8.0/go.mod h1:i9KWgbLyxg/NT+3+g4nE74Zp3DgTCP3X04YkSfsJeDI=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.starlark.net v0.0.0-20230128213706-3f75dec8e403 h1:jPeC7Exc+m8OBJUlWbBLh0O5UZPM7yU5W4adnhhbG4U=
|
go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg=
|
||||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
@@ -180,19 +181,19 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
|
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -210,9 +211,9 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -220,26 +221,26 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4=
|
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 h1:znp6mq/drrY+6khTAlJUDNFFcDGV2ENLYKpMq8SyCds=
|
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
||||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
|
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||||
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
|
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
||||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@@ -252,8 +253,8 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|||||||
gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc=
|
gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc=
|
||||||
gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
|
gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
|
||||||
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||||
gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE=
|
gorm.io/gorm v1.24.6 h1:wy98aq9oFEetsc4CAbKD2SoBCdMzsbSIvSUUFJuHi5s=
|
||||||
gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
gorm.io/gorm v1.24.6/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
|
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
|
||||||
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
|||||||
72
install.sh
@@ -10,24 +10,18 @@ cur_dir=$(pwd)
|
|||||||
# check root
|
# check root
|
||||||
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error:${plain} Please run this script with root privilege \n " && exit 1
|
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error:${plain} Please run this script with root privilege \n " && exit 1
|
||||||
|
|
||||||
# check os
|
# Check OS and set release variable
|
||||||
if [[ -f /etc/redhat-release ]]; then
|
if [[ -f /etc/os-release ]]; then
|
||||||
release="centos"
|
source /etc/os-release
|
||||||
elif cat /etc/issue | grep -Eqi "debian"; then
|
release=$ID
|
||||||
release="debian"
|
elif [[ -f /usr/lib/os-release ]]; then
|
||||||
elif cat /etc/issue | grep -Eqi "ubuntu"; then
|
source /usr/lib/os-release
|
||||||
release="ubuntu"
|
release=$ID
|
||||||
elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then
|
|
||||||
release="centos"
|
|
||||||
elif cat /proc/version | grep -Eqi "debian"; then
|
|
||||||
release="debian"
|
|
||||||
elif cat /proc/version | grep -Eqi "ubuntu"; then
|
|
||||||
release="ubuntu"
|
|
||||||
elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then
|
|
||||||
release="centos"
|
|
||||||
else
|
else
|
||||||
echo -e "${red} Check system OS failed, please contact the author! ${plain}\n" && exit 1
|
echo "Failed to check the system OS, please contact the author!" >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
echo "The OS release is: $release"
|
||||||
|
|
||||||
arch=$(arch)
|
arch=$(arch)
|
||||||
|
|
||||||
@@ -48,37 +42,38 @@ if [ $(getconf WORD_BIT) != '32' ] && [ $(getconf LONG_BIT) != '64' ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
os_version=""
|
os_version=""
|
||||||
|
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
||||||
|
|
||||||
# os version
|
if [[ "${release}" == "centos" ]]; then
|
||||||
if [[ -f /etc/os-release ]]; then
|
if [[ ${os_version} -lt 8 ]]; then
|
||||||
os_version=$(awk -F'[= ."]' '/VERSION_ID/{print $3}' /etc/os-release)
|
|
||||||
fi
|
|
||||||
if [[ -z "$os_version" && -f /etc/lsb-release ]]; then
|
|
||||||
os_version=$(awk -F'[= ."]+' '/DISTRIB_RELEASE/{print $2}' /etc/lsb-release)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ x"${release}" == x"centos" ]]; then
|
|
||||||
if [[ ${os_version} -le 7 ]]; then
|
|
||||||
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
|
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
elif [[ x"${release}" == x"ubuntu" ]]; then
|
elif [[ "${release}" == "ubuntu" ]]; then
|
||||||
if [[ ${os_version} -lt 20 ]]; then
|
if [[ ${os_version} -lt 20 ]]; then
|
||||||
echo -e "${red} Please use Ubuntu 20 or higher ${plain}\n" && exit 1
|
echo -e "${red}please use Ubuntu 20 or higher version!${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
elif [[ x"${release}" == x"debian" ]]; then
|
|
||||||
if [[ ${os_version} -lt 9 ]]; then
|
elif [[ "${release}" == "fedora" ]]; then
|
||||||
|
if [[ ${os_version} -lt 36 ]]; then
|
||||||
|
echo -e "${red}please use Fedora 36 or higher version!${plain}\n" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [[ "${release}" == "debian" ]]; then
|
||||||
|
if [[ ${os_version} -lt 10 ]]; then
|
||||||
echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
|
echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${red}Failed to check the OS version, please contact the author!${plain}" && exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
install_base() {
|
install_base() {
|
||||||
if [[ x"${release}" == x"centos" ]]; then
|
if [[ "${release}" == "centos" ]]; then
|
||||||
yum install wget curl tar -y
|
yum install wget curl tar -y
|
||||||
else
|
else
|
||||||
apt install wget curl tar -y
|
apt install wget curl tar -y
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
#This function will be called when user installed x-ui out of sercurity
|
#This function will be called when user installed x-ui out of sercurity
|
||||||
config_after_install() {
|
config_after_install() {
|
||||||
echo -e "${yellow}Install/update finished! For security it's recommended to modify panel settings ${plain}"
|
echo -e "${yellow}Install/update finished! For security it's recommended to modify panel settings ${plain}"
|
||||||
@@ -103,9 +98,8 @@ config_after_install() {
|
|||||||
/usr/local/x-ui/x-ui setting -username ${usernameTemp} -password ${passwordTemp}
|
/usr/local/x-ui/x-ui setting -username ${usernameTemp} -password ${passwordTemp}
|
||||||
echo -e "this is a fresh installation,will generate random login info for security concerns:"
|
echo -e "this is a fresh installation,will generate random login info for security concerns:"
|
||||||
echo -e "###############################################"
|
echo -e "###############################################"
|
||||||
echo -e "${green}user name:${usernameTemp}${plain}"
|
echo -e "${green}username:${usernameTemp}${plain}"
|
||||||
echo -e "${green}user password:${passwordTemp}${plain}"
|
echo -e "${green}password:${passwordTemp}${plain}"
|
||||||
echo -e "${red}web port:${portTemp}${plain}"
|
|
||||||
echo -e "###############################################"
|
echo -e "###############################################"
|
||||||
echo -e "${red}if you forgot your login info,you can type x-ui and then type 7 to check after installation${plain}"
|
echo -e "${red}if you forgot your login info,you can type x-ui and then type 7 to check after installation${plain}"
|
||||||
else
|
else
|
||||||
@@ -119,20 +113,20 @@ install_x-ui() {
|
|||||||
cd /usr/local/
|
cd /usr/local/
|
||||||
|
|
||||||
if [ $# == 0 ]; then
|
if [ $# == 0 ]; then
|
||||||
last_version=$(curl -Ls "https://api.github.com/repos/mhsanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
last_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||||
if [[ ! -n "$last_version" ]]; then
|
if [[ ! -n "$last_version" ]]; then
|
||||||
echo -e "${red}Failed to fetch x-ui version, it maybe due to Github API restrictions, please try it later${plain}"
|
echo -e "${red}Failed to fetch x-ui version, it maybe due to Github API restrictions, please try it later${plain}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo -e "Got x-ui latest version: ${last_version}, beginning the installation..."
|
echo -e "Got x-ui latest version: ${last_version}, beginning the installation..."
|
||||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-${arch}.tar.gz https://github.com/mhsanaei/3x-ui/releases/download/${last_version}/x-ui-linux-${arch}.tar.gz
|
wget -N --no-check-certificate -O /usr/local/x-ui-linux-${arch}.tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-${arch}.tar.gz
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
echo -e "${red}Downloading x-ui failed, please be sure that your server can access Github ${plain}"
|
echo -e "${red}Downloading x-ui failed, please be sure that your server can access Github ${plain}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
last_version=$1
|
last_version=$1
|
||||||
url="https://github.com/mhsanaei/3x-ui/releases/download/${last_version}/x-ui-linux-${arch}.tar.gz"
|
url="https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-${arch}.tar.gz"
|
||||||
echo -e "Begining to install x-ui $1"
|
echo -e "Begining to install x-ui $1"
|
||||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-${arch}.tar.gz ${url}
|
wget -N --no-check-certificate -O /usr/local/x-ui-linux-${arch}.tar.gz ${url}
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
@@ -150,7 +144,7 @@ install_x-ui() {
|
|||||||
cd x-ui
|
cd x-ui
|
||||||
chmod +x x-ui bin/xray-linux-${arch}
|
chmod +x x-ui bin/xray-linux-${arch}
|
||||||
cp -f x-ui.service /etc/systemd/system/
|
cp -f x-ui.service /etc/systemd/system/
|
||||||
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/mhsanaei/3x-ui/main/x-ui.sh
|
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
|
||||||
chmod +x /usr/local/x-ui/x-ui.sh
|
chmod +x /usr/local/x-ui/x-ui.sh
|
||||||
chmod +x /usr/bin/x-ui
|
chmod +x /usr/bin/x-ui
|
||||||
config_after_install
|
config_after_install
|
||||||
|
|||||||
BIN
media/1.png
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 47 KiB |
BIN
media/2.png
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 49 KiB |
BIN
media/3.png
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 42 KiB |
BIN
media/4.png
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 28 KiB |
2
web/assets/ant-design-vue@1.7.2/antd.min.css
vendored
@@ -150,3 +150,190 @@
|
|||||||
color:rgb(255, 255, 255) !important;
|
color:rgb(255, 255, 255) !important;
|
||||||
background-color: rgb(255, 127, 127);
|
background-color: rgb(255, 127, 127);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody>tr>td,
|
||||||
|
.ant-table-thead>tr>th{
|
||||||
|
padding:16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-menu-dark,
|
||||||
|
.ant-menu-dark .ant-menu-sub,
|
||||||
|
.ant-layout-header,
|
||||||
|
.ant-layout-sider-dark,
|
||||||
|
.ant-layout-sider-zero-width-trigger,
|
||||||
|
.ant-dropdown-menu-dark,.ant-dropdown-menu-dark .ant-dropdown-menu,
|
||||||
|
.ant-menu-dark.ant-menu-horizontal>.ant-menu-item,.ant-menu-dark.ant-menu-horizontal>.ant-menu-submenu {
|
||||||
|
background:#161b22
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #1a212a;
|
||||||
|
border-color:rgba(0,0,0,.09);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark:hover {
|
||||||
|
border-color: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-table-thead th {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #161b22;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-table-tbody tr td,
|
||||||
|
.ant-card-dark .ant-modal-title {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-collapse-content,
|
||||||
|
.ant-card-dark .ant-calendar,
|
||||||
|
.ant-card-dark .ant-table-placeholder,
|
||||||
|
.ant-card-dark .ant-input-group-addon {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #262f3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-list-item-meta-title,
|
||||||
|
.ant-card-dark .ant-list-item-meta-description,
|
||||||
|
.ant-card-dark .ant-form-item-label>label,
|
||||||
|
.ant-card-dark .ant-form-item,
|
||||||
|
.ant-card-dark .ant-divider-inner-text,
|
||||||
|
.ant-card-dark .ant-modal-confirm-content,
|
||||||
|
.ant-card-dark .ant-modal-confirm-title,
|
||||||
|
.ant-card-dark .ant-progress-text,
|
||||||
|
.ant-card-dark .ant-modal-close,
|
||||||
|
.ant-card-dark i,
|
||||||
|
.ant-card-dark .ant-select-dropdown-menu-item,
|
||||||
|
.ant-card-dark .ant-calendar-month-select,
|
||||||
|
.ant-card-dark .ant-calendar-year-select,
|
||||||
|
.ant-card-dark .ant-calendar-date,
|
||||||
|
.ant-card-dark .ant-collapse>.ant-collapse-item>.ant-collapse-header,
|
||||||
|
.ant-card-dark .ant-empty-normal,
|
||||||
|
.ant-card-dark .ant-checkbox+span {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-table-tbody>tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,
|
||||||
|
.ant-card-dark .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled),
|
||||||
|
.ant-card-dark .ant-calendar-date:hover {
|
||||||
|
background-color: #004488;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark tbody .ant-table-expanded-row {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #1a212a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-input,
|
||||||
|
.ant-card-dark .ant-input-number,
|
||||||
|
.ant-card-dark .ant-calendar-input,
|
||||||
|
.ant-card-dark .ant-select-dropdown-menu-item-selected,
|
||||||
|
.ant-card-dark .ant-select-selection {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #2e3b52;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-collapse-item {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #161b22;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-modal-content,
|
||||||
|
.ant-card-dark .ant-modal-body,
|
||||||
|
.ant-card-dark .ant-modal-header,
|
||||||
|
.ant-card-dark .ant-calendar-selected-day .ant-calendar-date {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #222a37;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-table-header {
|
||||||
|
background-color: #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-table-odd-row {
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .client-table-header {
|
||||||
|
background-color: #1a212a;
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .client-table-odd-row {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #242c3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-calendar-last-month-cell .ant-calendar-date,
|
||||||
|
.ant-card-dark .ant-calendar-next-month-btn-day .ant-calendar-date {
|
||||||
|
color: hsla(0,0%,100%,.30);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-dark {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-dark .ant-drawer-wrapper-body,
|
||||||
|
.ant-drawer-dark .drawer-handle {
|
||||||
|
background-color: #1a212a;
|
||||||
|
border: 1px solid hsla(0,0%,100%,.30);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-blue {
|
||||||
|
color: #3c9ae8;
|
||||||
|
background: #111d2c;
|
||||||
|
border-color: #15395b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-green {
|
||||||
|
color: #6abe39;
|
||||||
|
background: #162312;
|
||||||
|
border-color: #274916;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-cyan {
|
||||||
|
color: #33bcb7;
|
||||||
|
background: #112123;
|
||||||
|
border-color: #144848;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-red {
|
||||||
|
color: #e84749;
|
||||||
|
background: #2a1215;
|
||||||
|
border-color: #58181c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-tag-orange {
|
||||||
|
color: #e89a3c;
|
||||||
|
background: #2b1d11;
|
||||||
|
border-color: #593815;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-table-row-expand-icon,
|
||||||
|
.ant-card-dark .ant-checkbox-inner {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-switch-checked {
|
||||||
|
background-color: #0c61b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-btn,
|
||||||
|
.ant-card-dark .ant-radio-button-wrapper {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background: none;
|
||||||
|
border: 1px solid hsla(0,0%,100%,.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-radio-button-wrapper:hover {
|
||||||
|
color: #177ddc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-dark .ant-btn-primary {
|
||||||
|
color: hsla(0,0%,100%,.65);
|
||||||
|
background-color: #073763;
|
||||||
|
border-color: #1890ff;
|
||||||
|
text-shadow: 0 -1px 0 rgba(0,0,0,.12);
|
||||||
|
box-shadow: 0 2px 0 rgba(0,0,0,.045);
|
||||||
|
}
|
||||||
@@ -155,7 +155,7 @@ class DBInbound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
genLink(clientIndex = 0) {
|
genLink(clientIndex) {
|
||||||
const inbound = this.toInbound();
|
const inbound = this.toInbound();
|
||||||
return inbound.genLink(this.address, this.remark, clientIndex);
|
return inbound.genLink(this.address, this.remark, clientIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ const TLS_VERSION_OPTION = {
|
|||||||
TLS11: "1.1",
|
TLS11: "1.1",
|
||||||
TLS12: "1.2",
|
TLS12: "1.2",
|
||||||
TLS13: "1.3",
|
TLS13: "1.3",
|
||||||
}
|
};
|
||||||
|
|
||||||
const TLS_CIPHER_OPTION = {
|
const TLS_CIPHER_OPTION = {
|
||||||
RSA_AES_128_CBC: "TLS_RSA_WITH_AES_128_CBC_SHA",
|
RSA_AES_128_CBC: "TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||||
@@ -92,6 +92,11 @@ const UTLS_FINGERPRINT = {
|
|||||||
UTLS_RANDOMIZED: "randomized",
|
UTLS_RANDOMIZED: "randomized",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ALPN_OPTION = {
|
||||||
|
H2: "h2",
|
||||||
|
HTTP1: "http/1.1",
|
||||||
|
};
|
||||||
|
|
||||||
Object.freeze(Protocols);
|
Object.freeze(Protocols);
|
||||||
Object.freeze(VmessMethods);
|
Object.freeze(VmessMethods);
|
||||||
Object.freeze(SSMethods);
|
Object.freeze(SSMethods);
|
||||||
@@ -102,6 +107,7 @@ Object.freeze(TLS_FLOW_CONTROL);
|
|||||||
Object.freeze(TLS_VERSION_OPTION);
|
Object.freeze(TLS_VERSION_OPTION);
|
||||||
Object.freeze(TLS_CIPHER_OPTION);
|
Object.freeze(TLS_CIPHER_OPTION);
|
||||||
Object.freeze(UTLS_FINGERPRINT);
|
Object.freeze(UTLS_FINGERPRINT);
|
||||||
|
Object.freeze(ALPN_OPTION);
|
||||||
|
|
||||||
class XrayCommonClass {
|
class XrayCommonClass {
|
||||||
|
|
||||||
@@ -469,9 +475,9 @@ class GrpcStreamSettings extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TlsStreamSettings extends XrayCommonClass {
|
class TlsStreamSettings extends XrayCommonClass {
|
||||||
constructor(serverName = '', minVersion = TLS_VERSION_OPTION.TLS12, maxVersion = TLS_VERSION_OPTION.TLS13,
|
constructor(serverName = '', minVersion = TLS_VERSION_OPTION.TLS10, maxVersion = TLS_VERSION_OPTION.TLS13,
|
||||||
cipherSuites = '',
|
cipherSuites = '',
|
||||||
certificates = [new TlsStreamSettings.Cert()], alpn = ["h2", "http/1.1"]) {
|
certificates = [new TlsStreamSettings.Cert()], alpn=[''] ,settings=[new TlsStreamSettings.Settings()]) {
|
||||||
super();
|
super();
|
||||||
this.server = serverName;
|
this.server = serverName;
|
||||||
this.minVersion = minVersion;
|
this.minVersion = minVersion;
|
||||||
@@ -479,6 +485,7 @@ class TlsStreamSettings extends XrayCommonClass {
|
|||||||
this.cipherSuites = cipherSuites;
|
this.cipherSuites = cipherSuites;
|
||||||
this.certs = certificates;
|
this.certs = certificates;
|
||||||
this.alpn = alpn;
|
this.alpn = alpn;
|
||||||
|
this.settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
addCert(cert) {
|
addCert(cert) {
|
||||||
@@ -491,9 +498,14 @@ class TlsStreamSettings extends XrayCommonClass {
|
|||||||
|
|
||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
let certs;
|
let certs;
|
||||||
|
let settings;
|
||||||
if (!ObjectUtil.isEmpty(json.certificates)) {
|
if (!ObjectUtil.isEmpty(json.certificates)) {
|
||||||
certs = json.certificates.map(cert => TlsStreamSettings.Cert.fromJson(cert));
|
certs = json.certificates.map(cert => TlsStreamSettings.Cert.fromJson(cert));
|
||||||
}
|
}
|
||||||
|
if (!ObjectUtil.isEmpty(json.settings)) {
|
||||||
|
let values = json.settings[0];
|
||||||
|
settings = [new TlsStreamSettings.Settings(values.allowInsecure , values.fingerprint, values.serverName)];
|
||||||
|
}
|
||||||
|
|
||||||
return new TlsStreamSettings(
|
return new TlsStreamSettings(
|
||||||
json.serverName,
|
json.serverName,
|
||||||
@@ -502,6 +514,7 @@ class TlsStreamSettings extends XrayCommonClass {
|
|||||||
json.cipherSuites,
|
json.cipherSuites,
|
||||||
certs,
|
certs,
|
||||||
json.alpn,
|
json.alpn,
|
||||||
|
settings,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,7 +525,9 @@ class TlsStreamSettings extends XrayCommonClass {
|
|||||||
maxVersion: this.maxVersion,
|
maxVersion: this.maxVersion,
|
||||||
cipherSuites: this.cipherSuites,
|
cipherSuites: this.cipherSuites,
|
||||||
certificates: TlsStreamSettings.toJsonArray(this.certs),
|
certificates: TlsStreamSettings.toJsonArray(this.certs),
|
||||||
alpn: this.alpn
|
alpn: this.alpn,
|
||||||
|
settings: TlsStreamSettings.toJsonArray(this.settings),
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -558,6 +573,30 @@ TlsStreamSettings.Cert = class extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TlsStreamSettings.Settings = class extends XrayCommonClass {
|
||||||
|
constructor(allowInsecure = false, fingerprint = '', serverName = '') {
|
||||||
|
super();
|
||||||
|
this.allowInsecure = allowInsecure;
|
||||||
|
this.fingerprint = fingerprint;
|
||||||
|
this.serverName = serverName;
|
||||||
|
}
|
||||||
|
static fromJson(json = {}) {
|
||||||
|
return new TlsStreamSettings.Settings(
|
||||||
|
json.allowInsecure,
|
||||||
|
json.fingerprint,
|
||||||
|
json.servername,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
toJson() {
|
||||||
|
return {
|
||||||
|
allowInsecure: this.allowInsecure,
|
||||||
|
fingerprint: this.fingerprint,
|
||||||
|
serverName: this.serverName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class StreamSettings extends XrayCommonClass {
|
class StreamSettings extends XrayCommonClass {
|
||||||
constructor(network='tcp',
|
constructor(network='tcp',
|
||||||
security='none',
|
security='none',
|
||||||
@@ -593,12 +632,12 @@ class StreamSettings extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get isXTls() {
|
get isXTLS() {
|
||||||
return this.security === "xtls";
|
return this.security === "xtls";
|
||||||
}
|
}
|
||||||
|
|
||||||
set isXTls(isXTls) {
|
set isXTLS(isXTLS) {
|
||||||
if (isXTls) {
|
if (isXTLS) {
|
||||||
this.security = 'xtls';
|
this.security = 'xtls';
|
||||||
} else {
|
} else {
|
||||||
this.security = 'none';
|
this.security = 'none';
|
||||||
@@ -608,7 +647,7 @@ class StreamSettings extends XrayCommonClass {
|
|||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
let tls;
|
let tls;
|
||||||
if (json.security === "xtls") {
|
if (json.security === "xtls") {
|
||||||
tls = TlsStreamSettings.fromJson(json.xtlsSettings);
|
tls = TlsStreamSettings.fromJson(json.XTLSSettings);
|
||||||
} else {
|
} else {
|
||||||
tls = TlsStreamSettings.fromJson(json.tlsSettings);
|
tls = TlsStreamSettings.fromJson(json.tlsSettings);
|
||||||
}
|
}
|
||||||
@@ -631,7 +670,7 @@ class StreamSettings extends XrayCommonClass {
|
|||||||
network: network,
|
network: network,
|
||||||
security: this.security,
|
security: this.security,
|
||||||
tlsSettings: this.isTls ? this.tls.toJson() : undefined,
|
tlsSettings: this.isTls ? this.tls.toJson() : undefined,
|
||||||
xtlsSettings: this.isXTls ? this.tls.toJson() : undefined,
|
XTLSSettings: this.isXTLS ? this.tls.toJson() : undefined,
|
||||||
tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined,
|
tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined,
|
||||||
kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined,
|
kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined,
|
||||||
wsSettings: network === 'ws' ? this.ws.toJson() : undefined,
|
wsSettings: network === 'ws' ? this.ws.toJson() : undefined,
|
||||||
@@ -666,7 +705,7 @@ class Sniffing extends XrayCommonClass {
|
|||||||
class Inbound extends XrayCommonClass {
|
class Inbound extends XrayCommonClass {
|
||||||
constructor(port=RandomUtil.randomIntRange(10000, 60000),
|
constructor(port=RandomUtil.randomIntRange(10000, 60000),
|
||||||
listen='',
|
listen='',
|
||||||
protocol=Protocols.VMESS,
|
protocol=Protocols.VLESS,
|
||||||
settings=null,
|
settings=null,
|
||||||
streamSettings=new StreamSettings(),
|
streamSettings=new StreamSettings(),
|
||||||
tag='',
|
tag='',
|
||||||
@@ -710,12 +749,12 @@ class Inbound extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get xtls() {
|
get XTLS() {
|
||||||
return this.stream.security === 'xtls';
|
return this.stream.security === 'xtls';
|
||||||
}
|
}
|
||||||
|
|
||||||
set xtls(isXTls) {
|
set XTLS(isXTLS) {
|
||||||
if (isXTls) {
|
if (isXTLS) {
|
||||||
this.stream.security = 'xtls';
|
this.stream.security = 'xtls';
|
||||||
} else {
|
} else {
|
||||||
this.stream.security = 'none';
|
this.stream.security = 'none';
|
||||||
@@ -754,18 +793,6 @@ class Inbound extends XrayCommonClass {
|
|||||||
return this.network === "http";
|
return this.network === "http";
|
||||||
}
|
}
|
||||||
|
|
||||||
isInboundEmpty() {
|
|
||||||
if (this.protocol == Protocols.VMESS && this.settings.vmesses.length == 0) {
|
|
||||||
return true;
|
|
||||||
} else if (this.protocol == Protocols.VLESS && this.settings.vlesses.length == 0) {
|
|
||||||
return true;
|
|
||||||
} else if (this.protocol == Protocols.TROJAN && this.settings.trojans.length == 0) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VMess & VLess
|
// VMess & VLess
|
||||||
get uuid() {
|
get uuid() {
|
||||||
switch (this.protocol) {
|
switch (this.protocol) {
|
||||||
@@ -837,7 +864,7 @@ class Inbound extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get serverName() {
|
get serverName() {
|
||||||
if (this.stream.isTls || this.stream.isXTls) {
|
if (this.stream.isTls || this.stream.isXTLS) {
|
||||||
return this.stream.tls.server;
|
return this.stream.tls.server;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
@@ -931,7 +958,7 @@ class Inbound extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//this is used for xtls-rprx-vison
|
//this is used for xtls-rprx-vision
|
||||||
canEnableTlsFlow() {
|
canEnableTlsFlow() {
|
||||||
if ((this.stream.security === 'tls') && (this.network === "tcp")) {
|
if ((this.stream.security === 'tls') && (this.network === "tcp")) {
|
||||||
switch (this.protocol) {
|
switch (this.protocol) {
|
||||||
@@ -948,7 +975,8 @@ class Inbound extends XrayCommonClass {
|
|||||||
return this.canEnableTls();
|
return this.canEnableTls();
|
||||||
}
|
}
|
||||||
|
|
||||||
canEnableXTls() {
|
|
||||||
|
canEnableXTLS() {
|
||||||
switch (this.protocol) {
|
switch (this.protocol) {
|
||||||
case Protocols.VLESS:
|
case Protocols.VLESS:
|
||||||
case Protocols.TROJAN:
|
case Protocols.TROJAN:
|
||||||
@@ -1053,6 +1081,10 @@ class Inbound extends XrayCommonClass {
|
|||||||
host: host,
|
host: host,
|
||||||
path: path,
|
path: path,
|
||||||
tls: this.stream.security,
|
tls: this.stream.security,
|
||||||
|
sni: this.stream.tls.settings[0]['serverName'],
|
||||||
|
fp: this.stream.tls.settings[0]['fingerprint'],
|
||||||
|
alpn: this.stream.tls.alpn.join(','),
|
||||||
|
allowInsecure: this.stream.tls.settings[0].allowInsecure,
|
||||||
};
|
};
|
||||||
return 'vmess://' + base64(JSON.stringify(obj, null, 2));
|
return 'vmess://' + base64(JSON.stringify(obj, null, 2));
|
||||||
}
|
}
|
||||||
@@ -1064,11 +1096,6 @@ class Inbound extends XrayCommonClass {
|
|||||||
const type = this.stream.network;
|
const type = this.stream.network;
|
||||||
const params = new Map();
|
const params = new Map();
|
||||||
params.set("type", this.stream.network);
|
params.set("type", this.stream.network);
|
||||||
if (this.xtls) {
|
|
||||||
params.set("security", "xtls");
|
|
||||||
} else {
|
|
||||||
params.set("security", this.stream.security);
|
|
||||||
}
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
const tcp = this.stream.tcp;
|
const tcp = this.stream.tcp;
|
||||||
@@ -1114,20 +1141,35 @@ class Inbound extends XrayCommonClass {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.stream.security === 'tls') {
|
if (this.tls) {
|
||||||
|
params.set("security", "tls");
|
||||||
|
params.set("fp" , this.stream.tls.settings[0]['fingerprint']);
|
||||||
|
params.set("alpn", this.stream.tls.alpn);
|
||||||
|
if(this.stream.tls.settings[0].allowInsecure){
|
||||||
|
params.set("allowInsecure", "1");
|
||||||
|
}
|
||||||
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
||||||
address = this.stream.tls.server;
|
address = this.stream.tls.server;
|
||||||
params.set("sni", address);
|
}
|
||||||
|
if (this.stream.tls.settings[0]['serverName'] !== ''){
|
||||||
|
params.set("sni", this.stream.tls.settings[0]['serverName']);
|
||||||
}
|
}
|
||||||
if (this.settings.vlesses[clientIndex].flow === "xtls-rprx-vision") {
|
if (type === "tcp" && this.settings.vlesses[clientIndex].flow.length > 0) {
|
||||||
params.set("flow", this.settings.vlesses[clientIndex].flow);
|
params.set("flow", this.settings.vlesses[clientIndex].flow);
|
||||||
}
|
}
|
||||||
params.set("fp", this.settings.vlesses[clientIndex].fingerprint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.xtls) {
|
if (this.XTLS) {
|
||||||
params.set("flow", this.settings.vlesses[clientIndex].flow);
|
params.set("security", "tls");
|
||||||
}
|
params.set("alpn", this.stream.tls.alpn);
|
||||||
|
if(this.stream.tls.settings[0].allowInsecure){
|
||||||
|
params.set("allowInsecure", "1");
|
||||||
|
}
|
||||||
|
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
||||||
|
address = this.stream.tls.server;
|
||||||
|
}
|
||||||
|
params.set("flow", this.settings.vlesses[clientIndex].flow);
|
||||||
|
}
|
||||||
|
|
||||||
const link = `vless://${uuid}@${address}:${port}`;
|
const link = `vless://${uuid}@${address}:${port}`;
|
||||||
const url = new URL(link);
|
const url = new URL(link);
|
||||||
@@ -1138,7 +1180,7 @@ class Inbound extends XrayCommonClass {
|
|||||||
return url.toString();
|
return url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
genSSLink(address = '', remark = '',clientIndex) {
|
genSSLink(address = '', remark = '') {
|
||||||
let settings = this.settings;
|
let settings = this.settings;
|
||||||
const server = this.stream.tls.server;
|
const server = this.stream.tls.server;
|
||||||
if (!ObjectUtil.isEmpty(server)) {
|
if (!ObjectUtil.isEmpty(server)) {
|
||||||
@@ -1157,12 +1199,7 @@ class Inbound extends XrayCommonClass {
|
|||||||
const port = this.port;
|
const port = this.port;
|
||||||
const type = this.stream.network;
|
const type = this.stream.network;
|
||||||
const params = new Map();
|
const params = new Map();
|
||||||
params.set("type", this.stream.network);
|
params.set("type", this.stream.network);
|
||||||
if (this.xtls) {
|
|
||||||
params.set("security", "xtls");
|
|
||||||
} else {
|
|
||||||
params.set("security", this.stream.security);
|
|
||||||
}
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
const tcp = this.stream.tcp;
|
const tcp = this.stream.tcp;
|
||||||
@@ -1208,16 +1245,33 @@ class Inbound extends XrayCommonClass {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.stream.security === 'tls') {
|
if (this.tls) {
|
||||||
|
params.set("security", "tls");
|
||||||
|
params.set("fp" , this.stream.tls.settings[0]['fingerprint']);
|
||||||
|
params.set("alpn", this.stream.tls.alpn);
|
||||||
|
if(this.stream.tls.settings[0].allowInsecure){
|
||||||
|
params.set("allowInsecure", "1");
|
||||||
|
}
|
||||||
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
||||||
address = this.stream.tls.server;
|
address = this.stream.tls.server;
|
||||||
params.set("sni", address);
|
}
|
||||||
|
if (this.stream.tls.settings[0]['serverName'] !== ''){
|
||||||
|
params.set("sni", this.stream.tls.settings[0]['serverName']);
|
||||||
}
|
}
|
||||||
params.set("flow", this.settings.trojans[clientIndex].flow);
|
|
||||||
}
|
|
||||||
if (this.xtls) {
|
|
||||||
params.set("flow", this.settings.trojans[clientIndex].flow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.XTLS) {
|
||||||
|
params.set("security", "tls");
|
||||||
|
params.set("alpn", this.stream.tls.alpn);
|
||||||
|
if(this.stream.tls.settings[0].allowInsecure){
|
||||||
|
params.set("allowInsecure", "1");
|
||||||
|
}
|
||||||
|
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
||||||
|
address = this.stream.tls.server;
|
||||||
|
}
|
||||||
|
params.set("flow", this.settings.trojans[clientIndex].flow);
|
||||||
|
}
|
||||||
|
|
||||||
const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`;
|
const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`;
|
||||||
const url = new URL(link);
|
const url = new URL(link);
|
||||||
for (const [key, value] of params) {
|
for (const [key, value] of params) {
|
||||||
@@ -1250,19 +1304,18 @@ class Inbound extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
genInboundLinks(address = '', remark = '') {
|
genInboundLinks(address = '', remark = '') {
|
||||||
let link = '';
|
let link = '';
|
||||||
JSON.parse(this.settings)
|
switch (this.protocol) {
|
||||||
switch (this.protocol) {
|
case Protocols.VMESS:
|
||||||
case Protocols.VMESS:
|
case Protocols.VLESS:
|
||||||
case Protocols.VLESS:
|
case Protocols.TROJAN:
|
||||||
case Protocols.TROJAN:
|
JSON.parse(this.settings).clients.forEach((_,index) => {
|
||||||
JSON.parse(this.settings).clients.forEach((client,index) => {
|
link += this.genLink(address, remark, index) + '\r\n';
|
||||||
link += this.genLink(address, remark, index) + '\r\n';
|
});
|
||||||
});
|
return link;
|
||||||
return link;
|
case Protocols.SHADOWSOCKS:
|
||||||
case Protocols.SHADOWSOCKS:
|
return (this.genSSLink(address, remark) + '\r\n');
|
||||||
return (this.genSSLink(address, remark) + '\r\n');
|
default: return '';
|
||||||
default: return '';
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
@@ -1430,7 +1483,7 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
|
|||||||
fallbacks=[],) {
|
fallbacks=[],) {
|
||||||
super(protocol);
|
super(protocol);
|
||||||
this.vlesses = vlesses;
|
this.vlesses = vlesses;
|
||||||
this.decryption = decryption;
|
this.decryption = 'none';
|
||||||
this.fallbacks = fallbacks;
|
this.fallbacks = fallbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1446,7 +1499,7 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
|
|||||||
return new Inbound.VLESSSettings(
|
return new Inbound.VLESSSettings(
|
||||||
Protocols.VLESS,
|
Protocols.VLESS,
|
||||||
json.clients.map(client => Inbound.VLESSSettings.VLESS.fromJson(client)),
|
json.clients.map(client => Inbound.VLESSSettings.VLESS.fromJson(client)),
|
||||||
json.decryption,
|
'none',
|
||||||
Inbound.VLESSSettings.Fallback.fromJson(json.fallbacks),
|
Inbound.VLESSSettings.Fallback.fromJson(json.fallbacks),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1462,14 +1515,13 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
|
|||||||
};
|
};
|
||||||
Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
|
Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
|
||||||
|
|
||||||
constructor(id=RandomUtil.randomUUID(), flow='', email=RandomUtil.randomText(),limitIp=0, totalGB=0, fingerprint = UTLS_FINGERPRINT.UTLS_CHROME, expiryTime='') {
|
constructor(id=RandomUtil.randomUUID(), flow='', email=RandomUtil.randomText(),limitIp=0, totalGB=0, expiryTime='') {
|
||||||
super();
|
super();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.flow = flow;
|
this.flow = flow;
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.limitIp = limitIp;
|
this.limitIp = limitIp;
|
||||||
this.totalGB = totalGB;
|
this.totalGB = totalGB;
|
||||||
this.fingerprint = fingerprint;
|
|
||||||
this.expiryTime = expiryTime;
|
this.expiryTime = expiryTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1481,7 +1533,6 @@ Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
|
|||||||
json.email,
|
json.email,
|
||||||
json.limitIp,
|
json.limitIp,
|
||||||
json.totalGB,
|
json.totalGB,
|
||||||
json.fingerprint,
|
|
||||||
json.expiryTime,
|
json.expiryTime,
|
||||||
|
|
||||||
);
|
);
|
||||||
@@ -1580,7 +1631,7 @@ Inbound.TrojanSettings = class extends Inbound.Settings {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
|
Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
|
||||||
constructor(password=RandomUtil.randomSeq(10), flow ='', email=RandomUtil.randomText(),limitIp=0, totalGB=0, expiryTime='') {
|
constructor(password=RandomUtil.randomSeq(10), flow='', email=RandomUtil.randomText(),limitIp=0, totalGB=0, expiryTime='') {
|
||||||
super();
|
super();
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.flow = flow;
|
this.flow = flow;
|
||||||
@@ -1707,11 +1758,12 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Inbound.DokodemoSettings = class extends Inbound.Settings {
|
Inbound.DokodemoSettings = class extends Inbound.Settings {
|
||||||
constructor(protocol, address, port, network='tcp,udp') {
|
constructor(protocol, address, port, network='tcp,udp', followRedirect=false) {
|
||||||
super(protocol);
|
super(protocol);
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.network = network;
|
this.network = network;
|
||||||
|
this.followRedirect = followRedirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
@@ -1720,6 +1772,7 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
|
|||||||
json.address,
|
json.address,
|
||||||
json.port,
|
json.port,
|
||||||
json.network,
|
json.network,
|
||||||
|
json.followRedirect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1728,6 +1781,7 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
|
|||||||
address: this.address,
|
address: this.address,
|
||||||
port: this.port,
|
port: this.port,
|
||||||
network: this.network,
|
network: this.network,
|
||||||
|
followRedirect: this.followRedirect,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) {
|
|||||||
g.Use(a.checkLogin)
|
g.Use(a.checkLogin)
|
||||||
g.POST("/status", a.status)
|
g.POST("/status", a.status)
|
||||||
g.POST("/getXrayVersion", a.getXrayVersion)
|
g.POST("/getXrayVersion", a.getXrayVersion)
|
||||||
|
g.POST("/stopXrayService", a.stopXrayService)
|
||||||
|
g.POST("/restartXrayService", a.restartXrayService)
|
||||||
g.POST("/installXray/:version", a.installXray)
|
g.POST("/installXray/:version", a.installXray)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,3 +85,23 @@ func (a *ServerController) installXray(c *gin.Context) {
|
|||||||
err := a.serverService.UpdateXray(version)
|
err := a.serverService.UpdateXray(version)
|
||||||
jsonMsg(c, I18n(c, "install")+" xray", err)
|
jsonMsg(c, I18n(c, "install")+" xray", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *ServerController) stopXrayService(c *gin.Context) {
|
||||||
|
a.lastGetStatusTime = time.Now()
|
||||||
|
err := a.serverService.StopXrayService()
|
||||||
|
if err != nil {
|
||||||
|
jsonMsg(c, "", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
jsonMsg(c, "Xray stoped",err)
|
||||||
|
|
||||||
|
}
|
||||||
|
func (a *ServerController) restartXrayService(c *gin.Context) {
|
||||||
|
err := a.serverService.RestartXrayService()
|
||||||
|
if err != nil {
|
||||||
|
jsonMsg(c, "", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
jsonMsg(c, "Xray restarted",err)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{{define "promptModal"}}
|
{{define "promptModal"}}
|
||||||
<a-modal id="prompt-modal" v-model="promptModal.visible" :title="promptModal.title"
|
<a-modal id="prompt-modal" v-model="promptModal.visible" :title="promptModal.title"
|
||||||
:closable="true" @ok="promptModal.ok" :mask-closable="false"
|
:closable="true" @ok="promptModal.ok" :mask-closable="false"
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
:ok-text="promptModal.okText" cancel-text='{{ i18n "cancel" }}'>
|
:ok-text="promptModal.okText" cancel-text='{{ i18n "cancel" }}'>
|
||||||
<a-input id="prompt-modal-input" :type="promptModal.type"
|
<a-input id="prompt-modal-input" :type="promptModal.type"
|
||||||
v-model="promptModal.value"
|
v-model="promptModal.value"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{{define "qrcodeModal"}}
|
{{define "qrcodeModal"}}
|
||||||
<a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title"
|
<a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title"
|
||||||
:closable="true" width="300px" :ok-text="qrModal.okText"
|
:closable="true" width="300px" :ok-text="qrModal.okText"
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
cancel-text='{{ i18n "close" }}' :ok-button-props="{attrs:{id:'qr-modal-ok-btn'}}">
|
cancel-text='{{ i18n "close" }}' :ok-button-props="{attrs:{id:'qr-modal-ok-btn'}}">
|
||||||
<canvas id="qrCode" style="width: 100%; height: 100%;"></canvas>
|
<canvas id="qrCode" style="width: 100%; height: 100%;"></canvas>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
{{define "textModal"}}
|
{{define "textModal"}}
|
||||||
<a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title"
|
<a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title"
|
||||||
:closable="true" ok-text='{{ i18n "copy" }}' cancel-text='{{ i18n "close" }}'
|
:closable="true" ok-text='{{ i18n "copy" }}' cancel-text='{{ i18n "close" }}'
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
:ok-button-props="{attrs:{id:'txt-modal-ok-btn'}}">
|
:ok-button-props="{attrs:{id:'txt-modal-ok-btn'}}">
|
||||||
<a-button v-if="!ObjectUtil.isEmpty(txtModal.fileName)" type="primary" style="margin-bottom: 10px;"
|
<a-button v-if="!ObjectUtil.isEmpty(txtModal.fileName)" type="primary" style="margin-bottom: 10px;"
|
||||||
@click="downloader.download(txtModal.fileName, txtModal.content)">
|
:href="'data:application/text;charset=utf-8,' + encodeURIComponent(txtModal.content)" :download="txtModal.fileName">
|
||||||
{{ i18n "download" }} [[ txtModal.fileName ]]
|
{{ i18n "download" }} [[ txtModal.fileName ]]
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-input type="textarea" v-model="txtModal.content"
|
<a-input type="textarea" v-model="txtModal.content"
|
||||||
@@ -31,15 +32,7 @@
|
|||||||
});
|
});
|
||||||
this.clipboard.on('success', () => app.$message.success('{{ i18n "copied" }}'));
|
this.clipboard.on('success', () => app.$message.success('{{ i18n "copied" }}'));
|
||||||
}
|
}
|
||||||
if (this.qrcode === null) {
|
|
||||||
this.qrcode = new QRious({
|
|
||||||
element: document.querySelector('#qrCode'),
|
|
||||||
size: 260,
|
|
||||||
value: content,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.qrcode.value = content;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
close: function () {
|
close: function () {
|
||||||
@@ -48,6 +41,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const textModalApp = new Vue({
|
const textModalApp = new Vue({
|
||||||
|
delimiters: ['[[', ']]'],
|
||||||
el: '#text-modal',
|
el: '#text-modal',
|
||||||
data: {
|
data: {
|
||||||
txtModal: txtModal,
|
txtModal: txtModal,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<a-icon type="github"></a-icon>
|
<a-icon type="github"></a-icon>
|
||||||
<span>Github</span>
|
<span>Github</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="https://t.me/xxxuiforever">
|
<a-menu-item key="https://t.me/panel3xui">
|
||||||
<a-icon type="usergroup-add"></a-icon>
|
<a-icon type="usergroup-add"></a-icon>
|
||||||
<span>Telegram</span>
|
<span>Telegram</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -37,27 +37,51 @@
|
|||||||
|
|
||||||
|
|
||||||
{{define "commonSider"}}
|
{{define "commonSider"}}
|
||||||
<a-layout-sider id="sider" collapsible breakpoint="md" collapsed-width="0">
|
<a-layout-sider :theme="siderDrawer.theme" id="sider" collapsible breakpoint="md" collapsed-width="0">
|
||||||
<a-menu theme="dark" mode="inline" :selected-keys="['{{ .request_uri }}']"
|
<a-menu :theme="siderDrawer.theme" mode="inline" selected-keys="">
|
||||||
|
<a-menu-item mode="inline">
|
||||||
|
<a-icon type="bg-colors"></a-icon>
|
||||||
|
<a-switch size="small" :default-checked="siderDrawer.isDarkTheme"
|
||||||
|
checked-children="☀"
|
||||||
|
un-checked-children="🌙"
|
||||||
|
@change="siderDrawer.changeTheme()"></a-switch>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
<a-menu :theme="siderDrawer.theme" mode="inline" :selected-keys="['{{ .request_uri }}']"
|
||||||
@click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key">
|
@click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key">
|
||||||
{{template "menuItems" .}}
|
{{template "menuItems" .}}
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-layout-sider>
|
</a-layout-sider>
|
||||||
<a-drawer id="sider-drawer" placement="left" :closable="false"
|
<a-drawer id="sider-drawer" placement="left" :closable="false"
|
||||||
@close="siderDrawer.close()"
|
@close="siderDrawer.close()"
|
||||||
:visible="siderDrawer.visible" :wrap-style="{ padding: 0 }">
|
:visible="siderDrawer.visible"
|
||||||
|
:wrap-style="{ padding: 0 }">
|
||||||
<div class="drawer-handle" @click="siderDrawer.change()" slot="handle">
|
<div class="drawer-handle" @click="siderDrawer.change()" slot="handle">
|
||||||
<a-icon :type="siderDrawer.visible ? 'close' : 'menu-fold'"></a-icon>
|
<a-icon :type="siderDrawer.visible ? 'close' : 'menu-fold'"></a-icon>
|
||||||
</div>
|
</div>
|
||||||
<a-menu theme="light" mode="inline" :selected-keys="['{{ .request_uri }}']"
|
<a-menu mode="inline" selected-keys="">
|
||||||
|
<a-menu-item mode="inline">
|
||||||
|
<a-icon type="bg-colors"></a-icon>
|
||||||
|
<a-switch :default-checked="siderDrawer.isDarkTheme"
|
||||||
|
checked-children="☀"
|
||||||
|
un-checked-children="🌙"
|
||||||
|
@change="siderDrawer.changeTheme()"></a-switch>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
<a-menu mode="inline" :selected-keys="['{{ .request_uri }}']"
|
||||||
@click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key">
|
@click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key">
|
||||||
{{template "menuItems" .}}
|
{{template "menuItems" .}}
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-drawer>
|
</a-drawer>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
const darkClass = "ant-card-dark";
|
||||||
|
const bgDarkStyle = "background-color: #242c3a";
|
||||||
const siderDrawer = {
|
const siderDrawer = {
|
||||||
visible: false,
|
visible: false,
|
||||||
|
collapsed: false,
|
||||||
|
isDarkTheme: localStorage.getItem("dark-mode") === 'true' ? true : false,
|
||||||
show() {
|
show() {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
},
|
},
|
||||||
@@ -66,6 +90,16 @@
|
|||||||
},
|
},
|
||||||
change() {
|
change() {
|
||||||
this.visible = !this.visible;
|
this.visible = !this.visible;
|
||||||
|
},
|
||||||
|
toggleCollapsed() {
|
||||||
|
this.collapsed = !this.collapsed;
|
||||||
|
},
|
||||||
|
changeTheme() {
|
||||||
|
this.isDarkTheme = ! this.isDarkTheme;
|
||||||
|
localStorage.setItem("dark-mode", this.isDarkTheme);
|
||||||
|
},
|
||||||
|
get theme() {
|
||||||
|
return this.isDarkTheme ? 'dark' : 'light';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
{{define "inboundInfoStream"}}
|
|
||||||
<p>{{ i18n "transmission" }}: <a-tag color="green">[[ inbound.network ]]</a-tag></p>
|
|
||||||
|
|
||||||
<template v-if="inbound.isTcp || inbound.isWs || inbound.isH2">
|
|
||||||
<p v-if="inbound.host">host: <a-tag color="green">[[ inbound.host ]]</a-tag></p>
|
|
||||||
<p v-else>{{ i18n "host" }}: <a-tag color="orange">{{ i18n "none" }}</a-tag></p>
|
|
||||||
|
|
||||||
<p v-if="inbound.path">path: <a-tag color="green">[[ inbound.path ]]</a-tag></p>
|
|
||||||
<p v-else>{{ i18n "path" }}: <a-tag color="orange">{{ i18n "none" }}</a-tag></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="inbound.isQuic">
|
|
||||||
<p>quic {{ i18n "encryption" }}: <a-tag color="green">[[ inbound.quicSecurity ]]</a-tag></p>
|
|
||||||
<p>quic {{ i18n "password" }}: <a-tag color="green">[[ inbound.quicKey ]]</a-tag></p>
|
|
||||||
<p>quic {{ i18n "camouflage" }}: <a-tag color="green">[[ inbound.quicType ]]</a-tag></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="inbound.isKcp">
|
|
||||||
<p>kcp {{ i18n "encryption" }}: <a-tag color="green">[[ inbound.kcpType ]]</a-tag></p>
|
|
||||||
<p>kcp {{ i18n "password" }}: <a-tag color="green">[[ inbound.kcpSeed ]]</a-tag></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="inbound.isGrpc">
|
|
||||||
<p>grpc serviceName: <a-tag color="green">[[ inbound.serviceName ]]</a-tag></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="inbound.tls || inbound.xtls">
|
|
||||||
<p v-if="inbound.tls">tls: <a-tag color="green">{{ i18n "enabled" }}</a-tag></p>
|
|
||||||
<p v-if="inbound.xtls">xtls: <a-tag color="green">{{ i18n "enabled" }}</a-tag></p>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<p>tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag></p>
|
|
||||||
</template>
|
|
||||||
<p v-if="inbound.tls">
|
|
||||||
tls {{ i18n "domainName" }}: <a-tag :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag>
|
|
||||||
</p>
|
|
||||||
<p v-if="inbound.xtls">
|
|
||||||
xtls {{ i18n "domainName" }}: <a-tag :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag>
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
|
|
||||||
{{define "component/inboundInfoComponent"}}
|
|
||||||
<div>
|
|
||||||
<p>{{ i18n "protocol"}}: <a-tag color="green">[[ dbInbound.protocol ]]</a-tag></p>
|
|
||||||
<p>{{ i18n "pages.inbounds.address"}}: <a-tag color="blue">[[ dbInbound.address ]]</a-tag></p>
|
|
||||||
<p>{{ i18n "pages.inbounds.port"}}: <a-tag color="green">[[ dbInbound.port ]]</a-tag></p>
|
|
||||||
|
|
||||||
<template v-if="dbInbound.isVMess" v-for="(vmess, index) in inbound.settings.vmesses">
|
|
||||||
<p>uuid: <a-tag color="green">[[ vmess.id ]]</a-tag></p>
|
|
||||||
<p>alterId: <a-tag color="green">[[ vmess.alterId ]]</a-tag></p>
|
|
||||||
<a-divider style="height: 2px; background-color: #7e7e7e" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="dbInbound.isVLess" v-for="(vless, index) in inbound.settings.vlesses">
|
|
||||||
<p>uuid: <a-tag color="green">[[ vless.id ]]</a-tag></p>
|
|
||||||
<p v-if="inbound.isXTls">flow: <a-tag color="green">[[ vless.flow ]]</a-tag></p>
|
|
||||||
<a-divider style="height: 2px; background-color: #7e7e7e" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="dbInbound.isTrojan">
|
|
||||||
<p>{{ i18n "password"}}: <a-tag color="green">[[ inbound.password ]]</a-tag></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="dbInbound.isSS">
|
|
||||||
<p>{{ i18n "encryption"}}: <a-tag color="green">[[ inbound.method ]]</a-tag></p>
|
|
||||||
<p>{{ i18n "password"}}: <a-tag color="green">[[ inbound.password ]]</a-tag></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="dbInbound.isSocks">
|
|
||||||
<p>{{ i18n "username"}}: <a-tag color="green">[[ inbound.username ]]</a-tag></p>
|
|
||||||
<p>{{ i18n "password"}}: <a-tag color="green">[[ inbound.password ]]</a-tag></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="dbInbound.isHTTP">
|
|
||||||
<p>{{ i18n "username"}}: <a-tag color="green">[[ inbound.username ]]</a-tag></p>
|
|
||||||
<p>{{ i18n "password"}}: <a-tag color="green">[[ inbound.password ]]</a-tag></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="dbInbound.isVMess || dbInbound.isVLess || dbInbound.isTrojan || dbInbound.isSS">
|
|
||||||
{{template "inboundInfoStream"}}
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{define "component/inboundInfo"}}
|
|
||||||
<script>
|
|
||||||
Vue.component('inbound-info', {
|
|
||||||
delimiters: ['[[', ']]'],
|
|
||||||
props: ["dbInbound", "inbound"],
|
|
||||||
template: `{{template "component/inboundInfoComponent"}}`,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{{end}}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{{define "form/trojan"}}
|
{{define "form/trojan"}}
|
||||||
<a-form layout="inline">
|
<a-form layout="inline">
|
||||||
<label>{{ i18n "clients"}} </label>
|
<label style="color: green;">{{ i18n "clients"}}</label>
|
||||||
<a-collapse activeKey="0" v-for="(trojan, index) in inbound.settings.trojans"
|
<a-collapse activeKey="0" v-for="(trojan, index) in inbound.settings.trojans"
|
||||||
:key="`trojan-${index}`">
|
:key="`trojan-${index}`">
|
||||||
|
|
||||||
@@ -20,8 +20,11 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/> </svg>
|
xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/> </svg>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-input v-model.trim="trojan.email"></a-input>
|
<a-input v-model.trim="trojan.email" style="width: 150px;"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="Password" >
|
||||||
|
<a-input v-model.trim="trojan.password" style="width: 150px;"></a-input>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
IP Count Limit
|
IP Count Limit
|
||||||
@@ -32,7 +35,7 @@
|
|||||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-input type="number" v-model.number="trojan.limitIp" min="0" ></a-input>
|
<a-input type="number" v-model.number="trojan.limitIp" min="0" style="width: 70px;"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="trojan.email && trojan.limitIp > 0 && isEdit">
|
<a-form-item v-if="trojan.email && trojan.limitIp > 0 && isEdit">
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
@@ -53,15 +56,12 @@
|
|||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-form layout="block">
|
<a-form layout="block">
|
||||||
<a-textarea readonly @click="getDBClientIps(trojan.email,$event)" placeholder="Click To Get IPs" :auto-size="{ minRows: 0.5, maxRows: 10 }">
|
<a-textarea readonly @click="getDBClientIps(trojan.email,$event)" placeholder="Click To Get IPs" :auto-size="{ minRows: 2, maxRows: 10 }">
|
||||||
</a-textarea>
|
</a-textarea>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
<a-form-item label="Password">
|
<a-form-item v-if="inbound.XTLS" label="Flow">
|
||||||
<a-input v-model.trim="trojan.password"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item v-if="inbound.xtls" label="Flow">
|
|
||||||
<a-select v-model="trojan.flow" style="width: 150px">
|
<a-select v-model="trojan.flow" style="width: 150px">
|
||||||
<a-select-option value="">{{ i18n "none" }}</a-select-option>
|
<a-select-option value="">{{ i18n "none" }}</a-select-option>
|
||||||
<a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-date-picker :show-time="{ format: 'HH:mm' }" format="YYYY-MM-DD HH:mm"
|
<a-date-picker :show-time="{ format: 'HH:mm' }" format="YYYY-MM-DD HH:mm"
|
||||||
v-model="trojan._expiryTime" style="width: 300px;"></a-date-picker>
|
v-model="trojan._expiryTime" style="width: 170px;"></a-date-picker>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form layout="inline">
|
<a-form layout="inline">
|
||||||
<a-tooltip v-if="trojan._totalGB > 0">
|
<a-tooltip v-if="trojan._totalGB > 0">
|
||||||
@@ -123,39 +123,41 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a-tag>
|
</a-tag>
|
||||||
|
|
||||||
<a-form layout="inline">
|
<template v-if="inbound.isTcp && inbound.tls || inbound.XTLS">
|
||||||
<a-form-item label="Fallbacks">
|
<a-form layout="inline">
|
||||||
<a-row>
|
<a-form-item label="Fallbacks">
|
||||||
<a-button type="primary" size="small"
|
<a-row>
|
||||||
@click="inbound.settings.addTrojanFallback()">
|
<a-button type="primary" size="small"
|
||||||
+
|
@click="inbound.settings.addTrojanFallback()">
|
||||||
</a-button>
|
+
|
||||||
</a-row>
|
</a-button>
|
||||||
</a-form-item>
|
</a-row>
|
||||||
</a-form>
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
|
||||||
<!-- trojan fallbacks -->
|
<!-- trojan fallbacks -->
|
||||||
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" layout="inline">
|
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" layout="inline">
|
||||||
<a-divider>
|
<a-divider>
|
||||||
fallback[[ index + 1 ]]
|
fallback[[ index + 1 ]]
|
||||||
<a-icon type="delete" @click="() => inbound.settings.delTrojanFallback(index)"
|
<a-icon type="delete" @click="() => inbound.settings.delTrojanFallback(index)"
|
||||||
style="color: rgb(255, 77, 79);cursor: pointer;"/>
|
style="color: rgb(255, 77, 79);cursor: pointer;"/>
|
||||||
</a-divider>
|
</a-divider>
|
||||||
<a-form-item label="Name">
|
<a-form-item label="name">
|
||||||
<a-input v-model="fallback.name"></a-input>
|
<a-input v-model="fallback.name"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Alpn">
|
<a-form-item label="alpn">
|
||||||
<a-input v-model="fallback.alpn"></a-input>
|
<a-input v-model="fallback.alpn"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Path">
|
<a-form-item label="path">
|
||||||
<a-input v-model="fallback.path"></a-input>
|
<a-input v-model="fallback.path"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Dest">
|
<a-form-item label="dest">
|
||||||
<a-input v-model="fallback.dest"></a-input>
|
<a-input v-model="fallback.dest"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="xVer">
|
<a-form-item label="xver">
|
||||||
<a-input type="number" v-model.number="fallback.xver"></a-input>
|
<a-input type="number" v-model.number="fallback.xver"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-divider v-if="inbound.settings.fallbacks.length - 1 === index"/>
|
<a-divider v-if="inbound.settings.fallbacks.length - 1 === index"/>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
</template>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{{define "form/vless"}}
|
{{define "form/vless"}}
|
||||||
<a-form layout="inline">
|
<a-form layout="inline">
|
||||||
<label>{{ i18n "clients"}}</label>
|
<label style="color: green;">{{ i18n "clients"}}</label>
|
||||||
<a-collapse activeKey="0" v-for="(vless, index) in inbound.settings.vlesses"
|
<a-collapse activeKey="0" v-for="(vless, index) in inbound.settings.vlesses"
|
||||||
:key="`vless-${index}`">
|
:key="`vless-${index}`">
|
||||||
|
|
||||||
@@ -21,8 +21,11 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/> </svg>
|
xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/> </svg>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-input v-model.trim="vless.email"></a-input>
|
<a-input v-model.trim="vless.email" style="width: 150px;"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="ID">
|
||||||
|
<a-input v-model.trim="vless.id" style="width: 300px;" ></a-input>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
IP Count Limit
|
IP Count Limit
|
||||||
@@ -33,7 +36,7 @@
|
|||||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-input type="number" v-model.number="vless.limitIp" min="0" ></a-input>
|
<a-input type="number" v-model.number="vless.limitIp" min="0" style="width: 70px;"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="vless.email && vless.limitIp > 0 && isEdit">
|
<a-form-item v-if="vless.email && vless.limitIp > 0 && isEdit">
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
@@ -55,15 +58,12 @@
|
|||||||
</span>
|
</span>
|
||||||
<a-form layout="block">
|
<a-form layout="block">
|
||||||
|
|
||||||
<a-textarea readonly @click="getDBClientIps(vless.email,$event)" placeholder="Click To Get IPs" :auto-size="{ minRows: 0.5, maxRows: 10 }">
|
<a-textarea readonly @click="getDBClientIps(vless.email,$event)" placeholder="Click To Get IPs" :auto-size="{ minRows: 2, maxRows: 10 }">
|
||||||
</a-textarea>
|
</a-textarea>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
<a-form-item label="ID">
|
<a-form-item v-if="inbound.XTLS" label="Flow">
|
||||||
<a-input v-model.trim="vless.id"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item v-if="inbound.xtls" label="Flow">
|
|
||||||
<a-select v-model="inbound.settings.vlesses[index].flow" style="width: 150px">
|
<a-select v-model="inbound.settings.vlesses[index].flow" style="width: 150px">
|
||||||
<a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
|
<a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
|
||||||
<a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
||||||
@@ -75,11 +75,6 @@
|
|||||||
<a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="inbound.tls" label="uTLS" layout="inline">
|
|
||||||
<a-select v-model="inbound.settings.vlesses[index].fingerprint" label="uTLS" style="width: 150px">
|
|
||||||
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
<span >{{ i18n "pages.inbounds.totalFlow" }}</span>(GB)
|
<span >{{ i18n "pages.inbounds.totalFlow" }}</span>(GB)
|
||||||
@@ -137,39 +132,41 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a-tag>
|
</a-tag>
|
||||||
|
|
||||||
<a-form layout="inline">
|
<template v-if="inbound.isTcp && inbound.tls || inbound.XTLS">
|
||||||
<a-form-item label="Fallbacks">
|
<a-form layout="inline">
|
||||||
<a-row>
|
<a-form-item label="Fallbacks">
|
||||||
<a-button type="primary" size="small"
|
<a-row>
|
||||||
@click="inbound.settings.addFallback()">
|
<a-button type="primary" size="small"
|
||||||
+
|
@click="inbound.settings.addFallback()">
|
||||||
</a-button>
|
+
|
||||||
</a-row>
|
</a-button>
|
||||||
</a-form-item>
|
</a-row>
|
||||||
</a-form>
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
|
||||||
<!-- vless fallbacks -->
|
<!-- vless fallbacks -->
|
||||||
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" layout="inline">
|
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" layout="inline">
|
||||||
<a-divider>
|
<a-divider>
|
||||||
fallback[[ index + 1 ]]
|
fallback[[ index + 1 ]]
|
||||||
<a-icon type="delete" @click="() => inbound.settings.delFallback(index)"
|
<a-icon type="delete" @click="() => inbound.settings.delFallback(index)"
|
||||||
style="color: rgb(255, 77, 79);cursor: pointer;"/>
|
style="color: rgb(255, 77, 79);cursor: pointer;"/>
|
||||||
</a-divider>
|
</a-divider>
|
||||||
<a-form-item label="Name">
|
<a-form-item label="name">
|
||||||
<a-input v-model="fallback.name"></a-input>
|
<a-input v-model="fallback.name"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Alpn">
|
<a-form-item label="alpn">
|
||||||
<a-input v-model="fallback.alpn"></a-input>
|
<a-input v-model="fallback.alpn"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Path">
|
<a-form-item label="path">
|
||||||
<a-input v-model="fallback.path"></a-input>
|
<a-input v-model="fallback.path"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Dest">
|
<a-form-item label="dest">
|
||||||
<a-input v-model="fallback.dest"></a-input>
|
<a-input v-model="fallback.dest"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="xVer">
|
<a-form-item label="xver">
|
||||||
<a-input type="number" v-model.number="fallback.xver"></a-input>
|
<a-input type="number" v-model.number="fallback.xver"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-divider v-if="inbound.settings.fallbacks.length - 1 === index"/>
|
<a-divider v-if="inbound.settings.fallbacks.length - 1 === index"/>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
</template>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{{define "form/vmess"}}
|
{{define "form/vmess"}}
|
||||||
<a-form layout="inline">
|
<a-form layout="inline">
|
||||||
<label>{{ i18n "clients"}}</label>
|
<label style="color: green;">{{ i18n "clients"}}</label>
|
||||||
<a-collapse activeKey="0" v-for="(vmess, index) in inbound.settings.vmesses"
|
<a-collapse activeKey="0" v-for="(vmess, index) in inbound.settings.vmesses"
|
||||||
:key="`vmess-${index}`">
|
:key="`vmess-${index}`">
|
||||||
<a-collapse-panel :class="getHeaderStyle(vmess.email)" :header="getHeaderText(vmess.email)">
|
<a-collapse-panel :class="getHeaderStyle(vmess.email)" :header="getHeaderText(vmess.email)">
|
||||||
@@ -20,8 +20,14 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/> </svg>
|
xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="anticon anticon-question-circle" viewBox="0 0 16 16"> <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/> <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/> </svg>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-input v-model.trim="vmess.email"></a-input>
|
<a-input v-model.trim="vmess.email" style="width: 150px;"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="ID">
|
||||||
|
<a-input v-model.trim="vmess.id" style="width: 300px;" ></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='{{ i18n "additional" }} ID'>
|
||||||
|
<a-input type="number" v-model.number="vmess.alterId"></a-input>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
IP Count Limit
|
IP Count Limit
|
||||||
@@ -32,7 +38,7 @@
|
|||||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-input type="number" v-model.number="vmess.limitIp" min="0" ></a-input>
|
<a-input type="number" v-model.number="vmess.limitIp" min="0" style="width: 70px;" ></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="vmess.email && vmess.limitIp > 0 && isEdit">
|
<a-form-item v-if="vmess.email && vmess.limitIp > 0 && isEdit">
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
@@ -52,16 +58,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<a-textarea readonly @click="getDBClientIps(vmess.email,$event)" placeholder="Click To Get IPs" :auto-size="{ minRows: 0.5, maxRows: 10 }">
|
<a-textarea readonly @click="getDBClientIps(vmess.email,$event)" placeholder="Click To Get IPs" :auto-size="{ minRows: 2, maxRows: 10 }">
|
||||||
</a-textarea>
|
</a-textarea>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
<a-form-item label="ID">
|
|
||||||
<a-input v-model.trim="vmess.id"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label='{{ i18n "additional" }} ID'>
|
|
||||||
<a-input type="number" v-model.number="vmess.alterId"></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<span slot="label">
|
<span slot="label">
|
||||||
<span >{{ i18n "pages.inbounds.totalFlow" }}</span>(GB)
|
<span >{{ i18n "pages.inbounds.totalFlow" }}</span>(GB)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<a-select-option value="ws">WS</a-select-option>
|
<a-select-option value="ws">WS</a-select-option>
|
||||||
<a-select-option value="http">HTTP</a-select-option>
|
<a-select-option value="http">HTTP</a-select-option>
|
||||||
<a-select-option value="quic">QUIC</a-select-option>
|
<a-select-option value="quic">QUIC</a-select-option>
|
||||||
<a-select-option value="grpc">GRPC</a-select-option>
|
<a-select-option value="grpc">gRPC</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|||||||
@@ -5,13 +5,22 @@
|
|||||||
<a-switch v-model="inbound.tls">
|
<a-switch v-model="inbound.tls">
|
||||||
</a-switch>
|
</a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="inbound.canEnableXTls()" label="XTLS">
|
<a-form-item v-if="inbound.canEnableXTLS()" label="XTLS">
|
||||||
<a-switch v-model="inbound.xtls"></a-switch>
|
<a-switch v-model="inbound.XTLS"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|
||||||
<!-- tls settings -->
|
<!-- tls settings -->
|
||||||
<a-form v-if="inbound.tls || inbound.xtls"layout="inline">
|
<a-form v-if="inbound.tls || inbound.XTLS"layout="inline">
|
||||||
|
<a-form-item label="SNI" placeholder="Server Name Indication" v-if="inbound.tls">
|
||||||
|
<a-input v-model.trim="inbound.stream.tls.settings[0].serverName"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="CipherSuites">
|
||||||
|
<a-select v-model="inbound.stream.tls.cipherSuites" style="width: 300px">
|
||||||
|
<a-select-option value="">auto</a-select-option>
|
||||||
|
<a-select-option v-for="key in TLS_CIPHER_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item label="MinVersion">
|
<a-form-item label="MinVersion">
|
||||||
<a-select v-model="inbound.stream.tls.minVersion" style="width: 60px">
|
<a-select v-model="inbound.stream.tls.minVersion" style="width: 60px">
|
||||||
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||||
@@ -22,17 +31,22 @@
|
|||||||
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="CipherSuites">
|
<a-form-item label="uTLS" v-if="inbound.tls" >
|
||||||
<a-select v-model="inbound.stream.tls.cipherSuites" style="width: 300px">
|
<a-select v-model="inbound.stream.tls.settings[0].fingerprint" style="width: 135px">
|
||||||
<a-select-option value="">auto</a-select-option>
|
<a-select-option value=''>None</a-select-option>
|
||||||
<a-select-option v-for="key in TLS_CIPHER_OPTION" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "domainName" }}'>
|
<a-form-item label='{{ i18n "domainName" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.tls.server"></a-input>
|
<a-input v-model.trim="inbound.stream.tls.server"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Alpn">
|
<a-form-item label="Alpn">
|
||||||
<a-input v-model.trim="inbound.stream.tls.alpn"></a-input>
|
<a-checkbox-group v-model="inbound.stream.tls.alpn" style="width:200px">
|
||||||
|
<a-checkbox v-for="key in ALPN_OPTION" :value="key">[[ key ]]</a-checkbox>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Allow insecure">
|
||||||
|
<a-switch v-model="inbound.stream.tls.settings[0].allowInsecure"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "certificate" }}'>
|
<a-form-item label='{{ i18n "certificate" }}'>
|
||||||
<a-radio-group v-model="inbound.stream.tls.certs[0].useFile" button-style="solid">
|
<a-radio-group v-model="inbound.stream.tls.certs[0].useFile" button-style="solid">
|
||||||
@@ -42,18 +56,18 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<template v-if="inbound.stream.tls.certs[0].useFile">
|
<template v-if="inbound.stream.tls.certs[0].useFile">
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.publicKeyPath" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.publicKeyPath" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.tls.certs[0].certFile"></a-input>
|
<a-input v-model.trim="inbound.stream.tls.certs[0].certFile" style="width:300px;"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.keyPath" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.keyPath" }}'>
|
||||||
<a-input v-model.trim="inbound.stream.tls.certs[0].keyFile"></a-input>
|
<a-input v-model.trim="inbound.stream.tls.certs[0].keyFile" style="width:300px;"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.publicKeyContent" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.publicKeyContent" }}'>
|
||||||
<a-input type="textarea" :rows="2" v-model="inbound.stream.tls.certs[0].cert"></a-input>
|
<a-input type="textarea" :rows="3" style="width:300px;" v-model="inbound.stream.tls.certs[0].cert"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label='{{ i18n "pages.inbounds.keyContent" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.keyContent" }}'>
|
||||||
<a-input type="textarea" :rows="2" v-model="inbound.stream.tls.certs[0].key"></a-input>
|
<a-input type="textarea" :rows="3" style="width:300px;" v-model="inbound.stream.tls.certs[0].key"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}'
|
v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}'
|
||||||
:closable="true"
|
:closable="true"
|
||||||
:mask-closable="true"
|
:mask-closable="true"
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
width="600px"
|
width="600px"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{{define "inboundModal"}}
|
{{define "inboundModal"}}
|
||||||
<a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" @ok="inModal.ok"
|
<a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" @ok="inModal.ok"
|
||||||
:confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false"
|
:confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false"
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
:ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'>
|
:ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'>
|
||||||
{{template "form/inbound"}}
|
{{template "form/inbound"}}
|
||||||
</a-modal>
|
</a-modal>
|
||||||
@@ -88,22 +89,18 @@
|
|||||||
removeClient(index, clients) {
|
removeClient(index, clients) {
|
||||||
clients.splice(index, 1);
|
clients.splice(index, 1);
|
||||||
},
|
},
|
||||||
async getDBClientIps(email,event) {
|
async getDBClientIps(email, event) {
|
||||||
|
const msg = await HttpUtil.post('/xui/inbound/clientIps/' + email);
|
||||||
const msg = await HttpUtil.post('/xui/inbound/clientIps/'+ email);
|
if (!msg.success) {
|
||||||
if (!msg.success) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
try {
|
||||||
try {
|
let ips = JSON.parse(msg.obj);
|
||||||
ips = JSON.parse(msg.obj)
|
ips = ips.join(",");
|
||||||
ips = ips.join(",")
|
event.target.value = ips;
|
||||||
event.target.value = ips
|
} catch (error) {
|
||||||
} catch (error) {
|
event.target.value = msg.obj;
|
||||||
// text
|
}
|
||||||
event.target.value = msg.obj
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
},
|
||||||
async clearDBClientIps(email,event) {
|
async clearDBClientIps(email,event) {
|
||||||
const msg = await HttpUtil.post('/xui/inbound/clearClientIps/'+ email);
|
const msg = await HttpUtil.post('/xui/inbound/clearClientIps/'+ email);
|
||||||
@@ -112,20 +109,19 @@
|
|||||||
}
|
}
|
||||||
event.target.value = ""
|
event.target.value = ""
|
||||||
},
|
},
|
||||||
async resetClientTraffic(client,event) {
|
async resetClientTraffic(client, event) {
|
||||||
const msg = await HttpUtil.post('/xui/inbound/resetClientTraffic/'+ client.email);
|
const msg = await HttpUtil.post(`/xui/inbound/resetClientTraffic/${client.email}`);
|
||||||
if (!msg.success) {
|
if (!msg.success) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clientStats = this.inbound.clientStats
|
const clientStats = this.inbound.clientStats;
|
||||||
if(clientStats.length > 0)
|
if (clientStats.length > 0) {
|
||||||
{
|
for (let i = 0; i < clientStats.length; i++) {
|
||||||
for (const key in clientStats) {
|
if (clientStats[i].email === client.email) {
|
||||||
if (Object.hasOwnProperty.call(clientStats, key)) {
|
clientStats[i].up = 0;
|
||||||
if(clientStats[key]['email'] == client.email){
|
clientStats[i].down = 0;
|
||||||
clientStats[key]['up'] = 0
|
break; // Stop looping once we've found the matching client.
|
||||||
clientStats[key]['down'] = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<a-layout id="app" v-cloak>
|
<a-layout id="app" v-cloak>
|
||||||
{{ template "commonSider" . }}
|
{{ template "commonSider" . }}
|
||||||
<a-layout id="content-layout">
|
<a-layout id="content-layout" :style="siderDrawer.isDarkTheme ? bgDarkStyle : ''">
|
||||||
<a-layout-content>
|
<a-layout-content>
|
||||||
<a-spin :spinning="spinning" :delay="500" tip="loading">
|
<a-spin :spinning="spinning" :delay="500" tip="loading">
|
||||||
<transition name="list" appear>
|
<transition name="list" appear>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</a-tag>
|
</a-tag>
|
||||||
</transition>
|
</transition>
|
||||||
<transition name="list" appear>
|
<transition name="list" appear>
|
||||||
<a-card hoverable style="margin-bottom: 20px;">
|
<a-card hoverable style="margin-bottom: 20px;" :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :xs="24" :sm="24" :lg="12">
|
<a-col :xs="24" :sm="24" :lg="12">
|
||||||
{{ i18n "pages.inbounds.totalDownUp" }}:
|
{{ i18n "pages.inbounds.totalDownUp" }}:
|
||||||
@@ -38,11 +38,17 @@
|
|||||||
{{ i18n "pages.inbounds.inboundCount" }}:
|
{{ i18n "pages.inbounds.inboundCount" }}:
|
||||||
<a-tag color="green">[[ dbInbounds.length ]]</a-tag>
|
<a-tag color="green">[[ dbInbounds.length ]]</a-tag>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
<a-col :xs="24" :sm="24" :lg="12">
|
||||||
|
{{ i18n "clients" }}:
|
||||||
|
<a-tag color="green">[[ total.clients ]]</a-tag>
|
||||||
|
<a-tag color="blue">{{ i18n "enabled" }} [[ total.active ]]</a-tag>
|
||||||
|
<a-tag color="red">{{ i18n "disabled" }} [[ total.deactive ]]</a-tag>
|
||||||
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-card>
|
</a-card>
|
||||||
</transition>
|
</transition>
|
||||||
<transition name="list" appear>
|
<transition name="list" appear>
|
||||||
<a-card hoverable>
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
<div slot="title">
|
<div slot="title">
|
||||||
<a-button type="primary" @click="openAddInbound">Add Inbound</a-button>
|
<a-button type="primary" @click="openAddInbound">Add Inbound</a-button>
|
||||||
<a-button type="primary" @click="exportAllLinks" class="copy-btn">Export Links</a-button>
|
<a-button type="primary" @click="exportAllLinks" class="copy-btn">Export Links</a-button>
|
||||||
@@ -67,6 +73,12 @@
|
|||||||
<a-icon type="edit"></a-icon>
|
<a-icon type="edit"></a-icon>
|
||||||
{{ i18n "edit" }}
|
{{ i18n "edit" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
<template v-if="dbInbound.isTrojan || dbInbound.isVLess || dbInbound.isVMess">
|
||||||
|
<a-menu-item key="export">
|
||||||
|
<a-icon type="export"></a-icon>
|
||||||
|
{{ i18n "pages.inbounds.export"}}
|
||||||
|
</a-menu-item>
|
||||||
|
</template>
|
||||||
<a-menu-item key="resetTraffic">
|
<a-menu-item key="resetTraffic">
|
||||||
<a-icon type="retweet"></a-icon> {{ i18n "pages.inbounds.resetTraffic" }}
|
<a-icon type="retweet"></a-icon> {{ i18n "pages.inbounds.resetTraffic" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -202,7 +214,7 @@
|
|||||||
{ title: '{{ i18n "pages.inbounds.client" }}', width: 60, scopedSlots: { customRender: 'client' } },
|
{ title: '{{ i18n "pages.inbounds.client" }}', width: 60, scopedSlots: { customRender: 'client' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 100, scopedSlots: { customRender: 'traffic' } },
|
{ title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 100, scopedSlots: { customRender: 'traffic' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
|
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
|
||||||
{ title: 'UID', width: 120, dataIndex: "id" },
|
{ title: 'UID', width: 150, dataIndex: "id" },
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -281,6 +293,9 @@
|
|||||||
case "qrcode":
|
case "qrcode":
|
||||||
this.showQrcode(dbInbound);
|
this.showQrcode(dbInbound);
|
||||||
break;
|
break;
|
||||||
|
case "export":
|
||||||
|
this.inboundLinks(dbInbound.id);
|
||||||
|
break;
|
||||||
case "edit":
|
case "edit":
|
||||||
this.openEditInbound(dbInbound.id);
|
this.openEditInbound(dbInbound.id);
|
||||||
break;
|
break;
|
||||||
@@ -372,18 +387,6 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
exportAllLinks() {
|
|
||||||
let copyText = '';
|
|
||||||
for (const dbInbound of this.dbInbounds) {
|
|
||||||
copyText += dbInbound.genInboundLinks
|
|
||||||
}
|
|
||||||
const clipboard = new ClipboardJS('.copy-btn', {
|
|
||||||
text: function () {
|
|
||||||
return copyText;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
clipboard.on('success', () => { this.$message.success('Export Links succeed'); });
|
|
||||||
},
|
|
||||||
delInbound(dbInbound) {
|
delInbound(dbInbound) {
|
||||||
this.$confirm({
|
this.$confirm({
|
||||||
title: '{{ i18n "pages.inbounds.deleteInbound"}}',
|
title: '{{ i18n "pages.inbounds.deleteInbound"}}',
|
||||||
@@ -393,7 +396,15 @@
|
|||||||
onOk: () => this.submit('/xui/inbound/del/' + dbInbound.id),
|
onOk: () => this.submit('/xui/inbound/del/' + dbInbound.id),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
showQrcode(dbInbound, clientIndex) {
|
getClients(protocol, clientSettings) {
|
||||||
|
switch(protocol){
|
||||||
|
case Protocols.VMESS: return clientSettings.vmesses;
|
||||||
|
case Protocols.VLESS: return clientSettings.vlesses;
|
||||||
|
case Protocols.TROJAN: return clientSettings.trojans;
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showQrcode(dbInbound, clientIndex) {
|
||||||
const link = dbInbound.genLink(clientIndex);
|
const link = dbInbound.genLink(clientIndex);
|
||||||
qrModal.show('{{ i18n "qrCode"}}', link, dbInbound);
|
qrModal.show('{{ i18n "qrCode"}}', link, dbInbound);
|
||||||
},
|
},
|
||||||
@@ -451,60 +462,34 @@
|
|||||||
return dbInbound.toInbound().isExpiry(index)
|
return dbInbound.toInbound().isExpiry(index)
|
||||||
},
|
},
|
||||||
getUpStats(dbInbound, email) {
|
getUpStats(dbInbound, email) {
|
||||||
clientStats = dbInbound.clientStats
|
if(email.length == 0) return 0
|
||||||
if(clientStats.length > 0)
|
clientStats = dbInbound.clientStats.find(stats => stats.email === email)
|
||||||
{
|
return clientStats ? clientStats.up : 0
|
||||||
for (const key in clientStats) {
|
|
||||||
if (Object.hasOwnProperty.call(clientStats, key)) {
|
|
||||||
if(clientStats[key]['email'] == email)
|
|
||||||
return clientStats[key]['up']
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
},
|
||||||
getDownStats(dbInbound, email) {
|
getDownStats(dbInbound, email) {
|
||||||
clientStats = dbInbound.clientStats
|
if(email.length == 0) return 0
|
||||||
if(clientStats.length > 0)
|
clientStats = dbInbound.clientStats.find(stats => stats.email === email)
|
||||||
{
|
return clientStats ? clientStats.down : 0
|
||||||
for (const key in clientStats) {
|
|
||||||
if (Object.hasOwnProperty.call(clientStats, key)) {
|
|
||||||
if(clientStats[key]['email'] == email)
|
|
||||||
return clientStats[key]['down']
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
isTrafficExhausted(dbInbound, email) {
|
isTrafficExhausted(dbInbound, email) {
|
||||||
clientStats = dbInbound.clientStats
|
if(email.length == 0) return false
|
||||||
if(clientStats.length > 0)
|
clientStats = dbInbound.clientStats.find(stats => stats.email === email)
|
||||||
{
|
return clientStats ? clientStats.down + clientStats.up > clientStats.total : false
|
||||||
for (const key in clientStats) {
|
},
|
||||||
if (Object.hasOwnProperty.call(clientStats, key)) {
|
inboundLinks(dbInboundId) {
|
||||||
if(clientStats[key]['email'] == email)
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
return clientStats[key]['down']+clientStats[key]['up'] > clientStats[key]['total']
|
txtModal.show('{{ i18n "pages.inbounds.export"}}',dbInbound.genInboundLinks,dbInbound.remark);
|
||||||
|
},
|
||||||
}
|
exportAllLinks() {
|
||||||
}
|
let copyText = '';
|
||||||
|
for (const dbInbound of this.dbInbounds) {
|
||||||
|
copyText += dbInbound.genInboundLinks
|
||||||
}
|
}
|
||||||
|
txtModal.show('{{ i18n "pages.inbounds.export"}}',copyText,'All-Inbounds');
|
||||||
},
|
},
|
||||||
isClientEnabled(dbInbound, email) {
|
isClientEnabled(dbInbound, email) {
|
||||||
clientStats = dbInbound.clientStats
|
clientStats = dbInbound.clientStats ? dbInbound.clientStats.find(stats => stats.email === email) : null
|
||||||
if(clientStats.length > 0)
|
return clientStats ? clientStats['enable'] : true
|
||||||
{
|
|
||||||
for (const key in clientStats) {
|
|
||||||
if (Object.hasOwnProperty.call(clientStats, key)) {
|
|
||||||
if(clientStats[key]['email'] == email)
|
|
||||||
return clientStats[key]['enable']
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -518,13 +503,32 @@
|
|||||||
computed: {
|
computed: {
|
||||||
total() {
|
total() {
|
||||||
let down = 0, up = 0;
|
let down = 0, up = 0;
|
||||||
for (let i = 0; i < this.dbInbounds.length; ++i) {
|
let clients = 0, active = 0, deactive = 0;
|
||||||
down += this.dbInbounds[i].down;
|
this.dbInbounds.forEach(dbInbound => {
|
||||||
up += this.dbInbounds[i].up;
|
down += dbInbound.down;
|
||||||
}
|
up += dbInbound.up;
|
||||||
|
inbound = dbInbound.toInbound();
|
||||||
|
clients = this.getClients(dbInbound.protocol, inbound.settings);
|
||||||
|
if(clients){
|
||||||
|
if(dbInbound.enable){
|
||||||
|
isClientEnable = false;
|
||||||
|
clients.forEach(client => {
|
||||||
|
isClientEnable = client.email == "" ? true: this.isClientEnabled(dbInbound,client.email);
|
||||||
|
isClientEnable ? active++ : deactive++;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
deactive += clients.length;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dbInbound.enable ? active++ : deactive++;
|
||||||
|
}
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
down: down,
|
down: down,
|
||||||
up: up,
|
up: up,
|
||||||
|
clients: active + deactive,
|
||||||
|
active: active,
|
||||||
|
deactive: deactive,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,24 +15,26 @@
|
|||||||
<body>
|
<body>
|
||||||
<a-layout id="app" v-cloak>
|
<a-layout id="app" v-cloak>
|
||||||
{{ template "commonSider" . }}
|
{{ template "commonSider" . }}
|
||||||
<a-layout id="content-layout">
|
<a-layout id="content-layout" :style="siderDrawer.isDarkTheme ? bgDarkStyle : ''">
|
||||||
<a-layout-content>
|
<a-layout-content>
|
||||||
<a-spin :spinning="spinning" :delay="200" :tip="loadingTip"/>
|
<a-spin :spinning="spinning" :delay="200" :tip="loadingTip"/>
|
||||||
<transition name="list" appear>
|
<transition name="list" appear>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-card hoverable>
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="12" style="text-align: center">
|
<a-col :span="12" style="text-align: center">
|
||||||
<a-progress type="dashboard" status="normal"
|
<a-progress type="dashboard" status="normal"
|
||||||
:stroke-color="status.cpu.color"
|
:stroke-color="status.cpu.color"
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
:percent="status.cpu.percent"></a-progress>
|
:percent="status.cpu.percent"></a-progress>
|
||||||
<div>CPU</div>
|
<div>CPU</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12" style="text-align: center">
|
<a-col :span="12" style="text-align: center">
|
||||||
<a-progress type="dashboard" status="normal"
|
<a-progress type="dashboard" status="normal"
|
||||||
:stroke-color="status.mem.color"
|
:stroke-color="status.mem.color"
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
:percent="status.mem.percent"></a-progress>
|
:percent="status.mem.percent"></a-progress>
|
||||||
<div>
|
<div>
|
||||||
{{ i18n "pages.index.memory"}}: [[ sizeFormat(status.mem.current) ]] / [[ sizeFormat(status.mem.total) ]]
|
{{ i18n "pages.index.memory"}}: [[ sizeFormat(status.mem.current) ]] / [[ sizeFormat(status.mem.total) ]]
|
||||||
@@ -45,6 +47,7 @@
|
|||||||
<a-col :span="12" style="text-align: center">
|
<a-col :span="12" style="text-align: center">
|
||||||
<a-progress type="dashboard" status="normal"
|
<a-progress type="dashboard" status="normal"
|
||||||
:stroke-color="status.swap.color"
|
:stroke-color="status.swap.color"
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
:percent="status.swap.percent"></a-progress>
|
:percent="status.swap.percent"></a-progress>
|
||||||
<div>
|
<div>
|
||||||
Swap: [[ sizeFormat(status.swap.current) ]] / [[ sizeFormat(status.swap.total) ]]
|
Swap: [[ sizeFormat(status.swap.current) ]] / [[ sizeFormat(status.swap.total) ]]
|
||||||
@@ -53,6 +56,7 @@
|
|||||||
<a-col :span="12" style="text-align: center">
|
<a-col :span="12" style="text-align: center">
|
||||||
<a-progress type="dashboard" status="normal"
|
<a-progress type="dashboard" status="normal"
|
||||||
:stroke-color="status.disk.color"
|
:stroke-color="status.disk.color"
|
||||||
|
:class="siderDrawer.isDarkTheme ? darkClass : ''"
|
||||||
:percent="status.disk.percent"></a-progress>
|
:percent="status.disk.percent"></a-progress>
|
||||||
<div>
|
<div>
|
||||||
{{ i18n "pages.index.hard"}}: [[ sizeFormat(status.disk.current) ]] / [[ sizeFormat(status.disk.total) ]]
|
{{ i18n "pages.index.hard"}}: [[ sizeFormat(status.disk.current) ]] / [[ sizeFormat(status.disk.total) ]]
|
||||||
@@ -67,7 +71,7 @@
|
|||||||
<transition name="list" appear>
|
<transition name="list" appear>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
{{ i18n "pages.index.xrayStatus" }}:
|
{{ i18n "pages.index.xrayStatus" }}:
|
||||||
<a-tag :color="status.xray.color">[[ status.xray.state ]]</a-tag>
|
<a-tag :color="status.xray.color">[[ status.xray.state ]]</a-tag>
|
||||||
<a-tooltip v-if="status.xray.state === State.Error">
|
<a-tooltip v-if="status.xray.state === State.Error">
|
||||||
@@ -76,14 +80,16 @@
|
|||||||
</template>
|
</template>
|
||||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tag color="green" @click="openSelectV2rayVersion">[[ status.xray.version ]]</a-tag>
|
<a-tag color="green" style="cursor: pointer;" @click="openSelectV2rayVersion">[[ status.xray.version ]]</a-tag>
|
||||||
<a-tag color="blue" @click="openSelectV2rayVersion">{{ i18n "pages.index.xraySwitch"}}</a-tag>
|
<a-tag color="blue" style="cursor: pointer;" @click="stopXrayService">{{ i18n "pages.index.stopXray" }}</a-tag>
|
||||||
|
<a-tag color="blue" style="cursor: pointer;" @click="restartXrayService">{{ i18n "pages.index.restartXray" }}</a-tag>
|
||||||
|
<a-tag color="blue" style="cursor: pointer;" @click="openSelectV2rayVersion">{{ i18n "pages.index.xraySwitch" }}</a-tag>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
{{ i18n "pages.index.operationHours" }}:
|
{{ i18n "pages.index.operationHours" }}:
|
||||||
<a-tag color="#87d068">[[ formatSecond(status.uptime) ]]</a-tag>
|
<a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ i18n "pages.index.operationHoursDesc" }}
|
{{ i18n "pages.index.operationHoursDesc" }}
|
||||||
@@ -93,12 +99,12 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
{{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]]
|
{{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]]
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
TCP / UDP {{ i18n "pages.index.connectionCount" }}: [[ status.tcpCount ]] / [[ status.udpCount ]]
|
TCP / UDP {{ i18n "pages.index.connectionCount" }}: [[ status.tcpCount ]] / [[ status.udpCount ]]
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
@@ -109,7 +115,7 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<a-icon type="arrow-up"></a-icon>
|
<a-icon type="arrow-up"></a-icon>
|
||||||
@@ -135,7 +141,7 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<a-icon type="cloud-upload"></a-icon>
|
<a-icon type="cloud-upload"></a-icon>
|
||||||
@@ -315,6 +321,24 @@
|
|||||||
this.loading(false);
|
this.loading(false);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
//here add stop xray function
|
||||||
|
async stopXrayService() {
|
||||||
|
this.loading(true);
|
||||||
|
const msg = await HttpUtil.post('server/stopXrayService');
|
||||||
|
this.loading(false);
|
||||||
|
if (!msg.success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//here add restart xray function
|
||||||
|
async restartXrayService() {
|
||||||
|
this.loading(true);
|
||||||
|
const msg = await HttpUtil.post('server/restartXrayService');
|
||||||
|
this.loading(false);
|
||||||
|
if (!msg.success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
|||||||
@@ -20,14 +20,14 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-tabs-top-bar {
|
:not(.ant-card-dark)>.ant-tabs-top-bar {
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<body>
|
<body>
|
||||||
<a-layout id="app" v-cloak>
|
<a-layout id="app" v-cloak>
|
||||||
{{ template "commonSider" . }}
|
{{ template "commonSider" . }}
|
||||||
<a-layout id="content-layout">
|
<a-layout id="content-layout" :style="siderDrawer.isDarkTheme ? bgDarkStyle : ''">
|
||||||
<a-layout-content>
|
<a-layout-content>
|
||||||
<a-spin :spinning="spinning" :delay="500" tip="loading">
|
<a-spin :spinning="spinning" :delay="500" tip="loading">
|
||||||
<a-space direction="vertical">
|
<a-space direction="vertical">
|
||||||
@@ -35,17 +35,17 @@
|
|||||||
<a-button type="primary" :disabled="saveBtnDisable" @click="updateAllSetting">{{ i18n "pages.setting.save" }}</a-button>
|
<a-button type="primary" :disabled="saveBtnDisable" @click="updateAllSetting">{{ i18n "pages.setting.save" }}</a-button>
|
||||||
<a-button type="danger" :disabled="!saveBtnDisable" @click="restartPanel">{{ i18n "pages.setting.restartPanel" }}</a-button>
|
<a-button type="danger" :disabled="!saveBtnDisable" @click="restartPanel">{{ i18n "pages.setting.restartPanel" }}</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
<a-tabs default-active-key="1">
|
<a-tabs default-active-key="1" :class="siderDrawer.isDarkTheme ? darkClass : ''">
|
||||||
<a-tab-pane key="1" tab='{{ i18n "pages.setting.panelConfig"}}'>
|
<a-tab-pane key="1" tab='{{ i18n "pages.setting.panelConfig"}}'>
|
||||||
|
|
||||||
<a-list item-layout="horizontal" style="background: white">
|
<a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'">
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.setting.panelListeningIP"}}' desc='{{ i18n "pages.setting.panelListeningIPDesc"}}' v-model="allSetting.webListen"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.setting.panelListeningIP"}}' desc='{{ i18n "pages.setting.panelListeningIPDesc"}}' v-model="allSetting.webListen"></setting-list-item>
|
||||||
<setting-list-item type="number" title='{{ i18n "pages.setting.panelPort"}}' desc='{{ i18n "pages.setting.panelPortDesc"}}' v-model.number="allSetting.webPort"></setting-list-item>
|
<setting-list-item type="number" title='{{ i18n "pages.setting.panelPort"}}' desc='{{ i18n "pages.setting.panelPortDesc"}}' v-model.number="allSetting.webPort"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.setting.publicKeyPath"}}' desc='{{ i18n "pages.setting.publicKeyPathDesc"}}' v-model="allSetting.webCertFile"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.setting.publicKeyPath"}}' desc='{{ i18n "pages.setting.publicKeyPathDesc"}}' v-model="allSetting.webCertFile"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.setting.privateKeyPath"}}' desc='{{ i18n "pages.setting.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.setting.privateKeyPath"}}' desc='{{ i18n "pages.setting.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.setting.panelUrlPath"}}' desc='{{ i18n "pages.setting.panelUrlPathDesc"}}' v-model="allSetting.webBasePath"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.setting.panelUrlPath"}}' desc='{{ i18n "pages.setting.panelUrlPathDesc"}}' v-model="allSetting.webBasePath"></setting-list-item>
|
||||||
<a-list-item>
|
<a-list-item>
|
||||||
<a-row style="padding: 20px">
|
<a-row style="padding: 20px">
|
||||||
<a-col :lg="24" :xl="12">
|
<a-col :lg="24" :xl="12">
|
||||||
<a-list-item-meta title="Language"/>
|
<a-list-item-meta title="Language"/>
|
||||||
</a-col>
|
</a-col>
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
@change="setLang(lang)"
|
@change="setLang(lang)"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
<a-select-option :value="l.value" label="China" v-for="l in supportLangs" >
|
<a-select-option :value="l.value" :label="l.value" v-for="l in supportLangs">
|
||||||
<span role="img" aria-label="l.name" v-text="l.icon"></span>
|
<span role="img" aria-label="l.name" v-text="l.icon"></span>
|
||||||
<span v-text="l.name"></span>
|
<span v-text="l.name"></span>
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
</a-list>
|
</a-list>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="2" tab='{{ i18n "pages.setting.userSetting"}}'>
|
<a-tab-pane key="2" tab='{{ i18n "pages.setting.userSetting"}}'>
|
||||||
<a-form style="background: white; padding: 20px">
|
<a-form :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65); padding: 20px;': 'background: white; padding: 20px;'">
|
||||||
<a-form-item label='{{ i18n "pages.setting.oldUsername"}}'>
|
<a-form-item label='{{ i18n "pages.setting.oldUsername"}}'>
|
||||||
<a-input v-model="user.oldUsername" style="max-width: 300px"></a-input>
|
<a-input v-model="user.oldUsername" style="max-width: 300px"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -93,12 +93,12 @@
|
|||||||
</a-form>
|
</a-form>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="3" tab='{{ i18n "pages.setting.xrayConfiguration"}}'>
|
<a-tab-pane key="3" tab='{{ i18n "pages.setting.xrayConfiguration"}}'>
|
||||||
<a-list item-layout="horizontal" style="background: white">
|
<a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'">
|
||||||
<setting-list-item type="textarea" title='{{ i18n "pages.setting.xrayConfigTemplate"}}' desc='{{ i18n "pages.setting.xrayConfigTemplateDesc"}}' v-model="allSetting.xrayTemplateConfig"></setting-list-item>
|
<setting-list-item type="textarea" title='{{ i18n "pages.setting.xrayConfigTemplate"}}' desc='{{ i18n "pages.setting.xrayConfigTemplateDesc"}}' v-model="allSetting.xrayTemplateConfig"></setting-list-item>
|
||||||
</a-list>
|
</a-list>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="4" tab='{{ i18n "pages.setting.TGReminder"}}'>
|
<a-tab-pane key="4" tab='{{ i18n "pages.setting.TGReminder"}}'>
|
||||||
<a-list item-layout="horizontal" style="background: white">
|
<a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'">
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.setting.telegramBotEnable" }}' desc='{{ i18n "pages.setting.telegramBotEnableDesc" }}' v-model="allSetting.tgBotEnable"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.setting.telegramBotEnable" }}' desc='{{ i18n "pages.setting.telegramBotEnableDesc" }}' v-model="allSetting.tgBotEnable"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.setting.telegramToken"}}' desc='{{ i18n "pages.setting.telegramTokenDesc"}}' v-model="allSetting.tgBotToken"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.setting.telegramToken"}}' desc='{{ i18n "pages.setting.telegramTokenDesc"}}' v-model="allSetting.tgBotToken"></setting-list-item>
|
||||||
<setting-list-item type="number" title='{{ i18n "pages.setting.telegramChatId"}}' desc='{{ i18n "pages.setting.telegramChatIdDesc"}}' v-model.number="allSetting.tgBotChatId"></setting-list-item>
|
<setting-list-item type="number" title='{{ i18n "pages.setting.telegramChatId"}}' desc='{{ i18n "pages.setting.telegramChatIdDesc"}}' v-model.number="allSetting.tgBotChatId"></setting-list-item>
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
</a-list>
|
</a-list>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="5" tab='{{ i18n "pages.setting.otherSetting"}}'>
|
<a-tab-pane key="5" tab='{{ i18n "pages.setting.otherSetting"}}'>
|
||||||
<a-list item-layout="horizontal" style="background: white">
|
<a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'">
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.setting.timeZonee"}}' desc='{{ i18n "pages.setting.timeZoneDesc"}}' v-model="allSetting.timeLocation"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.setting.timeZonee"}}' desc='{{ i18n "pages.setting.timeZoneDesc"}}' v-model="allSetting.timeLocation"></setting-list-item>
|
||||||
</a-list>
|
</a-list>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
|||||||
@@ -275,15 +275,18 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e
|
|||||||
|
|
||||||
for _, traffic := range traffics {
|
for _, traffic := range traffics {
|
||||||
inbound := &model.Inbound{}
|
inbound := &model.Inbound{}
|
||||||
|
client := &xray.ClientTraffic{}
|
||||||
err := txInbound.Where("settings like ?", "%"+traffic.Email+"%").First(inbound).Error
|
err := tx.Where("email = ?", traffic.Email).First(client).Error
|
||||||
traffic.InboundId = inbound.Id
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
// delete removed client record
|
logger.Warning(err, traffic.Email)
|
||||||
clientErr := s.DelClientStat(tx, traffic.Email)
|
}
|
||||||
logger.Warning(err, traffic.Email, clientErr)
|
continue
|
||||||
|
}
|
||||||
|
err = txInbound.Where("id=?", client.InboundId).First(inbound).Error
|
||||||
|
if err != nil {
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
logger.Warning(err, traffic.Email)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,6 +198,30 @@ func (s *ServerService) GetXrayVersions() ([]string, error) {
|
|||||||
return versions, nil
|
return versions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ServerService) StopXrayService() (string error) {
|
||||||
|
|
||||||
|
err := s.xrayService.StopXray()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("stop xray failed:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServerService) RestartXrayService() (string error) {
|
||||||
|
|
||||||
|
s.xrayService.StopXray()
|
||||||
|
defer func() {
|
||||||
|
err := s.xrayService.RestartXray(true)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("start xray failed:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ServerService) downloadXRay(version string) (string, error) {
|
func (s *ServerService) downloadXRay(version string) (string, error) {
|
||||||
osName := runtime.GOOS
|
osName := runtime.GOOS
|
||||||
arch := runtime.GOARCH
|
arch := runtime.GOARCH
|
||||||
|
|||||||
@@ -71,6 +71,8 @@
|
|||||||
"hard" = "Hard Disk"
|
"hard" = "Hard Disk"
|
||||||
"xrayStatus" = "Xray Status"
|
"xrayStatus" = "Xray Status"
|
||||||
"xraySwitch" = "Switch Version"
|
"xraySwitch" = "Switch Version"
|
||||||
|
"restartXray" = "Restart"
|
||||||
|
"stopXray" = "Stop"
|
||||||
"xraySwitchClick" = "Click on the version you want to switch"
|
"xraySwitchClick" = "Click on the version you want to switch"
|
||||||
"xraySwitchClickDesk" = "Please choose carefully, older versions may have incompatible configurations"
|
"xraySwitchClickDesk" = "Please choose carefully, older versions may have incompatible configurations"
|
||||||
"operationHours" = "Operation Hours"
|
"operationHours" = "Operation Hours"
|
||||||
@@ -87,6 +89,7 @@
|
|||||||
"dontRefreshh" = "Installation is in progress, please do not refresh this page"
|
"dontRefreshh" = "Installation is in progress, please do not refresh this page"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"export" = "Export"
|
||||||
"title" = "Inbounds"
|
"title" = "Inbounds"
|
||||||
"totalDownUp" = "Total Uploads/Downloads"
|
"totalDownUp" = "Total Uploads/Downloads"
|
||||||
"totalUsage" = "Total Usage"
|
"totalUsage" = "Total Usage"
|
||||||
@@ -121,10 +124,10 @@
|
|||||||
"noRecommendKeepDefault" = "There are no special requirements to keep the default"
|
"noRecommendKeepDefault" = "There are no special requirements to keep the default"
|
||||||
"certificatePath" = "Certificate File Path"
|
"certificatePath" = "Certificate File Path"
|
||||||
"certificateContent" = "Certificate File Content"
|
"certificateContent" = "Certificate File Content"
|
||||||
"publicKeyPath" = "Public Key File Path"
|
"publicKeyPath" = "Public Key Path"
|
||||||
"publicKeyContent" = "public Key Content"
|
"publicKeyContent" = "public Key Content"
|
||||||
"keyPath" = "Key File Path"
|
"keyPath" = "Private key Path"
|
||||||
"keyContent" = "Key Content"
|
"keyContent" = "Private Key Content"
|
||||||
"client" = "Client"
|
"client" = "Client"
|
||||||
"uid" = "UID"
|
"uid" = "UID"
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,8 @@
|
|||||||
"hard" = "حافظه دیسک"
|
"hard" = "حافظه دیسک"
|
||||||
"xrayStatus" = "وضعیت Xray"
|
"xrayStatus" = "وضعیت Xray"
|
||||||
"xraySwitch" = "تغییر ورژن"
|
"xraySwitch" = "تغییر ورژن"
|
||||||
|
"restartXray" = "راه اندازی مجدد"
|
||||||
|
"stopXray" = "توقف"
|
||||||
"xraySwitchClick" = "ورژن مورد نظر را انتخاب کنید"
|
"xraySwitchClick" = "ورژن مورد نظر را انتخاب کنید"
|
||||||
"xraySwitchClickDesk" = "لطفا با دقت انتخاب کنید ، در صورت انتخاب اشتباه امکان قطعی سیستم وجود دارد ."
|
"xraySwitchClickDesk" = "لطفا با دقت انتخاب کنید ، در صورت انتخاب اشتباه امکان قطعی سیستم وجود دارد ."
|
||||||
"operationHours" = "ساعت فعال"
|
"operationHours" = "ساعت فعال"
|
||||||
@@ -88,6 +90,7 @@
|
|||||||
|
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"export" = "استخراج لینکها"
|
||||||
"title" = "کاربران"
|
"title" = "کاربران"
|
||||||
"totalDownUp" = "جمع آپلود/دانلود"
|
"totalDownUp" = "جمع آپلود/دانلود"
|
||||||
"totalUsage" = "جمع کل"
|
"totalUsage" = "جمع کل"
|
||||||
|
|||||||
@@ -70,6 +70,8 @@
|
|||||||
"hard" = "硬盘"
|
"hard" = "硬盘"
|
||||||
"xrayStatus" = "xray 状态"
|
"xrayStatus" = "xray 状态"
|
||||||
"xraySwitch" = "切换版本"
|
"xraySwitch" = "切换版本"
|
||||||
|
"restartXray" = "重新开始"
|
||||||
|
"stopXray" = "停止"
|
||||||
"xraySwitchClick" = "点击你想切换的版本"
|
"xraySwitchClick" = "点击你想切换的版本"
|
||||||
"xraySwitchClickDesk" = "请谨慎选择,旧版本可能配置不兼容"
|
"xraySwitchClickDesk" = "请谨慎选择,旧版本可能配置不兼容"
|
||||||
"operationHours" = "运行时间"
|
"operationHours" = "运行时间"
|
||||||
@@ -87,6 +89,7 @@
|
|||||||
|
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"export" = "导出链接"
|
||||||
"title" = "入站列表"
|
"title" = "入站列表"
|
||||||
"totalDownUp" = "总上传 / 下载"
|
"totalDownUp" = "总上传 / 下载"
|
||||||
"totalUsage" = "总用量"
|
"totalUsage" = "总用量"
|
||||||
|
|||||||
118
x-ui.sh
@@ -20,49 +20,45 @@ function LOGI() {
|
|||||||
# check root
|
# check root
|
||||||
[[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1
|
[[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1
|
||||||
|
|
||||||
# check os
|
# Check OS and set release variable
|
||||||
if [[ -f /etc/redhat-release ]]; then
|
if [[ -f /etc/os-release ]]; then
|
||||||
release="centos"
|
source /etc/os-release
|
||||||
elif cat /etc/issue | grep -Eqi "debian"; then
|
release=$ID
|
||||||
release="debian"
|
elif [[ -f /usr/lib/os-release ]]; then
|
||||||
elif cat /etc/issue | grep -Eqi "ubuntu"; then
|
source /usr/lib/os-release
|
||||||
release="ubuntu"
|
release=$ID
|
||||||
elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then
|
|
||||||
release="centos"
|
|
||||||
elif cat /proc/version | grep -Eqi "debian"; then
|
|
||||||
release="debian"
|
|
||||||
elif cat /proc/version | grep -Eqi "ubuntu"; then
|
|
||||||
release="ubuntu"
|
|
||||||
elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then
|
|
||||||
release="centos"
|
|
||||||
else
|
else
|
||||||
LOGE "check system OS failed,please contact with author! \n" && exit 1
|
echo "Failed to check the system OS, please contact the author!" >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "The OS release is: $release"
|
||||||
|
|
||||||
|
|
||||||
os_version=""
|
os_version=""
|
||||||
|
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
||||||
|
|
||||||
# os version
|
if [[ "${release}" == "centos" ]]; then
|
||||||
if [[ -f /etc/os-release ]]; then
|
|
||||||
os_version=$(awk -F'[= ."]' '/VERSION_ID/{print $3}' /etc/os-release)
|
|
||||||
fi
|
|
||||||
if [[ -z "$os_version" && -f /etc/lsb-release ]]; then
|
|
||||||
os_version=$(awk -F'[= ."]+' '/DISTRIB_RELEASE/{print $2}' /etc/lsb-release)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ x"${release}" == x"centos" ]]; then
|
|
||||||
if [[ ${os_version} -le 6 ]]; then
|
|
||||||
LOGE "please use CentOS 7 or higher version! \n" && exit 1
|
|
||||||
fi
|
|
||||||
elif [[ x"${release}" == x"ubuntu" ]]; then
|
|
||||||
if [[ ${os_version} -lt 16 ]]; then
|
|
||||||
LOGE "please use Ubuntu 16 or higher version!\n" && exit 1
|
|
||||||
fi
|
|
||||||
elif [[ x"${release}" == x"debian" ]]; then
|
|
||||||
if [[ ${os_version} -lt 8 ]]; then
|
if [[ ${os_version} -lt 8 ]]; then
|
||||||
LOGE "please use Debian 8 or higher version!\n" && exit 1
|
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
|
||||||
|
fi
|
||||||
|
elif [[ "${release}" == "ubuntu" ]]; then
|
||||||
|
if [[ ${os_version} -lt 20 ]]; then
|
||||||
|
echo -e "${red}please use Ubuntu 20 or higher version!${plain}\n" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [[ "${release}" == "fedora" ]]; then
|
||||||
|
if [[ ${os_version} -lt 36 ]]; then
|
||||||
|
echo -e "${red}please use Fedora 36 or higher version!${plain}\n" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [[ "${release}" == "debian" ]]; then
|
||||||
|
if [[ ${os_version} -lt 10 ]]; then
|
||||||
|
echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
confirm() {
|
confirm() {
|
||||||
if [[ $# > 1 ]]; then
|
if [[ $# > 1 ]]; then
|
||||||
echo && read -p "$1 [Default$2]: " temp
|
echo && read -p "$1 [Default$2]: " temp
|
||||||
@@ -94,7 +90,7 @@ before_show_menu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/main/install.sh)
|
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||||
if [[ $? == 0 ]]; then
|
if [[ $? == 0 ]]; then
|
||||||
if [[ $# == 0 ]]; then
|
if [[ $# == 0 ]]; then
|
||||||
start
|
start
|
||||||
@@ -113,7 +109,7 @@ update() {
|
|||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/main/install.sh)
|
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||||
if [[ $? == 0 ]]; then
|
if [[ $? == 0 ]]; then
|
||||||
LOGI "Update is complete, Panel has automatically restarted "
|
LOGI "Update is complete, Panel has automatically restarted "
|
||||||
exit 0
|
exit 0
|
||||||
@@ -288,21 +284,45 @@ show_log() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
migrate_v2_ui() {
|
enable_bbr() {
|
||||||
/usr/local/x-ui/x-ui v2-ui
|
|
||||||
|
|
||||||
before_show_menu
|
if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf && grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
|
||||||
}
|
echo -e "${green}BBR is already enabled!${plain}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check the OS and install necessary packages
|
||||||
|
if [[ "$(cat /etc/os-release | grep -E '^ID=' | awk -F '=' '{print $2}')" == "ubuntu" ]]; then
|
||||||
|
sudo apt-get update && sudo apt-get install -yqq --no-install-recommends ca-certificates
|
||||||
|
elif [[ "$(cat /etc/os-release | grep -E '^ID=' | awk -F '=' '{print $2}')" == "debian" ]]; then
|
||||||
|
sudo apt-get update && sudo apt-get install -yqq --no-install-recommends ca-certificates
|
||||||
|
elif [[ "$(cat /etc/os-release | grep -E '^ID=' | awk -F '=' '{print $2}')" == "fedora" ]]; then
|
||||||
|
sudo dnf -y update && sudo dnf -y install ca-certificates
|
||||||
|
elif [[ "$(cat /etc/os-release | grep -E '^ID=' | awk -F '=' '{print $2}')" == "centos" ]]; then
|
||||||
|
sudo yum -y update && sudo yum -y install ca-certificates
|
||||||
|
else
|
||||||
|
echo "Unsupported operating system. Please check the script and install the necessary packages manually."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable BBR
|
||||||
|
echo "net.core.default_qdisc=fq" | sudo tee -a /etc/sysctl.conf
|
||||||
|
echo "net.ipv4.tcp_congestion_control=bbr" | sudo tee -a /etc/sysctl.conf
|
||||||
|
|
||||||
|
# Apply changes
|
||||||
|
sudo sysctl -p
|
||||||
|
|
||||||
|
# Verify that BBR is enabled
|
||||||
|
if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "bbr" ]]; then
|
||||||
|
echo -e "${green}BBR has been enabled successfully.${plain}"
|
||||||
|
else
|
||||||
|
echo -e "${red}Failed to enable BBR. Please check your system configuration.${plain}"
|
||||||
|
fi
|
||||||
|
|
||||||
install_bbr() {
|
|
||||||
# temporary workaround for installing bbr
|
|
||||||
bash <(curl -L -s https://raw.githubusercontent.com/teddysun/across/master/bbr.sh)
|
|
||||||
echo ""
|
|
||||||
before_show_menu
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_shell() {
|
update_shell() {
|
||||||
wget -O /usr/bin/x-ui -N --no-check-certificate https://github.com/mhsanaei/3x-ui/raw/main/x-ui.sh
|
wget -O /usr/bin/x-ui -N --no-check-certificate https://github.com/MHSanaei/3x-ui/raw/main/x-ui.sh
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $? != 0 ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
LOGE "Failed to download script,Please check whether the machine can connect Github"
|
LOGE "Failed to download script,Please check whether the machine can connect Github"
|
||||||
@@ -657,8 +677,8 @@ show_menu() {
|
|||||||
${green}11.${plain} Check x-ui Status
|
${green}11.${plain} Check x-ui Status
|
||||||
${green}12.${plain} Check x-ui Logs
|
${green}12.${plain} Check x-ui Logs
|
||||||
————————————————
|
————————————————
|
||||||
${green}13.${plain} Enable x-ui On Sysyem Startup
|
${green}13.${plain} Enable x-ui On System Startup
|
||||||
${green}14.${plain} Disabel x-ui On Sysyem Startup
|
${green}14.${plain} Disabel x-ui On System Startup
|
||||||
————————————————
|
————————————————
|
||||||
${green}15.${plain} Enable BBR
|
${green}15.${plain} Enable BBR
|
||||||
${green}16.${plain} Issuse Certs
|
${green}16.${plain} Issuse Certs
|
||||||
@@ -713,7 +733,7 @@ show_menu() {
|
|||||||
check_install && disable
|
check_install && disable
|
||||||
;;
|
;;
|
||||||
15)
|
15)
|
||||||
install_bbr
|
enable_bbr
|
||||||
;;
|
;;
|
||||||
16)
|
16)
|
||||||
ssl_cert_issue
|
ssl_cert_issue
|
||||||
|
|||||||